Line data Source code
1 :
2 : // vacollect.cpp: fill vertex array structure using vacollect object
3 : #include "../libprimis-headers/cube.h"
4 : #include "../../shared/geomexts.h"
5 : #include "../../shared/glemu.h"
6 : #include "../../shared/glexts.h"
7 :
8 : #include "grass.h"
9 : #include "octarender.h"
10 : #include "rendergl.h"
11 : #include "renderlights.h"
12 : #include "renderparticles.h"
13 : #include "rendersky.h"
14 : #include "renderva.h"
15 : #include "shader.h"
16 : #include "shaderparam.h"
17 : #include "texture.h"
18 :
19 : #include "interface/menus.h"
20 :
21 : #include "world/entities.h"
22 : #include "world/light.h"
23 : #include "world/material.h"
24 : #include "world/octaworld.h"
25 : #include "world/world.h"
26 :
27 : enum AlphaState
28 : {
29 : Alpha_None = 0,
30 : Alpha_Back,
31 : Alpha_Front,
32 : Alpha_Refract
33 : };
34 :
35 : class SortKey final
36 : {
37 : public:
38 : ushort tex;
39 : uchar orient, layer, alpha;
40 :
41 : SortKey() {}
42 0 : SortKey(ushort tex, uchar orient, uchar layer = BlendLayer_Top, uchar alpha = Alpha_None)
43 0 : : tex(tex), orient(orient), layer(layer), alpha(alpha)
44 0 : {}
45 :
46 0 : bool operator==(const SortKey &o) const
47 : {
48 0 : return tex==o.tex && orient==o.orient && layer==o.layer && alpha==o.alpha;
49 : }
50 :
51 0 : static bool sort(const SortKey &x, const SortKey &y)
52 : {
53 0 : if(x.alpha != y.alpha)
54 : {
55 0 : return x.alpha < y.alpha;
56 : }
57 0 : if(x.layer != y.layer)
58 : {
59 0 : return x.layer < y.layer;
60 : }
61 0 : if(x.tex == y.tex)
62 : {
63 0 : return x.orient < y.orient;
64 : }
65 0 : VSlot &xs = lookupvslot(x.tex, false),
66 0 : &ys = lookupvslot(y.tex, false);
67 0 : if(xs.slot->shader != ys.slot->shader)
68 : {
69 0 : return xs.slot->shader < ys.slot->shader;
70 : }
71 0 : if(xs.slot->params.size() != ys.slot->params.size())
72 : {
73 0 : return xs.slot->params.size() < ys.slot->params.size();
74 : }
75 0 : if(x.tex < y.tex)
76 : {
77 0 : return true;
78 : }
79 0 : return false;
80 : }
81 : };
82 :
83 : template<>
84 : struct std::hash<SortKey> final
85 : {
86 0 : size_t operator()(const SortKey &k) const
87 : {
88 0 : return k.tex;
89 : }
90 : };
91 :
92 : struct decalkey final
93 : {
94 : ushort tex, reuse;
95 :
96 : decalkey() {}
97 0 : decalkey(ushort tex, ushort reuse = 0)
98 0 : : tex(tex), reuse(reuse)
99 0 : {}
100 :
101 0 : bool operator==(const decalkey &o) const
102 : {
103 0 : return tex==o.tex && reuse==o.reuse;
104 : }
105 :
106 : static bool sort(const decalkey &x, const decalkey &y)
107 : {
108 : if(x.tex == y.tex)
109 : {
110 : if(x.reuse < y.reuse)
111 : {
112 : return true;
113 : }
114 : else
115 : {
116 : return false;
117 : }
118 : }
119 : const DecalSlot &xs = lookupdecalslot(x.tex, false),
120 : &ys = lookupdecalslot(y.tex, false);
121 : if(xs.slot->shader < ys.slot->shader)
122 : {
123 : return true;
124 : }
125 : if(xs.slot->shader > ys.slot->shader)
126 : {
127 : return false;
128 : }
129 : if(xs.slot->params.size() < ys.slot->params.size())
130 : {
131 : return true;
132 : }
133 : if(xs.slot->params.size() > ys.slot->params.size())
134 : {
135 : return false;
136 : }
137 : if(x.tex < y.tex)
138 : {
139 : return true;
140 : }
141 : else
142 : {
143 : return false;
144 : }
145 : }
146 : };
147 :
148 : template<>
149 : struct std::hash<decalkey> final
150 : {
151 0 : size_t operator()(const decalkey &k) const
152 : {
153 0 : return k.tex;
154 : }
155 : };
156 :
157 : struct sortval final
158 : {
159 : std::vector<ushort> tris;
160 :
161 0 : sortval() {}
162 : };
163 :
164 : struct vboinfo final
165 : {
166 : int uses;
167 : uchar *data;
168 : };
169 :
170 : static std::unordered_map<GLuint, vboinfo> vbos;
171 :
172 0 : static VARFN(vbosize, maxvbosize, 0, 1<<14, 1<<16, rootworld.allchanged());
173 :
174 : //vbo (vertex buffer object) enum is local to this file
175 : enum
176 : {
177 : VBO_VBuf = 0,
178 : VBO_EBuf,
179 : VBO_SkyBuf,
180 : VBO_DecalBuf,
181 : VBO_NumVBOs
182 : };
183 :
184 : static std::vector<uchar> vbodata[VBO_NumVBOs];
185 : static std::vector<vtxarray *> vbovas[VBO_NumVBOs];
186 : static std::array<int, VBO_NumVBOs> vbosize;
187 :
188 0 : void destroyvbo(GLuint vbo)
189 : {
190 0 : std::unordered_map<GLuint, vboinfo>::iterator exists = vbos.find(vbo);
191 0 : if(exists == vbos.end())
192 : {
193 0 : return;
194 : }
195 0 : vboinfo &vbi = (*exists).second;
196 0 : if(vbi.uses <= 0)
197 : {
198 0 : return;
199 : }
200 0 : vbi.uses--;
201 0 : if(!vbi.uses)
202 : {
203 0 : glDeleteBuffers(1, &vbo);
204 0 : if(vbi.data)
205 : {
206 0 : delete[] vbi.data;
207 : }
208 0 : vbos.erase(vbo);
209 : }
210 : }
211 :
212 : //sets up vbos (vertex buffer objects) for each entry in the vas vector
213 : //by setting up each vertex array's vbuf and vdata
214 0 : static void genvbo(int type, std::vector<uchar> &buf, std::vector<vtxarray *> &vas)
215 : {
216 0 : gle::disable();
217 :
218 : GLuint vbo;
219 0 : glGenBuffers(1, &vbo);
220 0 : const GLenum target = type==VBO_VBuf ? GL_ARRAY_BUFFER : GL_ELEMENT_ARRAY_BUFFER;
221 0 : glBindBuffer(target, vbo);
222 0 : glBufferData(target, buf.size(), buf.data(), GL_STATIC_DRAW);
223 0 : glBindBuffer(target, 0);
224 :
225 0 : vboinfo &vbi = vbos[vbo];
226 0 : vbi.uses = vas.size();
227 0 : vbi.data = new uchar[buf.size()];
228 0 : std::memcpy(vbi.data, buf.data(), buf.size());
229 :
230 0 : for(vtxarray *va: vas)
231 : {
232 0 : switch(type)
233 : {
234 0 : case VBO_VBuf:
235 : {
236 0 : va->vbuf = vbo;
237 0 : va->vdata = reinterpret_cast<vertex *>(vbi.data);
238 0 : break;
239 : }
240 0 : case VBO_EBuf:
241 : {
242 0 : va->ebuf = vbo;
243 0 : va->edata = reinterpret_cast<ushort *>(vbi.data);
244 0 : break;
245 : }
246 0 : case VBO_SkyBuf:
247 : {
248 0 : va->skybuf = vbo;
249 0 : va->skydata = reinterpret_cast<ushort *>(vbi.data);
250 0 : break;
251 : }
252 0 : case VBO_DecalBuf:
253 : {
254 0 : va->decalbuf = vbo;
255 0 : va->decaldata = reinterpret_cast<ushort *>(vbi.data);
256 0 : break;
257 : }
258 : }
259 : }
260 0 : }
261 :
262 : /**
263 : * @brief Flushes data out of a VBO object.
264 : *
265 : * flushes data out of the specified VBO object and calls genvbo()
266 : * then destroys the data in the relevant VBO
267 : *
268 : * default type = -1 flushes every vbo
269 : *
270 : * @param type location in the vbodata array to flush, or -1 for all
271 : */
272 0 : static void flushvbo(int type = -1)
273 : {
274 0 : if(type < 0)
275 : {
276 0 : for(int i = 0; i < VBO_NumVBOs; ++i)
277 : {
278 0 : flushvbo(i);
279 : }
280 0 : return;
281 : }
282 :
283 0 : std::vector<uchar> &data = vbodata[type];
284 0 : if(data.empty())
285 : {
286 0 : return;
287 : }
288 0 : std::vector<vtxarray *> &vas = vbovas[type];
289 0 : genvbo(type, data, vas);
290 0 : data.clear();
291 0 : vas.clear();
292 0 : vbosize[type] = 0;
293 : }
294 :
295 0 : static uchar *addvbo(vtxarray *va, int type, int numelems, int elemsize)
296 : {
297 0 : switch(type)
298 : {
299 0 : case VBO_VBuf:
300 : {
301 0 : va->voffset = vbosize[type];
302 0 : break;
303 : }
304 0 : case VBO_EBuf:
305 : {
306 0 : va->eoffset = vbosize[type];
307 0 : break;
308 : }
309 0 : case VBO_SkyBuf:
310 : {
311 0 : va->skyoffset = vbosize[type];
312 0 : break;
313 : }
314 0 : case VBO_DecalBuf:
315 : {
316 0 : va->decaloffset = vbosize[type];
317 0 : break;
318 : }
319 : }
320 0 : vbosize[type] += numelems;
321 0 : std::vector<uchar> &data = vbodata[type];
322 0 : std::vector<vtxarray *> &vas = vbovas[type];
323 0 : vas.push_back(va);
324 0 : int len = numelems*elemsize;
325 0 : data.insert(data.end(), len, {});
326 0 : return &(*(data.end()-len)); //return pointer to where iterator points
327 : }
328 :
329 : //takes a packed ushort vector and turns it into a vec3 vector object
330 0 : static vec decodenormal(ushort norm)
331 : {
332 0 : if(!norm)
333 : {
334 0 : return vec(0, 0, 1);
335 : }
336 0 : norm--;
337 0 : const vec2 &yaw = sincos360[norm%360],
338 0 : &pitch = sincos360[norm/360+270];
339 0 : return vec(-yaw.y*pitch.x, yaw.x*pitch.x, pitch.y);
340 : }
341 :
342 : class vacollect final
343 : {
344 :
345 : public:
346 : int updateva(std::array<cube, 8> &c, const ivec &co, int size, int csi);
347 : vacollect();
348 :
349 : private:
350 : int size;
351 : std::vector<materialsurface> matsurfs;
352 : std::vector<octaentities *> mapmodels, decals;
353 : std::vector<const octaentities *> extdecals;
354 : vec skymin, skymax;
355 : vec alphamin, alphamax;
356 : vec refractmin, refractmax;
357 : std::vector<grasstri> grasstris;
358 : int worldtris, skytris;
359 : std::vector<ushort> skyindices;
360 : std::unordered_map<SortKey, sortval> indices;
361 : std::unordered_map<decalkey, sortval> decalindices;
362 : std::vector<SortKey> texs;
363 : std::vector<decalkey> decaltexs;
364 : int decaltris;
365 : std::vector<octaentities *> entstack;
366 :
367 :
368 : static constexpr int hashsize = 1<<13;
369 : std::array<int, hashsize> table;
370 :
371 : std::vector<int> chain;
372 : std::vector<vertex> verts;
373 :
374 : struct MergedFace final
375 : {
376 : uchar orient, numverts;
377 : ushort mat, tex;
378 : const vertinfo *verts;
379 : int tjoints;
380 : };
381 :
382 : static constexpr int maxmergelevel = 12;
383 : int vahasmerges = 0,
384 : vamergemax = 0;
385 : std::array<std::vector<MergedFace>, maxmergelevel+1> vamerges;
386 :
387 : const vec orientation_bitangent[8][6] =
388 : {
389 : { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) },
390 : { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
391 : { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) },
392 : { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
393 : { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) },
394 : { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) },
395 : { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
396 : { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
397 : };
398 :
399 : static constexpr int vamaxsize = 0x1000; //4096 = 2^12
400 :
401 : // pos is an array of length numverts
402 : void addcubeverts(VSlot &vslot, int orient, const vec *pos, ushort texture, const vertinfo *vinfo, int numverts, int tj = -1, int grassy = 0, bool alpha = false, int layer = BlendLayer_Top);
403 :
404 : // verts is an array of length numverts
405 : void addtris(const VSlot &vslot, int orient, const SortKey &key, vertex *verts, const int *index, int numverts, int tj);
406 :
407 : // verts is an array of length face + 2 or face + 3
408 : void addgrasstri(int face, const vertex *verts, int numv, ushort texture);
409 : vtxarray *newva(const ivec &o, int size);
410 : void rendercube(cube &c, const ivec &co, int size, int csi, int &maxlevel); // creates vertices and indices ready to be put into a va
411 : void finddecals(const vtxarray *va);
412 : void calcgeombb(const ivec &co, int size, ivec &bbmin, ivec &bbmax) const;
413 : void setva(cube &c, const ivec &co, int size, int csi);
414 : void gencubeverts(const cube &c, const ivec &co, int size);
415 : void addmergedverts(int level, const ivec &o);
416 :
417 : /**
418 : * @brief Clears but does not destroy the vacollect object.
419 : *
420 : * Each of the vacollect fields will have their clear() method called,
421 : * and the bounding vars of alpha/refract/sky min/max will be reset to
422 : * +/-1e16.
423 : *
424 : * Does not free any fields itself.
425 : */
426 : void clear();
427 : void setupdata(vtxarray *va);
428 : bool emptyva();
429 : void optimize();
430 : /**
431 : * @brief Copies verts vector into passed memory space.
432 : *
433 : * Copies verts into this array and flips its norm and tangent values.
434 : * Requires sizeof(vertex) * size(verts) amount of space or this function
435 : * will cause a buffer overflow.
436 : *
437 : * @param buf the start of the memory area to copy values into
438 : */
439 : void genverts(uchar *buf);
440 : void gendecal(const extentity &e, const DecalSlot &s, const decalkey &key);
441 : void gendecals();
442 :
443 : /**
444 : * @brief Finds merged faces for a specific cube.
445 : *
446 : * The grid size is equal to csi^2. Recursively finds merged faces for the cube
447 : * provided.
448 : *
449 : * @param c the cube to query
450 : * @param co the cube origin (world vector)
451 : * @param size the grid size
452 : * @param csi grid scale
453 : * @param minlevel level to stop recursively finding at
454 : *
455 : * @return max merge level, or -1 if failed
456 : */
457 : int findmergedfaces(cube &c, const ivec &co, int size, int csi, int minlevel);
458 : int genmergedfaces(cube &c, const ivec &co, int size, int minlevel = -1);
459 : void calctexgen(const VSlot &vslot, int orient, vec4<float> &sgen, vec4<float> &tgen);
460 :
461 : int addvert(const vertex &v);
462 : void clearverts();
463 : int addvert(const vec &pos, const vec &tc = vec(0, 0, 0), const bvec &norm = bvec(128, 128, 128), const vec4<uchar> &tangent = vec4<uchar>(128, 128, 128, 128));
464 :
465 : } vc;
466 :
467 0 : int vacollect::addvert(const vertex &v)
468 : {
469 : const auto vechash = std::hash<vec>();
470 0 : size_t h = vechash(v.pos)&(hashsize-1);
471 0 : for(int i = table[h]; i>=0; i = chain[i])
472 : {
473 0 : const vertex &c = verts[i];
474 0 : if(c.pos==v.pos && c.tc==v.tc && c.norm==v.norm && c.tangent==v.tangent)
475 : {
476 0 : return i;
477 : }
478 : }
479 0 : if(verts.size() >= USHRT_MAX)
480 : {
481 0 : return -1;
482 : }
483 0 : verts.push_back(v);
484 0 : chain.emplace_back(table[h]);
485 0 : return table[h] = verts.size()-1;
486 : }
487 1 : void vacollect::clearverts()
488 : {
489 1 : table.fill(-1);
490 1 : chain.clear();
491 1 : verts.clear();
492 1 : }
493 :
494 1 : vacollect::vacollect()
495 : {
496 1 : clearverts();
497 1 : }
498 :
499 0 : int vacollect::addvert(const vec &pos, const vec &tc, const bvec &norm, const vec4<uchar> &tangent)
500 : {
501 0 : vertex vtx;
502 0 : vtx.pos = pos;
503 0 : vtx.tc = tc;
504 0 : vtx.norm = norm;
505 0 : vtx.tangent = tangent;
506 0 : return addvert(vtx);
507 : }
508 :
509 0 : void vacollect::clear()
510 : {
511 0 : clearverts();
512 0 : worldtris = skytris = decaltris = 0;
513 0 : indices.clear();
514 0 : decalindices.clear();
515 0 : skyindices.clear();
516 0 : matsurfs.clear();
517 0 : mapmodels.clear();
518 0 : decals.clear();
519 0 : extdecals.clear();
520 0 : grasstris.clear();
521 0 : texs.clear();
522 0 : decaltexs.clear();
523 0 : alphamin = refractmin = skymin = vec(1e16f, 1e16f, 1e16f);
524 0 : alphamax = refractmax = skymax = vec(-1e16f, -1e16f, -1e16f);
525 0 : }
526 :
527 0 : void vacollect::setupdata(vtxarray *va)
528 : {
529 0 : optimize();
530 0 : gendecals();
531 :
532 0 : va->verts = verts.size();
533 0 : va->tris = worldtris/3;
534 0 : va->vbuf = 0;
535 0 : va->vdata = 0;
536 0 : va->minvert = 0;
537 0 : va->maxvert = va->verts-1;
538 0 : va->voffset = 0;
539 0 : if(va->verts)
540 : {
541 0 : if(vbosize[VBO_VBuf] + static_cast<int>(verts.size()) > maxvbosize ||
542 0 : vbosize[VBO_EBuf] + worldtris > USHRT_MAX ||
543 0 : vbosize[VBO_SkyBuf] + skytris > USHRT_MAX ||
544 0 : vbosize[VBO_DecalBuf] + decaltris > USHRT_MAX)
545 : {
546 0 : flushvbo();
547 : }
548 0 : uchar *vdata = addvbo(va, VBO_VBuf, va->verts, sizeof(vertex));
549 0 : genverts(vdata);
550 0 : va->minvert += va->voffset;
551 0 : va->maxvert += va->voffset;
552 : }
553 :
554 0 : va->matbuf.clear();
555 0 : va->matsurfs = matsurfs.size();
556 0 : va->matmask = 0;
557 0 : if(va->matsurfs)
558 : {
559 0 : va->matbuf = matsurfs;
560 0 : for(materialsurface &m : matsurfs)
561 : {
562 0 : if(m.visible == MatSurf_EditOnly)
563 : {
564 0 : continue;
565 : }
566 0 : switch(m.material)
567 : {
568 0 : case Mat_Glass:
569 : case Mat_Water:
570 : {
571 0 : break;
572 : }
573 0 : default:
574 : {
575 0 : continue;
576 : }
577 : }
578 0 : va->matmask |= 1<<m.material;
579 : }
580 : }
581 :
582 0 : va->skybuf = 0;
583 0 : va->skydata = 0;
584 0 : va->skyoffset = 0;
585 0 : va->sky = skyindices.size();
586 0 : if(va->sky)
587 : {
588 0 : ushort *skydata = reinterpret_cast<ushort *>(addvbo(va, VBO_SkyBuf, va->sky, sizeof(ushort)));
589 0 : std::memcpy(skydata, skyindices.data(), va->sky*sizeof(ushort));
590 0 : if(va->voffset)
591 : {
592 0 : for(uint i = 0; i < va->sky; ++i)
593 : {
594 0 : skydata[i] += va->voffset;
595 : }
596 : }
597 : }
598 :
599 0 : va->texelems = nullptr;
600 0 : va->texs = texs.size();
601 0 : va->alphabacktris = 0;
602 0 : va->alphaback = 0;
603 0 : va->alphafronttris = 0;
604 0 : va->alphafront = 0;
605 0 : va->refracttris = 0;
606 0 : va->refract = 0;
607 0 : va->ebuf = 0;
608 0 : va->edata = 0;
609 0 : va->eoffset = 0;
610 0 : if(va->texs)
611 : {
612 0 : va->texelems = new ElementSet[va->texs];
613 0 : ushort *edata = reinterpret_cast<ushort *>(addvbo(va, VBO_EBuf, worldtris, sizeof(ushort))),
614 0 : *curbuf = edata;
615 0 : for(size_t i = 0; i < texs.size(); i++)
616 : {
617 0 : const SortKey &k = texs[i];
618 0 : const sortval &t = indices[k];
619 0 : ElementSet &e = va->texelems[i];
620 0 : e.texture = k.tex;
621 0 : e.attrs.orient = k.orient;
622 0 : e.attrs.layer = k.layer;
623 0 : const ushort *startbuf = curbuf;
624 0 : e.minvert = USHRT_MAX;
625 0 : e.maxvert = 0;
626 :
627 0 : if(t.tris.size())
628 : {
629 0 : std::memcpy(curbuf, t.tris.data(), t.tris.size() * sizeof(ushort));
630 0 : for(size_t j = 0; j < t.tris.size(); j++)
631 : {
632 0 : curbuf[j] += va->voffset;
633 0 : e.minvert = std::min(e.minvert, curbuf[j]);
634 0 : e.maxvert = std::max(e.maxvert, curbuf[j]);
635 : }
636 0 : curbuf += t.tris.size();
637 : }
638 0 : e.length = curbuf-startbuf;
639 0 : if(k.alpha==Alpha_Back)
640 : {
641 0 : va->texs--;
642 0 : va->tris -= e.length/3;
643 0 : va->alphaback++;
644 0 : va->alphabacktris += e.length/3;
645 : }
646 0 : else if(k.alpha==Alpha_Front)
647 : {
648 0 : va->texs--;
649 0 : va->tris -= e.length/3;
650 0 : va->alphafront++;
651 0 : va->alphafronttris += e.length/3;
652 : }
653 0 : else if(k.alpha==Alpha_Refract)
654 : {
655 0 : va->texs--;
656 0 : va->tris -= e.length/3;
657 0 : va->refract++;
658 0 : va->refracttris += e.length/3;
659 : }
660 : }
661 : }
662 :
663 0 : va->texmask = 0;
664 0 : va->dyntexs = 0;
665 0 : for(int i = 0; i < (va->texs+va->alphaback+va->alphafront+va->refract); ++i)
666 : {
667 0 : VSlot &vslot = lookupvslot(va->texelems[i].texture, false);
668 0 : if(vslot.isdynamic())
669 : {
670 0 : va->dyntexs++;
671 : }
672 0 : Slot &slot = *vslot.slot;
673 0 : for(DecalSlot::Tex j : slot.sts)
674 : {
675 0 : va->texmask |= 1 << j.type;
676 : }
677 : }
678 :
679 0 : va->decalbuf = 0;
680 0 : va->decaldata = 0;
681 0 : va->decaloffset = 0;
682 0 : va->decalelems = nullptr;
683 0 : va->decaltexs = decaltexs.size();
684 0 : va->decaltris = decaltris/3;
685 0 : if(va->decaltexs)
686 : {
687 0 : va->decalelems = new ElementSet[va->decaltexs];
688 0 : ushort *edata = reinterpret_cast<ushort *>(addvbo(va, VBO_DecalBuf, decaltris, sizeof(ushort))),
689 0 : *curbuf = edata;
690 0 : for(size_t i = 0; i < decaltexs.size(); i++)
691 : {
692 0 : const decalkey &k = decaltexs[i];
693 0 : const sortval &t = decalindices[k];
694 0 : ElementSet &e = va->decalelems[i];
695 0 : e.texture = k.tex;
696 0 : e.reuse = k.reuse;
697 0 : ushort *startbuf = curbuf;
698 0 : e.minvert = USHRT_MAX;
699 0 : e.maxvert = 0;
700 0 : if(t.tris.size())
701 : {
702 0 : std::memcpy(curbuf, t.tris.data(), t.tris.size() * sizeof(ushort));
703 0 : for(size_t j = 0; j < t.tris.size(); j++)
704 : {
705 0 : curbuf[j] += va->voffset;
706 0 : e.minvert = std::min(e.minvert, curbuf[j]);
707 0 : e.maxvert = std::max(e.maxvert, curbuf[j]);
708 : }
709 0 : curbuf += t.tris.size();
710 : }
711 0 : e.length = curbuf-startbuf;
712 : }
713 : }
714 0 : if(grasstris.size())
715 : {
716 0 : std::swap(va->grasstris, grasstris);
717 0 : loadgrassshaders();
718 : }
719 0 : if(mapmodels.size())
720 : {
721 0 : va->mapmodels.insert(va->decals.end(), mapmodels.begin(), mapmodels.end());
722 : }
723 0 : if(decals.size())
724 : {
725 0 : va->decals.insert(va->decals.end(), decals.begin(), decals.end());
726 : }
727 0 : }
728 :
729 0 : bool vacollect::emptyva()
730 : {
731 0 : return verts.empty() && matsurfs.empty() && skyindices.empty() && grasstris.empty() && mapmodels.empty() && decals.empty();
732 : }
733 :
734 0 : void vacollect::optimize()
735 : {
736 0 : for(auto &[k, t] : indices)
737 : {
738 0 : if(t.tris.size())
739 : {
740 0 : texs.push_back(k);
741 : }
742 : }
743 0 : std::sort(texs.begin(), texs.end(), SortKey::sort);
744 :
745 0 : matsurfs.resize(optimizematsurfs(matsurfs.data(), matsurfs.size()));
746 0 : }
747 :
748 0 : void vacollect::genverts(uchar *buf)
749 : {
750 0 : vertex *f = reinterpret_cast<vertex *>(buf);
751 0 : for(const vertex &i : verts)
752 : {
753 0 : const vertex &v = i;
754 0 : *f = v;
755 0 : f->norm.flip();
756 0 : f->tangent.flip();
757 0 : f++;
758 : }
759 0 : }
760 :
761 0 : void vacollect::gendecal(const extentity &e, const DecalSlot &s, const decalkey &key)
762 : {
763 0 : matrix3 orient;
764 0 : orient.identity();
765 0 : if(e.attr2)
766 : {
767 0 : orient.rotate_around_z(sincosmod360(e.attr2));
768 : }
769 0 : if(e.attr3)
770 : {
771 0 : orient.rotate_around_x(sincosmod360(e.attr3));
772 : }
773 0 : if(e.attr4)
774 : {
775 0 : orient.rotate_around_y(sincosmod360(-e.attr4));
776 : }
777 0 : vec size(std::max(static_cast<float>(e.attr5), 1.0f));
778 0 : size.y *= s.depth;
779 0 : if(!s.sts.empty())
780 : {
781 0 : Texture *t = s.sts[0].t;
782 0 : if(t->xs < t->ys)
783 : {
784 0 : size.x *= t->xs / static_cast<float>(t->ys);
785 : }
786 0 : else if(t->xs > t->ys)
787 : {
788 0 : size.z *= t->ys / static_cast<float>(t->xs);
789 : }
790 : }
791 0 : vec center = orient.transform(vec(0, size.y*0.5f, 0)).add(e.o),
792 0 : radius = orient.abstransform(vec(size).mul(0.5f)),
793 0 : bbmin = vec(center).sub(radius),
794 0 : bbmax = vec(center).add(radius),
795 0 : clipoffset = orient.transposedtransform(center).msub(size, 0.5f);
796 0 : for(size_t i = 0; i < texs.size(); i++)
797 : {
798 0 : const SortKey &k = texs[i];
799 0 : if(k.layer == BlendLayer_Blend || k.alpha != Alpha_None)
800 : {
801 0 : continue;
802 : }
803 0 : const sortval &t = indices[k];
804 0 : if(t.tris.empty())
805 : {
806 0 : continue;
807 : }
808 0 : decalkey tkey(key);
809 0 : if(shouldreuseparams(s, lookupvslot(k.tex, false)))
810 : {
811 0 : tkey.reuse = k.tex;
812 : }
813 0 : for(size_t j = 0; j < t.tris.size(); j += 3)
814 : {
815 0 : const vertex &t0 = verts[t.tris[j]],
816 0 : &t1 = verts[t.tris[j+1]],
817 0 : &t2 = verts[t.tris[j+2]];
818 0 : vec v0 = t0.pos,
819 0 : v1 = t1.pos,
820 0 : v2 = t2.pos,
821 0 : tmin = vec(v0).min(v1).min(v2),
822 0 : tmax = vec(v0).max(v1).max(v2);
823 0 : if(tmin.x >= bbmax.x || tmin.y >= bbmax.y || tmin.z >= bbmax.z ||
824 0 : tmax.x <= bbmin.x || tmax.y <= bbmin.y || tmax.z <= bbmin.z)
825 : {
826 0 : continue;
827 : }
828 0 : float f0 = t0.norm.tonormal().dot(orient.b),
829 0 : f1 = t1.norm.tonormal().dot(orient.b),
830 0 : f2 = t2.norm.tonormal().dot(orient.b);
831 0 : if(f0 >= 0 && f1 >= 0 && f2 >= 0)
832 : {
833 0 : continue;
834 : }
835 0 : std::array<vec, 9> p1, p2;
836 0 : p1[0] = v0;
837 0 : p1[1] = v1;
838 0 : p1[2] = v2;
839 0 : int nump = polyclip(p1.data(), 3, orient.b, clipoffset.y, clipoffset.y + size.y, p2.data());
840 0 : if(nump < 3)
841 : {
842 0 : continue;
843 : }
844 0 : nump = polyclip(p2.data(), nump, orient.a, clipoffset.x, clipoffset.x + size.x, p1.data());
845 0 : if(nump < 3)
846 : {
847 0 : continue;
848 : }
849 0 : nump = polyclip(p1.data(), nump, orient.c, clipoffset.z, clipoffset.z + size.z, p2.data());
850 0 : if(nump < 3)
851 : {
852 0 : continue;
853 : }
854 0 : vec4<uchar> n0 = t0.norm,
855 0 : n1 = t1.norm,
856 0 : n2 = t2.norm,
857 0 : x0 = t0.tangent,
858 0 : x1 = t1.tangent,
859 0 : x2 = t2.tangent;
860 0 : vec e1 = vec(v1).sub(v0),
861 0 : e2 = vec(v2).sub(v0);
862 0 : float d11 = e1.dot(e1),
863 0 : d12 = e1.dot(e2),
864 0 : d22 = e2.dot(e2);
865 : std::array<int, 9> idx;
866 0 : for(int k = 0; k < nump; ++k)
867 : {
868 0 : vertex v;
869 0 : v.pos = p2[k];
870 0 : vec ep = vec(v.pos).sub(v0);
871 0 : float dp1 = ep.dot(e1),
872 0 : dp2 = ep.dot(e2),
873 0 : denom = d11*d22 - d12*d12,
874 0 : b1 = (d22*dp1 - d12*dp2) / denom,
875 0 : b2 = (d11*dp2 - d12*dp1) / denom,
876 0 : b0 = 1 - b1 - b2;
877 0 : v.norm.lerp(n0, n1, n2, b0, b1, b2);
878 0 : v.norm.w = static_cast<uchar>(127.5f - 127.5f*(f0*b0 + f1*b1 + f2*b2));
879 0 : vec tc = orient.transposedtransform(vec(center).sub(v.pos)).div(size).add(0.5f);
880 0 : v.tc = vec(tc.x, tc.z, s.fade ? tc.y * s.depth / s.fade : 1.0f);
881 0 : v.tangent.lerp(x0, x1, x2, b0, b1, b2);
882 0 : idx[k] = addvert(v);
883 : }
884 0 : std::vector<ushort> &tris = decalindices[tkey].tris;
885 0 : for(int k = 0; k < nump-2; ++k)
886 : {
887 0 : if(idx[0] != idx[k+1] && idx[k+1] != idx[k+2] && idx[k+2] != idx[0])
888 : {
889 0 : tris.push_back(idx[0]);
890 0 : tris.push_back(idx[k+1]);
891 0 : tris.push_back(idx[k+2]);
892 0 : decaltris += 3;
893 : }
894 : }
895 : }
896 : }
897 0 : }
898 :
899 0 : void vacollect::gendecals()
900 : {
901 0 : if(decals.size())
902 : {
903 0 : extdecals.insert(extdecals.end(), decals.begin(), decals.end());
904 : }
905 0 : if(extdecals.empty())
906 : {
907 0 : return;
908 : }
909 0 : const std::vector<extentity *> &ents = entities::getents();
910 0 : for(const octaentities* oe : extdecals)
911 : {
912 : //get an index to ents in this VA from oe->decals
913 0 : for(const uint j : oe->decals)
914 : {
915 0 : extentity &e = *ents[j];
916 0 : if(e.flags&EntFlag_Render)
917 : {
918 0 : continue;
919 : }
920 0 : e.flags |= EntFlag_Render;
921 0 : const DecalSlot &s = lookupdecalslot(e.attr1, true);
922 0 : if(!s.shader)
923 : {
924 0 : continue;
925 : }
926 0 : const decalkey k(e.attr1);
927 0 : gendecal(e, s, k);
928 : }
929 : }
930 0 : for(const octaentities* oe : extdecals)
931 : {
932 : //get an index to ents in this VA from oe->decals
933 0 : for(const uint j : oe->decals)
934 : {
935 0 : extentity &e = *ents[j];
936 0 : if(e.flags&EntFlag_Render)
937 : {
938 0 : e.flags &= ~EntFlag_Render;
939 : }
940 : }
941 : }
942 0 : for(auto &[k, t] : decalindices)
943 : {
944 0 : if(t.tris.size())
945 : {
946 0 : decaltexs.push_back(k);
947 : }
948 : }
949 0 : std::sort(texs.begin(), texs.end(), SortKey::sort);
950 : }
951 :
952 0 : int vacollect::genmergedfaces(cube &c, const ivec &co, int size, int minlevel)
953 : {
954 0 : if(!c.ext || c.isempty())
955 : {
956 0 : return -1;
957 : }
958 0 : int tj = c.ext->tjoints,
959 0 : maxlevel = -1;
960 0 : for(size_t i = 0; i < c.ext->surfaces.size(); ++i)
961 : {
962 0 : if(c.merged&(1<<i))
963 : {
964 0 : surfaceinfo &surf = c.ext->surfaces[i];
965 0 : const int numverts = surf.numverts&Face_MaxVerts;
966 0 : if(!numverts)
967 : {
968 0 : if(minlevel < 0)
969 : {
970 0 : vahasmerges |= Merge_Part;
971 : }
972 0 : continue;
973 : }
974 : MergedFace mf;
975 0 : mf.orient = i;
976 0 : mf.mat = c.material;
977 0 : mf.tex = c.texture[i];
978 0 : mf.numverts = surf.numverts;
979 0 : mf.verts = c.ext->verts() + surf.verts;
980 0 : mf.tjoints = -1;
981 0 : const int level = calcmergedsize(co, size, mf.verts, mf.numverts&Face_MaxVerts);
982 0 : if(level > minlevel)
983 : {
984 0 : maxlevel = std::max(maxlevel, level);
985 :
986 0 : while(tj >= 0 && tjoints[tj].edge < i*(Face_MaxVerts+1))
987 : {
988 0 : tj = tjoints[tj].next;
989 : }
990 0 : if(tj >= 0 && tjoints[tj].edge < (i+1)*(Face_MaxVerts+1))
991 : {
992 0 : mf.tjoints = tj;
993 : }
994 0 : if(surf.numverts&BlendLayer_Top)
995 : {
996 0 : vamerges[level].push_back(mf);
997 : }
998 0 : if(surf.numverts&BlendLayer_Bottom)
999 : {
1000 0 : mf.numverts &= ~BlendLayer_Blend;
1001 0 : mf.numverts |= surf.numverts&BlendLayer_Top ? BlendLayer_Bottom : BlendLayer_Top;
1002 0 : vamerges[level].push_back(mf);
1003 : }
1004 : }
1005 : }
1006 : }
1007 0 : if(maxlevel >= 0)
1008 : {
1009 0 : vamergemax = std::max(vamergemax, maxlevel);
1010 0 : vahasmerges |= Merge_Origin;
1011 : }
1012 0 : return maxlevel;
1013 : }
1014 :
1015 0 : int vacollect::findmergedfaces(cube &c, const ivec &co, int size, int csi, int minlevel)
1016 : {
1017 0 : if(c.ext && c.ext->va && !(c.ext->va->hasmerges&Merge_Origin))
1018 : {
1019 0 : return c.ext->va->mergelevel;
1020 : }
1021 0 : else if(c.children)
1022 : {
1023 0 : int maxlevel = -1;
1024 0 : for(int i = 0; i < 8; ++i)
1025 : {
1026 0 : const ivec o(i, co, size/2);
1027 0 : const int level = findmergedfaces((*c.children)[i], o, size/2, csi-1, minlevel);
1028 0 : maxlevel = std::max(maxlevel, level);
1029 : }
1030 0 : return maxlevel;
1031 : }
1032 0 : else if(c.ext && c.merged)
1033 : {
1034 0 : return genmergedfaces(c, co, size, minlevel);
1035 : }
1036 : else
1037 : {
1038 0 : return -1;
1039 : }
1040 : }
1041 :
1042 : /**
1043 : * @brief Sets visibility field for specified cube.
1044 : *
1045 : * @param c the cube to modify
1046 : * @param co face vector
1047 : * @param size cube size for comparison with neighbors
1048 : *
1049 : * @return number of visible faces
1050 : */
1051 0 : static int setcubevisibility(cube &c, const ivec &co, int size)
1052 : {
1053 0 : if(c.isempty() && (c.material&MatFlag_Clip) != Mat_Clip)
1054 : {
1055 0 : return 0;
1056 : }
1057 0 : int numvis = 0,
1058 0 : vismask = 0,
1059 0 : collidemask = 0,
1060 0 : checkmask = 0;
1061 0 : for(int i = 0; i < 6; ++i)
1062 : {
1063 0 : int facemask = classifyface(c, i, co, size);
1064 0 : if(facemask&1)
1065 : {
1066 0 : vismask |= 1<<i;
1067 0 : if(c.merged&(1<<i))
1068 : {
1069 0 : if(c.ext && c.ext->surfaces[i].numverts&Face_MaxVerts)
1070 : {
1071 0 : numvis++;
1072 : }
1073 : }
1074 : else
1075 : {
1076 0 : numvis++;
1077 0 : if(c.texture[i] != Default_Sky && !(c.ext && c.ext->surfaces[i].numverts & Face_MaxVerts))
1078 : {
1079 0 : checkmask |= 1<<i;
1080 : }
1081 : }
1082 : }
1083 0 : if(facemask&2)
1084 : {
1085 0 : collidemask |= 1<<i;
1086 : }
1087 : }
1088 0 : c.visible = collidemask | (vismask ? (vismask != collidemask ? (checkmask ? 0x80|0x40 : 0x80) : 0x40) : 0);
1089 0 : return numvis;
1090 : }
1091 :
1092 : //index array must be >= numverts long
1093 : //verts array must be >= Face_MaxVerts + 1 and >= numverts long
1094 0 : void vacollect::addtris(const VSlot &vslot, int orient, const SortKey &key, vertex *verts, const int *index, int numverts, int tj)
1095 : {
1096 0 : int &total = key.tex == Default_Sky ? skytris : worldtris,
1097 0 : edge = orient*(Face_MaxVerts+1);
1098 0 : for(int i = 0; i < numverts-2; ++i)
1099 : {
1100 0 : if(index[0]!=index[i+1] && index[i+1]!=index[i+2] && index[i+2]!=index[0])
1101 : {
1102 0 : std::vector<ushort> &idxs = key.tex == Default_Sky ? skyindices : indices[key].tris;
1103 0 : int left = index[0],
1104 0 : mid = index[i+1],
1105 0 : right = index[i+2],
1106 0 : start = left,
1107 0 : i0 = left,
1108 0 : i1 = -1;
1109 0 : for(int k = 0; k < 4; ++k)
1110 : {
1111 0 : int i2 = -1,
1112 0 : ctj = -1,
1113 0 : cedge = -1;
1114 0 : switch(k)
1115 : {
1116 0 : case 1:
1117 : {
1118 0 : i1 = i2 = mid;
1119 0 : cedge = edge+i+1;
1120 0 : break;
1121 : }
1122 0 : case 2:
1123 : {
1124 0 : if(i1 != mid || i0 == left)
1125 : {
1126 0 : i0 = i1;
1127 0 : i1 = right;
1128 : }
1129 0 : i2 = right;
1130 0 : if(i+1 == numverts-2)
1131 : {
1132 0 : cedge = edge+i+2;
1133 : }
1134 0 : break;
1135 : }
1136 0 : case 3:
1137 : {
1138 0 : if(i0 == start)
1139 : {
1140 0 : i0 = i1;
1141 0 : i1 = left;
1142 : }
1143 0 : i2 = left;
1144 : }
1145 : [[fallthrough]];
1146 0 : default:
1147 : {
1148 0 : if(!i)
1149 : {
1150 0 : cedge = edge;
1151 : }
1152 0 : break;
1153 : }
1154 : }
1155 0 : if(i1 != i2)
1156 : {
1157 0 : if(total + 3 > USHRT_MAX)
1158 : {
1159 0 : return;
1160 : }
1161 0 : total += 3;
1162 0 : idxs.push_back(i0);
1163 0 : idxs.push_back(i1);
1164 0 : idxs.push_back(i2);
1165 0 : i1 = i2;
1166 : }
1167 0 : if(cedge >= 0)
1168 : {
1169 0 : for(ctj = tj;;)
1170 : {
1171 0 : if(ctj < 0)
1172 : {
1173 0 : break;
1174 : }
1175 0 : if(tjoints[ctj].edge < cedge)
1176 : {
1177 0 : ctj = tjoints[ctj].next;
1178 0 : continue;
1179 : }
1180 0 : if(tjoints[ctj].edge != cedge)
1181 : {
1182 0 : ctj = -1;
1183 : }
1184 0 : break;
1185 : }
1186 : }
1187 0 : if(ctj >= 0)
1188 : {
1189 0 : int e1 = cedge%(Face_MaxVerts+1),
1190 0 : e2 = (e1+1)%numverts;
1191 0 : vertex &v1 = verts[e1],
1192 0 : &v2 = verts[e2];
1193 0 : ivec d(vec(v2.pos).sub(v1.pos).mul(8));
1194 0 : int axis = std::abs(d.x) > std::abs(d.y) ? (std::abs(d.x) > std::abs(d.z) ? 0 : 2) : (std::abs(d.y) > std::abs(d.z) ? 1 : 2);
1195 0 : if(d[axis] < 0)
1196 : {
1197 0 : d.neg();
1198 : }
1199 0 : reduceslope(d);
1200 0 : int origin = static_cast<int>(std::min(v1.pos[axis], v2.pos[axis])*8)&~0x7FFF,
1201 0 : offset1 = (static_cast<int>(v1.pos[axis]*8) - origin) / d[axis],
1202 0 : offset2 = (static_cast<int>(v2.pos[axis]*8) - origin) / d[axis];
1203 0 : vec o = vec(v1.pos).sub(vec(d).mul(offset1/8.0f));
1204 0 : float doffset = 1.0f / (offset2 - offset1);
1205 :
1206 0 : if(i1 < 0)
1207 : {
1208 : for(;;)
1209 : {
1210 0 : TJoint &t = tjoints[ctj];
1211 0 : if(t.next < 0 || tjoints[t.next].edge != cedge)
1212 : {
1213 0 : break;
1214 : }
1215 0 : ctj = t.next;
1216 0 : }
1217 : }
1218 0 : while(ctj >= 0)
1219 : {
1220 0 : TJoint &t = tjoints[ctj];
1221 0 : if(t.edge != cedge)
1222 : {
1223 0 : break;
1224 : }
1225 0 : float offset = (t.offset - offset1) * doffset;
1226 0 : vertex vt;
1227 0 : vt.pos = vec(d).mul(t.offset/8.0f).add(o);
1228 0 : vt.tc.lerp(v1.tc, v2.tc, offset);
1229 0 : vt.norm.lerp(v1.norm, v2.norm, offset);
1230 0 : vt.tangent.lerp(v1.tangent, v2.tangent, offset);
1231 0 : if(v1.tangent.w != v2.tangent.w)
1232 : {
1233 0 : vt.tangent.w = orientation_bitangent[vslot.rotation][orient].scalartriple(vt.norm.tonormal(), vt.tangent.tonormal()) < 0 ? 0 : 255;
1234 : }
1235 0 : int i2 = addvert(vt);
1236 0 : if(i2 < 0)
1237 : {
1238 0 : return;
1239 : }
1240 0 : if(i1 >= 0)
1241 : {
1242 0 : if(total + 3 > USHRT_MAX)
1243 : {
1244 0 : return;
1245 : }
1246 0 : total += 3;
1247 0 : idxs.push_back(i0);
1248 0 : idxs.push_back(i1);
1249 0 : idxs.push_back(i2);
1250 0 : i1 = i2;
1251 : }
1252 : else
1253 : {
1254 0 : start = i0 = i2;
1255 : }
1256 0 : ctj = t.next;
1257 : }
1258 : }
1259 : }
1260 : }
1261 : }
1262 : }
1263 :
1264 : //face: index of which face to cover
1265 : //verts: information about grass texs' face, array of vertices, must be >= face+3 long
1266 : //numv: number of grass vertices
1267 : //texture: index for the grass texture to use
1268 0 : void vacollect::addgrasstri(int face, const vertex *verts, int numv, ushort texture)
1269 : {
1270 0 : grasstris.emplace_back();
1271 0 : grasstri &g = grasstris.back();
1272 : int i1, i2, i3, i4;
1273 0 : if(numv <= 3 && face%2)
1274 : {
1275 0 : i1 = face+1;
1276 0 : i2 = face+2;
1277 0 : i3 = i4 = 0;
1278 : }
1279 : else
1280 : {
1281 0 : i1 = 0;
1282 0 : i2 = face+1;
1283 0 : i3 = face+2;
1284 0 : i4 = numv > 3 ? face+3 : i3;
1285 : }
1286 0 : g.v[0] = verts[i1].pos;
1287 0 : g.v[1] = verts[i2].pos;
1288 0 : g.v[2] = verts[i3].pos;
1289 0 : g.v[3] = verts[i4].pos;
1290 0 : g.numv = numv;
1291 0 : g.surface.toplane(g.v[0], g.v[1], g.v[2]);
1292 0 : if(g.surface.z <= 0)
1293 : {
1294 0 : grasstris.pop_back();
1295 0 : return;
1296 : }
1297 0 : g.minz = std::min(std::min(g.v[0].z, g.v[1].z), std::min(g.v[2].z, g.v[3].z));
1298 0 : g.maxz = std::max(std::max(g.v[0].z, g.v[1].z), std::max(g.v[2].z, g.v[3].z));
1299 0 : g.center = vec(0, 0, 0);
1300 0 : for(int k = 0; k < numv; ++k)
1301 : {
1302 0 : g.center.add(g.v[k]);
1303 : }
1304 0 : g.center.div(numv);
1305 0 : g.radius = 0;
1306 0 : for(int k = 0; k < numv; ++k)
1307 : {
1308 0 : g.radius = std::max(g.radius, g.v[k].dist(g.center));
1309 : }
1310 0 : g.texture = texture;
1311 : }
1312 :
1313 0 : void vacollect::gencubeverts(const cube &c, const ivec &co, int size)
1314 : {
1315 0 : if(!(c.visible&0xC0))
1316 : {
1317 0 : return;
1318 : }
1319 0 : int vismask = ~c.merged & 0x3F;
1320 0 : if(!(c.visible&0x80))
1321 : {
1322 0 : vismask &= c.visible;
1323 : }
1324 0 : if(!vismask)
1325 : {
1326 0 : return;
1327 : }
1328 0 : int tj = filltjoints && c.ext ? c.ext->tjoints : -1, vis;
1329 0 : for(int i = 0; i < 6; ++i)
1330 : {
1331 0 : if(vismask&(1<<i) && (vis = visibletris(c, i, co, size)))
1332 : {
1333 0 : vec pos[Face_MaxVerts];
1334 0 : vertinfo *verts = nullptr;
1335 0 : int numverts = c.ext ? c.ext->surfaces[i].numverts&Face_MaxVerts : 0,
1336 0 : convex = 0;
1337 0 : if(numverts)
1338 : {
1339 0 : verts = c.ext->verts() + c.ext->surfaces[i].verts;
1340 0 : vec vo(ivec(co).mask(~0xFFF));
1341 0 : for(int j = 0; j < numverts; ++j)
1342 : {
1343 0 : pos[j] = vec(verts[j].getxyz()).mul(1.0f/8).add(vo);
1344 : }
1345 0 : if(!flataxisface(c, i))
1346 : {
1347 0 : convex = faceconvexity(verts, numverts, size);
1348 : }
1349 : }
1350 : else
1351 : {
1352 0 : std::array<ivec, 4> v;
1353 0 : genfaceverts(c, i, v);
1354 0 : if(!flataxisface(c, i))
1355 : {
1356 0 : convex = faceconvexity(v);
1357 : }
1358 0 : int order = vis&4 || convex < 0 ? 1 : 0;
1359 0 : vec vo(co);
1360 0 : pos[numverts++] = vec(v[order]).mul(size/8.0f).add(vo);
1361 0 : if(vis&1)
1362 : {
1363 0 : pos[numverts++] = vec(v[order+1]).mul(size/8.0f).add(vo);
1364 : }
1365 0 : pos[numverts++] = vec(v[order+2]).mul(size/8.0f).add(vo);
1366 0 : if(vis&2)
1367 : {
1368 0 : pos[numverts++] = vec(v[(order+3)&3]).mul(size/8.0f).add(vo);
1369 : }
1370 : }
1371 :
1372 0 : VSlot &vslot = lookupvslot(c.texture[i], true);
1373 0 : while(tj >= 0 && tjoints[tj].edge < i*(Face_MaxVerts+1))
1374 : {
1375 0 : tj = tjoints[tj].next;
1376 : }
1377 0 : int hastj = tj >= 0 && tjoints[tj].edge < (i+1)*(Face_MaxVerts+1) ? tj : -1,
1378 0 : grassy = vslot.slot->grass && i!=Orient_Bottom ? (vis!=3 || convex ? 1 : 2) : 0;
1379 0 : if(!c.ext)
1380 : {
1381 0 : addcubeverts(vslot, i, pos, c.texture[i], nullptr, numverts, hastj, grassy, (c.material&Mat_Alpha)!=0);
1382 : }
1383 : else
1384 : {
1385 0 : const surfaceinfo &surf = c.ext->surfaces[i];
1386 0 : if(!surf.numverts || surf.numverts&BlendLayer_Top)
1387 : {
1388 0 : addcubeverts(vslot, i, pos, c.texture[i], verts, numverts, hastj, grassy, (c.material&Mat_Alpha)!=0, surf.numverts&BlendLayer_Blend);
1389 : }
1390 0 : if(surf.numverts&BlendLayer_Bottom)
1391 : {
1392 0 : addcubeverts(vslot, i, pos, 0, verts, numverts, hastj, 0, false, surf.numverts&BlendLayer_Top ? BlendLayer_Bottom : BlendLayer_Top);
1393 : }
1394 : }
1395 : }
1396 : }
1397 : }
1398 :
1399 :
1400 0 : vtxarray *vacollect::newva(const ivec &o, int size)
1401 : {
1402 0 : vtxarray *va = new vtxarray;
1403 0 : va->parent = nullptr;
1404 0 : va->o = o;
1405 0 : va->size = size;
1406 0 : va->curvfc = ViewFrustumCull_NotVisible;
1407 0 : va->occluded = Occlude_Nothing;
1408 0 : va->query = nullptr;
1409 0 : va->bbmin = va->alphamin = va->refractmin = va->skymin = ivec(-1, -1, -1);
1410 0 : va->bbmax = va->alphamax = va->refractmax = va->skymax = ivec(-1, -1, -1);
1411 0 : va->hasmerges = 0;
1412 0 : va->mergelevel = -1;
1413 :
1414 0 : setupdata(va);
1415 :
1416 0 : if(va->alphafronttris || va->alphabacktris || va->refracttris)
1417 : {
1418 0 : va->alphamin = ivec(vec(alphamin).mul(8)).shr(3);
1419 0 : va->alphamax = ivec(vec(alphamax).mul(8)).add(7).shr(3);
1420 : }
1421 0 : if(va->refracttris)
1422 : {
1423 0 : va->refractmin = ivec(vec(refractmin).mul(8)).shr(3);
1424 0 : va->refractmax = ivec(vec(refractmax).mul(8)).add(7).shr(3);
1425 : }
1426 0 : if(va->sky && skymax.x >= 0)
1427 : {
1428 0 : va->skymin = ivec(vec(skymin).mul(8)).shr(3);
1429 0 : va->skymax = ivec(vec(skymax).mul(8)).add(7).shr(3);
1430 : }
1431 :
1432 0 : wverts += va->verts;
1433 0 : wtris += va->tris + va->alphabacktris + va->alphafronttris + va->refracttris + va->decaltris;
1434 0 : allocva++;
1435 0 : valist.push_back(va);
1436 0 : return va;
1437 : }
1438 :
1439 0 : void vacollect::addmergedverts(int level, const ivec &o)
1440 : {
1441 0 : std::vector<MergedFace> &mfl = vamerges[level];
1442 0 : if(mfl.empty())
1443 : {
1444 0 : return;
1445 : }
1446 0 : vec vo(ivec(o).mask(~0xFFF));
1447 0 : vec pos[Face_MaxVerts];
1448 0 : for(MergedFace &mf : mfl)
1449 : {
1450 0 : int numverts = mf.numverts&Face_MaxVerts;
1451 0 : for(int i = 0; i < numverts; ++i)
1452 : {
1453 0 : const vertinfo &v = mf.verts[i];
1454 0 : pos[i] = vec(v.x, v.y, v.z).mul(1.0f/8).add(vo);
1455 : }
1456 0 : VSlot &vslot = lookupvslot(mf.tex, true);
1457 0 : int grassy = vslot.slot->grass && mf.orient!=Orient_Bottom && mf.numverts&BlendLayer_Top ? 2 : 0;
1458 0 : addcubeverts(vslot, mf.orient, pos, mf.tex, mf.verts, numverts, mf.tjoints, grassy, (mf.mat&Mat_Alpha)!=0, mf.numverts&BlendLayer_Blend);
1459 0 : vahasmerges |= Merge_Use;
1460 : }
1461 0 : mfl.clear();
1462 : }
1463 :
1464 : //recursively finds and adds decals to vacollect object
1465 0 : void vacollect::finddecals(const vtxarray *va)
1466 : {
1467 0 : if(va->hasmerges&(Merge_Origin|Merge_Part))
1468 : {
1469 0 : for(const octaentities * const i : va->decals)
1470 : {
1471 0 : extdecals.push_back(i);
1472 : }
1473 0 : for(const vtxarray * const i : va->children)
1474 : {
1475 0 : finddecals(i);
1476 : }
1477 : }
1478 0 : }
1479 :
1480 0 : void vacollect::rendercube(cube &c, const ivec &co, int size, int csi, int &maxlevel)
1481 : {
1482 0 : if(c.ext && c.ext->va)
1483 : {
1484 0 : maxlevel = std::max(maxlevel, c.ext->va->mergelevel);
1485 0 : finddecals(c.ext->va);
1486 0 : return; // don't re-render
1487 : }
1488 :
1489 0 : if(c.children)
1490 : {
1491 0 : neighborstack[++neighbordepth] = &(*c.children)[0];
1492 0 : c.escaped = 0;
1493 0 : for(int i = 0; i < 8; ++i)
1494 : {
1495 0 : ivec o(i, co, size/2);
1496 0 : int level = -1;
1497 0 : rendercube((*c.children)[i], o, size/2, csi-1, level);
1498 0 : if(level >= csi)
1499 : {
1500 0 : c.escaped |= 1<<i;
1501 : }
1502 0 : maxlevel = std::max(maxlevel, level);
1503 : }
1504 0 : --neighbordepth;
1505 :
1506 0 : if(csi <= maxmergelevel && vamerges[csi].size())
1507 : {
1508 0 : addmergedverts(csi, co);
1509 : }
1510 0 : if(c.ext && c.ext->ents)
1511 : {
1512 0 : if(c.ext->ents->mapmodels.size())
1513 : {
1514 0 : mapmodels.push_back(c.ext->ents);
1515 : }
1516 0 : if(c.ext->ents->decals.size())
1517 : {
1518 0 : decals.push_back(c.ext->ents);
1519 : }
1520 : }
1521 0 : return;
1522 : }
1523 :
1524 0 : if(!(c.isempty()))
1525 : {
1526 0 : gencubeverts(c, co, size);
1527 0 : if(c.merged)
1528 : {
1529 0 : maxlevel = std::max(maxlevel, genmergedfaces(c, co, size));
1530 : }
1531 : }
1532 0 : if(c.material != Mat_Air)
1533 : {
1534 0 : genmatsurfs(c, co, size, matsurfs);
1535 : }
1536 0 : if(c.ext && c.ext->ents)
1537 : {
1538 0 : if(c.ext->ents->mapmodels.size())
1539 : {
1540 0 : mapmodels.push_back(c.ext->ents);
1541 : }
1542 0 : if(c.ext->ents->decals.size())
1543 : {
1544 0 : decals.push_back(c.ext->ents);
1545 : }
1546 : }
1547 :
1548 0 : if(csi <= maxmergelevel && vamerges[csi].size())
1549 : {
1550 0 : addmergedverts(csi, co);
1551 : }
1552 : }
1553 :
1554 0 : void vacollect::calcgeombb(const ivec &co, int size, ivec &bbmin, ivec &bbmax) const
1555 : {
1556 0 : vec vmin(co),
1557 0 : vmax = vmin;
1558 0 : vmin.add(size);
1559 :
1560 0 : for(size_t i = 0; i < verts.size(); i++)
1561 : {
1562 0 : const vec &v = verts[i].pos;
1563 0 : vmin.min(v);
1564 0 : vmax.max(v);
1565 : }
1566 :
1567 0 : bbmin = ivec(vmin.mul(8)).shr(3);
1568 0 : bbmax = ivec(vmax.mul(8)).add(7).shr(3);
1569 0 : }
1570 :
1571 0 : void vacollect::setva(cube &c, const ivec &co, int sz, int csi)
1572 : {
1573 : int vamergeoffset[maxmergelevel+1];
1574 0 : for(int i = 0; i < maxmergelevel+1; ++i)
1575 : {
1576 0 : vamergeoffset[i] = vamerges[i].size();
1577 : }
1578 0 : size = sz;
1579 0 : for(octaentities *oe : entstack)
1580 : {
1581 0 : if(oe->decals.size())
1582 : {
1583 0 : extdecals.push_back(oe);
1584 : }
1585 : }
1586 0 : int maxlevel = -1;
1587 0 : rendercube(c, co, size, csi, maxlevel);
1588 : //this is what determines the root VA cubes:
1589 0 : if(size == std::min(vamaxsize, rootworld.mapsize()/2) || !emptyva())
1590 : {
1591 0 : vtxarray *va = newva(co, size);
1592 0 : ext(c).va = va;
1593 0 : calcgeombb(co, size, va->geommin, va->geommax);
1594 0 : calcmatbb(va, co, size, matsurfs);
1595 0 : va->hasmerges = vahasmerges;
1596 0 : va->mergelevel = vamergemax;
1597 : }
1598 : else
1599 : {
1600 0 : for(int i = 0; i < maxmergelevel+1; ++i)
1601 : {
1602 0 : vamerges[i].resize(vamergeoffset[i]);
1603 : }
1604 : }
1605 0 : clear();
1606 0 : }
1607 :
1608 0 : void vacollect::calctexgen(const VSlot &vslot, int orient, vec4<float> &sgen, vec4<float> &tgen)
1609 : {
1610 0 : const Texture *tex = vslot.slot->sts.empty() ? notexture : vslot.slot->sts[0].t;
1611 0 : const TexRotation &r = texrotations[vslot.rotation];
1612 0 : float k = defaulttexscale/vslot.scale,
1613 0 : xs = r.flipx ? -tex->xs : tex->xs,
1614 0 : ys = r.flipy ? -tex->ys : tex->ys,
1615 0 : sk = k/xs, tk = k/ys,
1616 0 : soff = -(r.swapxy ? vslot.offset.y() : vslot.offset.x())/xs,
1617 0 : toff = -(r.swapxy ? vslot.offset.x() : vslot.offset.y())/ys;
1618 0 : sgen = vec4<float>(0, 0, 0, soff);
1619 0 : tgen = vec4<float>(0, 0, 0, toff);
1620 0 : if(r.swapxy)
1621 : {
1622 0 : switch(orient)
1623 : {
1624 0 : case 0:
1625 : {
1626 0 : sgen.z = -sk;
1627 0 : tgen.y = tk;
1628 0 : break;
1629 : }
1630 0 : case 1:
1631 : {
1632 0 : sgen.z = -sk;
1633 0 : tgen.y = -tk;
1634 0 : break;
1635 : }
1636 0 : case 2:
1637 : {
1638 0 : sgen.z = -sk;
1639 0 : tgen.x = -tk;
1640 0 : break;
1641 : }
1642 0 : case 3:
1643 : {
1644 0 : sgen.z = -sk;
1645 0 : tgen.x = tk;
1646 0 : break;
1647 : }
1648 0 : case 4:
1649 : {
1650 0 : sgen.y = -sk;
1651 0 : tgen.x = tk;
1652 0 : break;
1653 : }
1654 0 : case 5:
1655 : {
1656 0 : sgen.y = sk;
1657 0 : tgen.x = tk;
1658 0 : break;
1659 : }
1660 : }
1661 : }
1662 : else
1663 : {
1664 0 : switch(orient)
1665 : {
1666 0 : case 0:
1667 : {
1668 0 : sgen.y = sk;
1669 0 : tgen.z = -tk;
1670 0 : break;
1671 : }
1672 0 : case 1:
1673 : {
1674 0 : sgen.y = -sk;
1675 0 : tgen.z = -tk;
1676 0 : break;
1677 : }
1678 0 : case 2:
1679 : {
1680 0 : sgen.x = -sk;
1681 0 : tgen.z = -tk;
1682 0 : break;
1683 : }
1684 0 : case 3:
1685 : {
1686 0 : sgen.x = sk;
1687 0 : tgen.z = -tk;
1688 0 : break;
1689 : }
1690 0 : case 4:
1691 : {
1692 0 : sgen.x = sk;
1693 0 : tgen.y = -tk;
1694 0 : break;
1695 : }
1696 0 : case 5:
1697 : {
1698 0 : sgen.x = sk;
1699 0 : tgen.y = tk;
1700 0 : break;
1701 : }
1702 : }
1703 : }
1704 0 : }
1705 :
1706 : //pos: array of size Face_MaxVerts
1707 : //vinfo: array of size numverts
1708 0 : void vacollect::addcubeverts(VSlot &vslot, int orient, const vec *pos, ushort texture, const vertinfo *vinfo, int numverts, int tj, int grassy, bool alpha, int layer)
1709 : {
1710 : // [rotation][orient]
1711 : const vec orientation_tangent[8][6] =
1712 : {
1713 : { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
1714 : { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) },
1715 : { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
1716 : { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) },
1717 : { vec( 0, -1, 0), vec( 0, 1, 0), vec( 1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
1718 : { vec( 0, 1, 0), vec( 0, -1, 0), vec(-1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
1719 : { vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, 0, -1), vec( 0, -1, 0), vec( 0, 1, 0) },
1720 : { vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 0, 1), vec( 0, 1, 0), vec( 0, -1, 0) },
1721 0 : };
1722 :
1723 0 : vec4<float> sgen, tgen;
1724 0 : calctexgen(vslot, orient, sgen, tgen);
1725 0 : std::array<vertex, Face_MaxVerts> verts;
1726 : std::array<int, Face_MaxVerts> index;
1727 0 : std::array<vec, Face_MaxVerts> normals;
1728 0 : for(int k = 0; k < numverts; ++k)
1729 : {
1730 0 : vertex &v = verts[k];
1731 0 : v.pos = pos[k];
1732 0 : v.tc = vec(sgen.dot(v.pos), tgen.dot(v.pos), 0);
1733 0 : if(vinfo && vinfo[k].norm)
1734 : {
1735 0 : vec n = decodenormal(vinfo[k].norm),
1736 0 : t = orientation_tangent[vslot.rotation][orient];
1737 0 : t.project(n).normalize();
1738 0 : v.norm = bvec(n);
1739 0 : v.tangent = vec4<uchar>(bvec(t), orientation_bitangent[vslot.rotation][orient].scalartriple(n, t) < 0 ? 0 : 255);
1740 0 : }
1741 0 : else if(texture != Default_Sky)
1742 : {
1743 0 : if(!k)
1744 : {
1745 0 : guessnormals(pos, numverts, normals.data());
1746 : }
1747 0 : const vec &n = normals[k];
1748 0 : vec t = orientation_tangent[vslot.rotation][orient];
1749 0 : t.project(n).normalize();
1750 0 : v.norm = bvec(n);
1751 0 : v.tangent = vec4<uchar>(bvec(t), orientation_bitangent[vslot.rotation][orient].scalartriple(n, t) < 0 ? 0 : 255);
1752 : }
1753 : else
1754 : {
1755 0 : v.norm = bvec(128, 128, 255);
1756 0 : v.tangent = vec4<uchar>(255, 128, 128, 255);
1757 : }
1758 0 : index[k] = addvert(v);
1759 0 : if(index[k] < 0)
1760 : {
1761 0 : return;
1762 : }
1763 : }
1764 :
1765 0 : if(alpha)
1766 : {
1767 0 : for(int k = 0; k < numverts; ++k)
1768 : {
1769 0 : alphamin.min(pos[k]);
1770 0 : alphamax.max(pos[k]);
1771 : }
1772 0 : if(vslot.refractscale > 0)
1773 : {
1774 0 : for(int k = 0; k < numverts; ++k)
1775 : {
1776 0 : refractmin.min(pos[k]);
1777 0 : refractmax.max(pos[k]);
1778 : }
1779 : }
1780 : }
1781 0 : if(texture == Default_Sky)
1782 : {
1783 0 : for(int i = 0; i < numverts; ++i)
1784 : {
1785 0 : if(pos[i][orient>>1] != ((orient&1)<<rootworld.mapscale()))
1786 : {
1787 0 : for(int k = 0; k < numverts; ++k)
1788 : {
1789 0 : skymin.min(pos[k]);
1790 0 : skymax.max(pos[k]);
1791 : }
1792 0 : break;
1793 : }
1794 : }
1795 : }
1796 : const SortKey key(texture,
1797 0 : vslot.scroll.iszero() ? Orient_Any : orient,
1798 0 : layer&BlendLayer_Bottom ? layer : BlendLayer_Top,
1799 0 : alpha ? (vslot.refractscale > 0 ? Alpha_Refract : (vslot.alphaback ? Alpha_Back : Alpha_Front)) : Alpha_None);
1800 0 : addtris(vslot, orient, key, verts.data(), index.data(), numverts, tj);
1801 0 : if(grassy)
1802 : {
1803 0 : for(int i = 0; i < numverts-2; i += 2)
1804 : {
1805 0 : int faces = 0;
1806 0 : if(index[0]!=index[i+1] && index[i+1]!=index[i+2] && index[i+2]!=index[0])
1807 : {
1808 0 : faces |= 1;
1809 : }
1810 0 : if(i+3 < numverts && index[0]!=index[i+2] && index[i+2]!=index[i+3] && index[i+3]!=index[0])
1811 : {
1812 0 : faces |= 2;
1813 : }
1814 0 : if(grassy > 1 && faces==3)
1815 : {
1816 0 : addgrasstri(i, verts.data(), 4, texture);
1817 : }
1818 : else
1819 : {
1820 0 : if(faces&1)
1821 : {
1822 0 : addgrasstri(i, verts.data(), 3, texture);
1823 : }
1824 0 : if(faces&2)
1825 : {
1826 0 : addgrasstri(i+1, verts.data(), 3, texture);
1827 : }
1828 : }
1829 : }
1830 : }
1831 : }
1832 :
1833 : //va settings, used in updateva below
1834 0 : static VARF(vafacemax, 64, 384, 256*256, rootworld.allchanged());
1835 0 : static VARF(vafacemin, 0, 96, 256*256, rootworld.allchanged());
1836 0 : static VARF(vacubesize, 32, 128, 0x1000, rootworld.allchanged()); //note that performance drops off at low values -> large numbers of VAs
1837 :
1838 : //updates the va that contains the cube c
1839 0 : int vacollect::updateva(std::array<cube, 8> &c, const ivec &co, int size, int csi)
1840 : {
1841 0 : int ccount = 0,
1842 0 : cmergemax = vamergemax,
1843 0 : chasmerges = vahasmerges;
1844 0 : neighborstack[++neighbordepth] = &c[0];
1845 0 : for(int i = 0; i < 8; ++i) // counting number of semi-solid/solid children cubes
1846 : {
1847 0 : int count = 0,
1848 0 : childpos = varoot.size();
1849 0 : ivec o(i, co, size); //translate cube vector to world vector
1850 0 : vamergemax = 0;
1851 0 : vahasmerges = 0;
1852 0 : if(c[i].ext && c[i].ext->va)
1853 : {
1854 0 : varoot.push_back(c[i].ext->va);
1855 0 : if(c[i].ext->va->hasmerges&Merge_Origin)
1856 : {
1857 0 : findmergedfaces(c[i], o, size, csi, csi);
1858 : }
1859 : }
1860 : else
1861 : {
1862 0 : if(c[i].children)
1863 : {
1864 0 : if(c[i].ext && c[i].ext->ents)
1865 : {
1866 0 : entstack.push_back(c[i].ext->ents);
1867 : }
1868 0 : count += updateva(*c[i].children, o, size/2, csi-1);
1869 0 : if(c[i].ext && c[i].ext->ents)
1870 : {
1871 0 : entstack.pop_back();
1872 : }
1873 : }
1874 : else
1875 : {
1876 0 : count += setcubevisibility(c[i], o, size);
1877 : }
1878 0 : int tcount = count + (csi <= maxmergelevel ? vamerges[csi].size() : 0);
1879 0 : if(tcount > vafacemax || (tcount >= vafacemin && size >= vacubesize) || size == std::min(0x1000, rootworld.mapsize()/2))
1880 : {
1881 0 : setva(c[i], o, size, csi);
1882 0 : if(c[i].ext && c[i].ext->va)
1883 : {
1884 0 : while(static_cast<long>(varoot.size()) > childpos)
1885 : {
1886 0 : vtxarray *child = varoot.back();
1887 0 : varoot.pop_back();
1888 0 : c[i].ext->va->children.push_back(child);
1889 0 : child->parent = c[i].ext->va;
1890 : }
1891 0 : varoot.push_back(c[i].ext->va);
1892 0 : if(vamergemax > size)
1893 : {
1894 0 : cmergemax = std::max(cmergemax, vamergemax);
1895 0 : chasmerges |= vahasmerges&~Merge_Use;
1896 : }
1897 0 : continue;
1898 0 : }
1899 : else
1900 : {
1901 0 : count = 0;
1902 : }
1903 : }
1904 : }
1905 0 : if(csi+1 <= maxmergelevel && vamerges[csi].size())
1906 : {
1907 0 : vamerges[csi+1].swap(vamerges[csi]);
1908 : }
1909 0 : cmergemax = std::max(cmergemax, vamergemax);
1910 0 : chasmerges |= vahasmerges;
1911 0 : ccount += count;
1912 : }
1913 0 : --neighbordepth;
1914 0 : vamergemax = cmergemax;
1915 0 : vahasmerges = chasmerges;
1916 :
1917 0 : return ccount;
1918 : }
1919 :
1920 0 : void cubeworld::octarender() // creates va s for all leaf cubes that don't already have them
1921 : {
1922 0 : int csi = 0;
1923 0 : while(1<<csi < mapsize())
1924 : {
1925 0 : csi++;
1926 : }
1927 0 : varoot.clear();
1928 0 : vc.updateva(*worldroot, ivec(0, 0, 0), mapsize()/2, csi-1);
1929 0 : flushvbo();
1930 0 : setexplicitsky(false);
1931 0 : for(size_t i = 0; i < valist.size(); i++)
1932 : {
1933 0 : if(valist[i]->sky)
1934 : {
1935 0 : setexplicitsky(true);
1936 0 : break;
1937 : }
1938 : }
1939 0 : visibleva = nullptr;
1940 0 : }
|