Index: engine/decal.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/decal.cpp,v
retrieving revision 1.38
diff -r1.38 decal.cpp
470c470
<                 bool solid = cu[i].ext && isclipped(cu[i].ext->material) && cu[i].ext->material!=MAT_CLIP;
---
>                 bool solid = cu[i].ext && isclipped(cu[i].ext->material&MATF_VOLUME);
477c477
<                 bool solid = cu[i].ext && isclipped(cu[i].ext->material) && cu[i].ext->material!=MAT_CLIP;
---
>                 bool solid = cu[i].ext && isclipped(cu[i].ext->material&MATF_VOLUME);
Index: engine/engine.h
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/engine.h,v
retrieving revision 1.286
diff -r1.286 engine.h
221c221
< extern bool visibleface(cube &c, int orient, int x, int y, int z, int size, uchar mat = MAT_AIR, uchar nmat = MAT_AIR);
---
> extern bool visibleface(cube &c, int orient, int x, int y, int z, int size, uchar mat = MAT_AIR, uchar nmat = MAT_AIR, uchar matmask = MATF_VOLUME);
332c332
< extern int visiblematerial(cube &c, int orient, int x, int y, int z, int size);
---
> extern int visiblematerial(cube &c, int orient, int x, int y, int z, int size, uchar matmask = MATF_VOLUME);
Index: engine/material.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/material.cpp,v
retrieving revision 1.45
diff -r1.45 material.cpp
150c150
< int visiblematerial(cube &c, int orient, int x, int y, int z, int size)
---
> int visiblematerial(cube &c, int orient, int x, int y, int z, int size, uchar matmask)
152c152,153
<     if(c.ext) switch(c.ext->material)
---
>     uchar mat = c.ext->material&matmask;
>     if(c.ext) switch(mat)
159c160
<         if(visibleface(c, orient, x, y, z, size, c.ext->material))
---
>         if(visibleface(c, orient, x, y, z, size, mat, MAT_AIR, matmask))
164c165
<         if(visibleface(c, orient, x, y, z, size, MAT_GLASS))
---
>         if(visibleface(c, orient, x, y, z, size, MAT_GLASS, MAT_AIR, matmask))
169c170
<         if(visibleface(c, orient, x, y, z, size, c.ext->material))
---
>         if(visibleface(c, orient, x, y, z, size, mat, MAT_AIR, matmask))
180,181c181,183
<         int vis = visiblematerial(c, i, cx, cy, cz, size);
<         if(vis != MATSURF_NOT_VISIBLE)
---
>         static uchar matmasks[3] = { MATF_VOLUME, MATF_CLIP, MAT_DEATH };
>         int matmask = 0, vis = MATSURF_NOT_VISIBLE;
>         loopj(sizeof(matmasks)/sizeof(matmasks[0]))
183,195c185,203
<             materialsurface m;
<             m.material = (vis == MATSURF_EDIT_ONLY ? c.ext->material+MAT_EDIT : c.ext->material);
<             m.orient = i;
<             m.o = ivec(cx, cy, cz);
<             m.csize = m.rsize = size;
<             if(dimcoord(i)) m.o[dimension(i)] += size;
<             matsurfs.add(m);
<         }
<         if(isclipped(c.ext->material) && c.ext->material != MAT_CLIP) 
<         {
<             clipmask |= 1<<i;
<             if(vis == MATSURF_VISIBLE) vismask |= 1<<i;
<             else vismask &= ~(1<<i);
---
>             matmask = matmasks[j];
>             vis = visiblematerial(c, i, cx, cy, cz, size, matmask);
>             if(vis != MATSURF_NOT_VISIBLE) 
>             {
>                 materialsurface m;
>                 m.material = (vis == MATSURF_EDIT_ONLY ? MAT_EDIT : 0) | (c.ext->material&matmask);
>                 m.orient = i;
>                 m.o = ivec(cx, cy, cz);
>                 m.csize = m.rsize = size;
>                 if(dimcoord(i)) m.o[dimension(i)] += size;
>                 matsurfs.add(m);
>                 if(isclipped(c.ext->material&matmask))
>                 {
>                     clipmask |= 1<<i;
>                     if(vis == MATSURF_VISIBLE) vismask |= 1<<i;
>                     else vismask &= ~(1<<i);
>                 }
>                 break;
>             }
367c375
<                     if(c.ext && isliquid(c.ext->material)) { m.ends |= 1; break; }
---
>                     if(c.ext && isliquid(c.ext->material&MATF_VOLUME)) { m.ends |= 1; break; }
392c400
<             hasmat |= 1<<m.material;
---
>             if(m.material&MATF_VOLUME) hasmat |= 1<<m.material;
476c484
<                 if(m.material>=MAT_EDIT) continue;
---
>                 if(m.material&MAT_EDIT) continue;
490,500d497
<     static uchar cols[MAT_EDIT][3] =
<     {
<         { 0, 0, 0 },   // MAT_AIR - no edit volume,
<         { 0, 0, 85 },  // MAT_WATER - blue,
<         { 85, 0, 0 },  // MAT_CLIP - red,
<         { 0, 85, 85 }, // MAT_GLASS - cyan,
<         { 0, 85, 0 },  // MAT_NOCLIP - green
<         { 85, 40, 0 }, // MAT_LAVA - orange
<         { 85, 85, 0 }, // MAT_AICLIP - yellow
<         { 40, 40, 40 } // MAT_DEATH - black
<     };
506c503
<         int curmat = m.material >= MAT_EDIT ? m.material-MAT_EDIT : m.material;
---
>         int curmat = m.material&~MAT_EDIT;
510c507,516
<             glColor3ubv(cols[curmat]);
---
>             switch(curmat)
>             {
>                 case MAT_WATER:  glColor3ub( 0,  0, 85); break; // blue
>                 case MAT_CLIP:   glColor3ub(85,  0,  0); break; // red
>                 case MAT_GLASS:  glColor3ub( 0, 85, 85); break; // cyan
>                 case MAT_NOCLIP: glColor3ub( 0, 85,  0); break; // green
>                 case MAT_LAVA:   glColor3ub(85, 40,  0); break; // orange
>                 case MAT_AICLIP: glColor3ub(85, 85,  0); break; // yellow
>                 case MAT_DEATH:  glColor3ub(40, 40, 40); break; // black
>             }
578c584
<         int curmat = !editmode || !showmat || m.material>=MAT_EDIT ? m.material : m.material+MAT_EDIT;
---
>         int curmat = !editmode || !showmat || m.material&MAT_EDIT ? m.material : m.material|MAT_EDIT;
774c780
<                     if(lastmat<MAT_EDIT)
---
>                     if(lastmat < MAT_EDIT)
785c791
<                     static uchar blendcols[MAT_EDIT][3] =
---
>                     switch(curmat&~MAT_EDIT)
787,796c793,800
<                         { 0,   0,   0   }, // MAT_AIR - no edit volume,
<                         { 255, 128, 0   }, // MAT_WATER - blue,
<                         { 0,   255, 255 }, // MAT_CLIP - red,
<                         { 255, 0,   0   }, // MAT_GLASS - cyan,
<                         { 255, 0,   255 }, // MAT_NOCLIP - green
<                         { 0, 128,   255 }, // MAT_LAVA - orange
<                         { 0,   0,   255 }, // MAT_AICLIP - yellow
<                         { 192, 192, 192 }, // MAT_DEATH - black
<                     };
<                     glColor3ubv(blendcols[curmat >= MAT_EDIT ? curmat-MAT_EDIT : curmat]);
---
>                         case MAT_WATER:  glColor3ub(255, 128,   0); break; // blue
>                         case MAT_CLIP:   glColor3ub(  0, 255, 255); break; // red
>                         case MAT_GLASS:  glColor3ub(255,   0,   0); break; // cyan
>                         case MAT_NOCLIP: glColor3ub(255,   0, 255); break; // green
>                         case MAT_LAVA:   glColor3ub(  0, 128, 255); break; // orange
>                         case MAT_AICLIP: glColor3ub(  0,   0, 255); break; // yellow
>                         case MAT_DEATH:  glColor3ub(192, 192, 192); break; // black
>                     }   
Index: engine/octa.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/octa.cpp,v
retrieving revision 1.78
diff -r1.78 octa.cpp
721c721
< void genfacevecs(cube &c, int orient, const ivec &pos, int size, bool solid, facevec *fvecs)
---
> static inline void genfacevecs(cube &c, int orient, const ivec &pos, int size, bool solid, facevec *fvecs)
745c745
< int clipfacevecy(const facevec &o, const facevec &dir, int cx, int cy, int size, facevec &r)
---
> static inline int clipfacevecy(const facevec &o, const facevec &dir, int cx, int cy, int size, facevec &r)
761c761
< int clipfacevecx(const facevec &o, const facevec &dir, int cx, int cy, int size, facevec &r)
---
> static inline int clipfacevecx(const facevec &o, const facevec &dir, int cx, int cy, int size, facevec &r)
777c777
< int clipfacevec(const facevec &o, const facevec &dir, int cx, int cy, int size, facevec *rvecs)
---
> static inline int clipfacevec(const facevec &o, const facevec &dir, int cx, int cy, int size, facevec *rvecs)
799c799
< bool insideface(const facevec *p, int nump, const facevec *o)
---
> static inline bool insideface(const facevec *p, int nump, const facevec *o)
814c814
< int clipfacevecs(const facevec *o, int cx, int cy, int size, facevec *rvecs)
---
> static inline int clipfacevecs(const facevec *o, int cx, int cy, int size, facevec *rvecs)
840c840
< bool occludesface(cube &c, int orient, const ivec &o, int size, const ivec &vo, int vsize, uchar vmat, uchar nmat, const facevec *vf)
---
> static inline bool occludesface(cube &c, int orient, const ivec &o, int size, const ivec &vo, int vsize, uchar vmat, uchar nmat, uchar matmask, const facevec *vf)
845c845
<          if(nmat != MAT_AIR && c.ext && c.ext->material == nmat)
---
>          if(nmat != MAT_AIR && c.ext && (c.ext->material&matmask) == nmat)
851c851
<          if(vmat != MAT_AIR && c.ext && (c.ext->material == vmat || (c.ext->material == MAT_GLASS && isliquid(vmat)))) return true;
---
>          if(vmat != MAT_AIR && c.ext && ((c.ext->material&matmask) == vmat || (isliquid(vmat) && isclipped(c.ext->material&MATF_VOLUME)))) return true;
866c866
<         if(!occludesface(c.children[i], orient, ivec(i, o.x, o.y, o.z, size), size, vo, vsize, vmat, nmat, vf)) return false;
---
>         if(!occludesface(c.children[i], orient, ivec(i, o.x, o.y, o.z, size), size, vo, vsize, vmat, nmat, matmask, vf)) return false;
872c872
< bool visibleface(cube &c, int orient, int x, int y, int z, int size, uchar mat, uchar nmat)
---
> bool visibleface(cube &c, int orient, int x, int y, int z, int size, uchar mat, uchar nmat, uchar matmask)
890c890
<         if(nmat != MAT_AIR && o.ext && o.ext->material == nmat) return true;
---
>         if(nmat != MAT_AIR && o.ext && (o.ext->material&matmask) == nmat) return true;
892c892
<         if(mat != MAT_AIR && o.ext && (o.ext->material == mat || (o.ext->material == MAT_GLASS && isliquid(mat)))) return false;
---
>         if(mat != MAT_AIR && o.ext && ((o.ext->material&matmask) == mat || (isliquid(mat) && (o.ext->material&MATF_VOLUME) == MAT_GLASS))) return false;
910c910
<     return !occludesface(o, opposite(orient), lu, lusize, vo, size, mat, nmat, cf);
---
>     return !occludesface(o, opposite(orient), lu, lusize, vo, size, mat, nmat, matmask, cf);
Index: engine/octaedit.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/octaedit.cpp,v
retrieving revision 1.250
diff -r1.250 octaedit.cpp
1588c1588
< void setmat(cube &c, uchar mat)
---
> void setmat(cube &c, uchar mat, uchar matmask)
1591,1592c1591,1597
<         loopi(8) setmat(c.children[i], mat);
<     else if(mat!=MAT_AIR) ext(c).material = mat;
---
>         loopi(8) setmat(c.children[i], mat, matmask);
>     else if(mat!=MAT_AIR) 
>     {
>         cubeext &e = ext(c);
>         e.material &= matmask;
>         e.material |= mat;
>     }
1599c1604,1608
<     loopselxyz(setmat(c, matid));
---
> 
>     uchar matmask = matid&MATF_VOLUME ? 0 : (matid&MATF_CLIP ? ~MATF_CLIP : 0xFF);
>     if(isclipped(matid&MATF_VOLUME)) matid |= MAT_CLIP;
>     if(isdeadly(matid&MATF_VOLUME)) matid |= MAT_DEATH;
>     loopselxyz(setmat(c, matid, matmask));
Index: engine/octarender.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/octarender.cpp,v
retrieving revision 1.341
diff -r1.341 octarender.cpp
888c888
<         if(visibleface(c, i, x, y, z, size, MAT_AIR, MAT_NOCLIP)) ext(c).visible |= 1<<i;
---
>         if(visibleface(c, i, x, y, z, size, MAT_AIR, MAT_NOCLIP, MATF_CLIP)) ext(c).visible |= 1<<i;
Index: engine/physics.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/physics.cpp,v
retrieving revision 1.370
diff -r1.370 physics.cpp
287c287
<            (((mode&RAY_CLIPMAT) && c.ext && isclipped(c.ext->material) && c.ext->material != MAT_CLIP) ||
---
>            (((mode&RAY_CLIPMAT) && c.ext && isclipped(c.ext->material&MATF_VOLUME)) ||
707c707
<             if(c[i].ext) switch(c[i].ext->material)
---
>             if(c[i].ext) switch(c[i].ext->material&MATF_CLIP)
712d711
<                 case MAT_GLASS: solid = true; break;
738c737
<     if(c->ext) switch(c->ext->material)
---
>     if(c->ext) switch(c->ext->material&MATF_CLIP)
743d741
<         case MAT_GLASS: solid = true; break;
1249c1247
<     bool water = isliquid(material);
---
>     bool water = isliquid(material&MATF_VOLUME);
1318c1316
<             water = isliquid(material);
---
>             water = isliquid(material&MATF_VOLUME);
1320c1318
<         if(!pl->inwater && water) cl->physicstrigger(pl, local, 0, -1, material);
---
>         if(!pl->inwater && water) cl->physicstrigger(pl, local, 0, -1, material&MATF_VOLUME);
1322c1320
<         pl->inwater = water ? material : MAT_AIR;
---
>         pl->inwater = water ? material&MATF_VOLUME : MAT_AIR;
1324c1322
<         if(pl->state==CS_ALIVE && (pl->o.z < 0 || material==MAT_LAVA || material==MAT_DEATH)) cl->suicide(pl);
---
>         if(pl->state==CS_ALIVE && (pl->o.z < 0 || material&MAT_DEATH)) cl->suicide(pl);
Index: engine/pvs.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/pvs.cpp,v
retrieving revision 1.23
diff -r1.23 pvs.cpp
859c859
<         if(h.children ? !isallclip(h.children) : (!isentirelysolid(h) && (!h.ext || !isclipped(h.ext->material))))
---
>         if(h.children ? !isallclip(h.children) : (!isentirelysolid(h) && (!h.ext || (h.ext->material&MATF_CLIP)!=MAT_CLIP)))
882c882
<         else if(isentirelysolid(h) || (h.ext && isclipped(h.ext->material))) continue;
---
>         else if(isentirelysolid(h) || (h.ext && (h.ext->material&MATF_CLIP)==MAT_CLIP)) continue;
907c907
<         else if(isentirelysolid(h) || (h.ext && isclipped(h.ext->material))) continue;
---
>         else if(isentirelysolid(h) || (h.ext && (h.ext->material&MATF_CLIP)==MAT_CLIP)) continue;
Index: engine/rendergl.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/rendergl.cpp,v
retrieving revision 1.450
diff -r1.450 rendergl.cpp
779c779
<         if(!c.ext || c.ext->material != fogmat)
---
>         if(!c.ext || (c.ext->material&MATF_VOLUME) != fogmat)
781c781
<             abovemat = c.ext && isliquid(c.ext->material) ? c.ext->material : MAT_AIR;
---
>             abovemat = c.ext && isliquid(c.ext->material&MATF_VOLUME) ? c.ext->material&MATF_VOLUME : MAT_AIR;
1056c1056
<     int fogmat = lookupmaterial(o);
---
>     int fogmat = lookupmaterial(o)&MATF_VOLUME;
1148c1148
<     int fogmat = lookupmaterial(camera1->o), abovemat = MAT_AIR;
---
>     int fogmat = lookupmaterial(camera1->o)&MATF_VOLUME, abovemat = MAT_AIR;
Index: engine/texture.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/texture.cpp,v
retrieving revision 1.121
diff -r1.121 texture.cpp
528c528
< Slot materialslots[MAT_EDIT];
---
> Slot materialslots[MATF_VOLUME+1];
542c542
<     loopi(MAT_EDIT) materialslots[i].reset();
---
>     loopi(MATF_VOLUME+1) materialslots[i].reset();
785c785
<     Slot &s = slot<0 && slot>-MAT_EDIT ? materialslots[-slot] : (slots.inrange(slot) ? slots[slot] : (slots.empty() ? dummyslot : slots[0]));
---
>     Slot &s = slot<0 && slot>=-MATF_VOLUME ? materialslots[-slot] : (slots.inrange(slot) ? slots[slot] : (slots.empty() ? dummyslot : slots[0]));
794c794
<                 if(hasCM && (renderpath!=R_FIXEDFUNCTION || (slot<0 && slot>-MAT_EDIT))) t.t = cubemapload(t.name);
---
>                 if(hasCM && (renderpath!=R_FIXEDFUNCTION || (slot<0 && slot>=-MATF_VOLUME))) t.t = cubemapload(t.name);
798c798
<                 texcombine(s, i, t, slot<0 && slot>-MAT_EDIT);
---
>                 texcombine(s, i, t, slot<0 && slot>=-MATF_VOLUME);
806c806
< Shader *lookupshader(int slot) { return slot<0 && slot>-MAT_EDIT ? materialslots[-slot].shader : (slots.inrange(slot) ? slots[slot].shader : defaultshader); }
---
> Shader *lookupshader(int slot) { return slot<0 && slot>=-MATF_VOLUME ? materialslots[-slot].shader : (slots.inrange(slot) ? slots[slot].shader : defaultshader); }
1199c1199
<     loopi(MAT_EDIT) materialslots[i].cleanup();
---
>     loopi(MATF_VOLUME+1) materialslots[i].cleanup();
Index: engine/world.h
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/world.h,v
retrieving revision 1.65
diff -r1.65 world.h
11c11
< #define MAPVERSION 26           // bump if map format changes, see worldio.cpp
---
> #define MAPVERSION 27           // bump if map format changes, see worldio.cpp
46c46,47
< #define isclipped(mat) ((mat) >= MAT_CLIP && (mat) < MAT_NOCLIP)
---
> #define isclipped(mat) ((mat)==MAT_GLASS)
> #define isdeadly(mat) ((mat)==MAT_LAVA)
Index: engine/worldio.cpp
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/engine/worldio.cpp,v
retrieving revision 1.123
diff -r1.123 worldio.cpp
197c197,206
<         if(mask & 0x80) ext(c).material = gzgetc(f);
---
>         if(mask & 0x80) 
>         {
>             int mat = gzgetc(f);
>             if(hdr.version < 27)
>             {
>                 static uchar matconv[] = { MAT_AIR, MAT_WATER, MAT_CLIP, MAT_GLASS|MAT_CLIP, MAT_NOCLIP, MAT_LAVA|MAT_DEATH, MAT_AICLIP, MAT_DEATH };
>                 mat = size_t(mat) < sizeof(matconv)/sizeof(matconv[0]) ? matconv[mat] : MAT_AIR;
>             }
>             ext(c).material = mat;
>         }
Index: shared/iengine.h
===================================================================
RCS file: /cvsroot/sauerbraten/sauerbraten/src/shared/iengine.h,v
retrieving revision 1.260
diff -r1.260 iengine.h
3c3
< enum                            // cube empty-space materials
---
> enum
5,13c5,26
<     MAT_AIR = 0,                // the default, fill the empty space with air
<     MAT_WATER,                  // fill with water, showing waves at the surface
<     MAT_CLIP,                   // collisions always treat cube as solid
<     MAT_GLASS,                  // behaves like clip but is blended blueish
<     MAT_NOCLIP,                 // collisions always treat cube as empty
<     MAT_LAVA,                   // fill with lava
<     MAT_AICLIP,                 // clip monsters only
<     MAT_DEATH,                  // force player suicide
<     MAT_EDIT                    // basis for the edit volumes of the above materials
---
>     MATF_VOLUME_SHIFT = 0,
>     MATF_CLIP_SHIFT   = 3,
>     MATF_FLAG_SHIFT   = 5,
> 
>     MATF_VOLUME = 7 << MATF_VOLUME_SHIFT,
>     MATF_CLIP   = 3 << MATF_CLIP_SHIFT,
>     MATF_FLAGS  = 7 << MATF_FLAG_SHIFT
> };
> 
> enum // cube empty-space materials
> {
>     MAT_AIR   = 0,                      // the default, fill the empty space with air
>     MAT_WATER = 1 << MATF_VOLUME_SHIFT, // fill with water, showing waves at the surface
>     MAT_LAVA  = 2 << MATF_VOLUME_SHIFT, // fill with lava
>     MAT_GLASS = 3 << MATF_VOLUME_SHIFT, // behaves like clip but is blended blueish
> 
>     MAT_NOCLIP = 1 << MATF_CLIP_SHIFT,  // collisions always treat cube as empty
>     MAT_CLIP   = 2 << MATF_CLIP_SHIFT,  // collisions always treat cube as solid
>     MAT_AICLIP = 3 << MATF_CLIP_SHIFT,  // clip monsters only
> 
>     MAT_DEATH  = 1 << MATF_FLAG_SHIFT,  // force player suicide
>     MAT_EDIT   = 4 << MATF_FLAG_SHIFT   // edit-only surfaces

