1 #include "engine.h"
2 
3 struct QuadNode
4 {
5     int x, y, size;
6     uint filled;
7     QuadNode *child[4];
8 
QuadNodeQuadNode9     QuadNode(int x, int y, int size) : x(x), y(y), size(size), filled(0) { loopi(4) child[i] = 0; }
10 
clearQuadNode11     void clear()
12     {
13         loopi(4) DELETEP(child[i]);
14     }
15 
~QuadNodeQuadNode16     ~QuadNode()
17     {
18         clear();
19     }
20 
insertQuadNode21     void insert(int mx, int my, int msize)
22     {
23         if(size == msize)
24         {
25             filled = 0xF;
26             return;
27         }
28         int csize = size>>1, i = 0;
29         if(mx >= x+csize) i |= 1;
30         if(my >= y+csize) i |= 2;
31         if(csize == msize)
32         {
33             filled |= (1 << i);
34             return;
35         }
36         if(!child[i]) child[i] = new QuadNode(i&1 ? x+csize : x, i&2 ? y+csize : y, csize);
37         child[i]->insert(mx, my, msize);
38         loopj(4) if(child[j])
39         {
40             if(child[j]->filled == 0xF)
41             {
42                 DELETEP(child[j]);
43                 filled |= (1 << j);
44             }
45         }
46     }
47 
genmatsurfQuadNode48     void genmatsurf(ushort mat, uchar orient, uchar visible, int x, int y, int z, int size, materialsurface *&matbuf)
49     {
50         materialsurface &m = *matbuf++;
51         m.material = mat;
52         m.orient = orient;
53         m.visible = visible;
54         m.csize = size;
55         m.rsize = size;
56         int dim = dimension(orient);
57         m.o[C[dim]] = x;
58         m.o[R[dim]] = y;
59         m.o[dim] = z;
60     }
61 
genmatsurfsQuadNode62     void genmatsurfs(ushort mat, uchar orient, uchar visible, int z, materialsurface *&matbuf)
63     {
64         if(filled == 0xF) genmatsurf(mat, orient, visible, x, y, z, size, matbuf);
65         else if(filled)
66         {
67             int csize = size>>1;
68             loopi(4) if(filled & (1 << i))
69                 genmatsurf(mat, orient, visible, i&1 ? x+csize : x, i&2 ? y+csize : y, z, csize, matbuf);
70         }
71         loopi(4) if(child[i]) child[i]->genmatsurfs(mat, orient, visible, z, matbuf);
72     }
73 };
74 
drawmaterial(const materialsurface & m,float offset)75 static void drawmaterial(const materialsurface &m, float offset)
76 {
77     if(gle::attribbuf.empty())
78     {
79         gle::defvertex();
80         gle::begin(GL_QUADS);
81     }
82     float x = m.o.x, y = m.o.y, z = m.o.z, csize = m.csize, rsize = m.rsize;
83     switch(m.orient)
84     {
85 #define GENFACEORIENT(orient, v0, v1, v2, v3) \
86         case orient: v0 v1 v2 v3 break;
87 #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) \
88             gle::attribf(mx sx, my sy, mz sz);
89         GENFACEVERTS(x, x, y, y, z, z, /**/, + csize, /**/, + rsize, + offset, - offset)
90 #undef GENFACEORIENT
91 #undef GENFACEVERT
92     }
93 }
94 
95 const struct material
96 {
97     const char *name;
98     ushort id;
99 } materials[] =
100 {
101     {"air", MAT_AIR},
102     {"water", MAT_WATER}, {"water1", MAT_WATER}, {"water2", MAT_WATER+1}, {"water3", MAT_WATER+2}, {"water4", MAT_WATER+3},
103     {"glass", MAT_GLASS}, {"glass1", MAT_GLASS}, {"glass2", MAT_GLASS+1}, {"glass3", MAT_GLASS+2}, {"glass4", MAT_GLASS+3},
104     {"lava", MAT_LAVA}, {"lava1", MAT_LAVA}, {"lava2", MAT_LAVA+1}, {"lava3", MAT_LAVA+2}, {"lava4", MAT_LAVA+3},
105     {"clip", MAT_CLIP},
106     {"noclip", MAT_NOCLIP},
107     {"gameclip", MAT_GAMECLIP},
108     {"death", MAT_DEATH},
109     {"nogi", MAT_NOGI},
110     {"alpha", MAT_ALPHA}
111 };
112 
findmaterial(const char * name)113 int findmaterial(const char *name)
114 {
115     loopi(sizeof(materials)/sizeof(material))
116     {
117         if(!strcmp(materials[i].name, name)) return materials[i].id;
118     }
119     return -1;
120 }
121 
findmaterialname(int mat)122 const char *findmaterialname(int mat)
123 {
124     loopi(sizeof(materials)/sizeof(materials[0])) if(materials[i].id == mat) return materials[i].name;
125     return NULL;
126 }
127 
getmaterialdesc(int mat,const char * prefix)128 const char *getmaterialdesc(int mat, const char *prefix)
129 {
130     static const ushort matmasks[] = { MATF_VOLUME|MATF_INDEX, MATF_CLIP, MAT_DEATH, MAT_NOGI, MAT_ALPHA };
131     static string desc;
132     desc[0] = '\0';
133     loopi(sizeof(matmasks)/sizeof(matmasks[0])) if(mat&matmasks[i])
134     {
135         const char *matname = findmaterialname(mat&matmasks[i]);
136         if(matname)
137         {
138             concatstring(desc, desc[0] ? ", " : prefix);
139             concatstring(desc, matname);
140         }
141     }
142     return desc;
143 }
144 
visiblematerial(const cube & c,int orient,const ivec & co,int size,ushort matmask)145 int visiblematerial(const cube &c, int orient, const ivec &co, int size, ushort matmask)
146 {
147     ushort mat = c.material&matmask;
148     switch(mat)
149     {
150     case MAT_AIR:
151          break;
152 
153     case MAT_LAVA:
154     case MAT_WATER:
155         if(visibleface(c, orient, co, size, mat, MAT_AIR, matmask))
156             return (orient != O_BOTTOM ? MATSURF_VISIBLE : MATSURF_EDIT_ONLY);
157         break;
158 
159     case MAT_GLASS:
160         if(visibleface(c, orient, co, size, MAT_GLASS, MAT_AIR, matmask))
161             return MATSURF_VISIBLE;
162         break;
163 
164     default:
165         if(visibleface(c, orient, co, size, mat, MAT_AIR, matmask))
166             return MATSURF_EDIT_ONLY;
167         break;
168     }
169     return MATSURF_NOT_VISIBLE;
170 }
171 
genmatsurfs(const cube & c,const ivec & co,int size,vector<materialsurface> & matsurfs)172 void genmatsurfs(const cube &c, const ivec &co, int size, vector<materialsurface> &matsurfs)
173 {
174     loopi(6)
175     {
176         static const ushort matmasks[] = { MATF_VOLUME|MATF_INDEX, MATF_CLIP, MAT_DEATH, MAT_NOGI, MAT_ALPHA };
177         loopj(sizeof(matmasks)/sizeof(matmasks[0]))
178         {
179             ushort matmask = matmasks[j];
180             int vis = visiblematerial(c, i, co, size, matmask&~MATF_INDEX);
181             if(vis != MATSURF_NOT_VISIBLE)
182             {
183                 materialsurface m;
184                 m.material = c.material&matmask;
185                 m.orient = i;
186                 m.visible = vis;
187                 m.o = co;
188                 m.csize = m.rsize = size;
189                 if(dimcoord(i)) m.o[dimension(i)] += size;
190                 matsurfs.add(m);
191                 break;
192             }
193         }
194     }
195 }
196 
addmatbb(ivec & matmin,ivec & matmax,const materialsurface & m)197 static inline void addmatbb(ivec &matmin, ivec &matmax, const materialsurface &m)
198 {
199     int dim = dimension(m.orient);
200     ivec mmin(m.o), mmax(m.o);
201     if(dimcoord(m.orient)) mmin[dim] -= 2; else mmax[dim] += 2;
202     mmax[R[dim]] += m.rsize;
203     mmax[C[dim]] += m.csize;
204     matmin.min(mmin);
205     matmax.max(mmax);
206 }
207 
calcmatbb(vtxarray * va,const ivec & co,int size,vector<materialsurface> & matsurfs)208 void calcmatbb(vtxarray *va, const ivec &co, int size, vector<materialsurface> &matsurfs)
209 {
210     va->lavamax = va->watermax = va->glassmax = co;
211     va->lavamin = va->watermin = va->glassmin = ivec(co).add(size);
212     loopv(matsurfs)
213     {
214         materialsurface &m = matsurfs[i];
215         switch(m.material&MATF_VOLUME)
216         {
217             case MAT_LAVA:
218                 if(m.visible == MATSURF_EDIT_ONLY) continue;
219                 addmatbb(va->lavamin, va->lavamax, m);
220                 break;
221 
222             case MAT_WATER:
223                 if(m.visible == MATSURF_EDIT_ONLY) continue;
224                 addmatbb(va->watermin, va->watermax, m);
225                 break;
226 
227             case MAT_GLASS:
228                 addmatbb(va->glassmin, va->glassmax, m);
229                 break;
230 
231             default:
232                 continue;
233         }
234     }
235 }
236 
mergematcmp(const materialsurface & x,const materialsurface & y)237 static inline bool mergematcmp(const materialsurface &x, const materialsurface &y)
238 {
239     int dim = dimension(x.orient), c = C[dim], r = R[dim];
240     if(x.o[r] + x.rsize < y.o[r] + y.rsize) return true;
241     if(x.o[r] + x.rsize > y.o[r] + y.rsize) return false;
242     return x.o[c] < y.o[c];
243 }
244 
mergematr(materialsurface * m,int sz,materialsurface & n)245 static int mergematr(materialsurface *m, int sz, materialsurface &n)
246 {
247     int dim = dimension(n.orient), c = C[dim], r = R[dim];
248     for(int i = sz-1; i >= 0; --i)
249     {
250         if(m[i].o[r] + m[i].rsize < n.o[r]) break;
251         if(m[i].o[r] + m[i].rsize == n.o[r] && m[i].o[c] == n.o[c] && m[i].csize == n.csize)
252         {
253             n.o[r] = m[i].o[r];
254             n.rsize += m[i].rsize;
255             memmove(&m[i], &m[i+1], (sz - (i+1)) * sizeof(materialsurface));
256             return 1;
257         }
258     }
259     return 0;
260 }
261 
mergematc(materialsurface & m,materialsurface & n)262 static int mergematc(materialsurface &m, materialsurface &n)
263 {
264     int dim = dimension(n.orient), c = C[dim], r = R[dim];
265     if(m.o[r] == n.o[r] && m.rsize == n.rsize && m.o[c] + m.csize == n.o[c])
266     {
267         n.o[c] = m.o[c];
268         n.csize += m.csize;
269         return 1;
270     }
271     return 0;
272 }
273 
mergemat(materialsurface * m,int sz,materialsurface & n)274 static int mergemat(materialsurface *m, int sz, materialsurface &n)
275 {
276     for(bool merged = false; sz; merged = true)
277     {
278         int rmerged = mergematr(m, sz, n);
279         sz -= rmerged;
280         if(!rmerged && merged) break;
281         if(!sz) break;
282         int cmerged = mergematc(m[sz-1], n);
283         sz -= cmerged;
284         if(!cmerged) break;
285     }
286     m[sz++] = n;
287     return sz;
288 }
289 
mergemats(materialsurface * m,int sz)290 static int mergemats(materialsurface *m, int sz)
291 {
292     quicksort(m, sz, mergematcmp);
293 
294     int nsz = 0;
295     loopi(sz) nsz = mergemat(m, nsz, m[i]);
296     return nsz;
297 }
298 
optmatcmp(const materialsurface & x,const materialsurface & y)299 static inline bool optmatcmp(const materialsurface &x, const materialsurface &y)
300 {
301     if(x.material < y.material) return true;
302     if(x.material > y.material) return false;
303     if(x.orient > y.orient) return true;
304     if(x.orient < y.orient) return false;
305     int dim = dimension(x.orient);
306     return x.o[dim] < y.o[dim];
307 }
308 
309 VARF(optmats, 0, 1, 1, allchanged());
310 
optimizematsurfs(materialsurface * matbuf,int matsurfs)311 int optimizematsurfs(materialsurface *matbuf, int matsurfs)
312 {
313     quicksort(matbuf, matsurfs, optmatcmp);
314     if(!optmats) return matsurfs;
315     materialsurface *cur = matbuf, *end = matbuf+matsurfs;
316     while(cur < end)
317     {
318          materialsurface *start = cur++;
319          int dim = dimension(start->orient);
320          while(cur < end &&
321                cur->material == start->material &&
322                cur->orient == start->orient &&
323                cur->visible == start->visible &&
324                cur->o[dim] == start->o[dim])
325             ++cur;
326          if(!isliquid(start->material&MATF_VOLUME) || start->orient != O_TOP || !vertwater)
327          {
328             if(start!=matbuf) memmove(matbuf, start, (cur-start)*sizeof(materialsurface));
329             matbuf += mergemats(matbuf, cur-start);
330          }
331          else if(cur-start>=4)
332          {
333             QuadNode vmats(0, 0, worldsize);
334             loopi(cur-start) vmats.insert(start[i].o[C[dim]], start[i].o[R[dim]], start[i].csize);
335             vmats.genmatsurfs(start->material, start->orient, start->visible, start->o[dim], matbuf);
336          }
337          else
338          {
339             if(start!=matbuf) memmove(matbuf, start, (cur-start)*sizeof(materialsurface));
340             matbuf += cur-start;
341          }
342     }
343     return matsurfs - (end-matbuf);
344 }
345 
preloadglassshaders(bool force=false)346 void preloadglassshaders(bool force = false)
347 {
348     static bool needglass = false;
349     if(force) needglass = true;
350     if(!needglass) return;
351 
352     useshaderbyname("glass");
353 
354     extern int glassenv;
355     if(glassenv) useshaderbyname("glassenv");
356 }
357 
358 extern vector<vtxarray *> valist;
359 
setupmaterials(int start,int len)360 void setupmaterials(int start, int len)
361 {
362     int hasmat = 0;
363     if(!len) len = valist.length();
364     for(int i = start; i < len; i++)
365     {
366         vtxarray *va = valist[i];
367         materialsurface *skip = NULL;
368         loopj(va->matsurfs)
369         {
370             materialsurface &m = va->matbuf[j];
371             int matvol = m.material&MATF_VOLUME;
372             if(isliquid(matvol) && m.orient!=O_BOTTOM && m.orient!=O_TOP)
373             {
374                 m.ends = 0;
375                 int dim = dimension(m.orient), coord = dimcoord(m.orient);
376                 ivec o(m.o);
377                 o.z -= 1;
378                 o[dim] += coord ? 1 : -1;
379                 int minc = o[dim^1], maxc = minc + (C[dim]==2 ? m.rsize : m.csize);
380                 ivec co;
381                 int csize;
382                 while(o[dim^1] < maxc)
383                 {
384                     cube &c = lookupcube(o, 0, co, csize);
385                     if(isliquid(c.material&MATF_VOLUME)) { m.ends |= 1; break; }
386                     o[dim^1] += csize;
387                 }
388                 o[dim^1] = minc;
389                 o.z += R[dim]==2 ? m.rsize : m.csize;
390                 o[dim] -= coord ? 2 : -2;
391                 while(o[dim^1] < maxc)
392                 {
393                     cube &c = lookupcube(o, 0, co, csize);
394                     if(visiblematerial(c, O_TOP, co, csize)) { m.ends |= 2; break; }
395                     o[dim^1] += csize;
396                 }
397             }
398             else if(matvol==MAT_GLASS)
399             {
400                 int dim = dimension(m.orient);
401                 vec center(m.o);
402                 center[R[dim]] += m.rsize/2;
403                 center[C[dim]] += m.csize/2;
404                 m.envmap = closestenvmap(center);
405             }
406             if(matvol) hasmat |= 1<<m.material;
407             m.skip = 0;
408             if(skip && m.material == skip->material && m.orient == skip->orient && skip->skip < 0xFFFF)
409                 skip->skip++;
410             else
411                 skip = &m;
412         }
413     }
414     if(hasmat&(0xF<<MAT_WATER))
415     {
416         loadcaustics(true);
417         preloadwatershaders(true);
418         loopi(4) if(hasmat&(1<<(MAT_WATER+i))) lookupmaterialslot(MAT_WATER+i);
419     }
420     if(hasmat&(0xF<<MAT_LAVA))
421     {
422         useshaderbyname("lava");
423         loopi(4) if(hasmat&(1<<(MAT_LAVA+i))) lookupmaterialslot(MAT_LAVA+i);
424     }
425     if(hasmat&(0xF<<MAT_GLASS))
426     {
427         preloadglassshaders(true);
428         loopi(4) if(hasmat&(1<<(MAT_GLASS+i))) lookupmaterialslot(MAT_GLASS+i);
429     }
430 }
431 
432 VARP(showmat, 0, 1, 1);
433 
434 static int sortdim[3];
435 static ivec sortorigin;
436 
editmatcmp(const materialsurface & x,const materialsurface & y)437 static inline bool editmatcmp(const materialsurface &x, const materialsurface &y)
438 {
439     int xdim = dimension(x.orient), ydim = dimension(y.orient);
440     loopi(3)
441     {
442         int dim = sortdim[i], xmin, xmax, ymin, ymax;
443         xmin = xmax = x.o[dim];
444         if(dim==C[xdim]) xmax += x.csize;
445         else if(dim==R[xdim]) xmax += x.rsize;
446         ymin = ymax = y.o[dim];
447         if(dim==C[ydim]) ymax += y.csize;
448         else if(dim==R[ydim]) ymax += y.rsize;
449         if(xmax > ymin && ymax > xmin) continue;
450         int c = sortorigin[dim];
451         if(c > xmin && c < xmax) return true;
452         if(c > ymin && c < ymax) return false;
453         xmin = abs(xmin - c);
454         xmax = abs(xmax - c);
455         ymin = abs(ymin - c);
456         ymax = abs(ymax - c);
457         if(max(xmin, xmax) <= min(ymin, ymax)) return true;
458         else if(max(ymin, ymax) <= min(xmin, xmax)) return false;
459     }
460     if(x.material < y.material) return true;
461     //if(x.material > y.material) return false;
462     return false;
463 }
464 
sorteditmaterials()465 void sorteditmaterials()
466 {
467     sortorigin = ivec(camera1->o);
468     vec dir = vec(camdir).abs();
469     loopi(3) sortdim[i] = i;
470     if(dir[sortdim[2]] > dir[sortdim[1]]) swap(sortdim[2], sortdim[1]);
471     if(dir[sortdim[1]] > dir[sortdim[0]]) swap(sortdim[1], sortdim[0]);
472     if(dir[sortdim[2]] > dir[sortdim[1]]) swap(sortdim[2], sortdim[1]);
473     editsurfs.sort(editmatcmp);
474 }
475 
rendermatgrid()476 void rendermatgrid()
477 {
478     enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
479     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
480     int lastmat = -1;
481     loopvrev(editsurfs)
482     {
483         materialsurface &m = editsurfs[i];
484         if(m.material != lastmat)
485         {
486             xtraverts += gle::end();
487             bvec color;
488             switch(m.material&~MATF_INDEX)
489             {
490                 case MAT_WATER:    color = bvec( 0,  0, 85); break; // blue
491                 case MAT_CLIP:     color = bvec(85,  0,  0); break; // red
492                 case MAT_GLASS:    color = bvec( 0, 85, 85); break; // cyan
493                 case MAT_NOCLIP:   color = bvec( 0, 85,  0); break; // green
494                 case MAT_LAVA:     color = bvec(85, 40,  0); break; // orange
495                 case MAT_GAMECLIP: color = bvec(85, 85,  0); break; // yellow
496                 case MAT_DEATH:    color = bvec(40, 40, 40); break; // black
497                 case MAT_NOGI:     color = bvec(40, 30,  0); break; // brown
498                 case MAT_ALPHA:    color = bvec(85,  0, 85); break; // pink
499                 default: continue;
500             }
501             gle::colorf(color.x*ldrscaleb, color.y*ldrscaleb, color.z*ldrscaleb);
502             lastmat = m.material;
503         }
504         drawmaterial(m, -0.1f);
505     }
506     xtraverts += gle::end();
507     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
508     disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
509 }
510 
511 static float glassxscale = 0, glassyscale = 0;
512 
drawglass(const materialsurface & m,float offset,const vec * normal=NULL)513 static void drawglass(const materialsurface &m, float offset, const vec *normal = NULL)
514 {
515     if(gle::attribbuf.empty())
516     {
517         gle::defvertex();
518         if(normal) gle::defnormal();
519         gle::deftexcoord0();
520         gle::begin(GL_QUADS);
521     }
522     #define GENFACEORIENT(orient, v0, v1, v2, v3) \
523         case orient: v0 v1 v2 v3 break;
524     #undef GENFACEVERTX
525     #define GENFACEVERTX(orient, vert, mx,my,mz, sx,sy,sz) \
526         { \
527             vec v(mx sx, my sy, mz sz); \
528             gle::attribf(v.x, v.y, v.z); \
529             GENFACENORMAL \
530             gle::attribf(glassxscale*v.y, -glassyscale*v.z); \
531         }
532     #undef GENFACEVERTY
533     #define GENFACEVERTY(orient, vert, mx,my,mz, sx,sy,sz) \
534         { \
535             vec v(mx sx, my sy, mz sz); \
536             gle::attribf(v.x, v.y, v.z); \
537             GENFACENORMAL \
538             gle::attribf(glassxscale*v.x, -glassyscale*v.z); \
539         }
540     #undef GENFACEVERTZ
541     #define GENFACEVERTZ(orient, vert, mx,my,mz, sx,sy,sz) \
542         { \
543             vec v(mx sx, my sy, mz sz); \
544             gle::attribf(v.x, v.y, v.z); \
545             GENFACENORMAL \
546             gle::attribf(glassxscale*v.x, glassyscale*v.y); \
547         }
548     #define GENFACENORMAL gle::attribf(n.x, n.y, n.z);
549     float x = m.o.x, y = m.o.y, z = m.o.z, csize = m.csize, rsize = m.rsize;
550     if(normal)
551     {
552         vec n = *normal;
553         switch(m.orient) { GENFACEVERTS(x, x, y, y, z, z, /**/, + csize, /**/, + rsize, + offset, - offset) }
554     }
555     #undef GENFACENORMAL
556     #define GENFACENORMAL
557     else switch(m.orient) { GENFACEVERTS(x, x, y, y, z, z, /**/, + csize, /**/, + rsize, + offset, - offset) }
558     #undef GENFACENORMAL
559     #undef GENFACEORIENT
560     #undef GENFACEVERTX
561     #define GENFACEVERTX(o,n, x,y,z, xv,yv,zv) GENFACEVERT(o,n, x,y,z, xv,yv,zv)
562     #undef GENFACEVERTY
563     #define GENFACEVERTY(o,n, x,y,z, xv,yv,zv) GENFACEVERT(o,n, x,y,z, xv,yv,zv)
564     #undef GENFACEVERTZ
565     #define GENFACEVERTZ(o,n, x,y,z, xv,yv,zv) GENFACEVERT(o,n, x,y,z, xv,yv,zv)
566 }
567 
568 vector<materialsurface> editsurfs, glasssurfs[4], watersurfs[4], waterfallsurfs[4], lavasurfs[4], lavafallsurfs[4];
569 
570 float matliquidsx1 = -1, matliquidsy1 = -1, matliquidsx2 = 1, matliquidsy2 = 1;
571 float matsolidsx1 = -1, matsolidsy1 = -1, matsolidsx2 = 1, matsolidsy2 = 1;
572 float matrefractsx1 = -1, matrefractsy1 = -1, matrefractsx2 = 1, matrefractsy2 = 1;
573 uint matliquidtiles[LIGHTTILE_MAXH], matsolidtiles[LIGHTTILE_MAXH];
574 
575 extern vtxarray *visibleva;
576 
findmaterials()577 int findmaterials()
578 {
579     editsurfs.setsize(0);
580     loopi(4)
581     {
582         glasssurfs[i].setsize(0);
583         watersurfs[i].setsize(0);
584         waterfallsurfs[i].setsize(0);
585         lavasurfs[i].setsize(0);
586         lavafallsurfs[i].setsize(0);
587     }
588     matliquidsx1 = matliquidsy1 = matsolidsx1 = matsolidsy1 = matrefractsx1 = matrefractsy1 = 1;
589     matliquidsx2 = matliquidsy2 = matsolidsx2 = matsolidsy2 = matrefractsx2 = matrefractsy2 = -1;
590     memset(matliquidtiles, 0, sizeof(matliquidtiles));
591     memset(matsolidtiles, 0, sizeof(matsolidtiles));
592     int hasmats = 0;
593     for(vtxarray *va = visibleva; va; va = va->next)
594     {
595         if(!va->matsurfs || va->occluded >= OCCLUDE_BB || va->curvfc >= VFC_FOGGED) continue;
596         if(editmode && showmat && !drawtex)
597         {
598             loopi(va->matsurfs) editsurfs.add(va->matbuf[i]);
599             continue;
600         }
601         float sx1, sy1, sx2, sy2;
602         if(va->lavamin.x <= va->lavamax.x && calcbbscissor(va->lavamin, va->lavamax, sx1, sy1, sx2, sy2))
603         {
604             matliquidsx1 = min(matliquidsx1, sx1);
605             matliquidsy1 = min(matliquidsy1, sy1);
606             matliquidsx2 = max(matliquidsx2, sx2);
607             matliquidsy2 = max(matliquidsy2, sy2);
608             masktiles(matliquidtiles, sx1, sy1, sx2, sy2);
609             loopi(va->matsurfs)
610             {
611                 materialsurface &m = va->matbuf[i];
612                 if((m.material&MATF_VOLUME) != MAT_LAVA || m.visible == MATSURF_EDIT_ONLY) { i += m.skip; continue; }
613                 hasmats |= 1;
614                 if(m.orient == O_TOP) lavasurfs[m.material&MATF_INDEX].put(&m, 1+int(m.skip));
615                 else lavafallsurfs[m.material&MATF_INDEX].put(&m, 1+int(m.skip));
616                 i += m.skip;
617             }
618         }
619         if(va->watermin.x <= va->watermax.x && calcbbscissor(va->watermin, va->watermax, sx1, sy1, sx2, sy2))
620         {
621             matliquidsx1 = min(matliquidsx1, sx1);
622             matliquidsy1 = min(matliquidsy1, sy1);
623             matliquidsx2 = max(matliquidsx2, sx2);
624             matliquidsy2 = max(matliquidsy2, sy2);
625             masktiles(matliquidtiles, sx1, sy1, sx2, sy2);
626             matrefractsx1 = min(matrefractsx1, sx1);
627             matrefractsy1 = min(matrefractsy1, sy1);
628             matrefractsx2 = max(matrefractsx2, sx2);
629             matrefractsy2 = max(matrefractsy2, sy2);
630             loopi(va->matsurfs)
631             {
632                 materialsurface &m = va->matbuf[i];
633                 if((m.material&MATF_VOLUME) != MAT_WATER || m.visible == MATSURF_EDIT_ONLY) { i += m.skip; continue; }
634                 hasmats |= 4|1;
635                 if(m.orient == O_TOP) watersurfs[m.material&MATF_INDEX].put(&m, 1+int(m.skip));
636                 else waterfallsurfs[m.material&MATF_INDEX].put(&m, 1+int(m.skip));
637                 i += m.skip;
638             }
639         }
640         if(drawtex != DRAWTEX_ENVMAP && va->glassmin.x <= va->glassmax.x && calcbbscissor(va->glassmin, va->glassmax, sx1, sy1, sx2, sy2))
641         {
642             matsolidsx1 = min(matsolidsx1, sx1);
643             matsolidsy1 = min(matsolidsy1, sy1);
644             matsolidsx2 = max(matsolidsx2, sx2);
645             matsolidsy2 = max(matsolidsy2, sy2);
646             masktiles(matsolidtiles, sx1, sy1, sx2, sy2);
647             matrefractsx1 = min(matrefractsx1, sx1);
648             matrefractsy1 = min(matrefractsy1, sy1);
649             matrefractsx2 = max(matrefractsx2, sx2);
650             matrefractsy2 = max(matrefractsy2, sy2);
651             loopi(va->matsurfs)
652             {
653                 materialsurface &m = va->matbuf[i];
654                 if((m.material&MATF_VOLUME) != MAT_GLASS) { i += m.skip; continue; }
655                 hasmats |= 4|2;
656                 glasssurfs[m.material&MATF_INDEX].put(&m, 1+int(m.skip));
657                 i += m.skip;
658             }
659         }
660     }
661     return hasmats;
662 }
663 
rendermaterialmask()664 void rendermaterialmask()
665 {
666     glDisable(GL_CULL_FACE);
667     loopk(4) { vector<materialsurface> &surfs = glasssurfs[k]; loopv(surfs) drawmaterial(surfs[i], 0.1f); }
668     loopk(4) { vector<materialsurface> &surfs = watersurfs[k]; loopv(surfs) drawmaterial(surfs[i], WATER_OFFSET); }
669     loopk(4) { vector<materialsurface> &surfs = waterfallsurfs[k]; loopv(surfs) drawmaterial(surfs[i], 0.1f); }
670     xtraverts += gle::end();
671     gle::disable();
672     glEnable(GL_CULL_FACE);
673 }
674 
675 extern const vec matnormals[6] =
676 {
677     vec(-1, 0, 0),
678     vec( 1, 0, 0),
679     vec(0, -1, 0),
680     vec(0,  1, 0),
681     vec(0, 0, -1),
682     vec(0, 0,  1)
683 };
684 
685 #define GLASSVARS(name) \
686     CVAR0R(name##colour, 0xB0D8FF); \
687     FVARR(name##refract, 0, 0.1f, 1e3f); \
688     VARR(name##spec, 0, 150, 200);
689 
690 GLASSVARS(glass)
691 GLASSVARS(glass2)
692 GLASSVARS(glass3)
693 GLASSVARS(glass4)
694 
695 GETMATIDXVAR(glass, colour, const bvec &)
696 GETMATIDXVAR(glass, refract, float)
697 GETMATIDXVAR(glass, spec, int)
698 
699 VARFP(glassenv, 0, 1, 1, preloadglassshaders());
700 
renderglass()701 void renderglass()
702 {
703     loopk(4)
704     {
705         vector<materialsurface> &surfs = glasssurfs[k];
706         if(surfs.empty()) continue;
707 
708         MatSlot &gslot = lookupmaterialslot(MAT_GLASS+k);
709 
710         Texture *tex = gslot.sts.inrange(0) ? gslot.sts[0].t : notexture;
711         glassxscale = TEX_SCALE/(tex->xs*gslot.scale);
712         glassyscale = TEX_SCALE/(tex->ys*gslot.scale);
713 
714         glActiveTexture_(GL_TEXTURE1);
715         glBindTexture(GL_TEXTURE_2D, tex->id);
716         glActiveTexture_(GL_TEXTURE0);
717 
718         float refractscale = (0.5f/255)/ldrscale;
719         const bvec &col = getglasscolour(k);
720         float refract = getglassrefract(k);
721         int spec = getglassspec(k);
722         GLOBALPARAMF(glassrefract, col.x*refractscale, col.y*refractscale, col.z*refractscale, refract*viewh);
723         GLOBALPARAMF(glassspec, 0.5f*spec/100.0f);
724 
725         short envmap = EMID_NONE;
726         if(!glassenv) SETSHADER(glass);
727         loopv(surfs)
728         {
729             materialsurface &m = surfs[i];
730             if(m.envmap != envmap && glassenv)
731             {
732                 xtraverts += gle::end();
733                 if(m.envmap != EMID_NONE && glassenv) SETSHADER(glassenv);
734                 else SETSHADER(glass);
735                 glBindTexture(GL_TEXTURE_CUBE_MAP, lookupenvmap(m.envmap));
736                 envmap = m.envmap;
737             }
738             drawglass(m, 0.1f, &matnormals[m.orient]);
739         }
740         xtraverts += gle::end();
741     }
742 }
743 
renderliquidmaterials()744 void renderliquidmaterials()
745 {
746     glDisable(GL_CULL_FACE);
747 
748     renderlava();
749     renderwater();
750     renderwaterfalls();
751 
752     gle::disable();
753     glEnable(GL_CULL_FACE);
754 }
755 
rendersolidmaterials()756 void rendersolidmaterials()
757 {
758     glDisable(GL_CULL_FACE);
759 
760     renderglass();
761 
762     gle::disable();
763     glEnable(GL_CULL_FACE);
764 }
765 
rendereditmaterials()766 void rendereditmaterials()
767 {
768     if(editsurfs.empty()) return;
769 
770     sorteditmaterials();
771 
772     glDisable(GL_CULL_FACE);
773 
774     zerofogcolor();
775 
776     foggednotextureshader->set();
777 
778     glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
779     glEnable(GL_BLEND);
780 
781     int lastmat = -1;
782     loopv(editsurfs)
783     {
784         const materialsurface &m = editsurfs[i];
785         if(lastmat!=m.material)
786         {
787             xtraverts += gle::end();
788             bvec color;
789             switch(m.material&~MATF_INDEX)
790             {
791                 case MAT_WATER:    color = bvec(255, 128,   0); break; // blue
792                 case MAT_CLIP:     color = bvec(  0, 255, 255); break; // red
793                 case MAT_GLASS:    color = bvec(255,   0,   0); break; // cyan
794                 case MAT_NOCLIP:   color = bvec(255,   0, 255); break; // green
795                 case MAT_LAVA:     color = bvec(  0, 128, 255); break; // orange
796                 case MAT_GAMECLIP: color = bvec(  0,   0, 255); break; // yellow
797                 case MAT_DEATH:    color = bvec(192, 192, 192); break; // black
798                 case MAT_NOGI:     color = bvec(128, 160, 255); break; // brown
799                 case MAT_ALPHA:    color = bvec(  0, 255,   0); break; // pink
800                 default: continue;
801             }
802             gle::color(color);
803             lastmat = m.material;
804         }
805         drawmaterial(m, -0.1f);
806     }
807 
808     xtraverts += gle::end();
809 
810     glDisable(GL_BLEND);
811 
812     resetfogcolor();
813 
814     rendermatgrid();
815 
816     gle::disable();
817     glEnable(GL_CULL_FACE);
818 }
819 
renderminimapmaterials()820 void renderminimapmaterials()
821 {
822     glDisable(GL_CULL_FACE);
823 
824     renderlava();
825     renderwater();
826 
827     gle::disable();
828     glEnable(GL_CULL_FACE);
829 }
830 
831