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 @@ -