1 // octarender.cpp: fill vertex arrays with different cube surfaces.
2
3 #include "engine.h"
4
5 struct vboinfo
6 {
7 int uses;
8 uchar *data;
9 };
10
11 hashtable<GLuint, vboinfo> vbos;
12
13 VAR(0, printvbo, 0, 0, 1);
14 VARFN(0, vbosize, maxvbosize, 0, 1<<14, 1<<16, allchanged());
15
16 enum
17 {
18 VBO_VBUF = 0,
19 VBO_EBUF,
20 VBO_SKYBUF,
21 VBO_DECALBUF,
22 NUMVBO
23 };
24
25 static vector<uchar> vbodata[NUMVBO];
26 static vector<vtxarray *> vbovas[NUMVBO];
27 static int vbosize[NUMVBO];
28
destroyvbo(GLuint vbo)29 void destroyvbo(GLuint vbo)
30 {
31 vboinfo *exists = vbos.access(vbo);
32 if(!exists) return;
33 vboinfo &vbi = *exists;
34 if(vbi.uses <= 0) return;
35 vbi.uses--;
36 if(!vbi.uses)
37 {
38 glDeleteBuffers_(1, &vbo);
39 if(vbi.data) delete[] vbi.data;
40 vbos.remove(vbo);
41 }
42 }
43
genvbo(int type,void * buf,int len,vtxarray ** vas,int numva)44 void genvbo(int type, void *buf, int len, vtxarray **vas, int numva)
45 {
46 gle::disable();
47
48 GLuint vbo;
49 glGenBuffers_(1, &vbo);
50 GLenum target = type==VBO_VBUF ? GL_ARRAY_BUFFER : GL_ELEMENT_ARRAY_BUFFER;
51 glBindBuffer_(target, vbo);
52 glBufferData_(target, len, buf, GL_STATIC_DRAW);
53 glBindBuffer_(target, 0);
54
55 vboinfo &vbi = vbos[vbo];
56 vbi.uses = numva;
57 vbi.data = new uchar[len];
58 memcpy(vbi.data, buf, len);
59
60 if(printvbo) conoutf("VBO %d: type %d, size %d, %d uses", vbo, type, len, numva);
61
62 loopi(numva)
63 {
64 vtxarray *va = vas[i];
65 switch(type)
66 {
67 case VBO_VBUF:
68 va->vbuf = vbo;
69 va->vdata = (vertex *)vbi.data;
70 break;
71 case VBO_EBUF:
72 va->ebuf = vbo;
73 va->edata = (ushort *)vbi.data;
74 break;
75 case VBO_SKYBUF:
76 va->skybuf = vbo;
77 va->skydata = (ushort *)vbi.data;
78 break;
79 case VBO_DECALBUF:
80 va->decalbuf = vbo;
81 va->decaldata = (ushort *)vbi.data;
82 break;
83 }
84 }
85 }
86
flushvbo(int type=-1)87 void flushvbo(int type = -1)
88 {
89 if(type < 0)
90 {
91 loopi(NUMVBO) flushvbo(i);
92 return;
93 }
94
95 vector<uchar> &data = vbodata[type];
96 if(data.empty()) return;
97 vector<vtxarray *> &vas = vbovas[type];
98 genvbo(type, data.getbuf(), data.length(), vas.getbuf(), vas.length());
99 data.setsize(0);
100 vas.setsize(0);
101 vbosize[type] = 0;
102 }
103
addvbo(vtxarray * va,int type,int numelems,int elemsize)104 uchar *addvbo(vtxarray *va, int type, int numelems, int elemsize)
105 {
106 switch(type)
107 {
108 case VBO_VBUF: va->voffset = vbosize[type]; break;
109 case VBO_EBUF: va->eoffset = vbosize[type]; break;
110 case VBO_SKYBUF: va->skyoffset = vbosize[type]; break;
111 case VBO_DECALBUF: va->decaloffset = vbosize[type]; break;
112 }
113
114 vbosize[type] += numelems;
115
116 vector<uchar> &data = vbodata[type];
117 vector<vtxarray *> &vas = vbovas[type];
118
119 vas.add(va);
120
121 int len = numelems*elemsize;
122 uchar *buf = data.reserve(len).buf;
123 data.advance(len);
124 return buf;
125 }
126
127 struct verthash
128 {
129 static const int SIZE = 1<<13;
130 int table[SIZE];
131 vector<vertex> verts;
132 vector<int> chain;
133
verthashverthash134 verthash() { clearverts(); }
135
clearvertsverthash136 void clearverts()
137 {
138 memset(table, -1, sizeof(table));
139 chain.setsize(0);
140 verts.setsize(0);
141 }
142
addvertverthash143 int addvert(const vertex &v)
144 {
145 uint h = hthash(v.pos)&(SIZE-1);
146 for(int i = table[h]; i>=0; i = chain[i])
147 {
148 const vertex &c = verts[i];
149 if(c.pos==v.pos && c.tc==v.tc && c.norm==v.norm && c.tangent==v.tangent)
150 return i;
151 }
152 if(verts.length() >= USHRT_MAX) return -1;
153 verts.add(v);
154 chain.add(table[h]);
155 return table[h] = verts.length()-1;
156 }
157
addvertverthash158 int addvert(const vec &pos, const vec &tc = vec(0, 0, 0), const bvec &norm = bvec(128, 128, 128), const bvec4 &tangent = bvec4(128, 128, 128, 128))
159 {
160 vertex vtx;
161 vtx.pos = pos;
162 vtx.tc = tc;
163 vtx.norm = norm;
164 vtx.tangent = tangent;
165 return addvert(vtx);
166 }
167 };
168
169 enum
170 {
171 NO_ALPHA = 0,
172 ALPHA_BACK,
173 ALPHA_FRONT,
174 ALPHA_REFRACT
175 };
176
compareentcolor(ushort entid1,ushort entid2)177 bool compareentcolor(ushort entid1, ushort entid2)
178 {
179 if(entid1 != USHRT_MAX && entid2 != USHRT_MAX)
180 {
181 const vector<extentity *> &ents = entities::getents();
182 bool found1 = ents.inrange(entid1) && ents[entid1]->type == ET_DECAL,
183 found2 = ents.inrange(entid2) && ents[entid2]->type == ET_DECAL;
184 if(found1 && found2)
185 {
186 int blend1 = ents[entid1]->attrs[5] > 0 && ents[entid1]->attrs[5] < 100 ? ents[entid1]->attrs[5] : 100,
187 blend2 = ents[entid2]->attrs[5] > 0 && ents[entid2]->attrs[5] < 100 ? ents[entid2]->attrs[5] : 100;
188 if(blend1 != blend2) return false;
189 int color1 = ents[entid1]->attrs[6] > 0 ? ents[entid1]->attrs[6] : 0xFFFFFF,
190 color2 = ents[entid2]->attrs[6] > 0 ? ents[entid2]->attrs[6] : 0xFFFFFF;
191 if(color1 != color2) return false;
192 int palette1 = ents[entid1]->attrs[7] || ents[entid1]->attrs[8] ? game::hexpalette(ents[entid1]->attrs[7], ents[entid1]->attrs[8]) : 0xFFFFFF,
193 palette2 = ents[entid2]->attrs[7] || ents[entid2]->attrs[8] ? game::hexpalette(ents[entid2]->attrs[7], ents[entid2]->attrs[8]) : 0xFFFFFF;
194 if(palette1 != palette2) return false;
195 }
196 else if(found1 || found2) return false;
197 }
198 else if(entid1 != USHRT_MAX || entid2 != USHRT_MAX) return false;
199 return true;
200 }
201
sortentcolor(ushort entid1,ushort entid2)202 int sortentcolor(ushort entid1, ushort entid2)
203 {
204 if(entid1 != USHRT_MAX && entid2 != USHRT_MAX)
205 {
206 const vector<extentity *> &ents = entities::getents();
207 bool found1 = ents.inrange(entid1), found2 = ents.inrange(entid2);
208 if(found1 && found2)
209 {
210 bool decal1 = ents[entid1]->type == ET_DECAL, decal2 = ents[entid2]->type == ET_DECAL;
211 if(decal1 && decal2)
212 {
213 int blend1 = ents[entid1]->attrs[5] > 0 && ents[entid1]->attrs[5] < 100 ? ents[entid1]->attrs[5] : 100,
214 blend2 = ents[entid2]->attrs[5] > 0 && ents[entid2]->attrs[5] < 100 ? ents[entid2]->attrs[5] : 100;
215 if(blend1 < blend2) return -1;
216 if(blend1 > blend2) return 1;
217 int color1 = ents[entid1]->attrs[6] > 0 ? ents[entid1]->attrs[6] : 0xFFFFFF,
218 color2 = ents[entid2]->attrs[6] > 0 ? ents[entid2]->attrs[6] : 0xFFFFFF;
219 if(color1 < color2) return -1;
220 if(color1 > color2) return 1;
221 int palette1 = ents[entid1]->attrs[7] || ents[entid1]->attrs[8] ? game::hexpalette(ents[entid1]->attrs[7], ents[entid1]->attrs[8]) : 0xFFFFFF,
222 palette2 = ents[entid2]->attrs[7] || ents[entid2]->attrs[8] ? game::hexpalette(ents[entid2]->attrs[7], ents[entid2]->attrs[8]) : 0xFFFFFF;
223 if(palette1 < palette2) return -1;
224 if(palette1 > palette2) return 1;
225 }
226 else if(decal1) return -1;
227 else if(decal2) return 1;
228 }
229 else if(found1) return -1;
230 else if(found2) return 1;
231 }
232 else if(entid1 != USHRT_MAX) return -1;
233 else if(entid2 != USHRT_MAX) return 1;
234 return 0;
235 }
236
237
238 struct sortkey
239 {
240 ushort tex, envmap, entid;
241 uchar orient, layer, alpha;
242
sortkeysortkey243 sortkey() {}
sortkeysortkey244 sortkey(ushort tex, uchar orient, uchar layer = LAYER_TOP, ushort envmap = EMID_NONE, uchar alpha = NO_ALPHA, ushort entid = USHRT_MAX)
245 : tex(tex), envmap(envmap), entid(entid), orient(orient), layer(layer), alpha(alpha)
246 {}
247
operator ==sortkey248 bool operator==(const sortkey &o) const { return tex==o.tex && envmap==o.envmap && orient==o.orient && layer==o.layer && alpha==o.alpha && compareentcolor(entid, o.entid); }
249
sortsortkey250 static inline bool sort(const sortkey &x, const sortkey &y)
251 {
252 if(x.alpha < y.alpha) return true;
253 if(x.alpha > y.alpha) return false;
254 if(x.layer < y.layer) return true;
255 if(x.layer > y.layer) return false;
256 if(x.tex == y.tex)
257 {
258 if(x.envmap < y.envmap) return true;
259 if(x.envmap > y.envmap) return false;
260 if(x.orient < y.orient) return true;
261 if(x.orient > y.orient) return false;
262 return false;
263 }
264 VSlot &xs = lookupvslot(x.tex, false), &ys = lookupvslot(y.tex, false);
265 if(xs.slot->shader < ys.slot->shader) return true;
266 if(xs.slot->shader > ys.slot->shader) return false;
267 if(xs.slot->params.length() < ys.slot->params.length()) return true;
268 if(xs.slot->params.length() > ys.slot->params.length()) return false;
269 if(x.tex < y.tex) return true;
270 if(x.tex > y.tex) return false;
271 return sortentcolor(x.entid, y.entid) < 0;
272 }
273 };
274
htcmp(const sortkey & x,const sortkey & y)275 static inline bool htcmp(const sortkey &x, const sortkey &y)
276 {
277 return x == y;
278 }
279
hthash(const sortkey & k)280 static inline uint hthash(const sortkey &k)
281 {
282 return k.tex;
283 }
284
285 struct decalkey
286 {
287 ushort tex, envmap, reuse, entid;
288
decalkeydecalkey289 decalkey() {}
decalkeydecalkey290 decalkey(ushort tex, ushort envmap = EMID_NONE, ushort reuse = 0, ushort entid = USHRT_MAX)
291 : tex(tex), envmap(envmap), reuse(reuse), entid(entid)
292 {}
293
operator ==decalkey294 bool operator==(const decalkey &o) const { return tex==o.tex && envmap==o.envmap && reuse==o.reuse && compareentcolor(entid, o.entid); }
295
sortdecalkey296 static inline bool sort(const decalkey &x, const decalkey &y)
297 {
298 if(x.tex == y.tex)
299 {
300 if(x.envmap < y.envmap) return true;
301 if(x.envmap > y.envmap) return false;
302 if(x.reuse < y.reuse) return true;
303 else return false;
304 }
305 DecalSlot &xs = lookupdecalslot(x.tex, false), &ys = lookupdecalslot(y.tex, false);
306 if(xs.slot->shader < ys.slot->shader) return true;
307 if(xs.slot->shader > ys.slot->shader) return false;
308 if(xs.slot->params.length() < ys.slot->params.length()) return true;
309 if(xs.slot->params.length() > ys.slot->params.length()) return false;
310 if(x.tex < y.tex) return true;
311 if(x.tex > y.tex) return false;
312 return sortentcolor(x.entid, y.entid);
313 }
314 };
315
htcmp(const decalkey & x,const decalkey & y)316 static inline bool htcmp(const decalkey &x, const decalkey &y)
317 {
318 return x == y;
319 }
320
hthash(const decalkey & k)321 static inline uint hthash(const decalkey &k)
322 {
323 return k.tex;
324 }
325
326 struct sortval
327 {
328 vector<ushort> tris;
329
sortvalsortval330 sortval() {}
331 };
332 struct vacollect : verthash
333 {
334 ivec origin;
335 int size;
336 hashtable<sortkey, sortval> indices;
337 hashtable<decalkey, sortval> decalindices;
338 vector<ushort> skyindices;
339 vector<sortkey> texs;
340 vector<decalkey> decaltexs;
341 vector<grasstri> grasstris;
342 vector<materialsurface> matsurfs;
343 vector<octaentities *> mapmodels, decals, extdecals;
344 int worldtris, skytris, decaltris;
345 vec alphamin, alphamax;
346 vec refractmin, refractmax;
347 vec skymin, skymax;
348 ivec nogimin, nogimax;
349
clearvacollect350 void clear()
351 {
352 clearverts();
353 worldtris = skytris = decaltris = 0;
354 indices.clear();
355 decalindices.clear();
356 skyindices.setsize(0);
357 matsurfs.setsize(0);
358 mapmodels.setsize(0);
359 decals.setsize(0);
360 extdecals.setsize(0);
361 grasstris.setsize(0);
362 texs.setsize(0);
363 decaltexs.setsize(0);
364 alphamin = refractmin = skymin = vec(1e16f, 1e16f, 1e16f);
365 alphamax = refractmax = skymax = vec(-1e16f, -1e16f, -1e16f);
366 nogimin = ivec(INT_MAX, INT_MAX, INT_MAX);
367 nogimax = ivec(INT_MIN, INT_MIN, INT_MIN);
368 }
369
optimizevacollect370 void optimize()
371 {
372 enumeratekt(indices, sortkey, k, sortval, t,
373 {
374 if(t.tris.length()) texs.add(k);
375 });
376 texs.sort(sortkey::sort);
377
378 matsurfs.shrink(optimizematsurfs(matsurfs.getbuf(), matsurfs.length()));
379 }
380
381 #define GENVERTS(type, ptr, body) do \
382 { \
383 type *f = (type *)ptr; \
384 loopv(verts) \
385 { \
386 const vertex &v = verts[i]; \
387 body; \
388 f++; \
389 } \
390 } while(0)
391
genvertsvacollect392 void genverts(void *buf)
393 {
394 GENVERTS(vertex, buf, { *f = v; f->norm.flip(); f->tangent.flip(); });
395 }
396
gendecalvacollect397 void gendecal(const extentity &e, DecalSlot &s, const decalkey &key)
398 {
399 matrix3 orient;
400 orient.identity();
401 if(e.attrs[1]) orient.rotate_around_z(sincosmod360(e.attrs[1]));
402 if(e.attrs[2]) orient.rotate_around_x(sincosmod360(e.attrs[2]));
403 if(e.attrs[3]) orient.rotate_around_y(sincosmod360(-e.attrs[3]));
404 vec size(max(float(e.attrs[4]), 1.0f));
405 size.y *= s.depth;
406 if(!s.sts.empty())
407 {
408 Texture *t = s.sts[0].t;
409 if(t->xs < t->ys) size.x *= t->xs / float(t->ys);
410 else if(t->xs > t->ys) size.z *= t->ys / float(t->xs);
411 }
412 vec center = orient.transform(vec(0, size.y*0.5f, 0)).add(e.o), radius = orient.abstransform(vec(size).mul(0.5f));
413 vec bbmin = vec(center).sub(radius), bbmax = vec(center).add(radius);
414 vec clipoffset = orient.transposedtransform(center).msub(size, 0.5f);
415 loopv(texs)
416 {
417 const sortkey &k = texs[i];
418 if(k.layer == LAYER_BLEND || k.alpha != NO_ALPHA) continue;
419 const sortval &t = indices[k];
420 if(t.tris.empty()) continue;
421 decalkey tkey(key);
422 if(shouldreuseparams(s, lookupvslot(k.tex, false))) tkey.reuse = k.tex;
423 for(int j = 0; j < t.tris.length(); j += 3)
424 {
425 const vertex &t0 = verts[t.tris[j]], &t1 = verts[t.tris[j+1]], &t2 = verts[t.tris[j+2]];
426 vec v0 = t0.pos, v1 = t1.pos, v2 = t2.pos;
427 vec tmin = vec(v0).min(v1).min(v2), tmax = vec(v0).max(v1).max(v2);
428 if(tmin.x >= bbmax.x || tmin.y >= bbmax.y || tmin.z >= bbmax.z ||
429 tmax.x <= bbmin.x || tmax.y <= bbmin.y || tmax.z <= bbmin.z)
430 continue;
431 float f0 = t0.norm.tonormal().dot(orient.b), f1 = t1.norm.tonormal().dot(orient.b), f2 = t2.norm.tonormal().dot(orient.b);
432 if(f0 >= 0 && f1 >= 0 && f2 >= 0) continue;
433 vec p1[9], p2[9];
434 p1[0] = v0; p1[1] = v1; p1[2] = v2;
435 int nump = polyclip(p1, 3, orient.b, clipoffset.y, clipoffset.y + size.y, p2);
436 if(nump < 3) continue;
437 nump = polyclip(p2, nump, orient.a, clipoffset.x, clipoffset.x + size.x, p1);
438 if(nump < 3) continue;
439 nump = polyclip(p1, nump, orient.c, clipoffset.z, clipoffset.z + size.z, p2);
440 if(nump < 3) continue;
441
442 bvec4 n0 = t0.norm, n1 = t1.norm, n2 = t2.norm,
443 x0 = t0.tangent, x1 = t1.tangent, x2 = t2.tangent;
444 vec e1 = vec(v1).sub(v0), e2 = vec(v2).sub(v0);
445 float d11 = e1.dot(e1), d12 = e1.dot(e2), d22 = e2.dot(e2);
446 int idx[9];
447 loopk(nump)
448 {
449 vertex v;
450 v.pos = p2[k];
451 vec ep = vec(v.pos).sub(v0);
452 float dp1 = ep.dot(e1), dp2 = ep.dot(e2), denom = d11*d22 - d12*d12,
453 b1 = (d22*dp1 - d12*dp2) / denom,
454 b2 = (d11*dp2 - d12*dp1) / denom,
455 b0 = 1 - b1 - b2;
456 v.norm.lerp(n0, n1, n2, b0, b1, b2);
457 v.norm.w = uchar(127.5f - 127.5f*(f0*b0 + f1*b1 + f2*b2));
458 vec tc = orient.transposedtransform(vec(center).sub(v.pos)).div(size).add(0.5f);
459 v.tc = vec(tc.x, tc.z, s.fade ? tc.y * s.depth / s.fade : 1.0f);
460 v.tangent.lerp(x0, x1, x2, b0, b1, b2);
461 idx[k] = addvert(v);
462 }
463 vector<ushort> &tris = decalindices[tkey].tris;
464 loopk(nump-2) if(idx[0] != idx[k+1] && idx[k+1] != idx[k+2] && idx[k+2] != idx[0])
465 {
466 tris.add(idx[0]);
467 tris.add(idx[k+1]);
468 tris.add(idx[k+2]);
469 decaltris += 3;
470 }
471 }
472 }
473 }
474
gendecalsvacollect475 void gendecals()
476 {
477 if(decals.length()) extdecals.put(decals.getbuf(), decals.length());
478 if(extdecals.empty()) return;
479 vector<extentity *> &ents = entities::getents();
480 loopv(extdecals)
481 {
482 octaentities *oe = extdecals[i];
483 loopvj(oe->decals)
484 {
485 extentity &e = *ents[oe->decals[j]];
486 if(e.flags&EF_RENDER || !checkmapvariant(e.attrs[9]) || !checkmapeffects(e.attrs[10])) continue;
487 e.flags |= EF_RENDER;
488 DecalSlot &s = lookupdecalslot(e.attrs[0], true);
489 if(!s.shader) continue;
490 ushort envmap = s.shader->type&SHADER_ENVMAP ? (s.texmask&(1<<TEX_ENVMAP) ? EMID_CUSTOM : closestenvmap(e.o)) : EMID_NONE;
491 decalkey k(e.attrs[0], envmap, 0, oe->decals[j]);
492 gendecal(e, s, k);
493 }
494 }
495 loopv(extdecals)
496 {
497 octaentities *oe = extdecals[i];
498 loopvj(oe->decals)
499 {
500 extentity &e = *ents[oe->decals[j]];
501 if(e.flags&EF_RENDER) e.flags &= ~EF_RENDER;
502 }
503 }
504 enumeratekt(decalindices, decalkey, k, sortval, t,
505 {
506 if(t.tris.length()) decaltexs.add(k);
507 });
508 decaltexs.sort(decalkey::sort);
509 }
510
setupdatavacollect511 void setupdata(vtxarray *va)
512 {
513 optimize();
514 gendecals();
515
516 va->verts = verts.length();
517 va->tris = worldtris/3;
518 va->vbuf = 0;
519 va->vdata = 0;
520 va->minvert = 0;
521 va->maxvert = va->verts-1;
522 va->voffset = 0;
523 if(va->verts)
524 {
525 if(vbosize[VBO_VBUF] + verts.length() > maxvbosize ||
526 vbosize[VBO_EBUF] + worldtris > USHRT_MAX ||
527 vbosize[VBO_SKYBUF] + skytris > USHRT_MAX ||
528 vbosize[VBO_DECALBUF] + decaltris > USHRT_MAX)
529 flushvbo();
530
531 uchar *vdata = addvbo(va, VBO_VBUF, va->verts, sizeof(vertex));
532 genverts(vdata);
533 va->minvert += va->voffset;
534 va->maxvert += va->voffset;
535 }
536
537 va->matbuf = NULL;
538 va->matsurfs = matsurfs.length();
539 va->matmask = 0;
540 if(va->matsurfs)
541 {
542 va->matbuf = new materialsurface[matsurfs.length()];
543 memcpy(va->matbuf, matsurfs.getbuf(), matsurfs.length()*sizeof(materialsurface));
544 loopv(matsurfs)
545 {
546 materialsurface &m = matsurfs[i];
547 if(m.visible == MATSURF_EDIT_ONLY) continue;
548 switch(m.material)
549 {
550 case MAT_GLASS: case MAT_LAVA: case MAT_WATER: break;
551 default: continue;
552 }
553 va->matmask |= 1<<m.material;
554 }
555 }
556
557 va->skybuf = 0;
558 va->skydata = 0;
559 va->skyoffset = 0;
560 va->sky = skyindices.length();
561 if(va->sky)
562 {
563 ushort *skydata = (ushort *)addvbo(va, VBO_SKYBUF, va->sky, sizeof(ushort));
564 memcpy(skydata, skyindices.getbuf(), va->sky*sizeof(ushort));
565 if(va->voffset) loopi(va->sky) skydata[i] += va->voffset;
566 }
567
568 va->texelems = NULL;
569 va->texs = texs.length();
570 va->blendtris = 0;
571 va->blends = 0;
572 va->alphabacktris = 0;
573 va->alphaback = 0;
574 va->alphafronttris = 0;
575 va->alphafront = 0;
576 va->refracttris = 0;
577 va->refract = 0;
578 va->ebuf = 0;
579 va->edata = 0;
580 va->eoffset = 0;
581 if(va->texs)
582 {
583 va->texelems = new elementset[va->texs];
584 ushort *edata = (ushort *)addvbo(va, VBO_EBUF, worldtris, sizeof(ushort)), *curbuf = edata;
585 loopv(texs)
586 {
587 const sortkey &k = texs[i];
588 const sortval &t = indices[k];
589 elementset &e = va->texelems[i];
590 e.texture = k.tex;
591 e.orient = k.orient;
592 e.layer = k.layer;
593 e.envmap = k.envmap;
594 e.entid = k.entid;
595 ushort *startbuf = curbuf;
596 e.minvert = USHRT_MAX;
597 e.maxvert = 0;
598
599 if(t.tris.length())
600 {
601 memcpy(curbuf, t.tris.getbuf(), t.tris.length() * sizeof(ushort));
602
603 loopvj(t.tris)
604 {
605 curbuf[j] += va->voffset;
606 e.minvert = min(e.minvert, curbuf[j]);
607 e.maxvert = max(e.maxvert, curbuf[j]);
608 }
609
610 curbuf += t.tris.length();
611 }
612 e.length = curbuf-startbuf;
613
614 if(k.layer==LAYER_BLEND) { va->texs--; va->tris -= e.length/3; va->blends++; va->blendtris += e.length/3; }
615 else if(k.alpha==ALPHA_BACK) { va->texs--; va->tris -= e.length/3; va->alphaback++; va->alphabacktris += e.length/3; }
616 else if(k.alpha==ALPHA_FRONT) { va->texs--; va->tris -= e.length/3; va->alphafront++; va->alphafronttris += e.length/3; }
617 else if(k.alpha==ALPHA_REFRACT) { va->texs--; va->tris -= e.length/3; va->refract++; va->refracttris += e.length/3; }
618 }
619 }
620
621 va->texmask = 0;
622 va->dyntexs = 0;
623 loopi(va->texs+va->blends+va->alphaback+va->alphafront+va->refract)
624 {
625 VSlot &vslot = lookupvslot(va->texelems[i].texture, false);
626 if(vslot.isdynamic()) va->dyntexs++;
627 Slot &slot = *vslot.slot;
628 loopvj(slot.sts) va->texmask |= 1<<slot.sts[j].type;
629 if(slot.shader && slot.shader->type&SHADER_ENVMAP) va->texmask |= 1<<TEX_ENVMAP;
630 }
631
632 va->decalbuf = 0;
633 va->decaldata = 0;
634 va->decaloffset = 0;
635 va->decalelems = NULL;
636 va->decaltexs = decaltexs.length();
637 va->decaltris = decaltris/3;
638 if(va->decaltexs)
639 {
640 va->decalelems = new elementset[va->decaltexs];
641 ushort *edata = (ushort *)addvbo(va, VBO_DECALBUF, decaltris, sizeof(ushort)), *curbuf = edata;
642 loopv(decaltexs)
643 {
644 const decalkey &k = decaltexs[i];
645 const sortval &t = decalindices[k];
646 elementset &e = va->decalelems[i];
647 e.texture = k.tex;
648 e.reuse = k.reuse;
649 e.envmap = k.envmap;
650 e.entid = k.entid;
651 ushort *startbuf = curbuf;
652 e.minvert = USHRT_MAX;
653 e.maxvert = 0;
654
655 if(t.tris.length())
656 {
657 memcpy(curbuf, t.tris.getbuf(), t.tris.length() * sizeof(ushort));
658
659 loopvj(t.tris)
660 {
661 curbuf[j] += va->voffset;
662 e.minvert = min(e.minvert, curbuf[j]);
663 e.maxvert = max(e.maxvert, curbuf[j]);
664 }
665
666 curbuf += t.tris.length();
667 }
668 e.length = curbuf-startbuf;
669 }
670 }
671
672 if(grasstris.length())
673 {
674 va->grasstris.move(grasstris);
675 loadgrassshaders();
676 }
677
678 if(mapmodels.length()) va->mapmodels.put(mapmodels.getbuf(), mapmodels.length());
679 if(decals.length()) va->decals.put(decals.getbuf(), decals.length());
680 }
681
emptyvavacollect682 bool emptyva()
683 {
684 return verts.empty() && matsurfs.empty() && skyindices.empty() && grasstris.empty() && mapmodels.empty() && decals.empty();
685 }
686 } vc;
687
688 int recalcprogress = 0;
689 #define rcprogress(s) if((recalcprogress++&0xFFF)==0) progress(recalcprogress/(float)allocnodes, s);
690
691 vector<tjoint> tjoints;
692
693 VARF(IDF_PERSIST, filltjoints, 0, 1, 1, allchanged());
694
reduceslope(ivec & n)695 void reduceslope(ivec &n)
696 {
697 int mindim = -1, minval = 64;
698 loopi(3) if(n[i])
699 {
700 int val = abs(n[i]);
701 if(mindim < 0 || val < minval)
702 {
703 mindim = i;
704 minval = val;
705 }
706 }
707 if(!(n[R[mindim]]%minval) && !(n[C[mindim]]%minval)) n.div(minval);
708 while(!((n.x|n.y|n.z)&1)) n.shr(1);
709 }
710
711 // [rotation][orient]
712 extern const vec orientation_tangent[8][6] =
713 {
714 { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
715 { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) },
716 { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
717 { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) },
718 { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
719 { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
720 { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) },
721 { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) },
722 };
723 extern const vec orientation_bitangent[8][6] =
724 {
725 { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) },
726 { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
727 { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) },
728 { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
729 { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) },
730 { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) },
731 { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
732 { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
733 };
734
addtris(VSlot & vslot,int orient,const sortkey & key,vertex * verts,int * index,int numverts,int convex,int tj)735 void addtris(VSlot &vslot, int orient, const sortkey &key, vertex *verts, int *index, int numverts, int convex, int tj)
736 {
737 int &total = key.tex==DEFAULT_SKY ? vc.skytris : vc.worldtris;
738 int edge = orient*(MAXFACEVERTS+1);
739 loopi(numverts-2) if(index[0]!=index[i+1] && index[i+1]!=index[i+2] && index[i+2]!=index[0])
740 {
741 vector<ushort> &idxs = key.tex==DEFAULT_SKY ? vc.skyindices : vc.indices[key].tris;
742 int left = index[0], mid = index[i+1], right = index[i+2], start = left, i0 = left, i1 = -1;
743 loopk(4)
744 {
745 int i2 = -1, ctj = -1, cedge = -1;
746 switch(k)
747 {
748 case 1: i1 = i2 = mid; cedge = edge+i+1; break;
749 case 2: if(i1 != mid || i0 == left) { i0 = i1; i1 = right; } i2 = right; if(i+1 == numverts-2) cedge = edge+i+2; break;
750 case 3: if(i0 == start) { i0 = i1; i1 = left; } i2 = left; // fall-through
751 default: if(!i) cedge = edge; break;
752 }
753 if(i1 != i2)
754 {
755 if(total + 3 > USHRT_MAX) return;
756 total += 3;
757 idxs.add(i0);
758 idxs.add(i1);
759 idxs.add(i2);
760 i1 = i2;
761 }
762 if(cedge >= 0)
763 {
764 for(ctj = tj;;)
765 {
766 if(ctj < 0) break;
767 if(tjoints[ctj].edge < cedge) { ctj = tjoints[ctj].next; continue; }
768 if(tjoints[ctj].edge != cedge) ctj = -1;
769 break;
770 }
771 }
772 if(ctj >= 0)
773 {
774 int e1 = cedge%(MAXFACEVERTS+1), e2 = (e1+1)%numverts;
775 vertex &v1 = verts[e1], &v2 = verts[e2];
776 ivec d(vec(v2.pos).sub(v1.pos).mul(8));
777 int axis = abs(d.x) > abs(d.y) ? (abs(d.x) > abs(d.z) ? 0 : 2) : (abs(d.y) > abs(d.z) ? 1 : 2);
778 if(d[axis] < 0) d.neg();
779 reduceslope(d);
780 int origin = int(min(v1.pos[axis], v2.pos[axis])*8)&~0x7FFF,
781 offset1 = (int(v1.pos[axis]*8) - origin) / d[axis],
782 offset2 = (int(v2.pos[axis]*8) - origin) / d[axis];
783 vec o = vec(v1.pos).sub(vec(d).mul(offset1/8.0f));
784 float doffset = 1.0f / (offset2 - offset1);
785
786 if(i1 < 0) for(;;)
787 {
788 tjoint &t = tjoints[ctj];
789 if(t.next < 0 || tjoints[t.next].edge != cedge) break;
790 ctj = t.next;
791 }
792 while(ctj >= 0)
793 {
794 tjoint &t = tjoints[ctj];
795 if(t.edge != cedge) break;
796 float offset = (t.offset - offset1) * doffset;
797 vertex vt;
798 vt.pos = vec(d).mul(t.offset/8.0f).add(o);
799 vt.tc.lerp(v1.tc, v2.tc, offset);
800 vt.norm.lerp(v1.norm, v2.norm, offset);
801 vt.tangent.lerp(v1.tangent, v2.tangent, offset);
802 if(v1.tangent.w != v2.tangent.w)
803 vt.tangent.w = orientation_bitangent[vslot.rotation][orient].scalartriple(vt.norm.tonormal(), vt.tangent.tonormal()) < 0 ? 0 : 255;
804 int i2 = vc.addvert(vt);
805 if(i2 < 0) return;
806 if(i1 >= 0)
807 {
808 if(total + 3 > USHRT_MAX) return;
809 total += 3;
810 idxs.add(i0);
811 idxs.add(i1);
812 idxs.add(i2);
813 i1 = i2;
814 }
815 else start = i0 = i2;
816 ctj = t.next;
817 }
818 }
819 }
820 }
821 }
822
addgrasstri(int face,vertex * verts,int numv,ushort texture,int layer)823 void addgrasstri(int face, vertex *verts, int numv, ushort texture, int layer)
824 {
825 grasstri &g = vc.grasstris.add();
826 int i1, i2, i3, i4;
827 if(numv <= 3 && face%2) { i1 = face+1; i2 = face+2; i3 = i4 = 0; }
828 else { i1 = 0; i2 = face+1; i3 = face+2; i4 = numv > 3 ? face+3 : i3; }
829 g.v[0] = verts[i1].pos;
830 g.v[1] = verts[i2].pos;
831 g.v[2] = verts[i3].pos;
832 g.v[3] = verts[i4].pos;
833 g.numv = numv;
834
835 g.surface.toplane(g.v[0], g.v[1], g.v[2]);
836 if(g.surface.z <= 0) { vc.grasstris.pop(); return; }
837
838 g.minz = min(min(g.v[0].z, g.v[1].z), min(g.v[2].z, g.v[3].z));
839 g.maxz = max(max(g.v[0].z, g.v[1].z), max(g.v[2].z, g.v[3].z));
840
841 g.center = vec(0, 0, 0);
842 loopk(numv) g.center.add(g.v[k]);
843 g.center.div(numv);
844 g.radius = 0;
845 loopk(numv) g.radius = max(g.radius, g.v[k].dist(g.center));
846
847 g.texture = texture;
848 g.blend = layer == LAYER_BLEND ? ((int(g.center.x)>>12)+1) | (((int(g.center.y)>>12)+1)<<8) : 0;
849 }
850
calctexgen(VSlot & vslot,int orient,vec4 & sgen,vec4 & tgen)851 static inline void calctexgen(VSlot &vslot, int orient, vec4 &sgen, vec4 &tgen)
852 {
853 Texture *tex = vslot.slot->sts.empty() ? notexture : vslot.slot->sts[0].t;
854 const texrotation &r = texrotations[vslot.rotation];
855 float k = TEX_SCALE/vslot.scale,
856 xs = r.flipx ? -tex->xs : tex->xs,
857 ys = r.flipy ? -tex->ys : tex->ys,
858 sk = k/xs, tk = k/ys,
859 soff = -(r.swapxy ? vslot.offset.y : vslot.offset.x)/xs,
860 toff = -(r.swapxy ? vslot.offset.x : vslot.offset.y)/ys;
861 sgen = vec4(0, 0, 0, soff);
862 tgen = vec4(0, 0, 0, toff);
863 if(r.swapxy) switch(orient)
864 {
865 case 0: sgen.z = -sk; tgen.y = tk; break;
866 case 1: sgen.z = -sk; tgen.y = -tk; break;
867 case 2: sgen.z = -sk; tgen.x = -tk; break;
868 case 3: sgen.z = -sk; tgen.x = tk; break;
869 case 4: sgen.y = -sk; tgen.x = tk; break;
870 case 5: sgen.y = sk; tgen.x = tk; break;
871 }
872 else switch(orient)
873 {
874 case 0: sgen.y = sk; tgen.z = -tk; break;
875 case 1: sgen.y = -sk; tgen.z = -tk; break;
876 case 2: sgen.x = -sk; tgen.z = -tk; break;
877 case 3: sgen.x = sk; tgen.z = -tk; break;
878 case 4: sgen.x = sk; tgen.y = -tk; break;
879 case 5: sgen.x = sk; tgen.y = tk; break;
880 }
881 }
882
encodenormal(const vec & n)883 ushort encodenormal(const vec &n)
884 {
885 if(n.iszero()) return 0;
886 int yaw = int(-atan2(n.x, n.y)/RAD), pitch = int(asin(n.z)/RAD);
887 return ushort(clamp(pitch + 90, 0, 180)*360 + (yaw < 0 ? yaw%360 + 360 : yaw%360) + 1);
888 }
889
decodenormal(ushort norm)890 vec decodenormal(ushort norm)
891 {
892 if(!norm) return vec(0, 0, 1);
893 norm--;
894 const vec2 &yaw = sincos360[norm%360], &pitch = sincos360[norm/360+270];
895 return vec(-yaw.y*pitch.x, yaw.x*pitch.x, pitch.y);
896 }
897
guessnormals(const vec * pos,int numverts,vec * normals)898 void guessnormals(const vec *pos, int numverts, vec *normals)
899 {
900 vec n1, n2;
901 n1.cross(pos[0], pos[1], pos[2]);
902 if(numverts != 4)
903 {
904 n1.normalize();
905 loopk(numverts) normals[k] = n1;
906 return;
907 }
908 n2.cross(pos[0], pos[2], pos[3]);
909 if(n1.iszero())
910 {
911 n2.normalize();
912 loopk(4) normals[k] = n2;
913 return;
914 }
915 else n1.normalize();
916 if(n2.iszero())
917 {
918 loopk(4) normals[k] = n1;
919 return;
920 }
921 else n2.normalize();
922 vec avg = vec(n1).add(n2).normalize();
923 normals[0] = avg;
924 normals[1] = n1;
925 normals[2] = avg;
926 normals[3] = n2;
927 }
928
addcubeverts(VSlot & vslot,int orient,int size,vec * pos,int convex,ushort texture,vertinfo * vinfo,int numverts,int tj=-1,ushort envmap=EMID_NONE,int grassy=0,bool alpha=false,int layer=LAYER_TOP)929 void addcubeverts(VSlot &vslot, int orient, int size, vec *pos, int convex, ushort texture, vertinfo *vinfo, int numverts, int tj = -1, ushort envmap = EMID_NONE, int grassy = 0, bool alpha = false, int layer = LAYER_TOP)
930 {
931 vec4 sgen, tgen;
932 calctexgen(vslot, orient, sgen, tgen);
933 vertex verts[MAXFACEVERTS];
934 int index[MAXFACEVERTS];
935 vec normals[MAXFACEVERTS];
936 loopk(numverts)
937 {
938 vertex &v = verts[k];
939 v.pos = pos[k];
940 v.tc = vec(sgen.dot(v.pos), tgen.dot(v.pos), 0);
941 if(vinfo && vinfo[k].norm)
942 {
943 vec n = decodenormal(vinfo[k].norm), t = orientation_tangent[vslot.rotation][orient];
944 t.project(n).normalize();
945 v.norm = bvec(n);
946 v.tangent = bvec4(bvec(t), orientation_bitangent[vslot.rotation][orient].scalartriple(n, t) < 0 ? 0 : 255);
947 }
948 else if(texture != DEFAULT_SKY)
949 {
950 if(!k) guessnormals(pos, numverts, normals);
951 const vec &n = normals[k];
952 vec t = orientation_tangent[vslot.rotation][orient];
953 t.project(n).normalize();
954 v.norm = bvec(n);
955 v.tangent = bvec4(bvec(t), orientation_bitangent[vslot.rotation][orient].scalartriple(n, t) < 0 ? 0 : 255);
956 }
957 else
958 {
959 v.norm = bvec(128, 128, 255);
960 v.tangent = bvec4(255, 128, 128, 255);
961 }
962 index[k] = vc.addvert(v);
963 if(index[k] < 0) return;
964 }
965
966 if(alpha)
967 {
968 loopk(numverts) { vc.alphamin.min(pos[k]); vc.alphamax.max(pos[k]); }
969 if(vslot.refractscale > 0) loopk(numverts) { vc.refractmin.min(pos[k]); vc.refractmax.max(pos[k]); }
970 }
971 if(texture == DEFAULT_SKY) loopi(numverts) if(pos[i][orient>>1] != ((orient&1)<<worldscale))
972 {
973 loopk(numverts) { vc.skymin.min(pos[k]); vc.skymax.max(pos[k]); }
974 break;
975 }
976
977 sortkey key(texture, vslot.scroll.iszero() ? O_ANY : orient, layer&LAYER_BOTTOM ? layer : LAYER_TOP, envmap, alpha ? (vslot.refractscale > 0 ? ALPHA_REFRACT : (vslot.alphaback ? ALPHA_BACK : ALPHA_FRONT)) : NO_ALPHA);
978 addtris(vslot, orient, key, verts, index, numverts, convex, tj);
979
980 if(grassy)
981 {
982 for(int i = 0; i < numverts-2; i += 2)
983 {
984 int faces = 0;
985 if(index[0]!=index[i+1] && index[i+1]!=index[i+2] && index[i+2]!=index[0]) faces |= 1;
986 if(i+3 < numverts && index[0]!=index[i+2] && index[i+2]!=index[i+3] && index[i+3]!=index[0]) faces |= 2;
987 if(grassy > 1 && faces==3) addgrasstri(i, verts, 4, texture, layer);
988 else
989 {
990 if(faces&1) addgrasstri(i, verts, 3, texture, layer);
991 if(faces&2) addgrasstri(i+1, verts, 3, texture, layer);
992 }
993 }
994 }
995 }
996
997 struct edgegroup
998 {
999 ivec slope, origin;
1000 int axis;
1001 };
1002
hthash(const edgegroup & g)1003 static inline uint hthash(const edgegroup &g)
1004 {
1005 return g.slope.x^g.slope.y^g.slope.z^g.origin.x^g.origin.y^g.origin.z;
1006 }
1007
htcmp(const edgegroup & x,const edgegroup & y)1008 static inline bool htcmp(const edgegroup &x, const edgegroup &y)
1009 {
1010 return x.slope==y.slope && x.origin==y.origin;
1011 }
1012
1013 enum
1014 {
1015 CE_START = 1<<0,
1016 CE_END = 1<<1,
1017 CE_FLIP = 1<<2,
1018 CE_DUP = 1<<3
1019 };
1020
1021 struct cubeedge
1022 {
1023 cube *c;
1024 int next, offset;
1025 ushort size;
1026 uchar index, flags;
1027 };
1028
1029 vector<cubeedge> cubeedges;
1030 hashtable<edgegroup, int> edgegroups(1<<13);
1031
gencubeedges(cube & c,const ivec & co,int size)1032 void gencubeedges(cube &c, const ivec &co, int size)
1033 {
1034 ivec pos[MAXFACEVERTS];
1035 int vis;
1036 loopi(6) if((vis = visibletris(c, i, co, size)))
1037 {
1038 int numverts = c.ext ? c.ext->surfaces[i].numverts&MAXFACEVERTS : 0;
1039 if(numverts)
1040 {
1041 vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
1042 ivec vo = ivec(co).mask(~0xFFF).shl(3);
1043 loopj(numverts)
1044 {
1045 vertinfo &v = verts[j];
1046 pos[j] = ivec(v.x, v.y, v.z).add(vo);
1047 }
1048 }
1049 else if(c.merged&(1<<i)) continue;
1050 else
1051 {
1052 ivec v[4];
1053 genfaceverts(c, i, v);
1054 int order = vis&4 || (!flataxisface(c, i) && faceconvexity(v) < 0) ? 1 : 0;
1055 ivec vo = ivec(co).shl(3);
1056 pos[numverts++] = v[order].mul(size).add(vo);
1057 if(vis&1) pos[numverts++] = v[order+1].mul(size).add(vo);
1058 pos[numverts++] = v[order+2].mul(size).add(vo);
1059 if(vis&2) pos[numverts++] = v[(order+3)&3].mul(size).add(vo);
1060 }
1061 loopj(numverts)
1062 {
1063 int e1 = j, e2 = j+1 < numverts ? j+1 : 0;
1064 ivec d = pos[e2];
1065 d.sub(pos[e1]);
1066 if(d.iszero()) continue;
1067 int axis = abs(d.x) > abs(d.y) ? (abs(d.x) > abs(d.z) ? 0 : 2) : (abs(d.y) > abs(d.z) ? 1 : 2);
1068 if(d[axis] < 0)
1069 {
1070 d.neg();
1071 swap(e1, e2);
1072 }
1073 reduceslope(d);
1074
1075 int t1 = pos[e1][axis]/d[axis],
1076 t2 = pos[e2][axis]/d[axis];
1077 edgegroup g;
1078 g.origin = ivec(pos[e1]).sub(ivec(d).mul(t1));
1079 g.slope = d;
1080 g.axis = axis;
1081 cubeedge ce;
1082 ce.c = &c;
1083 ce.offset = t1;
1084 ce.size = t2 - t1;
1085 ce.index = i*(MAXFACEVERTS+1)+j;
1086 ce.flags = CE_START | CE_END | (e1!=j ? CE_FLIP : 0);
1087 ce.next = -1;
1088
1089 bool insert = true;
1090 int *exists = edgegroups.access(g);
1091 if(exists)
1092 {
1093 int prev = -1, cur = *exists;
1094 while(cur >= 0)
1095 {
1096 cubeedge &p = cubeedges[cur];
1097 if(p.flags&CE_DUP ?
1098 ce.offset>=p.offset && ce.offset+ce.size<=p.offset+p.size :
1099 ce.offset==p.offset && ce.size==p.size)
1100 {
1101 p.flags |= CE_DUP;
1102 insert = false;
1103 break;
1104 }
1105 else if(ce.offset >= p.offset)
1106 {
1107 if(ce.offset == p.offset+p.size) ce.flags &= ~CE_START;
1108 prev = cur;
1109 cur = p.next;
1110 }
1111 else break;
1112 }
1113 if(insert)
1114 {
1115 ce.next = cur;
1116 while(cur >= 0)
1117 {
1118 cubeedge &p = cubeedges[cur];
1119 if(ce.offset+ce.size==p.offset) { ce.flags &= ~CE_END; break; }
1120 cur = p.next;
1121 }
1122 if(prev>=0) cubeedges[prev].next = cubeedges.length();
1123 else *exists = cubeedges.length();
1124 }
1125 }
1126 else edgegroups[g] = cubeedges.length();
1127
1128 if(insert) cubeedges.add(ce);
1129 }
1130 }
1131 }
1132
gencubeedges(cube * c=worldroot,const ivec & co=ivec (0,0,0),int size=worldsize>>1)1133 void gencubeedges(cube *c = worldroot, const ivec &co = ivec(0, 0, 0), int size = worldsize>>1)
1134 {
1135 rcprogress("Fixing t-joints...");
1136 neighbourstack[++neighbourdepth] = c;
1137 loopi(8)
1138 {
1139 ivec o(i, co, size);
1140 if(c[i].ext) c[i].ext->tjoints = -1;
1141 if(c[i].children) gencubeedges(c[i].children, o, size>>1);
1142 else if(!isempty(c[i])) gencubeedges(c[i], o, size);
1143 }
1144 --neighbourdepth;
1145 }
1146
gencubeverts(cube & c,const ivec & co,int size,int csi)1147 void gencubeverts(cube &c, const ivec &co, int size, int csi)
1148 {
1149 if(!(c.visible&0xC0)) return;
1150
1151 int vismask = ~c.merged & 0x3F;
1152 if(!(c.visible&0x80)) vismask &= c.visible;
1153 if(!vismask) return;
1154
1155 int tj = filltjoints && c.ext ? c.ext->tjoints : -1, vis = 0;
1156 loopi(6) if(vismask&(1<<i) && (vis = visibletris(c, i, co, size)))
1157 {
1158 vec pos[MAXFACEVERTS];
1159 vertinfo *verts = NULL;
1160 int numverts = c.ext ? c.ext->surfaces[i].numverts&MAXFACEVERTS : 0, convex = 0;
1161 if(numverts)
1162 {
1163 verts = c.ext->verts() + c.ext->surfaces[i].verts;
1164 vec vo(ivec(co).mask(~0xFFF));
1165 loopj(numverts) pos[j] = vec(verts[j].getxyz()).mul(1.0f/8).add(vo);
1166 if(!flataxisface(c, i)) convex = faceconvexity(verts, numverts, size);
1167 }
1168 else
1169 {
1170 ivec v[4];
1171 genfaceverts(c, i, v);
1172 if(!flataxisface(c, i)) convex = faceconvexity(v);
1173 int order = vis&4 || convex < 0 ? 1 : 0;
1174 vec vo(co);
1175 pos[numverts++] = vec(v[order]).mul(size/8.0f).add(vo);
1176 if(vis&1) pos[numverts++] = vec(v[order+1]).mul(size/8.0f).add(vo);
1177 pos[numverts++] = vec(v[order+2]).mul(size/8.0f).add(vo);
1178 if(vis&2) pos[numverts++] = vec(v[(order+3)&3]).mul(size/8.0f).add(vo);
1179 }
1180
1181 VSlot &vslot = lookupvslot(c.texture[i], true),
1182 *layer = vslot.layer && !(c.material&MAT_ALPHA) ? &lookupvslot(vslot.layer, true) : NULL;
1183 ushort envmap = vslot.slot->shader && vslot.slot->shader->type&SHADER_ENVMAP ? (vslot.slot->texmask&(1<<TEX_ENVMAP) ? EMID_CUSTOM : closestenvmap(i, co, size)) : EMID_NONE,
1184 envmap2 = layer && layer->slot->shader && layer->slot->shader->type&SHADER_ENVMAP ? (layer->slot->texmask&(1<<TEX_ENVMAP) ? EMID_CUSTOM : closestenvmap(i, co, size)) : EMID_NONE;
1185 while(tj >= 0 && tjoints[tj].edge < i*(MAXFACEVERTS+1)) tj = tjoints[tj].next;
1186 int hastj = tj >= 0 && tjoints[tj].edge < (i+1)*(MAXFACEVERTS+1) ? tj : -1;
1187 int grassy = vslot.slot->grass && i!=O_BOTTOM ? (vis!=3 || convex ? 1 : 2) : 0;
1188 if(!c.ext)
1189 addcubeverts(vslot, i, size, pos, convex, c.texture[i], NULL, numverts, hastj, envmap, grassy, (c.material&MAT_ALPHA)!=0);
1190 else
1191 {
1192 const surfaceinfo &surf = c.ext->surfaces[i];
1193 if(!surf.numverts || surf.numverts&LAYER_TOP)
1194 addcubeverts(vslot, i, size, pos, convex, c.texture[i], verts, numverts, hastj, envmap, grassy, (c.material&MAT_ALPHA)!=0, surf.numverts&LAYER_BLEND);
1195 if(surf.numverts&LAYER_BOTTOM)
1196 addcubeverts(layer ? *layer : vslot, i, size, pos, convex, vslot.layer, verts, numverts, hastj, envmap2, 0, false, surf.numverts&LAYER_TOP ? LAYER_BOTTOM : LAYER_TOP);
1197 }
1198 }
1199 }
1200
1201 ////////// Vertex Arrays //////////////
1202
1203 int allocva = 0;
1204 int wtris = 0, wverts = 0, vtris = 0, vverts = 0, glde = 0, gbatches = 0;
1205 vector<vtxarray *> valist, varoot;
1206
newva(const ivec & o,int size)1207 vtxarray *newva(const ivec &o, int size)
1208 {
1209 vtxarray *va = new vtxarray;
1210 va->parent = NULL;
1211 va->o = o;
1212 va->size = size;
1213 va->curvfc = VFC_NOT_VISIBLE;
1214 va->occluded = OCCLUDE_NOTHING;
1215 va->query = NULL;
1216 va->bbmin = va->alphamin = va->refractmin = va->skymin = ivec(-1, -1, -1);
1217 va->bbmax = va->alphamax = va->refractmax = va->skymax = ivec(-1, -1, -1);
1218 va->hasmerges = 0;
1219 va->mergelevel = -1;
1220
1221 vc.setupdata(va);
1222
1223 if(va->alphafronttris || va->alphabacktris || va->refracttris)
1224 {
1225 va->alphamin = ivec(vec(vc.alphamin).mul(8)).shr(3);
1226 va->alphamax = ivec(vec(vc.alphamax).mul(8)).add(7).shr(3);
1227 }
1228
1229 if(va->refracttris)
1230 {
1231 va->refractmin = ivec(vec(vc.refractmin).mul(8)).shr(3);
1232 va->refractmax = ivec(vec(vc.refractmax).mul(8)).add(7).shr(3);
1233 }
1234
1235 if(va->sky && vc.skymax.x >= 0)
1236 {
1237 va->skymin = ivec(vec(vc.skymin).mul(8)).shr(3);
1238 va->skymax = ivec(vec(vc.skymax).mul(8)).add(7).shr(3);
1239 }
1240
1241 va->nogimin = vc.nogimin;
1242 va->nogimax = vc.nogimax;
1243
1244 wverts += va->verts;
1245 wtris += va->tris + va->blends + va->alphabacktris + va->alphafronttris + va->refracttris + va->decaltris;
1246 allocva++;
1247 valist.add(va);
1248
1249 return va;
1250 }
1251
destroyva(vtxarray * va,bool reparent)1252 void destroyva(vtxarray *va, bool reparent)
1253 {
1254 wverts -= va->verts;
1255 wtris -= va->tris + va->blends + va->alphabacktris + va->alphafronttris + va->refracttris + va->decaltris;
1256 allocva--;
1257 valist.removeobj(va);
1258 if(!va->parent) varoot.removeobj(va);
1259 if(reparent)
1260 {
1261 if(va->parent) va->parent->children.removeobj(va);
1262 loopv(va->children)
1263 {
1264 vtxarray *child = va->children[i];
1265 child->parent = va->parent;
1266 if(child->parent) child->parent->children.add(child);
1267 }
1268 }
1269 if(va->vbuf) destroyvbo(va->vbuf);
1270 if(va->ebuf) destroyvbo(va->ebuf);
1271 if(va->skybuf) destroyvbo(va->skybuf);
1272 if(va->decalbuf) destroyvbo(va->decalbuf);
1273 if(va->texelems) delete[] va->texelems;
1274 if(va->decalelems) delete[] va->decalelems;
1275 if(va->matbuf) delete[] va->matbuf;
1276 delete va;
1277 }
1278
clearvas(cube * c)1279 void clearvas(cube *c)
1280 {
1281 loopi(8)
1282 {
1283 if(c[i].ext)
1284 {
1285 if(c[i].ext->va) destroyva(c[i].ext->va, false);
1286 c[i].ext->va = NULL;
1287 c[i].ext->tjoints = -1;
1288 }
1289 if(c[i].children) clearvas(c[i].children);
1290 }
1291 }
1292
1293 ivec worldmin(0, 0, 0), worldmax(0, 0, 0), nogimin(0, 0, 0), nogimax(0, 0, 0);
1294
updatevabb(vtxarray * va,bool force)1295 void updatevabb(vtxarray *va, bool force)
1296 {
1297 if(!force && va->bbmin.x >= 0) return;
1298
1299 va->bbmin = va->geommin;
1300 va->bbmax = va->geommax;
1301 va->bbmin.min(va->lavamin);
1302 va->bbmax.max(va->lavamax);
1303 va->bbmin.min(va->watermin);
1304 va->bbmax.max(va->watermax);
1305 va->bbmin.min(va->glassmin);
1306 va->bbmax.max(va->glassmax);
1307 loopv(va->children)
1308 {
1309 vtxarray *child = va->children[i];
1310 updatevabb(child, force);
1311 va->bbmin.min(child->bbmin);
1312 va->bbmax.max(child->bbmax);
1313 }
1314 loopv(va->mapmodels)
1315 {
1316 octaentities *oe = va->mapmodels[i];
1317 va->bbmin.min(oe->bbmin);
1318 va->bbmax.max(oe->bbmax);
1319 }
1320 loopv(va->decals)
1321 {
1322 octaentities *oe = va->decals[i];
1323 va->bbmin.min(oe->bbmin);
1324 va->bbmax.max(oe->bbmax);
1325 }
1326 va->bbmin.max(va->o);
1327 va->bbmax.min(ivec(va->o).add(va->size));
1328 worldmin.min(va->bbmin);
1329 worldmax.max(va->bbmax);
1330 nogimin.min(va->nogimin);
1331 nogimax.max(va->nogimax);
1332 }
1333
updatevabbs(bool force)1334 void updatevabbs(bool force)
1335 {
1336 if(force)
1337 {
1338 worldmin = nogimin = ivec(worldsize, worldsize, worldsize);
1339 worldmax = nogimax = ivec(0, 0, 0);
1340 loopv(varoot) updatevabb(varoot[i], true);
1341 if(worldmin.x >= worldmax.x)
1342 {
1343 worldmin = ivec(0, 0, 0);
1344 worldmax = ivec(worldsize, worldsize, worldsize);
1345 }
1346 }
1347 else loopv(varoot) updatevabb(varoot[i]);
1348 }
1349
1350 struct mergedface
1351 {
1352 uchar orient, numverts;
1353 ushort mat, tex, envmap;
1354 vertinfo *verts;
1355 int tjoints;
1356 };
1357
1358 #define MAXMERGELEVEL 12
1359 static int vahasmerges = 0, vamergemax = 0;
1360 static vector<mergedface> vamerges[MAXMERGELEVEL+1];
1361
genmergedfaces(cube & c,const ivec & co,int size,int minlevel=-1)1362 int genmergedfaces(cube &c, const ivec &co, int size, int minlevel = -1)
1363 {
1364 if(!c.ext || isempty(c)) return -1;
1365 int tj = c.ext->tjoints, maxlevel = -1;
1366 loopi(6) if(c.merged&(1<<i))
1367 {
1368 surfaceinfo &surf = c.ext->surfaces[i];
1369 int numverts = surf.numverts&MAXFACEVERTS;
1370 if(!numverts)
1371 {
1372 if(minlevel < 0) vahasmerges |= MERGE_PART;
1373 continue;
1374 }
1375 mergedface mf;
1376 mf.orient = i;
1377 mf.mat = c.material;
1378 mf.tex = c.texture[i];
1379 mf.envmap = EMID_NONE;
1380 mf.numverts = surf.numverts;
1381 mf.verts = c.ext->verts() + surf.verts;
1382 mf.tjoints = -1;
1383 int level = calcmergedsize(i, co, size, mf.verts, mf.numverts&MAXFACEVERTS);
1384 if(level > minlevel)
1385 {
1386 maxlevel = max(maxlevel, level);
1387
1388 while(tj >= 0 && tjoints[tj].edge < i*(MAXFACEVERTS+1)) tj = tjoints[tj].next;
1389 if(tj >= 0 && tjoints[tj].edge < (i+1)*(MAXFACEVERTS+1)) mf.tjoints = tj;
1390
1391 VSlot &vslot = lookupvslot(mf.tex, true),
1392 *layer = vslot.layer && !(c.material&MAT_ALPHA) ? &lookupvslot(vslot.layer, true) : NULL;
1393 if(vslot.slot->shader && vslot.slot->shader->type&SHADER_ENVMAP)
1394 mf.envmap = vslot.slot->texmask&(1<<TEX_ENVMAP) ? EMID_CUSTOM : closestenvmap(i, co, size);
1395 ushort envmap2 = layer && layer->slot->shader && layer->slot->shader->type&SHADER_ENVMAP ? (layer->slot->texmask&(1<<TEX_ENVMAP) ? EMID_CUSTOM : closestenvmap(i, co, size)) : EMID_NONE;
1396
1397 if(surf.numverts&LAYER_TOP) vamerges[level].add(mf);
1398 if(surf.numverts&LAYER_BOTTOM)
1399 {
1400 mf.tex = vslot.layer;
1401 mf.envmap = envmap2;
1402 mf.numverts &= ~LAYER_BLEND;
1403 mf.numverts |= surf.numverts&LAYER_TOP ? LAYER_BOTTOM : LAYER_TOP;
1404 vamerges[level].add(mf);
1405 }
1406 }
1407 }
1408 if(maxlevel >= 0)
1409 {
1410 vamergemax = max(vamergemax, maxlevel);
1411 vahasmerges |= MERGE_ORIGIN;
1412 }
1413 return maxlevel;
1414 }
1415
findmergedfaces(cube & c,const ivec & co,int size,int csi,int minlevel)1416 int findmergedfaces(cube &c, const ivec &co, int size, int csi, int minlevel)
1417 {
1418 if(c.ext && c.ext->va && !(c.ext->va->hasmerges&MERGE_ORIGIN)) return c.ext->va->mergelevel;
1419 else if(c.children)
1420 {
1421 int maxlevel = -1;
1422 loopi(8)
1423 {
1424 ivec o(i, co, size/2);
1425 int level = findmergedfaces(c.children[i], o, size/2, csi-1, minlevel);
1426 maxlevel = max(maxlevel, level);
1427 }
1428 return maxlevel;
1429 }
1430 else if(c.ext && c.merged) return genmergedfaces(c, co, size, minlevel);
1431 else return -1;
1432 }
1433
addmergedverts(int level,const ivec & o)1434 void addmergedverts(int level, const ivec &o)
1435 {
1436 vector<mergedface> &mfl = vamerges[level];
1437 if(mfl.empty()) return;
1438 vec vo(ivec(o).mask(~0xFFF));
1439 vec pos[MAXFACEVERTS];
1440 loopv(mfl)
1441 {
1442 mergedface &mf = mfl[i];
1443 int numverts = mf.numverts&MAXFACEVERTS;
1444 loopi(numverts)
1445 {
1446 vertinfo &v = mf.verts[i];
1447 pos[i] = vec(v.x, v.y, v.z).mul(1.0f/8).add(vo);
1448 }
1449 VSlot &vslot = lookupvslot(mf.tex, true);
1450 int grassy = vslot.slot->grass && mf.orient!=O_BOTTOM && mf.numverts&LAYER_TOP ? 2 : 0;
1451 addcubeverts(vslot, mf.orient, 1<<level, pos, 0, mf.tex, mf.verts, numverts, mf.tjoints, mf.envmap, grassy, (mf.mat&MAT_ALPHA)!=0, mf.numverts&LAYER_BLEND);
1452 vahasmerges |= MERGE_USE;
1453 }
1454 mfl.setsize(0);
1455 }
1456
finddecals(vtxarray * va)1457 static inline void finddecals(vtxarray *va)
1458 {
1459 if(va->hasmerges&(MERGE_ORIGIN|MERGE_PART))
1460 {
1461 loopv(va->decals) vc.extdecals.add(va->decals[i]);
1462 loopv(va->children) finddecals(va->children[i]);
1463 }
1464 }
1465
rendercube(cube & c,const ivec & co,int size,int csi,int & maxlevel)1466 void rendercube(cube &c, const ivec &co, int size, int csi, int &maxlevel) // creates vertices and indices ready to be put into a va
1467 {
1468 //if(size<=16) return;
1469 if(c.ext && c.ext->va)
1470 {
1471 maxlevel = max(maxlevel, c.ext->va->mergelevel);
1472 finddecals(c.ext->va);
1473 return; // don't re-render
1474 }
1475
1476 if(c.children)
1477 {
1478 neighbourstack[++neighbourdepth] = c.children;
1479 c.escaped = 0;
1480 loopi(8)
1481 {
1482 ivec o(i, co, size/2);
1483 int level = -1;
1484 rendercube(c.children[i], o, size/2, csi-1, level);
1485 if(level >= csi)
1486 c.escaped |= 1<<i;
1487 maxlevel = max(maxlevel, level);
1488 }
1489 --neighbourdepth;
1490
1491 if(csi <= MAXMERGELEVEL && vamerges[csi].length()) addmergedverts(csi, co);
1492
1493 if(c.ext && c.ext->ents)
1494 {
1495 if(c.ext->ents->mapmodels.length()) vc.mapmodels.add(c.ext->ents);
1496 if(c.ext->ents->decals.length()) vc.decals.add(c.ext->ents);
1497 }
1498 return;
1499 }
1500
1501 if(!isempty(c))
1502 {
1503 gencubeverts(c, co, size, csi);
1504 if(c.merged) maxlevel = max(maxlevel, genmergedfaces(c, co, size));
1505 }
1506 if(c.material != MAT_AIR)
1507 {
1508 genmatsurfs(c, co, size, vc.matsurfs);
1509 if(c.material&MAT_NOGI)
1510 {
1511 vc.nogimin.min(co);
1512 vc.nogimax.max(ivec(co).add(size));
1513 }
1514 }
1515
1516 if(c.ext && c.ext->ents)
1517 {
1518 if(c.ext->ents->mapmodels.length()) vc.mapmodels.add(c.ext->ents);
1519 if(c.ext->ents->decals.length()) vc.decals.add(c.ext->ents);
1520 }
1521
1522 if(csi <= MAXMERGELEVEL && vamerges[csi].length()) addmergedverts(csi, co);
1523 }
1524
calcgeombb(const ivec & co,int size,ivec & bbmin,ivec & bbmax)1525 void calcgeombb(const ivec &co, int size, ivec &bbmin, ivec &bbmax)
1526 {
1527 vec vmin(co), vmax = vmin;
1528 vmin.add(size);
1529
1530 loopv(vc.verts)
1531 {
1532 const vec &v = vc.verts[i].pos;
1533 vmin.min(v);
1534 vmax.max(v);
1535 }
1536
1537 bbmin = ivec(vmin.mul(8)).shr(3);
1538 bbmax = ivec(vmax.mul(8)).add(7).shr(3);
1539 }
1540
1541 static int entdepth = -1;
1542 static octaentities *entstack[32];
1543
setva(cube & c,const ivec & co,int size,int csi)1544 void setva(cube &c, const ivec &co, int size, int csi)
1545 {
1546 ASSERT(size <= 0x1000);
1547
1548 int vamergeoffset[MAXMERGELEVEL+1];
1549 loopi(MAXMERGELEVEL+1) vamergeoffset[i] = vamerges[i].length();
1550
1551 vc.origin = co;
1552 vc.size = size;
1553
1554 loopi(entdepth+1)
1555 {
1556 octaentities *oe = entstack[i];
1557 if(oe->decals.length()) vc.extdecals.add(oe);
1558 }
1559
1560 int maxlevel = -1;
1561 rendercube(c, co, size, csi, maxlevel);
1562
1563 if(size == min(0x1000, worldsize/2) || !vc.emptyva())
1564 {
1565 vtxarray *va = newva(co, size);
1566 ext(c).va = va;
1567 calcgeombb(co, size, va->geommin, va->geommax);
1568 calcmatbb(va, co, size, vc.matsurfs);
1569 va->hasmerges = vahasmerges;
1570 va->mergelevel = vamergemax;
1571 }
1572 else
1573 {
1574 loopi(MAXMERGELEVEL+1) vamerges[i].setsize(vamergeoffset[i]);
1575 }
1576
1577 vc.clear();
1578 }
1579
setcubevisibility(cube & c,const ivec & co,int size)1580 static inline int setcubevisibility(cube &c, const ivec &co, int size)
1581 {
1582 if(isempty(c) && (c.material&MATF_CLIP) != MAT_CLIP) return 0;
1583 int numvis = 0, vismask = 0, collidemask = 0, checkmask = 0;
1584 loopi(6)
1585 {
1586 int facemask = classifyface(c, i, co, size);
1587 if(facemask&1)
1588 {
1589 vismask |= 1<<i;
1590 if(c.merged&(1<<i))
1591 {
1592 if(c.ext && c.ext->surfaces[i].numverts&MAXFACEVERTS) numvis++;
1593 }
1594 else
1595 {
1596 numvis++;
1597 if(c.texture[i] != DEFAULT_SKY && !(c.ext && c.ext->surfaces[i].numverts&MAXFACEVERTS)) checkmask |= 1<<i;
1598 }
1599 }
1600 if(facemask&2) collidemask |= 1<<i;
1601 }
1602 c.visible = collidemask | (vismask ? (vismask != collidemask ? (checkmask ? 0x80|0x40 : 0x80) : 0x40) : 0);
1603 return numvis;
1604 }
1605
1606 VARF(0, vafacemax, 64, 384, 256*256, allchanged());
1607 VARF(0, vafacemin, 0, 96, 256*256, allchanged());
1608 VARF(0, vacubesize, 32, 128, 0x1000, allchanged());
1609
updateva(cube * c,const ivec & co,int size,int csi)1610 int updateva(cube *c, const ivec &co, int size, int csi)
1611 {
1612 rcprogress("Recalculating geometry...");
1613 int ccount = 0, cmergemax = vamergemax, chasmerges = vahasmerges;
1614 neighbourstack[++neighbourdepth] = c;
1615 loopi(8) // counting number of semi-solid/solid children cubes
1616 {
1617 int count = 0, childpos = varoot.length();
1618 ivec o(i, co, size);
1619 vamergemax = 0;
1620 vahasmerges = 0;
1621 if(c[i].ext && c[i].ext->va)
1622 {
1623 varoot.add(c[i].ext->va);
1624 if(c[i].ext->va->hasmerges&MERGE_ORIGIN) findmergedfaces(c[i], o, size, csi, csi);
1625 }
1626 else
1627 {
1628 if(c[i].children)
1629 {
1630 if(c[i].ext && c[i].ext->ents) entstack[++entdepth] = c[i].ext->ents;
1631 count += updateva(c[i].children, o, size/2, csi-1);
1632 if(c[i].ext && c[i].ext->ents) --entdepth;
1633 }
1634 else count += setcubevisibility(c[i], o, size);
1635 int tcount = count + (csi <= MAXMERGELEVEL ? vamerges[csi].length() : 0);
1636 if(tcount > vafacemax || (tcount >= vafacemin && size >= vacubesize) || size == min(0x1000, worldsize/2))
1637 {
1638 loadprogress = clamp(recalcprogress/float(allocnodes), 0.0f, 1.0f);
1639 setva(c[i], o, size, csi);
1640 if(c[i].ext && c[i].ext->va)
1641 {
1642 while(varoot.length() > childpos)
1643 {
1644 vtxarray *child = varoot.pop();
1645 c[i].ext->va->children.add(child);
1646 child->parent = c[i].ext->va;
1647 }
1648 varoot.add(c[i].ext->va);
1649 if(vamergemax > size)
1650 {
1651 cmergemax = max(cmergemax, vamergemax);
1652 chasmerges |= vahasmerges&~MERGE_USE;
1653 }
1654 continue;
1655 }
1656 else count = 0;
1657 }
1658 }
1659 if(csi+1 <= MAXMERGELEVEL && vamerges[csi].length()) vamerges[csi+1].move(vamerges[csi]);
1660 cmergemax = max(cmergemax, vamergemax);
1661 chasmerges |= vahasmerges;
1662 ccount += count;
1663 }
1664 --neighbourdepth;
1665 vamergemax = cmergemax;
1666 vahasmerges = chasmerges;
1667
1668 return ccount;
1669 }
1670
addtjoint(const edgegroup & g,const cubeedge & e,int offset)1671 void addtjoint(const edgegroup &g, const cubeedge &e, int offset)
1672 {
1673 int vcoord = (g.slope[g.axis]*offset + g.origin[g.axis]) & 0x7FFF;
1674 tjoint &tj = tjoints.add();
1675 tj.offset = vcoord / g.slope[g.axis];
1676 tj.edge = e.index;
1677
1678 int prev = -1, cur = ext(*e.c).tjoints;
1679 while(cur >= 0)
1680 {
1681 tjoint &o = tjoints[cur];
1682 if(tj.edge < o.edge || (tj.edge==o.edge && (e.flags&CE_FLIP ? tj.offset > o.offset : tj.offset < o.offset))) break;
1683 prev = cur;
1684 cur = o.next;
1685 }
1686
1687 tj.next = cur;
1688 if(prev < 0) e.c->ext->tjoints = tjoints.length()-1;
1689 else tjoints[prev].next = tjoints.length()-1;
1690 }
1691
findtjoints(int cur,const edgegroup & g)1692 void findtjoints(int cur, const edgegroup &g)
1693 {
1694 int active = -1;
1695 while(cur >= 0)
1696 {
1697 cubeedge &e = cubeedges[cur];
1698 int prevactive = -1, curactive = active;
1699 while(curactive >= 0)
1700 {
1701 cubeedge &a = cubeedges[curactive];
1702 if(a.offset+a.size <= e.offset)
1703 {
1704 if(prevactive >= 0) cubeedges[prevactive].next = a.next;
1705 else active = a.next;
1706 }
1707 else
1708 {
1709 prevactive = curactive;
1710 if(!(a.flags&CE_DUP))
1711 {
1712 if(e.flags&CE_START && e.offset > a.offset && e.offset < a.offset+a.size)
1713 addtjoint(g, a, e.offset);
1714 if(e.flags&CE_END && e.offset+e.size > a.offset && e.offset+e.size < a.offset+a.size)
1715 addtjoint(g, a, e.offset+e.size);
1716 }
1717 if(!(e.flags&CE_DUP))
1718 {
1719 if(a.flags&CE_START && a.offset > e.offset && a.offset < e.offset+e.size)
1720 addtjoint(g, e, a.offset);
1721 if(a.flags&CE_END && a.offset+a.size > e.offset && a.offset+a.size < e.offset+e.size)
1722 addtjoint(g, e, a.offset+a.size);
1723 }
1724 }
1725 curactive = a.next;
1726 }
1727 int next = e.next;
1728 e.next = active;
1729 active = cur;
1730 cur = next;
1731 }
1732 }
1733
findtjoints()1734 void findtjoints()
1735 {
1736 recalcprogress = 0;
1737 gencubeedges();
1738 tjoints.setsize(0);
1739 enumeratekt(edgegroups, edgegroup, g, int, e, findtjoints(e, g));
1740 cubeedges.setsize(0);
1741 edgegroups.clear();
1742 }
1743
octarender()1744 void octarender() // creates va s for all leaf cubes that don't already have them
1745 {
1746 int csi = 0;
1747 while(1<<csi < worldsize) csi++;
1748
1749 recalcprogress = 0;
1750 varoot.setsize(0);
1751 updateva(worldroot, ivec(0, 0, 0), worldsize/2, csi-1);
1752 loadprogress = 0;
1753 flushvbo();
1754
1755 explicitsky = 0;
1756 loopv(valist)
1757 {
1758 vtxarray *va = valist[i];
1759 explicitsky += va->sky;
1760 }
1761
1762 visibleva = NULL;
1763 }
1764
precachetextures()1765 void precachetextures()
1766 {
1767 vector<int> texs;
1768 loopv(valist)
1769 {
1770 vtxarray *va = valist[i];
1771 loopj(va->texs + va->blends)
1772 {
1773 int tex = va->texelems[j].texture;
1774 if(texs.find(tex) < 0)
1775 {
1776 texs.add(tex);
1777
1778 VSlot &vslot = lookupvslot(tex, false);
1779 if(vslot.layer && texs.find(vslot.layer) < 0) texs.add(vslot.layer);
1780 if(vslot.detail && texs.find(vslot.detail) < 0) texs.add(vslot.detail);
1781 }
1782 }
1783 }
1784 loopv(texs)
1785 {
1786 loadprogress = float(i+1)/texs.length();
1787 lookupvslot(texs[i]);
1788 }
1789 loadprogress = 0;
1790 }
1791
allchanged(bool load)1792 void allchanged(bool load)
1793 {
1794 if(!connected()) load = false;
1795 if(load) initlights();
1796 progress(-1, "Clearing vertex arrays...");
1797 clearvas(worldroot);
1798 resetqueries();
1799 resetclipplanes();
1800 if(load) initenvtexs();
1801 entitiesinoctanodes();
1802 tjoints.setsize(0);
1803 if(filltjoints) findtjoints();
1804 octarender();
1805 if(load) precachetextures();
1806 setupmaterials();
1807 clearshadowcache();
1808 updatevabbs(true);
1809 if(load)
1810 {
1811 genshadowmeshes();
1812 updateblendtextures();
1813 seedparticles();
1814 genenvtexs();
1815 drawminimap();
1816 }
1817 }
1818
recalc()1819 void recalc()
1820 {
1821 allchanged(true);
1822 }
1823
1824 COMMAND(0, recalc, "");
1825
1826