guiradio "^f3high quality" shadowmapsize 10 [blurshadowmap 2]
] [
guibar
- guicheckbox "^f2blob shadows" blobs
]
]
if $glare [
autosortservers 1
autoupdateservers 1
bilinear 1
-blobdyntris 4096
-blobfadehigh 8
-blobfadelow 8
-blobheight 32
-blobintensity 60
-blobmargin 1
-blobs 1
-blobstattris 4096
blood 1
blurdepthfx 0
blurdepthfxsigma 50
invmouse 0
jumpspawn 1
lightthreads 0
-maxbarreldebris 10
maxcon 200
maxdebris 25
maxdecaldistance 512
motionblurmillis 5
motionblurscale 0.5
mouseaccel 0.0
-movieaccel 1
-moviefps 24
-movieh 240
-movieminquality 0.0
-moviesound 1
-moviesync 0
-moview 320
mumble 1
musicvol 60
muzzleflash 1
box barrel platform elevator
flag
]
-complete coop "packages/base" "ogz"
+complete coop "packages/maps" "ogz"
varcomplete demo "demodir" "dmo"
listcomplete editmat [air water clip glass noclip lava gameclip death alpha]
-complete effic "packages/base" "ogz"
-complete efficteam "packages/base" "ogz"
+complete effic "packages/maps" "ogz"
+complete efficteam "packages/maps" "ogz"
listcomplete entfind [
light mapmodel playerstart envmap particles sound
shells bullets rockets riflerounds grenades cartridges
box barrel platform elevator
flag
]
-complete ffa "packages/base" "ogz"
-complete insta "packages/base" "ogz"
-complete instateam "packages/base" "ogz"
-complete map "packages/base" "ogz"
+complete ffa "packages/maps" "ogz"
+complete insta "packages/maps" "ogz"
+complete instateam "packages/maps" "ogz"
+complete map "packages/maps" "ogz"
listcomplete newent [
light mapmodel playerstart envmap particles sound
shells bullets rockets riflerounds grenades cartridges
box barrel platform elevator
flag
]
-complete teamplay "packages/base" "ogz"
+complete teamplay "packages/maps" "ogz"
+++ /dev/null
-#!/bin/sh
-# SAUER_DATA should refer to the directory in which Sauerbraten data files are placed.
-#SAUER_DATA=~/sauerbraten
-#SAUER_DATA=/usr/local/sauerbraten
-SAUER_DATA=.
-
-# SAUER_BIN should refer to the directory in which Sauerbraten executable files are placed.
-SAUER_BIN=${SAUER_DATA}/bin_unix
-
-# SAUER_OPTIONS contains any command line options you would like to start Sauerbraten with.
-#SAUER_OPTIONS="-f"
-SAUER_OPTIONS="-q${HOME}/.uberbraten"
-
-# SYSTEM_NAME should be set to the name of your operating system.
-#SYSTEM_NAME=Linux
-SYSTEM_NAME=`uname -s`
-
-# MACHINE_NAME should be set to the name of your processor.
-#MACHINE_NAME=i686
-MACHINE_NAME=`uname -m`
-
-case ${SYSTEM_NAME} in
-Linux)
- SYSTEM_NAME=linux_
- ;;
-*)
- SYSTEM_NAME=unknown_
- ;;
-esac
-
-case ${MACHINE_NAME} in
-i486|i586|i686)
- MACHINE_NAME=
- ;;
-x86_64|amd64)
- MACHINE_NAME=64_
- ;;
-*)
- if [ ${SYSTEM_NAME} != native_ ]
- then
- SYSTEM_NAME=native_
- fi
- MACHINE_NAME=
- ;;
-esac
-
-if [ -x ${SAUER_BIN}/native_client ]
-then
- SYSTEM_NAME=native_
- MACHINE_NAME=
-fi
-
-if [ -x ${SAUER_BIN}/${SYSTEM_NAME}${MACHINE_NAME}client ]
-then
- cd ${SAUER_DATA}
- exec ${SAUER_BIN}/${SYSTEM_NAME}${MACHINE_NAME}client ${SAUER_OPTIONS} "$@"
-else
- echo "Your platform does not have a pre-compiled Sauerbraten client."
- echo "Please follow the following steps to build a native client:"
- echo "1) Ensure you have the SDL2, SDL2-image, SDL2-mixer, and OpenGL libraries installed."
- echo "2) Change directory to src/ and type \"make install\"."
- echo "3) If the build succeeds, return to this directory and run this script again."
- exit 1
-fi
-
-CXXFLAGS= -O3 -fomit-frame-pointer -ffast-math
+CXXFLAGS= -O3 -g -fomit-frame-pointer -ffast-math
override CXXFLAGS+= -Wall -fsigned-char -fno-exceptions -fno-rtti -Wno-unused-parameter
PLATFORM= $(shell uname -s | tr '[:lower:]' '[:upper:]')
engine/3dgui.o \
engine/bih.o \
engine/blend.o \
- engine/blob.o \
engine/client.o \
engine/command.o \
engine/console.o \
engine/main.o \
engine/material.o \
engine/menus.o \
- engine/movie.o \
engine/normal.o \
engine/octa.o \
engine/octaedit.o \
engine/blend.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
engine/blend.o: engine/lightmap.h engine/bih.h engine/texture.h
engine/blend.o: engine/model.h
-engine/blob.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
-engine/blob.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
-engine/blob.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/blob.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/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/model.h
-engine/movie.o: engine/engine.h shared/cube.h shared/tools.h shared/geom.h
-engine/movie.o: shared/ents.h shared/command.h shared/glexts.h shared/glemu.h
-engine/movie.o: shared/iengine.h shared/igame.h engine/world.h engine/octa.h
-engine/movie.o: engine/lightmap.h engine/bih.h engine/texture.h
-engine/movie.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/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/vertmodel.h engine/skelmodel.h
-engine/rendermodel.o: engine/md3.h engine/md5.h engine/iqm.h engine/smd.h
+engine/rendermodel.o: engine/md3.h 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
extern void cleardecals();
extern void renderdecals(bool mainpass = false);
-// blob
-
-enum
-{
- BLOB_STATIC = 0,
- BLOB_DYNAMIC
-};
-
-extern int showblobs;
-
-extern void initblobs(int type = -1);
-extern void resetblobs();
-extern void renderblob(int type, const vec &o, float radius, float fade = 1);
-extern void flushblobs();
-
// rendersky
extern int explicitsky;
extern double skyarea;
extern void saveblendmap(stream *f);
extern uchar shouldsaveblendmap();
-// recorder
-
-namespace recorder
-{
- extern void stop();
- extern void capture(bool overlay = true);
- extern void cleanup();
-}
-
#endif
#endif
void cleanup()
{
- recorder::stop();
cleanupserver();
SDL_ShowCursor(SDL_TRUE);
SDL_SetRelativeMouseMode(SDL_FALSE);
extern void cleanupva();
extern void cleanupparticles();
extern void cleanupdecals();
- extern void cleanupblobs();
extern void cleanupsky();
extern void cleanupmodels();
extern void cleanupprefabs();
extern void cleanreflections();
extern void cleanupglare();
extern void cleanupdepthfx();
- recorder::cleanup();
cleanupva();
cleanupparticles();
cleanupdecals();
- cleanupblobs();
cleanupsky();
cleanupmodels();
cleanupprefabs();
void swapbuffers(bool overlay)
{
- recorder::capture(overlay);
gle::disable();
SDL_GL_SwapWindow(screen);
}
-enum { MDL_MD3, MDL_MD5, MDL_IQM, MDL_SMD, NUMMODELTYPES };
+enum { MDL_MD3, MDL_MD5, MDL_IQM, NUMMODELTYPES };
struct model
{
bool boxoutline = false;
-void boxs(int orient, vec o, const vec &s, float size)
+void boxs(int orient, vec o, const vec &s, float size)
{
int d = dimension(orient), dc = dimcoord(orient);
float f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0;
{
ivec o(i, cor, size);
if(c[i].children) countselchild(c[i].children, o, size/2);
- else
+ else
{
selchildcount++;
if(c[i].material != MAT_AIR && selchildmat != MAT_AIR)
selchildcount = 0;
selchildmat = -1;
countselchild(worldroot, ivec(0, 0, 0), worldsize/2);
- if(mag>=1 && selchildcount==1)
+ if(mag>=1 && selchildcount==1)
{
selchildmat = c->material;
if(mag>1) selchildcount = -mag;
setupmaterials(oldlen);
invalidatepostfx();
updatevabbs();
- resetblobs();
}
void changed(const block3 &sel, bool commit = true)
}
struct vslotmap
-{
+{
int index;
VSlot *vslot;
}
else if(!isempty(c))
{
- int vis;
+ int vis;
loopi(6) if((vis = visibletris(c, i, co, size)))
{
ivec v[4];
void mpflip(selinfo &sel, bool local)
{
- if(local)
- {
+ if(local)
+ {
game::edittrigger(sel, EDIT_FLIP);
makeundo();
}
COMMAND(rotate, "i");
enum { EDITMATF_EMPTY = 0x10000, EDITMATF_NOTEMPTY = 0x20000, EDITMATF_SOLID = 0x30000, EDITMATF_NOTSOLID = 0x40000 };
-static const struct { const char *name; int filter; } editmatfilters[] =
-{
+static const struct { const char *name; int filter; } editmatfilters[] =
+{
{ "empty", EDITMATF_EMPTY },
{ "notempty", EDITMATF_NOTEMPTY },
{ "solid", EDITMATF_SOLID },
if(filter < 0) filter = findmaterial(filtername);
if(filter < 0)
{
- conoutf(CON_ERROR, "unknown material \"%s\"", filtername);
- return;
+ conoutf(CON_ERROR, "unknown material \"%s\"", filtername);
+ return;
}
}
int id = -1;
vboinfo &vbi = *exists;
if(vbi.uses <= 0) return;
vbi.uses--;
- if(!vbi.uses)
+ if(!vbi.uses)
{
glDeleteBuffers_(1, &vbo);
vbos.remove(vbo);
glBufferData_(target, len, buf, GL_STATIC_DRAW);
glBindBuffer_(target, 0);
- vboinfo &vbi = vbos[vbo];
+ vboinfo &vbi = vbos[vbo];
vbi.uses = numva;
-
+
if(printvbo) conoutf(CON_DEBUG, "vbo %d: type %d, size %d, %d uses", vbo, type, len, numva);
loopi(numva)
vtxarray *va = vas[i];
switch(type)
{
- case VBO_VBUF:
- va->vbuf = vbo;
+ case VBO_VBUF:
+ va->vbuf = vbo;
break;
- case VBO_EBUF:
- va->ebuf = vbo;
+ case VBO_EBUF:
+ va->ebuf = vbo;
break;
- case VBO_SKYBUF:
- va->skybuf = vbo;
+ case VBO_SKYBUF:
+ va->skybuf = vbo;
break;
}
}
int len = numelems*elemsize;
uchar *buf = data.reserve(len).buf;
data.advance(len);
- return buf;
+ return buf;
}
-
+
struct verthash
{
static const int SIZE = 1<<13;
verthash() { clearverts(); }
- void clearverts()
- {
+ void clearverts()
+ {
memset(table, -1, sizeof(table));
- chain.setsize(0);
+ chain.setsize(0);
verts.setsize(0);
}
vtx.norm = norm;
vtx.tangent = tangent;
return addvert(vtx);
- }
+ }
};
enum
void remapunlit(vector<sortkey> &remap)
{
- uint lastlmid[8] = { LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT },
+ uint lastlmid[8] = { LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT },
firstlmid[8] = { LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT };
int firstlit[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
loopv(texs)
{
sortkey &k = texs[i];
- if(k.lmid>=LMID_RESERVED)
+ if(k.lmid>=LMID_RESERVED)
{
LightMapTexture &lmtex = lightmaptexs[k.lmid];
int type = lmtex.type&LM_TYPE;
if(firstlmid[type]==LMID_AMBIENT) continue;
indices[k].unlit = firstlmid[type];
}
- }
+ }
loopj(2)
{
int offset = 4 + 2*j;
if(firstlmid[type]==LMID_AMBIENT) continue;
indices[k].unlit = firstlmid[type];
}
- }
+ }
loopv(remap)
{
sortkey &k = remap[i];
sortval &t = indices[k];
- if(t.unlit<=0) continue;
+ if(t.unlit<=0) continue;
LightMapTexture &lm = lightmaptexs[t.unlit];
- svec2 lmtc(short(ceil((lm.unlitx + 0.5f) * SHRT_MAX/lm.w)),
+ svec2 lmtc(short(ceil((lm.unlitx + 0.5f) * SHRT_MAX/lm.w)),
short(ceil((lm.unlity + 0.5f) * SHRT_MAX/lm.h)));
loopl(2) loopvj(t.tris[l])
{
if(dst) loopl(2) loopvj(t.tris[l]) dst->tris[l].add(t.tris[l][j]);
}
}
-
+
void optimize()
{
vector<sortkey> remap;
if(x.alpha > y.alpha) return false;
if(x.layer < y.layer) return true;
if(x.layer > y.layer) return false;
- if(x.tex == y.tex)
+ if(x.tex == y.tex)
{
if(x.lmid < y.lmid) return true;
if(x.lmid > y.lmid) return false;
va->voffset = 0;
if(va->verts)
{
- if(vbosize[VBO_VBUF] + verts.length() > maxvbosize ||
+ if(vbosize[VBO_VBUF] + verts.length() > maxvbosize ||
vbosize[VBO_EBUF] + worldtris > USHRT_MAX ||
- vbosize[VBO_SKYBUF] + skytris > USHRT_MAX)
+ vbosize[VBO_SKYBUF] + skytris > USHRT_MAX)
flushvbo();
va->voffset = vbosize[VBO_VBUF];
va->matbuf = NULL;
va->matsurfs = matsurfs.length();
- if(va->matsurfs)
+ if(va->matsurfs)
{
va->matbuf = new materialsurface[matsurfs.length()];
memcpy(va->matbuf, matsurfs.getbuf(), matsurfs.length()*sizeof(materialsurface));
ushort *skydata = (ushort *)addvbo(va, VBO_SKYBUF, va->sky+va->explicitsky, sizeof(ushort));
memcpy(skydata, skyindices.getbuf(), va->sky*sizeof(ushort));
memcpy(skydata+va->sky, explicitskyindices.getbuf(), va->explicitsky*sizeof(ushort));
- if(va->voffset) loopi(va->sky+va->explicitsky) skydata[i] += va->voffset;
+ if(va->voffset) loopi(va->sky+va->explicitsky) skydata[i] += va->voffset;
}
va->eslist = NULL;
e.layer = k.layer;
e.envmap = k.envmap;
ushort *startbuf = curbuf;
- loopl(2)
+ loopl(2)
{
e.minvert[l] = USHRT_MAX;
e.maxvert[l] = 0;
}
if(k.layer==LAYER_BLEND) { va->texs--; va->tris -= e.length[1]/3; va->blends++; va->blendtris += e.length[1]/3; }
else if(k.alpha==ALPHA_BACK) { va->texs--; va->tris -= e.length[1]/3; va->alphaback++; va->alphabacktris += e.length[1]/3; }
- else if(k.alpha==ALPHA_FRONT) { va->texs--; va->tris -= e.length[1]/3; va->alphafront++; va->alphafronttris += e.length[1]/3; }
+ else if(k.alpha==ALPHA_FRONT) { va->texs--; va->tris -= e.length[1]/3; va->alphafront++; va->alphafronttris += e.length[1]/3; }
Slot &slot = *lookupvslot(k.tex, false).slot;
loopvj(slot.sts) va->texmask |= 1<<slot.sts[j].type;
bool emptyva()
{
return verts.empty() && matsurfs.empty() && skyindices.empty() && explicitskyindices.empty() && grasstris.empty() && mapmodels.empty();
- }
+ }
} vc;
int recalcprogress = 0;
{
case 1: i1 = i2 = mid; cedge = edge+i+1; break;
case 2: if(i1 != mid || i0 == left) { i0 = i1; i1 = right; } i2 = right; if(i+1 == numverts-2) cedge = edge+i+2; break;
- case 3: if(i0 == start) { i0 = i1; i1 = left; } i2 = left; // fall-through
+ case 3: if(i0 == start) { i0 = i1; i1 = left; } i2 = left; // fall-through
default: if(!i) cedge = edge; break;
}
if(i1 != i2)
offset2 = (int(v2.pos[axis]*8) - origin) / d[axis];
vec o = vec(v1.pos).sub(vec(d).mul(offset1/8.0f));
float doffset = 1.0f / (offset2 - offset1);
-
+
if(i1 < 0) for(;;)
{
tjoint &t = tjoints[ctj];
if(t.next < 0 || tjoints[t.next].edge != cedge) break;
ctj = t.next;
- }
+ }
while(ctj >= 0)
{
tjoint &t = tjoints[ctj];
grasstri &g = vc.grasstris.add();
int i1, i2, i3, i4;
if(numv <= 3 && face%2) { i1 = face+1; i2 = face+2; i3 = i4 = 0; }
- else { i1 = 0; i2 = face+1; i3 = face+2; i4 = numv > 3 ? face+3 : i3; }
+ else { i1 = 0; i2 = face+1; i3 = face+2; i4 = numv > 3 ? face+3 : i3; }
g.v[0] = verts[i1].pos;
g.v[1] = verts[i2].pos;
g.v[2] = verts[i3].pos;
tc2v = verts[i2].lm.y - verts[i1].lm.y,
tc3u = verts[i3].lm.x - verts[i1].lm.x,
tc3v = verts[i3].lm.y - verts[i1].lm.y;
-
+
g.tcu = vec4(0, 0, 0, tc1u - (bx.z*tc2u + by.z*tc3u));
g.tcu[px] = bx.x*tc2u + by.x*tc3u;
g.tcu[py] = -(bx.y*tc2u + by.y*tc3u);
toff = -(r.swapxy ? vslot.offset.x : vslot.offset.y)/ys;
static const int si[] = { 1, 0, 0 }, ti[] = { 2, 2, 1 };
int sdim = si[dim], tdim = ti[dim];
- sgen = vec4(0, 0, 0, soff);
+ sgen = vec4(0, 0, 0, soff);
tgen = vec4(0, 0, 0, toff);
if(r.swapxy)
{
}
ushort encodenormal(const vec &n)
-{
+{
if(n.iszero()) return 0;
int yaw = int(-atan2(n.x, n.y)/RAD), pitch = int(asin(n.z)/RAD);
return ushort(clamp(pitch + 90, 0, 180)*360 + (yaw < 0 ? yaw%360 + 360 : yaw%360) + 1);
vertex &v = verts[k];
v.pos = pos[k];
v.tc = vec2(sgen.dot(v.pos), tgen.dot(v.pos));
- if(lmtex)
- {
- v.lm = svec2(short(ceil((lm->offsetx + vinfo[k].u*(float(LM_PACKW)/float(USHRT_MAX+1)) + 0.5f) * float(SHRT_MAX)/lmtex->w)),
+ if(lmtex)
+ {
+ v.lm = svec2(short(ceil((lm->offsetx + vinfo[k].u*(float(LM_PACKW)/float(USHRT_MAX+1)) + 0.5f) * float(SHRT_MAX)/lmtex->w)),
short(ceil((lm->offsety + vinfo[k].v*(float(LM_PACKH)/float(USHRT_MAX+1)) + 0.5f) * float(SHRT_MAX)/lmtex->h)));
}
else v.lm = svec2(0, 0);
sortkey key(texture, lmid, !vslot.scroll.iszero() ? dim : 3, layer == LAYER_BLEND ? LAYER_BLEND : LAYER_TOP, envmap, alpha ? (vslot.alphaback ? ALPHA_BACK : (vslot.alphafront ? ALPHA_FRONT : NO_ALPHA)) : NO_ALPHA);
addtris(key, orient, verts, index, numverts, convex, shadowmask, tj);
- if(grassy)
+ if(grassy)
{
for(int i = 0; i < numverts-2; i += 2)
{
if(index[0]!=index[i+1] && index[i+1]!=index[i+2] && index[i+2]!=index[0]) faces |= 1;
if(i+3 < numverts && index[0]!=index[i+2] && index[i+2]!=index[i+3] && index[i+3]!=index[0]) faces |= 2;
if(grassy > 1 && faces==3) addgrasstri(i, verts, 4, texture, lmid);
- else
+ else
{
if(faces&1) addgrasstri(i, verts, 3, texture, lmid);
if(faces&2) addgrasstri(i+1, verts, 3, texture, lmid);
return g.slope.x^(g.slope.y<<2)^(g.slope.z<<4)^g.origin.x^g.origin.y^g.origin.z;
}
-static bool htcmp(const edgegroup &x, const edgegroup &y)
-{
+static bool htcmp(const edgegroup &x, const edgegroup &y)
+{
return x.slope==y.slope && x.origin==y.origin;
}
int vismask = ~c.merged & 0x3F;
if(!(c.visible&0x80)) vismask &= c.visible;
if(!vismask) return;
-
+
int tj = filltjoints && c.ext ? c.ext->tjoints : -1, vis;
loopi(6) if(vismask&(1<<i) && (vis = visibletris(c, i, co, size)))
{
if(!c.ext)
addcubeverts(vslot, i, size, pos, convex, c.texture[i], LMID_AMBIENT, NULL, numverts, hastj, envmap, grassy, (c.material&MAT_ALPHA)!=0);
else
- {
+ {
const surfaceinfo &surf = c.ext->surfaces[i];
if(!surf.numverts || surf.numverts&LAYER_TOP)
addcubeverts(vslot, i, size, pos, convex, c.texture[i], surf.lmid[0], verts, numverts, hastj, envmap, grassy, (c.material&MAT_ALPHA)!=0, LAYER_TOP|(surf.numverts&LAYER_BLEND));
}
void minskyface(cube &cu, int orient, const ivec &co, int size, facebounds &orig)
-{
+{
facebounds mincf;
mincf.u1 = orig.u2;
mincf.u2 = orig.u1;
orig.u2 = min(mincf.u2, orig.u2);
orig.v1 = max(mincf.v1, orig.v1);
orig.v2 = min(mincf.v2, orig.v2);
-}
+}
void genskyfaces(cube &c, const ivec &o, int size)
{
{
int orient = faces[i], dim = dimension(orient);
facebounds m;
- m.u1 = (o[C[dim]]&0xFFF)<<3;
+ m.u1 = (o[C[dim]]&0xFFF)<<3;
m.u2 = m.u1 + (size<<3);
m.v1 = (o[R[dim]]&0xFFF)<<3;
m.v2 = m.v1 + (size<<3);
loopi(6)
{
int dim = dimension(i), c = C[dim], r = R[dim];
- vector<facebounds> &sf = vc.skyfaces[i];
+ vector<facebounds> &sf = vc.skyfaces[i];
if(sf.empty()) continue;
vc.skymask |= 0x3F&~(1<<opposite(i));
sf.setsize(mergefaces(i, sf.getbuf(), sf.length()));
}
}
}
-
+
////////// Vertex Arrays //////////////
int allocva = 0;
}
struct mergedface
-{
+{
uchar orient, lmid, numverts;
ushort mat, tex, envmap;
vertinfo *verts;
int tjoints;
-};
+};
#define MAXMERGELEVEL 12
static int vahasmerges = 0, vamergemax = 0;
{
if(!c.ext || isempty(c)) return -1;
int tj = c.ext->tjoints, maxlevel = -1;
- loopi(6) if(c.merged&(1<<i))
+ loopi(6) if(c.merged&(1<<i))
{
surfaceinfo &surf = c.ext->surfaces[i];
int numverts = surf.numverts&MAXFACEVERTS;
- if(!numverts)
+ if(!numverts)
{
if(minlevel < 0) vahasmerges |= MERGE_PART;
continue;
mf.envmap = EMID_NONE;
mf.lmid = surf.lmid[0];
mf.numverts = surf.numverts;
- mf.verts = c.ext->verts() + surf.verts;
+ mf.verts = c.ext->verts() + surf.verts;
mf.tjoints = -1;
int level = calcmergedsize(i, co, size, mf.verts, mf.numverts&MAXFACEVERTS);
if(level > minlevel)
mf.envmap = vslot.slot->texmask&(1<<TEX_ENVMAP) ? EMID_CUSTOM : closestenvmap(i, co, size);
ushort envmap2 = layer && layer->slot->shader->type&SHADER_ENVMAP ? (layer->slot->texmask&(1<<TEX_ENVMAP) ? EMID_CUSTOM : closestenvmap(i, co, size)) : EMID_NONE;
- if(surf.numverts&LAYER_TOP) vamerges[level].add(mf);
+ if(surf.numverts&LAYER_TOP) vamerges[level].add(mf);
if(surf.numverts&LAYER_BOTTOM)
{
mf.tex = vslot.layer;
int maxlevel = -1;
loopi(8)
{
- ivec o(i, co, size/2);
+ ivec o(i, co, size/2);
int level = findmergedfaces(c.children[i], o, size/2, csi-1, minlevel);
maxlevel = max(maxlevel, level);
}
void rendercube(cube &c, const ivec &co, int size, int csi, int &maxlevel) // creates vertices and indices ready to be put into a va
{
//if(size<=16) return;
- if(c.ext && c.ext->va)
+ if(c.ext && c.ext->va)
{
maxlevel = max(maxlevel, c.ext->va->mergelevel);
return; // don't re-render
ivec o(i, co, size/2);
int level = -1;
rendercube(c.children[i], o, size/2, csi-1, level);
- if(level >= csi)
+ if(level >= csi)
c.escaped |= 1<<i;
- maxlevel = max(maxlevel, level);
+ maxlevel = max(maxlevel, level);
}
--neighbourdepth;
}
return;
}
-
+
genskyfaces(c, co, size);
- if(!isempty(c))
+ if(!isempty(c))
{
gencubeverts(c, co, size, csi);
if(c.merged) maxlevel = max(maxlevel, genmergedfaces(c, co, size));
loopi(6)
{
int facemask = classifyface(c, i, co, size);
- if(facemask&1)
+ if(facemask&1)
{
vismask |= 1<<i;
if(c.merged&(1<<i))
{
if(c.ext && c.ext->surfaces[i].numverts&MAXFACEVERTS) numvis++;
}
- else
+ else
{
numvis++;
if(c.texture[i] != DEFAULT_SKY && !(c.ext && c.ext->surfaces[i].numverts&MAXFACEVERTS)) checkmask |= 1<<i;
}
- }
+ }
if(facemask&2 && collideface(c, i)) collidemask |= 1<<i;
}
c.visible = collidemask | (vismask ? (vismask != collidemask ? (checkmask ? 0x80|0x40 : 0x80) : 0x40) : 0);
ivec o(i, co, size);
vamergemax = 0;
vahasmerges = 0;
- if(c[i].ext && c[i].ext->va)
+ if(c[i].ext && c[i].ext->va)
{
varoot.add(c[i].ext->va);
if(c[i].ext->va->hasmerges&MERGE_ORIGIN) findmergedfaces(c[i], o, size, csi, csi);
else
{
if(c[i].children) count += updateva(c[i].children, o, size/2, csi-1);
- else
+ else
{
if(!isempty(c[i])) count += setcubevisibility(c[i], o, size);
count += hasskyfaces(c[i], o, size);
}
int tcount = count + (csi <= MAXMERGELEVEL ? vamerges[csi].length() : 0);
- if(tcount > vafacemax || (tcount >= vafacemin && size >= vacubesize) || size == min(0x1000, worldsize/2))
+ if(tcount > vafacemax || (tcount >= vafacemin && size >= vacubesize) || size == min(0x1000, worldsize/2))
{
loadprogress = clamp(recalcprogress/float(allocnodes), 0.0f, 1.0f);
setva(c[i], o, size, csi);
tj.next = cur;
if(prev < 0) e.c->ext->tjoints = tjoints.length()-1;
- else tjoints[prev].next = tjoints.length()-1;
+ else tjoints[prev].next = tjoints.length()-1;
}
void findtjoints(int cur, const edgegroup &g)
setupmaterials();
invalidatepostfx();
updatevabbs(true);
- resetblobs();
lightents();
- if(load)
+ if(load)
{
seedparticles();
drawtextures();
#include "md3.h"
#include "md5.h"
#include "iqm.h"
-#include "smd.h"
MODELTYPE(MDL_MD3, md3);
MODELTYPE(MDL_MD5, md5);
MODELTYPE(MDL_IQM, iqm);
-MODELTYPE(MDL_SMD, smd);
#define checkmdl if(!loadingmodel) { conoutf(CON_ERROR, "not loading a model"); return; }
{
modelbatch &b = *batches[i];
if(b.batched.empty()) continue;
- if(b.flags&(MDL_SHADOW|MDL_DYNSHADOW))
- {
- vec center, bbradius;
- b.m->boundbox(center, bbradius);
- loopvj(b.batched)
- {
- batchedmodel &bm = b.batched[j];
- if(bm.flags&(MDL_SHADOW|MDL_DYNSHADOW))
- renderblob(bm.flags&MDL_DYNSHADOW ? BLOB_DYNAMIC : BLOB_STATIC, bm.d && bm.d->ragdoll ? bm.d->ragdoll->center : bm.pos, bm.d ? bm.d->radius : max(bbradius.x, bbradius.y), bm.transparent);
- }
- flushblobs();
- }
+
bool rendered = false;
occludequery *query = NULL;
if(b.flags&MDL_GHOST)
if(!m) return;
vec center(0, 0, 0), bbradius(0, 0, 0);
float radius = 0;
- bool shadow = !shadowmap && !glaring && (flags&(MDL_SHADOW|MDL_DYNSHADOW)) && showblobs;
+ bool shadow = !shadowmap && !glaring && (flags&(MDL_SHADOW|MDL_DYNSHADOW));//~ && showblobs;
if(flags&(MDL_CULL_VFC|MDL_CULL_DIST|MDL_CULL_OCCLUDED|MDL_CULL_QUERY|MDL_SHADOW|MDL_DYNSHADOW))
{
return;
}
- if(shadow && !reflecting && refracting<=0)
- {
- renderblob(flags&MDL_DYNSHADOW ? BLOB_DYNAMIC : BLOB_STATIC, d && d->ragdoll ? center : o, d ? d->radius : max(bbradius.x, bbradius.y), trans);
- flushblobs();
- if((flags&MDL_CULL_VFC) && refracting<0 && center.z-radius>=reflectz) return;
- }
-
m->startrender();
if(shadowmapping)
+++ /dev/null
-struct smd;
-
-struct smdbone
-{
- string name;
- int parent;
- smdbone() : parent(-1) { name[0] = '\0'; }
-};
-
-struct smd : skelloader<smd>
-{
- smd(const char *name) : skelloader(name) {}
-
- static const char *formatname() { return "smd"; }
- int type() const { return MDL_SMD; }
-
- struct smdmesh : skelmesh
- {
- };
-
- struct smdmeshgroup : skelmeshgroup
- {
- smdmeshgroup()
- {
- }
-
- bool skipcomment(char *&curbuf)
- {
- while(*curbuf && isspace(*curbuf)) curbuf++;
- switch(*curbuf)
- {
- case '#':
- case ';':
- case '\r':
- case '\n':
- case '\0':
- return true;
- case '/':
- if(curbuf[1] == '/') return true;
- break;
- }
- return false;
- }
-
- void skipsection(stream *f, char *buf, size_t bufsize)
- {
- while(f->getline(buf, bufsize))
- {
- char *curbuf = buf;
- if(skipcomment(curbuf)) continue;
- if(!strncmp(curbuf, "end", 3)) break;
- }
- }
-
- void readname(char *&curbuf, char *name, size_t namesize)
- {
- char *curname = name;
- while(*curbuf && isspace(*curbuf)) curbuf++;
- bool allowspace = false;
- if(*curbuf == '"') { curbuf++; allowspace = true; }
- while(*curbuf)
- {
- char c = *curbuf++;
- if(c == '"') break;
- if(isspace(c) && !allowspace) break;
- if(curname < &name[namesize-1]) *curname++ = c;
- }
- *curname = '\0';
- }
-
- void readnodes(stream *f, char *buf, size_t bufsize, vector<smdbone> &bones)
- {
- while(f->getline(buf, bufsize))
- {
- char *curbuf = buf;
- if(skipcomment(curbuf)) continue;
- if(!strncmp(curbuf, "end", 3)) break;
- int id = strtol(curbuf, &curbuf, 10);
- string name;
- readname(curbuf, name, sizeof(name));
- int parent = strtol(curbuf, &curbuf, 10);
- if(id < 0 || id > 255 || parent > 255 || !name[0]) continue;
- while(!bones.inrange(id)) bones.add();
- smdbone &bone = bones[id];
- copystring(bone.name, name);
- bone.parent = parent;
- }
- }
-
- void readmaterial(char *&curbuf, char *name, size_t namesize)
- {
- char *curname = name;
- while(*curbuf && isspace(*curbuf)) curbuf++;
- while(*curbuf)
- {
- char c = *curbuf++;
- if(isspace(c)) break;
- if(c == '.')
- {
- while(*curbuf && !isspace(*curbuf)) curbuf++;
- break;
- }
- if(curname < &name[namesize-1]) *curname++ = c;
- }
- *curname = '\0';
- }
-
- struct smdmeshdata
- {
- smdmesh *mesh;
- vector<vert> verts;
- vector<tri> tris;
-
- void finalize()
- {
- if(verts.empty() || tris.empty()) return;
- vert *mverts = new vert[mesh->numverts + verts.length()];
- if(mesh->numverts)
- {
- memcpy(mverts, mesh->verts, mesh->numverts*sizeof(vert));
- delete[] mesh->verts;
- }
- memcpy(&mverts[mesh->numverts], verts.getbuf(), verts.length()*sizeof(vert));
- mesh->numverts += verts.length();
- mesh->verts = mverts;
- tri *mtris = new tri[mesh->numtris + tris.length()];
- if(mesh->numtris)
- {
- memcpy(mtris, mesh->tris, mesh->numtris*sizeof(tri));
- delete[] mesh->tris;
- }
- memcpy(&mtris[mesh->numtris], tris.getbuf(), tris.length()*sizeof(tri));
- mesh->numtris += tris.length();
- mesh->tris = mtris;
- }
- };
-
- struct smdvertkey : vert
- {
- smdmeshdata *mesh;
-
- smdvertkey(smdmeshdata *mesh) : mesh(mesh) {}
- };
-
- void readtriangles(stream *f, char *buf, size_t bufsize)
- {
- smdmeshdata *curmesh = NULL;
- hashtable<const char *, smdmeshdata> materials(1<<6);
- hashset<int> verts(1<<12);
- while(f->getline(buf, bufsize))
- {
- char *curbuf = buf;
- if(skipcomment(curbuf)) continue;
- if(!strncmp(curbuf, "end", 3)) break;
- string material;
- readmaterial(curbuf, material, sizeof(material));
- if(!curmesh || strcmp(curmesh->mesh->name, material))
- {
- curmesh = materials.access(material);
- if(!curmesh)
- {
- smdmesh *m = new smdmesh;
- m->group = this;
- m->name = newstring(material);
- meshes.add(m);
- curmesh = &materials[m->name];
- curmesh->mesh = m;
- }
- }
- tri curtri;
- loopi(3)
- {
- char *curbuf;
- do
- {
- if(!f->getline(buf, bufsize)) goto endsection;
- curbuf = buf;
- } while(skipcomment(curbuf));
- smdvertkey key(curmesh);
- int parent = -1, numlinks = 0, len = 0;
- if(sscanf(curbuf, " %d %f %f %f %f %f %f %f %f %d%n", &parent, &key.pos.x, &key.pos.y, &key.pos.z, &key.norm.x, &key.norm.y, &key.norm.z, &key.tc.x, &key.tc.y, &numlinks, &len) < 9) goto endsection;
- curbuf += len;
- key.pos.y = -key.pos.y;
- key.norm.y = -key.norm.y;
- key.tc.y = 1 - key.tc.y;
- blendcombo c;
- int sorted = 0;
- float pweight = 0, tweight = 0;
- for(; numlinks > 0; numlinks--)
- {
- int bone = -1, len = 0;
- float weight = 0;
- if(sscanf(curbuf, " %d %f%n", &bone, &weight, &len) < 2) break;
- curbuf += len;
- tweight += weight;
- if(bone == parent) pweight += weight;
- else sorted = c.addweight(sorted, weight, bone);
- }
- if(tweight < 1) pweight += 1 - tweight;
- if(pweight > 0) sorted = c.addweight(sorted, pweight, parent);
- c.finalize(sorted);
- key.blend = curmesh->mesh->addblendcombo(c);
- int index = verts.access(key, curmesh->verts.length());
- if(index == curmesh->verts.length()) curmesh->verts.add(key);
- curtri.vert[2-i] = index;
- }
- curmesh->tris.add(curtri);
- }
- endsection:
- enumerate(materials, smdmeshdata, data, data.finalize());
- }
-
- void readskeleton(stream *f, char *buf, size_t bufsize)
- {
- int frame = -1;
- while(f->getline(buf, bufsize))
- {
- char *curbuf = buf;
- if(skipcomment(curbuf)) continue;
- if(sscanf(curbuf, " time %d", &frame) == 1) continue;
- else if(!strncmp(curbuf, "end", 3)) break;
- else if(frame != 0) continue;
- int bone;
- vec pos, rot;
- if(sscanf(curbuf, " %d %f %f %f %f %f %f", &bone, &pos.x, &pos.y, &pos.z, &rot.x, &rot.y, &rot.z) != 7)
- continue;
- if(bone < 0 || bone >= skel->numbones)
- continue;
- rot.x = -rot.x;
- rot.z = -rot.z;
- float cx = cosf(rot.x/2), sx = sinf(rot.x/2),
- cy = cosf(rot.y/2), sy = sinf(rot.y/2),
- cz = cosf(rot.z/2), sz = sinf(rot.z/2);
- pos.y = -pos.y;
- dualquat dq(quat(sx*cy*cz - cx*sy*sz,
- cx*sy*cz + sx*cy*sz,
- cx*cy*sz - sx*sy*cz,
- cx*cy*cz + sx*sy*sz),
- pos);
- boneinfo &b = skel->bones[bone];
- if(b.parent < 0) b.base = dq;
- else b.base.mul(skel->bones[b.parent].base, dq);
- (b.invbase = b.base).invert();
- }
- }
-
- bool loadmesh(const char *filename)
- {
- stream *f = openfile(filename, "r");
- if(!f) return false;
-
- char buf[512];
- int version = -1;
- while(f->getline(buf, sizeof(buf)))
- {
- char *curbuf = buf;
- if(skipcomment(curbuf)) continue;
- if(sscanf(curbuf, " version %d", &version) == 1)
- {
- if(version != 1) { delete f; return false; }
- }
- else if(!strncmp(curbuf, "nodes", 5))
- {
- if(skel->numbones > 0) { skipsection(f, buf, sizeof(buf)); continue; }
- vector<smdbone> bones;
- readnodes(f, buf, sizeof(buf), bones);
- if(bones.empty()) continue;
- skel->numbones = bones.length();
- skel->bones = new boneinfo[skel->numbones];
- loopv(bones)
- {
- boneinfo &dst = skel->bones[i];
- smdbone &src = bones[i];
- dst.name = newstring(src.name);
- dst.parent = src.parent;
- }
- skel->linkchildren();
- }
- else if(!strncmp(curbuf, "triangles", 9))
- readtriangles(f, buf, sizeof(buf));
- else if(!strncmp(curbuf, "skeleton", 8))
- {
- if(skel->shared > 1) skipsection(f, buf, sizeof(buf));
- else readskeleton(f, buf, sizeof(buf));
- }
- else if(!strncmp(curbuf, "vertexanimation", 15))
- skipsection(f, buf, sizeof(buf));
- }
-
- sortblendcombos();
-
- delete f;
- return true;
- }
-
- int readframes(stream *f, char *buf, size_t bufsize, vector<dualquat> &animbones)
- {
- int frame = -1, numframes = 0, lastbone = skel->numbones;
- while(f->getline(buf, bufsize))
- {
- char *curbuf = buf;
- if(skipcomment(curbuf)) continue;
- int nextframe = -1;
- if(sscanf(curbuf, " time %d", &nextframe) == 1)
- {
- for(; lastbone < skel->numbones; lastbone++) animbones[frame*skel->numbones + lastbone] = animbones[lastbone];
- if(nextframe >= numframes)
- {
- databuf<dualquat> framebones = animbones.reserve(skel->numbones * (nextframe + 1 - numframes));
- loopi(nextframe - numframes) framebones.put(animbones.getbuf(), skel->numbones);
- animbones.addbuf(framebones);
- animbones.advance(skel->numbones);
- numframes = nextframe + 1;
- }
- frame = nextframe;
- lastbone = 0;
- continue;
- }
- else if(!strncmp(curbuf, "end", 3)) break;
- int bone;
- vec pos, rot;
- if(sscanf(curbuf, " %d %f %f %f %f %f %f", &bone, &pos.x, &pos.y, &pos.z, &rot.x, &rot.y, &rot.z) != 7)
- continue;
- if(bone < 0 || bone >= skel->numbones)
- continue;
- for(; lastbone < bone; lastbone++) animbones[frame*skel->numbones + lastbone] = animbones[lastbone];
- lastbone++;
- float cx = cosf(rot.x/2), sx = sinf(rot.x/2),
- cy = cosf(rot.y/2), sy = sinf(rot.y/2),
- cz = cosf(rot.z/2), sz = sinf(rot.z/2);
- pos.y = -pos.y;
- dualquat dq(quat(-(sx*cy*cz - cx*sy*sz),
- cx*sy*cz + sx*cy*sz,
- -(cx*cy*sz - sx*sy*cz),
- cx*cy*cz + sx*sy*sz),
- pos);
- if(adjustments.inrange(bone)) adjustments[bone].adjust(dq);
- dq.mul(skel->bones[bone].invbase);
- dualquat &dst = animbones[frame*skel->numbones + bone];
- if(skel->bones[bone].parent < 0) dst = dq;
- else dst.mul(skel->bones[skel->bones[bone].parent].base, dq);
- dst.fixantipodal(skel->numframes > 0 ? skel->framebones[bone] : animbones[bone]);
- }
- for(; lastbone < skel->numbones; lastbone++) animbones[frame*skel->numbones + lastbone] = animbones[lastbone];
- return numframes;
- }
-
- skelanimspec *loadanim(const char *filename)
- {
- skelanimspec *sa = skel->findskelanim(filename);
- if(sa || skel->numbones <= 0) return sa;
-
- stream *f = openfile(filename, "r");
- if(!f) return NULL;
-
- char buf[512];
- int version = -1;
- vector<dualquat> animbones;
- while(f->getline(buf, sizeof(buf)))
- {
- char *curbuf = buf;
- if(skipcomment(curbuf)) continue;
- if(sscanf(curbuf, " version %d", &version) == 1)
- {
- if(version != 1) { delete f; return NULL; }
- }
- else if(!strncmp(curbuf, "nodes", 5))
- {
- vector<smdbone> bones;
- readnodes(f, buf, sizeof(buf), bones);
- if(bones.length() != skel->numbones) { delete f; return NULL; }
- }
- else if(!strncmp(curbuf, "triangles", 9))
- skipsection(f, buf, sizeof(buf));
- else if(!strncmp(curbuf, "skeleton", 8))
- readframes(f, buf, sizeof(buf), animbones);
- else if(!strncmp(curbuf, "vertexanimation", 15))
- skipsection(f, buf, sizeof(buf));
- }
- int numframes = animbones.length() / skel->numbones;
- dualquat *framebones = new dualquat[(skel->numframes+numframes)*skel->numbones];
- if(skel->framebones)
- {
- memcpy(framebones, skel->framebones, skel->numframes*skel->numbones*sizeof(dualquat));
- delete[] skel->framebones;
- }
- memcpy(&framebones[skel->numframes*skel->numbones], animbones.getbuf(), numframes*skel->numbones*sizeof(dualquat));
- skel->framebones = framebones;
- sa = &skel->addskelanim(filename);
- sa->frame = skel->numframes;
- sa->range = numframes;
- skel->numframes += numframes;
-
- delete f;
-
- return sa;
- }
-
- bool load(const char *meshfile)
- {
- name = newstring(meshfile);
-
- if(!loadmesh(meshfile)) return false;
-
- return true;
- }
- };
-
- meshgroup *loadmeshes(const char *name, va_list args)
- {
- smdmeshgroup *group = new smdmeshgroup;
- group->shareskeleton(va_arg(args, char *));
- if(!group->load(name)) { delete group; return NULL; }
- return group;
- }
-
- bool loaddefaultparts()
- {
- skelpart &mdl = addpart();
- mdl.pitchscale = mdl.pitchoffset = mdl.pitchmin = mdl.pitchmax = 0;
- adjustments.setsize(0);
- const char *fname = name + strlen(name);
- do --fname; while(fname >= name && *fname!='/' && *fname!='\\');
- fname++;
- defformatstring(meshname, "packages/models/%s/%s.smd", name, fname);
- mdl.meshes = sharemeshes(path(meshname), NULL);
- if(!mdl.meshes) return false;
- mdl.initanimparts();
- mdl.initskins();
- return true;
- }
-};
-
-static inline uint hthash(const smd::smdmeshgroup::smdvertkey &k)
-{
- return hthash(k.pos);
-}
-
-static inline bool htcmp(const smd::smdmeshgroup::smdvertkey &k, int index)
-{
- if(!k.mesh->verts.inrange(index)) return false;
- const smd::vert &v = k.mesh->verts[index];
- return k.pos == v.pos && k.norm == v.norm && k.tc == v.tc && k.blend == v.blend;
-}
-
-skelcommands<smd> smdcommands;
-
{
gamestate &gs = ci->state;
spawnstate(ci);
- sendf(ci->ownernum, 1, "rii7v", N_SPAWNSTATE, ci->clientnum, gs.lifesequence,
+ sendf(ci->ownernum, 1, "rii8v", N_SPAWNSTATE, ci->clientnum, gs.lifesequence,
gs.health, gs.maxhealth,
gs.armour, gs.maxarmour, gs.armourtype,
gs.gunselect, GUN_PISTOL-GUN_SG+1, &gs.ammo[GUN_SG]);
void sendresume(clientinfo *ci)
{
gamestate &gs = ci->state;
- sendf(-1, 1, "ri3i4i6vi", N_RESUME, ci->clientnum, gs.state,
+ sendf(-1, 1, "ri3i5i6vi", N_RESUME, ci->clientnum, gs.state,
gs.frags, gs.flags, gs.deaths, gs.quadmillis,
gs.lifesequence,
gs.health, gs.maxhealth,
--- /dev/null
+#!/bin/sh
+# SAUER_DATA should refer to the directory in which Sauerbraten data files are placed.
+#SAUER_DATA=~/sauerbraten
+#SAUER_DATA=/usr/local/sauerbraten
+SAUER_DATA=.
+
+# SAUER_BIN should refer to the directory in which Sauerbraten executable files are placed.
+SAUER_BIN=${SAUER_DATA}/bin_unix
+
+# SAUER_OPTIONS contains any command line options you would like to start Sauerbraten with.
+#SAUER_OPTIONS="-f"
+SAUER_OPTIONS="-q${HOME}/.uberbraten"
+
+# SYSTEM_NAME should be set to the name of your operating system.
+#SYSTEM_NAME=Linux
+SYSTEM_NAME=`uname -s`
+
+# MACHINE_NAME should be set to the name of your processor.
+#MACHINE_NAME=i686
+MACHINE_NAME=`uname -m`
+
+case ${SYSTEM_NAME} in
+Linux)
+ SYSTEM_NAME=linux_
+ ;;
+*)
+ SYSTEM_NAME=unknown_
+ ;;
+esac
+
+case ${MACHINE_NAME} in
+i486|i586|i686)
+ MACHINE_NAME=
+ ;;
+x86_64|amd64)
+ MACHINE_NAME=64_
+ ;;
+*)
+ if [ ${SYSTEM_NAME} != native_ ]
+ then
+ SYSTEM_NAME=native_
+ fi
+ MACHINE_NAME=
+ ;;
+esac
+
+if [ -x ${SAUER_BIN}/native_client ]
+then
+ SYSTEM_NAME=native_
+ MACHINE_NAME=
+fi
+
+if [ -x ${SAUER_BIN}/${SYSTEM_NAME}${MACHINE_NAME}client ]
+then
+ cd ${SAUER_DATA}
+ exec ${SAUER_BIN}/${SYSTEM_NAME}${MACHINE_NAME}client ${SAUER_OPTIONS} "$@"
+else
+ echo "Your platform does not have a pre-compiled Sauerbraten client."
+ echo "Please follow the following steps to build a native client:"
+ echo "1) Ensure you have the SDL2, SDL2-image, SDL2-mixer, and OpenGL libraries installed."
+ echo "2) Change directory to src/ and type \"make install\"."
+ echo "3) If the build succeeds, return to this directory and run this script again."
+ exit 1
+fi
+