Merge branch 'next' of https://git.do.srb2.org/STJr/SRB2 into udmf-multitag

This commit is contained in:
Nev3r 2020-11-10 11:46:53 +01:00
commit fb9432ae57
36 changed files with 762 additions and 1239 deletions

View File

@ -234,7 +234,7 @@ set(SRB2_CONFIG_HAVE_GME ON CACHE BOOL
set(SRB2_CONFIG_HAVE_OPENMPT ON CACHE BOOL
"Enable OpenMPT support.")
set(SRB2_CONFIG_HAVE_CURL ON CACHE BOOL
"Enable curl support, used for downloading files via HTTP.")
"Enable curl support.")
set(SRB2_CONFIG_HAVE_THREADS ON CACHE BOOL
"Enable multithreading support.")
if(${CMAKE_SYSTEM} MATCHES Windows)
@ -460,7 +460,7 @@ endif()
if(${SRB2_CONFIG_HAVE_CURL})
if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES})
set(CURL_FOUND ON)
set(CURL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/curl)
set(CURL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/curl/include)
if(${SRB2_SYSTEM_BITS} EQUAL 64)
set(CURL_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/curl/lib64 -lcurl")
else() # 32-bit
@ -554,6 +554,7 @@ if(${SRB2_CONFIG_USEASM})
endif()
set(SRB2_USEASM ON)
add_definitions(-DUSEASM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse3 -mfpmath=sse")
else()
set(SRB2_USEASM OFF)
add_definitions(-DNONX86 -DNORUSEASM)

View File

@ -277,7 +277,7 @@ OPTS += -DCOMPVERSION
ifndef NONX86
ifndef GCC29
ARCHOPTS?=-march=pentium
ARCHOPTS?=-msse3 -mfpmath=sse
else
ARCHOPTS?=-mpentium
endif

File diff suppressed because it is too large Load Diff

View File

@ -64,8 +64,10 @@ typedef enum
PT_REQUESTFILE, // Client requests a file transfer
PT_ASKINFOVIAMS, // Packet from the MS requesting info be sent to new client.
// If this ID changes, update masterserver definition.
PT_RESYNCHEND, // Player is now resynched and is being requested to remake the gametic
PT_RESYNCHGET, // Player got resynch packet
PT_WILLRESENDGAMESTATE, // Hey Client, I am about to resend you the gamestate!
PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead.
PT_RECEIVEDGAMESTATE, // Thank you Server, I am ready to play again!
PT_SENDINGLUAFILE, // Server telling a client Lua needs to open a file
PT_ASKLUAFILE, // Client telling the server they don't have the file
@ -85,8 +87,6 @@ typedef enum
PT_TEXTCMD2, // Splitscreen text commands.
PT_CLIENTJOIN, // Client wants to join; used in start game.
PT_NODETIMEOUT, // Packet sent to self if the connection times out.
PT_RESYNCHING, // Packet sent to resync players.
// Blocks game advance until synched.
PT_LOGIN, // Login attempt from the client.
@ -139,168 +139,6 @@ typedef struct
ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
} ATTRPACK servertics_pak;
// Sent to client when all consistency data
// for players has been restored
typedef struct
{
UINT32 randomseed;
// CTF flag stuff
SINT8 flagplayer[2];
INT32 flagloose[2];
INT32 flagflags[2];
fixed_t flagx[2];
fixed_t flagy[2];
fixed_t flagz[2];
UINT32 ingame; // Spectator bit for each player
UINT32 outofcoop; // outofcoop bit for each player
INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
// Resynch game scores and the like all at once
UINT32 score[MAXPLAYERS]; // Everyone's score
INT16 numboxes[MAXPLAYERS];
INT16 totalring[MAXPLAYERS];
tic_t realtime[MAXPLAYERS];
UINT8 laps[MAXPLAYERS];
} ATTRPACK resynchend_pak;
typedef struct
{
// Player stuff
UINT8 playernum;
// Do not send anything visual related.
// Only send data that we need to know for physics.
UINT8 playerstate; // playerstate_t
UINT32 pflags; // pflags_t
UINT8 panim; // panim_t
INT16 angleturn;
INT16 oldrelangleturn;
angle_t aiming;
INT32 currentweapon;
INT32 ringweapons;
UINT16 ammoremoval;
tic_t ammoremovaltimer;
INT32 ammoremovalweapon;
UINT16 powers[NUMPOWERS];
// Score is resynched in the confirm resync packet
INT16 rings;
INT16 spheres;
SINT8 lives;
SINT8 continues;
UINT8 scoreadd;
SINT8 xtralife;
SINT8 pity;
UINT16 skincolor;
INT32 skin;
UINT32 availabilities;
// Just in case Lua does something like
// modify these at runtime
fixed_t camerascale;
fixed_t shieldscale;
fixed_t normalspeed;
fixed_t runspeed;
UINT8 thrustfactor;
UINT8 accelstart;
UINT8 acceleration;
UINT8 charability;
UINT8 charability2;
UINT32 charflags;
UINT32 thokitem; // mobjtype_t
UINT32 spinitem; // mobjtype_t
UINT32 revitem; // mobjtype_t
UINT32 followitem; // mobjtype_t
fixed_t actionspd;
fixed_t mindash;
fixed_t maxdash;
fixed_t jumpfactor;
fixed_t playerheight;
fixed_t playerspinheight;
fixed_t speed;
UINT8 secondjump;
UINT8 fly1;
tic_t glidetime;
UINT8 climbing;
INT32 deadtimer;
tic_t exiting;
UINT8 homing;
tic_t dashmode;
tic_t skidtime;
fixed_t cmomx;
fixed_t cmomy;
fixed_t rmomx;
fixed_t rmomy;
INT32 weapondelay;
INT32 tossdelay;
INT16 starpostx;
INT16 starposty;
INT16 starpostz;
INT32 starpostnum;
tic_t starposttime;
angle_t starpostangle;
fixed_t starpostscale;
INT32 maxlink;
fixed_t dashspeed;
angle_t angle_pos;
angle_t old_angle_pos;
tic_t bumpertime;
INT32 flyangle;
tic_t drilltimer;
INT32 linkcount;
tic_t linktimer;
INT32 anotherflyangle;
tic_t nightstime;
INT32 drillmeter;
UINT8 drilldelay;
UINT8 bonustime;
UINT8 mare;
INT16 lastsidehit, lastlinehit;
tic_t losstime;
UINT8 timeshit;
INT32 onconveyor;
//player->mo stuff
UINT8 hasmo; // Boolean
INT32 health;
angle_t angle;
angle_t rollangle;
fixed_t x;
fixed_t y;
fixed_t z;
fixed_t momx;
fixed_t momy;
fixed_t momz;
fixed_t friction;
fixed_t movefactor;
spritenum_t sprite;
UINT32 frame;
UINT8 sprite2;
UINT16 anim_duration;
INT32 tics;
statenum_t statenum;
UINT32 flags;
UINT32 flags2;
UINT16 eflags;
fixed_t radius;
fixed_t height;
fixed_t scale;
fixed_t destscale;
fixed_t scalespeed;
} ATTRPACK resynch_pak;
typedef struct
{
UINT8 version; // Different versions don't work
@ -314,18 +152,10 @@ typedef struct
UINT8 clientnode;
UINT8 gamestate;
// 0xFF == not in game; else player skin num
UINT8 playerskins[MAXPLAYERS];
UINT16 playercolor[MAXPLAYERS];
UINT32 playeravailabilities[MAXPLAYERS];
UINT8 gametype;
UINT8 modifiedgame;
SINT8 adminplayers[MAXPLAYERS]; // Needs to be signed
char server_context[8]; // Unique context id, generated at server startup.
UINT8 varlengthinputs[0]; // Playernames and netvars
} ATTRPACK serverconfig_pak;
typedef struct
@ -462,9 +292,6 @@ typedef struct
client2cmd_pak client2pak; // 200 bytes
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
serverconfig_pak servercfg; // 773 bytes
resynchend_pak resynchend; //
resynch_pak resynchpak; //
UINT8 resynchgot; //
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
filetx_pak filetxpak; // 139 bytes
fileack_pak fileack;
@ -606,7 +433,7 @@ UINT8 GetFreeXCmdSize(void);
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);
extern UINT8 hu_resynching;
extern UINT8 hu_redownloadinggamestate;
extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;

View File

@ -1598,7 +1598,7 @@ void D_SRB2Main(void)
{
levelstarttic = gametic;
G_SetGamestate(GS_LEVEL);
if (!P_LoadLevel(false))
if (!P_LoadLevel(false, false))
I_Quit(); // fail so reset game stuff
}
}

View File

@ -798,8 +798,9 @@ static const char *packettypename[NUMPACKETTYPE] =
"REQUESTFILE",
"ASKINFOVIAMS",
"RESYNCHEND",
"RESYNCHGET",
"WILLRESENDGAMESTATE",
"CANRECEIVEGAMESTATE",
"RECEIVEDGAMESTATE",
"SENDINGLUAFILE",
"ASKLUAFILE",
@ -813,7 +814,6 @@ static const char *packettypename[NUMPACKETTYPE] =
"TEXTCMD2",
"CLIENTJOIN",
"NODETIMEOUT",
"RESYNCHING",
"LOGIN",
"PING"
};

View File

@ -38,6 +38,7 @@
#include "lua_script.h"
#include "lua_hook.h"
#include "d_clisrv.h"
#include "g_state.h" // gamestate_t (for lua)
#include "m_cond.h"
@ -5178,6 +5179,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_TAILSOVERLAY_PAIN",
"S_TAILSOVERLAY_GASP",
"S_TAILSOVERLAY_EDGE",
"S_TAILSOVERLAY_DASH",
// [:
"S_JETFUMEFLASH",
@ -10106,6 +10108,22 @@ struct {
{"MA_NOCUTSCENES",MA_NOCUTSCENES},
{"MA_INGAME",MA_INGAME},
// gamestates
{"GS_NULL",GS_NULL},
{"GS_LEVEL",GS_LEVEL},
{"GS_INTERMISSION",GS_INTERMISSION},
{"GS_CONTINUING",GS_CONTINUING},
{"GS_TITLESCREEN",GS_TITLESCREEN},
{"GS_TIMEATTACK",GS_TIMEATTACK},
{"GS_CREDITS",GS_CREDITS},
{"GS_EVALUATION",GS_EVALUATION},
{"GS_GAMEEND",GS_GAMEEND},
{"GS_INTRO",GS_INTRO},
{"GS_ENDING",GS_ENDING},
{"GS_CUTSCENE",GS_CUTSCENE},
{"GS_DEDICATEDSERVER",GS_DEDICATEDSERVER},
{"GS_WAITINGPLAYERS",GS_WAITINGPLAYERS},
{NULL,0}
};

View File

@ -1829,7 +1829,7 @@ void G_DoLoadLevel(boolean resetplayer)
}
// Setup the level.
if (!P_LoadLevel(false)) // this never returns false?
if (!P_LoadLevel(false, false)) // this never returns false?
{
// fail so reset game stuff
Command_ExitGame_f();

View File

@ -1,7 +1,6 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 2020 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.

View File

@ -1,7 +1,6 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 2020 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.

View File

@ -295,6 +295,16 @@ enum hwdsetspecialstate
typedef enum hwdsetspecialstate hwdspecialstate_t;
// Lactozilla: Shader options
enum hwdshaderoption
{
HWD_SHADEROPTION_OFF,
HWD_SHADEROPTION_ON,
HWD_SHADEROPTION_NOCUSTOM,
};
typedef enum hwdshaderoption hwdshaderoption_t;
// Lactozilla: Shader info
// Generally set at the start of the frame.
enum hwdshaderinfo

View File

@ -70,7 +70,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]);
// jimita
EXPORT boolean HWRAPI(CompileShaders) (void);
EXPORT void HWRAPI(CleanShaders) (void);
EXPORT void HWRAPI(SetShader) (int shader);
EXPORT void HWRAPI(SetShader) (int type);
EXPORT void HWRAPI(UnSetShader) (void);
EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value);

View File

@ -5580,6 +5580,20 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean
trans->anglex = (float)(gl_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
}
//
// Sets the shader state.
//
static void HWR_SetShaderState(void)
{
hwdshaderoption_t state = cv_glshaders.value;
if (!cv_glallowshaders.value)
state = (cv_glshaders.value == HWD_SHADEROPTION_ON ? HWD_SHADEROPTION_NOCUSTOM : cv_glshaders.value);
HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)state);
HWD.pfnSetShader(SHADER_DEFAULT);
}
// ==========================================================================
// Same as rendering the player view, but from the skybox object
// ==========================================================================
@ -5698,8 +5712,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
HWD.pfnSetTransform(&atransform);
// Reset the shader state.
HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value);
HWD.pfnSetShader(SHADER_DEFAULT);
HWR_SetShaderState();
validcount++;
@ -5913,8 +5926,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
HWD.pfnSetTransform(&atransform);
// Reset the shader state.
HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value);
HWD.pfnSetShader(SHADER_DEFAULT);
HWR_SetShaderState();
ps_numbspcalls = 0;
ps_numpolyobjects = 0;
@ -6009,9 +6021,10 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
// 3D ENGINE COMMANDS
// ==========================================================================
static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}};
static CV_PossibleValue_t grshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}};
static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {HWD_SHADEROPTION_ON, "On"}, {HWD_SHADEROPTION_NOCUSTOM, "Ignore custom shaders"}, {0, NULL}};
static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}};
static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}};
static void CV_glfiltermode_OnChange(void);
static void CV_glanisotropic_OnChange(void);
@ -6022,9 +6035,10 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA
{HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"},
{HWD_SET_TEXTUREFILTER_MIXED3, "Nearest_Mipmap"},
{0, NULL}};
CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL);
consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL);
#ifdef ALAM_LIGHTING
@ -6035,17 +6049,17 @@ consvar_t cv_glcoronasize = CVAR_INIT ("gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0
#endif
consvar_t cv_glmodels = CVAR_INIT ("gr_models", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL);
consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, glmodelinterpolation_cons_t, NULL);
consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, grshearing_cons_t, NULL);
consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL);
consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glskydome = CVAR_INIT ("gr_skydome", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glfakecontrast = CVAR_INIT ("gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL);
consvar_t cv_glfakecontrast = CVAR_INIT ("gr_fakecontrast", "Smooth", CV_SAVE, glfakecontrast_cons_t, NULL);
consvar_t cv_glslopecontrast = CVAR_INIT ("gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glfiltermode = CVAR_INIT ("gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t, CV_glfiltermode_OnChange);
consvar_t cv_glanisotropicmode = CVAR_INIT ("gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t, CV_glanisotropic_OnChange);
consvar_t cv_glanisotropicmode = CVAR_INIT ("gr_anisotropicmode", "1", CV_CALL, glanisotropicmode_cons_t, CV_glanisotropic_OnChange);
consvar_t cv_glsolvetjoin = CVAR_INIT ("gr_solvetjoin", "On", 0, CV_OnOff, NULL);
@ -6084,6 +6098,7 @@ void HWR_AddCommands(void)
CV_RegisterVar(&cv_glfakecontrast);
CV_RegisterVar(&cv_glshearing);
CV_RegisterVar(&cv_glshaders);
CV_RegisterVar(&cv_glallowshaders);
CV_RegisterVar(&cv_glfiltermode);
CV_RegisterVar(&cv_glsolvetjoin);

View File

@ -78,7 +78,7 @@ const char *HWR_GetShaderName(INT32 shader);
extern customshaderxlat_t shaderxlat[];
extern CV_PossibleValue_t granisotropicmode_cons_t[];
extern CV_PossibleValue_t glanisotropicmode_cons_t[];
#ifdef ALAM_LIGHTING
extern consvar_t cv_gldynamiclighting;
@ -87,7 +87,7 @@ extern consvar_t cv_glcoronas;
extern consvar_t cv_glcoronasize;
#endif
extern consvar_t cv_glshaders;
extern consvar_t cv_glshaders, cv_glallowshaders;
extern consvar_t cv_glmodels;
extern consvar_t cv_glmodelinterpolation;
extern consvar_t cv_glmodellighting;

View File

@ -91,13 +91,6 @@ static GLuint startScreenWipe = 0;
static GLuint endScreenWipe = 0;
static GLuint finalScreenTexture = 0;
// Lactozilla: Shader functions
static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade);
static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade);
static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum);
static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f};
// shortcut for ((float)1/i)
static const GLfloat byte2float[256] = {
0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f,
@ -533,8 +526,8 @@ boolean SetupGLfunc(void)
return true;
}
static boolean gl_allowshaders = false;
static boolean gl_shadersenabled = false;
static hwdshaderoption_t gl_allowshaders = HWD_SHADEROPTION_OFF;
#ifdef GL_SHADERS
typedef GLuint (APIENTRY *PFNglCreateShader) (GLenum);
@ -544,6 +537,7 @@ typedef void (APIENTRY *PFNglGetShaderiv) (GLuint, GLenum, GLint*);
typedef void (APIENTRY *PFNglGetShaderInfoLog) (GLuint, GLsizei, GLsizei*, GLchar*);
typedef void (APIENTRY *PFNglDeleteShader) (GLuint);
typedef GLuint (APIENTRY *PFNglCreateProgram) (void);
typedef void (APIENTRY *PFNglDeleteProgram) (GLuint);
typedef void (APIENTRY *PFNglAttachShader) (GLuint, GLuint);
typedef void (APIENTRY *PFNglLinkProgram) (GLuint);
typedef void (APIENTRY *PFNglGetProgramiv) (GLuint, GLenum, GLint*);
@ -565,6 +559,7 @@ static PFNglGetShaderiv pglGetShaderiv;
static PFNglGetShaderInfoLog pglGetShaderInfoLog;
static PFNglDeleteShader pglDeleteShader;
static PFNglCreateProgram pglCreateProgram;
static PFNglDeleteProgram pglDeleteProgram;
static PFNglAttachShader pglAttachShader;
static PFNglLinkProgram pglLinkProgram;
static PFNglGetProgramiv pglGetProgramiv;
@ -579,12 +574,6 @@ static PFNglUniform2fv pglUniform2fv;
static PFNglUniform3fv pglUniform3fv;
static PFNglGetUniformLocation pglGetUniformLocation;
// 18032019
static GLuint gl_currentshaderprogram = 0;
static boolean gl_shaderprogramchanged = true;
static shadersource_t gl_customshaders[HWR_MAXSHADERS];
// 13062019
typedef enum
{
@ -602,17 +591,37 @@ typedef enum
gluniform_max,
} gluniform_t;
typedef struct gl_shaderprogram_s
typedef struct gl_shader_s
{
GLuint program;
boolean custom;
GLint uniforms[gluniform_max+1];
} gl_shaderprogram_t;
static gl_shaderprogram_t gl_shaderprograms[HWR_MAXSHADERS];
boolean custom;
} gl_shader_t;
static gl_shader_t gl_shaders[HWR_MAXSHADERS];
static gl_shader_t gl_usershaders[HWR_MAXSHADERS];
static shadersource_t gl_customshaders[HWR_MAXSHADERS];
// 09102020
typedef struct gl_shaderstate_s
{
gl_shader_t *current;
GLuint type;
GLuint program;
boolean changed;
} gl_shaderstate_t;
static gl_shaderstate_t gl_shaderstate;
// Shader info
static INT32 shader_leveltime = 0;
// Lactozilla: Shader functions
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader);
static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum);
static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade);
static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f};
// ================
// Vertex shaders
// ================
@ -873,6 +882,7 @@ void SetupGLFunc4(void)
pglGetShaderInfoLog = GetGLFunc("glGetShaderInfoLog");
pglDeleteShader = GetGLFunc("glDeleteShader");
pglCreateProgram = GetGLFunc("glCreateProgram");
pglDeleteProgram = GetGLFunc("glDeleteProgram");
pglAttachShader = GetGLFunc("glAttachShader");
pglLinkProgram = GetGLFunc("glLinkProgram");
pglGetProgramiv = GetGLFunc("glGetProgramiv");
@ -896,20 +906,40 @@ void SetupGLFunc4(void)
EXPORT boolean HWRAPI(CompileShaders) (void)
{
#ifdef GL_SHADERS
GLuint gl_vertShader, gl_fragShader;
GLint i, result;
GLint i;
if (!pglUseProgram) return false;
if (!pglUseProgram)
return false;
gl_customshaders[0].vertex = NULL;
gl_customshaders[0].fragment = NULL;
gl_customshaders[SHADER_DEFAULT].vertex = NULL;
gl_customshaders[SHADER_DEFAULT].fragment = NULL;
for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++)
{
gl_shaderprogram_t *shader;
gl_shader_t *shader, *usershader;
const GLchar *vert_shader = gl_shadersources[i].vertex;
const GLchar *frag_shader = gl_shadersources[i].fragment;
boolean custom = ((gl_customshaders[i].vertex || gl_customshaders[i].fragment) && (i > 0));
if (i >= HWR_MAXSHADERS)
break;
shader = &gl_shaders[i];
usershader = &gl_usershaders[i];
if (shader->program)
pglDeleteProgram(shader->program);
if (usershader->program)
pglDeleteProgram(usershader->program);
shader->program = 0;
usershader->program = 0;
if (!Shader_CompileProgram(shader, i, vert_shader, frag_shader))
shader->program = 0;
// Compile custom shader
if ((i == SHADER_DEFAULT) || !(gl_customshaders[i].vertex || gl_customshaders[i].fragment))
continue;
// 18032019
if (gl_customshaders[i].vertex)
@ -917,92 +947,15 @@ EXPORT boolean HWRAPI(CompileShaders) (void)
if (gl_customshaders[i].fragment)
frag_shader = gl_customshaders[i].fragment;
if (i >= HWR_MAXSHADERS)
break;
shader = &gl_shaderprograms[i];
shader->program = 0;
shader->custom = custom;
//
// Load and compile vertex shader
//
gl_vertShader = pglCreateShader(GL_VERTEX_SHADER);
if (!gl_vertShader)
if (!Shader_CompileProgram(usershader, i, vert_shader, frag_shader))
{
GL_MSG_Error("CompileShaders: Error creating vertex shader %s\n", HWR_GetShaderName(i));
continue;
GL_MSG_Warning("CompileShaders: Could not compile custom shader program for %s\n", HWR_GetShaderName(i));
usershader->program = 0;
}
pglShaderSource(gl_vertShader, 1, &vert_shader, NULL);
pglCompileShader(gl_vertShader);
// check for compile errors
pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling vertex shader", gl_vertShader, i);
continue;
}
//
// Load and compile fragment shader
//
gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER);
if (!gl_fragShader)
{
GL_MSG_Error("CompileShaders: Error creating fragment shader %s\n", HWR_GetShaderName(i));
continue;
}
pglShaderSource(gl_fragShader, 1, &frag_shader, NULL);
pglCompileShader(gl_fragShader);
// check for compile errors
pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling fragment shader", gl_fragShader, i);
continue;
}
shader->program = pglCreateProgram();
pglAttachShader(shader->program, gl_vertShader);
pglAttachShader(shader->program, gl_fragShader);
pglLinkProgram(shader->program);
// check link status
pglGetProgramiv(shader->program, GL_LINK_STATUS, &result);
// delete the shader objects
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
// couldn't link?
if (result != GL_TRUE)
{
shader->program = 0;
shader->custom = false;
GL_MSG_Error("CompileShaders: Error linking shader program %s\n", HWR_GetShaderName(i));
continue;
}
// 13062019
#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform);
// lighting
shader->uniforms[gluniform_poly_color] = GETUNI("poly_color");
shader->uniforms[gluniform_tint_color] = GETUNI("tint_color");
shader->uniforms[gluniform_fade_color] = GETUNI("fade_color");
shader->uniforms[gluniform_lighting] = GETUNI("lighting");
shader->uniforms[gluniform_fade_start] = GETUNI("fade_start");
shader->uniforms[gluniform_fade_end] = GETUNI("fade_end");
// misc. (custom shaders)
shader->uniforms[gluniform_leveltime] = GETUNI("leveltime");
#undef GETUNI
}
SetShader(SHADER_DEFAULT);
return true;
#else
return false;
@ -1070,26 +1023,45 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole
#endif
}
EXPORT void HWRAPI(SetShader) (int shader)
EXPORT void HWRAPI(SetShader) (int type)
{
#ifdef GL_SHADERS
if (gl_allowshaders)
if (gl_allowshaders != HWD_SHADEROPTION_OFF)
{
gl_shader_t *shader = gl_shaderstate.current;
// If using model lighting, set the appropriate shader.
// However don't override a custom shader.
if (shader == SHADER_MODEL && model_lighting
&& !(gl_shaderprograms[SHADER_MODEL].custom && !gl_shaderprograms[SHADER_MODEL_LIGHTING].custom))
shader = SHADER_MODEL_LIGHTING;
if ((GLuint)shader != gl_currentshaderprogram)
if (type == SHADER_MODEL && model_lighting
&& !(gl_shaders[SHADER_MODEL].custom && !gl_shaders[SHADER_MODEL_LIGHTING].custom))
type = SHADER_MODEL_LIGHTING;
if ((shader == NULL) || (GLuint)type != gl_shaderstate.type)
{
gl_currentshaderprogram = shader;
gl_shaderprogramchanged = true;
gl_shader_t *baseshader = &gl_shaders[type];
gl_shader_t *usershader = &gl_usershaders[type];
if (usershader->program)
shader = (gl_allowshaders == HWD_SHADEROPTION_NOCUSTOM) ? baseshader : usershader;
else
shader = baseshader;
gl_shaderstate.current = shader;
gl_shaderstate.type = type;
gl_shaderstate.changed = true;
}
gl_shadersenabled = true;
if (gl_shaderstate.program != shader->program)
{
gl_shaderstate.program = shader->program;
gl_shaderstate.changed = true;
}
gl_shadersenabled = (shader->program != 0);
return;
}
#else
(void)shader;
(void)type;
#endif
gl_shadersenabled = false;
}
@ -1097,11 +1069,15 @@ EXPORT void HWRAPI(SetShader) (int shader)
EXPORT void HWRAPI(UnSetShader) (void)
{
#ifdef GL_SHADERS
gl_shadersenabled = false;
gl_currentshaderprogram = 0;
if (!pglUseProgram) return;
pglUseProgram(0);
gl_shaderstate.current = NULL;
gl_shaderstate.type = 0;
gl_shaderstate.program = 0;
if (pglUseProgram)
pglUseProgram(0);
#endif
gl_shadersenabled = false;
}
EXPORT void HWRAPI(CleanShaders) (void)
@ -1901,42 +1877,24 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo)
}
}
static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade)
{
#ifdef GL_SHADERS
if (gl_shadersenabled && pglUseProgram)
{
gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram];
if (shader->program)
{
if (gl_shaderprogramchanged)
{
pglUseProgram(gl_shaderprograms[gl_currentshaderprogram].program);
gl_shaderprogramchanged = false;
}
Shader_SetUniforms(Surface, poly, tint, fade);
return shader;
}
else
pglUseProgram(0);
}
#else
(void)Surface;
(void)poly;
(void)tint;
(void)fade;
#endif
return NULL;
}
static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade)
{
#ifdef GL_SHADERS
if (gl_shadersenabled)
gl_shader_t *shader = gl_shaderstate.current;
if (gl_shadersenabled && (shader != NULL) && pglUseProgram)
{
gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram];
if (!shader->program)
{
pglUseProgram(0);
return;
}
if (gl_shaderstate.changed)
{
pglUseProgram(shader->program);
gl_shaderstate.changed = false;
}
// Color uniforms can be left NULL and will be set to white (1.0f, 1.0f, 1.0f, 1.0f)
if (poly == NULL)
@ -1989,6 +1947,97 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF
#endif
}
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader)
{
GLuint gl_vertShader, gl_fragShader;
GLint result;
//
// Load and compile vertex shader
//
gl_vertShader = pglCreateShader(GL_VERTEX_SHADER);
if (!gl_vertShader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i));
return false;
}
pglShaderSource(gl_vertShader, 1, &vert_shader, NULL);
pglCompileShader(gl_vertShader);
// check for compile errors
pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling vertex shader", gl_vertShader, i);
pglDeleteShader(gl_vertShader);
return false;
}
//
// Load and compile fragment shader
//
gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER);
if (!gl_fragShader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i));
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
}
pglShaderSource(gl_fragShader, 1, &frag_shader, NULL);
pglCompileShader(gl_fragShader);
// check for compile errors
pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling fragment shader", gl_fragShader, i);
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
}
shader->program = pglCreateProgram();
pglAttachShader(shader->program, gl_vertShader);
pglAttachShader(shader->program, gl_fragShader);
pglLinkProgram(shader->program);
// check link status
pglGetProgramiv(shader->program, GL_LINK_STATUS, &result);
// delete the shader objects
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
// couldn't link?
if (result != GL_TRUE)
{
GL_MSG_Error("Shader_CompileProgram: Error linking shader program %s\n", HWR_GetShaderName(i));
pglDeleteProgram(shader->program);
return false;
}
// 13062019
#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform);
// lighting
shader->uniforms[gluniform_poly_color] = GETUNI("poly_color");
shader->uniforms[gluniform_tint_color] = GETUNI("tint_color");
shader->uniforms[gluniform_fade_color] = GETUNI("fade_color");
shader->uniforms[gluniform_lighting] = GETUNI("lighting");
shader->uniforms[gluniform_fade_start] = GETUNI("fade_start");
shader->uniforms[gluniform_fade_end] = GETUNI("fade_end");
// misc. (custom shaders)
shader->uniforms[gluniform_leveltime] = GETUNI("leveltime");
#undef GETUNI
return true;
}
static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum)
{
GLchar *infoLog = NULL;
@ -2002,7 +2051,7 @@ static void Shader_CompileError(const char *message, GLuint program, INT32 shade
pglGetShaderInfoLog(program, logLength, NULL, infoLog);
}
GL_MSG_Error("CompileShaders: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : ""));
GL_MSG_Error("Shader_CompileProgram: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : ""));
if (infoLog)
free(infoLog);
@ -2112,7 +2161,7 @@ static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD
pglColor4ubv(c);
}
Shader_Load(pSurf, &poly, &tint, &fade);
Shader_SetUniforms(pSurf, &poly, &tint, &fade);
}
// -----------------+
@ -2158,7 +2207,7 @@ EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky)
{
int i, j;
Shader_Load(NULL, NULL, NULL, NULL);
Shader_SetUniforms(NULL, NULL, NULL, NULL);
// Build the sky dome! Yes!
if (sky->rebuild)
@ -2250,15 +2299,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
break;
case HWD_SET_SHADERS:
switch (Value)
{
case 1:
gl_allowshaders = true;
break;
default:
gl_allowshaders = false;
break;
}
gl_allowshaders = (hwdshaderoption_t)Value;
break;
case HWD_SET_TEXTUREFILTERMODE:
@ -2607,7 +2648,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
fade.blue = byte2float[Surface->FadeColor.s.blue];
fade.alpha = byte2float[Surface->FadeColor.s.alpha];
Shader_Load(Surface, &poly, &tint, &fade);
Shader_SetUniforms(Surface, &poly, &tint, &fade);
pglEnable(GL_CULL_FACE);
pglEnable(GL_NORMALIZE);

View File

@ -2120,7 +2120,7 @@ void HU_Drawer(void)
HU_DrawCrosshair2();
// draw desynch text
if (hu_resynching)
if (hu_redownloadinggamestate)
{
static UINT32 resynch_ticker = 0;
char resynch_text[14];

View File

@ -584,6 +584,7 @@ char spr2names[NUMPLAYERSPRITES][5] =
"TAL9",
"TALA",
"TALB",
"TALC",
"CNT1",
"CNT2",
@ -661,6 +662,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_TAL0, // SPR2_TAL9,
SPR2_TAL9, // SPR2_TALA,
SPR2_TAL0, // SPR2_TALB,
SPR2_TAL6, // SPR2_TALC,
SPR2_WAIT, // SPR2_CNT1,
SPR2_FALL, // SPR2_CNT2,
@ -801,6 +803,7 @@ state_t states[NUMSTATES] =
{SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN}, // S_TAILSOVERLAY_PAIN
{SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP}, // S_TAILSOVERLAY_GASP
{SPR_PLAY, SPR2_TALB , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE}, // S_TAILSOVERLAY_EDGE
{SPR_PLAY, SPR2_TALC|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_DASH}, // S_TAILSOVERLAY_DASH
// [:
{SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1}, // S_JETFUMEFLASH

View File

@ -856,6 +856,7 @@ typedef enum playersprite
SPR2_TAL9,
SPR2_TALA,
SPR2_TALB,
SPR2_TALC,
SPR2_CNT1, // continue disappointment
SPR2_CNT2, // continue lift
@ -997,6 +998,7 @@ typedef enum state
S_TAILSOVERLAY_PAIN,
S_TAILSOVERLAY_GASP,
S_TAILSOVERLAY_EDGE,
S_TAILSOVERLAY_DASH,
// [:
S_JETFUMEFLASH,

View File

@ -247,6 +247,56 @@ static int lib_userdataType(lua_State *L)
return luaL_typerror(L, 1, "userdata");
}
// Takes a metatable as first and only argument
// Only callable during script loading
static int lib_registerMetatable(lua_State *L)
{
static UINT16 nextid = 1;
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
luaL_checktype(L, 1, LUA_TTABLE);
if (nextid == 0)
return luaL_error(L, "Too many metatables registered?! Please consider rewriting your script once you are sober again.\n");
lua_getfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); // 2
// registry.metatables[metatable] = nextid
lua_pushvalue(L, 1); // 3
lua_pushnumber(L, nextid); // 4
lua_settable(L, 2);
// registry.metatables[nextid] = metatable
lua_pushnumber(L, nextid); // 3
lua_pushvalue(L, 1); // 4
lua_settable(L, 2);
lua_pop(L, 1);
nextid++;
return 0;
}
// Takes a string as only argument and returns the metatable
// associated to the userdata type this string refers to
// Returns nil if the string does not refer to a valid userdata type
static int lib_userdataMetatable(lua_State *L)
{
UINT32 i;
const char *udname = luaL_checkstring(L, 1);
// Find internal metatable name
for (i = 0; meta2utype[i].meta; i++)
if (!strcmp(udname, meta2utype[i].utype))
{
luaL_getmetatable(L, meta2utype[i].meta);
return 1;
}
lua_pushnil(L);
return 1;
}
static int lib_isPlayerAdmin(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
@ -3495,6 +3545,8 @@ static luaL_Reg lib[] = {
{"chatprint", lib_chatprint},
{"chatprintf", lib_chatprintf},
{"userdataType", lib_userdataType},
{"registerMetatable", lib_registerMetatable},
{"userdataMetatable", lib_userdataMetatable},
{"IsPlayerAdmin", lib_isPlayerAdmin},
{"reserveLuabanks", lib_reserveLuabanks},

View File

@ -16,6 +16,7 @@ extern lua_State *gL;
#define LREG_EXTVARS "LUA_VARS"
#define LREG_STATEACTION "STATE_ACTION"
#define LREG_ACTIONS "MOBJ_ACTION"
#define LREG_METATABLES "METATABLES"
#define META_STATE "STATE_T*"
#define META_MOBJINFO "MOBJINFO_T*"

View File

@ -34,6 +34,7 @@
#include "lua_hook.h"
#include "doomstat.h"
#include "g_state.h"
lua_State *gL = NULL;
@ -361,6 +362,9 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word, "token")) {
lua_pushinteger(L, token);
return 1;
} else if (fastcmp(word, "gamestate")) {
lua_pushinteger(L, gamestate);
return 1;
}
return 0;
}
@ -439,6 +443,10 @@ static void LUA_ClearState(void)
lua_newtable(L);
lua_setfield(L, LUA_REGISTRYINDEX, LREG_VALID);
// make LREG_METATABLES table for all registered metatables
lua_newtable(L);
lua_setfield(L, LUA_REGISTRYINDEX, LREG_METATABLES);
// open srb2 libraries
for(i = 0; liblist[i]; i++) {
lua_pushcfunction(L, liblist[i]);
@ -976,8 +984,17 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
lua_pop(gL, 1);
}
if (!found)
{
t++;
if (t == 0)
{
CONS_Alert(CONS_ERROR, "Too many tables to archive!\n");
WRITEUINT8(save_p, ARCH_NULL);
return 0;
}
}
WRITEUINT8(save_p, ARCH_TABLE);
WRITEUINT16(save_p, t);
@ -1290,8 +1307,22 @@ static void ArchiveTables(void)
lua_pop(gL, 1);
}
lua_pop(gL, 1);
WRITEUINT8(save_p, ARCH_TEND);
// Write metatable ID
if (lua_getmetatable(gL, -1))
{
// registry.metatables[metatable]
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
lua_pushvalue(gL, -2);
lua_gettable(gL, -2);
WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1));
lua_pop(gL, 3);
}
else
WRITEUINT16(save_p, 0);
lua_pop(gL, 1);
}
}
@ -1462,6 +1493,7 @@ static void UnArchiveTables(void)
{
int TABLESINDEX;
UINT16 i, n;
UINT16 metatableid;
if (!gL)
return;
@ -1486,6 +1518,19 @@ static void UnArchiveTables(void)
else
lua_rawset(gL, -3);
}
metatableid = READUINT16(save_p);
if (metatableid)
{
// setmetatable(table, registry.metatables[metatableid])
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
lua_rawgeti(gL, -1, metatableid);
if (lua_isnil(gL, -1))
I_Error("Unknown metatable ID %d\n", metatableid);
lua_setmetatable(gL, -3);
lua_pop(gL, 1);
}
lua_pop(gL, 1);
}
}

View File

@ -29,15 +29,21 @@
// GIFs are always little-endian
#include "byteptr.h"
CV_PossibleValue_t gif_dynamicdelay_cons_t[] = {
{0, "Off"},
{1, "On"},
{2, "Accurate, experimental"},
{0, NULL}};
consvar_t cv_gif_optimize = CVAR_INIT ("gif_optimize", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_gif_downscale = CVAR_INIT ("gif_downscale", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_gif_dynamicdelay = CVAR_INIT ("gif_dynamicdelay", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_gif_dynamicdelay = CVAR_INIT ("gif_dynamicdelay", "On", CV_SAVE, gif_dynamicdelay_cons_t, NULL);
consvar_t cv_gif_localcolortable = CVAR_INIT ("gif_localcolortable", "On", CV_SAVE, CV_OnOff, NULL);
#ifdef HAVE_ANIGIF
static boolean gif_optimize = false; // So nobody can do something dumb
static boolean gif_downscale = false; // like changing cvars mid output
static boolean gif_dynamicdelay = false; // and messing something up
static UINT8 gif_dynamicdelay = (UINT8)0; // and messing something up
// Palette handling
static boolean gif_localcolortable = false;
@ -47,7 +53,8 @@ static RGBA_t *gif_framepalette = NULL;
static FILE *gif_out = NULL;
static INT32 gif_frames = 0;
static UINT32 gif_prevframems = 0;
static UINT32 gif_prevframeus = 0; // "us" is microseconds
static UINT32 gif_delayus = 0;
static UINT8 gif_writeover = 0;
@ -594,16 +601,30 @@ static void GIF_framewrite(void)
// screen regions are handled in GIF_lzw
{
UINT16 delay;
UINT16 delay = 0;
INT32 startline;
if (gif_dynamicdelay) {
if (gif_dynamicdelay ==(UINT8) 2)
{
// golden's attempt at creating a "dynamic delay"
UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise).
gif_delayus += (I_GetTimeMicros() - gif_prevframeus); // increase delay by how much time was spent between last measurement
if (gif_delayus/1000 >= mingifdelay) // delay is big enough to be able to effect gif frame delay?
{
int frames = (gif_delayus/1000) / mingifdelay; // get amount of frames to delay.
delay = frames; // set the delay to delay that amount of frames.
gif_delayus -= frames*(mingifdelay*1000); // remove frames by the amount of milliseconds they take. don't reset to 0, the microseconds help consistency.
}
}
else if (gif_dynamicdelay ==(UINT8) 1)
{
float delayf = ceil(100.0f/NEWTICRATE);
delay = (UINT16)((I_GetTimeMicros() - gif_prevframems)/10/1000);
if (delay < (int)(delayf))
delay = (int)(delayf);
delay = (UINT16)((I_GetTimeMicros() - gif_prevframeus)/10/1000);
if (delay < (UINT16)(delayf))
delay = (UINT16)(delayf);
}
else
{
@ -690,7 +711,7 @@ static void GIF_framewrite(void)
}
fwrite(gifframe_data, 1, (p - gifframe_data), gif_out);
++gif_frames;
gif_prevframems = I_GetTimeMicros();
gif_prevframeus = I_GetTimeMicros();
}
@ -711,14 +732,15 @@ INT32 GIF_open(const char *filename)
gif_optimize = (!!cv_gif_optimize.value);
gif_downscale = (!!cv_gif_downscale.value);
gif_dynamicdelay = (!!cv_gif_dynamicdelay.value);
gif_dynamicdelay = (UINT8)cv_gif_dynamicdelay.value;
gif_localcolortable = (!!cv_gif_localcolortable.value);
gif_colorprofile = (!!cv_screenshot_colorprofile.value);
gif_headerpalette = GIF_getpalette(0);
GIF_headwrite();
gif_frames = 0;
gif_prevframems = I_GetTimeMicros();
gif_prevframeus = I_GetTimeMicros();
gif_delayus = 0;
return 1;
}

View File

@ -1434,19 +1434,26 @@ void Command_Writethings_f(void)
REQUIRE_SINGLEPLAYER;
REQUIRE_OBJECTPLACE;
P_WriteThings(W_GetNumForName(G_BuildMapName(gamemap)) + ML_THINGS);
P_WriteThings();
}
void Command_ObjectPlace_f(void)
{
size_t thingarg;
size_t silent;
REQUIRE_INLEVEL;
REQUIRE_SINGLEPLAYER;
REQUIRE_NOULTIMATE;
G_SetGameModified(multiplayer);
silent = COM_CheckParm("-silent");
thingarg = 2 - ( silent != 1 );
// Entering objectplace?
if (!objectplacing || COM_Argc() > 1)
if (!objectplacing || thingarg < COM_Argc())
{
if (!objectplacing)
{
@ -1455,7 +1462,7 @@ void Command_ObjectPlace_f(void)
if (players[0].powers[pw_carry] == CR_NIGHTSMODE)
return;
if (!COM_CheckParm("-silent"))
if (! silent)
{
HU_SetCEchoFlags(V_RETURN8|V_MONOSPACE|V_AUTOFADEOUT);
HU_SetCEchoDuration(10);
@ -1506,9 +1513,9 @@ void Command_ObjectPlace_f(void)
op_oldstate = (statenum_t)(players[0].mo->state-states);
}
if (COM_Argc() > 1)
if (thingarg < COM_Argc())
{
UINT16 mapthingnum = atoi(COM_Argv(1));
UINT16 mapthingnum = atoi(COM_Argv(thingarg));
mobjtype_t type = P_GetMobjtype(mapthingnum);
if (type == MT_UNKNOWN)
CONS_Printf(M_GetText("No mobj type delegated to thing type %d.\n"), mapthingnum);

View File

@ -8246,7 +8246,7 @@ static void M_CacheLoadGameData(void)
static void M_DrawLoadGameData(void)
{
INT32 i, savetodraw, x, y, hsep = 90;
INT32 i, prev_i = 1, savetodraw, x, y, hsep = 90;
skin_t *charskin = NULL;
if (vid.width != BASEVIDWIDTH*vid.dupx)
@ -8255,8 +8255,9 @@ static void M_DrawLoadGameData(void)
if (needpatchrecache)
M_CacheLoadGameData();
for (i = -2; i <= 2; i++)
for (i = 2; prev_i; i = -(i + ((UINT32)i >> 31))) // draws from outwards in; 2, -2, 1, -1, 0
{
prev_i = i;
savetodraw = (saveSlotSelected + i + numsaves)%numsaves;
x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*hsep);
y = 33 + 9;

View File

@ -1,7 +1,6 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 2020 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.

View File

@ -1,7 +1,6 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 2020 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.

View File

@ -2735,7 +2735,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
// Step up
if (thing->z < tmfloorz)
{
if (tmfloorz - thing->z <= maxstep)
if (maxstep > 0 && tmfloorz - thing->z <= maxstep)
{
thing->z = thing->floorz = tmfloorz;
thing->floorrover = tmfloorrover;
@ -2748,7 +2748,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
}
else if (tmceilingz < thingtop)
{
if (thingtop - tmceilingz <= maxstep)
if (maxstep > 0 && thingtop - tmceilingz <= maxstep)
{
thing->z = ( thing->ceilingz = tmceilingz ) - thing->height;
thing->ceilingrover = tmceilingrover;
@ -3107,7 +3107,7 @@ static void P_HitSlideLine(line_t *ld)
lineangle >>= ANGLETOFINESHIFT;
deltaangle >>= ANGLETOFINESHIFT;
movelen = P_AproxDistance(tmxmove, tmymove);
movelen = R_PointToDist2(0, 0, tmxmove, tmymove);
newlen = FixedMul(movelen, FINECOSINE(deltaangle));
tmxmove = FixedMul(newlen, FINECOSINE(lineangle));

View File

@ -98,13 +98,16 @@ static void P_NetArchivePlayers(void)
for (i = 0; i < MAXPLAYERS; i++)
{
WRITESINT8(save_p, (SINT8)adminplayers[i]);
if (!playeringame[i])
continue;
flags = 0;
// no longer send ticcmds, player name, skin, or color
// no longer send ticcmds
WRITESTRINGN(save_p, player_names[i], MAXPLAYERNAME);
WRITEINT16(save_p, players[i].angleturn);
WRITEINT16(save_p, players[i].oldrelangleturn);
WRITEANGLE(save_p, players[i].aiming);
@ -134,6 +137,9 @@ static void P_NetArchivePlayers(void)
WRITEUINT16(save_p, players[i].flashpal);
WRITEUINT16(save_p, players[i].flashcount);
WRITEUINT8(save_p, players[i].skincolor);
WRITEINT32(save_p, players[i].skin);
WRITEUINT32(save_p, players[i].availabilities);
WRITEUINT32(save_p, players[i].score);
WRITEFIXED(save_p, players[i].dashspeed);
WRITESINT8(save_p, players[i].lives);
@ -305,6 +311,8 @@ static void P_NetUnArchivePlayers(void)
for (i = 0; i < MAXPLAYERS; i++)
{
adminplayers[i] = (INT32)READSINT8(save_p);
// Do NOT memset player struct to 0
// other areas may initialize data elsewhere
//memset(&players[i], 0, sizeof (player_t));
@ -312,9 +320,8 @@ static void P_NetUnArchivePlayers(void)
continue;
// NOTE: sending tics should (hopefully) no longer be necessary
// sending player names, skin and color should not be necessary at all!
// (that data is handled in the server config now)
READSTRINGN(save_p, player_names[i], MAXPLAYERNAME);
players[i].angleturn = READINT16(save_p);
players[i].oldrelangleturn = READINT16(save_p);
players[i].aiming = READANGLE(save_p);
@ -344,6 +351,9 @@ static void P_NetUnArchivePlayers(void)
players[i].flashpal = READUINT16(save_p);
players[i].flashcount = READUINT16(save_p);
players[i].skincolor = READUINT8(save_p);
players[i].skin = READINT32(save_p);
players[i].availabilities = READUINT32(save_p);
players[i].score = READUINT32(save_p);
players[i].dashspeed = READFIXED(save_p); // dashing speed
players[i].lives = READSINT8(save_p);
@ -3964,14 +3974,17 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride)
playeringame[consoleplayer] = true;
}
static void P_NetArchiveMisc(void)
static void P_NetArchiveMisc(boolean resending)
{
INT32 i;
WRITEUINT32(save_p, ARCHIVEBLOCK_MISC);
if (resending)
WRITEUINT32(save_p, gametic);
WRITEINT16(save_p, gamemap);
WRITEINT16(save_p, gamestate);
WRITEINT16(save_p, gametype);
{
UINT32 pig = 0;
@ -4034,13 +4047,16 @@ static void P_NetArchiveMisc(void)
WRITEUINT8(save_p, 0x2e);
}
static inline boolean P_NetUnArchiveMisc(void)
static inline boolean P_NetUnArchiveMisc(boolean reloading)
{
INT32 i;
if (READUINT32(save_p) != ARCHIVEBLOCK_MISC)
I_Error("Bad $$$.sav at archive block Misc");
if (reloading)
gametic = READUINT32(save_p);
gamemap = READINT16(save_p);
// gamemap changed; we assume that its map header is always valid,
@ -4054,6 +4070,8 @@ static inline boolean P_NetUnArchiveMisc(void)
G_SetGamestate(READINT16(save_p));
gametype = READINT16(save_p);
{
UINT32 pig = READUINT32(save_p);
for (i = 0; i < MAXPLAYERS; i++)
@ -4067,7 +4085,7 @@ static inline boolean P_NetUnArchiveMisc(void)
tokenlist = READUINT32(save_p);
if (!P_LoadLevel(true))
if (!P_LoadLevel(true, reloading))
return false;
// get the time
@ -4166,14 +4184,14 @@ void P_SaveGame(INT16 mapnum)
P_ArchiveLuabanksAndConsistency();
}
void P_SaveNetGame(void)
void P_SaveNetGame(boolean resending)
{
thinker_t *th;
mobj_t *mobj;
INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
CV_SaveNetVars(&save_p);
P_NetArchiveMisc();
P_NetArchiveMisc(resending);
// Assign the mobjnumber for pointer tracking
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
@ -4221,10 +4239,10 @@ boolean P_LoadGame(INT16 mapoverride)
return true;
}
boolean P_LoadNetGame(void)
boolean P_LoadNetGame(boolean reloading)
{
CV_LoadNetVars(&save_p);
if (!P_NetUnArchiveMisc())
if (!P_NetUnArchiveMisc(reloading))
return false;
P_NetUnArchivePlayers();
if (gamestate == GS_LEVEL)

View File

@ -22,9 +22,9 @@
// These are the load / save game routines.
void P_SaveGame(INT16 mapnum);
void P_SaveNetGame(void);
void P_SaveNetGame(boolean resending);
boolean P_LoadGame(INT16 mapoverride);
boolean P_LoadNetGame(void);
boolean P_LoadNetGame(boolean reloading);
mobj_t *P_FindNewPosition(UINT32 oldposition);

View File

@ -906,16 +906,13 @@ static void P_SpawnMapThings(boolean spawnemblems)
}
// Experimental groovy write function!
void P_WriteThings(lumpnum_t lumpnum)
void P_WriteThings(void)
{
size_t i, length;
mapthing_t *mt;
UINT8 *data;
UINT8 *savebuffer, *savebuf_p;
INT16 temp;
data = W_CacheLumpNum(lumpnum, PU_LEVEL);
savebuf_p = savebuffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t));
if (!savebuf_p)
@ -937,8 +934,6 @@ void P_WriteThings(lumpnum_t lumpnum)
WRITEUINT16(savebuf_p, mt->options);
}
Z_Free(data);
length = savebuf_p - savebuffer;
FIL_WriteFile(va("newthings%d.lmp", gamemap), savebuffer, length);
@ -2432,6 +2427,10 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype
seg->angle = R_PointToAngle2(v1->x, v1->y, v2->x, v2->y);
if (seg->linedef)
segs[i].offset = FixedHypot(v1->x - seg->linedef->v1->x, v1->y - seg->linedef->v1->y);
seg->length = P_SegLength(seg);
#ifdef HWRENDER
seg->flength = (rendermode == render_opengl) ? P_SegLengthFloat(seg) : 0;
#endif
}
return true;
@ -3359,8 +3358,6 @@ static void P_InitLevelSettings(void)
leveltime = 0;
localaiming = 0;
localaiming2 = 0;
modulothing = 0;
// special stage tokens, emeralds, and ring total
@ -3475,6 +3472,9 @@ void P_RespawnThings(void)
P_InitLevelSettings();
localaiming = 0;
localaiming2 = 0;
P_SpawnMapThings(true);
// restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that
@ -3982,7 +3982,7 @@ static void P_InitGametype(void)
* \param fromnetsave If true, skip some stuff because we're loading a netgame snapshot.
* \todo Clean up, refactor, split up; get rid of the bloat.
*/
boolean P_LoadLevel(boolean fromnetsave)
boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
{
// use gamemap to get map number.
// 99% of the things already did, so.
@ -4052,7 +4052,10 @@ boolean P_LoadLevel(boolean fromnetsave)
players[consoleplayer].viewz = 1;
// Cancel all d_main.c fadeouts (keep fade in though).
wipegamestate = FORCEWIPEOFF;
if (reloadinggamestate)
wipegamestate = gamestate; // Don't fade if reloading the gamestate
else
wipegamestate = FORCEWIPEOFF;
wipestyleflags = 0;
// Special stage & record attack retry fade to white
@ -4078,18 +4081,20 @@ boolean P_LoadLevel(boolean fromnetsave)
// Fade out music here. Deduct 2 tics so the fade volume actually reaches 0.
// But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug.
if (!titlemapinaction && (RESETMUSIC ||
if (!(reloadinggamestate || titlemapinaction) && (RESETMUSIC ||
strnicmp(S_MusicName(),
(mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7)))
{
S_FadeMusic(0, FixedMul(
FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE));
}
// Let's fade to black here
// But only if we didn't do the special stage wipe
if (rendermode != render_none && !ranspecialwipe)
if (rendermode != render_none && !(ranspecialwipe || reloadinggamestate))
P_RunLevelWipe();
if (!titlemapinaction)
if (!(reloadinggamestate || titlemapinaction))
{
if (ranspecialwipe == 2)
{
@ -4214,7 +4219,12 @@ boolean P_LoadLevel(boolean fromnetsave)
if (!fromnetsave)
P_InitGametype();
P_InitCamera();
if (!reloadinggamestate)
{
P_InitCamera();
localaiming = 0;
localaiming2 = 0;
}
// clear special respawning que
iquehead = iquetail = 0;
@ -4222,7 +4232,7 @@ boolean P_LoadLevel(boolean fromnetsave)
P_MapEnd();
// Remove the loading shit from the screen
if (rendermode != render_none && !titlemapinaction)
if (rendermode != render_none && !(titlemapinaction || reloadinggamestate))
F_WipeColorFill(levelfadecol);
if (precache || dedicated)
@ -4266,8 +4276,8 @@ boolean P_LoadLevel(boolean fromnetsave)
LUAh_MapLoad();
}
// No render mode, stop here.
if (rendermode == render_none)
// No render mode or reloading gamestate, stop here.
if (rendermode == render_none || reloadinggamestate)
return true;
// Title card!

View File

@ -97,7 +97,7 @@ void P_SetupLevelSky(INT32 skynum, boolean global);
void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
#endif
void P_RespawnThings(void);
boolean P_LoadLevel(boolean fromnetsave);
boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate);
#ifdef HWRENDER
void HWR_SetupLevel(void);
#endif
@ -105,7 +105,7 @@ boolean P_AddWadFile(const char *wadfilename);
boolean P_RunSOC(const char *socfilename);
void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num);
void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num);
void P_WriteThings(lumpnum_t lump);
void P_WriteThings(void);
size_t P_PrecacheLevelFlats(void);
void P_AllocMapHeader(INT16 i);

View File

@ -2029,6 +2029,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
ghost->colorized = mobj->colorized; // alternatively, "true" for sonic advance style colourisation
ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle);
ghost->rollangle = mobj->rollangle;
ghost->sprite = mobj->sprite;
ghost->sprite2 = mobj->sprite2;
ghost->frame = mobj->frame;
@ -11223,6 +11224,8 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails)
chosenstate = S_TAILSOVERLAY_GASP;
else if (player->mo->state-states == S_PLAY_EDGE)
chosenstate = S_TAILSOVERLAY_EDGE;
else if (player->panim == PA_DASH)
chosenstate = S_TAILSOVERLAY_DASH;
else if (player->panim == PA_RUN)
chosenstate = S_TAILSOVERLAY_RUN;
else if (player->panim == PA_WALK)

View File

@ -887,26 +887,45 @@ static png_bytep *PNG_Read(
// matches the color count of SRB2's palette: 256 colors.
if (png_get_PLTE(png_ptr, png_info_ptr, &palette, &palette_size))
{
if (palette_size == 256)
if (palette_size == 256 && pMasterPalette)
{
png_colorp pal = palette;
INT32 i;
usepal = true;
for (i = 0; i < 256; i++)
{
UINT32 rgb = R_PutRgbaRGBA(pal->red, pal->green, pal->blue, 0xFF);
if (rgb != pMasterPalette[i].rgba)
{
usepal = false;
break;
}
pal++;
}
}
}
// If any of the tRNS colors have an alpha lower than 0xFF, and that
// color is present on the image, the palette flag is disabled.
png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values);
if (trans && trans_num == 256)
if (usepal)
{
int i;
for (i = 0; i < trans_num; i++)
png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values);
if (trans && trans_num == 256)
{
// libpng will transform this image into RGB even if
// the transparent index does not exist in the image,
// and there is no way around that.
if (trans[i] < 0xFF)
INT32 i;
for (i = 0; i < trans_num; i++)
{
usepal = false;
break;
// libpng will transform this image into RGB even if
// the transparent index does not exist in the image,
// and there is no way around that.
if (trans[i] < 0xFF)
{
usepal = false;
break;
}
}
}
}

View File

@ -272,7 +272,7 @@ if(${SDL2_FOUND})
endif()
target_compile_definitions(SRB2SDL2 PRIVATE
-DDDIRECTFULLSCREEN -DHAVE_SDL
-DDIRECTFULLSCREEN -DHAVE_SDL
)
## strip debug symbols into separate file when using gcc.

View File

@ -189,7 +189,7 @@ boolean OglSdlSurface(INT32 w, INT32 h)
SetupGLFunc4();
granisotropicmode_cons_t[1].value = maximumAnisotropy;
glanisotropicmode_cons_t[1].value = maximumAnisotropy;
SDL_GL_SetSwapInterval(cv_vidwait.value ? 1 : 0);

View File

@ -2074,14 +2074,59 @@ int W_VerifyNMUSlumps(const char *filename)
{"CLM", 3}, // Colormap changes
{"TRANS", 5}, // Translucency map changes
{"CONSBACK", 8}, // Console Background graphic
{"SAVE", 4}, // Save Select graphics here and below
{"BLACXLVL", 8},
{"GAMEDONE", 8},
{"CONT", 4}, // Continue icons on saves (probably not used anymore)
{"STNONEX", 7}, // "X" graphic
{"ULTIMATE", 8}, // Ultimate no-save
{"CRFNT", 5}, // Sonic 1 font changes
{"NTFNT", 5}, // Character Select font changes
{"NTFNO", 5}, // Character Select font (outline)
{"LTFNT", 5}, // Level title font changes
{"TTL", 3}, // Act number changes
{"STCFN", 5}, // Console font changes
{"TNYFN", 5}, // Tiny console font changes
{"STLIVE", 6}, // Life graphics, background and the "X" that shows under skin's HUDNAME
{"CROSHAI", 7}, // First person crosshairs
{"INTERSC", 7}, // Default intermission backgrounds (co-op)
{"STT", 3}, // Acceptable HUD changes (Score Time Rings)
{"YB_", 3}, // Intermission graphics, goes with the above
{"M_", 2}, // As does menu stuff
{"RESULT", 6}, // Used in intermission for competitive modes, above too :3
{"RACE", 4}, // Race mode graphics, 321go
{"M_", 2}, // Menu stuff
{"LT", 2}, // Titlecard changes
{"SLID", 4}, // Continue
{"CONT", 4},
{"MINICAPS", 8}, // NiGHTS graphics here and below
{"BLUESTAT", 8}, // Sphere status
{"BYELSTAT", 8},
{"ORNGSTAT", 8},
{"REDSTAT", 7},
{"YELSTAT", 7},
{"NBRACKET", 8},
{"NGHTLINK", 8},
{"NGT", 3}, // Link numbers
{"NARROW", 6},
{"NREDAR", 6},
{"NSS", 3},
{"NBON", 4},
{"NRNG", 4},
{"NHUD", 4},
{"CAPS", 4},
{"DRILL", 5},
{"GRADE", 5},
{"MINUS5", 6},
{"MUSICDEF", 8}, // Song definitions (thanks kart)
{"SHADERS", 7}, // OpenGL shader definitions
{"SH_", 3}, // GLSL shader
{NULL, 0},
};