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 flags, int z, materialsurface *&matbuf)
63 {
64 if(filled == 0xF) genmatsurf(mat, orient, flags, 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, flags, 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, flags, z, matbuf);
72 }
73 };
74
75 static float wfwave;
76
77 static const bvec4 matnormals[6] =
78 {
79 bvec4(0x80, 0, 0),
80 bvec4(0x7F, 0, 0),
81 bvec4(0, 0x80, 0),
82 bvec4(0, 0x7F, 0),
83 bvec4(0, 0, 0x80),
84 bvec4(0, 0, 0x7F)
85 };
86
renderwaterfall(const materialsurface & m,float offset)87 static void renderwaterfall(const materialsurface &m, float offset)
88 {
89 if(gle::attribbuf.empty())
90 {
91 gle::defvertex();
92 gle::defnormal(4, GL_BYTE);
93 gle::begin(GL_QUADS);
94 }
95 float x = m.o.x, y = m.o.y, zmin = m.o.z, zmax = zmin;
96 if(m.ends&1) zmin += -WATER_OFFSET-WATER_AMPLITUDE;
97 if(m.ends&2) zmax += wfwave;
98 int csize = m.csize, rsize = m.rsize;
99 switch(m.orient)
100 {
101 #define GENFACEORIENT(orient, v0, v1, v2, v3) \
102 case orient: v0 v1 v2 v3 break;
103 #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) \
104 { \
105 gle::attribf(mx sx, my sy, mz sz); \
106 gle::attrib(matnormals[orient]); \
107 }
108 GENFACEVERTSXY(x, x, y, y, zmin, zmax, /**/, + csize, /**/, + rsize, + offset, - offset)
109 #undef GENFACEORIENT
110 #undef GENFACEVERT
111 }
112 }
113
drawmaterial(const materialsurface & m,float offset,const bvec4 & color)114 static void drawmaterial(const materialsurface &m, float offset, const bvec4 &color)
115 {
116 if(gle::attribbuf.empty())
117 {
118 gle::defvertex();
119 gle::defcolor(4, GL_UNSIGNED_BYTE);
120 gle::begin(GL_QUADS);
121 }
122 float x = m.o.x, y = m.o.y, z = m.o.z, csize = m.csize, rsize = m.rsize;
123 switch(m.orient)
124 {
125 #define GENFACEORIENT(orient, v0, v1, v2, v3) \
126 case orient: v0 v1 v2 v3 break;
127 #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) \
128 { \
129 gle::attribf(mx sx, my sy, mz sz); \
130 gle::attrib(color); \
131 }
132 GENFACEVERTS(x, x, y, y, z, z, /**/, + csize, /**/, + rsize, + offset, - offset)
133 #undef GENFACEORIENT
134 #undef GENFACEVERT
135 }
136 }
137
138 const struct material
139 {
140 const char *name;
141 ushort id;
142 } materials[] =
143 {
144 {"air", MAT_AIR},
145 {"water", MAT_WATER}, {"water1", MAT_WATER}, {"water2", MAT_WATER+1}, {"water3", MAT_WATER+2}, {"water4", MAT_WATER+3},
146 {"glass", MAT_GLASS}, {"glass1", MAT_GLASS}, {"glass2", MAT_GLASS+1}, {"glass3", MAT_GLASS+2}, {"glass4", MAT_GLASS+3},
147 {"lava", MAT_LAVA}, {"lava1", MAT_LAVA}, {"lava2", MAT_LAVA+1}, {"lava3", MAT_LAVA+2}, {"lava4", MAT_LAVA+3},
148 {"clip", MAT_CLIP},
149 {"noclip", MAT_NOCLIP},
150 {"gameclip", MAT_GAMECLIP},
151 {"death", MAT_DEATH},
152 {"alpha", MAT_ALPHA}
153 };
154
findmaterial(const char * name)155 int findmaterial(const char *name)
156 {
157 loopi(sizeof(materials)/sizeof(material))
158 {
159 if(!strcmp(materials[i].name, name)) return materials[i].id;
160 }
161 return -1;
162 }
163
findmaterialname(int mat)164 const char *findmaterialname(int mat)
165 {
166 loopi(sizeof(materials)/sizeof(materials[0])) if(materials[i].id == mat) return materials[i].name;
167 return NULL;
168 }
169
getmaterialdesc(int mat,const char * prefix)170 const char *getmaterialdesc(int mat, const char *prefix)
171 {
172 static const ushort matmasks[] = { MATF_VOLUME|MATF_INDEX, MATF_CLIP, MAT_DEATH, MAT_ALPHA };
173 static string desc;
174 desc[0] = '\0';
175 loopi(sizeof(matmasks)/sizeof(matmasks[0])) if(mat&matmasks[i])
176 {
177 const char *matname = findmaterialname(mat&matmasks[i]);
178 if(matname)
179 {
180 concatstring(desc, desc[0] ? ", " : prefix);
181 concatstring(desc, matname);
182 }
183 }
184 return desc;
185 }
186
visiblematerial(const cube & c,int orient,const ivec & co,int size,ushort matmask)187 int visiblematerial(const cube &c, int orient, const ivec &co, int size, ushort matmask)
188 {
189 ushort mat = c.material&matmask;
190 switch(mat)
191 {
192 case MAT_AIR:
193 break;
194
195 case MAT_LAVA:
196 case MAT_WATER:
197 if(visibleface(c, orient, co, size, mat, MAT_AIR, matmask))
198 return (orient != O_BOTTOM ? MATSURF_VISIBLE : MATSURF_EDIT_ONLY);
199 break;
200
201 case MAT_GLASS:
202 if(visibleface(c, orient, co, size, MAT_GLASS, MAT_AIR, matmask))
203 return MATSURF_VISIBLE;
204 break;
205
206 default:
207 if(visibleface(c, orient, co, size, mat, MAT_AIR, matmask))
208 return MATSURF_EDIT_ONLY;
209 break;
210 }
211 return MATSURF_NOT_VISIBLE;
212 }
213
genmatsurfs(const cube & c,const ivec & co,int size,vector<materialsurface> & matsurfs)214 void genmatsurfs(const cube &c, const ivec &co, int size, vector<materialsurface> &matsurfs)
215 {
216 loopi(6)
217 {
218 static const ushort matmasks[] = { MATF_VOLUME|MATF_INDEX, MATF_CLIP, MAT_DEATH, MAT_ALPHA };
219 loopj(sizeof(matmasks)/sizeof(matmasks[0]))
220 {
221 int matmask = matmasks[j];
222 int vis = visiblematerial(c, i, co, size, matmask&~MATF_INDEX);
223 if(vis != MATSURF_NOT_VISIBLE)
224 {
225 materialsurface m;
226 m.material = c.material&matmask;
227 m.orient = i;
228 m.visible = vis;
229 m.o = co;
230 m.csize = m.rsize = size;
231 if(dimcoord(i)) m.o[dimension(i)] += size;
232 matsurfs.add(m);
233 break;
234 }
235 }
236 }
237 }
238
mergematcmp(const materialsurface & x,const materialsurface & y)239 static inline bool mergematcmp(const materialsurface &x, const materialsurface &y)
240 {
241 int dim = dimension(x.orient), c = C[dim], r = R[dim];
242 if(x.o[r] + x.rsize < y.o[r] + y.rsize) return true;
243 if(x.o[r] + x.rsize > y.o[r] + y.rsize) return false;
244 return x.o[c] < y.o[c];
245 }
246
mergematr(materialsurface * m,int sz,materialsurface & n)247 static int mergematr(materialsurface *m, int sz, materialsurface &n)
248 {
249 int dim = dimension(n.orient), c = C[dim], r = R[dim];
250 for(int i = sz-1; i >= 0; --i)
251 {
252 if(m[i].o[r] + m[i].rsize < n.o[r]) break;
253 if(m[i].o[r] + m[i].rsize == n.o[r] && m[i].o[c] == n.o[c] && m[i].csize == n.csize)
254 {
255 n.o[r] = m[i].o[r];
256 n.rsize += m[i].rsize;
257 memmove(&m[i], &m[i+1], (sz - (i+1)) * sizeof(materialsurface));
258 return 1;
259 }
260 }
261 return 0;
262 }
263
mergematc(materialsurface & m,materialsurface & n)264 static int mergematc(materialsurface &m, materialsurface &n)
265 {
266 int dim = dimension(n.orient), c = C[dim], r = R[dim];
267 if(m.o[r] == n.o[r] && m.rsize == n.rsize && m.o[c] + m.csize == n.o[c])
268 {
269 n.o[c] = m.o[c];
270 n.csize += m.csize;
271 return 1;
272 }
273 return 0;
274 }
275
mergemat(materialsurface * m,int sz,materialsurface & n)276 static int mergemat(materialsurface *m, int sz, materialsurface &n)
277 {
278 for(bool merged = false; sz; merged = true)
279 {
280 int rmerged = mergematr(m, sz, n);
281 sz -= rmerged;
282 if(!rmerged && merged) break;
283 if(!sz) break;
284 int cmerged = mergematc(m[sz-1], n);
285 sz -= cmerged;
286 if(!cmerged) break;
287 }
288 m[sz++] = n;
289 return sz;
290 }
291
mergemats(materialsurface * m,int sz)292 static int mergemats(materialsurface *m, int sz)
293 {
294 quicksort(m, sz, mergematcmp);
295
296 int nsz = 0;
297 loopi(sz) nsz = mergemat(m, nsz, m[i]);
298 return nsz;
299 }
300
optmatcmp(const materialsurface & x,const materialsurface & y)301 static inline bool optmatcmp(const materialsurface &x, const materialsurface &y)
302 {
303 if(x.material < y.material) return true;
304 if(x.material > y.material) return false;
305 if(x.orient > y.orient) return true;
306 if(x.orient < y.orient) return false;
307 int dim = dimension(x.orient);
308 return x.o[dim] < y.o[dim];
309 }
310
311 VARF(optmats, 0, 1, 1, allchanged());
312
optimizematsurfs(materialsurface * matbuf,int matsurfs)313 int optimizematsurfs(materialsurface *matbuf, int matsurfs)
314 {
315 quicksort(matbuf, matsurfs, optmatcmp);
316 if(!optmats) return matsurfs;
317 materialsurface *cur = matbuf, *end = matbuf+matsurfs;
318 while(cur < end)
319 {
320 materialsurface *start = cur++;
321 int dim = dimension(start->orient);
322 while(cur < end &&
323 cur->material == start->material &&
324 cur->orient == start->orient &&
325 cur->visible == start->visible &&
326 cur->o[dim] == start->o[dim])
327 ++cur;
328 if(!isliquid(start->material&MATF_VOLUME) || start->orient != O_TOP || !vertwater)
329 {
330 if(start!=matbuf) memmove(matbuf, start, (cur-start)*sizeof(materialsurface));
331 matbuf += mergemats(matbuf, cur-start);
332 }
333 else if(cur-start>=4)
334 {
335 QuadNode vmats(0, 0, worldsize);
336 loopi(cur-start) vmats.insert(start[i].o[C[dim]], start[i].o[R[dim]], start[i].csize);
337 vmats.genmatsurfs(start->material, start->orient, start->visible, start->o[dim], matbuf);
338 }
339 else
340 {
341 if(start!=matbuf) memmove(matbuf, start, (cur-start)*sizeof(materialsurface));
342 matbuf += cur-start;
343 }
344 }
345 return matsurfs - (end-matbuf);
346 }
347
348 struct waterinfo
349 {
350 materialsurface *m;
351 double depth, area;
352 };
353
setupmaterials(int start,int len)354 void setupmaterials(int start, int len)
355 {
356 int hasmat = 0;
357 vector<waterinfo> water;
358 unionfind uf;
359 if(!len) len = valist.length();
360 for(int i = start; i < len; i++)
361 {
362 vtxarray *va = valist[i];
363 materialsurface *skip = NULL;
364 loopj(va->matsurfs)
365 {
366 materialsurface &m = va->matbuf[j];
367 int matvol = m.material&MATF_VOLUME;
368 if(matvol==MAT_WATER && m.orient==O_TOP)
369 {
370 m.index = water.length();
371 loopvk(water)
372 {
373 materialsurface &n = *water[k].m;
374 if(m.material!=n.material || m.o.z!=n.o.z) continue;
375 if(n.o.x+n.rsize==m.o.x || m.o.x+m.rsize==n.o.x)
376 {
377 if(n.o.y+n.csize>m.o.y && n.o.y<m.o.y+m.csize) uf.unite(m.index, n.index);
378 }
379 else if(n.o.y+n.csize==m.o.y || m.o.y+m.csize==n.o.y)
380 {
381 if(n.o.x+n.rsize>m.o.x && n.o.x<m.o.x+m.rsize) uf.unite(m.index, n.index);
382 }
383 }
384 waterinfo &wi = water.add();
385 wi.m = &m;
386 vec center(m.o.x+m.rsize/2, m.o.y+m.csize/2, m.o.z-WATER_OFFSET);
387 m.light = brightestlight(center, vec(0, 0, 1));
388 float depth = raycube(center, vec(0, 0, -1), 10000);
389 wi.depth = double(depth)*m.rsize*m.csize;
390 wi.area = m.rsize*m.csize;
391 }
392 else if(isliquid(matvol) && m.orient!=O_BOTTOM && m.orient!=O_TOP)
393 {
394 m.ends = 0;
395 int dim = dimension(m.orient), coord = dimcoord(m.orient);
396 ivec o(m.o);
397 o.z -= 1;
398 o[dim] += coord ? 1 : -1;
399 int minc = o[dim^1], maxc = minc + (C[dim]==2 ? m.rsize : m.csize);
400 ivec co;
401 int csize;
402 while(o[dim^1] < maxc)
403 {
404 cube &c = lookupcube(o, 0, co, csize);
405 if(isliquid(c.material&MATF_VOLUME)) { m.ends |= 1; break; }
406 o[dim^1] += csize;
407 }
408 o[dim^1] = minc;
409 o.z += R[dim]==2 ? m.rsize : m.csize;
410 o[dim] -= coord ? 2 : -2;
411 while(o[dim^1] < maxc)
412 {
413 cube &c = lookupcube(o, 0, co, csize);
414 if(visiblematerial(c, O_TOP, co, csize)) { m.ends |= 2; break; }
415 o[dim^1] += csize;
416 }
417 }
418 else if(matvol==MAT_GLASS)
419 {
420 int dim = dimension(m.orient);
421 vec center(m.o);
422 center[R[dim]] += m.rsize/2;
423 center[C[dim]] += m.csize/2;
424 m.envmap = closestenvmap(center);
425 }
426 if(matvol) hasmat |= 1<<m.material;
427 m.skip = 0;
428 if(skip && m.material == skip->material && m.orient == skip->orient && skip->skip < 0xFFFF)
429 skip->skip++;
430 else
431 skip = &m;
432 }
433 }
434 loopv(water)
435 {
436 int root = uf.find(i);
437 if(i==root) continue;
438 materialsurface &m = *water[i].m, &n = *water[root].m;
439 if(m.light && (!m.light->attr1 || !n.light || (n.light->attr1 && m.light->attr1 > n.light->attr1))) n.light = m.light;
440 water[root].depth += water[i].depth;
441 water[root].area += water[i].area;
442 }
443 loopv(water)
444 {
445 int root = uf.find(i);
446 water[i].m->light = water[root].m->light;
447 water[i].m->depth = (short)(water[root].depth/water[root].area);
448 }
449 if(hasmat&(0xF<<MAT_WATER))
450 {
451 loadcaustics(true);
452 preloadwatershaders(true);
453 loopi(4) if(hasmat&(1<<(MAT_WATER+i))) lookupmaterialslot(MAT_WATER+i);
454 }
455 if(hasmat&(0xF<<MAT_LAVA))
456 {
457 useshaderbyname("lava");
458 useshaderbyname("lavaglare");
459 loopi(4) if(hasmat&(1<<(MAT_LAVA+i))) lookupmaterialslot(MAT_LAVA+i);
460 }
461 if(hasmat&(0xF<<MAT_GLASS)) useshaderbyname("glass");
462 }
463
464 VARP(showmat, 0, 1, 1);
465
466 static int sortdim[3];
467 static ivec sortorigin;
468 static bool sortedit;
469
vismatcmp(const materialsurface * xm,const materialsurface * ym)470 static inline bool vismatcmp(const materialsurface *xm, const materialsurface *ym)
471 {
472 const materialsurface &x = *xm, &y = *ym;
473 if(!sortedit)
474 {
475 if((x.material&MATF_VOLUME) == MAT_LAVA) { if((y.material&MATF_VOLUME) != MAT_LAVA) return true; }
476 else if((y.material&MATF_VOLUME) == MAT_LAVA) return false;
477 }
478 int xdim = dimension(x.orient), ydim = dimension(y.orient);
479 loopi(3)
480 {
481 int dim = sortdim[i], xmin, xmax, ymin, ymax;
482 xmin = xmax = x.o[dim];
483 if(dim==C[xdim]) xmax += x.csize;
484 else if(dim==R[xdim]) xmax += x.rsize;
485 ymin = ymax = y.o[dim];
486 if(dim==C[ydim]) ymax += y.csize;
487 else if(dim==R[ydim]) ymax += y.rsize;
488 if(xmax > ymin && ymax > xmin) continue;
489 int c = sortorigin[dim];
490 if(c > xmin && c < xmax) return sortedit;
491 if(c > ymin && c < ymax) return !sortedit;
492 xmin = abs(xmin - c);
493 xmax = abs(xmax - c);
494 ymin = abs(ymin - c);
495 ymax = abs(ymax - c);
496 if(max(xmin, xmax) <= min(ymin, ymax)) return sortedit;
497 else if(max(ymin, ymax) <= min(xmin, xmax)) return !sortedit;
498 }
499 if(x.material < y.material) return sortedit;
500 if(x.material > y.material) return !sortedit;
501 return false;
502 }
503
sortmaterials(vector<materialsurface * > & vismats)504 void sortmaterials(vector<materialsurface *> &vismats)
505 {
506 sortorigin = ivec(camera1->o);
507 if(reflecting) sortorigin.z = int(reflectz - (camera1->o.z - reflectz));
508 vec dir;
509 vecfromyawpitch(camera1->yaw, reflecting ? -camera1->pitch : camera1->pitch, 1, 0, dir);
510 loopi(3) { dir[i] = fabs(dir[i]); sortdim[i] = i; }
511 if(dir[sortdim[2]] > dir[sortdim[1]]) swap(sortdim[2], sortdim[1]);
512 if(dir[sortdim[1]] > dir[sortdim[0]]) swap(sortdim[1], sortdim[0]);
513 if(dir[sortdim[2]] > dir[sortdim[1]]) swap(sortdim[2], sortdim[1]);
514
515 for(vtxarray *va = reflecting ? reflectedva : visibleva; va; va = reflecting ? va->rnext : va->next)
516 {
517 if(!va->matsurfs || va->occluded >= OCCLUDE_BB) continue;
518 if(reflecting || refracting>0 ? va->o.z+va->size <= reflectz : va->o.z >= reflectz) continue;
519 loopi(va->matsurfs)
520 {
521 materialsurface &m = va->matbuf[i];
522 if(!editmode || !showmat || drawtex)
523 {
524 int matvol = m.material&MATF_VOLUME;
525 if(matvol==MAT_WATER && (m.orient==O_TOP || (refracting<0 && reflectz>worldsize))) { i += m.skip; continue; }
526 if(m.visible == MATSURF_EDIT_ONLY) { i += m.skip; continue; }
527 if(glaring && matvol!=MAT_LAVA) { i += m.skip; continue; }
528 }
529 else if(glaring) continue;
530 vismats.add(&m);
531 }
532 }
533 sortedit = editmode && showmat && !drawtex;
534 vismats.sort(vismatcmp);
535 }
536
rendermatgrid(vector<materialsurface * > & vismats)537 void rendermatgrid(vector<materialsurface *> &vismats)
538 {
539 enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
540 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
541 int lastmat = -1;
542 bvec4 color(0, 0, 0, 0);
543 loopvrev(vismats)
544 {
545 materialsurface &m = *vismats[i];
546 if(m.material != lastmat)
547 {
548 switch(m.material&~MATF_INDEX)
549 {
550 case MAT_WATER: color = bvec4( 0, 0, 85, 255); break; // blue
551 case MAT_CLIP: color = bvec4(85, 0, 0, 255); break; // red
552 case MAT_GLASS: color = bvec4( 0, 85, 85, 255); break; // cyan
553 case MAT_NOCLIP: color = bvec4( 0, 85, 0, 255); break; // green
554 case MAT_LAVA: color = bvec4(85, 40, 0, 255); break; // orange
555 case MAT_GAMECLIP: color = bvec4(85, 85, 0, 255); break; // yellow
556 case MAT_DEATH: color = bvec4(40, 40, 40, 255); break; // black
557 case MAT_ALPHA: color = bvec4(85, 0, 85, 255); break; // pink
558 default: continue;
559 }
560 lastmat = m.material;
561 }
562 drawmaterial(m, -0.1f, color);
563 }
564 xtraverts += gle::end();
565 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
566 disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
567 }
568
569 #define GLASSVARS(name) \
570 bvec name##color(0x20, 0x80, 0xC0); \
571 HVARFR(name##colour, 0, 0x2080C0, 0xFFFFFF, \
572 { \
573 if(!name##colour) name##colour = 0x2080C0; \
574 name##color = bvec((name##colour>>16)&0xFF, (name##colour>>8)&0xFF, name##colour&0xFF); \
575 });
576
577 GLASSVARS(glass)
578 GLASSVARS(glass2)
579 GLASSVARS(glass3)
580 GLASSVARS(glass4)
581
582 GETMATIDXVAR(glass, colour, int)
583 GETMATIDXVAR(glass, color, const bvec &)
584
585 VARP(glassenv, 0, 1, 1);
586
drawglass(const materialsurface & m,float offset)587 static void drawglass(const materialsurface &m, float offset)
588 {
589 if(gle::attribbuf.empty())
590 {
591 gle::defvertex();
592 gle::defnormal(4, GL_BYTE);
593 gle::begin(GL_QUADS);
594 }
595 float x = m.o.x, y = m.o.y, z = m.o.z, csize = m.csize, rsize = m.rsize;
596 switch(m.orient)
597 {
598 #define GENFACEORIENT(orient, v0, v1, v2, v3) \
599 case orient: v0 v1 v2 v3 break;
600 #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) \
601 { \
602 gle::attribf(mx sx, my sy, mz sz); \
603 gle::attrib(matnormals[orient]); \
604 }
605 GENFACEVERTS(x, x, y, y, z, z, /**/, + csize, /**/, + rsize, + offset, - offset)
606 #undef GENFACEORIENT
607 #undef GENFACEVERT
608 }
609 }
610
611 VARFP(waterfallenv, 0, 1, 1, preloadwatershaders());
612
changematerial(int mat,int orient)613 static inline void changematerial(int mat, int orient)
614 {
615 switch(mat&~MATF_INDEX)
616 {
617 case MAT_LAVA:
618 if(orient==O_TOP) flushlava();
619 else xtraverts += gle::end();
620 break;
621 default:
622 xtraverts += gle::end();
623 break;
624 }
625 }
626
rendermaterials()627 void rendermaterials()
628 {
629 vector<materialsurface *> vismats;
630 sortmaterials(vismats);
631 if(vismats.empty()) return;
632
633 glDisable(GL_CULL_FACE);
634
635 MSlot *mslot = NULL;
636 int lastorient = -1, lastmat = -1, usedwaterfall = -1;
637 bool depth = true, blended = false;
638 ushort envmapped = EMID_NONE;
639
640 GLOBALPARAM(camera, camera1->o);
641
642 int lastfogtype = 1;
643 if(editmode && showmat && !drawtex)
644 {
645 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
646 glEnable(GL_BLEND); blended = true;
647 foggednotextureshader->set();
648 zerofogcolor(); lastfogtype = 0;
649 bvec4 color(0, 0, 0, 0);
650 loopv(vismats)
651 {
652 const materialsurface &m = *vismats[i];
653 if(lastmat!=m.material)
654 {
655 switch(m.material&~MATF_INDEX)
656 {
657 case MAT_WATER: color = bvec4(255, 128, 0, 255); break; // blue
658 case MAT_CLIP: color = bvec4( 0, 255, 255, 255); break; // red
659 case MAT_GLASS: color = bvec4(255, 0, 0, 255); break; // cyan
660 case MAT_NOCLIP: color = bvec4(255, 0, 255, 255); break; // green
661 case MAT_LAVA: color = bvec4( 0, 128, 255, 255); break; // orange
662 case MAT_GAMECLIP: color = bvec4( 0, 0, 255, 255); break; // yellow
663 case MAT_DEATH: color = bvec4(192, 192, 192, 255); break; // black
664 case MAT_ALPHA: color = bvec4( 0, 255, 0, 255); break; // pink
665 default: continue;
666 }
667 lastmat = m.material;
668 }
669 drawmaterial(m, -0.1f, color);
670 }
671 xtraverts += gle::end();
672 }
673 else loopv(vismats)
674 {
675 const materialsurface &m = *vismats[i];
676 int matvol = m.material&~MATF_INDEX;
677 if(lastmat!=m.material || lastorient!=m.orient || (matvol==MAT_GLASS && envmapped && m.envmap != envmapped))
678 {
679 int fogtype = lastfogtype;
680 switch(matvol)
681 {
682 case MAT_WATER:
683 if(m.orient == O_TOP) continue;
684 if(lastmat == m.material) break;
685 mslot = &lookupmaterialslot(m.material, false);
686 if(!mslot->loaded || !mslot->sts.inrange(1)) continue;
687 else
688 {
689 changematerial(lastmat, lastorient);
690 glBindTexture(GL_TEXTURE_2D, mslot->sts[1].t->id);
691
692 bvec wfcol = getwaterfallcolor(m.material);
693 if(wfcol.iszero()) wfcol = getwatercolor(m.material);
694 gle::color(wfcol, 192);
695
696 int wfog = getwaterfog(m.material);
697 if(!wfog && !waterfallenv)
698 {
699 foggednotextureshader->set();
700 fogtype = 1;
701 if(blended) { glDisable(GL_BLEND); blended = false; }
702 if(!depth) { glDepthMask(GL_TRUE); depth = true; }
703 }
704 else if((!waterfallrefract || reflecting || refracting) && !waterfallenv)
705 {
706 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
707 SETSHADER(waterfall);
708 fogtype = 0;
709 if(!blended) { glEnable(GL_BLEND); blended = true; }
710 if(depth) { glDepthMask(GL_FALSE); depth = false; }
711 }
712 else
713 {
714 fogtype = 1;
715
716 if(waterfallrefract && wfog && !reflecting && !refracting)
717 {
718 if(waterfallenv) SETSHADER(waterfallenvrefract);
719 else SETSHADER(waterfallrefract);
720 if(blended) { glDisable(GL_BLEND); blended = false; }
721 if(!depth) { glDepthMask(GL_TRUE); depth = true; }
722 }
723 else
724 {
725 SETSHADER(waterfallenv);
726 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
727 if(wfog)
728 {
729 if(!blended) { glEnable(GL_BLEND); blended = true; }
730 if(depth) { glDepthMask(GL_FALSE); depth = false; }
731 }
732 else
733 {
734 if(blended) { glDisable(GL_BLEND); blended = false; }
735 if(!depth) { glDepthMask(GL_TRUE); depth = true; }
736 }
737 }
738
739 if(usedwaterfall != m.material)
740 {
741 Texture *dudv = mslot->sts.inrange(5) ? mslot->sts[5].t : notexture;
742 float scale = TEX_SCALE/(dudv->ys*mslot->scale);
743 LOCALPARAMF(dudvoffset, 0, scale*16*lastmillis/1000.0f);
744
745 glActiveTexture_(GL_TEXTURE1);
746 glBindTexture(GL_TEXTURE_2D, mslot->sts.inrange(4) ? mslot->sts[4].t->id : notexture->id);
747 glActiveTexture_(GL_TEXTURE2);
748 glBindTexture(GL_TEXTURE_2D, mslot->sts.inrange(5) ? mslot->sts[5].t->id : notexture->id);
749 if(waterfallenv)
750 {
751 glActiveTexture_(GL_TEXTURE3);
752 glBindTexture(GL_TEXTURE_CUBE_MAP, lookupenvmap(*mslot));
753 }
754 if(waterfallrefract && (!reflecting || !refracting) && usedwaterfall < 0)
755 {
756 glActiveTexture_(GL_TEXTURE4);
757 extern void setupwaterfallrefract();
758 setupwaterfallrefract();
759 }
760 glActiveTexture_(GL_TEXTURE0);
761
762 usedwaterfall = m.material;
763 }
764 }
765 float angle = fmod(float(lastmillis/600.0f/(2*M_PI)), 1.0f),
766 s = angle - int(angle) - 0.5f;
767 s *= 8 - fabs(s)*16;
768 wfwave = vertwater ? WATER_AMPLITUDE*s-WATER_OFFSET : -WATER_OFFSET;
769 float scroll = 16.0f*lastmillis/1000.0f;
770 float xscale = TEX_SCALE/(mslot->sts[1].t->xs*mslot->scale);
771 float yscale = -TEX_SCALE/(mslot->sts[1].t->ys*mslot->scale);
772 LOCALPARAMF(waterfalltexgen, xscale, yscale, 0.0f, scroll);
773 }
774 break;
775
776 case MAT_LAVA:
777 if(lastmat==m.material && lastorient!=O_TOP && m.orient!=O_TOP) break;
778 mslot = &lookupmaterialslot(m.material, false);
779 if(!mslot->loaded) continue;
780 else
781 {
782 int subslot = m.orient==O_TOP ? 0 : 1;
783 if(!mslot->sts.inrange(subslot)) continue;
784 changematerial(lastmat, lastorient);
785 glBindTexture(GL_TEXTURE_2D, mslot->sts[subslot].t->id);
786 }
787 if(lastmat!=m.material)
788 {
789 if(!depth) { glDepthMask(GL_TRUE); depth = true; }
790 if(blended) { glDisable(GL_BLEND); blended = false; }
791 float t = lastmillis/2000.0f;
792 t -= floor(t);
793 t = 1.0f - 2*fabs(t-0.5f);
794 extern int glare;
795 if(glare) t = 0.625f + 0.075f*t;
796 else t = 0.5f + 0.5f*t;
797 gle::colorf(t, t, t);
798 if(glaring) SETSHADER(lavaglare); else SETSHADER(lava);
799 fogtype = 1;
800 }
801 if(m.orient!=O_TOP)
802 {
803 float angle = fmod(float(lastmillis/2000.0f/(2*M_PI)), 1.0f),
804 s = angle - int(angle) - 0.5f;
805 s *= 8 - fabs(s)*16;
806 wfwave = vertwater ? WATER_AMPLITUDE*s-WATER_OFFSET : -WATER_OFFSET;
807 float scroll = 16.0f*lastmillis/3000.0f;
808 float xscale = TEX_SCALE/(mslot->sts[1].t->xs*mslot->scale);
809 float yscale = -TEX_SCALE/(mslot->sts[1].t->ys*mslot->scale);
810 LOCALPARAMF(lavatexgen, xscale, yscale, 0.0f, scroll);
811 }
812 else setuplava(mslot->sts[0].t, mslot->scale);
813 break;
814
815 case MAT_GLASS:
816 if((m.envmap==EMID_NONE || !glassenv || envmapped==m.envmap) && lastmat==m.material) break;
817 changematerial(lastmat, lastorient);
818 if(m.envmap!=EMID_NONE && glassenv && envmapped!=m.envmap)
819 {
820 glBindTexture(GL_TEXTURE_CUBE_MAP, lookupenvmap(m.envmap));
821 envmapped = m.envmap;
822 }
823 if(lastmat!=m.material)
824 {
825 if(!blended) { glEnable(GL_BLEND); blended = true; }
826 if(depth) { glDepthMask(GL_FALSE); depth = false; }
827 const bvec &gcol = getglasscolor(m.material);
828 if(m.envmap!=EMID_NONE && glassenv)
829 {
830 glBlendFunc(GL_ONE, GL_SRC_ALPHA);
831 gle::color(gcol);
832 SETSHADER(glass);
833 }
834 else
835 {
836 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
837 gle::color(gcol, 40);
838 foggednotextureshader->set();
839 fogtype = 1;
840 }
841 }
842 break;
843
844 default: continue;
845 }
846 lastmat = m.material;
847 lastorient = m.orient;
848 if(fogtype!=lastfogtype)
849 {
850 if(fogtype) resetfogcolor();
851 else zerofogcolor();
852 lastfogtype = fogtype;
853 }
854 }
855 switch(matvol)
856 {
857 case MAT_WATER:
858 renderwaterfall(m, 0.1f);
859 break;
860
861 case MAT_LAVA:
862 if(m.orient==O_TOP) renderlava(m);
863 else renderwaterfall(m, 0.1f);
864 break;
865
866 case MAT_GLASS:
867 drawglass(m, 0.1f);
868 break;
869 }
870 }
871
872 if(lastorient >= 0) changematerial(lastmat, lastorient);
873
874 if(!depth) glDepthMask(GL_TRUE);
875 if(blended) glDisable(GL_BLEND);
876 if(!lastfogtype) resetfogcolor();
877 extern int wireframe;
878 if(editmode && showmat && !drawtex && !wireframe)
879 {
880 foggednotextureshader->set();
881 rendermatgrid(vismats);
882 }
883
884 glEnable(GL_CULL_FACE);
885 }
886
887