autoupdateservers 1
bilinear 1
blood 1
-blurshadowmap 1
-blursmsigma 100
bumpmodels 1
-chainsawhudgun 1
clockerror 1000000
clockfix 0
compresspng 9
decalfade 10000
decals 1
demodir "demo"
-dynlightdist 1024
editinview 1
emitmillis 17
entcamdir 1
filltjoints 1
fixwav 1
fov 120
-fpshadowmap 0
fullbrightmodels 60
fullconfilter 65535
fullconsize 75
maxcon 200
maxdecaldistance 512
maxdecaltris 1024
-maxdynlights 5
maxfps 60
maxhistory 1000
maxparticledistance 1024
particlesize 100
particletext 1
playermodel 0
-ragdoll 1
-ragdollfade 1000
-ragdollmillis 10000
reducefilter 1
relativemouse 1
savebak 2
servpingdecay 15000
servpingrate 5000
shaderdetail 3
-shadowmap 1
-shadowmapbias 5
-shadowmapdist 256
-shadowmapintensity 40
-shadowmappeelbias 20
-shadowmapprecision 0
-shadowmapradius 96
-shadowmapsize 9
showclientnum 1
showconnecting 0
showdamagedealt 1
teamcrosshair 1
teamhudguns 1
teamskins 0
-teamsounds 1
texcompress 1025
texcompressquality -1
texgui2d 1
multiplier = [1]
multiplier2 = [16]
newname = [xolatile]
-skelanimlength = [192]
universaldelta = "^n do [delta_@(if $editing [ result edit ] [ result game ])_@modifier @arg1]^n"
listcomplete clearents [
texcoord1 = vtexcoord1 * @lmcoordscale;
@arg2
-
- //:shadowmap
}
] [
@(if (>= $numargs 5) [result $arg5])
vec4 diffuse = vec4(texture2D(diffusemap, texcoord0).rgb, 1.0);
])
vec4 lm = texture2D(lightmap, texcoord1);
-
- //:shadowmap lm
-
- @arg3
-
- diffuse *= colorparams;
- @(if (|| (< $numargs 4) [=s $arg4 []]) [result [gl_FragColor = diffuse * lm;]] [result $arg4])
}
]
]
@(if (btopt "G") [result [
pulse = abs(fract(millis*pulseglowspeed.x)*2.0 - 1.0);
]])
-
- @(if (! (btopt "i")) [result [
- //:shadowmap
- //:water
- ]])
}
] [
uniform vec4 colorparams;
]])
]])
- @(if (|| (! (btopt "i")) (btopt "s")) [result [
- lmc.rgb = max(lmc.rgb*clamp(dot(lmlv, bump), 0.0, 1.0), ambient.xyz);
- @(if (btopt "i") [result [
-
- @(? (btopt "g") "diffuse.rgb" "gl_FragColor.rgb") = diffuse.rgb * lmc.rgb;
- ]] [result [
- //:shadowmap lmc
-
- @(? (|| (btopt "g") (btopt "r")) "diffuse.rgb" "gl_FragColor.rgb") = diffuse.rgb * lmc.rgb;
- ]])
- ]])
-
@(if (btopt "r") [result [
vec3 rvec;
@(if (btopt "t") [result [
]
]
-// model shadowmapping
-
-shadowmapcastervertexshader = [
- result [
- @(if (>= $numargs 2) [result $arg1])
- attribute vec4 vvertex;
- uniform mat4 modelmatrix;
- uniform vec4 shadowintensity;
- varying vec4 shadowmapvals;
- void main(void)
- {
- @(if (>= $numargs 2) [result $arg2] [result [
- #define mpos vvertex
- ]])
- gl_Position = modelmatrix * mpos;
- shadowmapvals = vec4(1.0 - gl_Position.z, 1.0, 0.0, shadowintensity.x);
- }
- ]
-]
-
-shader 0 shadowmapcaster (shadowmapcastervertexshader) [
- varying vec4 shadowmapvals;
- void main(void)
- {
- gl_FragColor = shadowmapvals;
- }
-]
-loop i 4 [
- variantshader 0 shadowmapcaster 0 (shadowmapcastervertexshader (skelanimdefs (+ $i 1)) (skelanim (+ $i 1))) []
-]
-
-shader 0 "shadowmapreceiver" [
- attribute vec4 vvertex;
- uniform mat4 shadowmatrix;
- uniform vec2 shadowmapbias;
- varying vec4 shadowmapvals;
- void main(void)
- {
- gl_Position = shadowmatrix * vvertex;
- shadowmapvals = vec4(0.0, 0.0, shadowmapbias.y - gl_Position.z, 0.0);
- }
-] [
- varying vec4 shadowmapvals;
- void main(void)
- {
- gl_FragColor = shadowmapvals;
- }
-]
-
// model stenciling
notexturemodelvertexshader = [
]
guicheckbox "show scoreboard at death" deathscore
guicheckbox "blood" blood
- guilist [
- guicheckbox "ragdoll deaths" ragdoll
- if $ragdoll [
- guibar
- guicheckbox "keep after respawn" ragdollmillis 10000
- ]
- guibar
- guicheckbox "hide dead players" hidedead
- ]
- guitext "ragdoll velocity multiplier"
- guislider deadpush
guilist [
guicheckbox "fullbright player models" fullbrightmodels 60 0
if $fullbrightmodels [
guibar
guiradio "^f2high detail" shaderdetail 3
]
- guilist [
- guicheckbox "^f3soft shadows^t" shadowmap
- if $shadowmap [
- guibar
- guiradio "^f2medium quality" shadowmapsize 9 [blurshadowmap 1]
- guibar
- guiradio "^f3high quality" shadowmapsize 10 [blurshadowmap 2]
- ] [
- guibar
- ]
- ]
guilist [
guicheckbox "^f0decals^t^t" decals
if $decals [
shared/tools.o \
shared/zip.o \
engine/3dgui.o \
- engine/bih.o \
engine/client.o \
engine/command.o \
engine/console.o \
engine/server.o \
engine/serverbrowser.o \
engine/shader.o \
- engine/shadowmap.o \
engine/sound.o \
engine/texture.o \
engine/world.o \
master: $(MASTER_OBJS)
$(CXX) $(CXXFLAGS) -o sauer_master $(MASTER_OBJS) $(MASTER_LIBS)
-shared/cube2font.o: shared/cube2font.c
- $(CXX) $(CXXFLAGS) -c -o $@ $< `freetype-config --cflags`
-
-cube2font: shared/cube2font.o
- $(CXX) $(CXXFLAGS) -o cube2font shared/cube2font.o `freetype-config --libs` -lz
-
ifneq (,$(findstring DARWIN,$(PLATFORM)))
install: client
cp sauer_client ../sauerbraten.app/Contents/MacOS/sauerbraten_universal
engine/3dgui.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/3dgui.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
engine/3dgui.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/3dgui.o: engine/lightmap.h engine/bih.h engine/texture.h
+engine/3dgui.o: engine/lightmap.h engine/texture.h
engine/3dgui.o: engine/model.h engine/textedit.h
-engine/bih.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
-engine/bih.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
-engine/bih.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/bih.o: engine/lightmap.h engine/bih.h engine/texture.h engine/model.h
engine/client.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/client.o: shared/ents.h shared/command.h shared/glexts.h
engine/client.o: shared/glemu.h shared/iengine.h shared/igame.h
-engine/client.o: engine/world.h engine/octa.h engine/lightmap.h engine/bih.h
+engine/client.o: engine/world.h engine/octa.h engine/lightmap.h
engine/client.o: engine/texture.h engine/model.h
engine/command.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/command.o: shared/ents.h shared/command.h shared/glexts.h
engine/command.o: shared/glemu.h shared/iengine.h shared/igame.h
-engine/command.o: engine/world.h engine/octa.h engine/lightmap.h engine/bih.h
+engine/command.o: engine/world.h engine/octa.h engine/lightmap.h
engine/command.o: engine/texture.h engine/model.h
engine/console.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/console.o: shared/ents.h shared/command.h shared/glexts.h
engine/console.o: shared/glemu.h shared/iengine.h shared/igame.h
-engine/console.o: engine/world.h engine/octa.h engine/lightmap.h engine/bih.h
+engine/console.o: engine/world.h engine/octa.h engine/lightmap.h
engine/console.o: engine/texture.h engine/model.h
engine/decal.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/decal.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
engine/decal.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/decal.o: engine/lightmap.h engine/bih.h engine/texture.h
+engine/decal.o: engine/lightmap.h engine/texture.h
engine/decal.o: engine/model.h
engine/lightmap.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/lightmap.o: shared/ents.h shared/command.h shared/glexts.h
engine/lightmap.o: shared/glemu.h shared/iengine.h shared/igame.h
engine/lightmap.o: engine/world.h engine/octa.h engine/lightmap.h
-engine/lightmap.o: engine/bih.h engine/texture.h engine/model.h
+engine/lightmap.o: engine/texture.h engine/model.h
engine/main.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/main.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
engine/main.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/main.o: engine/lightmap.h engine/bih.h engine/texture.h engine/model.h
+engine/main.o: engine/lightmap.h engine/texture.h engine/model.h
engine/material.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/material.o: shared/ents.h shared/command.h shared/glexts.h
engine/material.o: shared/glemu.h shared/iengine.h shared/igame.h
engine/material.o: engine/world.h engine/octa.h engine/lightmap.h
-engine/material.o: engine/bih.h engine/texture.h engine/model.h
+engine/material.o: engine/texture.h engine/model.h
engine/menus.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/menus.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
engine/menus.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/menus.o: engine/lightmap.h engine/bih.h engine/texture.h
+engine/menus.o: engine/lightmap.h engine/texture.h
engine/menus.o: engine/model.h
engine/normal.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/normal.o: shared/ents.h shared/command.h shared/glexts.h
engine/normal.o: shared/glemu.h shared/iengine.h shared/igame.h
-engine/normal.o: engine/world.h engine/octa.h engine/lightmap.h engine/bih.h
+engine/normal.o: engine/world.h engine/octa.h engine/lightmap.h
engine/normal.o: engine/texture.h engine/model.h
engine/octa.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/octa.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
engine/octa.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/octa.o: engine/lightmap.h engine/bih.h engine/texture.h engine/model.h
+engine/octa.o: engine/lightmap.h engine/texture.h engine/model.h
engine/octaedit.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/octaedit.o: shared/ents.h shared/command.h shared/glexts.h
engine/octaedit.o: shared/glemu.h shared/iengine.h shared/igame.h
engine/octaedit.o: engine/world.h engine/octa.h engine/lightmap.h
-engine/octaedit.o: engine/bih.h engine/texture.h engine/model.h
+engine/octaedit.o: engine/texture.h engine/model.h
engine/octarender.o: engine/engine.h shared/cube.h shared/tools.h
engine/octarender.o: shared/geom.h shared/ents.h shared/command.h
engine/octarender.o: shared/glexts.h shared/glemu.h shared/iengine.h
engine/octarender.o: shared/igame.h engine/world.h engine/octa.h
-engine/octarender.o: engine/lightmap.h engine/bih.h engine/texture.h
+engine/octarender.o: engine/lightmap.h engine/texture.h
engine/octarender.o: engine/model.h
engine/physics.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/physics.o: shared/ents.h shared/command.h shared/glexts.h
engine/physics.o: shared/glemu.h shared/iengine.h shared/igame.h
-engine/physics.o: engine/world.h engine/octa.h engine/lightmap.h engine/bih.h
+engine/physics.o: engine/world.h engine/octa.h engine/lightmap.h
engine/physics.o: engine/texture.h engine/model.h engine/mpr.h
engine/rendergl.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/rendergl.o: shared/ents.h shared/command.h shared/glexts.h
engine/rendergl.o: shared/glemu.h shared/iengine.h shared/igame.h
engine/rendergl.o: engine/world.h engine/octa.h engine/lightmap.h
-engine/rendergl.o: engine/bih.h engine/texture.h engine/model.h
+engine/rendergl.o: engine/texture.h engine/model.h
engine/rendermodel.o: engine/engine.h shared/cube.h shared/tools.h
engine/rendermodel.o: shared/geom.h shared/ents.h shared/command.h
engine/rendermodel.o: shared/glexts.h shared/glemu.h shared/iengine.h
engine/rendermodel.o: shared/igame.h engine/world.h engine/octa.h
-engine/rendermodel.o: engine/lightmap.h engine/bih.h engine/texture.h
-engine/rendermodel.o: engine/model.h engine/ragdoll.h engine/animmodel.h
+engine/rendermodel.o: engine/lightmap.h engine/texture.h
+engine/rendermodel.o: engine/model.h engine/animmodel.h
engine/rendermodel.o: engine/skelmodel.h
engine/rendermodel.o: engine/md5.h engine/iqm.h
engine/renderparticles.o: engine/engine.h shared/cube.h shared/tools.h
engine/renderparticles.o: shared/geom.h shared/ents.h shared/command.h
engine/renderparticles.o: shared/glexts.h shared/glemu.h shared/iengine.h
engine/renderparticles.o: shared/igame.h engine/world.h engine/octa.h
-engine/renderparticles.o: engine/lightmap.h engine/bih.h engine/texture.h
+engine/renderparticles.o: engine/lightmap.h engine/texture.h
engine/renderparticles.o: engine/model.h engine/rendertarget.h
engine/rendertext.o: engine/engine.h shared/cube.h shared/tools.h
engine/rendertext.o: shared/geom.h shared/ents.h shared/command.h
engine/rendertext.o: shared/glexts.h shared/glemu.h shared/iengine.h
engine/rendertext.o: shared/igame.h engine/world.h engine/octa.h
-engine/rendertext.o: engine/lightmap.h engine/bih.h engine/texture.h
+engine/rendertext.o: engine/lightmap.h engine/texture.h
engine/rendertext.o: engine/model.h
engine/renderva.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/renderva.o: shared/ents.h shared/command.h shared/glexts.h
engine/renderva.o: shared/glemu.h shared/iengine.h shared/igame.h
engine/renderva.o: engine/world.h engine/octa.h engine/lightmap.h
-engine/renderva.o: engine/bih.h engine/texture.h engine/model.h
+engine/renderva.o: engine/texture.h engine/model.h
engine/server.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/server.o: shared/ents.h shared/command.h shared/glexts.h
engine/server.o: shared/glemu.h shared/iengine.h shared/igame.h
-engine/server.o: engine/world.h engine/octa.h engine/lightmap.h engine/bih.h
+engine/server.o: engine/world.h engine/octa.h engine/lightmap.h
engine/server.o: engine/texture.h engine/model.h
engine/serverbrowser.o: engine/engine.h shared/cube.h shared/tools.h
engine/serverbrowser.o: shared/geom.h shared/ents.h shared/command.h
engine/serverbrowser.o: shared/glexts.h shared/glemu.h shared/iengine.h
engine/serverbrowser.o: shared/igame.h engine/world.h engine/octa.h
-engine/serverbrowser.o: engine/lightmap.h engine/bih.h engine/texture.h
+engine/serverbrowser.o: engine/lightmap.h engine/texture.h
engine/serverbrowser.o: engine/model.h
engine/shader.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/shader.o: shared/ents.h shared/command.h shared/glexts.h
engine/shader.o: shared/glemu.h shared/iengine.h shared/igame.h
-engine/shader.o: engine/world.h engine/octa.h engine/lightmap.h engine/bih.h
+engine/shader.o: engine/world.h engine/octa.h engine/lightmap.h
engine/shader.o: engine/texture.h engine/model.h
-engine/shadowmap.o: engine/engine.h shared/cube.h shared/tools.h
-engine/shadowmap.o: shared/geom.h shared/ents.h shared/command.h
-engine/shadowmap.o: shared/glexts.h shared/glemu.h shared/iengine.h
-engine/shadowmap.o: shared/igame.h engine/world.h engine/octa.h
-engine/shadowmap.o: engine/lightmap.h engine/bih.h engine/texture.h
-engine/shadowmap.o: engine/model.h engine/rendertarget.h
engine/sound.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/sound.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
engine/sound.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/sound.o: engine/lightmap.h engine/bih.h engine/texture.h
+engine/sound.o: engine/lightmap.h engine/texture.h
engine/sound.o: engine/model.h
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/lightmap.h engine/bih.h
+engine/texture.o: engine/world.h engine/octa.h engine/lightmap.h
engine/texture.o: engine/texture.h engine/model.h
engine/world.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/world.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
engine/world.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/world.o: engine/lightmap.h engine/bih.h engine/texture.h
+engine/world.o: engine/lightmap.h engine/texture.h
engine/world.o: engine/model.h
engine/worldio.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
engine/worldio.o: shared/ents.h shared/command.h shared/glexts.h
engine/worldio.o: shared/glemu.h shared/iengine.h shared/igame.h
-engine/worldio.o: engine/world.h engine/octa.h engine/lightmap.h engine/bih.h
+engine/worldio.o: engine/world.h engine/octa.h engine/lightmap.h
engine/worldio.o: engine/texture.h engine/model.h
fpsgame/ai.o: fpsgame/game.h shared/cube.h shared/tools.h shared/geom.h
fpsgame/ai.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
fpsgame/server.o: fpsgame/game.h shared/cube.h shared/tools.h shared/geom.h
fpsgame/server.o: shared/ents.h shared/command.h shared/glexts.h
fpsgame/server.o: shared/glemu.h shared/iengine.h shared/igame.h fpsgame/ai.h
-fpsgame/server.o: fpsgame/extinfo.h fpsgame/aiman.h
fpsgame/waypoint.o: fpsgame/game.h shared/cube.h shared/tools.h shared/geom.h
fpsgame/waypoint.o: shared/ents.h shared/command.h shared/glexts.h
fpsgame/waypoint.o: shared/glemu.h shared/iengine.h shared/igame.h
engine/engine.h.gch: shared/cube.h shared/tools.h shared/geom.h shared/ents.h
engine/engine.h.gch: shared/command.h shared/glexts.h shared/glemu.h
engine/engine.h.gch: shared/iengine.h shared/igame.h engine/world.h
-engine/engine.h.gch: engine/octa.h engine/lightmap.h engine/bih.h
+engine/engine.h.gch: engine/octa.h engine/lightmap.h
engine/engine.h.gch: engine/texture.h engine/model.h
fpsgame/game.h.gch: shared/cube.h shared/tools.h shared/geom.h shared/ents.h
fpsgame/game.h.gch: shared/command.h shared/glexts.h shared/glemu.h
fpsgame/server-standalone.o: fpsgame/game.h shared/cube.h shared/tools.h
fpsgame/server-standalone.o: shared/geom.h shared/ents.h shared/command.h
fpsgame/server-standalone.o: shared/iengine.h shared/igame.h fpsgame/ai.h
-fpsgame/server-standalone.o: fpsgame/extinfo.h
-fpsgame/server-standalone.o: fpsgame/aiman.h
engine/master-standalone.o: shared/cube.h shared/tools.h shared/geom.h
engine/master-standalone.o: shared/ents.h shared/command.h shared/iengine.h
engine/master-standalone.o: shared/igame.h
void cleanup() {
if(shader && shader->standard) shader = NULL;
}
- void preloadBIH() {
- if(tex->type&Texture::ALPHA && !tex->alphamask) loadalphamask(tex);
- }
void preloadshader() {
//~if(force) cleanup();
loadshader();
else if(cullface && !enablecullface) { glEnable(GL_CULL_FACE); enablecullface = true; }
if(as->cur.anim&ANIM_NOSKIN) {
if(enablealphablend) { glDisable(GL_BLEND); enablealphablend = false; }
- if(shadowmapping) SETMODELSHADER(b, shadowmapcaster);
- else /*if(as->cur.anim&ANIM_SHADOW)*/ SETMODELSHADER(b, notexturemodel);
+ else SETMODELSHADER(b, notexturemodel);
return;
}
setshader(b);
DELETEA(name);
}
virtual void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m) = 0;
- virtual void genBIH(BIH::mesh &m) = 0;
- void genBIH(skin &s, vector<BIH::mesh> &bih, const matrix4x3 &t) {
- BIH::mesh &m = bih.add();
- m.xform = t;
- m.tex = s.tex;
- if(s.tex->type&Texture::ALPHA) m.flags |= BIH::MESH_ALPHA;
- if(noclip) m.flags |= BIH::MESH_NOCLIP;
- if(s.cullface) 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 setshader(Shader *s) {
s->set();
}
void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m) {
loopv(meshes) meshes[i]->calcbb(bbmin, bbmax, m);
}
- void genBIH(vector<skin> &skins, vector<BIH::mesh> &bih, const matrix4x3 &t) {
- loopv(meshes) meshes[i]->genBIH(skins[i], bih, t);
- }
virtual void *animkey() { return this; }
virtual int totalframes() const { return 1; }
bool hasframe(int i) const { return i>=0 && i<totalframes(); }
links[i].p->calcbb(bbmin, bbmax, n);
}
}
- void genBIH(vector<BIH::mesh> &bih, const matrix4x3 &m) {
- matrix4x3 t = m;
- t.scale(model->scale);
- t.translate(translate);
- meshes->genBIH(skins, bih, t);
- loopv(links) {
- matrix4x3 n;
- meshes->concattagtransform(this, links[i].tag, m, n);
- n.translate(links[i].translate, model->scale);
- links[i].p->genBIH(bih, n);
- }
- }
bool link(part *p, const char *tag, const vec &translate = vec(0, 0, 0), int anim = -1, int basetime = 0, vec *pos = NULL) {
int i = meshes ? meshes->findtag(tag) : -1;
if(i<0) {
loopv(skins) if(skins[i].tangents()) return true;
return false;
}
- void preloadBIH() {
- loopv(skins) skins[i].preloadBIH();
- }
void preloadshaders() {
loopv(skins) skins[i].preloadshader();
}
animinterpinfo &ai = d->animinterp[interp];
if((info.anim&ANIM_CLAMP)==ANIM_CLAMP) aitime = min(aitime, int(info.range*info.speed*0.5e-3f));
void *ak = meshes->animkey();
- if(d->ragdoll && !(anim&ANIM_RAGDOLL)) {
- ai.prev.range = ai.cur.range = 0;
- ai.lastswitch = -1;
- }
- else if(ai.lastmodel!=ak || ai.lastswitch<0 || lastmillis-d->lastrendered>aitime) {
+ if(ai.lastmodel!=ak || ai.lastswitch<0 || lastmillis-d->lastrendered>aitime) {
ai.prev = ai.cur = info;
ai.lastswitch = lastmillis-aitime*2;
}
matrixstack[matrixpos].transposedtransformnormal(forward, oforward);
if(!(anim&ANIM_NORENDER)) {
matrix4 modelmatrix;
- modelmatrix.mul(shadowmapping ? shadowmatrix : camprojmatrix, matrixstack[matrixpos]);
+ modelmatrix.mul(camprojmatrix, matrixstack[matrixpos]);
if(model->scale!=1) modelmatrix.scale(model->scale);
if(!translate.iszero()) modelmatrix.translate(translate);
GLOBALPARAM(modelmatrix, modelmatrix);
vec axis(0, -1, 0), forward(1, 0, 0);
matrixpos = 0;
matrixstack[0].identity();
- if(!d || !d->ragdoll || anim&ANIM_RAGDOLL) {
+ if(!d) {
matrixstack[0].settranslation(o);
matrixstack[0].rotate_around_z(yaw*RAD);
matrixstack[0].transformnormal(vec(axis), axis);
if(offsetyaw) m.rotate_around_z(offsetyaw*RAD);
if(offsetpitch) m.rotate_around_y(-offsetpitch*RAD);
}
- void genBIH(vector<BIH::mesh> &bih) {
- if(parts.empty()) return;
- matrix4x3 m;
- initmatrix(m);
- parts[0]->genBIH(bih, m);
- }
- void preloadBIH() {
- model::preloadBIH();
- if(bih) loopv(parts) parts[i]->preloadBIH();
- }
- BIH *setBIH() {
- if(bih) return bih;
- vector<BIH::mesh> meshes;
- genBIH(meshes);
- bih = new BIH(meshes);
- return bih;
- }
bool link(part *p, const char *tag, const vec &translate = vec(0, 0, 0), int anim = -1, int basetime = 0, vec *pos = NULL) {
if(parts.empty()) return false;
return parts[0]->link(p, tag, translate, anim, basetime, pos);
bool mmintersect(const extentity &e, const vec &o, const vec &ray, float maxdist, int mode, float &dist) {
model *m = loadmapmodel(e.attr2);
if(!m) return false;
- if(mode&RAY_SHADOW) {
- if(!m->shadow || e.flags&EF_NOSHADOW) return false;
- }
else if((mode&RAY_ENTS)!=RAY_ENTS && (!m->collide || e.flags&EF_NOCOLLIDE)) return false;
if(!m->bih && (lightmapping > 1 || !m->setBIH())) return false;
vec mo = vec(o).sub(e.o), mray(ray);
}
return m->bih->traverse(mo, mray, maxdist ? maxdist : 1e16f, dist, mode);
}
-
case ID_SVAR: code.add(CODE_SVAR|((ltype >= VAL_ANY ? VAL_STR : ltype)<<CODE_RET)|(id->index<<8)); goto done;
case ID_ALIAS: code.add((id->index < MAXARGS ? CODE_LOOKUPARG : CODE_LOOKUP)|((ltype >= VAL_ANY ? VAL_STR : ltype)<<CODE_RET)|(id->index<<8)); goto done;
case ID_COMMAND: {
- int comtype = CODE_COM, numargs = 0;
+ int comtype = CODE_COM;
code.add(CODE_ENTER);
for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt) {
- case 's': compilestr(code, NULL, 0, true); numargs++; break;
- case 'i': compileint(code); numargs++; break;
- case 'b': compileint(code, INT_MIN); numargs++; break;
- case 'f': compilefloat(code); numargs++; break;
- case 't': compilenull(code); numargs++; break;
- case 'e': compileblock(code); numargs++; break;
- case 'r': compileident(code); numargs++; break;
- case '$': compileident(code, id); numargs++; break;
- case 'N': compileint(code, -1); numargs++; break;
+ case 's': compilestr(code, NULL, 0, true); break;
+ case 'i': compileint(code); break;
+ case 'b': compileint(code, INT_MIN); break;
+ case 'f': compilefloat(code); break;
+ case 't': compilenull(code); break;
+ case 'e': compileblock(code); break;
+ case 'r': compileident(code); break;
+ case '$': compileident(code, id); break;
+ case 'N': compileint(code, -1); break;
#ifndef STANDALONE
- case 'D': comtype = CODE_COMD; numargs++; break;
+ case 'D': comtype = CODE_COMD; break;
#endif
- case 'C': comtype = CODE_COMC; numargs = 1; goto endfmt;
- case 'V': comtype = CODE_COMV; numargs = 2; goto endfmt;
+ case 'C': comtype = CODE_COMC; goto endfmt;
+ case 'V': comtype = CODE_COMV; goto endfmt;
case '1': case '2': case '3': case '4': break;
}
endfmt:
#include "octa.h"
#include "lightmap.h"
-#include "bih.h"
#include "texture.h"
#include "model.h"
extern void reloadtextures();
extern void cleanuptextures();
-// shadowmap
-
-extern int shadowmap, shadowmapcasters;
-extern bool shadowmapping;
-extern matrix4 shadowmatrix;
-
-extern bool isshadowmapcaster(const vec &o, float rad);
-extern bool addshadowmapcaster(const vec &o, float xyrad, float zrad);
-extern bool isshadowmapreceiver(vtxarray *va);
-extern void rendershadowmap();
-extern void pushshadowmap();
-extern void rendershadowmapreceivers();
-extern void guessshadowdir();
-
// rendergl
extern bool hasVAO, hasFBO, hasAFBO, hasDS, hasTF, hasTRG, hasTSW, hasS3TC, hasFXT1, hasLATC, hasRGTC, hasAF, hasFBB, hasUBO, hasMBR;
extern int glversion, glslversion, glcompat;
extern bool overlapsdynent(const vec &o, float radius);
extern void rotatebb(vec ¢er, vec &radius, int yaw);
extern float shadowray(const vec &o, const vec &ray, float radius, int mode, extentity *t = NULL);
-struct ShadowRayCache;
-extern ShadowRayCache *newshadowraycache();
-extern void freeshadowraycache(ShadowRayCache *&cache);
-extern void resetshadowraycache(ShadowRayCache *cache);
-extern float shadowray(ShadowRayCache *cache, const vec &o, const vec &ray, float radius, int mode, extentity *t = NULL);
// world
extern void startmodelquery(occludequery *query);
extern void endmodelquery();
extern void preloadmodelshaders();
-extern void preloadusedmapmodels(bool msg = false, bool bih = false);
+extern void preloadusedmapmodels(bool msg = false);
static inline model *loadmapmodel(int n) {
extern vector<mapmodelinfo> mapmodels;
VSlot *vslot;
Slot *slot;
vector<const extentity *> lights;
- ShadowRayCache *shadowraycache;
bool needspace, doneworking;
SDL_cond *spacecond;
SDL_Thread *thread;
float angle = -ray.dot(normal);
if(angle <= 0) continue;
if(lmshadows && mag) {
- float dist = shadowray(w->shadowraycache, light.o, ray, mag - tolerance, RAY_SHADOW | (lmshadows > 1 ? RAY_ALPHAPOLY : 0));
+ float dist = shadowray(light.o, ray, mag - tolerance, RAY_SHADOW | (lmshadows > 1 ? RAY_ALPHAPOLY : 0));
if(dist < mag - tolerance) continue;
}
lightused |= 1<<i;
blur = new uchar[4*(LM_MAXW + 4)*(LM_MAXH + 4)];
colordata = new vec[4*(LM_MAXW+1 + 4)*(LM_MAXH+1 + 4)];
raydata = new vec[(LM_MAXW + 4)*(LM_MAXH + 4)];
- shadowraycache = newshadowraycache();
needspace = doneworking = false;
spacecond = NULL;
thread = NULL;
delete[] blur;
delete[] colordata;
delete[] raydata;
- freeshadowraycache(shadowraycache);
}
void lightmapworker::cleanupthread() {
bufstart = bufused = 0;
firstlightmap = lastlightmap = curlightmaps = NULL;
needspace = doneworking = false;
- resetshadowraycache(shadowraycache);
}
bool lightmapworker::setupthread() {
mpremip(true);
loadlayermasks();
int numthreads = lightthreads > 0 ? lightthreads : numcpus;
- if(numthreads > 1) preloadusedmapmodels(false, true);
+ if(numthreads > 1) preloadusedmapmodels(false);
resetlightmaps(false);
clearsurfaces(worldroot);
taskprogress = progress = 0;
#define CHECK_CALCLIGHT_PROGRESS_LOCKED(exit, show_calclight_progress, before, after) \
if(check_calclight_progress) { \
- \
if(!calclight_canceled) { \
- \
before; \
show_calclight_progress(); \
check_calclight_canceled(); \
extern void cleanupdecals();
extern void cleanupmodels();
extern void cleanuplightmaps();
- extern void cleanshadowmap();
cleanupva();
cleanupparticles();
cleanupdecals();
cleanupmodels();
cleanuptextures();
cleanuplightmaps();
- cleanshadowmap();
cleanupshaders();
cleanupgl();
setupscreen();
}
void setupmaterials(int start, int len) {
- int hasmat = 0;
- unionfind uf;
if(!len) len = valist.length();
for(int i = start; i < len; i++) {
vtxarray *va = valist[i];
materialsurface *skip = NULL;
loopj(va->matsurfs) {
materialsurface &m = va->matbuf[j];
- int matvol = 0;
- if(matvol) hasmat |= 1<<m.material;
m.skip = 0;
if(skip && m.material == skip->material && m.orient == skip->orient && skip->skip < 0xFFFF)
skip->skip++;
};
skelcommands<md5> md5commands;
-
struct model {
char *name;
float spinyaw, spinpitch, offsetyaw, offsetpitch;
- bool collide, ellipsecollide, shadow, alphadepth, depthoffset;
+ bool collide, ellipsecollide, alphadepth, depthoffset;
float scale;
vec translate;
- BIH *bih;
vec bbcenter, bbradius, bbextend, collidecenter, collideradius;
float rejectradius, eyeheight, collidexyradius, collideheight;
int batch;
- model(const char *name) : name(name ? newstring(name) : NULL), spinyaw(0), spinpitch(0), offsetyaw(0), offsetpitch(0), collide(true), ellipsecollide(false), shadow(true), alphadepth(true), depthoffset(false), scale(1.0f), translate(0, 0, 0), bih(0), bbcenter(0, 0, 0), bbradius(-1, -1, -1), bbextend(0, 0, 0), collidecenter(0, 0, 0), collideradius(-1, -1, -1), rejectradius(-1), eyeheight(0.9f), collidexyradius(0), collideheight(0), batch(-1) {}
- virtual ~model() { DELETEA(name); DELETEP(bih); }
+ model(const char *name) : name(name ? newstring(name) : NULL), spinyaw(0), spinpitch(0), offsetyaw(0), offsetpitch(0), collide(true), ellipsecollide(false),
+ alphadepth(true), depthoffset(false), scale(1.0f), translate(0, 0, 0), bbcenter(0, 0, 0), bbradius(-1, -1, -1), bbextend(0, 0, 0),
+ collidecenter(0, 0, 0), collideradius(-1, -1, -1), rejectradius(-1), eyeheight(0.9f), collidexyradius(0), collideheight(0), batch(-1) {}
+
+ virtual ~model() { DELETEA(name); }
virtual void calcbb(vec ¢er, vec &radius) = 0;
virtual void render(int anim, int basetime, int basetime2, const vec &o, float yaw, float pitch, dynent *d, modelattach *a = NULL, const vec &color = vec(0, 0, 0), const vec &dir = vec(0, 0, 0), float transparent = 1) = 0;
virtual bool load() = 0;
virtual int type() const = 0;
- virtual BIH *setBIH() { return 0; }
virtual bool skeletal() const { return false; }
virtual void setshader(Shader *) {}
virtual void setspec(float) {}
virtual void setalphablend(bool) {}
virtual void setfullbright(float) {}
virtual void setcullface(bool) {}
- virtual void preloadBIH() { if(!bih) setBIH(); }
virtual void preloadshaders() {}
virtual void preloadmeshes() {}
virtual void cleanup() {}
ivec o;
int size; // location and size of cube.
ivec geommin, geommax; // BB of geom
- ivec shadowmapmin, shadowmapmax; // BB of shadowmapped surfaces
ivec matmin, matmax; // BB of any materials
ivec bbmin, bbmax; // BB of everything including children
uchar curvfc, occluded;
occludequery *query;
vector<octaentities *> mapmodels;
int hasmerges, mergelevel;
- bool shadowed;
};
struct cube;
hudmatrix.scale(h/1800.0f, h/1800.0f, 1);
flushhudmatrix(false);
SETSHADER(hudrgb);
- int y = 50, gap = 10;
+ int y = 50, gap = 10;(void)y;
gle::defvertex(2);
gle::deftexcoord0();
loopi(7) {
vector<tjoint> tjoints;
-vec shadowmapmin, shadowmapmax;
-
-int calcshadowmask(vec *pos, int numpos) {
- extern vec shadowdir;
- int mask = 0, used = 1;
- vec pe = vec(pos[1]).sub(pos[0]);
- loopk(numpos-2) {
- vec e = vec(pos[k+2]).sub(pos[0]);
- if(vec().cross(pe, e).dot(shadowdir)>0) {
- mask |= 1<<k;
- used |= 6<<k;
- }
- pe = e;
- }
- if(!mask) return 0;
- loopk(numpos) if(used&(1<<k)) {
- const vec &v = pos[k];
- shadowmapmin.min(v);
- shadowmapmax.max(v);
- }
- return mask;
-}
-
VARFP(filltjoints, 0, 1, 1, allchanged());
void reduceslope(ivec &n) {
void addcubeverts(VSlot &vslot, int orient, int size, vec *pos, ushort texture, ushort lmid, vertinfo *vinfo, int numverts, int tj = -1, bool alpha = false, int layer = LAYER_TOP) {
(void) size;
int dim = dimension(orient);
- int shadowmask = alpha ? 0 : calcshadowmask(pos, numverts);
+ int shadowmask = 0;
LightMap *lm = NULL;
LightMapTexture *lmtex = NULL;
if(lightmaps.inrange(lmid-LMID_RESERVED)) {
loopi(MAXMERGELEVEL+1) vamergeoffset[i] = vamerges[i].length();
vc.origin = co;
vc.size = size;
- shadowmapmin = vec(co).add(size);
- shadowmapmax = vec(co);
int maxlevel = -1;
rendercube(c, co, size, csi, maxlevel);
ivec bbmin, bbmax;
va->geommin = bbmin;
va->geommax = bbmax;
calcmatbb(co, size, va->matmin, va->matmax);
- va->shadowmapmin = ivec(shadowmapmin.mul(8)).shr(3);
- va->shadowmapmax = ivec(shadowmapmax.mul(8)).add(7).shr(3);
va->hasmerges = vahasmerges;
va->mergelevel = vamergemax;
}
clearvas(worldroot);
resetqueries();
resetclipplanes();
- guessshadowdir();
entitiesinoctanodes();
tjoints.setsize(0);
if(filltjoints) findtjoints();
float hitentdist;
int hitent, hitorient;
-static float disttoent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t) {
- vec eo, es;
- int orient = -1;
- float dist = radius, f = 0.0f;
- const vector<extentity *> &ents = entities::getents();
- #define entintersect(mask, type, func) {\
- if((mode&(mask))==(mask)) loopv(oc->type) { \
- \
- extentity &e = *ents[oc->type[i]]; \
- if(!(e.flags&EF_OCTA) || &e==t) continue; \
- func; \
- if(f<dist && f>0 && vec(ray).mul(f).add(o).insidebb(oc->o, oc->size)) { \
- \
- hitentdist = dist = f; \
- hitent = oc->type[i]; \
- hitorient = orient; \
- } \
- } \
- }
- entintersect(RAY_POLY, mapmodels,
- if(!mmintersect(e, o, ray, radius, mode, f)) continue;
- );
- entintersect(RAY_ENTS, other,
- entselectionbox(e, eo, es);
- if(!rayboxintersect(eo, es, o, ray, f, orient)) continue;
- );
- entintersect(RAY_ENTS, mapmodels,
- entselectionbox(e, eo, es);
- if(!rayboxintersect(eo, es, o, ray, f, orient)) continue;
- );
- return dist;
-}
+//~static float disttoent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t) {
+ //~vec eo, es;
+ //~int orient = -1;
+ //~float dist = radius, f = 0.0f;
+ //~const vector<extentity *> &ents = entities::getents();
+ //~#define entintersect(mask, type, func) {\
+ //~if((mode&(mask))==(mask)) loopv(oc->type) { \
+ //~\
+ //~extentity &e = *ents[oc->type[i]]; \
+ //~if(!(e.flags&EF_OCTA) || &e==t) continue; \
+ //~func; \
+ //~if(f<dist && f>0 && vec(ray).mul(f).add(o).insidebb(oc->o, oc->size)) { \
+ //~\
+ //~hitentdist = dist = f; \
+ //~hitent = oc->type[i]; \
+ //~hitorient = orient; \
+ //~} \
+ //~} \
+ //~}
+ //~entintersect(RAY_ENTS, other,
+ //~entselectionbox(e, eo, es);
+ //~if(!rayboxintersect(eo, es, o, ray, f, orient)) continue;
+ //~);
+ //~entintersect(RAY_ENTS, mapmodels,
+ //~entselectionbox(e, eo, es);
+ //~if(!rayboxintersect(eo, es, o, ray, f, orient)) continue;
+ //~);
+ //~return dist;
+//~}
static float disttooutsideent(const vec &o, const vec &ray, float radius, extentity *t) {
vec eo, es;
return dist;
}
-// optimized shadow version
-static float shadowent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t) {
- float dist = radius, f = 0.0f;
- const vector<extentity *> &ents = entities::getents();
- loopv(oc->mapmodels) {
- extentity &e = *ents[oc->mapmodels[i]];
- if(!(e.flags&EF_OCTA) || &e==t) continue;
- if(!mmintersect(e, o, ray, radius, mode, f)) continue;
- if(f>0 && f<dist) dist = f;
- }
- return dist;
-}
-
#define INITRAYCUBE \
float dist = 0, dent = radius > 0 ? radius : 1e16f; \
vec v(o), invray(ray.x ? 1/ray.x : 1e16f, ray.y ? 1/ray.y : 1e16f, ray.z ? 1/ray.z : 1e16f); \
levels[worldscale] = worldroot; \
int lshift = worldscale, elvl = mode&RAY_BB ? worldscale : 0; \
ivec lsizemask(invray.x>0 ? 1 : 0, invray.y>0 ? 1 : 0, invray.z>0 ? 1 : 0); \
+ (void) elvl; (void) dent;
#define CHECKINSIDEWORLD \
if(!insideworld(o)) { \
dist += disttoworld; \
}
-#define DOWNOCTREE(disttoent, earlyexit) \
- cube *lc = levels[lshift]; \
- for(;;) { \
- \
- lshift--; \
- lc += octastep(x, y, z, lshift); \
- if(lc->ext && lc->ext->ents && lshift < elvl) { \
- \
- float edist = disttoent(lc->ext->ents, o, ray, dent, mode, t); \
- if(edist < dent) { \
- \
- earlyexit return min(edist, dist); \
- elvl = lshift; \
- dent = min(dent, edist); \
- } \
- } \
- if(lc->children==NULL) break; \
- lc = lc->children; \
- levels[lshift] = lc; \
- }
+//~#define DOWNOCTREE(disttoent, earlyexit) \
+ //~cube *lc = levels[lshift]; \
+ //~for(;;) { \
+ //~lshift--; \
+ //~lc += octastep(x, y, z, lshift); \
+ //~if(lc->ext && lc->ext->ents && lshift < elvl) { \
+ //~\
+ //~float edist = disttoent(lc->ext->ents, o, ray, dent, mode, t); \
+ //~if(edist < dent) { \
+ //~\
+ //~earlyexit return min(edist, dist); \
+ //~elvl = lshift; \
+ //~dent = min(dent, edist); \
+ //~} \
+ //~} \
+ //~if(lc->children==NULL) break; \
+ //~lc = lc->children; \
+ //~levels[lshift] = lc; \
+ //~}
#define FINDCLOSEST(xclosest, yclosest, zclosest) \
float dx = (lo.x+(lsizemask.x<<lshift)-v.x)*invray.x, \
CHECKINSIDEWORLD;
int closest = -1, x = int(v.x), y = int(v.y), z = int(v.z);
for(;;) {
- DOWNOCTREE(disttoent, if(mode&RAY_SHADOW));
+ cube *lc = levels[lshift];
+ for(;;) {
+ lshift--;
+ lc += octastep(x, y, z, lshift);
+ //~if(lc->ext && lc->ext->ents && lshift < elvl) {
+ //~float edist = disttoent(lc->ext->ents, o, ray, dent, mode, t);
+ //~if(edist < dent) {
+ //~return min(edist, dist);
+ //~elvl = lshift;
+ //~dent = min(dent, edist);
+ //~}
+ //~}
+ if(lc->children==NULL) break;
+ lc = lc->children;
+ levels[lshift] = lc;
+ }
+
int lsize = 1<<lshift;
cube &c = *lc;
if((dist>0 || !(mode&RAY_SKIPFIRST)) &&
}
// optimized version for lightmap shadowing... every cycle here counts!!!
+
float shadowray(const vec &o, const vec &ray, float radius, int mode, extentity *t) {
INITRAYCUBE;
CHECKINSIDEWORLD;
int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z); (void) side;
for(;;) {
- DOWNOCTREE(shadowent, );
- cube &c = *lc;
- ivec lo(x&(~0U<<lshift), y&(~0U<<lshift), z&(~0U<<lshift));
- if(!isempty(c) && !(c.material&MAT_ALPHA)) {
- if(isentirelysolid(c)) {
- return dist;
- }
- else {
- const clipplanes &p = getclipplanes(c, lo, 1<<lshift, false, 1);
- INTERSECTPLANES(side = p.side[i], goto nextcube);
- INTERSECTBOX(side = (i<<1) + 1 - lsizemask[i], goto nextcube);
- if(exitdist >= 0) {
- return dist+max(enterdist+0.1f, 0.0f);
- }
- }
+ //~DOWNOCTREE(shadowent, );
+
+ cube *lc = levels[lshift];
+ for(;;) {
+ lshift--;
+ lc += octastep(x, y, z, lshift);
+ //~if(lc->ext && lc->ext->ents && lshift < elvl) {
+ //~float edist = shadowent(lc->ext->ents, o, ray, dent, mode, t);
+ //~if(edist < dent) {
+ //~return min(edist, dist);
+ //~elvl = lshift;
+ //~dent = min(dent, edist);
+ //~}
+ //~}
+ if(lc->children==NULL) break;
+ lc = lc->children;
+ levels[lshift] = lc;
}
- nextcube:
- FINDCLOSEST(side = O_RIGHT - lsizemask.x, side = O_FRONT - lsizemask.y, side = O_TOP - lsizemask.z);
- if(dist>=radius) return dist;
- UPOCTREE(return radius);
- }
-}
-
-// thread safe version
-struct ShadowRayCache {
- clipplanes clipcache[MAXCLIPPLANES];
- int version;
- ShadowRayCache() : version(-1) {}
-};
-
-ShadowRayCache *newshadowraycache() { return new ShadowRayCache; }
-
-void freeshadowraycache(ShadowRayCache *&cache) { delete cache; cache = NULL; }
-
-void resetshadowraycache(ShadowRayCache *cache) {
- cache->version++;
- if(!cache->version) {
- memclear(cache->clipcache);
- cache->version = 1;
- }
-}
-
-float shadowray(ShadowRayCache *cache, const vec &o, const vec &ray, float radius, int mode, extentity *t) {
- INITRAYCUBE;
- CHECKINSIDEWORLD;
- int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z); (void) side;
- for(;;) {
- DOWNOCTREE(shadowent, );
cube &c = *lc;
ivec lo(x&(~0U<<lshift), y&(~0U<<lshift), z&(~0U<<lshift));
if(!isempty(c) && !(c.material&MAT_ALPHA)) {
return dist;
}
else {
- clipplanes &p = cache->clipcache[int(&c - worldroot)&(MAXCLIPPLANES-1)];
- if(p.owner != &c || p.version != cache->version) { p.owner = &c; p.version = cache->version; genclipplanes(c, lo, 1<<lshift, p, false); }
+ const clipplanes &p = getclipplanes(c, lo, 1<<lshift, false, 1);
INTERSECTPLANES(side = p.side[i], goto nextcube);
INTERSECTBOX(side = (i<<1) + 1 - lsizemask[i], goto nextcube);
if(exitdist >= 0) {
+++ /dev/null
-struct ragdollskel {
- struct vert {
- vec pos;
- float radius, weight;
- };
- struct tri {
- int vert[3];
- bool shareverts(const tri &t) const {
- loopi(3) loopj(3) if(vert[i] == t.vert[j]) return true;
- return false;
- }
- };
- struct distlimit {
- int vert[2];
- float mindist, maxdist;
- };
- struct rotlimit {
- int tri[2];
- float maxangle;
- matrix3 middle;
- };
- struct rotfriction {
- int tri[2];
- matrix3 middle;
- };
- struct joint {
- int bone, tri, vert[3];
- float weight;
- matrix4x3 orient;
- };
- struct reljoint {
- int bone, parent;
- };
- bool loaded, animjoints;
- int eye;
- vector<vert> verts;
- vector<tri> tris;
- vector<distlimit> distlimits;
- vector<rotlimit> rotlimits;
- vector<rotfriction> rotfrictions;
- vector<joint> joints;
- vector<reljoint> reljoints;
- ragdollskel() : loaded(false), animjoints(false), eye(-1) {}
- void setupjoints() {
- loopv(verts) verts[i].weight = 0;
- loopv(joints) {
- joint &j = joints[i];
- j.weight = 0;
- vec pos(0, 0, 0);
- loopk(3) if(j.vert[k]>=0) {
- pos.add(verts[j.vert[k]].pos);
- j.weight++;
- verts[j.vert[k]].weight++;
- }
- if(j.weight) j.weight = 1/j.weight;
- pos.mul(j.weight);
- tri &t = tris[j.tri];
- matrix4x3 &m = j.orient;
- const vec &v1 = verts[t.vert[0]].pos,
- &v2 = verts[t.vert[1]].pos,
- &v3 = verts[t.vert[2]].pos;
- m.a = vec(v2).sub(v1).normalize();
- m.c.cross(m.a, vec(v3).sub(v1)).normalize();
- m.b.cross(m.c, m.a);
- m.d = pos;
- m.transpose();
- }
- loopv(verts) if(verts[i].weight) verts[i].weight = 1/verts[i].weight;
- reljoints.shrink(0);
- }
- void setuprotfrictions() {
- rotfrictions.shrink(0);
- loopv(tris) for(int j = i+1; j < tris.length(); j++) if(tris[i].shareverts(tris[j])) {
- rotfriction &r = rotfrictions.add();
- r.tri[0] = i;
- r.tri[1] = j;
- }
- }
- void setup() {
- setupjoints();
- setuprotfrictions();
- loaded = true;
- }
- void addreljoint(int bone, int parent) {
- reljoint &r = reljoints.add();
- r.bone = bone;
- r.parent = parent;
- }
-};
-
-struct ragdolldata {
- struct vert {
- vec oldpos, pos, newpos;
- float weight;
- bool collided, stuck;
- vert() : pos(0, 0, 0), newpos(0, 0, 0), weight(0), collided(false), stuck(true) {}
- };
- ragdollskel *skel;
- int millis, collidemillis, collisions, floating, lastmove, unsticks;
- vec offset, center;
- float radius, timestep, scale;
- vert *verts;
- matrix3 *tris;
- matrix4x3 *animjoints;
- dualquat *reljoints;
- ragdolldata(ragdollskel *skel, float scale = 1)
- : skel(skel),
- millis(lastmillis),
- collidemillis(0),
- collisions(0),
- floating(0),
- lastmove(lastmillis),
- unsticks(INT_MAX),
- radius(0),
- timestep(0),
- scale(scale),
- verts(new vert[skel->verts.length()]),
- tris(new matrix3[skel->tris.length()]),
- animjoints(!skel->animjoints || skel->joints.empty() ? NULL : new matrix4x3[skel->joints.length()]),
- reljoints(skel->reljoints.empty() ? NULL : new dualquat[skel->reljoints.length()]) {
- }
- ~ragdolldata() {
- delete[] verts;
- delete[] tris;
- if(animjoints) delete[] animjoints;
- if(reljoints) delete[] reljoints;
- }
- void calcanimjoint(int i, const matrix4x3 &anim) {
- if(!animjoints) return;
- ragdollskel::joint &j = skel->joints[i];
- vec pos(0, 0, 0);
- loopk(3) if(j.vert[k]>=0) pos.add(verts[j.vert[k]].pos);
- pos.mul(j.weight);
- ragdollskel::tri &t = skel->tris[j.tri];
- matrix4x3 m;
- const vec &v1 = verts[t.vert[0]].pos,
- &v2 = verts[t.vert[1]].pos,
- &v3 = verts[t.vert[2]].pos;
- m.a = vec(v2).sub(v1).normalize();
- m.c.cross(m.a, vec(v3).sub(v1)).normalize();
- m.b.cross(m.c, m.a);
- m.d = pos;
- animjoints[i].transposemul(m, anim);
- }
- void calctris() {
- loopv(skel->tris) {
- ragdollskel::tri &t = skel->tris[i];
- matrix3 &m = tris[i];
- const vec &v1 = verts[t.vert[0]].pos,
- &v2 = verts[t.vert[1]].pos,
- &v3 = verts[t.vert[2]].pos;
- m.a = vec(v2).sub(v1).normalize();
- m.c.cross(m.a, vec(v3).sub(v1)).normalize();
- m.b.cross(m.c, m.a);
- }
- }
- void calcboundsphere() {
- center = vec(0, 0, 0);
- loopv(skel->verts) center.add(verts[i].pos);
- center.div(skel->verts.length());
- radius = 0;
- loopv(skel->verts) radius = max(radius, verts[i].pos.dist(center));
- }
- void init(dynent *d) {
- extern int ragdolltimestepmin;
- float ts = ragdolltimestepmin/1000.0f;
- loopv(skel->verts) (verts[i].oldpos = verts[i].pos).sub(vec(d->vel).add(d->falling).mul(ts));
- timestep = ts;
- calctris();
- calcboundsphere();
- offset = d->o;
- offset.sub(skel->eye >= 0 ? verts[skel->eye].pos : center);
- offset.z += (d->eyeheight + d->aboveeye)/2;
- }
- void move(dynent *pl, float ts);
- void updatepos();
- void constrain();
- void constraindist();
- void applyrotlimit(ragdollskel::tri &t1, ragdollskel::tri &t2, float angle, const vec &axis);
- void constrainrot();
- void calcrotfriction();
- void applyrotfriction(float ts);
- void tryunstick(float speed);
- static inline bool collidevert(const vec &pos, const vec &dir, float radius) {
- static struct vertent : physent {
- vertent() {
- type = ENT_BOUNCE;
- radius = xradius = yradius = eyeheight = aboveeye = 1;
- }
- } v;
- v.o = pos;
- if(v.radius != radius) v.radius = v.xradius = v.yradius = v.eyeheight = v.aboveeye = radius;
- return collide(&v, dir, 0, false);
- }
-};
-
-/*
- seed particle position = avg(modelview * base2anim * spherepos)
- mapped transform = invert(curtri) * origtrig
- parented transform = parent{invert(curtri) * origtrig} * (invert(parent{base2anim}) * base2anim)
-*/
-
-void ragdolldata::constraindist() {
- float invscale = 1.0f/scale;
- loopv(skel->distlimits) {
- ragdollskel::distlimit &d = skel->distlimits[i];
- vert &v1 = verts[d.vert[0]], &v2 = verts[d.vert[1]];
- vec dir = vec(v2.pos).sub(v1.pos);
- float dist = dir.magnitude()*invscale, cdist;
- if(dist < d.mindist) cdist = d.mindist;
- else if(dist > d.maxdist) cdist = d.maxdist;
- else continue;
- if(dist > 1e-4f) dir.mul(cdist*0.5f/dist);
- else dir = vec(0, 0, cdist*0.5f/invscale);
- vec center = vec(v1.pos).add(v2.pos).mul(0.5f);
- v1.newpos.add(vec(center).sub(dir));
- v1.weight++;
- v2.newpos.add(vec(center).add(dir));
- v2.weight++;
- }
-}
-
-inline void ragdolldata::applyrotlimit(ragdollskel::tri &t1, ragdollskel::tri &t2, float angle, const vec &axis) {
- vert &v1a = verts[t1.vert[0]], &v1b = verts[t1.vert[1]], &v1c = verts[t1.vert[2]],
- &v2a = verts[t2.vert[0]], &v2b = verts[t2.vert[1]], &v2c = verts[t2.vert[2]];
- vec m1 = vec(v1a.pos).add(v1b.pos).add(v1c.pos).div(3),
- m2 = vec(v2a.pos).add(v2b.pos).add(v2c.pos).div(3),
- q1a, q1b, q1c, q2a, q2b, q2c;
- float w1 = q1a.cross(axis, vec(v1a.pos).sub(m1)).magnitude() +
- q1b.cross(axis, vec(v1b.pos).sub(m1)).magnitude() +
- q1c.cross(axis, vec(v1c.pos).sub(m1)).magnitude(),
- w2 = q2a.cross(axis, vec(v2a.pos).sub(m2)).magnitude() +
- q2b.cross(axis, vec(v2b.pos).sub(m2)).magnitude() +
- q2c.cross(axis, vec(v2c.pos).sub(m2)).magnitude();
- angle /= w1 + w2 + 1e-9f;
- float a1 = angle*w2, a2 = -angle*w1,
- s1 = sinf(a1), s2 = sinf(a2);
- vec c1 = vec(axis).mul(1 - cosf(a1)), c2 = vec(axis).mul(1 - cosf(a2));
- v1a.newpos.add(vec().cross(c1, q1a).madd(q1a, s1).add(v1a.pos));
- v1a.weight++;
- v1b.newpos.add(vec().cross(c1, q1b).madd(q1b, s1).add(v1b.pos));
- v1b.weight++;
- v1c.newpos.add(vec().cross(c1, q1c).madd(q1c, s1).add(v1c.pos));
- v1c.weight++;
- v2a.newpos.add(vec().cross(c2, q2a).madd(q2a, s2).add(v2a.pos));
- v2a.weight++;
- v2b.newpos.add(vec().cross(c2, q2b).madd(q2b, s2).add(v2b.pos));
- v2b.weight++;
- v2c.newpos.add(vec().cross(c2, q2c).madd(q2c, s2).add(v2c.pos));
- v2c.weight++;
-}
-
-void ragdolldata::constrainrot() {
- loopv(skel->rotlimits) {
- ragdollskel::rotlimit &r = skel->rotlimits[i];
- matrix3 rot;
- rot.mul(tris[r.tri[0]], r.middle);
- rot.multranspose(tris[r.tri[1]]);
- vec axis;
- float angle;
- if(!rot.calcangleaxis(angle, axis)) continue;
- angle = r.maxangle - fabs(angle);
- if(angle >= 0) continue;
- angle += 1e-3f;
- applyrotlimit(skel->tris[r.tri[0]], skel->tris[r.tri[1]], angle, axis);
- }
-}
-
-VAR(ragdolltimestepmin, 1, 5, 50);
-VAR(ragdolltimestepmax, 1, 10, 50);
-FVAR(ragdollrotfric, 0, 0.85f, 1);
-FVAR(ragdollrotfricstop, 0, 0.1f, 1);
-
-void ragdolldata::calcrotfriction() {
- loopv(skel->rotfrictions) {
- ragdollskel::rotfriction &r = skel->rotfrictions[i];
- r.middle.transposemul(tris[r.tri[0]], tris[r.tri[1]]);
- }
-}
-
-void ragdolldata::applyrotfriction(float ts) {
- calctris();
- float stopangle = 2*M_PI*ts*ragdollrotfricstop, rotfric = 1.0f - pow(ragdollrotfric, ts*1000.0f/ragdolltimestepmin);
- loopv(skel->rotfrictions) {
- ragdollskel::rotfriction &r = skel->rotfrictions[i];
- matrix3 rot;
- rot.mul(tris[r.tri[0]], r.middle);
- rot.multranspose(tris[r.tri[1]]);
- vec axis;
- float angle;
- if(rot.calcangleaxis(angle, axis)) {
- angle *= -(fabs(angle) >= stopangle ? rotfric : 1.0f);
- applyrotlimit(skel->tris[r.tri[0]], skel->tris[r.tri[1]], angle, axis);
- }
- }
- loopv(skel->verts) {
- vert &v = verts[i];
- if(v.weight) v.pos = v.newpos.div(v.weight);
- v.newpos = vec(0, 0, 0);
- v.weight = 0;
- }
-}
-
-void ragdolldata::tryunstick(float speed) {
- vec unstuck(0, 0, 0);
- int stuck = 0;
- loopv(skel->verts) {
- vert &v = verts[i];
- if(v.stuck) {
- if(collidevert(v.pos, vec(0, 0, 0), skel->verts[i].radius)) { stuck++; continue; }
- v.stuck = false;
- }
- unstuck.add(v.pos);
- }
- unsticks = 0;
- if(!stuck || stuck >= skel->verts.length()) return;
- unstuck.div(skel->verts.length() - stuck);
- loopv(skel->verts) {
- vert &v = verts[i];
- if(v.stuck) {
- v.pos.add(vec(unstuck).sub(v.pos).rescale(speed));
- unsticks++;
- }
- }
-}
-
-void ragdolldata::updatepos() {
- loopv(skel->verts) {
- vert &v = verts[i];
- if(v.weight) {
- v.newpos.div(v.weight);
- if(!collidevert(v.newpos, vec(v.newpos).sub(v.pos), skel->verts[i].radius)) v.pos = v.newpos;
- else {
- vec dir = vec(v.newpos).sub(v.oldpos);
- if(dir.dot(collidewall) < 0) v.oldpos = vec(v.pos).sub(dir.reflect(collidewall));
- v.collided = true;
- }
- }
- v.newpos = vec(0, 0, 0);
- v.weight = 0;
- }
-}
-
-VAR(ragdollconstrain, 1, 5, 100);
-
-void ragdolldata::constrain() {
- loopi(ragdollconstrain) {
- constraindist();
- updatepos();
- calctris();
- constrainrot();
- updatepos();
- }
-}
-
-FVAR(ragdollbodyfric, 0, 0.95f, 1);
-FVAR(ragdollbodyfricscale, 0, 2, 10);
-FVAR(ragdollgroundfric, 0, 0.8f, 1);
-FVAR(ragdollairfric, 0, 0.996f, 1);
-FVAR(ragdollunstick, 0, 10, 1e3f);
-VAR(ragdollexpireoffset, 0, 1500, 30000);
-
-void ragdolldata::move(dynent *pl, float ts) {
- extern const float GRAVITY;
- if(collidemillis && lastmillis > collidemillis) return;
- pl->inwater = MAT_AIR;
- calcrotfriction();
- float tsfric = timestep ? ts/timestep : 1,
- airfric = ragdollairfric + min((ragdollbodyfricscale*collisions)/skel->verts.length(), 1.0f)*(ragdollbodyfric - ragdollairfric);
- collisions = 0;
- loopv(skel->verts) {
- vert &v = verts[i];
- vec dpos = vec(v.pos).sub(v.oldpos);
- dpos.z -= GRAVITY*ts*ts;
- dpos.mul(pow(1.0f * (v.collided ? ragdollgroundfric : airfric), ts*1000.0f/ragdolltimestepmin)*tsfric);
- v.oldpos = v.pos;
- v.pos.add(dpos);
- }
- applyrotfriction(ts);
- loopv(skel->verts) {
- vert &v = verts[i];
- if(v.pos.z < 0) { v.pos.z = 0; v.oldpos = v.pos; collisions++; }
- vec dir = vec(v.pos).sub(v.oldpos);
- v.collided = collidevert(v.pos, dir, skel->verts[i].radius);
- if(v.collided) {
- v.pos = v.oldpos;
- v.oldpos.sub(dir.reflect(collidewall));
- collisions++;
- }
- }
- if(unsticks && ragdollunstick) tryunstick(ts*ragdollunstick);
- timestep = ts;
- if(collisions) {
- floating = 0;
- if(!collidemillis) collidemillis = lastmillis + ragdollexpireoffset;
- }
- else if(++floating > 1 && lastmillis < collidemillis) collidemillis = 0;
- constrain();
- calctris();
- calcboundsphere();
-}
-
-FVAR(ragdolleyesmooth, 0, 0.5f, 1);
-VAR(ragdolleyesmoothmillis, 1, 250, 10000);
-
-void moveragdoll(dynent *d) {
- if(!curtime || !d->ragdoll) return;
- if(!d->ragdoll->collidemillis || lastmillis < d->ragdoll->collidemillis) {
- int lastmove = d->ragdoll->lastmove;
- while(d->ragdoll->lastmove + (lastmove == d->ragdoll->lastmove ? ragdolltimestepmin : ragdolltimestepmax) <= lastmillis) {
- int timestep = min(ragdolltimestepmax, lastmillis - d->ragdoll->lastmove);
- d->ragdoll->move(d, timestep/1000.0f);
- d->ragdoll->lastmove += timestep;
- }
- }
- vec eye = d->ragdoll->skel->eye >= 0 ? d->ragdoll->verts[d->ragdoll->skel->eye].pos : d->ragdoll->center;
- eye.add(d->ragdoll->offset);
- float k = pow(ragdolleyesmooth, float(curtime)/ragdolleyesmoothmillis);
- d->o.mul(k).add(eye.mul(1-k));
-}
-
-void cleanragdoll(dynent *d) {
- DELETEP(d->ragdoll);
-}
hwcubetexsize = val;
if(glversion >= 300 || hasext("GL_ARB_texture_float") || hasext("GL_ATI_texture_float")) {
hasTF = true;
- shadowmap = 1;
- extern int smoothshadowmappeel;
- smoothshadowmappeel = 1;
}
if(glversion >= 300 || hasext("GL_ARB_texture_rg")) {
hasTRG = true;
void rendergame(bool mainpass) {
game::rendergame(mainpass);
- if(!shadowmapping) renderedgame = true;
+ renderedgame = true;
}
int drawtex = 0;
model *loadingmodel = NULL;
-#include "ragdoll.h"
#include "animmodel.h"
#include "skelmodel.h"
COMMAND(mdlpitch, "f");
-void mdlshadow(int *shadow) {
- checkmdl;
- loadingmodel->shadow = *shadow!=0;
-}
-
-COMMAND(mdlshadow, "i");
-
void mdlbb(float *rad, float *h, float *eyeheight) {
checkmdl;
loadingmodel->collidexyradius = *rad;
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; \
- skelmodel::skelmeshgroup *meshes = (skelmodel::skelmeshgroup *)m->parts.last()->meshes; \
- if(!meshes) return; \
- skelmodel::skeleton *skel = meshes->skel; \
- if(!skel->ragdoll) skel->ragdoll = new ragdollskel; \
- ragdollskel *ragdoll = skel->ragdoll; \
- if(ragdoll->loaded) return;
-
-void rdvert(float *x, float *y, float *z, float *radius) {
- checkragdoll;
- ragdollskel::vert &v = ragdoll->verts.add();
- v.pos = vec(*x, *y, *z);
- v.radius = *radius > 0 ? *radius : 1;
-}
-COMMAND(rdvert, "ffff");
-
-void rdeye(int *v) {
- checkragdoll;
- ragdoll->eye = *v;
-}
-COMMAND(rdeye, "i");
-
-void rdtri(int *v1, int *v2, int *v3) {
- checkragdoll;
- ragdollskel::tri &t = ragdoll->tris.add();
- t.vert[0] = *v1;
- t.vert[1] = *v2;
- t.vert[2] = *v3;
-}
-COMMAND(rdtri, "iii");
-
-void rdjoint(int *n, int *t, int *v1, int *v2, int *v3) {
- checkragdoll;
- if(*n < 0 || *n >= skel->numbones) return;
- ragdollskel::joint &j = ragdoll->joints.add();
- j.bone = *n;
- j.tri = *t;
- j.vert[0] = *v1;
- j.vert[1] = *v2;
- j.vert[2] = *v3;
-}
-COMMAND(rdjoint, "iibbb");
-
-void rdlimitdist(int *v1, int *v2, float *mindist, float *maxdist) {
- checkragdoll;
- ragdollskel::distlimit &d = ragdoll->distlimits.add();
- d.vert[0] = *v1;
- d.vert[1] = *v2;
- d.mindist = *mindist;
- d.maxdist = max(*maxdist, *mindist);
-}
-COMMAND(rdlimitdist, "iiff");
-
-void rdlimitrot(int *t1, int *t2, float *maxangle, float *qx, float *qy, float *qz, float *qw) {
- checkragdoll;
- ragdollskel::rotlimit &r = ragdoll->rotlimits.add();
- r.tri[0] = *t1;
- r.tri[1] = *t2;
- r.maxangle = *maxangle * RAD;
- r.middle = matrix3(quat(*qx, *qy, *qz, *qw));
-}
-COMMAND(rdlimitrot, "iifffff");
-
-void rdanimjoints(int *on) {
- checkragdoll;
- ragdoll->animjoints = *on!=0;
-}
-COMMAND(rdanimjoints, "i");
-
// mapmodels
vector<mapmodelinfo> mapmodels;
loadprogress = 0;
}
-void preloadusedmapmodels(bool msg, bool bih) {
+void preloadusedmapmodels(bool msg) {
vector<extentity *> &ents = entities::getents();
vector<int> mapmodels;
loopv(ents) {
if(!mmi) { if(msg) conoutf(CON_WARN, "could not find map model: %d", mmindex); }
else if(mmi->name[0] && !loadmodel(NULL, mmindex, msg)) { if(msg) conoutf(CON_WARN, "could not load model: %s", mmi->name); }
else if(mmi->m) {
- if(bih) mmi->m->preloadBIH();
mmi->m->preloadmeshes();
}
}
modelattach *a = NULL;
if(b.attached>=0) a = &modelattached[b.attached];
int anim = b.anim;
- if(shadowmapping) {
- anim |= ANIM_NOSKIN;
- GLOBALPARAMF(shadowintensity, b.transparent);
- }
- else {
- if(b.flags&MDL_FULLBRIGHT) anim |= ANIM_FULLBRIGHT;
- if(b.flags&MDL_GHOST) anim |= ANIM_GHOST;
- }
+ if(b.flags&MDL_FULLBRIGHT) anim |= ANIM_FULLBRIGHT;
+ if(b.flags&MDL_GHOST) anim |= ANIM_GHOST;
m->render(anim, b.basetime, b.basetime2, b.pos, b.yaw, b.pitch, b.d, a, b.color, b.dir, b.transparent);
}
query = bm.query;
if(query) startquery(query);
}
- if(bm.transparent < 1 && (!query || query->owner==bm.d) && !shadowmapping) {
+ if(bm.transparent < 1 && (!query || query->owner==bm.d)) {
transparentmodel &tm = transparent.add();
tm.m = b.m;
tm.batched = &bm;
- tm.dist = camera1->o.dist(bm.d && bm.d->ragdoll ? bm.d->ragdoll->center : bm.pos);
continue;
}
if(!rendered) { b.m->startrender(); rendered = true; }
static inline int cullmodel(const vec ¢er, float radius, int flags, dynent *d = NULL) {
if(flags&MDL_CULL_DIST && center.dist(camera1->o)/radius>maxmodelradiusdistance) return MDL_CULL_DIST;
- if(flags&MDL_CULL_VFC) {
- if(shadowmapping && !isshadowmapcaster(center, radius)) return MDL_CULL_VFC;
- }
- if(shadowmapping) {
- if(d) {
- if(flags&MDL_CULL_OCCLUDED && d->occluded>=OCCLUDE_PARENT) return MDL_CULL_OCCLUDED;
- if(flags&MDL_CULL_QUERY && d->occluded+1>=OCCLUDE_BB && d->query && d->query->owner==d && checkquery(d->query)) return MDL_CULL_QUERY;
- }
- if(!addshadowmapcaster(center, radius, radius)) return MDL_CULL_VFC;
- }
- else if(flags&MDL_CULL_OCCLUDED && modeloccluded(center, radius)) {
+ if(flags&MDL_CULL_OCCLUDED && modeloccluded(center, radius)) {
if(d) d->occluded = OCCLUDE_PARENT;
return MDL_CULL_OCCLUDED;
}
}
void rendermodel(entitylight *light, const char *mdl, int anim, const vec &o, float yaw, float pitch, int flags, dynent *d, modelattach *a, int basetime, int basetime2, float trans) {
- if(shadowmapping && !(flags&(MDL_SHADOW|MDL_DYNSHADOW))) return;
model *m = loadmodel(mdl);
if(!m) return;
vec center(0, 0, 0), bbradius(0, 0, 0);
float radius = 0;
- bool shadow = !shadowmap && (flags&(MDL_SHADOW|MDL_DYNSHADOW));
- if(flags&(MDL_CULL_VFC|MDL_CULL_DIST|MDL_CULL_OCCLUDED|MDL_CULL_QUERY|MDL_SHADOW|MDL_DYNSHADOW)) {
+ if(flags&(MDL_CULL_VFC|MDL_CULL_DIST|MDL_CULL_OCCLUDED|MDL_CULL_QUERY)) {
if(flags&MDL_CULL_QUERY) {
if(!oqfrags || !oqdynent || !d) flags &= ~MDL_CULL_QUERY;
}
m->boundbox(center, bbradius);
radius = bbradius.magnitude();
- if(d && d->ragdoll) {
- radius = max(radius, d->ragdoll->radius);
- center = d->ragdoll->center;
- }
- else {
- center.rotate_around_z(yaw*RAD);
- center.add(o);
- }
+ center.rotate_around_z(yaw*RAD);
+ center.add(o);
int culled = cullmodel(center, radius, flags, d);
if(culled) {
if(culled&(MDL_CULL_OCCLUDED|MDL_CULL_QUERY) && flags&MDL_CULL_QUERY) {
}
return;
}
- if(shadowmapping) flags &= ~MDL_CULL_QUERY;
}
if(flags&MDL_NORENDER) anim |= ANIM_NORENDER;
- else if(showboundingbox && !shadowmapping && editmode) {
+ else if(showboundingbox && editmode) {
notextureshader->set();
if(d && showboundingbox==1) {
render3dbox(d->o, d->eyeheight, d->aboveeye, d->radius);
}
}
vec lightcolor(1, 1, 1), lightdir(0, 0, 1);
- if(!shadowmapping) {
- vec pos = o;
- if(d) {
- d->occluded = OCCLUDE_NOTHING;
- if(!light) light = &d->light;
- if(flags&MDL_LIGHT && light->millis!=lastmillis) {
- if(d->ragdoll) {
- pos = d->ragdoll->center;
- pos.z += radius/2;
- }
- else if(d->type < ENT_CAMERA) pos.z += 0.75f*(d->eyeheight + d->aboveeye);
- lightreaching(pos, light->color, light->dir);
- light->millis = lastmillis;
- }
+ vec pos = o;
+ if(d) {
+ d->occluded = OCCLUDE_NOTHING;
+ if(!light) light = &d->light;
+ if(flags&MDL_LIGHT && light->millis!=lastmillis) {
+ if(d->type < ENT_CAMERA) pos.z += 0.75f*(d->eyeheight + d->aboveeye);
+ lightreaching(pos, light->color, light->dir);
+ light->millis = lastmillis;
}
- else if(flags&MDL_LIGHT) {
- if(!light) {
- lightreaching(pos, lightcolor, lightdir);
- }
- else if(light->millis!=lastmillis) {
- lightreaching(pos, light->color, light->dir);
- light->millis = lastmillis;
- }
+ }
+ else if(flags&MDL_LIGHT) {
+ if(!light) {
+ lightreaching(pos, lightcolor, lightdir);
+ }
+ else if(light->millis!=lastmillis) {
+ lightreaching(pos, light->color, light->dir);
+ light->millis = lastmillis;
}
- if(light) { lightcolor = light->color; lightdir = light->dir; }
}
+ if(light) { lightcolor = light->color; lightdir = light->dir; }
if(a) for(int i = 0; a[i].tag; i++) {
if(a[i].name) a[i].m = loadmodel(a[i].name);
//if(a[i].m && a[i].m->type()!=m->type()) a[i].m = NULL;
b.basetime2 = basetime2;
b.transparent = trans;
b.flags = flags & ~(MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED);
- if(!shadow) {
- b.flags &= ~(MDL_SHADOW|MDL_DYNSHADOW);
- if(flags&MDL_CULL_VFC) b.flags |= MDL_CULL_VFC;
- }
+ if(flags&MDL_CULL_VFC) b.flags |= MDL_CULL_VFC;
mb.flags |= b.flags;
b.d = d;
b.attached = a ? modelattached.length() : -1;
return;
}
m->startrender();
- if(shadowmapping) {
- anim |= ANIM_NOSKIN;
- GLOBALPARAMF(shadowintensity, trans);
- }
- else {
- if(flags&MDL_FULLBRIGHT) anim |= ANIM_FULLBRIGHT;
- if(flags&MDL_GHOST) anim |= ANIM_GHOST;
- }
+ if(flags&MDL_FULLBRIGHT) anim |= ANIM_FULLBRIGHT;
+ if(flags&MDL_GHOST) anim |= ANIM_GHOST;
if(flags&MDL_CULL_QUERY) {
d->query = newquery(d);
if(d->query) startquery(d->query);
m->endrender();
}
-void abovemodel(vec &o, const char *mdl) {
- model *m = loadmodel(mdl);
- if(!m) return;
- o.z += m->above();
-}
-
bool matchanim(const char *name, const char *pattern) {
for(;; pattern++) {
const char *s = name;
VAR(testanims, 0, 0, 1);
VAR(testpitch, -90, 0, 90);
-void renderclient(dynent *d, const char *mdlname, modelattach *attachments, int hold, int attack, int attackdelay, int lastaction, int lastpain, float fade, bool ragdoll) {
+void renderclient(dynent *d, const char *mdlname, modelattach *attachments, int hold, int attack, int attackdelay, int lastaction, int lastpain, float fade) {
int anim = hold ? hold : ANIM_IDLE|ANIM_LOOP;
float yaw = testanims && d==player ? 0 : d->yaw+90,
pitch = testpitch && d==player ? testpitch : d->pitch;
else if(d->state==CS_DEAD) {
anim = ANIM_DYING|ANIM_NOPITCH;
basetime = lastpain;
- if(ragdoll) {
- if(!d->ragdoll || d->ragdoll->millis < basetime) {
- DELETEP(d->ragdoll);
- anim |= ANIM_RAGDOLL;
- }
- }
- else if(lastmillis-basetime>1000) anim = ANIM_DEAD|ANIM_LOOP|ANIM_NOPITCH;
+ if(lastmillis-basetime>1000) anim = ANIM_DEAD|ANIM_LOOP|ANIM_NOPITCH;
}
else if(d->state==CS_EDITING || d->state==CS_SPECTATOR) anim = ANIM_EDIT|ANIM_LOOP;
else if(d->state==CS_LAGGED) anim = ANIM_LAG|ANIM_LOOP;
}
if((anim&ANIM_INDEX)==ANIM_IDLE && (anim>>ANIM_SECONDARY)&ANIM_INDEX) anim >>= ANIM_SECONDARY;
}
- if(d->ragdoll && (!ragdoll || (anim&ANIM_INDEX)!=ANIM_DYING)) DELETEP(d->ragdoll);
if(!((anim>>ANIM_SECONDARY)&ANIM_INDEX)) anim |= (ANIM_IDLE|ANIM_LOOP)<<ANIM_SECONDARY;
int flags = MDL_LIGHT;
- if(d!=player && !(anim&ANIM_RAGDOLL)) flags |= MDL_CULL_VFC | MDL_CULL_OCCLUDED | MDL_CULL_QUERY;
+ if(d!=player) flags |= MDL_CULL_VFC | MDL_CULL_OCCLUDED | MDL_CULL_QUERY;
if(d->type==ENT_PLAYER) flags |= MDL_FULLBRIGHT;
else flags |= MDL_CULL_DIST;
if(d->state==CS_LAGGED) fade = min(fade, 0.3f);
- else flags |= MDL_DYNSHADOW;
- if(drawtex == DRAWTEX_MODELPREVIEW) flags &= ~(MDL_LIGHT | MDL_FULLBRIGHT | MDL_CULL_VFC | MDL_CULL_OCCLUDED | MDL_CULL_QUERY | MDL_CULL_DIST | MDL_DYNSHADOW);
+ if(drawtex == DRAWTEX_MODELPREVIEW) flags &= ~(MDL_LIGHT | MDL_FULLBRIGHT | MDL_CULL_VFC | MDL_CULL_OCCLUDED | MDL_CULL_QUERY | MDL_CULL_DIST);
rendermodel(NULL, mdlname, anim, o, yaw, pitch, flags, d, attachments, basetime, 0, fade);
}
}
bool canaddparticles() {
- return !renderedgame && !shadowmapping && !minimized;
+ return !renderedgame && !minimized;
}
void regular_particle_splash(int type, int num, int fade, const vec &p, int color, float size, int radius, int gravity, int delay) {
}
else canemit = false;
if(!editmode || showparticles) {
- int emitted = 0, replayed = 0;
addedparticles = 0;
loopv(emitters) {
particleemitter &pe = emitters[i];
extentity &e = *pe.ent;
if(e.o.dist(camera1->o) > maxparticledistance) { pe.lastemit = lastmillis; continue; }
makeparticles(e);
- emitted++;
if(replayparticles && pe.maxfade > 5 && pe.lastcull > pe.lastemit) {
for(emitoffset = max(pe.lastemit + emitmillis - lastmillis, -pe.maxfade); emitoffset < 0; emitoffset += emitmillis) {
makeparticles(e);
- replayed++;
}
emitoffset = 0;
}
return v;
}
-static inline int ishiddencube(const ivec &o, int size) {
- loopi(5) if(o.dist(vfcP[i]) < -vfcDfar[i]*size) return true;
- return false;
-}
-
int isvisiblecube(const ivec &o, int size) {
int v = VFC_FULL_VISIBLE;
float dist;
gle::disablevertex();
}
-void rendershadowmapreceivers() {
- SETSHADER(shadowmapreceiver);
- gle::enablevertex();
- glCullFace(GL_FRONT);
- glDepthMask(GL_FALSE);
- glDepthFunc(GL_GREATER);
- extern int ati_minmax_bug;
- if(!ati_minmax_bug) glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
- glEnable(GL_BLEND);
- glBlendEquation_(GL_MAX);
- glBlendFunc(GL_ONE, GL_ONE);
- vtxarray *prev = NULL;
- for(vtxarray *va = visibleva; va; va = va->next) {
- if(!va->texs || !isshadowmapreceiver(va)) continue;
- if(!prev || va->vbuf != prev->vbuf) {
- gle::bindvbo(va->vbuf);
- gle::bindebo(va->ebuf);
- const vertex *ptr = 0;
- gle::vertexpointer(sizeof(vertex), ptr->pos.v);
- }
- drawvatris(va, 3*va->tris, va->edata);
- xtravertsva += va->verts;
- prev = va;
- }
- glDisable(GL_BLEND);
- glBlendEquation_(GL_FUNC_ADD);
- glCullFace(GL_BACK);
- glDepthMask(GL_TRUE);
- glDepthFunc(GL_LESS);
- if(!ati_minmax_bug) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- gle::clearvbo();
- gle::clearebo();
- gle::disablevertex();
-}
-
VAR(oqdist, 0, 256, 1024);
VAR(zpass, 0, 1, 1);
VAR(envpass, 0, 1, 1);
VSlot *vslot, *texgenvslot;
vec2 texgenscroll;
int texgendim;
- renderstate() : colormask(true), depthmask(true), blending(false), alphaing(0), vbuf(0), vattribs(false), vquery(false), colorscale(1, 1, 1), alphascale(0), slot(NULL), texgenslot(NULL), vslot(NULL), texgenvslot(NULL), texgenscroll(0, 0), texgendim(-1) {
+ renderstate() : colormask(true), depthmask(true), blending(false), alphaing(0), vbuf(0), vattribs(false), vquery(false), colorscale(1, 1, 1), alphascale(0),
+ slot(NULL), texgenslot(NULL), vslot(NULL), texgenvslot(NULL), texgenscroll(0, 0), texgendim(-1) {
loopk(8) textures[k] = 0;
}
};
}
static void renderbatch(geombatch &b) {
- geombatch *shadowed = NULL;
int rendered = -1;
for(geombatch *curbatch = &b;; curbatch = &geombatches[curbatch->batch]) {
- ushort len = curbatch->es.length[curbatch->va->shadowed ? 0 : 1];
+ ushort len = curbatch->es.length[1];
if(len) {
if(rendered < 0) {
rendered = 0;
gbatches++;
}
ushort minvert = curbatch->es.minvert[0], maxvert = curbatch->es.maxvert[0];
- if(!curbatch->va->shadowed) { minvert = min(minvert, curbatch->es.minvert[1]); maxvert = max(maxvert, curbatch->es.maxvert[1]); }
+ minvert = min(minvert, curbatch->es.minvert[1]); maxvert = max(maxvert, curbatch->es.maxvert[1]);
drawtris(len, curbatch->edata, minvert, maxvert);
vtris += len/3;
}
- if(curbatch->es.length[1] > len && !shadowed) shadowed = curbatch;
- if(curbatch->batch < 0) break;
- }
- if(shadowed) for(geombatch *curbatch = shadowed;; curbatch = &geombatches[curbatch->batch]) {
- if(curbatch->va->shadowed && curbatch->es.length[1] > curbatch->es.length[0]) {
- if(rendered < 1) {
- rendered = 1;
- gbatches++;
- }
- ushort len = curbatch->es.length[1] - curbatch->es.length[0];
- drawtris(len, curbatch->edata + curbatch->es.length[0], curbatch->es.minvert[1], curbatch->es.maxvert[1]);
- vtris += len/3;
- }
if(curbatch->batch < 0) break;
}
}
if(cur.vbuf!=va->vbuf) changevbuf(cur, RENDERPASS_Z, va);
if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); }
- int firsttex = 0, numtris = va->tris;
+ int numtris = va->tris;
ushort *edata = va->edata;
if(cur.alphaing) {
- firsttex += va->texs + va->blends;
edata += 3*(va->tris + va->blendtris);
numtris = va->alphatris;
xtravertsva += 3*numtris;
switch(pass) {
case RENDERPASS_LIGHTMAP:
if(!cur.alphaing) vverts += va->verts;
- va->shadowed = false;
- if(!drawtex && !cur.alphaing) {
- va->shadowed = isshadowmapreceiver(va);
- }
if(doquery) startvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); });
mergetexs(cur, va);
if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); });
void rendergeom(void) {
bool mainpass = !drawtex,
doOQ = oqfrags && oqgeom && mainpass,
- doZP = doOQ && zpass,
- doSM = shadowmap && !drawtex;
+ doZP = doOQ && zpass;
renderstate cur;
if(mainpass) {
flipqueries();
vtris = vverts = 0;
}
if(!doZP) {
- if(shadowmap && mainpass) rendershadowmap();
setupgeom();
- if(doSM) pushshadowmap();
}
resetbatches();
int blends = 0;
}
continue;
}
- }
- else {
+ } else {
va->query = NULL;
va->occluded = OCCLUDE_NOTHING;
}
bool multipassing = false;
if(doZP) {
glFlush();
- if(shadowmap && mainpass) rendershadowmap();
setupgeom();
- if(doSM) pushshadowmap();
if(!multipassing) { multipassing = true; glDepthFunc(GL_LEQUAL); }
cur.texgendim = -1;
for(vtxarray *va = visibleva; va; va = va->next) {
tmu++;
}
else UNIFORMTEX("lightmap", 1);
- UNIFORMTEX("shadowmap", 7);
int stex = 0;
loopv(slot->sts) {
Slot::Tex &t = slot->sts[i];
newshader(s.type, varname, vschanged ? vsv.getbuf() : reuse, pschanged ? psv.getbuf() : reuse, &s, row);
}
-static void genshadowmapvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 1) {
- const char *vspragma = strstr(vs, "//:shadowmap"), *pspragma = strstr(ps, "//:shadowmap");
- if(!vspragma || !pspragma) return;
- string pslight;
- vspragma += strcspn(vspragma, "\n");
- if(*vspragma) vspragma++;
- if(sscanf(pspragma, "//:shadowmap %100s", pslight)!=1) return;
- pspragma += strcspn(pspragma, "\n");
- if(*pspragma) pspragma++;
- const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps);
- if(vsmain > vspragma) vsmain = vs;
- if(psmain > pspragma) psmain = ps;
- vector<char> vssm, pssm;
- if(vsmain >= vs) vssm.put(vs, vsmain - vs);
- if(psmain >= ps) pssm.put(ps, psmain - ps);
- const char *vsdecl =
- "uniform mat4 shadowmapproject;\n"
- "varying vec3 shadowmaptc;\n";
- vssm.put(vsdecl, strlen(vsdecl));
- const char *psdecl =
- "uniform sampler2D shadowmap;\n"
- "uniform vec4 shadowmapambient;\n"
- "varying vec3 shadowmaptc;\n";
- pssm.put(psdecl, strlen(psdecl));
- vssm.put(vsmain, vspragma-vsmain);
- pssm.put(psmain, pspragma-psmain);
- extern int smoothshadowmappeel;
- const char *tcgen =
- "shadowmaptc = vec3(shadowmapproject * vvertex);\n";
- vssm.put(tcgen, strlen(tcgen));
- const char *sm =
- smoothshadowmappeel ?
- "vec4 smvals = texture2D(shadowmap, shadowmaptc.xy);\n"
- "vec2 smdiff = clamp(smvals.xz - shadowmaptc.zz*smvals.y, 0.0, 1.0);\n"
- "float shadowed = clamp((smdiff.x > 0.0 ? smvals.w : 0.0) - 8.0*smdiff.y, 0.0, 1.0);\n" :
- "vec4 smvals = texture2D(shadowmap, shadowmaptc.xy);\n"
- "float smtest = shadowmaptc.z*smvals.y;\n"
- "float shadowed = smtest < smvals.x && smtest > smvals.z ? smvals.w : 0.0;\n";
- pssm.put(sm, strlen(sm));
- defformatstring(smlight,
- "%s.rgb -= shadowed*clamp(%s.rgb - shadowmapambient.rgb, 0.0, 1.0);\n",
- pslight, pslight);
- pssm.put(smlight, strlen(smlight));
- vssm.put(vspragma, strlen(vspragma)+1);
- pssm.put(pspragma, strlen(pspragma)+1);
- defformatstring(name, "<shadowmap>%s", sname);
- Shader *variant = newshader(s.type, name, vssm.getbuf(), pssm.getbuf(), &s, row);
- if(!variant) return;
-}
-
static void genuniformdefs(vector<char> &vsbuf, vector<char> &psbuf, const char *vs, const char *ps, Shader *variant = NULL) {
if(variant ? variant->defaultparams.empty() : slotparams.empty()) return;
const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps);
}
GENSHADER(slotparams.length(), genuniformdefs(vsbuf, psbuf, vs, ps));
Shader *s = newshader(*type, name, vs, ps);
- if(s) {
- if(strstr(vs, "//:shadowmap")) genshadowmapvariant(*s, s->name, vs, ps);
- }
slotparams.shrink(0);
}
+++ /dev/null
-#include "engine.h"
-#include "rendertarget.h"
-
-VARP(shadowmap, 0, 0, 1);
-
-extern void cleanshadowmap();
-VARFP(shadowmapsize, 7, 9, 11, cleanshadowmap());
-VARP(shadowmapradius, 64, 96, 256);
-VAR(shadowmapheight, 0, 32, 128);
-VARP(shadowmapdist, 128, 256, 512);
-VARFP(fpshadowmap, 0, 0, 1, cleanshadowmap());
-VARFP(shadowmapprecision, 0, 0, 1, cleanshadowmap());
-bvec shadowmapambientcolor(0, 0, 0);
-HVARFR(shadowmapambient, 0, 0, 0xFFFFFF, {
- if(shadowmapambient <= 255) shadowmapambient |= (shadowmapambient<<8) | (shadowmapambient<<16);
- shadowmapambientcolor = bvec((shadowmapambient>>16)&0xFF, (shadowmapambient>>8)&0xFF, shadowmapambient&0xFF);
-});
-VARP(shadowmapintensity, 0, 40, 100);
-
-VARP(blurshadowmap, 0, 1, 3);
-VARP(blursmsigma, 1, 100, 200);
-
-#define SHADOWSKEW 0.7071068f
-
-vec shadowoffset(0, 0, 0), shadowfocus(0, 0, 0), shadowdir(0, SHADOWSKEW, 1);
-VAR(shadowmapcasters, 1, 0, 0);
-float shadowmapmaxz = 0;
-
-void setshadowdir(int angle) {
- shadowdir = vec(0, SHADOWSKEW, 1);
- shadowdir.rotate_around_z(angle*RAD);
-}
-
-VARFR(shadowmapangle, 0, 0, 360, setshadowdir(shadowmapangle));
-
-void guessshadowdir() {
- if(shadowmapangle) return;
- vec dir; {
- vec lightpos(0, 0, 0), casterpos(0, 0, 0);
- int numlights = 0, numcasters = 0;
- const vector<extentity *> &ents = entities::getents();
- loopv(ents) {
- extentity &e = *ents[i];
- switch(e.type) {
- case ET_LIGHT:
- if(!e.attr1) { lightpos.add(e.o); numlights++; }
- break;
- case ET_MAPMODEL:
- casterpos.add(e.o);
- numcasters++;
- break;
- default:
- if(e.type<ET_GAMESPECIFIC) break;
- casterpos.add(e.o);
- numcasters++;
- break;
- }
- }
- if(!numlights || !numcasters) return;
- lightpos.div(numlights);
- casterpos.div(numcasters);
- dir = vec(lightpos).sub(casterpos);
- }
- dir.z = 0;
- if(dir.iszero()) return;
- dir.normalize();
- dir.mul(SHADOWSKEW);
- dir.z = 1;
- shadowdir = dir;
-}
-
-bool shadowmapping = false;
-
-matrix4 shadowmatrix;
-
-VARP(shadowmapbias, 0, 5, 1024);
-VARP(shadowmappeelbias, 0, 20, 1024);
-VAR(smdepthpeel, 0, 1, 1);
-VAR(smoothshadowmappeel, 1, 0, 0);
-
-static struct shadowmaptexture : rendertarget {
- const GLenum *colorformats() const {
- static const GLenum rgbafmts[] = { GL_RGBA16F, GL_RGBA16, GL_RGBA, GL_RGBA8, GL_FALSE };
- return &rgbafmts[fpshadowmap && hasTF ? 0 : (shadowmapprecision ? 1 : 2)];
- }
- bool swaptexs() const { return true; }
- bool scissorblur(int &x, int &y, int &w, int &h) {
- x = max(int(floor((scissorx1+1)/2*vieww)) - 2*blursize, 2);
- y = max(int(floor((scissory1+1)/2*viewh)) - 2*blursize, 2);
- w = min(int(ceil((scissorx2+1)/2*vieww)) + 2*blursize, vieww-2) - x;
- h = min(int(ceil((scissory2+1)/2*viewh)) + 2*blursize, viewh-2) - y;
- return true;
- }
- bool scissorrender(int &x, int &y, int &w, int &h) {
- x = y = 2;
- w = vieww - 2*2;
- h = viewh - 2*2;
- return true;
- }
- void doclear() {
- glClearColor(0, 0, 0, 0);
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
- }
- bool dorender() {
- vec skewdir(shadowdir);
- skewdir.rotate_around_z(-camera1->yaw*RAD);
- vec dir;
- vecfromyawpitch(camera1->yaw, camera1->pitch, 1, 0, dir);
- dir.z = 0;
- dir.mul(shadowmapradius);
- vec dirx, diry;
- vecfromyawpitch(camera1->yaw, 0, 0, 1, dirx);
- vecfromyawpitch(camera1->yaw, 0, 1, 0, diry);
- shadowoffset.x = -fmod(dirx.dot(camera1->o) - skewdir.x*camera1->o.z, 2.0f*shadowmapradius/vieww);
- shadowoffset.y = -fmod(diry.dot(camera1->o) - skewdir.y*camera1->o.z, 2.0f*shadowmapradius/viewh);
- shadowmatrix.ortho(-shadowmapradius, shadowmapradius, -shadowmapradius, shadowmapradius, -shadowmapdist, shadowmapdist);
- shadowmatrix.mul(matrix3(vec(1, 0, 0), vec(0, 1, 0), vec(skewdir.x, skewdir.y, 1)));
- shadowmatrix.translate(skewdir.x*shadowmapheight + shadowoffset.x, skewdir.y*shadowmapheight + shadowoffset.y + dir.magnitude(), -shadowmapheight);
- shadowmatrix.rotate_around_z((camera1->yaw+180)*-RAD);
- shadowmatrix.translate(vec(camera1->o).neg());
- GLOBALPARAM(shadowmatrix, shadowmatrix);
- shadowfocus = camera1->o;
- shadowfocus.add(dir);
- shadowfocus.add(vec(shadowdir).mul(shadowmapheight));
- shadowfocus.add(dirx.mul(shadowoffset.x));
- shadowfocus.add(diry.mul(shadowoffset.y));
- gle::colorf(0, 0, 0);
- GLOBALPARAMF(shadowmapbias, -shadowmapbias/float(shadowmapdist), 1 - (shadowmapbias + (smoothshadowmappeel ? 0 : shadowmappeelbias))/float(shadowmapdist));
- shadowmapcasters = 0;
- shadowmapmaxz = shadowfocus.z - shadowmapdist;
- shadowmapping = true;
- rendergame();
- shadowmapping = false;
- shadowmapmaxz = min(shadowmapmaxz, shadowfocus.z);
- if(shadowmapcasters && smdepthpeel) {
- int sx, sy, sw, sh;
- bool scissoring = rtscissor && scissorblur(sx, sy, sw, sh) && sw > 0 && sh > 0;
- if(scissoring) glScissor(sx, sy, sw, sh);
- if(!rtscissor || scissoring) rendershadowmapreceivers();
- }
- return shadowmapcasters>0;
- }
-} shadowmaptex;
-
-void cleanshadowmap() {
- shadowmaptex.cleanup(true);
-}
-
-void calcshadowmapbb(const vec &o, float xyrad, float zrad, float &x1, float &y1, float &x2, float &y2) {
- vec skewdir(shadowdir);
- skewdir.rotate_around_z(-camera1->yaw*RAD);
- vec ro(o);
- ro.sub(camera1->o);
- ro.rotate_around_z(-(camera1->yaw+180)*RAD);
- ro.x += ro.z * skewdir.x + shadowoffset.x;
- ro.y += ro.z * skewdir.y + shadowmapradius * cosf(camera1->pitch*RAD) + shadowoffset.y;
- vec high(ro), low(ro);
- high.x += zrad * skewdir.x;
- high.y += zrad * skewdir.y;
- low.x -= zrad * skewdir.x;
- low.y -= zrad * skewdir.y;
- x1 = (min(high.x, low.x) - xyrad) / shadowmapradius;
- y1 = (min(high.y, low.y) - xyrad) / shadowmapradius;
- x2 = (max(high.x, low.x) + xyrad) / shadowmapradius;
- y2 = (max(high.y, low.y) + xyrad) / shadowmapradius;
-}
-
-bool addshadowmapcaster(const vec &o, float xyrad, float zrad) {
- if(o.z + zrad <= shadowfocus.z - shadowmapdist || o.z - zrad >= shadowfocus.z) return false;
- shadowmapmaxz = max(shadowmapmaxz, o.z + zrad);
- float x1, y1, x2, y2;
- calcshadowmapbb(o, xyrad, zrad, x1, y1, x2, y2);
- if(!shadowmaptex.addblurtiles(x1, y1, x2, y2, 2)) return false;
- shadowmapcasters++;
- return true;
-}
-
-bool isshadowmapreceiver(vtxarray *va) {
- if(!shadowmap || !shadowmapcasters) return false;
- if(va->shadowmapmax.z <= shadowfocus.z - shadowmapdist || va->shadowmapmin.z >= shadowmapmaxz) return false;
- float xyrad = SQRT2*0.5f*max(va->shadowmapmax.x-va->shadowmapmin.x, va->shadowmapmax.y-va->shadowmapmin.y),
- zrad = 0.5f*(va->shadowmapmax.z-va->shadowmapmin.z),
- x1, y1, x2, y2;
- if(xyrad<0 || zrad<0) return false;
- vec center = vec(va->shadowmapmin).add(vec(va->shadowmapmax)).mul(0.5f);
- calcshadowmapbb(center, xyrad, zrad, x1, y1, x2, y2);
- return shadowmaptex.checkblurtiles(x1, y1, x2, y2, 2);
-}
-
-bool isshadowmapcaster(const vec &o, float rad) {
- // cheaper inexact test
- float dz = o.z - shadowfocus.z;
- float cx = shadowfocus.x + dz*shadowdir.x, cy = shadowfocus.y + dz*shadowdir.y;
- float skew = rad*SHADOWSKEW;
- if(!shadowmapping ||
- o.z + rad <= shadowfocus.z - shadowmapdist || o.z - rad >= shadowfocus.z ||
- o.x + rad <= cx - shadowmapradius-skew || o.x - rad >= cx + shadowmapradius+skew ||
- o.y + rad <= cy - shadowmapradius-skew || o.y - rad >= cy + shadowmapradius+skew)
- return false;
- return true;
-}
-
-void pushshadowmap() {
- if(!shadowmap || !shadowmaptex.rendertex) return;
- glActiveTexture_(GL_TEXTURE7);
- glBindTexture(GL_TEXTURE_2D, shadowmaptex.rendertex);
- matrix4 m = shadowmatrix;
- m.projective(-1, 1-shadowmapbias/float(shadowmapdist));
- GLOBALPARAM(shadowmapproject, m);
- glActiveTexture_(GL_TEXTURE0);
- float r, g, b;
- if(!shadowmapambient) {
- r = max(25.0f, 2.0f*ambientcolor[0]);
- g = max(25.0f, 2.0f*ambientcolor[1]);
- b = max(25.0f, 2.0f*ambientcolor[2]);
- }
- else { r = shadowmapambientcolor[0]; g = shadowmapambientcolor[1]; b = shadowmapambientcolor[2]; }
- GLOBALPARAMF(shadowmapambient, r/255.0f, g/255.0f, b/255.0f);
-}
-
-void rendershadowmap() {
- if(!shadowmap) return;
- shadowmaptex.render(1<<shadowmapsize, 1<<shadowmapsize, blurshadowmap, blursmsigma/100.0f);
-}
float pitch;
int millis;
uchar *partmask;
- ragdolldata *ragdoll;
- animcacheentry() : ragdoll(NULL) {
- loopk(MAXANIMPARTS) as[k].cur.fr1 = as[k].prev.fr1 = -1;
- }
bool operator==(const animcacheentry &c) const {
loopi(MAXANIMPARTS) if(as[i]!=c.as[i]) return false;
- return pitch==c.pitch && partmask==c.partmask && ragdoll==c.ragdoll && (!ragdoll || min(millis, c.millis) >= ragdoll->lastmove);
+ return pitch==c.pitch && partmask==c.partmask;
}
};
struct vbocacheentry : animcacheentry {
}
}
}
- void genBIH(BIH::mesh &m) {
- m.tris = (const BIH::tri *)tris;
- m.numtris = numtris;
- m.pos = (const uchar *)&verts->pos;
- m.posstride = sizeof(vert);
- m.tc = (const uchar *)&verts->tc;
- m.tcstride = sizeof(vert);
- }
static inline void assignvert(vvertn &vv, int j, vert &v, blendcombo &c) {
(void)j;(void)c;
vv.pos = v.pos;
};
struct boneinfo {
const char *name;
- int parent, children, next, group, scheduled, interpindex, interpparent, ragdollindex, correctindex;
+ int parent, children, next, group, scheduled, interpindex, interpparent, correctindex;
float pitchscale, pitchoffset, pitchmin, pitchmax;
dualquat base, invbase;
- boneinfo() : name(NULL), parent(-1), children(-1), next(-1), group(INT_MAX), scheduled(-1), interpindex(-1), interpparent(-1), ragdollindex(-1), correctindex(-1), pitchscale(0), pitchoffset(0), pitchmin(0), pitchmax(0) {}
+ boneinfo() : name(NULL), parent(-1), children(-1), next(-1), group(INT_MAX), scheduled(-1), interpindex(-1), interpparent(-1), correctindex(-1), pitchscale(0), pitchoffset(0), pitchmin(0), pitchmax(0) {}
~boneinfo() {
DELETEA(name);
}
vector<skelanimspec> skelanims;
vector<tag> tags;
vector<antipode> antipodes;
- ragdollskel *ragdoll;
vector<pitchdep> pitchdeps;
vector<pitchtarget> pitchtargets;
vector<pitchcorrect> pitchcorrects;
bool usegpuskel;
vector<skelcacheentry> skelcache;
hashtable<GLuint, int> blendoffsets;
- skeleton() : name(NULL), shared(0), bones(NULL), numbones(0), numinterpbones(0), numgpubones(0), numframes(0), framebones(NULL), ragdoll(NULL), usegpuskel(false), blendoffsets(32) {
+ skeleton() : name(NULL), shared(0), bones(NULL), numbones(0), numinterpbones(0), numgpubones(0), numframes(0), framebones(NULL), usegpuskel(false), blendoffsets(32) {
}
~skeleton() {
DELETEA(name);
DELETEA(bones);
DELETEA(framebones);
- DELETEP(ragdoll);
loopv(skelcache) {
DELETEA(skelcache[i].bdata);
}
loopi(numbones) {
boneinfo &info = bones[i];
info.interpindex = -1;
- info.ragdollindex = -1;
}
numgpubones = 0;
loopv(users) {
boneinfo &info = bones[tags[i].bone];
if(info.interpindex < 0) info.interpindex = numinterpbones++;
}
- if(ragdoll) {
- loopv(ragdoll->joints) {
- boneinfo &info = bones[ragdoll->joints[i].bone];
- if(info.interpindex < 0) info.interpindex = numinterpbones++;
- info.ragdollindex = i;
- }
- }
loopi(numbones) {
boneinfo &info = bones[i];
if(info.interpindex < 0) continue;
if(info.interpindex < 0) continue;
info.interpparent = info.parent >= 0 ? bones[info.parent].interpindex : -1;
}
- if(ragdoll) {
- loopi(numbones) {
- boneinfo &info = bones[i];
- if(info.interpindex < 0 || info.ragdollindex >= 0) continue;
- for(int parent = info.parent; parent >= 0; parent = bones[parent].parent) {
- if(bones[parent].ragdollindex >= 0) { ragdoll->addreljoint(i, bones[parent].ragdollindex); break; }
- }
- }
- }
calcantipodes();
}
}
void optimize() {
cleanup();
- if(ragdoll) ragdoll->setup();
remapbones();
initpitchdeps();
}
}
loopv(antipodes) sc.bdata[antipodes[i].child].fixantipodal(sc.bdata[antipodes[i].parent]);
}
- void initragdoll(ragdolldata &d, skelcacheentry &sc, part *p) {
- const dualquat *bdata = sc.bdata;
- loopv(ragdoll->joints) {
- const ragdollskel::joint &j = ragdoll->joints[i];
- const boneinfo &b = bones[j.bone];
- const dualquat &q = bdata[b.interpindex];
- loopk(3) if(j.vert[k] >= 0) {
- ragdollskel::vert &v = ragdoll->verts[j.vert[k]];
- ragdolldata::vert &dv = d.verts[j.vert[k]];
- dv.pos.add(q.transform(v.pos).mul(v.weight));
- }
- }
- if(ragdoll->animjoints) loopv(ragdoll->joints) {
- const ragdollskel::joint &j = ragdoll->joints[i];
- const boneinfo &b = bones[j.bone];
- const dualquat &q = bdata[b.interpindex];
- d.calcanimjoint(i, matrix4x3(q));
- }
- loopv(ragdoll->verts) {
- ragdolldata::vert &dv = d.verts[i];
- matrixstack[matrixpos].transform(vec(dv.pos).add(p->translate).mul(p->model->scale), dv.pos);
- }
- loopv(ragdoll->reljoints) {
- const ragdollskel::reljoint &r = ragdoll->reljoints[i];
- const ragdollskel::joint &j = ragdoll->joints[r.parent];
- const boneinfo &br = bones[r.bone], &bj = bones[j.bone];
- d.reljoints[i].mul(dualquat(bdata[bj.interpindex]).invert(), bdata[br.interpindex]);
- }
- }
- void genragdollbones(ragdolldata &d, skelcacheentry &sc, part *p) {
- if(!sc.bdata) sc.bdata = new dualquat[numinterpbones];
- sc.nextversion();
- loopv(ragdoll->joints) {
- const ragdollskel::joint &j = ragdoll->joints[i];
- const boneinfo &b = bones[j.bone];
- vec pos(0, 0, 0);
- loopk(3) if(j.vert[k]>=0) pos.add(d.verts[j.vert[k]].pos);
- pos.mul(j.weight/p->model->scale).sub(p->translate);
- matrix4x3 m;
- m.mul(d.tris[j.tri], pos, d.animjoints ? d.animjoints[i] : j.orient);
- sc.bdata[b.interpindex] = dualquat(m);
- }
- loopv(ragdoll->reljoints) {
- const ragdollskel::reljoint &r = ragdoll->reljoints[i];
- const ragdollskel::joint &j = ragdoll->joints[r.parent];
- const boneinfo &br = bones[r.bone], &bj = bones[j.bone];
- sc.bdata[br.interpindex].mul(sc.bdata[bj.interpindex], d.reljoints[i]);
- }
- loopv(antipodes) sc.bdata[antipodes[i].child].fixantipodal(sc.bdata[antipodes[i].parent]);
- }
void concattagtransform(part *p, int i, const matrix4x3 &m, matrix4x3 &n) {
(void)i;(void)m;(void)n;(void)p;
matrix4x3 t;
usegpuskel = gpuaccelerate();
}
}
- skelcacheentry &checkskelcache(part *p, const animstate *as, float pitch, const vec &axis, const vec &forward, ragdolldata *rdata) {
+ skelcacheentry &checkskelcache(part *p, const animstate *as, float pitch, const vec &axis, const vec &forward) {
+ (void) p;
if(skelcache.empty()) {
usegpuskel = gpuaccelerate();
}
loopv(skelcache) {
skelcacheentry &c = skelcache[i];
loopj(numanimparts) if(c.as[j]!=as[j]) goto mismatch;
- if(c.pitch != pitch || c.partmask != partmask || c.ragdoll != rdata || (rdata && c.millis < rdata->lastmove)) goto mismatch;
+ if(c.pitch != pitch || c.partmask != partmask) goto mismatch;
match = true;
sc = &c;
break;
loopi(numanimparts) sc->as[i] = as[i];
sc->pitch = pitch;
sc->partmask = partmask;
- sc->ragdoll = rdata;
- if(rdata) genragdollbones(*rdata, *sc, p);
- else interpbones(as, pitch, axis, forward, numanimparts, partmask, *sc);
+ interpbones(as, pitch, axis, forward, numanimparts, partmask, *sc);
}
sc->millis = lastmillis;
return *sc;
skel->calctags(p);
return;
}
- skelcacheentry &sc = skel->checkskelcache(p, as, pitch, axis, forward, as->cur.anim&ANIM_RAGDOLL || !d || !d->ragdoll || d->ragdoll->skel != skel->ragdoll ? NULL : d->ragdoll);
+ skelcacheentry &sc = skel->checkskelcache(p, as, pitch, axis, forward);
if(!(as->cur.anim&ANIM_NORENDER)) {
int owner = &sc-&skel->skelcache[0];
vbocacheentry &vc = skel->usegpuskel ? *vbocache : checkvbocache(sc, owner);
}
}
skel->calctags(p, &sc);
- if(as->cur.anim&ANIM_RAGDOLL && skel->ragdoll && !d->ragdoll) {
- d->ragdoll = new ragdolldata(skel->ragdoll, p->model->scale);
- skel->initragdoll(*d->ragdoll, sc, p);
- d->ragdoll->init(d);
- }
}
};
struct animpartmask {
}
}
};
-
static void texcombine(Slot &s, int index, Slot::Tex &t, bool forceload = false) {
vector<char> key;
addname(key, t);
- int texmask = 0;
if(!forceload) switch(t.type) {
case TEX_DIFFUSE:
case TEX_NORMAL: {
int i = findtextype(s, t.type==TEX_DIFFUSE ? (s.texmask&(1<<TEX_SPEC) ? 1<<TEX_SPEC : 1<<TEX_ALPHA) : (s.texmask&(1<<TEX_DEPTH) ? 1<<TEX_DEPTH : 1<<TEX_ALPHA));
if(i<0) break;
- texmask |= 1<<s.sts[i].type;
s.sts[i].combined = index;
addname(key, s.sts[i], true);
break;
g->uval[3] = w;
}
template<class T>
- T *reserve(int n = 1) { return (T *)resolve()->buf; }
+ T *reserve(int n = 1) { (void)n;return (T *)resolve()->buf; }
};
struct LocalShaderParam {
}
VAR(entselsnap, 0, 0, 1);
-VAR(entmovingshadow, 0, 1, 1);
extern void boxs(int orient, vec o, const vec &s, float size);
extern void boxs(int orient, vec o, const vec &s);
gle::colorub(0, 40, 0);
entfocus(enthover, entselectionbox(e, eo, es)); // also ensures enthover is back in focus
boxs3D(eo, es, 1);
- if(entmoving && entmovingshadow==1) {
+ if(entmoving) {
vec a, b;
gle::colorub(20, 20, 20);
(a = eo).x = eo.x - fmod(eo.x, worldsize); (b = es).x = a.x + worldsize; boxs3D(a, b, 1);
ICOMMAND(addbot, "s", (char *s), addmsg(N_ADDBOT, "ri", *s ? clamp(parseint(s), 1, 101) : -1));
ICOMMAND(delbot, "", (), addmsg(N_DELBOT, "r"));
ICOMMAND(botlimit, "i", (int *n), addmsg(N_BOTLIMIT, "ri", *n));
- ICOMMAND(botbalance, "i", (int *n), addmsg(N_BOTBALANCE, "ri", *n));
float viewdist(int x) {
return x <= 100 ? clamp((SIGHTMIN+(SIGHTMAX-SIGHTMIN))/100.f*float(x), float(SIGHTMIN), 10000.0f) : 10000.0f;
}
shoot(d, d->ai->target);
}
if(!intermission) {
- if(d->ragdoll) cleanragdoll(d);
moveplayer(d, 10, true);
if(allowmove && !b.idle) timeouts(d);
if(d->quadmillis) entities::checkquad(curtime, d);
entities::checkitems(d);
}
- }
- else if(d->state == CS_DEAD) {
- if(d->ragdoll) moveragdoll(d);
- else if(lastmillis-d->lastpain<2000) {
+ } else if(d->state == CS_DEAD) {
+ if(lastmillis-d->lastpain<2000) {
d->move = d->strafe = 0;
moveplayer(d, 10, false);
}
}
}
}
-
extern void itemspawned(int ent);
extern void render();
}
-
+++ /dev/null
-// server-side ai manager
-namespace aiman {
- bool dorefresh = false, botbalance = true;
- VARN(serverbotlimit, botlimit, 0, 8, MAXBOTS);
- VAR(serverbotbalance, 0, 1, 1);
- void calcteams(vector<teamscore> &teams) {
- static const char * const defaults[2] = { "good", "evil" };
- loopv(clients) {
- clientinfo *ci = clients[i];
- if(ci->state.state==CS_SPECTATOR || !ci->team[0]) continue;
- teamscore *t = NULL;
- loopvj(teams) if(!strcmp(teams[j].team, ci->team)) { t = &teams[j]; break; }
- if(t) t->score++;
- else teams.add(teamscore(ci->team, 1));
- }
- teams.sort(teamscore::compare);
- if(teams.length() < int(sizeof(defaults)/sizeof(defaults[0]))) {
- loopi(sizeof(defaults)/sizeof(defaults[0])) if(teams.htfind(defaults[i]) < 0) teams.add(teamscore(defaults[i], 0));
- }
- }
- void balanceteams() {
- vector<teamscore> teams;
- calcteams(teams);
- vector<clientinfo *> reassign;
- loopv(bots) if(bots[i]) reassign.add(bots[i]);
- while(reassign.length() && teams.length() && teams[0].score > teams.last().score + 1) {
- teamscore &t = teams.last();
- clientinfo *bot = NULL;
- loopv(reassign) if(reassign[i] && !strcmp(reassign[i]->team, teams[0].team)) {
- bot = reassign.removeunordered(i);
- teams[0].score--;
- t.score++;
- for(int j = teams.length() - 2; j >= 0; j--) {
- if(teams[j].score >= teams[j+1].score) break;
- swap(teams[j], teams[j+1]);
- }
- break;
- }
- if(bot) {
- copystring(bot->team, t.team, MAXTEAMLEN+1);
- sendf(-1, 1, "riisi", N_SETTEAM, bot->clientnum, bot->team, 0);
- }
- else teams.remove(0, 1);
- }
- }
- const char *chooseteam() {
- vector<teamscore> teams;
- calcteams(teams);
- return teams.length() ? teams.last().team : "";
- }
- static inline bool validaiclient(clientinfo *ci) {
- return ci->clientnum >= 0 && ci->state.aitype == AI_NONE && (ci->state.state!=CS_SPECTATOR || ci->local || (ci->privilege && !ci->warned));
- }
- clientinfo *findaiclient(clientinfo *exclude = NULL) {
- clientinfo *least = NULL;
- loopv(clients) {
- clientinfo *ci = clients[i];
- if(!validaiclient(ci) || ci==exclude) continue;
- if(!least || ci->bots.length() < least->bots.length()) least = ci;
- }
- return least;
- }
- bool addai(int skill, int limit) {
- int numai = 0, cn = -1, maxai = limit >= 0 ? min(limit, MAXBOTS) : MAXBOTS;
- loopv(bots) {
- clientinfo *ci = bots[i];
- if(!ci || ci->ownernum < 0) { if(cn < 0) cn = i; continue; }
- numai++;
- }
- if(numai >= maxai) return false;
- if(bots.inrange(cn)) {
- clientinfo *ci = bots[cn];
- if(ci) {
- // reuse a slot that was going to removed
- clientinfo *owner = findaiclient();
- ci->ownernum = owner ? owner->clientnum : -1;
- if(owner) owner->bots.add(ci);
- ci->aireinit = 2;
- dorefresh = true;
- return true;
- }
- }
- else { cn = bots.length(); bots.add(NULL); }
- const char *team = m_teammode ? chooseteam() : "";
- if(!bots[cn]) bots[cn] = new clientinfo;
- clientinfo *ci = bots[cn];
- ci->clientnum = MAXCLIENTS + cn;
- ci->state.aitype = AI_BOT;
- clientinfo *owner = findaiclient();
- ci->ownernum = owner ? owner->clientnum : -1;
- if(owner) owner->bots.add(ci);
- ci->state.skill = skill <= 0 ? rnd(50) + 51 : clamp(skill, 1, 101);
- clients.add(ci);
- ci->state.lasttimeplayed = lastmillis;
- copystring(ci->name, "bot", MAXNAMELEN+1);
- ci->state.state = CS_DEAD;
- copystring(ci->team, team, MAXTEAMLEN+1);
- ci->playermodel = 0;
- ci->aireinit = 2;
- ci->connected = true;
- dorefresh = true;
- return true;
- }
- void deleteai(clientinfo *ci) {
- int cn = ci->clientnum - MAXCLIENTS;
- if(!bots.inrange(cn)) return;
- sendf(-1, 1, "ri2", N_CDIS, ci->clientnum);
- clientinfo *owner = (clientinfo *)getclientinfo(ci->ownernum);
- if(owner) owner->bots.removeobj(ci);
- clients.removeobj(ci);
- DELETEP(bots[cn]);
- dorefresh = true;
- }
- bool deleteai() {
- loopvrev(bots) if(bots[i] && bots[i]->ownernum >= 0) {
- deleteai(bots[i]);
- return true;
- }
- return false;
- }
- void reinitai(clientinfo *ci) {
- if(ci->ownernum < 0) deleteai(ci);
- else if(ci->aireinit >= 1) {
- sendf(-1, 1, "ri6ss", N_INITAI, ci->clientnum, ci->ownernum, ci->state.aitype, ci->state.skill, ci->playermodel, ci->name, ci->team);
- if(ci->aireinit == 2) {
- ci->reassign();
- if(ci->state.state==CS_ALIVE) sendspawn(ci);
- else sendresume(ci);
- }
- ci->aireinit = 0;
- }
- }
- void shiftai(clientinfo *ci, clientinfo *owner = NULL) {
- clientinfo *prevowner = (clientinfo *)getclientinfo(ci->ownernum);
- if(prevowner) prevowner->bots.removeobj(ci);
- if(!owner) { ci->aireinit = 0; ci->ownernum = -1; }
- else if(ci->ownernum != owner->clientnum) { ci->aireinit = 2; ci->ownernum = owner->clientnum; owner->bots.add(ci); }
- dorefresh = true;
- }
- void removeai(clientinfo *ci) {
- // either schedules a removal, or someone else to assign to
- loopvrev(ci->bots) shiftai(ci->bots[i], findaiclient(ci));
- }
- bool reassignai() {
- clientinfo *hi = NULL, *lo = NULL;
- loopv(clients) {
- clientinfo *ci = clients[i];
- if(!validaiclient(ci)) continue;
- if(!lo || ci->bots.length() < lo->bots.length()) lo = ci;
- if(!hi || ci->bots.length() > hi->bots.length()) hi = ci;
- }
- if(hi && lo && hi->bots.length() - lo->bots.length() > 1) {
- loopvrev(hi->bots) {
- shiftai(hi->bots[i], lo);
- return true;
- }
- }
- return false;
- }
-
- void checksetup() {
- if(m_teammode && botbalance) balanceteams();
- loopvrev(bots) if(bots[i]) reinitai(bots[i]);
- }
- void clearai() {
- // clear and remove all ai immediately
- loopvrev(bots) if(bots[i]) deleteai(bots[i]);
- }
- void checkai() {
- if(!dorefresh) return;
- dorefresh = false;
- if(m_botmode && numclients(-1, false, true)) {
- checksetup();
- while(reassignai());
- }
- else clearai();
- }
- void reqadd(clientinfo *ci, int skill) {
- if(!ci->local && !ci->privilege) return;
- if(!addai(skill, !ci->local && ci->privilege < PRIV_ADMIN ? botlimit : -1)) sendf(ci->clientnum, 1, "ris", N_SERVMSG, "failed to create or assign bot");
- }
- void reqdel(clientinfo *ci) {
- if(!ci->local && !ci->privilege) return;
- if(!deleteai()) sendf(ci->clientnum, 1, "ris", N_SERVMSG, "failed to remove any bots");
- }
- void setbotlimit(clientinfo *ci, int limit) {
- if(ci && !ci->local && ci->privilege < PRIV_ADMIN) return;
- botlimit = clamp(limit, 0, MAXBOTS);
- dorefresh = true;
- defformatstring(msg, "bot limit is now %d", botlimit);
- sendservmsg(msg);
- }
- void setbotbalance(clientinfo *ci, bool balance) {
- if(ci && !ci->local && !ci->privilege) return;
- botbalance = balance ? 1 : 0;
- dorefresh = true;
- defformatstring(msg, "bot team balancing is now %s", botbalance ? "enabled" : "disabled");
- sendservmsg(msg);
- }
-
- void changemap() {
- dorefresh = true;
- loopv(clients) if(clients[i]->local || clients[i]->privilege) return;
- if(botbalance != (serverbotbalance != 0)) setbotbalance(NULL, serverbotbalance != 0);
- }
- void addclient(clientinfo *ci) {
- if(ci->state.aitype == AI_NONE) dorefresh = true;
- }
- void changeteam(clientinfo *ci) {
- if(ci->state.aitype == AI_NONE) dorefresh = true;
- }
-}
if(i>=0) addmsg(N_SPECTATOR, "rii", i, val);
}
ICOMMAND(spectator, "is", (int *val, char *who), togglespectator(*val, who));
- ICOMMAND(checkmaps, "", (), addmsg(N_CHECKMAPS, "r"));
int gamemode = INT_MAX, nextmode = INT_MAX;
string clientmap = "";
void changemapserv(const char *name, int mode) { // forced map change from the server {
clientdisconnected(getint(p));
break;
case N_SPAWN: {
- if(d) {
- if(d->state==CS_DEAD && d->lastpain) saveragdoll(d);
- d->respawn();
- }
+ if(d) d->respawn();
parsestate(d, p);
if(!d) break;
d->state = CS_SPAWNING;
int scn = getint(p);
fpsent *s = getclient(scn);
if(!s) { parsestate(NULL, p); break; }
- if(s->state==CS_DEAD && s->lastpain) saveragdoll(s);
if(s==player1) {
if(editmode) toggleedit();
stopfollowing();
if(mdlname) {
vec p = e.o;
p.z += 1+sinf(lastmillis/100.0+e.o.x+e.o.y)/20;
- rendermodel(&e.light, mdlname, ANIM_MAPMODEL|ANIM_LOOP, p, lastmillis/(float)revs, 0, MDL_SHADOW | MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED);
+ rendermodel(&e.light, mdlname, ANIM_MAPMODEL|ANIM_LOOP, p, lastmillis/(float)revs, 0, MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED);
}
}
}
+++ /dev/null
-
-#define EXT_ACK -1
-#define EXT_VERSION 105
-#define EXT_NO_ERROR 0
-#define EXT_ERROR 1
-#define EXT_PLAYERSTATS_RESP_IDS -10
-#define EXT_PLAYERSTATS_RESP_STATS -11
-#define EXT_UPTIME 0
-#define EXT_PLAYERSTATS 1
-#define EXT_TEAMSCORE 2
-
-/*
- Client:
- -----
- A: 0 EXT_UPTIME
- B: 0 EXT_PLAYERSTATS cn #a client number or -1 for all players#
- C: 0 EXT_TEAMSCORE
- Server:
- --------
- A: 0 EXT_UPTIME EXT_ACK EXT_VERSION uptime #in seconds#
- B: 0 EXT_PLAYERSTATS cn #send by client# EXT_ACK EXT_VERSION 0 or 1 #error, if cn was > -1 and client does not exist# ...
- EXT_PLAYERSTATS_RESP_IDS pid(s) #1 packet#
- EXT_PLAYERSTATS_RESP_STATS pid playerdata #1 packet for each player#
- C: 0 EXT_TEAMSCORE EXT_ACK EXT_VERSION 0 or 1 #error, no teammode# remaining_time gamemode loop(teamdata [numbases bases] or -1)
- Errors:
- --------------
- B:C:default: 0 command EXT_ACK EXT_VERSION EXT_ERROR
-*/
- VAR(extinfoip, 0, 0, 1);
- void extinfoplayer(ucharbuf &p, clientinfo *ci) {
- ucharbuf q = p;
- putint(q, EXT_PLAYERSTATS_RESP_STATS); // send player stats following
- putint(q, ci->clientnum); //add player id
- putint(q, ci->ping);
- sendstring(ci->name, q);
- sendstring(ci->team, q);
- putint(q, ci->state.frags);
- putint(q, ci->state.flags);
- putint(q, ci->state.deaths);
- putint(q, ci->state.teamkills);
- putint(q, ci->state.damage*100/max(ci->state.shotdamage,1));
- putint(q, ci->state.health);
- putint(q, ci->state.armour);
- putint(q, ci->state.gunselect);
- putint(q, ci->privilege);
- putint(q, ci->state.state);
- uint ip = extinfoip ? getclientip(ci->clientnum) : 0;
- q.put((uchar*)&ip, 3);
- sendserverinforeply(q);
- }
- static inline void extinfoteamscore(ucharbuf &p, const char *team, int score) {
- sendstring(team, p);
- putint(p, score);
- putint(p,-1); //no bases follow
- }
- void extinfoteams(ucharbuf &p) {
- putint(p, m_teammode ? 0 : 1);
- putint(p, gamemode);
- putint(p, max((gamelimit - gamemillis)/1000, 0));
- if(!m_teammode) return;
- vector<teamscore> scores;
- loopv(clients) {
- clientinfo *ci = clients[i];
- if(ci->state.state!=CS_SPECTATOR && ci->team[0] && scores.htfind(ci->team) < 0) {
- teaminfo *ti = teaminfos.access(ci->team);
- scores.add(teamscore(ci->team, ti ? ti->frags : 0));
- }
- }
- loopv(scores) extinfoteamscore(p, scores[i].team, scores[i].score);
- }
- void extserverinforeply(ucharbuf &req, ucharbuf &p) {
- int extcmd = getint(req); // extended commands
- //Build a new packet
- putint(p, EXT_ACK); //send ack
- putint(p, EXT_VERSION); //send version of extended info
- switch(extcmd) {
- case EXT_UPTIME: {
- putint(p, totalsecs); //in seconds
- break;
- }
- case EXT_PLAYERSTATS: {
- int cn = getint(req); //a special player, -1 for all
- clientinfo *ci = NULL;
- if(cn >= 0) {
- loopv(clients) if(clients[i]->clientnum == cn) { ci = clients[i]; break; }
- if(!ci) {
- putint(p, EXT_ERROR); //client requested by id was not found
- sendserverinforeply(p);
- return;
- }
- }
- putint(p, EXT_NO_ERROR); //so far no error can happen anymore
- ucharbuf q = p; //remember buffer position
- putint(q, EXT_PLAYERSTATS_RESP_IDS); //send player ids following
- if(ci) putint(q, ci->clientnum);
- else loopv(clients) putint(q, clients[i]->clientnum);
- sendserverinforeply(q);
- if(ci) extinfoplayer(p, ci);
- else loopv(clients) extinfoplayer(p, clients[i]);
- return;
- }
- case EXT_TEAMSCORE: {
- extinfoteams(p);
- break;
- }
- default: {
- putint(p, EXT_ERROR);
- break;
- }
- }
- sendserverinforeply(p);
- }
loopv(players) {
fpsent *d = players[i];
if(d == player1 || d->ai) continue;
- if(d->state==CS_DEAD && d->ragdoll) moveragdoll(d);
- else if(!intermission) {
+ if(!intermission) {
if(lastmillis - d->lastaction >= d->gunwait) d->gunwait = 0;
if(d->quadmillis) entities::checkquad(curtime, d);
}
if(smoothmove && d->smoothmillis>0) predictplayer(d, true);
else moveplayer(d, 1, false);
}
- else if(d->state==CS_DEAD && !d->ragdoll && lastmillis-d->lastpain<2000) moveplayer(d, 1, true);
+ else if(d->state==CS_DEAD && lastmillis-d->lastpain<2000) moveplayer(d, 1, true);
}
}
void checkslowmo() {
updateweapons(curtime);
otherplayers(curtime);
ai::update();
- moveragdolls();
gets2c();
if(connected) {
if(player1->state == CS_DEAD) {
- if(player1->ragdoll) moveragdoll(player1);
- else if(lastmillis-player1->lastpain<2000) {
+ if(lastmillis-player1->lastpain<2000) {
player1->move = player1->strafe = 0;
moveplayer(player1, 10, true);
}
}
else if(!intermission) {
- if(player1->ragdoll) cleanragdoll(player1);
moveplayer(player1, 10, true);
swayhudgun(curtime);
entities::checkitems(player1);
float a = x - lower, b = x - upper;
return (b * b) / (a * a + b * b);
}
- static inline float harmonicmean(float a, float b) { return a + b > 0 ? 2 * a * b / (a + b) : 0.0f; }
// avoid spawning near other players
float ratespawn(dynent *d, const extentity &e) {
fpsent *p = (fpsent *)d;
void startgame() {
clearprojectiles();
clearbouncers();
- clearragdolls();
clearteaminfo();
// reset perma-state
loopv(players) {
N_AUTHTRY, N_AUTHKICK, N_AUTHCHAL, N_AUTHANS, N_REQAUTH,
N_PAUSEGAME, N_GAMESPEED,
N_ADDBOT, N_DELBOT, N_INITAI, N_FROMAI, N_BOTLIMIT, N_BOTBALANCE,
- N_MAPCRC, N_CHECKMAPS,
+ N_MAPCRC,
N_SWITCHNAME, N_SWITCHMODEL, N_SWITCHTEAM,
N_INITTOKENS, N_TAKETOKEN, N_EXPIRETOKENS, N_DROPTOKENS, N_DEPOSITTOKENS, N_STEALTOKENS,
N_SERVCMD,
N_AUTHTRY, 0, N_AUTHKICK, 0, N_AUTHCHAL, 0, N_AUTHANS, 0, N_REQAUTH, 0,
N_PAUSEGAME, 0, N_GAMESPEED, 0,
N_ADDBOT, 2, N_DELBOT, 1, N_INITAI, 0, N_FROMAI, 2, N_BOTLIMIT, 2, N_BOTBALANCE, 2,
- N_MAPCRC, 0, N_CHECKMAPS, 1,
+ N_MAPCRC, 0,
N_SWITCHNAME, 0, N_SWITCHMODEL, 2, N_SWITCHTEAM, 0,
N_INITTOKENS, 0, N_TAKETOKEN, 2, N_EXPIRETOKENS, 0, N_DROPTOKENS, 0, N_DEPOSITTOKENS, 2, N_STEALTOKENS, 0,
N_SERVCMD, 0,
const char *ffa, *blueteam, *redteam, *hudguns,
*vwep, *quad, *armour[3],
*ffaicon, *blueicon, *redicon;
- bool ragdoll;
};
extern int playermodel, teamskins, testteam;
- extern void saveragdoll(fpsent *d);
- extern void clearragdolls();
- extern void moveragdolls();
extern const playermodelinfo &getplayermodelinfo(fpsent *d);
extern void swayhudgun(int curtime);
extern vec hudgunorigin(int gun, const vec &from, const vec &to, fpsent *d);
namespace game {
vector<fpsent *> bestplayers;
vector<const char *> bestteams;
- VARP(ragdoll, 0, 1, 1);
- VARP(ragdollmillis, 0, 10000, 300000);
- VARP(ragdollfade, 0, 1000, 300000);
VARP(playermodel, 0, 0, 0);
VARP(hidedead, 0, 0, 2);
- vector<fpsent *> ragdolls;
- void saveragdoll(fpsent *d) {
- if(!d->ragdoll || !ragdollmillis || (!ragdollfade && lastmillis > d->lastpain + ragdollmillis)) return;
- fpsent *r = new fpsent(*d);
- r->lastupdate = ragdollfade && lastmillis > d->lastpain + max(ragdollmillis - ragdollfade, 0) ? lastmillis - max(ragdollmillis - ragdollfade, 0) : d->lastpain;
- r->edit = NULL;
- r->ai = NULL;
- r->attackchan = r->idlechan = -1;
- if(d==player1) r->playermodel = playermodel;
- ragdolls.add(r);
- d->ragdoll = NULL;
- }
- void clearragdolls() {
- ragdolls.deletecontents();
- }
- void moveragdolls() {
- loopv(ragdolls) {
- fpsent *d = ragdolls[i];
- if(lastmillis > d->lastupdate + ragdollmillis) {
- delete ragdolls.remove(i--);
- continue;
- }
- moveragdoll(d);
- }
- }
- static const playermodelinfo playermodels[1] = {
- {
- "mrfixit", "mrfixit/blue", "mrfixit/red", "mrfixit/hudguns", NULL, "mrfixit/horns", {
- "mrfixit/armor/blue", "mrfixit/armor/green", "mrfixit/armor/yellow" },
- "mrfixit", "mrfixit_blue", "mrfixit_red", true },
- };
+ static const playermodelinfo playermodels[1] = { {
+ //~const char *ffa, *blueteam, *redteam, *hudguns,
+ //~*vwep, *quad, *armour[3],
+ //~*ffaicon, *blueicon, *redicon;
+ "mrfixit", "mrfixit/blue", "mrfixit/red", "mrfixit/hudguns", NULL, "mrfixit/horns",
+ { "mrfixit/armor/blue", "mrfixit/armor/green", "mrfixit/armor/yellow" },
+ "mrfixit", "mrfixit_blue", "mrfixit_red"
+ } };
const playermodelinfo *getplayermodelinfo(int n) {
(void) n;
return &playermodels[0];
case 1: mdlname = mdl.blueteam; break;
case 2: mdlname = mdl.redteam; break;
}
- renderclient(d, mdlname, a[0].tag ? a : NULL, hold, attack, delay, lastaction, intermission && d->state!=CS_DEAD ? 0 : d->lastpain, fade, ragdoll && mdl.ragdoll);
+ renderclient(d, mdlname, a[0].tag ? a : NULL, hold, attack, delay, lastaction, intermission && d->state!=CS_DEAD ? 0 : d->lastpain, fade);
}
VARP(teamskins, 0, 0, 1);
VARP(statusicons, 0, 1, 1);
renderstatusicons(d, team, offset);
}
}
- loopv(ragdolls) {
- fpsent *d = ragdolls[i];
- int team = 0;
- if(teamskins || m_teammode) team = isteam(player1->team, d->team) ? 1 : 2;
- float fade = 1.0f;
- if(ragdollmillis && ragdollfade)
- fade -= clamp(float(lastmillis - (d->lastupdate + max(ragdollmillis - ragdollfade, 0)))/min(ragdollmillis, ragdollfade), 0.0f, 1.0f);
- renderplayer(d, getplayermodelinfo(d), team, fade, mainpass);
- }
if(isthirdperson() && !followingplayer() && (player1->state!=CS_DEAD || hidedead != 1)) renderplayer(player1, getplayermodelinfo(player1), teamskins || m_teammode ? 1 : 0, 1, mainpass);
entities::renderentities();
renderbouncers();
VARP(hudgun, 0, 1, 1);
VARP(hudgunsway, 0, 1, 1);
VARP(teamhudguns, 0, 1, 1);
- VARP(chainsawhudgun, 0, 1, 1);
VAR(testhudgun, 0, 0, 1);
FVAR(swaystep, 1, 35.0f, 100);
FVAR(swayside, 0, 0.04f, 1);
d->muzzle = vec(-1, -1, -1);
a[0] = modelattach("tag_muzzle", &d->muzzle);
dynent *interp = NULL;
- if(d->gunselect==GUN_FIST && chainsawhudgun) {
+ if(d->gunselect==GUN_FIST) {
anim |= ANIM_LOOP;
base = 0;
interp = &guninterp;
/// PW
g.separator();
g.pushlist();
- g.textf(" %d%% ", 0x787878, "chainsaw.png", pwaccuracy[0]);
- g.textf(" %d%% ", 0xfba6a6, "shotgun.png", pwaccuracy[1]);
- g.textf(" %d%% ", 0x7bc77a, "chaingun.png", pwaccuracy[2]);
- g.textf(" %d%% ", 0xefd7a6, "rocket_launcher.png", pwaccuracy[3]);
- g.textf(" %d%% ", 0x8f91e7, "rifle.png", pwaccuracy[4]);
- g.textf(" %d%% ", 0x9ee5e5, "grenade_launcher.png", pwaccuracy[5]);
- g.textf(" %d%% ", 0xc3c3c3, "pistol.png", pwaccuracy[6]);
+ g.textf("%d%% ", 0x787878, "chainsaw.png", pwaccuracy[0]);
+ g.textf("%d%% ", 0xfba6a6, "shotgun.png", pwaccuracy[1]);
+ g.textf("%d%% ", 0x7bc77a, "chaingun.png", pwaccuracy[2]);
+ g.textf("%d%% ", 0xefd7a6, "rocket_launcher.png", pwaccuracy[3]);
+ g.textf("%d%% ", 0x8f91e7, "rifle.png", pwaccuracy[4]);
+ g.textf("%d%% ", 0x9ee5e5, "grenade_launcher.png", pwaccuracy[5]);
+ g.textf("%d%% ", 0xc3c3c3, "pistol.png", pwaccuracy[6]);
g.poplist();
g.separator();
g.pushlist();
- g.textf(" x %d ", 0xffffff, "blue_armour.png", pwitemspicked[0]);
- g.textf(" x %d ", 0xffffff, "green_armour.png", pwitemspicked[1]);
- g.textf(" x %d ", 0xffffff, "yellow_armour.png", pwitemspicked[2]);
- g.textf(" x %d ", 0xffffff, "tiny_health.png", pwitemspicked[3]);
- g.textf(" x %d ", 0xffffff, "health.png", pwitemspicked[4]);
- g.textf(" x %d ", 0xffffff, "health_boost.png", pwitemspicked[5]);
- g.textf(" x %d ", 0xffffff, "quad_damage.png", pwitemspicked[6]);
+ g.textf("%d ", 0xffffff, "blue_armour.png", pwitemspicked[0]);
+ g.textf("%d ", 0xffffff, "green_armour.png", pwitemspicked[1]);
+ g.textf("%d ", 0xffffff, "yellow_armour.png", pwitemspicked[2]);
+ g.textf("%d ", 0xffffff, "tiny_health.png", pwitemspicked[3]);
+ g.textf("%d ", 0xffffff, "health.png", pwitemspicked[4]);
+ g.textf("%d ", 0xffffff, "health_boost.png", pwitemspicked[5]);
+ g.textf("%d ", 0xffffff, "quad_damage.png", pwitemspicked[6]);
g.poplist();
}
struct scoreboardgui : g3d_callback {
extern void reqadd(clientinfo *ci, int skill);
extern void reqdel(clientinfo *ci);
extern void setbotlimit(clientinfo *ci, int limit);
- extern void setbotbalance(clientinfo *ci, bool balance);
extern void changemap();
extern void addclient(clientinfo *ci);
extern void changeteam(clientinfo *ci);
crcinfo(int crc, int matches) : crc(crc), matches(matches) {}
static bool compare(const crcinfo &x, const crcinfo &y) { return x.matches > y.matches; }
};
- VAR(modifiedmapspectator, 0, 1, 2);
- void checkmaps(int req = -1) {
- if(m_edit || !smapname[0]) return;
- vector<crcinfo> crcs;
- int total = 0, unsent = 0, invalid = 0;
- if(mcrc) crcs.add(crcinfo(mcrc, clients.length() + 1));
- loopv(clients) {
- clientinfo *ci = clients[i];
- if(ci->state.state==CS_SPECTATOR || ci->state.aitype != AI_NONE) continue;
- total++;
- if(!ci->clientmap[0]) {
- if(ci->mapcrc < 0) invalid++;
- else if(!ci->mapcrc) unsent++;
- }
- else {
- crcinfo *match = NULL;
- loopvj(crcs) if(crcs[j].crc == ci->mapcrc) { match = &crcs[j]; break; }
- if(!match) crcs.add(crcinfo(ci->mapcrc, 1));
- else match->matches++;
- }
- }
- if(!mcrc && total - unsent < min(total, 4)) return;
- crcs.sort(crcinfo::compare);
- string msg;
- loopv(clients) {
- clientinfo *ci = clients[i];
- if(ci->state.state==CS_SPECTATOR || ci->state.aitype != AI_NONE || ci->clientmap[0] || ci->mapcrc >= 0 || (req < 0 && ci->warned)) continue;
- formatstring(msg, "%s has modified map \"%s\"", colorname(ci), smapname);
- sendf(req, 1, "ris", N_SERVMSG, msg);
- if(req < 0) ci->warned = true;
- }
- if(crcs.length() >= 2) loopv(crcs) {
- crcinfo &info = crcs[i];
- if(i || info.matches <= crcs[i+1].matches) loopvj(clients) {
- clientinfo *ci = clients[j];
- if(ci->state.state==CS_SPECTATOR || ci->state.aitype != AI_NONE || !ci->clientmap[0] || ci->mapcrc != info.crc || (req < 0 && ci->warned)) continue;
- formatstring(msg, "%s has modified map \"%s\"", colorname(ci), smapname);
- sendf(req, 1, "ris", N_SERVMSG, msg);
- if(req < 0) ci->warned = true;
- }
- }
- if(req < 0 && modifiedmapspectator && (mcrc || modifiedmapspectator > 1)) loopv(clients) {
- clientinfo *ci = clients[i];
- if(!ci->local && ci->warned && ci->state.state != CS_SPECTATOR) forcespectator(ci);
- }
- }
- bool shouldspectate(clientinfo *ci) {
- return !ci->local && ci->warned && modifiedmapspectator && (mcrc || modifiedmapspectator > 1);
- }
void unspectate(clientinfo *ci) {
- if(shouldspectate(ci)) return;
ci->state.state = CS_DEAD;
ci->state.respawn();
ci->state.lasttimeplayed = lastmillis;
aiman::addclient(ci);
sendf(-1, 1, "ri3", N_SPECTATOR, ci->clientnum, 0);
- if(ci->clientmap[0] || ci->mapcrc) checkmaps();
if(!hasmap(ci)) rotatemap(true);
}
void sendservinfo(clientinfo *ci) {
}
copystring(ci->clientmap, text);
ci->mapcrc = text[0] ? crc : 1;
- checkmaps();
if(cq && cq != ci && cq->ownernum != ci->clientnum) cq = NULL;
break;
}
- case N_CHECKMAPS:
- checkmaps(sender);
- break;
case N_TRYSPAWN:
if(!ci || !cq || cq->state.state!=CS_DEAD || cq->state.lastspawn>=0) break;
if(!ci->clientmap[0] && !ci->mapcrc) {
ci->mapcrc = -1;
- checkmaps();
if(ci == cq) { if(ci->state.state != CS_DEAD) break; }
else if(cq->ownernum != ci->clientnum) { cq = NULL; break; }
}
if(ci) aiman::setbotlimit(ci, limit);
break;
}
- case N_BOTBALANCE: {
- int balance = getint(p);
- if(ci) aiman::setbotbalance(ci, balance!=0);
- break;
- }
case N_AUTHTRY: {
string desc, name;
getstring(desc, p, sizeof(desc));
const char *defaultmaster() { return "master.sauerbraten.org"; }
int masterport() { return SAUERBRATEN_MASTER_PORT; }
int numchannels() { return 3; }
- #include "extinfo.h"
+
+#define EXT_ACK -1
+#define EXT_VERSION 105
+#define EXT_NO_ERROR 0
+#define EXT_ERROR 1
+#define EXT_PLAYERSTATS_RESP_IDS -10
+#define EXT_PLAYERSTATS_RESP_STATS -11
+#define EXT_UPTIME 0
+#define EXT_PLAYERSTATS 1
+#define EXT_TEAMSCORE 2
+
+ VAR(extinfoip, 0, 0, 1);
+ void extinfoplayer(ucharbuf &p, clientinfo *ci) {
+ ucharbuf q = p;
+ putint(q, EXT_PLAYERSTATS_RESP_STATS); // send player stats following
+ putint(q, ci->clientnum); //add player id
+ putint(q, ci->ping);
+ sendstring(ci->name, q);
+ sendstring(ci->team, q);
+ putint(q, ci->state.frags);
+ putint(q, ci->state.flags);
+ putint(q, ci->state.deaths);
+ putint(q, ci->state.teamkills);
+ putint(q, ci->state.damage*100/max(ci->state.shotdamage,1));
+ putint(q, ci->state.health);
+ putint(q, ci->state.armour);
+ putint(q, ci->state.gunselect);
+ putint(q, ci->privilege);
+ putint(q, ci->state.state);
+ uint ip = extinfoip ? getclientip(ci->clientnum) : 0;
+ q.put((uchar*)&ip, 3);
+ sendserverinforeply(q);
+ }
+ static inline void extinfoteamscore(ucharbuf &p, const char *team, int score) {
+ sendstring(team, p);
+ putint(p, score);
+ putint(p,-1); //no bases follow
+ }
+ void extinfoteams(ucharbuf &p) {
+ putint(p, m_teammode ? 0 : 1);
+ putint(p, gamemode);
+ putint(p, max((gamelimit - gamemillis)/1000, 0));
+ if(!m_teammode) return;
+ vector<teamscore> scores;
+ loopv(clients) {
+ clientinfo *ci = clients[i];
+ if(ci->state.state!=CS_SPECTATOR && ci->team[0] && scores.htfind(ci->team) < 0) {
+ teaminfo *ti = teaminfos.access(ci->team);
+ scores.add(teamscore(ci->team, ti ? ti->frags : 0));
+ }
+ }
+ loopv(scores) extinfoteamscore(p, scores[i].team, scores[i].score);
+ }
+ void extserverinforeply(ucharbuf &req, ucharbuf &p) {
+ int extcmd = getint(req); // extended commands
+ //Build a new packet
+ putint(p, EXT_ACK); //send ack
+ putint(p, EXT_VERSION); //send version of extended info
+ switch(extcmd) {
+ case EXT_UPTIME: {
+ putint(p, totalsecs); //in seconds
+ break;
+ }
+ case EXT_PLAYERSTATS: {
+ int cn = getint(req); //a special player, -1 for all
+ clientinfo *ci = NULL;
+ if(cn >= 0) {
+ loopv(clients) if(clients[i]->clientnum == cn) { ci = clients[i]; break; }
+ if(!ci) {
+ putint(p, EXT_ERROR); //client requested by id was not found
+ sendserverinforeply(p);
+ return;
+ }
+ }
+ putint(p, EXT_NO_ERROR); //so far no error can happen anymore
+ ucharbuf q = p; //remember buffer position
+ putint(q, EXT_PLAYERSTATS_RESP_IDS); //send player ids following
+ if(ci) putint(q, ci->clientnum);
+ else loopv(clients) putint(q, clients[i]->clientnum);
+ sendserverinforeply(q);
+ if(ci) extinfoplayer(p, ci);
+ else loopv(clients) extinfoplayer(p, clients[i]);
+ return;
+ }
+ case EXT_TEAMSCORE: {
+ extinfoteams(p);
+ break;
+ }
+ default: {
+ putint(p, EXT_ERROR);
+ break;
+ }
+ }
+ sendserverinforeply(p);
+ }
+
void serverinforeply(ucharbuf &req, ucharbuf &p) {
if(req.remaining() && !getint(req)) {
extserverinforeply(req, p);
sendstring(serverdesc, p);
sendserverinforeply(p);
}
- #include "aiman.h"
+
+ // server-side ai manager
+ namespace aiman {
+ bool dorefresh = false;
+ VARN(serverbotlimit, botlimit, 0, 8, MAXBOTS);
+ void calcteams(vector<teamscore> &teams) {
+ static const char * const defaults[2] = { "good", "evil" };
+ loopv(clients) {
+ clientinfo *ci = clients[i];
+ if(ci->state.state==CS_SPECTATOR || !ci->team[0]) continue;
+ teamscore *t = NULL;
+ loopvj(teams) if(!strcmp(teams[j].team, ci->team)) { t = &teams[j]; break; }
+ if(t) t->score++;
+ else teams.add(teamscore(ci->team, 1));
+ }
+ teams.sort(teamscore::compare);
+ if(teams.length() < int(sizeof(defaults)/sizeof(defaults[0]))) {
+ loopi(sizeof(defaults)/sizeof(defaults[0])) if(teams.htfind(defaults[i]) < 0) teams.add(teamscore(defaults[i], 0));
+ }
+ }
+
+ const char *chooseteam() {
+ vector<teamscore> teams;
+ calcteams(teams);
+ return teams.length() ? teams.last().team : "";
+ }
+ static inline bool validaiclient(clientinfo *ci) {
+ return ci->clientnum >= 0 && ci->state.aitype == AI_NONE && (ci->state.state!=CS_SPECTATOR || ci->local || (ci->privilege && !ci->warned));
+ }
+ clientinfo *findaiclient(clientinfo *exclude = NULL) {
+ clientinfo *least = NULL;
+ loopv(clients) {
+ clientinfo *ci = clients[i];
+ if(!validaiclient(ci) || ci==exclude) continue;
+ if(!least || ci->bots.length() < least->bots.length()) least = ci;
+ }
+ return least;
+ }
+ bool addai(int skill, int limit) {
+ int numai = 0, cn = -1, maxai = limit >= 0 ? min(limit, MAXBOTS) : MAXBOTS;
+ loopv(bots) {
+ clientinfo *ci = bots[i];
+ if(!ci || ci->ownernum < 0) { if(cn < 0) cn = i; continue; }
+ numai++;
+ }
+ if(numai >= maxai) return false;
+ if(bots.inrange(cn)) {
+ clientinfo *ci = bots[cn];
+ if(ci) {
+ // reuse a slot that was going to removed
+ clientinfo *owner = findaiclient();
+ ci->ownernum = owner ? owner->clientnum : -1;
+ if(owner) owner->bots.add(ci);
+ ci->aireinit = 2;
+ dorefresh = true;
+ return true;
+ }
+ }
+ else { cn = bots.length(); bots.add(NULL); }
+ const char *team = m_teammode ? chooseteam() : "";
+ if(!bots[cn]) bots[cn] = new clientinfo;
+ clientinfo *ci = bots[cn];
+ ci->clientnum = MAXCLIENTS + cn;
+ ci->state.aitype = AI_BOT;
+ clientinfo *owner = findaiclient();
+ ci->ownernum = owner ? owner->clientnum : -1;
+ if(owner) owner->bots.add(ci);
+ ci->state.skill = skill <= 0 ? rnd(50) + 51 : clamp(skill, 1, 101);
+ clients.add(ci);
+ ci->state.lasttimeplayed = lastmillis;
+ copystring(ci->name, "bot", MAXNAMELEN+1);
+ ci->state.state = CS_DEAD;
+ copystring(ci->team, team, MAXTEAMLEN+1);
+ ci->playermodel = 0;
+ ci->aireinit = 2;
+ ci->connected = true;
+ dorefresh = true;
+ return true;
+ }
+ void deleteai(clientinfo *ci) {
+ int cn = ci->clientnum - MAXCLIENTS;
+ if(!bots.inrange(cn)) return;
+ sendf(-1, 1, "ri2", N_CDIS, ci->clientnum);
+ clientinfo *owner = (clientinfo *)getclientinfo(ci->ownernum);
+ if(owner) owner->bots.removeobj(ci);
+ clients.removeobj(ci);
+ DELETEP(bots[cn]);
+ dorefresh = true;
+ }
+ bool deleteai() {
+ loopvrev(bots) if(bots[i] && bots[i]->ownernum >= 0) {
+ deleteai(bots[i]);
+ return true;
+ }
+ return false;
+ }
+ void reinitai(clientinfo *ci) {
+ if(ci->ownernum < 0) deleteai(ci);
+ else if(ci->aireinit >= 1) {
+ sendf(-1, 1, "ri6ss", N_INITAI, ci->clientnum, ci->ownernum, ci->state.aitype, ci->state.skill, ci->playermodel, ci->name, ci->team);
+ if(ci->aireinit == 2) {
+ ci->reassign();
+ if(ci->state.state==CS_ALIVE) sendspawn(ci);
+ else sendresume(ci);
+ }
+ ci->aireinit = 0;
+ }
+ }
+ void shiftai(clientinfo *ci, clientinfo *owner = NULL) {
+ clientinfo *prevowner = (clientinfo *)getclientinfo(ci->ownernum);
+ if(prevowner) prevowner->bots.removeobj(ci);
+ if(!owner) { ci->aireinit = 0; ci->ownernum = -1; }
+ else if(ci->ownernum != owner->clientnum) { ci->aireinit = 2; ci->ownernum = owner->clientnum; owner->bots.add(ci); }
+ dorefresh = true;
+ }
+ void removeai(clientinfo *ci) {
+ // either schedules a removal, or someone else to assign to
+ loopvrev(ci->bots) shiftai(ci->bots[i], findaiclient(ci));
+ }
+ bool reassignai() {
+ clientinfo *hi = NULL, *lo = NULL;
+ loopv(clients) {
+ clientinfo *ci = clients[i];
+ if(!validaiclient(ci)) continue;
+ if(!lo || ci->bots.length() < lo->bots.length()) lo = ci;
+ if(!hi || ci->bots.length() > hi->bots.length()) hi = ci;
+ }
+ if(hi && lo && hi->bots.length() - lo->bots.length() > 1) {
+ loopvrev(hi->bots) {
+ shiftai(hi->bots[i], lo);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void checksetup() {
+ loopvrev(bots) if(bots[i]) reinitai(bots[i]);
+ }
+ void clearai() {
+ // clear and remove all ai immediately
+ loopvrev(bots) if(bots[i]) deleteai(bots[i]);
+ }
+ void checkai() {
+ if(!dorefresh) return;
+ dorefresh = false;
+ if(m_botmode && numclients(-1, false, true)) {
+ checksetup();
+ while(reassignai());
+ }
+ else clearai();
+ }
+ void reqadd(clientinfo *ci, int skill) {
+ if(!ci->local && !ci->privilege) return;
+ if(!addai(skill, !ci->local && ci->privilege < PRIV_ADMIN ? botlimit : -1)) sendf(ci->clientnum, 1, "ris", N_SERVMSG, "failed to create or assign bot");
+ }
+ void reqdel(clientinfo *ci) {
+ if(!ci->local && !ci->privilege) return;
+ if(!deleteai()) sendf(ci->clientnum, 1, "ris", N_SERVMSG, "failed to remove any bots");
+ }
+ void setbotlimit(clientinfo *ci, int limit) {
+ if(ci && !ci->local && ci->privilege < PRIV_ADMIN) return;
+ botlimit = clamp(limit, 0, MAXBOTS);
+ dorefresh = true;
+ defformatstring(msg, "bot limit is now %d", botlimit);
+ sendservmsg(msg);
+ }
+ void changemap() {
+ dorefresh = true;
+ loopv(clients) if(clients[i]->local || clients[i]->privilege) return;
+ }
+ void addclient(clientinfo *ci) {
+ if(ci->state.aitype == AI_NONE) dorefresh = true;
+ }
+ void changeteam(clientinfo *ci) {
+ if(ci->state.aitype == AI_NONE) dorefresh = true;
+ }
+ }
}
else p.o = v;
}
}
- extern int chainsawhudgun;
VARP(muzzleflash, 0, 1, 1);
VARP(muzzlelight, 0, 1, 1);
void shoteffects(int gun, const vec &from, const vec &to, fpsent *d, bool local, int id, int prevaction) { // create visual effect from a shot {
int sound = guns[gun].sound, pspeed = 25;
switch(gun) {
case GUN_FIST:
- if(d->type==ENT_PLAYER && chainsawhudgun) sound = S_CHAINSAW_ATTACK;
+ if(d->type==ENT_PLAYER) sound = S_CHAINSAW_ATTACK;
break;
case GUN_SG: {
if(!local) createrays(gun, from, to);
}
pitch = -bnc.roll;
if(bnc.bouncetype==BNC_GRENADE)
- rendermodel(&bnc.light, "projectiles/grenade", ANIM_MAPMODEL|ANIM_LOOP, pos, yaw, pitch, MDL_CULL_VFC|MDL_CULL_OCCLUDED|MDL_LIGHT|MDL_LIGHT_FAST|MDL_DYNSHADOW);
+ rendermodel(&bnc.light, "projectiles/grenade", ANIM_MAPMODEL|ANIM_LOOP, pos, yaw, pitch, MDL_CULL_VFC|MDL_CULL_OCCLUDED|MDL_LIGHT|MDL_LIGHT_FAST);
else {
const char *mdl = NULL;
int cull = MDL_CULL_VFC|MDL_CULL_DIST|MDL_CULL_OCCLUDED;
int gun = -1;
switch(d->attacksound) {
case S_CHAINSAW_ATTACK:
- if(chainsawhudgun) gun = GUN_FIST;
+ gun = GUN_FIST;
break;
default:
return;
int sound = -1, radius = 0;
if(d->clientnum >= 0 && d->state == CS_ALIVE) switch(d->gunselect) {
case GUN_FIST:
- if(chainsawhudgun && d->attacksound < 0) {
+ if(d->attacksound < 0) {
sound = S_CHAINSAW_IDLE;
radius = 50;
}
/// Rough accuracy code, client-side only.
int pwshotsfired [NUMGUNS] = { 0 };
-int pwshotshit [NUMGUNS] = { 0 };
+int pwshotshit [NUMGUNS] = { 0 };
int pwdamagedealt [NUMGUNS] = { 0 };
-int pwaccuracy [NUMGUNS] = { 0 };
+int pwaccuracy [NUMGUNS] = { 0 };
+
int pwavgaccuracy = 0;
void pwshot(int gun) {
+++ /dev/null
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <stdio.h>\r
-#include <stdarg.h>\r
-#include <limits.h>\r
-#include <zlib.h>\r
-#include <ft2build.h>\r
-#include FT_FREETYPE_H\r
-#include FT_STROKER_H\r
-#include FT_GLYPH_H\r
-\r
-typedef unsigned char uchar;\r
-typedef unsigned short ushort;\r
-typedef unsigned int uint;\r
-\r
-int imin(int a, int b) { return a < b ? a : b; }\r
-int imax(int a, int b) { return a > b ? a : b; }\r
-\r
-void fatal(const char *fmt, ...)\r {
-\r
- va_list v;\r
- va_start(v, fmt);\r
- vfprintf(stderr, fmt, v);\r
- va_end(v);\r
- fputc('\n', stderr);\r
-\r
- exit(EXIT_FAILURE);\r
-}\r
-\r
-uint bigswap(uint n)\r {
-\r
- const int islittleendian = 1;\r
- return *(const uchar *)&islittleendian ? (n<<24) | (n>>24) | ((n>>8)&0xFF00) | ((n<<8)&0xFF0000) : n;\r
-}\r
-\r
-size_t writebig(FILE *f, uint n)\r {
-\r
- n = bigswap(n);\r
- return fwrite(&n, 1, sizeof(n), f);\r
-}\r
-\r
-void writepngchunk(FILE *f, const char *type, uchar *data, uint len)\r {
-\r
- uint crc;\r
- writebig(f, len);\r
- fwrite(type, 1, 4, f);\r
- fwrite(data, 1, len, f);\r
-\r
- crc = crc32(0, Z_NULL, 0);\r
- crc = crc32(crc, (const Bytef *)type, 4);\r
- if(data) crc = crc32(crc, data, len);\r
- writebig(f, crc);\r
-}\r
-\r
-struct pngihdr\r {
-\r
- uint width, height;\r
- uchar bitdepth, colortype, compress, filter, interlace;\r
-};\r
-\r
-void savepng(const char *filename, uchar *data, int w, int h, int bpp, int flip)\r {
-\r
- const uchar signature[] = { 137, 80, 78, 71, 13, 10, 26, 10 };\r
- struct pngihdr ihdr;\r
- FILE *f;\r
- long idat;\r
- uint len, crc;\r
- z_stream z;\r
- uchar buf[1<<12];\r
- int i, j;\r
-\r
- memset(&ihdr, 0, sizeof(ihdr));\r
- ihdr.width = bigswap(w);\r
- ihdr.height = bigswap(h);\r
- ihdr.bitdepth = 8;\r
- switch(bpp)\r {
-\r
- case 1: ihdr.colortype = 0; break;\r
- case 2: ihdr.colortype = 4; break;\r
- case 3: ihdr.colortype = 2; break;\r
- case 4: ihdr.colortype = 6; break;\r
- default: fatal("cube2font: invalid PNG bpp"); return;\r
- }\r
- f = fopen(filename, "wb");\r
- if(!f) { fatal("cube2font: could not write to %s", filename); return; }\r
-\r
- fwrite(signature, 1, sizeof(signature), f);\r
-\r
- writepngchunk(f, "IHDR", (uchar *)&ihdr, 13);\r
-\r
- idat = ftell(f);\r
- len = 0;\r
- fwrite("\0\0\0\0IDAT", 1, 8, f);\r
- crc = crc32(0, Z_NULL, 0);\r
- crc = crc32(crc, (const Bytef *)"IDAT", 4);\r
-\r
- z.zalloc = NULL;\r
- z.zfree = NULL;\r
- z.opaque = NULL;\r
-\r
- if(deflateInit(&z, Z_BEST_COMPRESSION) != Z_OK)\r
- goto error;\r
-\r
- z.next_out = (Bytef *)buf;\r
- z.avail_out = sizeof(buf);\r
-\r
- for(i = 0; i < h; i++)\r {
-\r
- uchar filter = 0;\r
- for(j = 0; j < 2; j++)\r {
-\r
- z.next_in = j ? (Bytef *)data + (flip ? h-i-1 : i)*w*bpp : (Bytef *)&filter;\r
- z.avail_in = j ? w*bpp : 1;\r
- while(z.avail_in > 0)\r {
-\r
- if(deflate(&z, Z_NO_FLUSH) != Z_OK) goto cleanuperror;\r
- #define FLUSHZ do { \\r
- int flush = sizeof(buf) - z.avail_out; \\r
- crc = crc32(crc, buf, flush); \\r
- len += flush; \\r
- fwrite(buf, 1, flush, f); \\r
- z.next_out = (Bytef *)buf; \\r
- z.avail_out = sizeof(buf); \\r
- } while(0)\r
- FLUSHZ;\r
- }\r
- }\r
- }\r
-\r
- for(;;)\r {
-\r
- int err = deflate(&z, Z_FINISH);\r
- if(err != Z_OK && err != Z_STREAM_END) goto cleanuperror;\r
- FLUSHZ;\r
- if(err == Z_STREAM_END) break;\r
- }\r
-\r
- deflateEnd(&z);\r
-\r
- fseek(f, idat, SEEK_SET);\r
- writebig(f, len);\r
- fseek(f, 0, SEEK_END);\r
- writebig(f, crc);\r
-\r
- writepngchunk(f, "IEND", NULL, 0);\r
-\r
- fclose(f);\r
- return;\r
-\r
-cleanuperror:\r
- deflateEnd(&z);\r
-\r
-error:\r
- fclose(f);\r
-\r
- fatal("cube2font: failed saving PNG to %s", filename);\r
-}\r
-\r
-enum\r {
-\r
- CT_PRINT = 1<<0,\r
- CT_SPACE = 1<<1,\r
- CT_DIGIT = 1<<2,\r
- CT_ALPHA = 1<<3,\r
- CT_LOWER = 1<<4,\r
- CT_UPPER = 1<<5,\r
- CT_UNICODE = 1<<6\r
-};\r
-#define CUBECTYPE(s, p, d, a, A, u, U) \\r
- 0, U, U, U, U, U, U, U, U, s, s, s, s, s, U, U, \\r
- U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, \\r
- s, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, \\r
- d, d, d, d, d, d, d, d, d, d, p, p, p, p, p, p, \\r
- p, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, \\r
- A, A, A, A, A, A, A, A, A, A, A, p, p, p, p, p, \\r
- p, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, \\r
- a, a, a, a, a, a, a, a, a, a, a, p, p, p, p, U, \\r
- U, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, \\r
- u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, U, \\r
- u, U, u, U, u, U, u, U, u, U, u, U, u, U, u, U, \\r
- u, U, u, U, u, U, u, U, u, U, u, U, u, U, u, U, \\r
- u, U, u, U, u, U, u, U, U, u, U, u, U, u, U, U, \\r
- U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, \\r
- U, U, U, U, u, u, u, u, u, u, u, u, u, u, u, u, \\r
- u, u, u, u, u, u, u, u, u, u, u, u, u, u, U, u\r
-const uchar cubectype[256] =\r {
-\r
- CUBECTYPE(CT_SPACE,\r
- CT_PRINT,\r
- CT_PRINT|CT_DIGIT,\r
- CT_PRINT|CT_ALPHA|CT_LOWER,\r
- CT_PRINT|CT_ALPHA|CT_UPPER,\r
- CT_PRINT|CT_UNICODE|CT_ALPHA|CT_LOWER,\r
- CT_PRINT|CT_UNICODE|CT_ALPHA|CT_UPPER)\r
-};\r
-int iscubeprint(uchar c) { return cubectype[c]&CT_PRINT; }\r
-int iscubespace(uchar c) { return cubectype[c]&CT_SPACE; }\r
-int iscubealpha(uchar c) { return cubectype[c]&CT_ALPHA; }\r
-int iscubealnum(uchar c) { return cubectype[c]&(CT_ALPHA|CT_DIGIT); }\r
-int iscubelower(uchar c) { return cubectype[c]&CT_LOWER; }\r
-int iscubeupper(uchar c) { return cubectype[c]&CT_UPPER; }\r
-const int cube2unichars[256] =\r {
-\r
- 0, 192, 193, 194, 195, 196, 197, 198, 199, 9, 10, 11, 12, 13, 200, 201,\r
- 202, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219,\r
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\r
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\r
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,\r
- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\r
- 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,\r
- 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 220,\r
- 221, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237,\r
- 238, 239, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 255, 0x104,\r
- 0x105, 0x106, 0x107, 0x10C, 0x10D, 0x10E, 0x10F, 0x118, 0x119, 0x11A, 0x11B, 0x11E, 0x11F, 0x130, 0x131, 0x141,\r
- 0x142, 0x143, 0x144, 0x147, 0x148, 0x150, 0x151, 0x152, 0x153, 0x158, 0x159, 0x15A, 0x15B, 0x15E, 0x15F, 0x160,\r
- 0x161, 0x164, 0x165, 0x16E, 0x16F, 0x170, 0x171, 0x178, 0x179, 0x17A, 0x17B, 0x17C, 0x17D, 0x17E, 0x404, 0x411,\r
- 0x413, 0x414, 0x416, 0x417, 0x418, 0x419, 0x41B, 0x41F, 0x423, 0x424, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B,\r
- 0x42C, 0x42D, 0x42E, 0x42F, 0x431, 0x432, 0x433, 0x434, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D,\r
- 0x43F, 0x442, 0x444, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x454, 0x490, 0x491\r
-};\r
-int cube2uni(uchar c)\r {
-\r
- return cube2unichars[c];\r
-}\r
-\r
-const char *encodeutf8(int uni)\r {
-\r
- static char buf[7];\r
- char *dst = buf;\r
- if(uni <= 0x7F) { *dst++ = uni; goto uni1; }\r
- else if(uni <= 0x7FF) { *dst++ = 0xC0 | (uni>>6); goto uni2; }\r
- else if(uni <= 0xFFFF) { *dst++ = 0xE0 | (uni>>12); goto uni3; }\r
- else if(uni <= 0x1FFFFF) { *dst++ = 0xF0 | (uni>>18); goto uni4; }\r
- else if(uni <= 0x3FFFFFF) { *dst++ = 0xF8 | (uni>>24); goto uni5; }\r
- else if(uni <= 0x7FFFFFFF) { *dst++ = 0xFC | (uni>>30); goto uni6; }\r
- else goto uni1;\r
-uni6: *dst++ = 0x80 | ((uni>>24)&0x3F);\r
-uni5: *dst++ = 0x80 | ((uni>>18)&0x3F);\r
-uni4: *dst++ = 0x80 | ((uni>>12)&0x3F);\r
-uni3: *dst++ = 0x80 | ((uni>>6)&0x3F);\r
-uni2: *dst++ = 0x80 | (uni&0x3F);\r
-uni1: *dst++ = '\0';\r
- return buf;\r
-}\r
-\r
-struct fontchar { int code, uni, tex, x, y, w, h, offx, offy, offset, advance; FT_BitmapGlyph color, alpha; };\r
-\r
-const char *texdir = "";\r
-\r
-const char *texfilename(const char *name, int texnum)\r {
-\r
- static char file[256];\r
- snprintf(file, sizeof(file), "%s%d.png", name, texnum);\r
- return file;\r
-}\r
-\r
-const char *texname(const char *name, int texnum)\r {
-\r
- static char file[512];\r
- snprintf(file, sizeof(file), "<grey>%s%s", texdir, texfilename(name, texnum));\r
- return file;\r
-}\r
-\r
-void writetexs(const char *name, struct fontchar *chars, int numchars, int numtexs, int tw, int th)\r {
-\r
- int tex;\r
- uchar *pixels = (uchar *)malloc(tw*th*2);\r
- if(!pixels) fatal("cube2font: failed allocating textures");\r
- for(tex = 0; tex < numtexs; tex++)\r {
-\r
- const char *file = texfilename(name, tex);\r
- int texchars = 0, i;\r
- uchar *dst, *src;\r
- memset(pixels, 0, tw*th*2);\r
- for(i = 0; i < numchars; i++)\r {
-\r
- struct fontchar *c = &chars[i];\r
- int x, y;\r
- if(c->tex != tex) continue;\r
- texchars++;\r
- dst = &pixels[2*((c->y + c->offy - c->color->top)*tw + c->x + c->color->left - c->offx)];\r
- src = (uchar *)c->color->bitmap.buffer;\r
- for(y = 0; y < c->color->bitmap.rows; y++)\r {
-\r
- for(x = 0; x < c->color->bitmap.width; x++)\r
- dst[2*x] = src[x];\r
- src += c->color->bitmap.pitch;\r
- dst += 2*tw;\r
- }\r
- dst = &pixels[2*((c->y + c->offy - c->alpha->top)*tw + c->x + c->alpha->left - c->offx)];\r
- src = (uchar *)c->alpha->bitmap.buffer;\r
- for(y = 0; y < c->alpha->bitmap.rows; y++)\r {
-\r
- for(x = 0; x < c->alpha->bitmap.width; x++)\r
- dst[2*x+1] = src[x];\r
- src += c->alpha->bitmap.pitch;\r
- dst += 2*tw;\r
- }\r
- }\r
- printf("cube2font: writing %d chars to %s\n", texchars, file);\r
- savepng(file, pixels, tw, th, 2, 0);\r
- }\r
- free(pixels);\r
-}\r
-\r
-void writecfg(const char *name, struct fontchar *chars, int numchars, int x1, int y1, int x2, int y2, int sw, int sh, int argc, char **argv)\r {
-\r
- FILE *f;\r
- char file[256];\r
- int i, lastcode = 0, lasttex = 0;\r
- snprintf(file, sizeof(file), "%s.cfg", name);\r
- f = fopen(file, "w");\r
- if(!f) fatal("cube2font: failed writing %s", file);\r
- printf("cube2font: writing %d chars to %s\n", numchars, file);\r
- fprintf(f, "//");\r
- for(i = 1; i < argc; i++)\r
- fprintf(f, " %s", argv[i]);\r
- fprintf(f, "\n");\r
- fprintf(f, "font \"%s\" \"%s\" %d %d\n", name, texname(name, 0), sw, sh);\r
- for(i = 0; i < numchars; i++)\r {
-\r
- struct fontchar *c = &chars[i];\r
- if(!lastcode && lastcode < c->code)\r {
-\r
- fprintf(f, "fontoffset \"%s\"\n", encodeutf8(c->uni));\r
- lastcode = c->code;\r
- }\r
- else if(lastcode < c->code)\r {
-\r
- if(lastcode + 1 == c->code)\r
- fprintf(f, "fontskip // %d\n", lastcode);\r
- else\r
- fprintf(f, "fontskip %d // %d .. %d\n", c->code - lastcode, lastcode, c->code-1);\r
- lastcode = c->code;\r
- }\r
- if(lasttex != c->tex)\r {
-\r
- fprintf(f, "\nfonttex \"%s\"\n", texname(name, c->tex));\r
- lasttex = c->tex;\r
- }\r
- if(c->code != c->uni)\r
- fprintf(f, "fontchar %d %d %d %d %d %d %d // %s (%d -> 0x%X)\n", c->x, c->y, c->w, c->h, c->offx+c->offset, y2-c->offy, c->advance, encodeutf8(c->uni), c->code, c->uni);\r
- else\r
- fprintf(f, "fontchar %d %d %d %d %d %d %d // %s (%d)\n", c->x, c->y, c->w, c->h, c->offx+c->offset, y2-c->offy, c->advance, encodeutf8(c->uni), c->code);\r
- lastcode++;\r
- }\r
- fclose(f);\r
-}\r
-\r
-int groupchar(int c)\r {
-\r
- switch(c)\r {
-\r
- case 0x152: case 0x153: case 0x178: return 1;\r
- }\r
- if(c < 127 || c >= 0x2000) return 0;\r
- if(c < 0x100) return 1;\r
- if(c < 0x400) return 2;\r
- return 3;\r
-}\r
-\r
-int sortchars(const void *x, const void *y)\r {
-\r
- const struct fontchar *xc = *(const struct fontchar **)x, *yc = *(const struct fontchar **)y;\r
- int xg = groupchar(xc->uni), yg = groupchar(yc->uni);\r
- if(xg < yg) return -1;\r
- if(xg > yg) return 1;\r
- if(xc->h != yc->h) return yc->h - xc->h;\r
- if(xc->w != yc->w) return yc->w - xc->w;\r
- return yc->uni - xc->uni;\r
-}\r
-\r
-int scorechar(struct fontchar *f, int pad, int tw, int th, int rw, int rh, int ry)\r {
-\r
- int score = 0;\r
- if(rw + f->w > tw) { ry += rh + pad; score = 1; }\r
- if(ry + f->h > th) score = 2;\r
- return score;\r
-}\r
-\r
-int main(int argc, char **argv)\r {
-\r
- FT_Library l;\r
- FT_Face f;\r
- FT_Stroker s, s2;\r
- int i, pad, offset, advance, w, h, tw, th, c, trial = -2, rw = 0, rh = 0, ry = 0, x1 = INT_MAX, x2 = INT_MIN, y1 = INT_MAX, y2 = INT_MIN, w2 = 0, h2 = 0, sw = 0, sh = 0;\r
- float outborder = 0, inborder = 0;\r
- struct fontchar chars[256];\r
- struct fontchar *order[256];\r
- int numchars = 0, numtex = 0;\r
- if(argc < 11)\r
- fatal("Usage: cube2font infile outfile outborder[:inborder] pad offset advance charwidth charheight texwidth texheight [spacewidth spaceheight texdir]");\r
- sscanf(argv[3], "%f:%f", &outborder, &inborder);\r
- pad = atoi(argv[4]);\r
- offset = atoi(argv[5]);\r
- advance = atoi(argv[6]);\r
- w = atoi(argv[7]);\r
- h = atoi(argv[8]);\r
- tw = atoi(argv[9]);\r
- th = atoi(argv[10]);\r
- if(argc > 11) sw = atoi(argv[11]);\r
- if(argc > 12) sh = atoi(argv[12]);\r
- if(argc > 13) texdir = argv[13];\r
- if(FT_Init_FreeType(&l))\r
- fatal("cube2font: failed initing freetype");\r
- if(FT_New_Face(l, argv[1], 0, &f) ||\r
- FT_Set_Charmap(f, f->charmaps[0]) ||\r
- FT_Set_Pixel_Sizes(f, w, h) ||\r
- FT_Stroker_New(l, &s) ||\r
- FT_Stroker_New(l, &s2))\r
- fatal("cube2font: failed loading font %s", argv[1]);\r
- if(outborder > 0) FT_Stroker_Set(s, (FT_Fixed)(outborder * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);\r
- if(inborder > 0) FT_Stroker_Set(s2, (FT_Fixed)(inborder * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);\r
- for(c = 0; c < 256; c++) if(iscubeprint(c))\r {
-\r
- FT_Glyph p, p2;\r
- FT_BitmapGlyph b, b2;\r
- struct fontchar *dst = &chars[numchars];\r
- dst->code = c;\r
- dst->uni = cube2uni(c);\r
- if(FT_Load_Char(f, dst->uni, FT_LOAD_DEFAULT))\r
- fatal("cube2font: failed loading character %s", encodeutf8(dst->uni));\r
- FT_Get_Glyph(f->glyph, &p);\r
- p2 = p;\r
- if(outborder > 0) FT_Glyph_StrokeBorder(&p, s, 0, 0);\r
- if(inborder > 0) FT_Glyph_StrokeBorder(&p2, s2, 1, 0);\r
- FT_Glyph_To_Bitmap(&p, FT_RENDER_MODE_NORMAL, 0, 1);\r
- if(inborder > 0 || outborder > 0) FT_Glyph_To_Bitmap(&p2, FT_RENDER_MODE_NORMAL, 0, 1);\r
- else p2 = p;\r
- b = (FT_BitmapGlyph)p;\r
- b2 = (FT_BitmapGlyph)p2;\r
- dst->tex = -1;\r
- dst->x = INT_MIN;\r
- dst->y = INT_MIN;\r
- dst->offx = imin(b->left, b2->left);\r
- dst->offy = imax(b->top, b2->top);\r
- dst->offset = offset;\r
- dst->advance = offset + ((p->advance.x+0xFFFF)>>16) + advance;\r
- dst->w = imax(b->left + b->bitmap.width, b2->left + b2->bitmap.width) - dst->offx;\r
- dst->h = dst->offy - imin(b->top - b->bitmap.rows, b2->top - b2->bitmap.rows);\r
- dst->alpha = b;\r
- dst->color = b2;\r
- order[numchars++] = dst;\r
- }\r
- qsort(order, numchars, sizeof(order[0]), sortchars);\r
- for(i = 0; i < numchars;)\r {
-\r
- struct fontchar *dst;\r
- int j, k, trial0, prevscore, dstscore, fitscore;\r
- for(trial0 = trial, prevscore = -1; (trial -= 2) >= trial0-512;)\r {
-\r
- int g, fw = rw, fh = rh, fy = ry, curscore = 0, reused = 0;\r
- for(j = i; j < numchars; j++)\r {
-\r
- dst = order[j];\r
- if(dst->tex >= 0 || dst->tex <= trial) continue;\r
- g = groupchar(dst->uni);\r
- dstscore = scorechar(dst, pad, tw, th, fw, fh, fy);\r
- for(k = j; k < numchars; k++)\r {
-\r
- struct fontchar *fit = order[k];\r
- if(fit->tex >= 0 || fit->tex <= trial) continue;\r
- if(fit->tex >= trial0 && groupchar(fit->uni) != g) break;\r
- fitscore = scorechar(fit, pad, tw, th, fw, fh, fy);\r
- if(fitscore < dstscore || (fitscore == dstscore && fit->h > dst->h))\r {
-\r
- dst = fit;\r
- dstscore = fitscore;\r
- }\r
- }\r
- if(fw + dst->w > tw)\r {
-\r
- fy += fh + pad;\r
- fw = fh = 0;\r
- }\r
- if(fy + dst->h > th)\r {
-\r
- fy = fw = fh = 0;\r
- if(curscore > 0) break;\r
- }\r
- if(dst->tex >= trial+1 && dst->tex <= trial+2) { dst->tex = trial; reused++; }\r
- else dst->tex = trial;\r
- fw += dst->w + pad;\r
- fh = imax(fh, dst->h);\r
- if(dst != order[j]) --j;\r
- curscore++;\r
- }\r
- if(reused < prevscore || curscore <= prevscore) break;\r
- prevscore = curscore;\r
- }\r
- for(; i < numchars; i++)\r {
-\r
- dst = order[i];\r
- if(dst->tex >= 0) continue;\r
- dstscore = scorechar(dst, pad, tw, th, rw, rh, ry);\r
- for(j = i; j < numchars; j++)\r {
-\r
- struct fontchar *fit = order[j];\r
- if(fit->tex < trial || fit->tex > trial+2) continue;\r
- fitscore = scorechar(fit, pad, tw, th, rw, rh, ry);\r
- if(fitscore < dstscore || (fitscore == dstscore && fit->h > dst->h))\r {
-\r
- dst = fit;\r
- dstscore = fitscore;\r
- }\r
- }\r
- if(dst->tex < trial || dst->tex > trial+2) break;\r
- if(rw + dst->w > tw)\r {
-\r
- ry += rh + pad;\r
- rw = rh = 0;\r
- }\r
- if(ry + dst->h > th)\r {
-\r
- ry = rw = rh = 0;\r
- numtex++;\r
- }\r
- dst->tex = numtex;\r
- dst->x = rw;\r
- dst->y = ry;\r
- rw += dst->w + pad;\r
- rh = imax(rh, dst->h);\r
- y1 = imin(y1, dst->offy - dst->h);\r
- y2 = imax(y2, dst->offy);\r
- x1 = imin(x1, dst->offx);\r
- x2 = imax(x2, dst->offx + dst->w);\r
- w2 = imax(w2, dst->w);\r
- h2 = imax(h2, dst->h);\r
- if(dst != order[i]) --i;\r
- }\r
- }\r
- if(rh > 0) numtex++;\r
- if(sh <= 0) sh = y2 - y1;\r
- if(sw <= 0) sw = sh/3;\r
- writetexs(argv[2], chars, numchars, numtex, tw, th);\r
- writecfg(argv[2], chars, numchars, x1, y1, x2, y2, sw, sh, argc, argv);\r
- for(i = 0; i < numchars; i++) {\r
- if(chars[i].alpha != chars[i].color) FT_Done_Glyph((FT_Glyph)chars[i].alpha);\r
- FT_Done_Glyph((FT_Glyph)chars[i].color);\r
- }\r
- FT_Stroker_Done(s);\r
- FT_Stroker_Done(s2);\r
- FT_Done_FreeType(l);\r
- printf("cube2font: (%d, %d) .. (%d, %d) = (%d, %d) / (%d, %d), %d texs\n", x1, y1, x2, y2, x2 - x1, y2 - y1, w2, h2, numtex);\r
- return EXIT_SUCCESS;\r
-}\r
-\r
enum {
EF_NOVIS = 1<<0,
- EF_NOSHADOW = 1<<1,
EF_NOCOLLIDE = 1<<2,
EF_ANIM = 1<<3,
EF_OCTA = 1<<4,
#define ANIM_FULLBRIGHT (1<<24)
#define ANIM_REUSE (1<<25)
#define ANIM_NORENDER (1<<26)
-#define ANIM_RAGDOLL (1<<27)
#define ANIM_SETSPEED (1<<28)
#define ANIM_NOPITCH (1<<29)
#define ANIM_GHOST (1<<30)
#define MAXANIMPARTS 3
struct occludequery;
-struct ragdolldata;
struct dynent : physent { // animated characters, or characters that can receive input {
bool k_left, k_right, k_up, k_down; // see input code
entitylight light;
animinterpinfo animinterp[MAXANIMPARTS];
- ragdolldata *ragdoll;
occludequery *query;
int lastrendered;
uchar occluded;
- dynent() : ragdoll(NULL), query(NULL), lastrendered(0), occluded(0) {
+ dynent() : query(NULL), lastrendered(0), occluded(0) {
reset();
}
- ~dynent() {
-#ifndef STANDALONE
- extern void cleanragdoll(dynent *d);
- if(ragdoll) cleanragdoll(this);
-#endif
- }
+ ~dynent() { }
void stopmoving() {
k_left = k_right = k_up = k_down = jumping = false;
move = strafe = 0;
if(offset >= MAXQUADS) return;
count = MAXQUADS - offset;
}
- glDrawRangeElements_(GL_TRIANGLES, offset*4, (offset + count)*4-1, count*6, GL_UNSIGNED_SHORT, (ushort *)0 + offset*6);
+ //~glDrawRangeElements_(GL_TRIANGLES, offset*4, (offset + count)*4-1, count*6, GL_UNSIGNED_SHORT, (ushort*)0+offset*6);
+ glDrawRangeElements_(GL_TRIANGLES, offset*4, (offset + count)*4-1, count*6, GL_UNSIGNED_SHORT, (const void *)((unsigned long int) (offset*6))); // Fuck you...
+ //~glDrawRangeElements_(GL_TRIANGLES, offset*4, (offset + count)*4-1, count*6, GL_UNSIGNED_SHORT, (const void *)(offset*6));
}
void defattrib(int type, int size, int format) {
if(type == ATTRIB_VERTEX) {
else glBufferSubData_(GL_ARRAY_BUFFER, vbooffset, attribbuf.length(), attribbuf.getbuf());
}
else glUnmapBuffer_(GL_ARRAY_BUFFER);
- buf = (uchar *)0 + vbooffset;
+ buf = (uchar*)((unsigned long int)vbooffset); /// Fucking piece of shit...
+ //~buf = (const void*)vbooffset;
if(vertexsize == lastvertexsize && buf >= lastbuf) {
start = int(buf - lastbuf)/vertexsize;
if(primtype == GL_QUADS && (start%4 || start + attribbuf.length()/vertexsize >= 4*MAXQUADS))
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_SHADOW = 1<<4, MDL_DYNSHADOW = 1<<5, MDL_LIGHT = 1<<6, MDL_DYNLIGHT = 1<<7, MDL_FULLBRIGHT = 1<<8, MDL_NORENDER = 1<<9, MDL_LIGHT_FAST = 1<<10, MDL_HUD = 1<<11, MDL_GHOST = 1<<12 };
+enum { MDL_CULL_VFC = 1<<0, MDL_CULL_DIST = 1<<1, MDL_CULL_OCCLUDED = 1<<2, MDL_CULL_QUERY = 1<<3, MDL_LIGHT = 1<<6, MDL_DYNLIGHT = 1<<7, MDL_FULLBRIGHT = 1<<8, MDL_NORENDER = 1<<9, MDL_LIGHT_FAST = 1<<10, MDL_HUD = 1<<11, MDL_GHOST = 1<<12 };
struct model;
struct modelattach {
extern void startmodelbatches();
extern void endmodelbatches();
extern void rendermodel(entitylight *light, const char *mdl, int anim, const vec &o, float yaw = 0, float pitch = 0, int cull = MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED | MDL_LIGHT, dynent *d = NULL, modelattach *a = NULL, int basetime = 0, int basetime2 = 0, float trans = 1);
-extern void abovemodel(vec &o, const char *mdl);
-extern void rendershadow(dynent *d);
-extern void renderclient(dynent *d, const char *mdlname, modelattach *attachments, int hold, int attack, int attackdelay, int lastaction, int lastpain, float fade = 1, bool ragdoll = false);
+extern void renderclient(dynent *d, const char *mdlname, modelattach *attachments, int hold, int attack, int attackdelay, int lastaction, int lastpain, float fade = 1);
extern void interpolateorientation(dynent *d, float &interpyaw, float &interppitch);
extern void setbbfrommodel(dynent *d, const char *mdl);
extern const char *mapmodelname(int i);
extern void preloadmodel(const char *name);
extern void flushpreloadedmodels(bool msg = true);
-// ragdoll
-
-extern void moveragdoll(dynent *d);
-extern void cleanragdoll(dynent *d);
-
// server
#define MAXCLIENTS 128 // DO NOT set this any higher
#define MAXTRANS 5000 // max amount of data to swallow in 1 go
#define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(void *ec = (ht).chains[i]; ec;) { k &e = (ht).enumkey(ec); t &f = (ht).enumdata(ec); ec = (ht).enumnext(ec); b; }
#define enumerate(ht,t,e,b) loopi((ht).size) for(void *ec = (ht).chains[i]; ec;) { t &e = (ht).enumdata(ec); ec = (ht).enumnext(ec); b; }
-struct unionfind {
- struct ufval {
- int rank, next;
- ufval() : rank(0), next(-1) {}
- };
- vector<ufval> ufvals;
- int find(int k) {
- if(k>=ufvals.length()) return k;
- while(ufvals[k].next>=0) k = ufvals[k].next;
- return k;
- }
- int compressfind(int k) {
- if(ufvals[k].next<0) return k;
- return ufvals[k].next = compressfind(ufvals[k].next);
- }
- void unite (int x, int y) {
- while(ufvals.length() <= max(x, y)) ufvals.add();
- x = compressfind(x);
- y = compressfind(y);
- if(x==y) return;
- ufval &xval = ufvals[x], &yval = ufvals[y];
- if(xval.rank < yval.rank) xval.next = y;
- else {
- yval.next = x;
- if(xval.rank==yval.rank) yval.rank++;
- }
- }
-};
-
template <class T, int SIZE> struct queue {
int head, tail, len;
T data[SIZE];