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