Skip to content

StrobeAPI Implementation #353

Merged
merged 48 commits into from
Jul 1, 2018
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5c14dfa
Strobe Implementation v2
fuzun Feb 10, 2018
5a01798
Brightness reduction calculations
fuzun Feb 10, 2018
511a8fe
PWM Simulation (Debug Mode)
fuzun Feb 10, 2018
faa97ce
Sync with 8578012e17982a0b7e37b6f2a7c20f64ae48bc22
fuzun Feb 10, 2018
1d58b1e
Revert "Sync with 8578012e17982a0b7e37b6f2a7c20f64ae48bc22"
fuzun Feb 10, 2018
f6a61e8
Sync with 8578012e17982a0b7e37b6f2a7c20f64ae48bc22
fuzun Feb 10, 2018
7739e2d
Some typo correction
fuzun Feb 10, 2018
9d01da8
Refactor & PWM Simulation Updates
fuzun Feb 17, 2018
03a3b9e
Merge branch 'master' of https://github.com/FWGS/xash3d into FWGS-master
fuzun Feb 17, 2018
c473483
Merge branch 'FWGS-master' into strobe-support
fuzun Feb 17, 2018
48782be
MainUI Sync
fuzun Feb 17, 2018
9a89b57
Implemented Stability Checker & Refactoring
fuzun Feb 18, 2018
b2fe83e
Complete refactor due to OOP implementation
fuzun Mar 3, 2018
425f426
Merge branch 'master' of https://github.com/FWGS/xash3d into FWGS-master
fuzun Mar 3, 2018
6a4683a
Merge branch 'FWGS-master' into strobe-support
fuzun Mar 3, 2018
f449716
Try to make gcc happy
fuzun Mar 3, 2018
d33d3d9
Try to make gcc happy #2
fuzun Mar 3, 2018
427c135
Try to make gcc happy #3
fuzun Mar 3, 2018
ebc5b49
Try to make gcc happy #4
fuzun Mar 3, 2018
4947d1b
Merge branch 'master' into strobe-support
fuzun Mar 9, 2018
fa412c3
Refactored
fuzun Mar 9, 2018
6c9e4da
Fix non consistent draw of debug drawer
fuzun Mar 9, 2018
ec2c7b9
gcc fix
fuzun Mar 9, 2018
de7bbd9
Better OOP & Bug Fix
fuzun Mar 27, 2018
e81370a
GCC Fix ?
fuzun Mar 27, 2018
f46692d
Revert "GCC Fix ?"
fuzun Mar 27, 2018
2a43c7d
GCC Fix ?
fuzun Mar 28, 2018
4db52f1
GCC Fix #2 ?
fuzun Mar 28, 2018
465c428
Merge pull request #3 from FWGS/master
fuzun Mar 29, 2018
bb5d065
Record elapsed time & small fixes
fuzun Mar 31, 2018
1c1be72
Reduced macros
fuzun Mar 31, 2018
2bcc54f
Fixes & Better oop
fuzun Apr 6, 2018
f1ffa67
Merge pull request #4 from FWGS/master
fuzun Apr 6, 2018
72642be
Merge branch 'strobe-support' of https://github.com/fuzun/xash3d into…
fuzun Apr 6, 2018
84759c7
Adjusted constness & format
fuzun Apr 6, 2018
41524d7
Format
fuzun Apr 6, 2018
472b8c0
Merge branch 'master' into strobe-support
fuzun Apr 13, 2018
8944808
Revert "Adjusted constness & format"
fuzun May 5, 2018
1ccf81a
Merge branch 'strobe-support' of https://github.com/fuzun/xash3d into…
fuzun May 5, 2018
b590a5b
Better transition for r_strobe = 1 or -1
fuzun May 7, 2018
c372b1c
Better statistics & transition fix
fuzun May 7, 2018
2592dd9
Change in stability measurement
fuzun May 7, 2018
325d385
Format
fuzun May 7, 2018
254e43a
Merge pull request #5 from FWGS/master
fuzun May 7, 2018
419422e
Safer alpha value for transitions
fuzun Jun 30, 2018
620d12b
Merge pull request #6 from FWGS/master
fuzun Jun 30, 2018
3d5d0cb
Merge branch 'strobe-support' of https://github.com/fuzun/xash3d into…
fuzun Jun 30, 2018
54aeb83
C89 compatibility
fuzun Jun 30, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion common/wrect.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ typedef struct wrect_s
int left, right, top, bottom;
} wrect_t;

#endif//WRECT_H
typedef struct rectf_s
{
float x, y, w, h;
} rectf_t;

#endif //WRECT_H
2 changes: 2 additions & 0 deletions engine/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ LOCAL_SRC_FILES := \
client/s_stream.c \
client/s_utils.c \
client/s_vox.c \
client/strobe/r_strobe_api.c \
client/strobe/r_strobe_core.c \
common/avikit.c \
common/build.c \
common/base_cmd.c \
Expand Down
61 changes: 22 additions & 39 deletions engine/client/cl_scrn.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ GNU General Public License for more details.
#include "qfont.h"
#include "library.h"

#include "strobe/r_strobe_core.h"

convar_t *scr_centertime;
convar_t *scr_loading;
convar_t *scr_download;
Expand All @@ -47,7 +49,7 @@ static qboolean scr_init = false;
SCR_DrawFPS
==============
*/
void SCR_DrawFPS( void )
void SCR_DrawFPS(void)
{
float calc;
rgba_t color;
Expand All @@ -59,13 +61,11 @@ void SCR_DrawFPS( void )
double newtime;
char fpsstring[64];
int offset;
int strobeInterval = r_strobe->integer; // cvar: r_strobe
int eFPS; // Effective FPS (strobing effect)

if( cls.state != ca_active ) return;
if( !cl_showfps->integer || cl.background ) return;
if (cls.state != ca_active) return;
if (!cl_showfps->integer || cl.background) return;

switch( cls.scrshot_action )
switch (cls.scrshot_action)
{
case scrshot_normal:
case scrshot_snapshot:
Expand All @@ -75,69 +75,52 @@ void SCR_DrawFPS( void )
}

newtime = Sys_DoubleTime();
if( newtime >= nexttime )
if (newtime >= nexttime)
{
framerate = framecount / (newtime - lasttime);
lasttime = newtime;
nexttime = max( nexttime + 1, lasttime - 1 );
nexttime = max(nexttime + 1, lasttime - 1);
framecount = 0;
}

framecount++;
calc = framerate;

if( calc == 0 ) return;
if (calc == 0) return;

if( calc < 1.0f )
if (calc < 1.0f)
{
Q_snprintf( fpsstring, sizeof( fpsstring ), "%4i spf", (int)(1.0f / calc + 0.5f));
MakeRGBA( color, 255, 0, 0, 255 );
Q_snprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5f));
MakeRGBA(color, 255, 0, 0, 255);
}
else
{
int curfps = (int)(calc + 0.5f);

if( curfps < minfps ) minfps = curfps;
if( curfps > maxfps ) maxfps = curfps;
if (curfps < minfps) minfps = curfps;
if (curfps > maxfps) maxfps = curfps;

/*if( !avgrate ) avgrate = ( maxfps - minfps ) / 2.0f;
else */avgrate += ( calc - avgrate ) / host.framecount;
else */avgrate += (calc - avgrate) / host.framecount;

if( strobeInterval > 0 )
{
eFPS = (int)(( curfps ) / ( strobeInterval + 1 ));
}
else if( strobeInterval < 0 )
{
strobeInterval = abs( strobeInterval );
eFPS = (int)(( curfps * strobeInterval ) / ( strobeInterval + 1 ));
}

switch( cl_showfps->integer )
switch (cl_showfps->integer)
{
case 3:
Q_snprintf( fpsstring, sizeof( fpsstring ), "fps: ^1%4i min, ^3%4i cur, ^2%4i max | ^3%.2f avg", minfps, curfps, maxfps, avgrate );
Q_snprintf(fpsstring, sizeof(fpsstring), "fps: ^1%4i min, ^3%4i cur, ^2%4i max | ^3%.2f avg", minfps, curfps, maxfps, avgrate);
break;
case 2:
Q_snprintf( fpsstring, sizeof( fpsstring ), "fps: ^1%4i min, ^3%4i cur, ^2%4i max", minfps, curfps, maxfps );
Q_snprintf(fpsstring, sizeof(fpsstring), "fps: ^1%4i min, ^3%4i cur, ^2%4i max", minfps, curfps, maxfps);
break;
case 1:
default:
if( !strobeInterval )
{
Q_snprintf( fpsstring, sizeof( fpsstring ), "%4i fps", curfps );
}
else
{
Q_snprintf( fpsstring, sizeof( fpsstring ), "%4i FPS\n%3i eFPS", curfps, eFPS );
}
Q_snprintf(fpsstring, sizeof(fpsstring), "%4i fps", curfps);
}

MakeRGBA( color, 255, 255, 255, 255 );
MakeRGBA(color, 255, 255, 255, 255);
}

Con_DrawStringLen( fpsstring, &offset, NULL );
Con_DrawString( scr_width->integer - offset - 5, 4, fpsstring, color );
Con_DrawStringLen(fpsstring, &offset, NULL);
Con_DrawString(scr_width->integer - offset - 2, 4, fpsstring, color);
}

/*
Expand Down
10 changes: 10 additions & 0 deletions engine/client/cl_view.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ GNU General Public License for more details.
#include "entity_types.h"
#include "gl_local.h"
#include "vgui_draw.h"

#include "strobe/r_strobe_core.h"

#include "touch.h" // IN_TouchDraw( )
#include "joyinput.h" // Joy_DrawOnScreenKeyboard( )


/*
===============
V_SetupRefDef
Expand Down Expand Up @@ -417,6 +421,12 @@ void V_PostRender( void )
SCR_RSpeeds();
SCR_NetSpeeds();
SCR_DrawFPS();

#ifdef STROBE_ENABLED
if (STROBE_CORE)
STROBE_CORE->STROBE_CORE_FUNC_debughandler(&STROBE_CORE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well... now it looks like something from Windows API...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Macros can be extended to make this more pretty but there are already a lot of them.

#endif

SCR_DrawPos();
SCR_DrawNetGraph();
SV_DrawOrthoTriangles();
Expand Down
2 changes: 1 addition & 1 deletion engine/client/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ convar_t *con_fontscale;
convar_t *con_fontnum;
convar_t *vgui_utf8;

conrect_t con_rect;
rectf_t con_rect;

static int g_codepage = 0;
static qboolean g_utf8 = false;
Expand Down
2 changes: 0 additions & 2 deletions engine/client/gl_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,6 @@ qboolean R_InitRenderAPI( void );
void R_SetupFrustum( void );
void R_FindViewLeaf( void );
void R_DrawFog( void );
void R_Strobe( void );

#define cmatrix3x4 vec4_t *const
#define cmatrix4x4 vec4_t *const
Expand Down Expand Up @@ -700,7 +699,6 @@ extern convar_t *r_lightmap;
extern convar_t *r_fastsky;
extern convar_t *r_vbo;
extern convar_t *r_bump;
extern convar_t *r_strobe;
extern convar_t *r_underwater_distortion;

extern convar_t *mp_decals;
Expand Down
94 changes: 9 additions & 85 deletions engine/client/gl_rmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ GNU General Public License for more details.
#include "particledef.h"
#include "entity_types.h"

#include "strobe/r_strobe_core.h"

#define IsLiquidContents( cnt ) ( cnt == CONTENTS_WATER || cnt == CONTENTS_SLIME || cnt == CONTENTS_LAVA )

msurface_t *r_debug_surface;
Expand Down Expand Up @@ -1326,99 +1328,21 @@ void R_RenderFrame( const ref_params_t *fd, qboolean drawWorld )
GL_BackendEndFrame();
}

_inline void GL_InsertBlackFrame( void )
{
// No strobing on the console
if( CL_IsInConsole() )
{
pglEnable( GL_SCISSOR_TEST );
pglScissor( con_rect.x, (-con_rect.y) - (con_rect.h*1.25), con_rect.w, con_rect.h ); // Preview strobe setting on static
pglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
pglClear( GL_COLOR_BUFFER_BIT );
pglDisable( GL_SCISSOR_TEST );
}
else
{
pglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
pglClear( GL_COLOR_BUFFER_BIT );
}
}

/*
===============
R_Strobe

TODO: Consider vsync timings and do not render the supposed black frame at all.
===============
*/
void R_Strobe( void )
{
static int sCounter = 0;
int getInterval = r_strobe->integer; // Check through modified tag first?

if( CL_IsInMenu() )
{
R_Set2DMode(false);
return;
}

if( !getInterval || ( !gl_swapInterval->integer && getInterval ) )
{
if( getInterval ) //If v-sync is off, turn off strobing
{
Cvar_Set( "r_strobe", "0" );
MsgDev( D_WARN, "Strobing (Black Frame Replacement) requires V-Sync not being turned off! (gl_swapInterval != 0)\n" );
}
else if( sCounter )
sCounter = 0;

// flush any remaining 2D bits
R_Set2DMode(false);
return;
}

// If interval is positive, insert (replace with) black frames.
// For example result of interval = 3 will be: "black-black-black-normal-black-black-black-normal-black-black-black-normal"
if( getInterval > 0 )
{
if( sCounter < getInterval )
{
GL_InsertBlackFrame();
++sCounter;
}
else
{
sCounter = 0;
R_Set2DMode( false );
}
}
// If interval is negative, the procedure will be the opposite reverse.
// For example result of interval = -4 will be: "normal-normal-normal-normal-black-normal-normal-normal-normal-black"
else
{
getInterval = abs( getInterval );
if( sCounter < getInterval )
{
++sCounter;
R_Set2DMode( false );
}
else
{
GL_InsertBlackFrame();
sCounter = 0;
}
}
}

/*
===============
R_EndFrame
===============
*/
void R_EndFrame( void )
{
R_Strobe();
#ifdef STROBE_ENABLED
Strobe_Invoker((void**)(&STROBE_CORE), STROBE_CORE_EXPORTEDFUNC_constructor, STROBE_CORE_EXPORTEDFUNC_main, STROBE_CORE_EXPORTEDFUNC_destructor);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it looks more ugly. Can you just look to other parts of engine and do similar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I know it is very ugly. But I do not think that this can be not ugly with the object orient structure intact. It is C after all.

I have thought using GObject or something like that but decided not to use because I want this strobe implementation to be self-contained.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what parts of the engine for instance ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • basecmd.c: everything is in base_cmd.c and only minimal possible functions are visible outside in base_cmd.h.
  • masterlist.c: there is only three functions are visible outside. Internal states are defined in global structure(encapsulated).
  • ImageLib & SoundLib as an example of images or sound manager in engine.
  • joyinput.c: abstraction over platform-dependent gamepad API.
  • avikit.c: opaque movie_state_t visible outside. You just operate with simple API.
  • cfgscript.c, identification.c, et cetera. Just everything in engine is structured.
  • Graphics rendering is complex and stays in it's own namespace for files: gl_*.c. The same for client, server and sound.
  • All functions are named in the such scheme: _, so there is almost no confusion. Cvar_Get means that this function is from "Cvar" subsystem. HTTP_Run shows that this is something for HTTP support in engine.

You will not find any feature, that's implementation is smudged over the whole engine. Only in such way engine development feels friendly and comfortable. Thanks to Carmack for it. Look into Quake engine, this is fully dervied from it. Some Quake-derived engines still use this, like QFusion, that's why I found QFusion code is beatiful.

I don't know why you think that you need OOP here. Yes, you may simulate some aspects from it, like encapsulation(example above) or polymorphism(see in backends. :)). And that's enough for everything in game engine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think that it's too hard to send patches for such small and young(compared to original Xash3D) project. I just want to keep single and simple way to work with engine source code. Otherwise it will go fast into the pile of garbage of too different code, like Darkplaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the concept here is different. This way a developer can develop their own strobe implementation without altering the core implementation and run it along with different implementations. Also with this way, even if STROBE_ENABLED is defined, strobe will not allocate unnecessary space in memory unless user sets r_strobe to non zero (for core implementation).

https://vgy.me/xnhxKP.png . I think if oop is not used here, either "strobe" will be all over the place or it will suck really hard memory-wise. Also maintenancing new implementations will be much harder.

I think it is a fair trade to use oop here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This a generic game engine in first place. If someone want to develop their strobe algorithm, they can implement it in client library.

Copy link

@blurbusters blurbusters Mar 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! Long term (eventually) this could be a generic strobe library.

Problem is that strobing requires very low-level synchronization and requires a certain amount of very tight 2-way integration as fuzun's diagram explains -- https://vgy.me/xnhxKP.png -- very good points. The strobe API should ideally have its own independently configurable features (e.g. black frame ratios) and maybe 'hint' to the rest of the game of its preferred patterns (e.g. a "biasing" to 72fps during 144Hz operation, or 45fps/60fps/90fps modes for various strobe patterns of 180Hz strobing -- the game has to change its framerate to adapt to the preferred strobe algorithm -- necessitiating a 2-way influence between the strobe API and the game engine, to maximize smoothness and minimize input lag, etc)

It's a code architectural challenge -- how to do it in a clean way, is a super-big-challenge. One can only do their best to self-contain the strobing, but will require quite a bunch of low-level hooks sprinkled throughout any game engine or emulators.

Theoretical independent workarounds can be done such as adding detection of VBlanks (e.g. Direct3D9 RasterStatus.InVBlank but that is not always reliable) but it can be very hard to detect if a framebuffer flip (Present) made it to the correct refresh cycle. Different engines have different ways of framepacing, and it's almost impossible to fully decouple a strobe library from the game engine behaviour, unless you're doing it at a super low level (e.g. attempting to do software strobing directly in NVIDIA graphics drivers, for example) -- and doing it at the driver levels will have more input lag than doing it correctly at the game engine level.

BTW, one thing I noticed on TN LCDs. 60Hz strobing at 180Hz has better color quality than 60Hz strobing at 120Hz. This is because the LCD 6-bit FRC often alternates the temporal dithering between even/odd refresh cycles so you get a color-depth reduction with software BFI on a 2-refresh-pattern on certain LCDs. So by adding a 3-refresh-cycle rotation (ON-OFF-OFF) or (ON-ON-OFF) rather than a 2-refresh-cycle rotation (ON-OFF) you gain back the full color depth of TN LCD 6-bit FRC during 60Hz software strobing. Anyway, a very interesting observation I've found. Yet another great pro of keeping flexibility for customizable number of BFI counts in any strobe API.

Nontheless I agree: Keep the amount of code outside of strobe API as small as possible.

There'll be necessarily hooks (especially correct VBI timing, and correct hinting or control of desired frame pacing / desired frametimes that fits the strobe API's current strobe algorithm) -

But yep -- it's a good idea to minimize amount of code outside the strobe module the absolute bare minimum where possible, and blackbox as much stuff as possible into the strobe library (where it doesn't impact lag) -- e.g. desired frametimes between unique frames -- to target a strobe algorithm that requires 2-vblank, 3-vblank, custom VRR (e.g. X number of different-length VRR refresh cycles for variable-persistence software BFI, etc), or whatnot.

Copy link

@blurbusters blurbusters Mar 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P.S. I see source code license says "This project uses Quake's C code style convention."

If there's a disagreement about using OOP or not .... how hard is it to use a client library approach? Or some other simplification tricks. Keep the OOP inside the library and simply use library calls from the favourite C project. It may mean additional work in the strobe module though, to make it simpler on various game engine authors themselves. Sometimes larger amounts of prettier code is preferable over smaller amounts of uglier code -- even from a maintainability perspective. Beauty is in the eye of the beholder...

Sometimes you prefer to actually consume (a small bit) of memory to simplify maintenance on all sides. Dummy strobe wrapper could also automatically be used (few bytes of memory to cover dummy calls) when strobe is disabled at compile time. That way, you can remove those #ifdefs and constructors/destructor parameters. Who cares about 100 bytes of memory by automatically using the dummywrapper strobe whenever strobe is disabled? I'd gladly waste 100 bytes to remove those #ifdefs possibly -- it is mostly stuff called once per frame render, so that almost-zero extra CPU cycles occuring only 60 times a second, wouldn't matter, if it's an immediate return anyway from a stub-out.

Even with C, there are various tricks like header files containing #define/#undef to dummy-out the calls (low-memory do-nothing version of strobe module, when strobe disabled) without sprinking #ifdefs throughout code. Smart compilers will probably actually compile it to nothingness anyway. It's all a programmer's decision on tradeoffs on memory-and-code-readability. Easing maintainability of strobe shouldn't degrade readability/maintainability on the engine side -- and that includes sometimes wasting 100 bytes of memory to remove hundreds of #ifdefs that are inside *.c instead of *.h -- tough decisions I know -- but...

In some cases one can use a global inside the strobe module to contain more of the OOP stuff to be contained only within the strobe module -- basically a defacto non-OOP wrapper on OOP code for those engines that strictly want to stay non-OOP. This could also additionally be the technique you use to dummy-out too (e.g. assign dummy functions in strobe-disable, assign working functions in strobe-enable).

Since usually only one strobe module active, certain things just simply be a global variable for a very good legitimate reason. Certainly, global is often discouraged, but in this case, it might be appropriate win-win compromise if agreed -- if it hides a little OOP overhead from the non-strobe code in a strongly traditional Quake / ANSI C engine (without needing to do much refactoring) and also hits two birds with one stone (e.g. makes it easier to dummy-out during strobe-disable, making it possible to remove #ifdef clutter).

Looks like plenty of halfway-meeting "compromises" that could keep both of you happy? I only briefly took a look, and I may have missed a lot of blockers (or code architecture decisions) that prevent most/all my suggestions -- just throwing ideas out on the table to help both of ya out...

Just brainstorming ways to make everyone happy :)

Copy link
Contributor Author

@fuzun fuzun Mar 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdrejhon - Thank you for sharing opinion. I want to clarify a few points.

"it's a good idea to minimize amount of code outside the strobe module the absolute bare minimum where possible, and blackbox as much stuff as possible into the strobe library" this was the main point of making this built on object oriented structure so that other implementations will be able to made with ease and with good memory handling. But it also stands out among the other Xash3d source files (structure is fundementally different as @a1batross have pointed out) and because it is hardcoded OOP in C.

With this way, a different implementation can be made really easily. I think that strobing is a very complex thing and the "core" implementation itself is not sufficient. For example it does not support varied positive phase shifting (think as PWM signal, not the other phase).

Look at the template files as an example (They have a few errors though that I will correct), they contain the basic structure for making a new strobing implementation. It is very easy to make because Strobe API provides all necessary backend functions. Even the debug script is generated by that.

The only thing that needs to be done is implementing the algorithm and updating protected members of the abstract base class/structure: Strobe-api through the new code. And including the new .h file and calling Strobe_Invoke function each frame and/or calling (own) debughandler function for drawing the debug script.

And yeah beyond this point it is all about decisions. Since it is C, I do not think that it will get much better than this. If it will have less OOP, maintenance and implementation will be harder. If it will have more OOP, it will be more bloated. There is a trade.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I understood. You only need to set up your IDE to match Unkle Mike's code style(a space after '(' and a space before ')', excluding repeated brackets).

If your IDE doesn't support it, there is clang-format settings at the root of repository.

And then I will merge it ASAP.

#else
// flush any remaining 2D bits
R_Set2DMode(false);
#endif


#ifdef XASH_SDL
SDL_GL_SwapWindow( host.hWnd );
#elif defined __ANDROID__ // For direct android backend
Expand Down
Loading