From 6a2513e5c51d1e9905551ca25ce1b42304b6b49f Mon Sep 17 00:00:00 2001 From: "Kevin \"Hirato Kirata\" Meyer" Date: Fri, 19 Apr 2019 21:09:01 +0800 Subject: [PATCH] import from tesseract SVN 2019-04-19 eihrul (51): fix clang warnings reset UI world state when building always init color in slot view findfragdatalocs fix remove gamma name hack fix hvecs on gcc 7 non-loc weapon switch sound linkedpart cleanups fix translation of linked models don't remove the current window if we're using it disable audio on SDL 2.0.6 get rid of scale.h generateshader fix model shader fixes force shader fix add nospec flag to lights flushpart fix nospec light shader modelloader cleanups decal shader fixes premultiply decal diffuse textures decal shader parallax fix decal shader normals fix add model flags to force shadows add bumpblend shader parameter for decals limit progress fps MDL_FORCETRANSPARENT option better collision with clip surfaces remove pointincube collision guard space classifyface fix set null shader on dummy decal map name cleanups vote fix update VC toolchain map cfg fix fix zipstream seek to end limit BIH mesh tris fix server gunselect addgban fix warning fix vrotate 6 and 7 texrotation cleanups getpubkey command getservauth command rndstr command rndstr fix rndstr cleanup processmasterinput fix ragdoll commands should check if model is loading make maxsoundradius read-only --- config/glsl/decal.cfg | 148 +++++++++++---------------- config/glsl/deferred.cfg | 10 +- src/engine/animmodel.h | 70 +++++++++++-- src/engine/bih.h | 2 + src/engine/blend.cpp | 4 +- src/engine/command.cpp | 18 +++- src/engine/engine.h | 8 +- src/engine/iqm.h | 32 +----- src/engine/main.cpp | 10 ++ src/engine/md3.h | 29 +----- src/engine/md5.h | 5 +- src/engine/obj.h | 29 +----- src/engine/octa.cpp | 197 ++++++++++++++++++++++++------------ src/engine/octaedit.cpp | 9 +- src/engine/octarender.cpp | 28 +++-- src/engine/physics.cpp | 79 ++++++++------- src/engine/pvs.cpp | 2 +- src/engine/renderlights.cpp | 22 ++-- src/engine/rendermodel.cpp | 9 +- src/engine/renderva.cpp | 12 ++- src/engine/scale.h | 122 ---------------------- src/engine/server.cpp | 3 +- src/engine/shader.cpp | 9 +- src/engine/skelmodel.h | 14 ++- src/engine/smd.h | 32 +----- src/engine/sound.cpp | 11 +- src/engine/texture.cpp | 173 ++++++++++++++++++++++--------- src/engine/texture.h | 9 ++ src/engine/ui.cpp | 7 +- src/engine/vertmodel.h | 4 +- src/engine/world.cpp | 9 +- src/engine/worldio.cpp | 23 ++++- src/includes.mk | 2 +- src/shared/crypto.cpp | 25 ++++- src/shared/geom.h | 4 +- src/shared/iengine.h | 6 +- src/shared/tools.cpp | 2 +- src/shared/zip.cpp | 1 + src/windows/lamiae.cbp | 1 - 39 files changed, 628 insertions(+), 552 deletions(-) delete mode 100644 src/engine/scale.h diff --git a/config/glsl/decal.cfg b/config/glsl/decal.cfg index 7f9744f8..28c1da2b 100644 --- a/config/glsl/decal.cfg +++ b/config/glsl/decal.cfg @@ -36,7 +36,7 @@ decalvariantshader = [ if (dtopt "R") [ defuniformparam "envscale" 1 1 1 // reflectivity map multiplier ] [if (dtopt "r") [ - defuniformparam "envscale" 0.2 0.2 0.2 // reflectivity + defuniformparam "envscale" 0.2 0.2 0.2 // reflectivity ]] reuseuniformparam "gloss" 1 // glossiness if (dtopt "S") [ @@ -47,6 +47,9 @@ decalvariantshader = [ if (dtopt "p") [ defuniformparam "parallaxscale" 0.06 -0.03 // parallax scaling ] + if (dtopt "n") [ + defuniformparam "bumpblend" 1 // alpha-blend strength for normals + ] variantshader $stype $arg1 $srow [ attribute vec4 vvertex; @(? (dtopt "n") [ @@ -117,123 +120,92 @@ decalvariantshader = [ void main(void) { @(if (dtopt "n") [result [ - @(? (|| (dtopt "p") [&& (! (dtopt "1")) (dtopt "r")]) [ - vec3 camvecn = normalize(camvec); - ]) - @(? (dtopt "p") [ float height = texture2D(normalmap, texcoord0.xy).a; - vec2 dtc = texcoord0 + (camvecn * world).xy*(height*parallaxscale.x + parallaxscale.y); + vec3 camvecn = normalize(camvec); + vec2 dtc = texcoord0.xy + (camvecn * world).xy*(height*parallaxscale.x + parallaxscale.y); ] [ #define dtc texcoord0.xy ]) - vec4 diffuse = texture2D(diffusemap, dtc); - @(? (|| (! (dtopt "0")) (dtopt "r")) [ vec3 bump = texture2D(normalmap, dtc).rgb*2.0 - 1.0; vec3 bumpw = world * bump; + #define nvec bumpw ]) - - @(if (dtopt "1") [ - ? (dtopt "g") [ - vec3 gcolor = diffuse.rgb*colorparams.rgb; - ] - ] [result [ - gcolor.rgb = diffuse.rgb*colorparams.rgb; - - @(if (dtopt "r") [result [ - float invfresnel = dot(camvecn, bumpw); - vec3 rvec = 2.0*bumpw*invfresnel - camvecn; - vec3 reflect = textureCube(envmap, rvec).rgb; - @(? (dtopt "R") [ - vec3 rmod = envscale.xyz*diffuse.a; - ] [ - #define rmod envscale.xyz - ]) - gcolor.rgb = mix(gcolor.rgb, reflect, rmod*clamp(1.0 - invfresnel, 0.0, 1.0)); - ]]) - ]]) - - @(if (dtopt "g") [result [ - vec4 glowspec = texture2D(glowmap, dtc); - #define glow glowspec.rgb - #define spec glowspec.a - glow *= @(? (dtopt "G") [mix(glowcolor.xyz, pulseglowcolor.xyz, pulse)] [glowcolor.xyz]); - ]]) - - @(if (dtopt "0") [result [ - @(if (&& (dtopt "S") [! (dtopt "g")]) [result [ - float spec = @(? (dtopt "p") [texture2D(glowmap, dtc).r] [texture2D(normalmap, dtc).a]); - ]]) - @(gspecpack [gloss.x] (if (dtopt "s") [? (dtopt "S") [spec * specscale.x] [specscale.x]])) - ]]) - - @(if (dtopt "g") [gglowpack glow packnorm]) - - @(if (! (dtopt "0")) [result [ - bumpw = normalize(bumpw); - @(gnormpackdef bumpw packnorm) - ]]) ]] [result [ #define dtc texcoord0.xy - vec4 diffuse = texture2D(diffusemap, dtc); + ]]) - @(if (dtopt "1") [ - ? (dtopt "g") [ - vec3 gcolor = diffuse.rgb*colorparams.rgb; - ] - ] [result [ - gcolor.rgb = diffuse.rgb*colorparams.rgb; + vec4 diffuse = texture2D(diffusemap, dtc); - @(if (dtopt "r") [result [ - vec3 camvecn = normalize(camvec); - float invfresnel = dot(camvecn, nvec); - vec3 rvec = 2.0*nvec*invfresnel - camvecn; - vec3 reflect = textureCube(envmap, rvec).rgb; - @(? (dtopt "R") [ - vec3 rmod = envscale.xyz*diffuse.a; - ] [ - #define rmod envscale.xyz - ]) - gcolor.rgb = mix(gcolor.rgb, reflect, rmod*clamp(1.0 - invfresnel, 0.0, 1.0)); - ]]) - ]]) + @(if (dtopt "g") [result [ + vec4 glowspec = texture2D(glowmap, dtc); + #define glow glowspec.rgb + #define spec glowspec.a + glow *= @(? (dtopt "G") [mix(glowcolor.xyz, pulseglowcolor.xyz, pulse)] [glowcolor.xyz]); + glow *= diffuse.a; + ]]) - @(if (dtopt "g") [result [ - vec4 glowspec = texture2D(glowmap, dtc); - #define glow glowspec.rgb - #define spec glowspec.a - glow *= @(? (dtopt "G") [mix(glowcolor.xyz, pulseglowcolor.xyz, pulse)] [glowcolor.xyz]); + @(if (dtopt "0") [result [ + @(if (&& (dtopt "S") [! (dtopt "g")]) [result [ + float spec = @(? (|| (! (dtopt "n")) (dtopt "p")) [texture2D(glowmap, dtc).r] [texture2D(normalmap, dtc).a]); ]]) + @(gspecpack [gloss.x] (if (dtopt "s") [? (dtopt "S") [spec * specscale.x] [specscale.x]])) + ]]) + + @(if (dtopt "1") [ + ? (dtopt "g") [ + vec3 gcolor = diffuse.rgb*colorparams.rgb; + ] + ] [result [ + gcolor.rgb = diffuse.rgb*colorparams.rgb; - @(if (dtopt "0") [result [ - @(? (&& (dtopt "S") [! (dtopt "g")]) [ - float spec = texture2D(glowmap, dtc).r; + @(if (dtopt "r") [result [ + @(? (|| (! (dtopt "n")) (! (dtopt "p"))) [ + vec3 camvecn = normalize(camvec); ]) - @(gspecpack [gloss.x] (if (dtopt "s") [? (dtopt "S") [spec * specscale.x] [specscale.x]])) + float invfresnel = dot(camvecn, nvec); + vec3 rvec = 2.0*nvec*invfresnel - camvecn; + vec3 reflect = textureCube(envmap, rvec).rgb * diffuse.a; + @(? (dtopt "R") [ + vec3 rmod = envscale.xyz*spec; + ] [ + #define rmod envscale.xyz + ]) + reflect *= diffuse.a; + gcolor.rgb = mix(gcolor.rgb, reflect, rmod*clamp(1.0 - invfresnel, 0.0, 1.0)); ]]) + ]]) - @(if (dtopt "g") [gglowpack glow packnorm]) + @(if (dtopt "g") [gglowpack glow packnorm]) - @(if (! (dtopt "0")) [result [ - vec3 normal = normalize(nvec); - @(gnormpackdef normal packnorm) - ]]) + @(if (! (dtopt "0")) [result [ + vec3 normal = normalize(nvec); + @(gnormpackdef normal packnorm) ]]) - float alpha = clamp(texcoord0.z, 0.0, 1.0) * clamp(texcoord0.w, 0.0, 1.0) * diffuse.a; + float inside = clamp(texcoord0.z, 0.0, 1.0) * clamp(texcoord0.w, 0.0, 1.0); + float alpha = inside * diffuse.a; @(cond [dtopt "0"] [result [ + gcolor.rgb *= inside; + gcolor.a *= alpha; gcolorblend = vec4(alpha); ]] [dtopt "1"] [ ? $usepacknorm [ - gnormal.a = alpha; + gnormal.a = alpha * bumpblend.x; ] [ - gnormalblend = vec4(alpha); + gnormalblend = vec4(alpha * bumpblend.x); ] ] [result [ + gcolor.rgb *= inside; gcolor.a = alpha; - gnormal.a = @(? (dtopt "b") [0.0] [alpha]); + @(? (dtopt "b") [ + gnormal = vec4(0.0); + ] [ + gnormal.rgb *= alpha * bumpblend.x; + gnormal.a = alpha * bumpblend.x; + ]) ]]) } ] @@ -246,7 +218,7 @@ decalshader = [ if $maxdualdrawbufs [ decalvariantshader @@arg1 @@(concatword $arg2 "0") if @@(! (dtopt "b")) [ - decalvariantshader @@arg1 @@(concatword $arg2 "1") + decalvariantshader @@@arg1 @@@(concatword $arg2 "1") ] ] [ decalvariantshader @@arg1 @@arg2 diff --git a/config/glsl/deferred.cfg b/config/glsl/deferred.cfg index 0bb8bb30..cfb9d874 100644 --- a/config/glsl/deferred.cfg +++ b/config/glsl/deferred.cfg @@ -76,6 +76,7 @@ lazyshader 0 msaaedgedetect [ // b -> combined base/light variants // d -> avatar shadow dist bias variants // D -> disable dist bias +// z -> spec toggle dlopt = [ >= (strstr $deferredlighttype $arg1) 0 ] unpacknormbias = 0.005 @@ -147,7 +148,7 @@ deferredlightvariantshader = [ ]) @(if $numlights [result [ uniform vec4 lightpos[@@numlights]; - uniform vec3 lightcolor[@@numlights]; + uniform vec4 lightcolor[@@numlights]; @(if $spotlight [result [ uniform vec4 spotparams[@@numlights]; ]]) @@ -573,11 +574,14 @@ deferredlightvariantshader = [ ]]) light@[j]facing *= light@[j]invdist; @(if (dlopt "m") [result [ - light += diffuse.rgb*light@[j]facing * lightcolor[@@j] * light@[j]atten; + light += diffuse.rgb*light@[j]facing * lightcolor[@@j].rgb * light@[j]atten; ]] [result [ @(if (= (+ $numlights (dlopt "c")) 1) [unpackspec]) float light@[j]spec = pow(clamp(light@[j]facing*facing - light@[j]invdist*dot(camdir, light@[j]dir), 0.0, 1.0), gloss) * specscale; - light += (diffuse.rgb*light@[j]facing + light@[j]spec) * lightcolor[@@j] * light@[j]atten; + @(if (dlopt "z") [result [ + light@[j]spec *= lightcolor[@@j].a; + ]]) + light += (diffuse.rgb*light@[j]facing + light@[j]spec) * lightcolor[@@j].rgb * light@[j]atten; @(? (= (+ $numlights $baselight) 1) [ float foglerp = clamp(exp2(fogcoord*fogdensity.x)*fogdensity.y, 0.0, 1.0); light *= foglerp; diff --git a/src/engine/animmodel.h b/src/engine/animmodel.h index 4a77039d..0afe274b 100644 --- a/src/engine/animmodel.h +++ b/src/engine/animmodel.h @@ -131,6 +131,7 @@ struct animmodel : model void setshaderparams(mesh &m, const animstate *as, bool skinned = true) { + if(!Shader::lastshader) return; if(key->checkversion() && Shader::lastshader->owner == key) return; Shader::lastshader->owner = key; @@ -218,7 +219,7 @@ struct animmodel : model void setshader(mesh &m, const animstate *as) { - m.setshader(loadshader(), !shadowmapping && colorscale.a < 1 ? 1 : 0); + m.setshader(loadshader(), transparentlayer ? 1 : 0); } void bind(mesh &b, const animstate *as) @@ -322,6 +323,13 @@ struct animmodel : model if(noclip) m.flags |= BIH::MESH_NOCLIP; if(s.cullface > 0) m.flags |= BIH::MESH_CULLFACE; genBIH(m); + while(bih.last().numtris > BIH::mesh::MAXTRIS) + { + BIH::mesh &overflow = bih.dup(); + overflow.tris += BIH::mesh::MAXTRIS; + overflow.numtris -= BIH::mesh::MAXTRIS; + bih[bih.length()-2].numtris = BIH::mesh::MAXTRIS; + } } virtual void genshadowmesh(vector &tris, const matrix4x3 &m) {} @@ -895,7 +903,7 @@ struct animmodel : model matrixstack[matrixpos] = matrixstack[matrixpos-1]; matrixstack[matrixpos].rotate(pitchamount*RAD, oaxis); } - if(!index && !model->translate.iszero()) + if(this == model->parts[0] && !model->translate.iszero()) { if(oldpos == matrixpos) { @@ -918,7 +926,7 @@ struct animmodel : model { linkedpart &link = links[i]; if(!link.p) continue; - link.matrix.translate(links[i].translate, resize); + link.matrix.translate(link.translate, resize); matrixpos++; matrixstack[matrixpos].mul(matrixstack[matrixpos-1], link.matrix); @@ -981,7 +989,7 @@ struct animmodel : model matrixstack[matrixpos] = matrixstack[matrixpos-1]; matrixstack[matrixpos].rotate(pitchamount*RAD, oaxis); } - if(!index && !model->translate.iszero()) + if(this == model->parts[0] && !model->translate.iszero()) { if(oldpos == matrixpos) { @@ -1017,7 +1025,7 @@ struct animmodel : model loopv(links) { linkedpart &link = links[i]; - link.matrix.translate(links[i].translate, resize); + link.matrix.translate(link.translate, resize); matrixpos++; matrixstack[matrixpos].mul(matrixstack[matrixpos-1], link.matrix); @@ -1362,8 +1370,11 @@ struct animmodel : model loopv(parts) parts[i]->cleanup(); } + virtual void flushpart() {} + part &addpart() { + flushpart(); part *p = new part(this, parts.length()); parts.add(p); return *p; @@ -1468,8 +1479,26 @@ struct animmodel : model return false; } - virtual bool loaddefaultparts() + virtual bool flipy() const { return false; } + virtual bool loadconfig() { return false; } + virtual bool loaddefaultparts() { return false; } + virtual void startload() {} + virtual void endload() {} + + bool load() { + startload(); + bool success = loadconfig() && parts.length(); // configured model, will call the model commands below + if(!success) + success = loaddefaultparts(); // model without configuration, try default tris and skin + flushpart(); + endload(); + if(flipy()) translate.y = -translate.y; + + if(!success) return false; + loopv(parts) if(!parts[i]->meshes) return false; + + loaded(); return true; } @@ -1672,18 +1701,41 @@ static inline bool htcmp(const animmodel::shaderparams &x, const animmodel::shad hashtable animmodel::shaderparamskey::keys; int animmodel::shaderparamskey::firstversion = 0, animmodel::shaderparamskey::lastversion = 1; -template struct modelloader +template struct modelloader : BASE { static MDL *loading; static string dir; + modelloader(const char *name) : BASE(name) {} + static bool cananimate() { return true; } static bool multiparted() { return true; } static bool multimeshed() { return true; } + + void startload() + { + loading = (MDL *)this; + } + + void endload() + { + loading = NULL; + } + + bool loadconfig() + { + formatstring(dir, "media/models/%s", BASE::name); + defformatstring(cfgname, "media/models/%s/%s.cfg", BASE::name, MDL::formatname()); + + identflags &= ~IDF_PERSIST; + bool success = execfile(cfgname, false); + identflags |= IDF_PERSIST; + return success; + } }; -template MDL *modelloader::loading = NULL; -template string modelloader::dir = {'\0'}; // crashes clang if "" is used here +template MDL *modelloader::loading = NULL; +template string modelloader::dir = {'\0'}; // crashes clang if "" is used here template struct modelcommands { diff --git a/src/engine/bih.h b/src/engine/bih.h index 259b3ebc..b3a8b7fa 100644 --- a/src/engine/bih.h +++ b/src/engine/bih.h @@ -33,6 +33,8 @@ struct BIH struct mesh { + enum { MAXTRIS = 1<<14 }; + matrix4x3 xform, invxform; matrix3 xformnorm, invxformnorm; float scale, invscale; diff --git a/src/engine/blend.cpp b/src/engine/blend.cpp index 5588a89d..2e3c8ad3 100644 --- a/src/engine/blend.cpp +++ b/src/engine/blend.cpp @@ -960,9 +960,9 @@ ICOMMAND(rotateblendbrush, "i", (int *val), { if(!canpaintblendmap()) return; - int numrots = *val < 0 ? 3 : clamp(*val, 1, 5); BlendBrush *brush = brushes[curbrush]; - brush->reorient(numrots>=2 && numrots<=4, numrots<=2 || numrots==5, (numrots&5)==1); + const texrotation &r = texrotations[*val < 0 ? 3 : clamp(*val, 1, 7)]; + brush->reorient(r.flipx, r.flipy, r.swapxy); }); void paintblendmap(bool msg) diff --git a/src/engine/command.cpp b/src/engine/command.cpp index 655c01cf..73789ff9 100644 --- a/src/engine/command.cpp +++ b/src/engine/command.cpp @@ -2741,7 +2741,7 @@ static const uint *runcode(const uint *code, tagval &result) identflags = oldflags; \ for(int i = 0; i < callargs; i++) \ poparg(*identmap[i]); \ - for(int argmask = aliaslink.usedargs&(~0< 0 ? rnd(*a - *b) + *b : *b)); +ICOMMAND(rndstr, "i", (int *len), +{ + int n = clamp(*len, 0, 10000); + char *s = newstring(n); + for(int i = 0; i < n;) + { + uint r = randomMT(); + for(int j = min(i + 4, n); i < j; i++) + { + s[i] = (r%255) + 1; + r /= 255; + } + } + s[n] = '\0'; + stringret(s); +}); ICOMMAND(tohex, "ii", (int *n, int *p), { diff --git a/src/engine/engine.h b/src/engine/engine.h index c50c2947..4628d0ea 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -228,11 +228,12 @@ extern bool collapsedface(const cube &c, int orient); extern bool touchingface(const cube &c, int orient); extern bool flataxisface(const cube &c, int orient); extern bool collideface(const cube &c, int orient); +extern void genclipbounds(const cube &c, const ivec &co, int size, clipplanes &p); extern int genclipplane(const cube &c, int i, vec *v, plane *clip); -extern void genclipplanes(const cube &c, const ivec &co, int size, clipplanes &p, bool collide = true); +extern void genclipplanes(const cube &c, const ivec &co, int size, clipplanes &p, bool collide = true, bool noclip = false); extern bool visibleface(const cube &c, int orient, const ivec &co, int size, ushort mat = MAT_AIR, ushort nmat = MAT_AIR, ushort matmask = MATF_VOLUME); extern int classifyface(const cube &c, int orient, const ivec &co, int size); -extern int visibletris(const cube &c, int orient, const ivec &co, int size, ushort nmat = MAT_ALPHA, ushort matmask = MAT_ALPHA); +extern int visibletris(const cube &c, int orient, const ivec &co, int size, ushort vmat = MAT_AIR, ushort nmat = MAT_ALPHA, ushort matmask = MAT_ALPHA); extern int visibleorient(const cube &c, int orient); extern void genfaceverts(const cube &c, int orient, ivec v[4]); extern int calcmergedsize(int orient, const ivec &co, int size, const vertinfo *verts, int numverts); @@ -328,6 +329,8 @@ static inline bool bbinsidespot(const vec &origin, const vec &dir, int spot, con extern matrix4 worldmatrix, screenmatrix; +extern int transparentlayer; + extern int gw, gh, gdepthformat, ghasstencil; extern GLuint gdepthtex, gcolortex, gnormaltex, gglowtex, gdepthrb, gstencilrb; extern int msaasamples, msaalight; @@ -642,7 +645,6 @@ extern void clearchanges(int type); // physics extern void modifyorient(float yaw, float pitch); extern void mousemove(int dx, int dy); -extern bool pointincube(const clipplanes &p, const vec &v); extern bool overlapsdynent(const vec &o, float radius); extern void rotatebb(vec ¢er, vec &radius, int yaw, int pitch, int roll = 0); extern float shadowray(const vec &o, const vec &ray, float radius, int mode, extentity *t = NULL); diff --git a/src/engine/iqm.h b/src/engine/iqm.h index 0266193a..a52e19dd 100644 --- a/src/engine/iqm.h +++ b/src/engine/iqm.h @@ -94,9 +94,9 @@ struct iqmvertexarray uint offset; }; -struct iqm : skelmodel, skelloader +struct iqm : skelloader { - iqm(const char *name) : skelmodel(name) {} + iqm(const char *name) : skelloader(name) {} static const char *formatname() { return "iqm"; } int type() const { return MDL_IQM; } @@ -375,7 +375,6 @@ struct iqm : skelmodel, skelloader bool loaddefaultparts() { skelpart &mdl = addpart(); - adjustments.setsize(0); const char *fname = name + strlen(name); do --fname; while(fname >= name && *fname!='/' && *fname!='\\'); fname++; @@ -386,33 +385,6 @@ struct iqm : skelmodel, skelloader mdl.initskins(); return true; } - - bool load() - { - formatstring(dir, "media/models/%s", name); - defformatstring(cfgname, "media/models/%s/iqm.cfg", name); - - loading = this; - identflags &= ~IDF_PERSIST; - if(execfile(cfgname, false) && parts.length()) // configured iqm, will call the iqm* commands below - { - identflags |= IDF_PERSIST; - loading = NULL; - loopv(parts) if(!parts[i]->meshes) return false; - } - else // iqm without configuration, try default tris and skin - { - identflags |= IDF_PERSIST; - if(!loaddefaultparts()) - { - loading = NULL; - return false; - } - loading = NULL; - } - loaded(); - return true; - } }; skelcommands iqmcommands; diff --git a/src/engine/main.cpp b/src/engine/main.cpp index d2af24be..2bb83181 100644 --- a/src/engine/main.cpp +++ b/src/engine/main.cpp @@ -225,6 +225,16 @@ void renderprogress(float bar, const char *text,bool background) { if(!inbetweenframes || drawtex) return; + extern int menufps, maxfps; + int fps = menufps ? (maxfps ? min(maxfps, menufps) : menufps) : maxfps; + if(fps) + { + static int lastprogress = 0; + int ticks = SDL_GetTicks(), diff = ticks - lastprogress; + if(bar > 0 && diff >= 0 && diff < (1000 + fps-1)/fps) return; + lastprogress = ticks; + } + clientkeepalive(); // make sure our connection doesn't time out while loading maps etc. #ifdef __APPLE__ diff --git a/src/engine/md3.h b/src/engine/md3.h index d30c6fa4..df34e22f 100644 --- a/src/engine/md3.h +++ b/src/engine/md3.h @@ -44,11 +44,12 @@ struct md3meshheader int ofs_triangles, ofs_shaders, ofs_uv, ofs_vertices, meshsize; // offsets }; -struct md3 : vertmodel, vertloader +struct md3 : vertloader { - md3(const char *name) : vertmodel(name) {} + md3(const char *name) : vertloader(name) {} static const char *formatname() { return "md3"; } + bool flipy() const { return true; } int type() const { return MDL_MD3; } struct md3meshgroup : vertmeshgroup @@ -173,30 +174,6 @@ struct md3 : vertmodel, vertloader if(tex==notexture) conoutf("could not load model skin for %s", name1); return true; } - - bool load() - { - formatstring(dir, "media/models/%s", name); - defformatstring(cfgname, "media/models/%s/md3.cfg", name); - - loading = this; - identflags &= ~IDF_PERSIST; - if(execfile(cfgname, false) && parts.length()) // configured md3, will call the md3* commands below - { - identflags |= IDF_PERSIST; - loading = NULL; - loopv(parts) if(!parts[i]->meshes) return false; - } - else // md3 without configuration, try default tris and skin - { - identflags |= IDF_PERSIST; - loading = NULL; - if(!loaddefaultparts()) return false; - } - translate.y = -translate.y; - loaded(); - return true; - } }; vertcommands md3commands; diff --git a/src/engine/md5.h b/src/engine/md5.h index d0b573f8..d4e97830 100644 --- a/src/engine/md5.h +++ b/src/engine/md5.h @@ -25,9 +25,9 @@ struct md5hierarchy int parent, flags, start; }; -struct md5 : skelmodel, skelloader +struct md5 : skelloader { - md5(const char *name) : skelmodel(name) {} + md5(const char *name) : skelloader(name) {} static const char *formatname() { return "md5"; } int type() const { return MDL_MD5; } @@ -397,7 +397,6 @@ struct md5 : skelmodel, skelloader bool loaddefaultparts() { skelpart &mdl = addpart(); - adjustments.setsize(0); const char *fname = name + strlen(name); do --fname; while(fname >= name && *fname!='/' && *fname!='\\'); fname++; diff --git a/src/engine/obj.h b/src/engine/obj.h index 43fbfba3..cd4e0c92 100644 --- a/src/engine/obj.h +++ b/src/engine/obj.h @@ -1,11 +1,12 @@ struct obj; -struct obj : vertmodel, vertloader +struct obj : vertloader { - obj(const char *name) : vertmodel(name) {} + obj(const char *name) : vertloader(name) {} static const char *formatname() { return "obj"; } static bool cananimate() { return false; } + bool flipy() const { return true; } int type() const { return MDL_OBJ; } struct objmeshgroup : vertmeshgroup @@ -180,30 +181,6 @@ struct obj : vertmodel, vertloader if(tex==notexture) conoutf("could not load model skin for %s", name1); return true; } - - bool load() - { - formatstring(dir, "media/models/%s", name); - defformatstring(cfgname, "media/models/%s/obj.cfg", name); - - loading = this; - identflags &= ~IDF_PERSIST; - if(execfile(cfgname, false) && parts.length()) // configured obj, will call the obj* commands below - { - identflags |= IDF_PERSIST; - loading = NULL; - loopv(parts) if(!parts[i]->meshes) return false; - } - else // obj without configuration, try default tris and skin - { - identflags |= IDF_PERSIST; - loading = NULL; - if(!loaddefaultparts()) return false; - } - translate.y = -translate.y; - loaded(); - return true; - } }; vertcommands objcommands; diff --git a/src/engine/octa.cpp b/src/engine/octa.cpp index be216dea..7f548c4f 100644 --- a/src/engine/octa.cpp +++ b/src/engine/octa.cpp @@ -186,13 +186,12 @@ COMMAND(printcube, ""); bool isvalidcube(const cube &c) { clipplanes p; + genclipbounds(c, ivec(0, 0, 0), 256, p); genclipplanes(c, ivec(0, 0, 0), 256, p); loopi(8) // test that cube is convex { - vec v; - calcvert(c, ivec(0, 0, 0), 256, v, i); - if(!pointincube(p, v)) - return false; + vec v = p.v[i]; + loopj(p.size) if(p.p[j].dist(v)>1e-3f) return false; } return true; } @@ -254,7 +253,7 @@ cube &lookupcube(const ivec &to, int tsize, ivec &ro, int &rsize) scale--; c = &c->children[octastep(tx, ty, tz, scale)]; } while(!(csize>>scale)); - ro = ivec(tx, ty, tz).mask(~0<children[octastep(n.x, n.y, n.z, scale)]; } while(!(size>>scale) && nc->children); - ro = n.mask(~0<= 3 && insideface(cf, numc, of, numo); + if(c.material) + { + if(nmat != MAT_AIR && (c.material&matmask) == nmat) + { + ivec2 nf[8]; + return clipfacevecs(vf, numv, o[C[dim]], o[R[dim]], size, nf) < 3; + } + if(vmat != MAT_AIR && ((c.material&matmask) == vmat || (isliquid(vmat) && isclipped(c.material&MATF_VOLUME)))) return true; + } + if(isentirelysolid(c)) return true; + if(touchingface(c, orient) && faceedges(c, orient) == F_SOLID) return true; + ivec2 cf[8]; + int numc = clipfacevecs(vf, numv, o[C[dim]], o[R[dim]], size, cf); + if(numc < 3) return true; + if(isempty(c) || notouchingface(c, orient)) return false; + ivec2 of[4]; + int numo = genfacevecs(c, orient, o, size, false, of); + return numo >= 3 && insideface(cf, numc, of, numo); } size >>= 1; @@ -955,7 +957,7 @@ bool visibleface(const cube &c, int orient, const ivec &co, int size, ushort mat { if(mat != MAT_AIR) { - if(faceedges(c, orient)==F_SOLID && touchingface(c, orient)) return false; + if(mat != MAT_CLIP && faceedges(c, orient)==F_SOLID && touchingface(c, orient)) return false; } else { @@ -970,9 +972,12 @@ bool visibleface(const cube &c, int orient, const ivec &co, int size, ushort mat int opp = opposite(orient); if(nsize > size || (nsize == size && !o.children)) { - if(nmat != MAT_AIR && (o.material&matmask) == nmat) return true; + if(o.material) + { + if(nmat != MAT_AIR && (o.material&matmask) == nmat) return true; + if(mat != MAT_AIR && ((o.material&matmask) == mat || (isliquid(mat) && isclipped(o.material&MATF_VOLUME)))) return false; + } if(isentirelysolid(o)) return false; - if(mat != MAT_AIR && ((o.material&matmask) == mat || (isliquid(mat) && (o.material&MATF_VOLUME) == MAT_GLASS))) return false; if(isempty(o) || notouchingface(o, opp)) return true; if(touchingface(o, opp) && faceedges(o, opp) == F_SOLID) return false; @@ -993,44 +998,97 @@ bool visibleface(const cube &c, int orient, const ivec &co, int size, ushort mat int classifyface(const cube &c, int orient, const ivec &co, int size) { - if(collapsedface(c, orient)) return 0; - int vismask = (c.material&MATF_CLIP) == MAT_NOCLIP ? 1 : 3; - if(!touchingface(c, orient)) return vismask; + int vismask = 2, forcevis = 0; + bool solid = false; + switch(c.material&MATF_CLIP) + { + case MAT_NOCLIP: vismask = 0; break; + case MAT_CLIP: solid = true; break; + } + if(isempty(c) || collapsedface(c, orient)) + { + if(!vismask) return 0; + } + else if(!touchingface(c, orient)) + { + forcevis = 1; + if(!solid) + { + if(vismask && collideface(c, orient)) forcevis |= 2; + return forcevis; + } + } + else vismask |= 1; ivec no; int nsize; const cube &o = neighbourcube(c, orient, co, size, no, nsize); if(&o==&c) return 0; - int vis = 0, opp = opposite(orient); + int opp = opposite(orient); if(nsize > size || (nsize == size && !o.children)) { - if((~c.material & o.material) & MAT_ALPHA) vis |= 1; - if((o.material&MATF_CLIP) == MAT_NOCLIP) vis |= vismask&2; - if(vis == vismask || isentirelysolid(o)) return vis; - if(isempty(o) || notouchingface(o, opp)) return vismask; - if(touchingface(o, opp) && faceedges(o, opp) == F_SOLID) return vis; - + if(o.material) + { + if((~c.material & o.material) & MAT_ALPHA) { forcevis |= vismask&1; vismask &= ~1; } + switch(o.material&MATF_CLIP) + { + case MAT_CLIP: vismask &= ~2; break; + case MAT_NOCLIP: forcevis |= vismask&2; vismask &= ~2; break; + } + } + if(vismask && !isentirelysolid(o)) + { + if(isempty(o) || notouchingface(o, opp)) forcevis |= vismask; + else if(!touchingface(o, opp) || faceedges(o, opp) != F_SOLID) + { + ivec vo = ivec(co).mask(0xFFF); + no.mask(0xFFF); + ivec2 cf[4], of[4]; + int numo = genfacevecs(o, opp, no, nsize, false, of); + if(numo < 3) forcevis |= vismask; + else + { + int numc = 0; + if(vismask&2 && solid) + { + numc = genfacevecs(c, orient, vo, size, true, cf); + if(!insideface(cf, numc, of, numo)) forcevis |= 2; + vismask &= ~2; + } + if(vismask) + { + numc = genfacevecs(c, orient, vo, size, false, cf); + if(!insideface(cf, numc, of, numo)) forcevis |= vismask; + } + } + } + } + } + else + { ivec vo = ivec(co).mask(0xFFF); no.mask(0xFFF); - ivec2 cf[4], of[4]; - int numc = genfacevecs(c, orient, vo, size, false, cf), - numo = genfacevecs(o, opp, no, nsize, false, of); - if(numo < 3 || !insideface(cf, numc, of, numo)) return vismask; - return vis; + ivec2 cf[4]; + int numc = 0; + if(vismask&1) + { + numc = genfacevecs(c, orient, vo, size, false, cf); + if(!occludesface(o, opp, no, nsize, vo, size, MAT_AIR, (c.material&MAT_ALPHA)^MAT_ALPHA, MAT_ALPHA, cf, numc)) forcevis |= 1; + } + if(vismask&2) + { + if(!numc || solid) numc = genfacevecs(c, orient, vo, size, solid, cf); + if(!occludesface(o, opp, no, nsize, vo, size, MAT_CLIP, MAT_NOCLIP, MATF_CLIP, cf, numc)) forcevis |= 2; + } } - ivec vo = ivec(co).mask(0xFFF); - no.mask(0xFFF); - ivec2 cf[4]; - int numc = genfacevecs(c, orient, vo, size, false, cf); - if(!occludesface(o, opp, no, nsize, vo, size, MAT_AIR, (c.material&MAT_ALPHA)^MAT_ALPHA, MAT_ALPHA, cf, numc)) vis |= 1; - if(vismask&2 && !occludesface(o, opp, no, nsize, vo, size, MAT_AIR, MAT_NOCLIP, MATF_CLIP, cf, numc)) vis |= 2; - return vis; + if(forcevis&2 && !solid && !collideface(c, orient)) forcevis &= ~2; + return forcevis; } // more expensive version that checks both triangles of a face independently -int visibletris(const cube &c, int orient, const ivec &co, int size, ushort nmat, ushort matmask) +int visibletris(const cube &c, int orient, const ivec &co, int size, ushort vmat, ushort nmat, ushort matmask) { int vis = 3, touching = 0xF; ivec v[4], e1, e2, e3, n; @@ -1070,8 +1128,12 @@ int visibletris(const cube &c, int orient, const ivec &co, int size, ushort nmat int opp = opposite(orient), numo = 0, numc; if(nsize > size || (nsize == size && !o.children)) { + if(o.material) + { + if(vmat != MAT_AIR && (o.material&matmask) == vmat) return vis¬ouch; + if(nmat != MAT_AIR && (o.material&matmask) == nmat) return vis; + } if(isempty(o) || notouchingface(o, opp)) return vis; - if(nmat != MAT_AIR && (o.material&matmask) == nmat) return vis; if(isentirelysolid(o) || (touchingface(o, opp) && faceedges(o, opp) == F_SOLID)) return vis¬ouch; numc = genfacevecs(c, orient, vo, size, false, cf, v); @@ -1082,7 +1144,7 @@ int visibletris(const cube &c, int orient, const ivec &co, int size, ushort nmat else { numc = genfacevecs(c, orient, vo, size, false, cf, v); - if(occludesface(o, opp, no, nsize, vo, size, MAT_AIR, nmat, matmask, cf, numc)) return vis¬ouch; + if(occludesface(o, opp, no, nsize, vo, size, vmat, nmat, matmask, cf, numc)) return vis¬ouch; } if(vis != 3 || notouch) return vis; @@ -1105,7 +1167,7 @@ int visibletris(const cube &c, int orient, const ivec &co, int size, ushort nmat const int *verts = triverts[order][coord][i]; ivec2 tf[3] = { cf[verts[0]], cf[verts[1]], cf[verts[2]] }; if(numo > 0) { if(!insideface(tf, 3, of, numo)) continue; } - else if(!occludesface(o, opp, no, nsize, vo, size, MAT_AIR, nmat, matmask, tf, 3)) continue; + else if(!occludesface(o, opp, no, nsize, vo, size, vmat, nmat, matmask, tf, 3)) continue; return vis & ~(1<= 2 && vslot.rotation <= 4) { xoff *= -1; loopk(4) tc[k].x *= -1; } - if(vslot.rotation <= 2 || vslot.rotation == 5) { yoff *= -1; loopk(4) tc[k].y *= -1; } + const texrotation &r = texrotations[vslot.rotation]; + if(r.swapxy) { swap(xoff, yoff); loopk(4) swap(tc[k].x, tc[k].y); } + if(r.flipx) { xoff *= -1; loopk(4) tc[k].x *= -1; } + if(r.flipy) { yoff *= -1; loopk(4) tc[k].y *= -1; } } loopk(4) { tc[k].x = tc[k].x/sx - xoff/tex->xs; tc[k].y = tc[k].y/sy - yoff/tex->ys; } glBindTexture(GL_TEXTURE_2D, tex->id); diff --git a/src/engine/octarender.cpp b/src/engine/octarender.cpp index e8acb7ff..990eaa77 100644 --- a/src/engine/octarender.cpp +++ b/src/engine/octarender.cpp @@ -644,23 +644,27 @@ void reduceslope(ivec &n) } // [rotation][orient] -extern const vec orientation_tangent[6][6] = +extern const vec orientation_tangent[8][6] = { { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) }, { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) }, { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) }, { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) }, { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) }, - { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) } + { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) }, + { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) }, + { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) }, }; -extern const vec orientation_bitangent[6][6] = +extern const vec orientation_bitangent[8][6] = { { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) }, { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) }, { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) }, { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) }, { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) }, - { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) } + { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) }, + { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) }, + { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) }, }; void addtris(VSlot &vslot, int orient, const sortkey &key, vertex *verts, int *index, int numverts, int convex, int tj) @@ -782,15 +786,16 @@ void addgrasstri(int face, vertex *verts, int numv, ushort texture, int layer) static inline void calctexgen(VSlot &vslot, int orient, vec4 &sgen, vec4 &tgen) { Texture *tex = vslot.slot->sts.empty() ? notexture : vslot.slot->sts[0].t; + const texrotation &r = texrotations[vslot.rotation]; float k = TEX_SCALE/vslot.scale, - xs = vslot.rotation>=2 && vslot.rotation<=4 ? -tex->xs : tex->xs, - ys = (vslot.rotation>=1 && vslot.rotation<=2) || vslot.rotation==5 ? -tex->ys : tex->ys, + xs = r.flipx ? -tex->xs : tex->xs, + ys = r.flipy ? -tex->ys : tex->ys, sk = k/xs, tk = k/ys, - soff = -((vslot.rotation&5)==1 ? vslot.offset.y : vslot.offset.x)/xs, - toff = -((vslot.rotation&5)==1 ? vslot.offset.x : vslot.offset.y)/ys; + soff = -(r.swapxy ? vslot.offset.y : vslot.offset.x)/xs, + toff = -(r.swapxy ? vslot.offset.x : vslot.offset.y)/ys; sgen = vec4(0, 0, 0, soff); tgen = vec4(0, 0, 0, toff); - if((vslot.rotation&5)==1) switch(orient) + if(r.swapxy) switch(orient) { case 0: sgen.z = -sk; tgen.y = tk; break; case 1: sgen.z = -sk; tgen.y = -tk; break; @@ -1509,6 +1514,7 @@ void setva(cube &c, const ivec &co, int size, int csi) static inline int setcubevisibility(cube &c, const ivec &co, int size) { + if(isempty(c) && (c.material&MATF_CLIP) != MAT_CLIP) return 0; int numvis = 0, vismask = 0, collidemask = 0, checkmask = 0; loopi(6) { @@ -1526,7 +1532,7 @@ static inline int setcubevisibility(cube &c, const ivec &co, int size) if(c.texture[i] != DEFAULT_SKY && !(c.ext && c.ext->surfaces[i].numverts&MAXFACEVERTS)) checkmask |= 1<ents) --entdepth; } - else if(!isempty(c[i])) count += setcubevisibility(c[i], o, size); + else count += setcubevisibility(c[i], o, size); int tcount = count + (csi <= MAXMERGELEVEL ? vamerges[csi].length() : 0); if(tcount > vafacemax || (tcount >= vafacemin && size >= vacubesize) || size == min(0x1000, worldsize/2)) { diff --git a/src/engine/physics.cpp b/src/engine/physics.cpp index baf68bc7..28b63d80 100644 --- a/src/engine/physics.cpp +++ b/src/engine/physics.cpp @@ -6,51 +6,59 @@ #include "engine.h" #include "mpr.h" +const int MAXCLIPOFFSET = 4; const int MAXCLIPPLANES = 1024; static clipplanes clipcache[MAXCLIPPLANES]; -static int clipcacheversion = -2; +static int clipcacheversion = -MAXCLIPOFFSET; -static inline clipplanes &getclipplanes(const cube &c, const ivec &o, int size, bool collide = true, int offset = 0) +static inline clipplanes &getclipbounds(const cube &c, const ivec &o, int size, int offset) { clipplanes &p = clipcache[int(&c - worldroot)&(MAXCLIPPLANES-1)]; if(p.owner != &c || p.version != clipcacheversion+offset) { p.owner = &c; p.version = clipcacheversion+offset; - genclipplanes(c, o, size, p, collide); + genclipbounds(c, o, size, p); } return p; } -void resetclipplanes() +static inline clipplanes &getclipbounds(const cube &c, const ivec &o, int size, physent *d) { - clipcacheversion += 2; - if(!clipcacheversion) + int offset = !(c.visible&0x80) || d->type==ENT_PLAYER ? 0 : 1; + return getclipbounds(c, o, size, offset); +} + +static inline int forceclipplanes(const cube &c, const ivec &o, int size, clipplanes &p) +{ + if(p.visible&0x80) { - memset(clipcache, 0, sizeof(clipcache)); - clipcacheversion = 2; + bool collide = true, noclip = false; + if(p.version&1) { collide = false; noclip = true; } + genclipplanes(c, o, size, p, collide, noclip); } + return p.visible; } -///////////////////////// ray - cube collision /////////////////////////////////////////////// - -static inline bool pointinbox(const vec &v, const vec &bo, const vec &br) +static inline clipplanes &getclipplanes(const cube &c, const ivec &o, int size) { - return v.x <= bo.x+br.x && - v.x >= bo.x-br.x && - v.y <= bo.y+br.y && - v.y >= bo.y-br.y && - v.z <= bo.z+br.z && - v.z >= bo.z-br.z; + clipplanes &p = getclipbounds(c, o, size, c.visible&0x80 ? 2 : 0); + if(p.visible&0x80) genclipplanes(c, o, size, p, false, false); + return p; } -bool pointincube(const clipplanes &p, const vec &v) +void resetclipplanes() { - if(!pointinbox(v, p.o, p.r)) return false; - loopi(p.size) if(p.p[i].dist(v)>1e-3f) return false; - return true; + clipcacheversion += MAXCLIPOFFSET; + if(!clipcacheversion) + { + memset(clipcache, 0, sizeof(clipcache)); + clipcacheversion = MAXCLIPOFFSET; + } } +///////////////////////// ray - cube collision /////////////////////////////////////////////// + #define INTERSECTPLANES(setentry, exit) \ float enterdist = -1e16f, exitdist = 1e16f; \ loopi(p.size) \ @@ -302,9 +310,9 @@ float raycube(const vec &o, const vec &ray, float radius, int mode, int size, ex { if(closest < 0) { - float dx = ((x&(~0<0 ? 0 : 1<0 ? 0 : 1<0 ? 0 : 1<0 ? 0 : 1<0 ? 0 : 1<0 ? 0 : 1< dy ? (dx > dz ? 0 : 2) : (dy > dz ? 1 : 2); } hitsurface = vec(0, 0, 0); @@ -314,11 +322,11 @@ float raycube(const vec &o, const vec &ray, float radius, int mode, int size, ex return dent; } - ivec lo(x&(~0<0 || !(mode&RAY_SKIPFIRST)) && (!(mode&RAY_CLIPMAT) || (c.material&MATF_CLIP)!=MAT_NOCLIP)) return min(dent, dist+f); @@ -344,12 +352,12 @@ float shadowray(const vec &o, const vec &ray, float radius, int mode, extentity DOWNOCTREE(shadowent, ); cube &c = *lc; - ivec lo(x&(~0<= 0) return c.texture[side]==DEFAULT_SKY && mode&RAY_SKIPSKY ? radius : dist+max(enterdist+0.1f, 0.0f); @@ -875,7 +883,7 @@ static bool fuzzycollidesolid(physent *d, const vec &dir, float cutoff, const cu collidewall = vec(0, 0, 0); float bestdist = -1e10f; - int visible = isentirelysolid(c) ? c.visible : 0xFF; + int visible = !(c.visible&0x80) || d->type==ENT_PLAYER ? c.visible : 0xFF; #define CHECKSIDE(side, distval, dotval, margin, normal) if(visible&(1< static bool fuzzycollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with deformed cube geometry { - const clipplanes &p = getclipplanes(c, co, size); + clipplanes &p = getclipbounds(c, co, size, d); if(fabs(d->o.x - p.o.x) > p.r.x + d->radius || fabs(d->o.y - p.o.y) > p.r.y + d->radius || d->o.z + d->aboveeye < p.o.z - p.r.z || d->o.z - d->eyeheight > p.o.z + p.r.z) @@ -942,7 +950,7 @@ static bool fuzzycollideplanes(physent *d, const vec &dir, float cutoff, const c collidewall = vec(0, 0, 0); float bestdist = -1e10f; - int visible = p.visible; + int visible = forceclipplanes(c, co, size, p); CHECKSIDE(O_LEFT, p.o.x - p.r.x - (d->o.x + d->radius), -dir.x, -d->radius, vec(-1, 0, 0)); CHECKSIDE(O_RIGHT, d->o.x - d->radius - (p.o.x + p.r.x), dir.x, -d->radius, vec(1, 0, 0)); CHECKSIDE(O_BACK, p.o.y - p.r.y - (d->o.y + d->radius), -dir.y, -d->radius, vec(0, -1, 0)); @@ -997,7 +1005,7 @@ static bool cubecollidesolid(physent *d, const vec &dir, float cutoff, const cub collidewall = vec(0, 0, 0); float bestdist = -1e10f; - int visible = isentirelysolid(c) ? c.visible : 0xFF; + int visible = !(c.visible&0x80) || d->type==ENT_PLAYER ? c.visible : 0xFF; CHECKSIDE(O_LEFT, co.x - entvol.right(), -dir.x, -d->radius, vec(-1, 0, 0)); CHECKSIDE(O_RIGHT, entvol.left() - (co.x + size), dir.x, -d->radius, vec(1, 0, 0)); CHECKSIDE(O_BACK, co.y - entvol.front(), -dir.y, -d->radius, vec(0, -1, 0)); @@ -1016,8 +1024,7 @@ static bool cubecollidesolid(physent *d, const vec &dir, float cutoff, const cub template static bool cubecollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with deformed cube geometry { - const clipplanes &p = getclipplanes(c, co, size); - + clipplanes &p = getclipbounds(c, co, size, d); if(fabs(d->o.x - p.o.x) > p.r.x + d->radius || fabs(d->o.y - p.o.y) > p.r.y + d->radius || d->o.z + d->aboveeye < p.o.z - p.r.z || d->o.z - d->eyeheight > p.o.z + p.r.z) return false; @@ -1028,7 +1035,7 @@ static bool cubecollideplanes(physent *d, const vec &dir, float cutoff, const cu collidewall = vec(0, 0, 0); float bestdist = -1e10f; - int visible = p.visible; + int visible = forceclipplanes(c, co, size, p); CHECKSIDE(O_LEFT, p.o.x - p.r.x - entvol.right(), -dir.x, -d->radius, vec(-1, 0, 0)); CHECKSIDE(O_RIGHT, entvol.left() - (p.o.x + p.r.x), dir.x, -d->radius, vec(1, 0, 0)); CHECKSIDE(O_BACK, p.o.y - p.r.y - entvol.front(), -dir.y, -d->radius, vec(0, -1, 0)); @@ -1141,7 +1148,7 @@ bool collide(physent *d, const vec &dir, float cutoff, bool playercol, bool insi collidewall = vec(0, 0, 0); ivec bo(int(d->o.x-d->radius), int(d->o.y-d->radius), int(d->o.z-d->eyeheight)), bs(int(d->o.x+d->radius), int(d->o.y+d->radius), int(d->o.z+d->aboveeye)); - bs.add(1); // guard space for rounding errors + bo.sub(1); bs.add(1); // guard space for rounding errors return octacollide(d, dir, cutoff, bo, bs) || (playercol && plcollide(d, dir, insideplayercol)); // collide with world } diff --git a/src/engine/pvs.cpp b/src/engine/pvs.cpp index e49783db..cf8633de 100644 --- a/src/engine/pvs.cpp +++ b/src/engine/pvs.cpp @@ -332,7 +332,7 @@ struct pvsworker levels[curlevel] = cur; } - origin = ivec(p.x&(~0<flags&PVS_HIDE_BB || cur->edges==bvec(0x80, 0x80, 0x80)) { diff --git a/src/engine/renderlights.cpp b/src/engine/renderlights.cpp index a7220e16..88bd748f 100644 --- a/src/engine/renderlights.cpp +++ b/src/engine/renderlights.cpp @@ -1591,6 +1591,8 @@ struct lightinfo } bool noshadow() const { return flags&L_NOSHADOW || radius <= smminradius; } + bool nospec() const { return (flags&L_NOSPEC) != 0; } + bool volumetric() const { return (flags&L_VOLUMETRIC) != 0; } void addscissor(float &dx1, float &dy1, float &dx2, float &dy2) const { @@ -2490,6 +2492,8 @@ void cleardeferredlightshaders() deferredmsaasampleshader = NULL; } +extern int nospeclights; + Shader *loaddeferredlightshader(const char *type = NULL) { string common, shadow, sun; @@ -2517,6 +2521,7 @@ Shader *loaddeferredlightshader(const char *type = NULL) if(usegatherforsm()) common[commonlen++] = smfilter > 2 ? 'G' : 'g'; else if(smfilter) common[commonlen++] = smfilter > 2 ? 'E' : (smfilter > 1 ? 'F' : 'f'); /*if(spotlights || forcespotlights)*/ common[commonlen++] = 's'; + if(nospeclights) common[commonlen++] = 'z'; common[commonlen] = '\0'; shadow[shadowlen++] = 'p'; @@ -2858,14 +2863,13 @@ static inline void setlightglobals(bool transparent = false) } static LocalShaderParam lightpos("lightpos"), lightcolor("lightcolor"), spotparams("spotparams"), shadowparams("shadowparams"), shadowoffset("shadowoffset"); -static vec4 lightposv[8], spotparamsv[8], shadowparamsv[8]; -static vec lightcolorv[8]; +static vec4 lightposv[8], lightcolorv[8], spotparamsv[8], shadowparamsv[8]; static vec2 shadowoffsetv[8]; static inline void setlightparams(int i, const lightinfo &l) { lightposv[i] = vec4(l.o, 1).div(l.radius); - lightcolorv[i] = vec(l.color).mul(2*ldrscaleb); + lightcolorv[i] = vec4(vec(l.color).mul(2*ldrscaleb), l.nospec() ? 0 : 1); if(l.spot > 0) spotparamsv[i] = vec4(vec(l.dir).neg(), 1/(1 - cos360(l.spot))); if(l.shadowmap >= 0) { @@ -3198,7 +3202,7 @@ void rendervolumetric() loopv(lightorder) { const lightinfo &l = lights[lightorder[i]]; - if(!(l.flags&L_VOLUMETRIC) || l.checkquery()) continue; + if(!l.volumetric() || l.checkquery()) continue; l.addscissor(bsx1, bsy1, bsx2, bsy2); } @@ -3240,7 +3244,7 @@ void rendervolumetric() loopv(lightorder) { const lightinfo &l = lights[lightorder[i]]; - if(!(l.flags&L_VOLUMETRIC) || l.checkquery()) continue; + if(!l.volumetric() || l.checkquery()) continue; matrix4 lightmatrix = camprojmatrix; lightmatrix.translate(l.o); @@ -3489,7 +3493,7 @@ void collectlights() { int idx = lightorder[i]; lightinfo &l = lights[idx]; - if((l.noshadow() && (!oqvol || !(l.flags&L_VOLUMETRIC))) || l.radius >= worldsize) continue; + if((l.noshadow() && (!oqvol || !l.volumetric())) || l.radius >= worldsize) continue; vec bbmin, bbmax; l.calcbb(bbmin, bbmax); if(!camera1->o.insidebb(bbmin, bbmax, 2)) @@ -4539,6 +4543,8 @@ void workinoq() FVAR(refractmargin, 0, 0.1f, 1); FVAR(refractdepth, 1e-3f, 16, 1e3f); +int transparentlayer = 0; + void rendertransparent() { int hasalphavas = findalphavas(); @@ -4642,6 +4648,8 @@ void rendertransparent() continue; } + transparentlayer = layer+1; + allsx1 = min(allsx1, sx1); allsy1 = min(allsy1, sy1); allsx2 = max(allsx2, sx2); @@ -4715,6 +4723,8 @@ void rendertransparent() } } + transparentlayer = 0; + if(ghasstencil) glDisable(GL_STENCIL_TEST); endtimer(transtimer); diff --git a/src/engine/rendermodel.cpp b/src/engine/rendermodel.cpp index 365bad27..b77fbc27 100644 --- a/src/engine/rendermodel.cpp +++ b/src/engine/rendermodel.cpp @@ -221,6 +221,7 @@ void mdlname() COMMAND(mdlname, ""); #define checkragdoll \ + checkmdl; \ if(!loadingmodel->skeletal()) { conoutf(CON_ERROR, "not loading a skeletal model"); return; } \ skelmodel *m = (skelmodel *)loadingmodel; \ if(m->parts.empty()) return; \ @@ -610,8 +611,8 @@ void shadowmaskbatchedmodels(bool dynshadow) loopv(batchedmodels) { batchedmodel &b = batchedmodels[i]; - if(b.flags&MDL_MAPMODEL) break; - b.visible = dynshadow && b.colorscale.a >= 1 ? shadowmaskmodel(b.center, b.radius) : 0; + if(b.flags&(MDL_MAPMODEL | MDL_NOSHADOW)) break; + b.visible = dynshadow && (b.colorscale.a >= 1 || b.flags&(MDL_ONLYSHADOW | MDL_FORCESHADOW)) ? shadowmaskmodel(b.center, b.radius) : 0; } } @@ -731,7 +732,7 @@ void rendermodelbatches() j = bm.next; bm.culled = cullmodel(b.m, bm.center, bm.radius, bm.flags, bm.d); if(bm.culled || bm.flags&MDL_ONLYSHADOW) continue; - if(bm.colorscale.a < 1) + if(bm.colorscale.a < 1 || bm.flags&MDL_FORCETRANSPARENT) { float sx1, sy1, sx2, sy2; ivec bbmin(vec(bm.center).sub(bm.radius)), bbmax(vec(bm.center).add(bm.radius+1)); @@ -802,7 +803,7 @@ void rendertransparentmodelbatches(int stencil) batchedmodel &bm = batchedmodels[j]; j = bm.next; bm.culled = cullmodel(b.m, bm.center, bm.radius, bm.flags, bm.d); - if(bm.culled || bm.colorscale.a >= 1 || bm.flags&MDL_ONLYSHADOW) continue; + if(bm.culled || !(bm.colorscale.a < 1 || bm.flags&MDL_FORCETRANSPARENT) || bm.flags&MDL_ONLYSHADOW) continue; if(!rendered) { b.m->startrender(); diff --git a/src/engine/renderva.cpp b/src/engine/renderva.cpp index 76ab898b..b5c38c6d 100644 --- a/src/engine/renderva.cpp +++ b/src/engine/renderva.cpp @@ -1498,10 +1498,11 @@ static void changetexgen(renderstate &cur, int orient, Slot &slot, VSlot &vslot) cur.texgenvslot->rotation != vslot.rotation || cur.texgenvslot->scale != vslot.scale || cur.texgenvslot->offset != vslot.offset || cur.texgenvslot->scroll != vslot.scroll)) { - float xs = vslot.rotation>=2 && vslot.rotation<=4 ? -tex->xs : tex->xs, - ys = (vslot.rotation>=1 && vslot.rotation<=2) || vslot.rotation==5 ? -tex->ys : tex->ys; + const texrotation &r = texrotations[vslot.rotation]; + float xs = r.flipx ? -tex->xs : tex->xs, + ys = r.flipy ? -tex->ys : tex->ys; vec2 scroll(vslot.scroll); - if((vslot.rotation&5)==1) swap(scroll.x, scroll.y); + if(r.swapxy) swap(scroll.x, scroll.y); scroll.x *= cur.texgenmillis*tex->xs/xs; scroll.y *= cur.texgenmillis*tex->ys/ys; if(cur.texgenscroll != scroll) @@ -2411,7 +2412,7 @@ void renderdecals() if(maxdualdrawbufs) { - glBlendFunc(GL_SRC1_ALPHA, GL_ONE_MINUS_SRC1_ALPHA); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC1_ALPHA); maskgbuffer("c"); for(vtxarray *va = decalva; va; va = va->next) if(va->decaltris && va->occluded < OCCLUDE_BB) { @@ -2425,6 +2426,7 @@ void renderdecals() glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); } + else glBlendFunc(GL_SRC1_ALPHA, GL_ONE_MINUS_SRC1_ALPHA); maskgbuffer("n"); cur.vbuf = 0; for(vtxarray *va = decalva; va; va = va->next) if(va->decaltris && va->occluded < OCCLUDE_BB) @@ -2436,7 +2438,7 @@ void renderdecals() } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); maskgbuffer("cn"); for(vtxarray *va = decalva; va; va = va->next) if(va->decaltris && va->occluded < OCCLUDE_BB) diff --git a/src/engine/scale.h b/src/engine/scale.h deleted file mode 100644 index b1f8b265..00000000 --- a/src/engine/scale.h +++ /dev/null @@ -1,122 +0,0 @@ -static void FUNCNAME(halvetexture)(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst) -{ - for(uchar *yend = &src[sh*stride]; src < yend;) - { - for(uchar *xend = &src[sw*BPP], *xsrc = src; xsrc < xend; xsrc += 2*BPP, dst += BPP) - { - #define OP(c, n) dst[n] = (uint(xsrc[n]) + uint(xsrc[n+BPP]) + uint(xsrc[stride+n]) + uint(xsrc[stride+n+BPP]))>>2 - PIXELOP - #undef OP - } - src += 2*stride; - } -} - -static void FUNCNAME(shifttexture)(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst, uint dw, uint dh) -{ - uint wfrac = sw/dw, hfrac = sh/dh, wshift = 0, hshift = 0; - while(dw<>tshift - PIXELOP - #undef OP - } - src += hfrac*stride; - } -} - -static void FUNCNAME(scaletexture)(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst, uint dw, uint dh) -{ - uint wfrac = (sw<<12)/dw, hfrac = (sh<<12)/dh, darea = dw*dh, sarea = sw*sh; - int over, under; - for(over = 0; (darea>>over) > sarea; over++); - for(under = 0; (darea<>12, h = (yn>>12) - yi, ylow = ((yn|(-int(h)>>24))&0xFFFU) + 1 - (y&0xFFFU), yhigh = (yn&0xFFFU) + 1; - const uchar *ysrc = &src[yi*stride]; - for(uint x = 0; x < dw; x += wfrac, dst += BPP) - { - const uint xn = x + wfrac - 1, xi = x>>12, w = (xn>>12) - xi, xlow = ((w+0xFFFU)&0x1000U) - (x&0xFFFU), xhigh = (xn&0xFFFU) + 1; - const uchar *xsrc = &ysrc[xi*BPP], *xend = &xsrc[w*BPP]; - #define OP(c, n) c##t = 0 - DEFPIXEL - #undef OP - for(const uchar *xcur = &xsrc[BPP]; xcur < xend; xcur += BPP) - { - #define OP(c, n) c##t += xcur[n] - PIXELOP - #undef OP - } - #define OP(c, n) c##t = (ylow*(c##t + ((xsrc[n]*xlow + xend[n]*xhigh)>>12)))>>cscale - PIXELOP - #undef OP - if(h) - { - xsrc += stride; - xend += stride; - for(uint hcur = h; --hcur; xsrc += stride, xend += stride) - { - #define OP(c, n) c = 0 - DEFPIXEL - #undef OP - for(const uchar *xcur = &xsrc[BPP]; xcur < xend; xcur += BPP) - { - #define OP(c, n) c += xcur[n] - PIXELOP - #undef OP - } - #define OP(c, n) c##t += ((c<<12) + xsrc[n]*xlow + xend[n]*xhigh)>>cscale - PIXELOP - #undef OP - } - #define OP(c, n) c = 0 - DEFPIXEL - #undef OP - for(const uchar *xcur = &xsrc[BPP]; xcur < xend; xcur += BPP) - { - #define OP(c, n) c += xcur[n] - PIXELOP - #undef OP - } - #define OP(c, n) c##t += (yhigh*(c + ((xsrc[n]*xlow + xend[n]*xhigh)>>12)))>>cscale - PIXELOP - #undef OP - } - #define OP(c, n) dst[n] = (c##t * area)>>dscale - PIXELOP - #undef OP - } - } -} - -#undef FUNCNAME -#undef DEFPIXEL -#undef PIXELOP -#undef BPP - diff --git a/src/engine/server.cpp b/src/engine/server.cpp index 53a67229..6647bde9 100644 --- a/src/engine/server.cpp +++ b/src/engine/server.cpp @@ -451,7 +451,7 @@ void processmasterinput() char *input = &masterin[masterinpos], *end = (char *)memchr(input, '\n', masterin.length() - masterinpos); while(end) { - *end++ = '\0'; + *end = '\0'; const char *args = input; while(args < end && !iscubespace(*args)) args++; @@ -464,6 +464,7 @@ void processmasterinput() conoutf("master server registration succeeded"); else server::processmasterinput(input, cmdlen, args); + end++; masterinpos = end - masterin.getbuf(); input = end; end = (char *)memchr(input, '\n', masterin.length() - masterinpos); diff --git a/src/engine/shader.cpp b/src/engine/shader.cpp index e6ad05b9..2028e11d 100644 --- a/src/engine/shader.cpp +++ b/src/engine/shader.cpp @@ -36,6 +36,7 @@ void loadshaders() if(!nullshader || !hudshader || !hudtextshader || !hudnotextureshader || !stdworldshader) fatal("cannot find shader definitions"); dummyslot.shader = stdworldshader; + dummydecalslot.shader = nullshader; nocolorshader = lookupshaderbyname("nocolor"); foggedshader = lookupshaderbyname("fogged"); @@ -61,9 +62,10 @@ Shader *generateshader(const char *name, const char *fmt, ...) if(!s) { defvformatstring(cmd, fmt, fmt); + bool wasstandard = standardshaders; standardshaders = true; execute(cmd); - standardshaders = false; + standardshaders = wasstandard; s = name ? lookupshaderbyname(name) : NULL; if(!s) s = nullshader; } @@ -439,7 +441,7 @@ static void findfragdatalocs(Shader &s, char *ps, const char *macroname, int ind const char *name = ps; ps += strcspn(ps, "; \t\r\n"); - if(ps > 0) + if(ps > name) { char end = *ps; *ps = '\0'; @@ -1081,7 +1083,7 @@ COMMAND(defershader, "iss"); void Shader::force() { - if(!deferred()) return; + if(!deferred() || !defer) return; char *cmd = defer; defer = NULL; @@ -1517,6 +1519,7 @@ void cleanupshaders() { cleanuppostfx(true); + loadedshaders = false; nullshader = hudshader = hudnotextureshader = NULL; enumerate(shaders, Shader, s, s.cleanup()); Shader::lastshader = NULL; diff --git a/src/engine/skelmodel.h b/src/engine/skelmodel.h index 8163b10f..ba07c8b0 100644 --- a/src/engine/skelmodel.h +++ b/src/engine/skelmodel.h @@ -358,6 +358,7 @@ struct skelmodel : animmodel void render(const animstate *as, skin &s, vbocacheentry &vc) { + if(!Shader::lastshader) return; glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, elen, GL_UNSIGNED_SHORT, &((skelmeshgroup *)group)->edata[eoffset]); glde++; xtravertsva += numverts; @@ -1593,6 +1594,7 @@ struct skelmodel : animmodel skelpart &addpart() { + flushpart(); skelpart *p = new skelpart(this, parts.length()); parts.add(p); return *p; @@ -1617,19 +1619,22 @@ struct skeladjustment } }; -template struct skelloader : modelloader +template struct skelloader : modelloader { static vector adjustments; static vector hitzones; + skelloader(const char *name) : modelloader(name) {} + void flushpart() { - if(MDL::loading && MDL::loading->parts.length()) + if(hitzones.length() && skelmodel::parts.length()) { - skelmodel::skelpart *p = (skelmodel::skelpart *)MDL::loading->parts.last(); + skelmodel::skelpart *p = (skelmodel::skelpart *)skelmodel::parts.last(); skelmodel::skelmeshgroup *m = (skelmodel::skelmeshgroup *)p->meshes; - if(hitzones.length() && m) m->buildhitdata(hitzones.getbuf()); + if(m) m->buildhitdata(hitzones.getbuf()); } + adjustments.setsize(0); hitzones.setsize(0); } @@ -1656,7 +1661,6 @@ template struct skelcommands : modelcommandsaddpart(); - MDL::adjustments.setsize(0); mdl.meshes = MDL::loading->sharemeshes(path(filename), skelname[0] ? skelname : NULL, *smooth > 0 ? cosf(clamp(*smooth, 0.0f, 180.0f)*RAD) : 2); if(!mdl.meshes) conoutf("could not load %s", filename); else diff --git a/src/engine/smd.h b/src/engine/smd.h index 754ee7eb..58e8eb3e 100644 --- a/src/engine/smd.h +++ b/src/engine/smd.h @@ -7,9 +7,9 @@ struct smdbone smdbone() : parent(-1) { name[0] = '\0'; } }; -struct smd : skelmodel, skelloader +struct smd : skelloader { - smd(const char *name) : skelmodel(name) {} + smd(const char *name) : skelloader(name) {} static const char *formatname() { return "smd"; } int type() const { return MDL_SMD; } @@ -412,7 +412,6 @@ struct smd : skelmodel, skelloader bool loaddefaultparts() { skelpart &mdl = addpart(); - adjustments.setsize(0); const char *fname = name + strlen(name); do --fname; while(fname >= name && *fname!='/' && *fname!='\\'); fname++; @@ -423,33 +422,6 @@ struct smd : skelmodel, skelloader mdl.initskins(); return true; } - - bool load() - { - formatstring(dir, "media/models/%s", name); - defformatstring(cfgname, "media/models/%s/smd.cfg", name); - - loading = this; - identflags &= ~IDF_PERSIST; - if(execfile(cfgname, false) && parts.length()) // configured smd, will call the smd* commands below - { - identflags |= IDF_PERSIST; - loading = NULL; - loopv(parts) if(!parts[i]->meshes) return false; - } - else // smd without configuration, try default tris and skin - { - identflags |= IDF_PERSIST; - if(!loaddefaultparts()) - { - loading = NULL; - return false; - } - loading = NULL; - } - loaded(); - return true; - } }; static inline uint hthash(const smd::smdmeshgroup::smdvertkey &k) diff --git a/src/engine/sound.cpp b/src/engine/sound.cpp index 6ad1c309..db94f176 100644 --- a/src/engine/sound.cpp +++ b/src/engine/sound.cpp @@ -159,6 +159,15 @@ VARF(soundbufferlen, 128, 1024, 4096, initwarning("sound configuration", INIT_RE void initsound() { + SDL_version version; + SDL_GetVersion(&version); + if(version.major == 2 && version.minor == 0 && version.patch == 6) + { + nosound = true; + if(sound) conoutf(CON_ERROR, "audio is broken in SDL 2.0.6"); + return; + } + if(!sound || Mix_OpenAudio(soundfreq, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0) { nosound = true; @@ -485,7 +494,7 @@ void checkmapsounds() VAR(stereo, 0, 1, 1); -VARP(maxsoundradius, 0, 340, 10000); +VAR(maxsoundradius, 1, 340, 0); bool updatechannel(soundchannel &chan) { diff --git a/src/engine/texture.cpp b/src/engine/texture.cpp index f9d68996..6269c87a 100644 --- a/src/engine/texture.cpp +++ b/src/engine/texture.cpp @@ -8,29 +8,86 @@ #include "SDL_image.h" #endif -#define FUNCNAME(name) name##1 -#define DEFPIXEL uint OP(r, 0); -#define PIXELOP OP(r, 0); -#define BPP 1 -#include "scale.h" - -#define FUNCNAME(name) name##2 -#define DEFPIXEL uint OP(r, 0), OP(g, 1); -#define PIXELOP OP(r, 0); OP(g, 1); -#define BPP 2 -#include "scale.h" - -#define FUNCNAME(name) name##3 -#define DEFPIXEL uint OP(r, 0), OP(g, 1), OP(b, 2); -#define PIXELOP OP(r, 0); OP(g, 1); OP(b, 2); -#define BPP 3 -#include "scale.h" - -#define FUNCNAME(name) name##4 -#define DEFPIXEL uint OP(r, 0), OP(g, 1), OP(b, 2), OP(a, 3); -#define PIXELOP OP(r, 0); OP(g, 1); OP(b, 2); OP(a, 3); -#define BPP 4 -#include "scale.h" +template static void halvetexture(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst) +{ + for(uchar *yend = &src[sh*stride]; src < yend;) + { + for(uchar *xend = &src[sw*BPP], *xsrc = src; xsrc < xend; xsrc += 2*BPP, dst += BPP) + { + loopi(BPP) dst[i] = (uint(xsrc[i]) + uint(xsrc[i+BPP]) + uint(xsrc[stride+i]) + uint(xsrc[stride+i+BPP]))>>2; + } + src += 2*stride; + } +} + +template static void shifttexture(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst, uint dw, uint dh) +{ + uint wfrac = sw/dw, hfrac = sh/dh, wshift = 0, hshift = 0; + while(dw<> tshift; + } + src += hfrac*stride; + } +} + +template static void scaletexture(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst, uint dw, uint dh) +{ + uint wfrac = (sw<<12)/dw, hfrac = (sh<<12)/dh, darea = dw*dh, sarea = sw*sh; + int over, under; + for(over = 0; (darea>>over) > sarea; over++); + for(under = 0; (darea<>12, h = (yn>>12) - yi, ylow = ((yn|(-int(h)>>24))&0xFFFU) + 1 - (y&0xFFFU), yhigh = (yn&0xFFFU) + 1; + const uchar *ysrc = &src[yi*stride]; + for(uint x = 0; x < dw; x += wfrac, dst += BPP) + { + const uint xn = x + wfrac - 1, xi = x>>12, w = (xn>>12) - xi, xlow = ((w+0xFFFU)&0x1000U) - (x&0xFFFU), xhigh = (xn&0xFFFU) + 1; + const uchar *xsrc = &ysrc[xi*BPP], *xend = &xsrc[w*BPP]; + uint t[BPP] = {0}; + for(const uchar *xcur = &xsrc[BPP]; xcur < xend; xcur += BPP) + loopi(BPP) t[i] += xcur[i]; + loopi(BPP) t[i] = (ylow*(t[i] + ((xsrc[i]*xlow + xend[i]*xhigh)>>12)))>>cscale; + if(h) + { + xsrc += stride; + xend += stride; + for(uint hcur = h; --hcur; xsrc += stride, xend += stride) + { + uint c[BPP] = {0}; + for(const uchar *xcur = &xsrc[BPP]; xcur < xend; xcur += BPP) + loopi(BPP) c[i] += xcur[i]; + loopi(BPP) t[i] += ((c[i]<<12) + xsrc[i]*xlow + xend[i]*xhigh)>>cscale; + } + uint c[BPP] = {0}; + for(const uchar *xcur = &xsrc[BPP]; xcur < xend; xcur += BPP) + loopi(BPP) c[i] += xcur[i]; + loopi(BPP) t[i] += (yhigh*(c[i] + ((xsrc[i]*xlow + xend[i]*xhigh)>>12)))>>cscale; + } + loopi(BPP) dst[i] = (t[i] * area)>>dscale; + } + } +} static void scaletexture(uchar * RESTRICT src, uint sw, uint sh, uint bpp, uint pitch, uchar * RESTRICT dst, uint dw, uint dh) { @@ -38,30 +95,30 @@ static void scaletexture(uchar * RESTRICT src, uint sw, uint sh, uint bpp, uint { switch(bpp) { - case 1: return halvetexture1(src, sw, sh, pitch, dst); - case 2: return halvetexture2(src, sw, sh, pitch, dst); - case 3: return halvetexture3(src, sw, sh, pitch, dst); - case 4: return halvetexture4(src, sw, sh, pitch, dst); + case 1: return halvetexture<1>(src, sw, sh, pitch, dst); + case 2: return halvetexture<2>(src, sw, sh, pitch, dst); + case 3: return halvetexture<3>(src, sw, sh, pitch, dst); + case 4: return halvetexture<4>(src, sw, sh, pitch, dst); } } else if(sw < dw || sh < dh || sw&(sw-1) || sh&(sh-1) || dw&(dw-1) || dh&(dh-1)) { switch(bpp) { - case 1: return scaletexture1(src, sw, sh, pitch, dst, dw, dh); - case 2: return scaletexture2(src, sw, sh, pitch, dst, dw, dh); - case 3: return scaletexture3(src, sw, sh, pitch, dst, dw, dh); - case 4: return scaletexture4(src, sw, sh, pitch, dst, dw, dh); + case 1: return scaletexture<1>(src, sw, sh, pitch, dst, dw, dh); + case 2: return scaletexture<2>(src, sw, sh, pitch, dst, dw, dh); + case 3: return scaletexture<3>(src, sw, sh, pitch, dst, dw, dh); + case 4: return scaletexture<4>(src, sw, sh, pitch, dst, dw, dh); } } else { switch(bpp) { - case 1: return shifttexture1(src, sw, sh, pitch, dst, dw, dh); - case 2: return shifttexture2(src, sw, sh, pitch, dst, dw, dh); - case 3: return shifttexture3(src, sw, sh, pitch, dst, dw, dh); - case 4: return shifttexture4(src, sw, sh, pitch, dst, dw, dh); + case 1: return shifttexture<1>(src, sw, sh, pitch, dst, dw, dh); + case 2: return shifttexture<2>(src, sw, sh, pitch, dst, dw, dh); + case 3: return shifttexture<3>(src, sw, sh, pitch, dst, dw, dh); + case 4: return shifttexture<4>(src, sw, sh, pitch, dst, dw, dh); } } } @@ -388,15 +445,25 @@ void texreorient(ImageData &s, bool flipx, bool flipy, bool swapxy, int type = T s.replace(d); } +extern const texrotation texrotations[8] = +{ + { false, false, false }, // 0: default + { false, true, true }, // 1: 90 degrees + { true, true, false }, // 2: 180 degrees + { true, false, true }, // 3: 270 degrees + { true, false, false }, // 4: flip X + { false, true, false }, // 5: flip Y + { false, false, true }, // 6: transpose + { true, true, true }, // 7: flipped transpose +}; + void texrotate(ImageData &s, int numrots, int type = TEX_DIFFUSE) { - // 1..3 rotate through 90..270 degrees, 4 flips X, 5 flips Y - if(numrots>=1 && numrots<=5) - texreorient(s, - numrots>=2 && numrots<=4, // flip X on 180/270 degrees - numrots<=2 || numrots==5, // flip Y on 90/180 degrees - (numrots&5)==1, // swap X/Y on 90/270 degrees - type); + if(numrots>=1 && numrots<=7) + { + const texrotation &r = texrotations[numrots]; + texreorient(s, r.flipx, r.flipy, r.swapxy, type); + } } void texoffset(ImageData &s, int xoffset, int yoffset) @@ -1856,7 +1923,7 @@ static void clampvslotoffset(VSlot &dst, Slot *slot = NULL) Texture *t = slot->sts[0].t; int xs = t->xs, ys = t->ys; if(t->type & Texture::MIRROR) { xs *= 2; ys *= 2; } - if((dst.rotation&5)==1) swap(xs, ys); + if(texrotations[dst.rotation].swapxy) swap(xs, ys); dst.offset.x %= xs; if(dst.offset.x < 0) dst.offset.x += xs; dst.offset.y %= ys; if(dst.offset.y < 0) dst.offset.y += ys; } @@ -1925,7 +1992,7 @@ static void mergevslot(VSlot &dst, const VSlot &src, int diff, Slot *slot = NULL } if(diff & (1<rotation = clamp(*rot, 0, 5); + s.variants->rotation = clamp(*rot, 0, 7); propagatevslot(s.variants, 1< &key, Slot &slot, Slot::Tex &t, bool combined = false, const char *prefix = NULL) { if(combined) key.add('&'); @@ -2484,7 +2560,7 @@ static void addname(vector &key, Slot &slot, Slot::Tex &t, bool combined = void Slot::load(int index, Slot::Tex &t) { vector key; - addname(key, *this, t); + addname(key, *this, t, false, shouldpremul(t.type) ? "" : NULL); Slot::Tex *combine = NULL; loopv(sts) { @@ -2526,6 +2602,7 @@ void Slot::load(int index, Slot::Tex &t) if(ts.bpp < 3) swizzleimage(ts); break; } + if(!ts.compressed && shouldpremul(t.type)) texpremul(ts); t.t = newtexture(NULL, key.getbuf(), ts, wrap, true, true, true, compress); } diff --git a/src/engine/texture.h b/src/engine/texture.h index 5ed2d7de..b7cc81fd 100644 --- a/src/engine/texture.h +++ b/src/engine/texture.h @@ -699,6 +699,7 @@ struct Slot virtual VSlot &emptyvslot(); virtual int cancombine(int type) const; + virtual bool shouldpremul(int type) const { return false; } int findtextype(int type, int last = -1) const; @@ -787,6 +788,7 @@ struct DecalSlot : Slot, VSlot VSlot &emptyvslot() { return *this; } int cancombine(int type) const; + bool shouldpremul(int type) const; void reset() { @@ -803,6 +805,11 @@ struct DecalSlot : Slot, VSlot } }; +struct texrotation +{ + bool flipx, flipy, swapxy; +}; + struct cubemapside { GLenum target; @@ -810,6 +817,7 @@ struct cubemapside bool flipx, flipy, swapxy; }; +extern const texrotation texrotations[8]; extern const cubemapside cubemapsides[6]; extern Texture *notexture; extern Shader *nullshader, *hudshader, *hudtextshader, *hudnotextureshader, *nocolorshader, *foggedshader, *foggednotextureshader, *ldrshader, *ldrnotextureshader, *stdworldshader; @@ -851,6 +859,7 @@ extern bool unpackvslot(ucharbuf &buf, VSlot &dst, bool delta); extern Slot dummyslot; extern VSlot dummyvslot; +extern DecalSlot dummydecalslot; extern vector slots; extern vector vslots; diff --git a/src/engine/ui.cpp b/src/engine/ui.cpp index 6be7b9d0..1d80bdb6 100644 --- a/src/engine/ui.cpp +++ b/src/engine/ui.cpp @@ -1907,9 +1907,10 @@ namespace UI int xoff = vslot.offset.x, yoff = vslot.offset.y; if(vslot.rotation) { - if((vslot.rotation&5) == 1) { swap(xoff, yoff); loopk(4) swap(tc[k][0], tc[k][1]); } - if(vslot.rotation >= 2 && vslot.rotation <= 4) { xoff *= -1; loopk(4) tc[k][0] *= -1; } - if(vslot.rotation <= 2 || vslot.rotation == 5) { yoff *= -1; loopk(4) tc[k][1] *= -1; } + const texrotation &r = texrotations[vslot.rotation]; + if(r.swapxy) { swap(xoff, yoff); loopk(4) swap(tc[k].x, tc[k].y); } + if(r.flipx) { xoff *= -1; loopk(4) tc[k].x *= -1; } + if(r.flipy) { yoff *= -1; loopk(4) tc[k].y *= -1; } } loopk(4) { tc[k][0] = tc[k][0]/xt - float(xoff)/tex->xs; tc[k][1] = tc[k][1]/yt - float(yoff)/tex->ys; } diff --git a/src/engine/vertmodel.h b/src/engine/vertmodel.h index 380813cf..ae34133e 100644 --- a/src/engine/vertmodel.h +++ b/src/engine/vertmodel.h @@ -167,6 +167,7 @@ struct vertmodel : animmodel void render(const animstate *as, skin &s, vbocacheentry &vc) { + if(!Shader::lastshader) return; glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, elen, GL_UNSIGNED_SHORT, &((vertmeshgroup *)group)->edata[eoffset]); glde++; xtravertsva += numverts; @@ -443,8 +444,9 @@ struct vertmodel : animmodel } }; -template struct vertloader : modelloader +template struct vertloader : modelloader { + vertloader(const char *name) : modelloader(name) {} }; template struct vertcommands : modelcommands diff --git a/src/engine/world.cpp b/src/engine/world.cpp index b91580dc..f92b9ecc 100644 --- a/src/engine/world.cpp +++ b/src/engine/world.cpp @@ -251,7 +251,7 @@ void modifyoctaentity(int flags, int id, extentity &e, cube *c, const ivec &cor, } vector outsideents; -int spotlights = 0, volumetriclights = 0; +int spotlights = 0, volumetriclights = 0, nospeclights = 0; static bool modifyoctaent(int flags, int id, extentity &e) { @@ -280,7 +280,11 @@ static bool modifyoctaent(int flags, int id, extentity &e) e.flags ^= EF_OCTA; switch(e.type) { - case ET_LIGHT: clearlightcache(id); if(e.attr[4]&L_VOLUMETRIC) { if(flags&MODOE_ADD) volumetriclights++; else --volumetriclights; } break; + case ET_LIGHT: + clearlightcache(id); + if(e.attr[4]&L_VOLUMETRIC) { if(flags&MODOE_ADD) volumetriclights++; else --volumetriclights; } + if(e.attr[4]&L_NOSPEC) { if(!(flags&MODOE_ADD ? nospeclights++ : --nospeclights)) cleardeferredlightshaders(); } + break; case ET_SPOTLIGHT: if(!(flags&MODOE_ADD ? spotlights++ : --spotlights)) { cleardeferredlightshaders(); cleanupvolumetric(); } break; case ET_PARTICLES: clearparticleemitters(); break; case ET_DECAL: if(flags&MODOE_CHANGED) changed(o, r, false); break; @@ -1574,6 +1578,7 @@ void resetmap() outsideents.setsize(0); spotlights = 0; volumetriclights = 0; + nospeclights = 0; } void startmap(const char *name) diff --git a/src/engine/worldio.cpp b/src/engine/worldio.cpp index 9ffd6fe0..d96860fe 100644 --- a/src/engine/worldio.cpp +++ b/src/engine/worldio.cpp @@ -23,6 +23,20 @@ ICOMMAND(setmapdir, "sN", (const char *pth, int *numargs), string mname, mpath; //holds the mapname and mappath +void validmapname(char *dst, const char *src, const char *prefix = NULL, const char *alt = "untitled", size_t maxlen = 100) +{ + if(prefix) while(*prefix) *dst++ = *prefix++; + const char *start = dst; + if(src) loopi(maxlen) + { + char c = *src++; + if(iscubealnum(c) || c == '_' || c == '-' || c == '/' || c == '\\') *dst++ = c; + else break; + } + if(dst > start) *dst = '\0'; + else if(dst != alt) copystring(dst, alt, maxlen); +} + void getmapfilenames(const char *map) { copystring(mpath, mapdir); @@ -44,10 +58,15 @@ void getmapfilenames(const char *map) map = slash; } - copystring(mname, map); + validmapname(mname, map); createdir(mpath); } +void fixmapname(char *name) +{ + validmapname(name, name, NULL, ""); +} + static void fixent(entity &e, int version) { if(version <= 3) @@ -638,7 +657,7 @@ void loadvslot(stream *f, VSlot &vs, int changed) } } if(vs.changed & (1<getlil(); - if(vs.changed & (1<getlil(); + if(vs.changed & (1<getlil(), 0, 7); if(vs.changed & (1<getlil(); diff --git a/src/includes.mk b/src/includes.mk index 5b5c6608..cd6969ea 100644 --- a/src/includes.mk +++ b/src/includes.mk @@ -406,7 +406,7 @@ engine/texture.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h engine/texture.o: shared/ents.h shared/command.h shared/glexts.h engine/texture.o: shared/glemu.h shared/iengine.h shared/igame.h engine/texture.o: engine/world.h engine/octa.h engine/light.h engine/bih.h -engine/texture.o: engine/texture.h engine/model.h engine/scale.h +engine/texture.o: engine/texture.h engine/model.h engine/ui.o: engine/textedit.h engine/water.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h engine/water.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h diff --git a/src/shared/crypto.cpp b/src/shared/crypto.cpp index bcdf5b5a..d5eca5af 100644 --- a/src/shared/crypto.cpp +++ b/src/shared/crypto.cpp @@ -322,6 +322,7 @@ template struct bigint bigint &rshift(int n) { + assert(len <= BI_DIGITS); if(!len || n<=0) return *this; if(n >= len*BI_DIGIT_BITS) { len = 0; return *this; } int dig = (n-1)/BI_DIGIT_BITS; @@ -836,6 +837,24 @@ const ecjacobian ecjacobian::base( #error Unsupported GF #endif +void calcpubkey(gfint privkey, vector &pubstr) +{ + ecjacobian c(ecjacobian::base); + c.mul(privkey); + c.normalize(); + c.print(pubstr); + pubstr.add('\0'); +} + +bool calcpubkey(const char *privstr, vector &pubstr) +{ + if(!privstr[0]) return false; + gfint privkey; + privkey.parse(privstr); + calcpubkey(privkey, pubstr); + return true; +} + void genprivkey(const char *seed, vector &privstr, vector &pubstr) { tiger::hashval hash; @@ -847,11 +866,7 @@ void genprivkey(const char *seed, vector &privstr, vector &pubstr) privkey.printdigits(privstr); privstr.add('\0'); - ecjacobian c(ecjacobian::base); - c.mul(privkey); - c.normalize(); - c.print(pubstr); - pubstr.add('\0'); + calcpubkey(privkey, pubstr); } bool hashstring(const char *str, char *result, int maxlen) diff --git a/src/shared/geom.h b/src/shared/geom.h index b46288c2..55d79cbb 100644 --- a/src/shared/geom.h +++ b/src/shared/geom.h @@ -1867,7 +1867,7 @@ struct hvec2 half x, y; hvec2() {} - hvec2(float x, float y) : x(x), y(y) {} + template hvec2(T x, T y) : x(x), y(y) {} hvec2(const vec2 &v) : x(v.x), y(v.y) {} bool operator==(const hvec2 &h) const { return x == h.x && y == h.y; } @@ -1879,7 +1879,7 @@ struct hvec half x, y, z; hvec() {} - hvec(float x, float y, float z) : x(x), y(y), z(z) {} + template hvec(T x, T y, T z) : x(x), y(y), z(z) {} hvec(const vec &v) : x(v.x), y(v.y), z(v.z) {} bool operator==(const hvec &h) const { return x == h.x && y == h.y && z == h.z; } diff --git a/src/shared/iengine.h b/src/shared/iengine.h index e83a4027..b3db4a51 100644 --- a/src/shared/iengine.h +++ b/src/shared/iengine.h @@ -285,7 +285,7 @@ extern void packvslot(vector &buf, const VSlot *vs); // renderlights -enum { L_NOSHADOW = 1<<0, L_NODYNSHADOW = 1<<1, L_VOLUMETRIC = 1<<2 }; +enum { L_NOSHADOW = 1<<0, L_NODYNSHADOW = 1<<1, L_VOLUMETRIC = 1<<2, L_NOSPEC = 1<<3 }; // dynlight enum @@ -389,6 +389,7 @@ extern bool load_world(const char *mname, const char *cname = NULL); extern bool save_world(const char *mname, bool nolms = false, bool octa = false); extern void setmapdir(const char *pth = NULL); extern void getmapfilenames(const char *cname); +extern void fixmapname(char *name); extern uint getmapcrc(); extern void clearmapcrc(); @@ -433,7 +434,7 @@ extern void stopsounds(); extern void initsound(); // rendermodel -enum { MDL_CULL_VFC = 1<<0, MDL_CULL_DIST = 1<<1, MDL_CULL_OCCLUDED = 1<<2, MDL_CULL_QUERY = 1<<3, MDL_FULLBRIGHT = 1<<4, MDL_NORENDER = 1<<5, MDL_MAPMODEL = 1<<6, MDL_NOBATCH = 1<<7, MDL_ONLYSHADOW = 1<<8 }; +enum { MDL_CULL_VFC = 1<<0, MDL_CULL_DIST = 1<<1, MDL_CULL_OCCLUDED = 1<<2, MDL_CULL_QUERY = 1<<3, MDL_FULLBRIGHT = 1<<4, MDL_NORENDER = 1<<5, MDL_MAPMODEL = 1<<6, MDL_NOBATCH = 1<<7, MDL_ONLYSHADOW = 1<<8, MDL_NOSHADOW = 1<<9, MDL_FORCESHADOW = 1<<10, MDL_FORCETRANSPARENT = 1<<11 }; struct model; struct modelattach @@ -534,6 +535,7 @@ extern void notifywelcome(); // crypto extern void genprivkey(const char *seed, vector &privstr, vector &pubstr); +extern bool calcpubkey(const char *privstr, vector &pubstr); extern bool hashstring(const char *str, char *result, int maxlen); extern void answerchallenge(const char *privstr, const char *challenge, vector &answerstr); extern void *parsepubkey(const char *pubstr); diff --git a/src/shared/tools.cpp b/src/shared/tools.cpp index 820bf78a..bd451287 100644 --- a/src/shared/tools.cpp +++ b/src/shared/tools.cpp @@ -148,7 +148,7 @@ int getuint(ucharbuf &p) n += (p.get() << 7) - 0x80; if(n & (1<<14)) n += (p.get() << 14) - (1<<14); if(n & (1<<21)) n += (p.get() << 21) - (1<<21); - if(n & (1<<28)) n |= -1<<28; + if(n & (1<<28)) n |= ~0U<<28; } return n; } diff --git a/src/shared/zip.cpp b/src/shared/zip.cpp index 98fe7da2..2b8eaf1d 100644 --- a/src/shared/zip.cpp +++ b/src/shared/zip.cpp @@ -447,6 +447,7 @@ struct zipstream : stream zfile.next_in += zfile.avail_in; zfile.avail_in = 0; zfile.total_in = info->compressedsize; + zfile.total_out = info->size; arch->owner = NULL; ended = false; return true; diff --git a/src/windows/lamiae.cbp b/src/windows/lamiae.cbp index 9869a797..b98bb1a6 100644 --- a/src/windows/lamiae.cbp +++ b/src/windows/lamiae.cbp @@ -207,7 +207,6 @@ -