diff --git a/engine/Makefile b/engine/Makefile index 4b9a65af..bc30c859 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -1516,7 +1516,7 @@ nacl-dbg: #makes an ant project for us droid/build.xml: - -cd droid && PATH=$$PATH:$(ANDROID_HOME)/tools:$(ANDROID_NDK_ROOT) $(ANDROID_SCRIPT) update project -t android-8 -p . -n FTEDroid + -cd droid && PATH=$$PATH:$(realpath $(ANDROID_HOME)/tools):$(realpath $(ANDROID_NDK_ROOT)) $(ANDROID_SCRIPT) update project -t android-8 -p . -n FTEDroid #build FTE as a library, then build the java+package (release) droid/ftekeystore: @@ -1537,7 +1537,8 @@ else @$(JAVATOOL)keytool -genkey -keystore $@ -alias autogen -keyalg RSA -keysize 2048 -validity 10000 -noprompt $(KEYTOOLARGS) endif -droid-rel: droid/build.xml droid/ftekeystore +droid-rel: + $(MAKE) FTE_TARGET=droid droid/build.xml droid/ftekeystore $(foreach a, $(DROID_ARCH), $(MAKE) FTE_TARGET=droid gl-rel DROID_ARCH=$a; ) @$(foreach a, $(DROID_ARCH), mkdir -p droid/libs/$a; ) -@$(foreach a, $(DROID_ARCH), cp $(RELEASE_DIR)/gl_droid-$a/libftedroid.so droid/libs/$a/libftedroid.so; ) @@ -1563,7 +1564,8 @@ endif -rm -f $(RELEASE_DIR)/FTEDroid.apk $(ANDROID_HOME)/tools/zipalign 4 droid/bin/FTEDroid-release-unsigned.apk $(RELEASE_DIR)/FTEDroid.apk -droid-opt: droid/build.xml droid/ftekeystore +droid-opt: + $(MAKE) FTE_TARGET=droid droid/build.xml droid/ftekeystore $(MAKE) FTE_TARGET=droid gl-rel mkdir -p droid/libs/armeabi @cp $(RELEASE_DIR)/libftedroid.so droid/libs/armeabi/ @@ -1571,7 +1573,8 @@ droid-opt: droid/build.xml droid/ftekeystore cp droid/bin/FTEDroid-unsigned.apk $(RELEASE_DIR)/FTEDroid.apk #build FTE as a library, then build the java+package (release). also installs it onto the 'current' device. -droid-dbg: droid/build.xml +droid-dbg: + $(MAKE) FTE_TARGET=droid droid/build.xml $(foreach a, $(DROID_ARCH), $(MAKE) FTE_TARGET=droid gl-dbg DROID_ARCH=$a; ) @$(foreach a, $(DROID_ARCH), mkdir -p droid/libs/$a; ) -@$(foreach a, $(DROID_ARCH), cp $(DEBUG_DIR)/gl_droid-$a/libftedroid.so droid/libs/$a/libftedroid.so; ) diff --git a/engine/client/r_d3.c b/engine/client/r_d3.c index 8f9f69f2..e44d18d6 100644 --- a/engine/client/r_d3.c +++ b/engine/client/r_d3.c @@ -6,10 +6,10 @@ #endif void Mod_SetParent (mnode_t *node, mnode_t *parent); -int D3_LeafnumForPoint (struct model_s *model, vec3_t point); +static int D3_LeafnumForPoint (struct model_s *model, vec3_t point); #ifndef SERVERONLY -qboolean Mod_LoadMap_Proc(model_t *model, char *data) +static qboolean Mod_LoadMap_Proc(model_t *model, char *data) { char token[256]; int ver = 0; @@ -359,7 +359,7 @@ qboolean R_CullBox (vec3_t mins, vec3_t maxs); static int walkno; /*convert each portal to a 2d box, because its much much simpler than true poly clipping*/ -void D3_WalkPortal(model_t *mod, int start, vec_t bounds[4], unsigned char *vis) +static void D3_WalkPortal(model_t *mod, int start, vec_t bounds[4], unsigned char *vis) { int i; portal_t *p; @@ -462,14 +462,15 @@ void D3_GenerateAreas(model_t *mod) #endif //edict system as opposed to q2 game dll system. -void D3_FindTouchedLeafs (struct model_s *model, struct pvscache_s *ent, vec3_t cullmins, vec3_t cullmaxs) +static void D3_FindTouchedLeafs (struct model_s *model, struct pvscache_s *ent, vec3_t cullmins, vec3_t cullmaxs) { } -qbyte *D3_LeafPVS (struct model_s *model, int num, qbyte *buffer, unsigned int buffersize) +static qbyte *D3_LeafPVS (struct model_s *model, int num, qbyte *buffer, unsigned int buffersize) { + memset(buffer, 0xff, buffersize); return buffer; } -int D3_LeafnumForPoint (struct model_s *model, vec3_t point) +static int D3_LeafnumForPoint (struct model_s *model, vec3_t point) { float p; int c; @@ -485,16 +486,16 @@ int D3_LeafnumForPoint (struct model_s *model, vec3_t point) } return 0; } -unsigned int D3_FatPVS (struct model_s *model, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean merge) +static unsigned int D3_FatPVS (struct model_s *model, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean merge) { return 0; } -void D3_StainNode (struct mnode_s *node, float *parms) +static void D3_StainNode (struct mnode_s *node, float *parms) { } -void D3_LightPointValues (struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) +static void D3_LightPointValues (struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) { /*basically require rtlighting for any light*/ VectorClear(res_diffuse); @@ -504,7 +505,7 @@ void D3_LightPointValues (struct model_s *model, vec3_t point, vec3_t res_diffus } -qboolean D3_EdictInFatPVS (struct model_s *model, struct pvscache_s *edict, qbyte *pvsbuffer) +static qboolean D3_EdictInFatPVS (struct model_s *model, struct pvscache_s *edict, qbyte *pvsbuffer) { int i; for (i = 0; i < edict->num_leafs; i++) @@ -840,7 +841,7 @@ return; D3_RecursiveSurfCheck (node->child[side^1], midf, p2f, mid, p2); } -qboolean D3_Trace (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, unsigned int hitcontentsmask, struct trace_s *trace) +static qboolean D3_Trace (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, unsigned int hitcontentsmask, struct trace_s *trace) { int i; float e1,e2; @@ -922,7 +923,7 @@ qboolean D3_Trace (struct model_s *model, int hulloverride, int frame, vec3_t ax return false; } -unsigned int D3_PointContents (struct model_s *model, vec3_t axis[3], vec3_t p) +static unsigned int D3_PointContents (struct model_s *model, vec3_t axis[3], vec3_t p) { cm_node_t *node = model->cnodes; cm_brush_t *brush; @@ -975,7 +976,7 @@ unsigned int D3_PointContents (struct model_s *model, vec3_t axis[3], vec3_t p) #define ensurenewtoken(t) buf = COM_ParseOut(buf, token, sizeof(token)); if (strcmp(token, t)) break; -int D3_ParseContents(char *str) +static int D3_ParseContents(char *str) { char *e, *n; unsigned int contents = 0; @@ -1305,6 +1306,7 @@ qboolean D3_LoadMap_CollisionMap(model_t *mod, char *buf) mod->funcs.StainNode = D3_StainNode; mod->funcs.LightPointValues = D3_LightPointValues; mod->funcs.EdictInFatPVS = D3_EdictInFatPVS; + mod->funcs.LeafPVS = D3_LeafPVS; mod->fromgame = fg_doom3; diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 5fab4abd..a494a78d 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -1319,7 +1319,8 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, } realtime = oldrealtime; - key_dest = oldkeydest; + if (oldkeydest != key_console) + key_dest = oldkeydest; editormodal = false; } diff --git a/engine/common/fs.c b/engine/common/fs.c index 92c6d602..e50d5290 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -2148,7 +2148,7 @@ const gamemode_info_t gamemode_info[] = { {"-halflife", "hl", "FTE-HalfLife", {"valve/liblist.gam"}, NULL, {"valve", "ftehl"}, "Half-Life"}, //the rest are not supported in any real way. maps-only mostly, if that - {"-q4", "q4", "FTE-Quake4", {"q4base/pak00.pk4"}, NULL, {"q4base", "fteq4"}, "Quake 4"}, + {"-quake4", "q4", "FTE-Quake4", {"q4base/pak00.pk4"}, NULL, {"q4base", "fteq4"}, "Quake 4"}, {"-et", "et", "FTE-EnemyTerritory", {"etmain/pak0.pk3"}, NULL, {"etmain", "fteet"}, "Wolfenstein - Enemy Territory"}, {"-jk2", "jk2", "FTE-JK2", {"base/assets0.pk3"}, NULL, {"base", "fte"}, "Jedi Knight II: Jedi Outcast"}, @@ -2156,6 +2156,7 @@ const gamemode_info_t gamemode_info[] = { {"-doom", "doom", "FTE-Doom", {"doom.wad"}, NULL, {"*doom.wad", "ftedoom"}, "Doom"}, {"-doom2", "doom2", "FTE-Doom2", {"doom2.wad"}, NULL, {"*doom2.wad", "ftedoom"}, "Doom2"}, + {"-doom3", "doom3", "FTE-Doom3", {"doom3.wad"}, NULL, {"*doom2.wad", "ftedoom"}, "Doom2"}, {NULL} }; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 1d87a308..4020fd99 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -2123,9 +2123,10 @@ static shaderkey_t shaderkeys[] = {"dp_camera", Shader_DP_Camera}, /*doom3 compat*/ - {"diffusemap", Shader_DiffuseMap}, - {"bumpmap", NULL}, - {"specularmap", NULL}, + {"diffusemap", Shader_DiffuseMap}, //macro for "{\nstage diffusemap\nmap \n}" + {"bumpmap", NULL}, //macro for "{\nstage bumpmap\nmap \n}" + {"specularmap", NULL}, //macro for "{\nstage specularmap\nmap \n}" + {"discrete", NULL}, {"nonsolid", NULL}, {"noimpact", NULL}, {"translucent", Shader_Translucent}, @@ -2136,6 +2137,19 @@ static shaderkey_t shaderkeys[] = {NULL, NULL} }; +static struct +{ + char *name; + char *body; +} shadermacros[] = +{ + {"decal_macro", "polygonOffset 1\ndiscrete\nsort decal\nnoShadows"}, +// {"diffusemap", "{\nblend diffusemap\nmap %1\n}"}, +// {"bumpmap", "{\nblend bumpmap\nmap %1\n}"}, +// {"specularmap", "{\nblend specularmap\nmap %1\n}"}, + {NULL} +}; + // =============================================================== static qboolean Shaderpass_MapGen (shader_t *shader, shaderpass_t *pass, char *tname) @@ -2550,33 +2564,25 @@ static void Shaderpass_BlendFunc (shader_t *shader, shaderpass_t *pass, char **p { char *token; + //reset to defaults pass->shaderbits &= ~(SBITS_BLEND_BITS); + pass->stagetype = ST_AMBIENT; token = Shader_ParseString (ptr); - if ( !Q_stricmp (token, "diffusemap")) - { - //if the shader is translucent then this pass must be meant to be blended - if (shader->flags & SHADER_BLEND) - pass->shaderbits |= SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - else - pass->shaderbits |= SBITS_SRCBLEND_NONE | SBITS_DSTBLEND_NONE; - } + if ( !Q_stricmp (token, "bumpmap")) //doom3 is awkward... + pass->stagetype = ST_BUMPMAP; + else if ( !Q_stricmp (token, "specularmap")) //doom3 is awkward... + pass->stagetype = ST_SPECULARMAP; + else if ( !Q_stricmp (token, "diffusemap")) //doom3 is awkward... + pass->stagetype = ST_DIFFUSEMAP; else if ( !Q_stricmp (token, "blend")) - { pass->shaderbits |= SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if (!Q_stricmp (token, "filter")) - { pass->shaderbits |= SBITS_SRCBLEND_DST_COLOR | SBITS_DSTBLEND_ZERO; - } else if (!Q_stricmp (token, "add")) - { pass->shaderbits |= SBITS_SRCBLEND_ONE | SBITS_DSTBLEND_ONE; - } else if (!Q_stricmp (token, "replace")) - { pass->shaderbits |= SBITS_SRCBLEND_NONE | SBITS_DSTBLEND_NONE; - } else { pass->shaderbits |= Shader_BlendFactor(token, false); @@ -3296,6 +3302,7 @@ void Shader_Readpass (shader_t *shader, char **ptr) pass->tcgen = TC_GEN_BASE; pass->numtcmods = 0; pass->numMergedPasses = 1; + pass->stagetype = ST_AMBIENT; if (shader->flags & SHADER_NOMIPMAPS) pass->flags |= SHADER_PASS_NOMIPMAP; @@ -3364,8 +3371,31 @@ void Shader_Readpass (shader_t *shader, char **ptr) Con_Printf("if statements without endif in shader %s\n", shader->name); } + if (!ignore) + { + switch(pass->stagetype) + { + case ST_DIFFUSEMAP: + if (pass->texgen == T_GEN_SINGLEMAP) + shader->defaulttextures.bump = pass->anim_frames[0]; + break; + case ST_AMBIENT: + break; + case ST_BUMPMAP: + if (pass->texgen == T_GEN_SINGLEMAP) + shader->defaulttextures.bump = pass->anim_frames[0]; + ignore = true; + break; + case ST_SPECULARMAP: + if (pass->texgen == T_GEN_SINGLEMAP) + shader->defaulttextures.specular = pass->anim_frames[0]; + ignore = true; + break; + } + } + // check some things - if ( ignore ) + if (ignore) { Shader_FreePass (pass); shader->numpasses--; @@ -3618,6 +3648,11 @@ void Shader_Finish (shader_t *s) { int i; shaderpass_t *pass; + + //FIXME: reorder doom3 stages. + //put diffuse first. give it a lightmap pass also, if we found a diffuse one with no lightmap. + //then the ambient stages. + //and forget about the bump/specular stages as we don't support them and already stripped them. if (s->flags & SHADER_SKY) { @@ -4727,81 +4762,115 @@ void Shader_Default2D(char *shortname, shader_t *s, const void *genargs) } } -//loads a shader string into an existing shader object, and finalises it and stuff -static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode) +qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode, int *conddepth, int maxconddepth, int *cond) { char *token; - int conddepth = 0; - int cond[8] = {0}; + #define COND_IGNORE 1 #define COND_IGNOREPARENT 2 #define COND_ALLOWELSE 4 + token = COM_ParseExt (shadersource, true, true); + + if ( !token[0] ) + return true; + else if (!Q_stricmp(token, "if")) + { + if (*conddepth+1 == maxconddepth) + { + Con_Printf("if statements nest too deeply in shader %s\n", s->name); + return false; + } + *conddepth+=1; + cond[*conddepth] = (!Shader_EvaluateCondition(s, shadersource)?COND_IGNORE:0); + cond[*conddepth] |= COND_ALLOWELSE; + if (cond[*conddepth-1] & (COND_IGNORE|COND_IGNOREPARENT)) + cond[*conddepth] |= COND_IGNOREPARENT; + } + else if (!Q_stricmp(token, "endif")) + { + if (!*conddepth) + { + Con_Printf("endif without if in shader %s\n", s->name); + return false; + } + *conddepth-=1; + } + else if (!Q_stricmp(token, "else")) + { + if (cond[*conddepth] & COND_ALLOWELSE) + { + cond[*conddepth] ^= COND_IGNORE; + cond[*conddepth] &= ~COND_ALLOWELSE; + } + else + Con_Printf("unexpected else statement in shader %s\n", s->name); + } + else if (cond[*conddepth] & (COND_IGNORE|COND_IGNOREPARENT)) + { + //eat it. + while (**shadersource) + { + token = COM_ParseExt(shadersource, false, true); + if ( !token[0] ) + break; + } + } + else + { + int i; + for (i = 0; shadermacros[i].name; i++) + { + if (!Q_stricmp (token, shadermacros[i].name)) + { +#define SHADER_MACRO_ARGS 6 + int argn = 0; + char *body; + char arg[SHADER_MACRO_ARGS][256]; + int cond = 0; + //parse args until the end of the line + while (*shadersource) + { + token = COM_ParseExt(shadersource, false, true); + if ( !token[0] ) + { + break; + } + if (argn <= SHADER_MACRO_ARGS) + { + Q_strncpyz(arg[argn], token, sizeof(arg[argn])); + argn++; + } + } + body = shadermacros[i].body; + Shader_ReadShaderTerms(s, &body, parsemode, &cond, 0, &cond); + return true; + } + } + if (token[0] == '}') + return false; + else if (token[0] == '{') + Shader_Readpass(s, shadersource); + else if (Shader_Parsetok(s, NULL, shaderkeys, token, shadersource)) + return false; + } + return true; +} + +//loads a shader string into an existing shader object, and finalises it and stuff +static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode) +{ + int conddepth = 0; + int cond[8]; + cond[0] = 0; shaderparsemode = parsemode; // set defaults s->flags = SHADER_CULL_FRONT; s->uses = 1; - while (shadersource) + while (Shader_ReadShaderTerms(s, &shadersource, parsemode, &conddepth, sizeof(cond)/sizeof(cond[0]), cond)) { - token = COM_ParseExt (&shadersource, true, true); - - if ( !token[0] ) - continue; - else if (!Q_stricmp(token, "if")) - { - if (conddepth+1 == sizeof(cond)/sizeof(cond[0])) - { - Con_Printf("if statements nest too deeply in shader %s\n", s->name); - break; - } - conddepth++; - cond[conddepth] = (!Shader_EvaluateCondition(s, &shadersource)?COND_IGNORE:0); - cond[conddepth] |= COND_ALLOWELSE; - if (cond[conddepth-1] & (COND_IGNORE|COND_IGNOREPARENT)) - cond[conddepth] |= COND_IGNOREPARENT; - } - else if (!Q_stricmp(token, "endif")) - { - if (!conddepth) - { - Con_Printf("endif without if in shader %s\n", s->name); - break; - } - conddepth--; - } - else if (!Q_stricmp(token, "else")) - { - if (cond[conddepth] & COND_ALLOWELSE) - { - cond[conddepth] ^= COND_IGNORE; - cond[conddepth] &= ~COND_ALLOWELSE; - } - else - Con_Printf("unexpected else statement in shader %s\n", s->name); - } - else if (cond[conddepth] & (COND_IGNORE|COND_IGNOREPARENT)) - { - //eat it. - while (*shadersource) - { - token = COM_ParseExt(&shadersource, false, true); - if ( !token[0] ) - { - break; - } - } - } - else - { - if (token[0] == '}') - break; - else if (token[0] == '{') - Shader_Readpass(s, &shadersource); - else if (Shader_Parsetok(s, NULL, shaderkeys, token, &shadersource)) - break; - } } if (conddepth) diff --git a/engine/gl/shader.h b/engine/gl/shader.h index befe1463..5e71240d 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -1,3 +1,32 @@ +/* +Copyright spike. GNU GPL V2. etc. +Much of this file and the parser derives originally from qfusion by vic. + +Quake1 rendering works by: +Draw everything in depth order and stall lots from switching textures. +draw transparent water surfaces last. + +Quake3 rendering works by: +generate a batch for every model+shader in the world. +sort batches by shader sort key, entity, shader. +draw surfaces. + +Doom3 rendering works by: +generate a batch for every model+shader in the world. +sort batches by shader sort key, entity, shader. +depth is drawn (yay alpha masked surfaces) +for each light+batch + draw each bump/diffuse/specular stage. combine to one pass if that ordering is not maintained. switch diffuse/specular if needed +ambient stages from each batch are added over the top. + +FTE rtlight rendering works by: +generate a batch for every model+shader in the world. +sort batches by shader sort key, entity, shader. +draw surfaces. if rtworld_lightmaps is 0 and there's no additive stuff, draw as black, otherwise just scale lightmap passes. +lights are then added over the top based upon the diffusemap, bumpmap and specularmap, and without any pass-specific info (no tcmods). +*/ + + #ifndef SHADER_H #define SHADER_H typedef void (shader_gen_t)(char *name, shader_t*, const void *args); @@ -238,6 +267,13 @@ typedef struct shaderpass_s { T_GEN_3DMAP, //use a 3d texture instead, otherwise T_GEN_SINGLEMAP. } texgen; + enum { + ST_DIFFUSEMAP, + ST_AMBIENT, + ST_BUMPMAP, + ST_SPECULARMAP + } stagetype; + enum { SHADER_PASS_CLAMP = 1<<0, //needed for d3d's sampler states, infects image flags SHADER_PASS_NEAREST = 1<<1, //needed for d3d's sampler states, infects image flags diff --git a/engine/sw/sw_vidwin.c b/engine/sw/sw_vidwin.c index bc8497f7..8c316fa6 100644 --- a/engine/sw/sw_vidwin.c +++ b/engine/sw/sw_vidwin.c @@ -432,7 +432,6 @@ LONG WINAPI MainWndProc ( r.right = nw*usingstretch; r.bottom = nh*usingstretch; AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW, FALSE, 0); - vid.recalc_refdef = true; if (move) MoveWindow(hWnd, nl, nt, r.right - r.left, r.bottom - r.top, true); else diff --git a/plugins/jabber/jabberclient.c b/plugins/jabber/jabberclient.c index 626293d3..96900141 100644 --- a/plugins/jabber/jabberclient.c +++ b/plugins/jabber/jabberclient.c @@ -4304,6 +4304,9 @@ qintptr_t JCL_Shutdown(qintptr_t *args) if (jcl) JCL_CloseConnection(jcl, false); } + +// if (_CrtDumpMemoryLeaks()) +// OutputDebugStringA("Leaks detected\n"); return true; }