1
// rendercubes.cpp: sits in between worldrender.cpp and rendergl.cpp and fills the vertex array for different cube surfaces.
8
struct cstat { int size, nleaf, nnode, nface; } cstats[32];
10
VAR(showcstats, 0, 0, 1);
14
if(showcstats) loopi(32)
16
if(!cstats[i].size) continue;
17
conoutf("%d: %d faces, %d leafs, %d nodes", cstats[i].size, cstats[i].nface, cstats[i].nleaf, cstats[i].nnode);
21
VARF(floatvtx, 0, 0, 1, allchanged());
23
void genfloatverts(fvertex *f)
27
const vertex &v = verts[i];
43
static inline uint hthash(GLuint key)
48
static inline bool htcmp(GLuint x, GLuint y)
53
hashtable<GLuint, vboinfo> vbos;
55
VAR(printvbo, 0, 0, 1);
56
VARF(vbosize, 0, 0, 1024*1024, allchanged());
68
static vector<char> vbodata[NUMVBO];
69
static vector<vtxarray *> vbovas[NUMVBO];
71
void destroyvbo(GLuint vbo)
73
vboinfo &vbi = vbos[vbo];
74
if(vbi.uses <= 0) return;
76
if(!vbi.uses) glDeleteBuffers_(1, &vbo);
79
void genvbo(int type, void *buf, int len, vtxarray **vas, int numva)
82
glGenBuffers_(1, &vbo);
83
GLenum target = type==VBO_VBUF ? GL_ARRAY_BUFFER_ARB : GL_ELEMENT_ARRAY_BUFFER_ARB;
84
glBindBuffer_(target, vbo);
85
glBufferData_(target, len, buf, GL_STATIC_DRAW_ARB);
86
glBindBuffer_(target, 0);
88
vboinfo &vbi = vbos[vbo];
91
if(printvbo) conoutf("vbo %d: type %d, size %d, %d uses", vbo, type, len, numva);
95
vtxarray *va = vas[i];
98
case VBO_VBUF: va->vbufGL = vbo; break;
99
case VBO_EBUF_L0: va->l0.ebufGL = vbo; break;
100
case VBO_EBUF_L1: va->l1.ebufGL = vbo; break;
101
case VBO_SKYBUF_L0: va->l0.skybufGL = vbo; break;
102
case VBO_SKYBUF_L1: va->l1.skybufGL = vbo; break;
107
void flushvbo(int type = -1)
111
loopi(NUMVBO) flushvbo(i);
115
vector<char> &data = vbodata[type];
116
if(data.empty()) return;
117
vector<vtxarray *> &vas = vbovas[type];
118
genvbo(type, data.getbuf(), data.length(), vas.getbuf(), vas.length());
119
data.setsizenodelete(0);
120
vas.setsizenodelete(0);
123
void *addvbo(vtxarray *va, int type, void *buf, int len)
125
int minsize = type==VBO_VBUF ? min(vbosize, int(floatvtx ? sizeof(fvertex) : sizeof(vertex)) << 16) : vbosize;
129
genvbo(type, buf, len, &va, 1);
133
vector<char> &data = vbodata[type];
134
vector<vtxarray *> &vas = vbovas[type];
136
if(data.length() && data.length() + len > minsize) flushvbo(type);
140
size_t offset = data.length();
142
memcpy(&data.getbuf()[offset], buf, len);
147
if(data.length() >= minsize) flushvbo(type);
149
return (void *)offset;
154
static const int size = 1<<16;
158
vechash() { clear(); };
159
void clear() { loopi(size) table[i] = -1; chain.setsizenodelete(0); };
161
int access(const vvec &v, short tu, short tv, const bvec &n)
163
const uchar *iv = (const uchar *)&v;
165
loopl(sizeof(v)) h = ((h<<5)+h)^iv[l];
167
for(int i = table[h]; i>=0; i = chain[i])
169
const vertex &c = verts[i];
170
if(c.x==v.x && c.y==v.y && c.z==v.z && c.n==n)
172
if(!tu && !tv) return i;
173
if(c.u==tu && c.v==tv) return i;
176
vertex &vtx = verts.add();
182
return table[h] = verts.length()-1;
192
sortkey(uint tex, uint lmid)
193
: tex(tex), lmid(lmid)
196
bool operator==(const sortkey &o) const { return tex==o.tex && lmid==o.lmid; };
204
sortval() : unlit(0) {};
207
static inline bool htcmp(const sortkey &x, const sortkey &y)
209
return x.tex == y.tex && x.lmid == y.lmid;
212
static inline uint hthash(const sortkey &k)
214
return k.tex + k.lmid*9741;
219
hashtable<sortkey, sortval> indices;
220
vector<sortkey> texs;
221
vector<materialsurface> matsurfs;
222
usvector skyindices, explicitskyindices;
226
int size() { return texs.length()*sizeof(elementset) + (hasVBO ? 0 : (3*curtris+skyindices.length()+explicitskyindices.length())*sizeof(ushort)) + matsurfs.length()*sizeof(materialsurface); };
228
void clearidx() { indices.clear(); };
233
skyindices.setsizenodelete(0);
234
explicitskyindices.setsizenodelete(0);
235
matsurfs.setsizenodelete(0);
238
void remapunlit(vector<sortkey> &unlit)
240
uint lastlmid = LMID_AMBIENT, firstlmid = LMID_AMBIENT;
244
sortkey &k = texs[i];
245
if(k.lmid>=LMID_RESERVED)
247
lastlmid = lightmaps[k.lmid-LMID_RESERVED].unlitx>=0 ? k.lmid : LMID_AMBIENT;
251
firstlmid = lastlmid;
254
else if(k.lmid==LMID_AMBIENT && lastlmid!=LMID_AMBIENT)
256
sortval &t = indices[k];
257
if(t.unlit<=0) t.unlit = lastlmid;
260
if(firstlmid!=LMID_AMBIENT) loopi(firstlit)
262
sortkey &k = texs[i];
263
if(k.lmid!=LMID_AMBIENT) continue;
264
indices[k].unlit = firstlmid;
268
sortkey &k = unlit[i];
269
sortval &t = indices[k];
270
if(t.unlit<=0) continue;
271
LightMap &lm = lightmaps[t.unlit-LMID_RESERVED];
272
short u = short((lm.unlitx + 0.5f) * SHRT_MAX/LM_PACKW),
273
v = short((lm.unlity + 0.5f) * SHRT_MAX/LM_PACKH);
274
loopl(3) loopvj(t.dims[l])
276
vertex &vtx = verts[t.dims[l][j]];
282
else if(vtx.u != u || vtx.v != v)
284
// necessary to copy these in case vechash reallocates verts before copying vtx
287
t.dims[l][j] = vh.access(vv, u, v, n);
290
sortval *dst = indices.access(sortkey(k.tex, t.unlit));
291
if(dst) loopl(3) loopvj(t.dims[l]) dst->dims[l].add(t.dims[l][j]);
297
vector<sortkey> unlit;
299
texs.setsizenodelete(0);
300
enumeratekt(indices, sortkey, k, sortval, t,
301
loopl(3) if(t.dims[l].length() && t.unlit<=0)
303
if(k.lmid>=LMID_RESERVED && lightmaps[k.lmid-LMID_RESERVED].unlitx>=0)
305
sortkey ukey(k.tex, LMID_AMBIENT);
306
sortval *uval = indices.access(ukey);
307
if(uval && uval->unlit<=0)
309
if(uval->unlit<0) texs.removeobj(ukey);
310
else unlit.add(ukey);
311
uval->unlit = k.lmid;
314
else if(k.lmid==LMID_AMBIENT)
327
matsurfs.setsize(optimizematsurfs(matsurfs.getbuf(), matsurfs.length()));
330
static int texsort(const sortkey *x, const sortkey *y)
332
if(x->tex == y->tex) return 0;
333
Slot &xs = lookuptexture(x->tex, false), &ys = lookuptexture(y->tex, false);
334
if(xs.shader < ys.shader) return -1;
335
if(xs.shader > ys.shader) return 1;
336
if(xs.params.length() < ys.params.length()) return -1;
337
if(xs.params.length() > ys.params.length()) return 1;
338
if(x->tex < y->tex) return -1;
342
char *setup(vtxarray *va, lodlevel &lod, char *buf)
344
lod.eslist = (elementset *)buf;
346
lod.sky = skyindices.length();
347
lod.explicitsky = explicitskyindices.length();
351
lod.ebufGL = lod.skybufGL = 0;
352
lod.ebuf = (ushort *)(lod.eslist + texs.length());
353
lod.skybuf = lod.ebuf + 3*curtris;
354
lod.matbuf = (materialsurface *)(lod.skybuf+lod.sky+lod.explicitsky);
357
ushort *skybuf = NULL;
358
if(lod.sky+lod.explicitsky)
360
skybuf = hasVBO ? new ushort[lod.sky+lod.explicitsky] : lod.skybuf;
361
memcpy(skybuf, skyindices.getbuf(), lod.sky*sizeof(ushort));
362
memcpy(skybuf+lod.sky, explicitskyindices.getbuf(), lod.explicitsky*sizeof(ushort));
367
lod.ebuf = lod.skybuf = 0;
368
lod.matbuf = (materialsurface *)(lod.eslist + texs.length());
373
if(offsetindices) loopi(lod.sky+lod.explicitsky) skybuf[i] += offsetindices;
374
lod.skybuf = (ushort *)addvbo(va, &lod==&va->l0 ? VBO_SKYBUF_L0 : VBO_SKYBUF_L1, skybuf, (lod.sky+lod.explicitsky)*sizeof(ushort));
376
glGenBuffers_(1, &lod.skybufGL);
377
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, lod.skybufGL);
378
glBufferData_(GL_ELEMENT_ARRAY_BUFFER_ARB, (lod.sky+lod.explicitsky)*sizeof(ushort), skybuf, GL_STATIC_DRAW_ARB);
382
else lod.skybufGL = 0;
385
lod.matsurfs = matsurfs.length();
386
if(lod.matsurfs) memcpy(lod.matbuf, matsurfs.getbuf(), matsurfs.length()*sizeof(materialsurface));
390
ushort *ebuf = hasVBO ? new ushort[3*curtris] : lod.ebuf, *curbuf = ebuf;
393
const sortkey &k = texs[i];
394
const sortval &t = indices[k];
395
lod.eslist[i].texture = k.tex;
396
lod.eslist[i].lmid = t.unlit>0 ? t.unlit : k.lmid;
397
loopl(3) if((lod.eslist[i].length[l] = t.dims[l].length()))
399
memcpy(curbuf, t.dims[l].getbuf(), t.dims[l].length() * sizeof(ushort));
400
curbuf += t.dims[l].length();
406
if(offsetindices) loopi(3*curtris) ebuf[i] += offsetindices;
407
lod.ebuf = (ushort *)addvbo(va, &lod==&va->l0 ? VBO_EBUF_L0 : VBO_EBUF_L1, ebuf, 3*curtris*sizeof(ushort));
409
glGenBuffers_(1, &lod.ebufGL);
410
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, lod.ebufGL);
411
glBufferData_(GL_ELEMENT_ARRAY_BUFFER_ARB, 3*curtris*sizeof(ushort), ebuf, GL_STATIC_DRAW_ARB);
416
else if(hasVBO) lod.ebufGL = 0;
417
lod.texs = texs.length();
419
return (char *)(lod.matbuf+lod.matsurfs);
423
int explicitsky = 0, skyarea = 0;
425
VARF(lodsize, 0, 32, 128, hdr.mapwlod = lodsize);
426
VAR(loddistance, 0, 2000, 100000);
428
int addtriindexes(usvector &v, int index[4])
431
if(index[0]!=index[1] && index[0]!=index[2] && index[1]!=index[2])
438
if(index[0]!=index[2] && index[0]!=index[3] && index[2]!=index[3])
448
void addcubeverts(int orient, int size, bool lodcube, vvec *vv, ushort texture, surfaceinfo *surface, surfacenormals *normals)
454
if(surface && surface->lmid >= LMID_RESERVED)
456
u = short((surface->x + (surface->texcoords[k*2] / 255.0f) * (surface->w - 1) + 0.5f) * SHRT_MAX/LM_PACKW);
457
v = short((surface->y + (surface->texcoords[k*2 + 1] / 255.0f) * (surface->h - 1) + 0.5f) * SHRT_MAX/LM_PACKH);
460
index[k] = vh.access(vv[k], u, v, normals ? normals->normals[k] : bvec(128, 128, 128));
463
extern vector<GLuint> lmtexids;
464
sortkey key(texture, surface && lmtexids.inrange(surface->lmid) ? surface->lmid : LMID_AMBIENT);
467
int tris = addtriindexes(texture == DEFAULT_SKY ? l0.explicitskyindices : l0.indices[key].dims[dimension(orient)], index);
468
if(texture == DEFAULT_SKY) explicitsky += tris;
469
else l0.curtris += tris;
471
if(lodsize && size>=lodsize)
473
int tris = addtriindexes(texture == DEFAULT_SKY ? l1.explicitskyindices : l1.indices[key].dims[dimension(orient)], index);
474
if(texture != DEFAULT_SKY) l1.curtris += tris;
478
void gencubeverts(cube &c, int x, int y, int z, int size, int csi, bool lodcube)
480
freeclipplanes(c); // physics planes based on rendering
482
loopi(6) if(visibleface(c, i, x, y, z, size, MAT_AIR, lodcube))
486
// this is necessary for physics to work, even if the face is merged
487
if(touchingface(c, i)) e.visible |= 1<<i;
489
if(!lodcube && e.merged&(1<<i)) continue;
494
loopk(4) calcvert(c, x, y, z, size, vv[k], faceverts(c, i, k));
495
addcubeverts(i, size, lodcube, vv, c.texture[i], e.surfaces ? &e.surfaces[i] : NULL, e.normals ? &e.normals[i] : NULL);
499
bool skyoccluded(cube &c, int orient)
501
if(isempty(c)) return false;
502
// if(c.texture[orient] == DEFAULT_SKY) return true;
503
if(touchingface(c, orient) && faceedges(c, orient) == F_SOLID) return true;
507
int hasskyfaces(cube &c, int x, int y, int z, int size, int faces[6])
510
if(x == 0 && !skyoccluded(c, O_LEFT)) faces[numfaces++] = O_LEFT;
511
if(x + size == hdr.worldsize && !skyoccluded(c, O_RIGHT)) faces[numfaces++] = O_RIGHT;
512
if(y == 0 && !skyoccluded(c, O_BACK)) faces[numfaces++] = O_BACK;
513
if(y + size == hdr.worldsize && !skyoccluded(c, O_FRONT)) faces[numfaces++] = O_FRONT;
514
if(z == 0 && !skyoccluded(c, O_BOTTOM)) faces[numfaces++] = O_BOTTOM;
515
if(z + size == hdr.worldsize && !skyoccluded(c, O_TOP)) faces[numfaces++] = O_TOP;
519
vector<cubeface> skyfaces[6][2];
521
void minskyface(cube &cu, int orient, const ivec &co, int size, mergeinfo &orig)
528
mincubeface(cu, orient, co, size, orig, mincf);
529
orig.u1 = max(mincf.u1, orig.u1);
530
orig.u2 = min(mincf.u2, orig.u2);
531
orig.v1 = max(mincf.v1, orig.v1);
532
orig.v2 = min(mincf.v2, orig.v2);
535
void genskyfaces(cube &c, const ivec &o, int size, bool lodcube)
537
if(isentirelysolid(c)) return;
540
numfaces = hasskyfaces(c, o.x, o.y, o.z, size, faces);
541
if(!numfaces) return;
545
int orient = faces[i], dim = dimension(orient);
548
m.u1 = (o[C[dim]]&VVEC_INT_MASK)<<VVEC_FRAC;
549
m.u2 = ((o[C[dim]]&VVEC_INT_MASK)+size)<<VVEC_FRAC;
550
m.v1 = (o[R[dim]]&VVEC_INT_MASK)<<VVEC_FRAC;
551
m.v2 = ((o[R[dim]]&VVEC_INT_MASK)+size)<<VVEC_FRAC;
552
minskyface(c, orient, o, size, m);
553
if(m.u1 >= m.u2 || m.v1 >= m.v2) continue;
556
skyarea += (int(m.u2-m.u1)*int(m.v2-m.v1) + (1<<(2*VVEC_FRAC))-1)>>(2*VVEC_FRAC);
557
skyfaces[orient][0].add(m);
559
if(lodsize && size>=lodsize) skyfaces[orient][1].add(m);
563
void addskyverts(const ivec &o, int size)
567
int dim = dimension(i), c = C[dim], r = R[dim];
570
vector<cubeface> &sf = skyfaces[i][l];
571
if(sf.empty()) continue;
572
sf.setsizenodelete(mergefaces(i, sf.getbuf(), sf.length()));
575
mergeinfo &m = sf[j];
579
const ivec &coords = cubecoords[fv[i][3-k]];
581
vv[dim] = (o[dim]&VVEC_INT_MASK)<<VVEC_FRAC;
582
if(coords[dim]) vv[dim] += size<<VVEC_FRAC;
583
vv[c] = coords[c] ? m.u2 : m.u1;
584
vv[r] = coords[r] ? m.v2 : m.v1;
585
index[k] = vh.access(vv, 0, 0, bvec(128, 128, 128));
587
addtriindexes((!l ? l0 : l1).skyindices, index);
589
sf.setsizenodelete(0);
594
////////// Vertex Arrays //////////////
597
int wtris = 0, wverts = 0, vtris = 0, vverts = 0, glde = 0;
598
vector<vtxarray *> valist, varoot;
600
vtxarray *newva(int x, int y, int z, int size)
604
int allocsize = sizeof(vtxarray) + l0.size() + l1.size();
605
int bufsize = verts.length()*(floatvtx ? sizeof(fvertex) : sizeof(vertex));
606
if(!hasVBO) allocsize += bufsize; // length of vertex buffer
607
vtxarray *va = (vtxarray *)new uchar[allocsize];
608
if(hasVBO && verts.length())
613
fvertex *f = new fvertex[verts.length()];
615
vbuf = (vertex *)addvbo(va, VBO_VBUF, f, bufsize);
618
else vbuf = (vertex *)addvbo(va, VBO_VBUF, verts.getbuf(), bufsize);
619
int offset = int(size_t(vbuf)) / (floatvtx ? sizeof(fvertex) : sizeof(vertex));
620
l0.offsetindices = offset;
621
l1.offsetindices = offset;
622
va->vbuf = 0; // Offset in VBO
624
char *buf = l1.setup(va, va->l1, l0.setup(va, va->l0, (char *)(va+1)));
628
va->vbuf = (vertex *)buf;
629
if(floatvtx) genfloatverts((fvertex *)buf);
630
else memcpy(va->vbuf, verts.getbuf(), bufsize);
634
va->children = new vector<vtxarray *>;
635
va->allocsize = allocsize;
636
va->x = x; va->y = y; va->z = z; va->size = size;
637
va->explicitsky = explicitsky;
638
va->skyarea = skyarea;
639
va->curvfc = VFC_NOT_VISIBLE;
640
va->occluded = OCCLUDE_NOTHING;
642
va->mapmodels = NULL;
644
wverts += va->verts = verts.length();
645
wtris += va->l0.tris;
651
void destroyva(vtxarray *va, bool reparent)
653
if(va->vbufGL) destroyvbo(va->vbufGL);
654
if(va->l0.ebufGL) destroyvbo(va->l0.ebufGL);
655
if(va->l0.skybufGL) destroyvbo(va->l0.skybufGL);
656
if(va->l1.ebufGL) destroyvbo(va->l1.ebufGL);
657
if(va->l1.skybufGL) destroyvbo(va->l1.skybufGL);
659
wtris -= va->l0.tris;
661
valist.removeobj(va);
662
if(!va->parent) varoot.removeobj(va);
665
if(va->parent) va->parent->children->removeobj(va);
668
vtxarray *child = (*va->children)[i];
669
child->parent = va->parent;
670
if(child->parent) child->parent->children->add(va);
673
if(va->mapmodels) delete va->mapmodels;
674
if(va->children) delete va->children;
675
delete[] (uchar *)va;
678
void vaclearc(cube *c)
684
if(c[i].ext->va) destroyva(c[i].ext->va, false);
687
if(c[i].children) vaclearc(c[i].children);
691
static ivec bbmin, bbmax;
692
static vector<octaentities *> vamms;
700
surfaceinfo *surface;
701
surfacenormals *normals;
706
mergedface *first, *last;
710
static int vahasmerges = 0, vamergemax = 0;
711
static mflist vamerges[VVEC_INT];
713
void genmergedfaces(cube &c, const ivec &co, int size, int minlevel = 0)
715
if(!c.ext || !c.ext->merges) return;
717
loopi(6) if(c.ext->mergeorigin & (1<<i))
719
mergeinfo &m = c.ext->merges[index++];
720
if(m.u1>=m.u2 || m.v1>=m.v2) continue;
723
mf.tex = c.texture[i];
724
mf.surface = c.ext->surfaces ? &c.ext->surfaces[i] : NULL;
725
mf.normals = c.ext->normals ? &c.ext->normals[i] : NULL;
726
genmergedverts(c, i, co, size, m, mf.v);
727
int level = calcmergedsize(i, co, size, m, mf.v);
730
mergedface &nf = *new mergedface;
732
mflist &mfl = vamerges[level];
735
if(!mfl.last) mfl.last = &nf;
737
vamergemax = max(vamergemax, level);
738
vahasmerges |= MERGE_ORIGIN;
743
void findmergedfaces(cube &c, const ivec &co, int size, int csi, int minlevel)
745
if(c.ext && c.ext->va && !(c.ext->va->hasmerges&MERGE_ORIGIN)) return;
750
ivec o(i, co.x, co.y, co.z, size/2);
751
findmergedfaces(c.children[i], o, size/2, csi-1, minlevel);
754
else if(c.ext && c.ext->merges) genmergedfaces(c, co, size, minlevel);
757
void addmergedverts(int level)
759
mflist &mfl = vamerges[level];
760
if(!mfl.count) return;
763
mergedface &mf = *mfl.first;
765
if(mfl.last == &mf) mfl.last = NULL;
766
addcubeverts(mf.orient, 1<<level, false, mf.v, mf.tex, mf.surface, mf.normals);
769
cstats[level].nface++;
770
vahasmerges |= MERGE_USE;
774
void rendercube(cube &c, int cx, int cy, int cz, int size, int csi) // creates vertices and indices ready to be put into a va
776
//if(size<=16) return;
777
if(c.ext && c.ext->va) return; // don't re-render
778
cstats[csi].size = size;
779
bool lodcube = false;
787
ivec o(i, cx, cy, cz, size/2);
788
rendercube(c.children[i], o.x, o.y, o.z, size/2, csi-1);
791
if(csi < VVEC_INT && vamerges[csi].count) addmergedverts(csi);
797
if(c.ext->ents && c.ext->ents->mapmodels.length()) vamms.add(c.ext->ents);
803
if(!c.children || lodcube) genskyfaces(c, ivec(cx, cy, cz), size, lodcube);
807
gencubeverts(c, cx, cy, cz, size, csi, lodcube);
809
if(cx<bbmin.x) bbmin.x = cx;
810
if(cy<bbmin.y) bbmin.y = cy;
811
if(cz<bbmin.z) bbmin.z = cz;
812
if(cx+size>bbmax.x) bbmax.x = cx+size;
813
if(cy+size>bbmax.y) bbmax.y = cy+size;
814
if(cz+size>bbmax.z) bbmax.z = cz+size;
821
if(c.ext->ents && c.ext->ents->mapmodels.length()) vamms.add(c.ext->ents);
822
if(c.ext->material != MAT_AIR) genmatsurfs(c, cx, cy, cz, size, l0.matsurfs);
823
if(c.ext->merges) genmergedfaces(c, ivec(cx, cy, cz), size);
824
if(c.ext->merged & ~c.ext->mergeorigin) vahasmerges |= MERGE_PART;
827
if(csi < VVEC_INT && vamerges[csi].count) addmergedverts(csi);
832
void setva(cube &c, int cx, int cy, int cz, int size, int csi)
834
ASSERT(size <= VVEC_INT_MASK+1);
836
if(verts.length()) // since reseting is a bit slow
838
verts.setsizenodelete(0);
839
explicitsky = skyarea = 0;
845
vamms.setsizenodelete(0);
847
bbmin = ivec(cx+size, cy+size, cz+size);
848
bbmax = ivec(cx, cy, cz);
850
rendercube(c, cx, cy, cz, size, csi);
852
addskyverts(ivec(cx, cy, cz), size);
856
vtxarray *va = newva(cx, cy, cz, size);
860
if(vamms.length()) va->mapmodels = new vector<octaentities *>(vamms);
861
va->hasmerges = vahasmerges;
868
VARF(vacubemax, 64, 2048, 256*256, allchanged());
869
VARF(vacubesize, 128, 128, VVEC_INT_MASK+1, allchanged());
870
VARF(vacubemin, 0, 128, 256*256, allchanged());
872
int recalcprogress = 0;
873
#define progress(s) if((recalcprogress++&0x7FF)==0) show_out_of_renderloop_progress(recalcprogress/(float)allocnodes, s);
875
int updateva(cube *c, int cx, int cy, int cz, int size, int csi)
877
progress("recalculating geometry...");
879
int ccount = 0, cmergemax = vamergemax, chasmerges = vahasmerges;
880
loopi(8) // counting number of semi-solid/solid children cubes
882
int count = 0, childpos = varoot.length();
883
ivec o(i, cx, cy, cz, size);
886
if(c[i].ext && c[i].ext->va)
888
//count += vacubemax+1; // since must already have more then max cubes
889
varoot.add(c[i].ext->va);
890
if(c[i].ext->va->hasmerges&MERGE_ORIGIN) findmergedfaces(c[i], o, size, csi, csi);
892
else if(c[i].children) count += updateva(c[i].children, o.x, o.y, o.z, size/2, csi-1);
893
else if(!isempty(c[i]) || hasskyfaces(c[i], o.x, o.y, o.z, size, faces)) count++;
894
int tcount = count + (csi < VVEC_INT ? vamerges[csi].count : 0);
895
if(tcount > vacubemax || (tcount >= vacubemin && size == vacubesize) || (tcount && size == min(VVEC_INT_MASK+1, hdr.worldsize/2)))
897
setva(c[i], o.x, o.y, o.z, size, csi);
898
if(c[i].ext && c[i].ext->va)
900
while(varoot.length() > childpos)
902
vtxarray *child = varoot.pop();
903
c[i].ext->va->children->add(child);
904
child->parent = c[i].ext->va;
906
varoot.add(c[i].ext->va);
907
if(vamergemax > size)
909
cmergemax = max(cmergemax, vamergemax);
910
vahasmerges |= vahasmerges&~MERGE_USE;
915
if(csi < VVEC_INT-1 && vamerges[csi].count)
917
mflist &mfl = vamerges[csi], &nfl = vamerges[csi+1];
918
mfl.last->next = nfl.first;
919
nfl.first = mfl.first;
920
if(!nfl.last) nfl.last = mfl.last;
921
mfl.first = mfl.last = 0;
922
nfl.count += mfl.count;
925
cmergemax = max(cmergemax, vamergemax);
926
chasmerges |= vahasmerges;
930
vamergemax = cmergemax;
931
vahasmerges = chasmerges;
936
void genlod(cube &c, int size)
938
if(!c.children || (c.ext && c.ext->va)) return;
939
progress("generating LOD...");
941
loopi(8) genlod(c.children[i], size/2);
943
if(size>lodsize) return;
945
if(c.ext) c.ext->material = MAT_AIR;
947
loopi(8) if(!isempty(c.children[i]))
956
void octarender() // creates va s for all leaf cubes that don't already have them
959
if(lodsize) loopi(8) genlod(worldroot[i], hdr.worldsize/2);
962
while(1<<csi < hdr.worldsize) csi++;
965
varoot.setsizenodelete(0);
966
updateva(worldroot, 0, 0, 0, hdr.worldsize/2, csi-1);
973
vtxarray *va = valist[i];
974
explicitsky += va->explicitsky;
975
skyarea += va->skyarea;
979
void precachetextures(lodlevel &lod) { loopi(lod.texs) lookuptexture(lod.eslist[i].texture); };
980
void precacheall() { loopv(valist) { precachetextures(valist[i]->l0); precachetextures(valist[i]->l1); } ; };
982
void allchanged(bool load)
984
show_out_of_renderloop_progress(0, "clearing VBOs...");
986
memset(cstats, 0, sizeof(cstat)*32);
989
if(load) precacheall();
990
setupmaterials(load);
1001
///////// view frustrum culling ///////////////////////
1003
plane vfcP[5]; // perpindictular vectors to view frustrum bounding planes
1004
float vfcDfog; // far plane culling distance (fog limit).
1005
int vfcw, vfch, vfcfov;
1007
vtxarray *visibleva;
1009
int isvisiblesphere(float rad, const vec &cv)
1011
int v = VFC_FULL_VISIBLE;
1016
dist = vfcP[i].dist(cv);
1017
if(dist < -rad) return VFC_NOT_VISIBLE;
1018
if(dist < rad) v = VFC_PART_VISIBLE;
1021
dist = vfcP[0].dist(cv) - vfcDfog;
1022
if(dist > rad) return VFC_FOGGED; //VFC_NOT_VISIBLE; // culling when fog is closer than size of world results in HOM
1023
if(dist > -rad) v = VFC_PART_VISIBLE;
1028
int isvisiblecube(const vec &o, int size)
1031
center.add(size/2.0f);
1032
return isvisiblesphere(size*SQRT3/2.0f, center);
1036
float vadist(vtxarray *va, const vec &p)
1038
if(va->min.x>va->max.x)
1040
ivec o(va->x, va->y, va->z);
1041
return p.dist_to_bb(o, ivec(o).add(va->size)); // box contains only sky/water
1043
return p.dist_to_bb(va->min, va->max);
1046
#define VASORTSIZE 64
1048
static vtxarray *vasort[VASORTSIZE];
1050
void addvisibleva(vtxarray *va)
1052
float dist = vadist(va, camera1->o);
1053
va->distance = int(dist); /*cv.dist(camera1->o) - va->size*SQRT3/2*/
1054
va->curlod = lodsize==0 || va->distance<loddistance ? 0 : 1;
1056
int hash = min(int(dist*VASORTSIZE/hdr.worldsize), VASORTSIZE-1);
1057
vtxarray **prev = &vasort[hash], *cur = vasort[hash];
1059
while(cur && va->distance > cur->distance)
1069
void sortvisiblevas()
1072
vtxarray **last = &visibleva;
1073
loopi(VASORTSIZE) if(vasort[i])
1075
vtxarray *va = vasort[i];
1077
while(va->next) va = va->next;
1082
void findvisiblevas(vector<vtxarray *> &vas, bool resetocclude = false)
1086
vtxarray &v = *vas[i];
1087
int prevvfc = resetocclude ? VFC_NOT_VISIBLE : v.curvfc;
1088
v.curvfc = isvisiblecube(vec(v.x, v.y, v.z), v.size);
1089
if(v.curvfc!=VFC_NOT_VISIBLE)
1092
if(v.children->length()) findvisiblevas(*v.children, prevvfc==VFC_NOT_VISIBLE);
1093
if(prevvfc==VFC_NOT_VISIBLE)
1095
v.occluded = OCCLUDE_NOTHING;
1102
void setvfcP(float pyaw, float ppitch, const vec &camera)
1104
float vpxo = 90.0 - vfcfov / 2.0;
1105
float vpyo = 90.0 - (vfcfov * float(vfch) / float(vfcw)) / 2;
1106
float yaw = pyaw * RAD;
1107
float yawp = (pyaw + vpxo) * RAD;
1108
float yawm = (pyaw - vpxo) * RAD;
1109
float pitch = ppitch * RAD;
1110
float pitchp = (ppitch + vpyo) * RAD;
1111
float pitchm = (ppitch - vpyo) * RAD;
1112
vfcP[0].toplane(vec(yaw, pitch), camera); // back/far plane
1113
vfcP[1].toplane(vec(yawp, pitch), camera); // left plane
1114
vfcP[2].toplane(vec(yawm, pitch), camera); // right plane
1115
vfcP[3].toplane(vec(yaw, pitchp), camera); // top plane
1116
vfcP[4].toplane(vec(yaw, pitchm), camera); // bottom plane
1117
vfcDfog = getvar("fog");
1122
void reflectvfcP(float z)
1124
memcpy(oldvfcP, vfcP, sizeof(vfcP));
1127
o.z = z-(camera1->o.z-z);
1128
setvfcP(camera1->yaw, -camera1->pitch, o);
1133
memcpy(vfcP, oldvfcP, sizeof(vfcP));
1136
void visiblecubes(cube *c, int size, int cx, int cy, int cz, int w, int h, int fov)
1138
memset(vasort, 0, sizeof(vasort));
1144
// Calculate view frustrum: Only changes if resize, but...
1145
setvfcP(camera1->yaw, camera1->pitch, camera1->o);
1147
findvisiblevas(varoot);
1151
bool insideva(const vtxarray *va, const vec &v)
1153
return va->x<=v.x && va->y<=v.y && va->z<=v.z && va->x+va->size>v.x && va->y+va->size>v.y && va->z+va->size>v.z;
1156
static ivec vaorigin;
1160
vaorigin = ivec(-1, -1, -1);
1163
void setorigin(vtxarray *va)
1165
ivec o(va->x, va->y, va->z);
1166
o.mask(~VVEC_INT_MASK);
1172
glTranslatef(o.x, o.y, o.z);
1173
static const float scale = 1.0f/(1<<VVEC_FRAC);
1174
glScalef(scale, scale, scale);
1180
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1181
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
1182
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
1183
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
1184
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
1185
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
1188
#define MAXQUERY 2048
1193
occludequery queries[MAXQUERY];
1196
static queryframe queryframes[2] = {{0, 0}, {0, 0}};
1197
static uint flipquery = 0;
1201
return queryframes[flipquery].cur;
1206
flipquery = (flipquery + 1) % 2;
1207
queryframe &qf = queryframes[flipquery];
1208
loopi(qf.cur) qf.queries[i].owner = NULL;
1212
occludequery *newquery(void *owner)
1214
queryframe &qf = queryframes[flipquery];
1215
if(qf.cur >= qf.max)
1217
if(qf.max >= MAXQUERY) return NULL;
1218
glGenQueries_(1, &qf.queries[qf.max++].id);
1220
occludequery *query = &qf.queries[qf.cur++];
1221
query->owner = owner;
1222
query->fragments = -1;
1228
loopi(2) loopj(queryframes[i].max) queryframes[i].queries[j].owner = NULL;
1231
VAR(oqfrags, 0, 8, 64);
1232
VAR(oqreflect, 0, 4, 64);
1234
extern float reflecting, refracting;
1236
bool checkquery(occludequery *query, bool nowait)
1239
if(query->fragments >= 0) fragments = query->fragments;
1245
glGetQueryObjectiv_(query->id, GL_QUERY_RESULT_AVAILABLE, &avail);
1246
if(!avail) return false;
1248
glGetQueryObjectuiv_(query->id, GL_QUERY_RESULT_ARB, &fragments);
1249
query->fragments = fragments;
1251
return fragments < (uint)(reflecting ? oqreflect : oqfrags);
1254
void drawbb(const ivec &bo, const ivec &br, const vec &camera = camera1->o)
1260
int dim = dimension(i), coord = dimcoord(i);
1264
if(camera[dim] < bo[dim] + br[dim]) continue;
1266
else if(camera[dim] > bo[dim]) continue;
1270
const ivec &cc = cubecoords[fv[i][j]];
1271
glVertex3i(cc.x ? bo.x+br.x : bo.x,
1272
cc.y ? bo.y+br.y : bo.y,
1273
cc.z ? bo.z+br.z : bo.z);
1282
extern int octaentsize;
1284
static octaentities *visiblemms, **lastvisiblemms;
1286
void findvisiblemms(const vector<extentity *> &ents)
1288
for(vtxarray *va = visibleva; va; va = va->next)
1290
if(!va->mapmodels || va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) continue;
1291
loopv(*va->mapmodels)
1293
octaentities *oe = (*va->mapmodels)[i];
1294
if(isvisiblecube(oe->o.tovec(), oe->size) >= VFC_FOGGED) continue;
1296
bool occluded = oe->query && oe->query->owner == oe && checkquery(oe->query);
1302
*lastvisiblemms = oe;
1303
lastvisiblemms = &oe->next;
1308
loopv(oe->mapmodels)
1310
extentity &e = *ents[oe->mapmodels[i]];
1311
if(e.visible || (e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED)) continue;
1315
if(!visible) continue;
1317
oe->distance = int(camera1->o.dist_to_bb(oe->o, oe->size));
1319
octaentities **prev = &visiblemms, *cur = visiblemms;
1320
while(cur && cur->distance >= 0 && oe->distance > cur->distance)
1326
if(*prev == NULL) lastvisiblemms = &oe->next;
1336
extern bool getentboundingbox(extentity &e, ivec &o, ivec &r);
1338
void rendermapmodel(extentity &e)
1340
int anim = ANIM_MAPMODEL|ANIM_LOOP, basetime = 0;
1341
if(e.attr3) switch(e.triggerstate)
1343
case TRIGGER_RESET: anim = ANIM_TRIGGER|ANIM_START; break;
1344
case TRIGGERING: anim = ANIM_TRIGGER; basetime = e.lasttrigger; break;
1345
case TRIGGERED: anim = ANIM_TRIGGER|ANIM_END; break;
1346
case TRIGGER_RESETTING: anim = ANIM_TRIGGER|ANIM_REVERSE; basetime = e.lasttrigger; break;
1348
mapmodelinfo &mmi = getmminfo(e.attr2);
1349
if(&mmi) rendermodel(e.color, e.dir, mmi.name, anim, 0, mmi.tex, e.o.x, e.o.y, e.o.z, (float)((e.attr1+7)-(e.attr1+7)%15), 0, 10.0f, basetime, NULL, MDL_CULL_VFC | MDL_CULL_DIST);
1352
extern int reflectdist;
1354
static vector<octaentities *> renderedmms;
1356
vtxarray *reflectedva;
1358
void renderreflectedmapmodels(float z, bool refract)
1360
bool reflected = !refract && camera1->o.z >= z;
1361
vector<octaentities *> reflectedmms;
1362
vector<octaentities *> &mms = reflected ? reflectedmms : renderedmms;
1363
const vector<extentity *> &ents = et->getents();
1368
for(vtxarray *va = reflectedva; va; va = va->rnext)
1370
if(!va->mapmodels || va->distance > reflectdist) continue;
1371
loopv(*va->mapmodels) reflectedmms.add((*va->mapmodels)[i]);
1376
octaentities *oe = mms[i];
1377
if(refract ? oe->o.z >= z : oe->o.z+oe->size <= z) continue;
1378
if(reflected && isvisiblecube(oe->o.tovec(), oe->size) >= VFC_FOGGED) continue;
1379
loopv(oe->mapmodels)
1381
extentity &e = *ents[oe->mapmodels[i]];
1382
if(e.visible || (e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED)) continue;
1388
octaentities *oe = mms[i];
1389
loopv(oe->mapmodels)
1391
extentity &e = *ents[oe->mapmodels[i]];
1392
if(!e.visible) continue;
1397
if(reflected) restorevfcP();
1400
void rendermapmodels()
1402
const vector<extentity *> &ents = et->getents();
1405
lastvisiblemms = &visiblemms;
1406
findvisiblemms(ents);
1408
static int skipoq = 0;
1410
renderedmms.setsizenodelete(0);
1412
for(octaentities *oe = visiblemms; oe; oe = oe->next)
1414
bool occluded = oe->distance < 0;
1417
bool hasmodels = false;
1418
loopv(oe->mapmodels)
1420
const extentity &e = *ents[oe->mapmodels[i]];
1421
if(!e.visible || (e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED)) continue;
1425
if(!hasmodels) continue;
1428
if(!hasOQ || !oqfrags || !oqmm || !oe->distance) oe->query = NULL;
1429
else if(!occluded && (++skipoq % oqmm)) oe->query = NULL;
1430
else oe->query = newquery(oe);
1436
glDepthMask(GL_FALSE);
1437
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1439
startquery(oe->query);
1441
if(!occluded || oe->query)
1443
ivec bbmin(oe->o), bbmax(oe->o);
1444
bbmin.add(oe->size);
1445
bool rendered = false;
1446
loopv(oe->mapmodels)
1448
extentity &e = *ents[oe->mapmodels[i]];
1449
if(e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED) continue;
1453
if(getentboundingbox(e, bo, br))
1457
bbmin[j] = min(bbmin[j], bo[j]);
1458
bbmax[j] = max(bbmax[j], bo[j]+br[j]);
1464
if(!rendered) { renderedmms.add(oe); rendered = true; };
1473
bbmin[j] = max(bbmin[j], oe->o[j]);
1474
bbmax[j] = min(bbmax[j], oe->o[j]+oe->size);
1476
drawbb(bbmin, bbmax.sub(bbmin));
1481
endquery(oe->query);
1484
glDepthMask(GL_TRUE);
1485
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1491
bool bboccluded(const ivec &bo, const ivec &br, cube *c, const ivec &o, int size)
1493
loopoctabox(o, size, bo, br)
1495
ivec co(i, o.x, o.y, o.z, size);
1496
if(c[i].ext && c[i].ext->va)
1498
vtxarray *va = c[i].ext->va;
1499
if(va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) continue;
1501
if(c[i].children && bboccluded(bo, br, c[i].children, co, size>>1)) continue;
1507
VAR(outline, 0, 0, 0xFFFFFF);
1509
void renderoutline()
1511
if(!editmode || !outline) return;
1513
notextureshader->set();
1515
glDisable(GL_TEXTURE_2D);
1516
glEnableClientState(GL_VERTEX_ARRAY);
1520
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1521
glColor3ub((outline>>16)&0xFF, (outline>>8)&0xFF, outline&0xFF);
1524
GLuint vbufGL = 0, ebufGL = 0;
1525
for(vtxarray *va = visibleva; va; va = va->next)
1527
lodlevel &lod = va->curlod ? va->l1 : va->l0;
1528
if(!lod.texs || va->occluded >= OCCLUDE_GEOM) continue;
1532
bool vbufchanged = true;
1535
if(vbufGL == va->vbufGL) vbufchanged = false;
1538
glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbufGL);
1539
vbufGL = va->vbufGL;
1541
if(ebufGL != lod.ebufGL)
1543
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, lod.ebufGL);
1544
ebufGL = lod.ebufGL;
1547
if(vbufchanged) glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, floatvtx ? sizeof(fvertex) : sizeof(vertex), &(va->vbuf[0].x));
1549
glDrawElements(GL_TRIANGLES, 3*lod.tris, GL_UNSIGNED_SHORT, lod.ebuf);
1551
xtravertsva += va->verts;
1554
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1560
glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
1561
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1563
glDisableClientState(GL_VERTEX_ARRAY);
1564
glEnable(GL_TEXTURE_2D);
1566
defaultshader->set();
1569
float orientation_tangent [3][4] = { { 0,1, 0,0 }, { 1,0, 0,0 }, { 1,0,0,0 }};
1570
float orientation_binormal[3][4] = { { 0,0,-1,0 }, { 0,0,-1,0 }, { 0,1,0,0 }};
1574
bool colormask, depthmask, texture;
1575
GLuint vbufGL, ebufGL;
1578
const ShaderParam *vertparams[MAXSHADERPARAMS], *pixparams[MAXSHADERPARAMS];
1580
renderstate() : colormask(true), depthmask(true), texture(true), vbufGL(0), ebufGL(0), fogplane(-1), shader(NULL)
1582
memset(vertparams, 0, sizeof(vertparams));
1583
memset(pixparams, 0, sizeof(pixparams));
1587
#define setvertparam(param) \
1589
if(!cur.vertparams[param.index] || memcmp(cur.vertparams[param.index]->val, param.val, sizeof(param.val))) \
1590
glProgramEnvParameter4fv_(GL_VERTEX_PROGRAM_ARB, 10+param.index, param.val); \
1591
cur.vertparams[param.index] = ¶m; \
1594
#define setpixparam(param) \
1596
if(!cur.pixparams[param.index] || memcmp(cur.pixparams[param.index]->val, param.val, sizeof(param.val))) \
1597
glProgramEnvParameter4fv_(GL_FRAGMENT_PROGRAM_ARB, 10+param.index, param.val); \
1598
cur.pixparams[param.index] = ¶m; \
1601
void renderquery(renderstate &cur, occludequery *query, vtxarray *va)
1604
if(cur.shader!=nocolorshader) (cur.shader = nocolorshader)->set();
1605
if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); };
1606
if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); };
1610
ivec origin(va->x, va->y, va->z);
1611
origin.mask(~VVEC_INT_MASK);
1613
vec camera(camera1->o);
1614
if(reflecting && !refracting) camera.z = reflecting;
1617
if(va->children || va->mapmodels || va->l0.matsurfs || va->l0.sky || va->l0.explicitsky)
1619
bbmin = ivec(va->x, va->y, va->z);
1620
bbmax = ivec(va->size, va->size, va->size);
1629
drawbb(bbmin.sub(origin).mul(1<<VVEC_FRAC),
1630
bbmax.mul(1<<VVEC_FRAC),
1631
vec(camera).sub(origin.tovec()).mul(1<<VVEC_FRAC));
1636
void renderva(renderstate &cur, vtxarray *va, lodlevel &lod, bool zfill = false)
1639
bool vbufchanged = true;
1642
if(cur.vbufGL == va->vbufGL) vbufchanged = false;
1645
glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbufGL);
1646
cur.vbufGL = va->vbufGL;
1648
if(cur.ebufGL != lod.ebufGL)
1650
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, lod.ebufGL);
1651
cur.ebufGL = lod.ebufGL;
1654
if(vbufchanged) glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, floatvtx ? sizeof(fvertex) : sizeof(vertex), &(va->vbuf[0].x));
1655
if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); };
1659
if(cur.shader != nocolorshader) (cur.shader = nocolorshader)->set();
1660
if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); };
1661
glDrawElements(GL_TRIANGLES, 3*lod.tris, GL_UNSIGNED_SHORT, lod.ebuf);
1663
xtravertsva += va->verts;
1669
float fogplane = refracting - (va->z & ~VVEC_INT_MASK);
1670
if(cur.fogplane!=fogplane)
1672
cur.fogplane = fogplane;
1673
setfogplane(0.5f, fogplane);
1676
if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); };
1678
extern int waterfog;
1679
if(refracting ? va->z+va->size<=refracting-waterfog : va->curvfc==VFC_FOGGED)
1681
static Shader *fogshader = NULL;
1682
if(!fogshader) fogshader = lookupshaderbyname("fogworld");
1683
if(fogshader!=cur.shader) (cur.shader = fogshader)->set();
1686
cur.texture = false;
1687
glDisable(GL_TEXTURE_2D);
1688
glActiveTexture_(GL_TEXTURE1_ARB);
1689
glDisable(GL_TEXTURE_2D);
1690
glActiveTexture_(GL_TEXTURE0_ARB);
1692
glDrawElements(GL_TRIANGLES, 3*lod.tris, GL_UNSIGNED_SHORT, lod.ebuf);
1695
vverts += va->verts;
1702
glEnable(GL_TEXTURE_2D);
1703
glActiveTexture_(GL_TEXTURE1_ARB);
1704
glEnable(GL_TEXTURE_2D);
1705
glActiveTexture_(GL_TEXTURE0_ARB);
1708
if(renderpath!=R_FIXEDFUNCTION)
1710
if(vbufchanged) glColorPointer(3, GL_UNSIGNED_BYTE, floatvtx ? sizeof(fvertex) : sizeof(vertex), floatvtx ? &(((fvertex *)va->vbuf)[0].n) : &(va->vbuf[0].n));
1711
glProgramEnvParameter4fv_(GL_VERTEX_PROGRAM_ARB, 4, vec4(camera1->o, 1).sub(ivec(va->x, va->y, va->z).mask(~VVEC_INT_MASK).tovec()).mul(2).v);
1716
glClientActiveTexture_(GL_TEXTURE1_ARB);
1717
glTexCoordPointer(2, GL_SHORT, floatvtx ? sizeof(fvertex) : sizeof(vertex), floatvtx ? &(((fvertex *)va->vbuf)[0].u) : &(va->vbuf[0].u));
1718
glClientActiveTexture_(GL_TEXTURE0_ARB);
1721
ushort *ebuf = lod.ebuf;
1722
int lastlm = -1, lastxs = -1, lastys = -1, lastl = -1;
1723
Slot *lastslot = NULL;
1726
Slot &slot = lookuptexture(lod.eslist[i].texture);
1727
Texture *tex = slot.sts[0].t;
1728
Shader *s = slot.shader;
1730
extern vector<GLuint> lmtexids;
1731
int lmid = lod.eslist[i].lmid, curlm = lmtexids[lmid];
1732
if(curlm!=lastlm || !lastslot || s->type!=lastslot->shader->type)
1736
glActiveTexture_(GL_TEXTURE1_ARB);
1737
glBindTexture(GL_TEXTURE_2D, curlm);
1740
if(renderpath!=R_FIXEDFUNCTION && s->type==SHADER_NORMALSLMS && (lmid<LMID_RESERVED || lightmaps[lmid-LMID_RESERVED].type==LM_BUMPMAP0))
1742
glActiveTexture_(GL_TEXTURE2_ARB);
1743
glBindTexture(GL_TEXTURE_2D, lmtexids[lmid+1]);
1746
glActiveTexture_(GL_TEXTURE0_ARB);
1751
glBindTexture(GL_TEXTURE_2D, tex->gl);
1752
if(s!=cur.shader) (cur.shader = s)->set();
1754
if(renderpath!=R_FIXEDFUNCTION)
1756
int tmu = s->type==SHADER_NORMALSLMS ? 3 : 2;
1759
Slot::Tex &t = slot.sts[j];
1760
if(t.type==TEX_DIFFUSE || t.combined>=0) continue;
1761
glActiveTexture_(GL_TEXTURE0_ARB+tmu++);
1762
glBindTexture(GL_TEXTURE_2D, t.t->gl);
1764
uint vertparams = 0, pixparams = 0;
1767
const ShaderParam ¶m = slot.params[j];
1768
if(param.type == SHPARAM_VERTEX)
1770
setvertparam(param);
1771
vertparams |= 1<<param.index;
1776
pixparams |= 1<<param.index;
1779
loopvj(s->defaultparams)
1781
const ShaderParam ¶m = s->defaultparams[j];
1782
if(param.type == SHPARAM_VERTEX)
1784
if(!(vertparams & (1<<param.index))) setvertparam(param);
1786
else if(!(pixparams & (1<<param.index))) setpixparam(param);
1788
glActiveTexture_(GL_TEXTURE0_ARB);
1793
loopl(3) if (lod.eslist[i].length[l])
1795
if(lastl!=l || lastxs!=tex->xs || lastys!=tex->ys)
1797
static int si[] = { 1, 0, 0 };
1798
static int ti[] = { 2, 2, 1 };
1800
GLfloat s[] = { 0.0f, 0.0f, 0.0f, 0.0f };
1801
s[si[l]] = 8.0f/(tex->xs<<VVEC_FRAC);
1802
GLfloat t[] = { 0.0f, 0.0f, 0.0f, 0.0f };
1803
t[ti[l]] = (l <= 1 ? -8.0f : 8.0f)/(tex->ys<<VVEC_FRAC);
1805
if(renderpath==R_FIXEDFUNCTION)
1807
glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
1808
glTexGenfv(GL_T, GL_OBJECT_PLANE, t);
1809
// KLUGE: workaround for buggy nvidia drivers
1810
// object planes are somehow invalid unless texgen is toggled
1811
extern int nvidia_texgen_bug;
1812
if(nvidia_texgen_bug)
1814
glDisable(GL_TEXTURE_GEN_S);
1815
glDisable(GL_TEXTURE_GEN_T);
1816
glEnable(GL_TEXTURE_GEN_S);
1817
glEnable(GL_TEXTURE_GEN_T);
1822
glProgramEnvParameter4fv_(GL_VERTEX_PROGRAM_ARB, 0, s); // have to pass in env, otherwise same problem as fixed function
1823
glProgramEnvParameter4fv_(GL_VERTEX_PROGRAM_ARB, 1, t);
1831
if(s->type>=SHADER_NORMALSLMS && renderpath!=R_FIXEDFUNCTION)
1833
glProgramEnvParameter4fv_(GL_VERTEX_PROGRAM_ARB, 2, orientation_tangent[l]);
1834
glProgramEnvParameter4fv_(GL_VERTEX_PROGRAM_ARB, 3, orientation_binormal[l]);
1837
glDrawElements(GL_TRIANGLES, lod.eslist[i].length[l], GL_UNSIGNED_SHORT, ebuf);
1838
ebuf += lod.eslist[i].length[l]; // Advance to next array.
1844
vverts += va->verts;
1847
VAR(oqdist, 0, 256, 1024);
1848
VAR(zpass, 0, 1, 1);
1850
extern int ati_texgen_bug;
1854
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1855
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1856
glEnable(GL_TEXTURE_GEN_S);
1857
glEnable(GL_TEXTURE_GEN_T);
1858
if(ati_texgen_bug) glEnable(GL_TEXTURE_GEN_R); // should not be needed, but apparently makes some ATI drivers happy
1860
if(renderpath!=R_FIXEDFUNCTION) glEnableClientState(GL_COLOR_ARRAY);
1864
glActiveTexture_(GL_TEXTURE1_ARB);
1865
glClientActiveTexture_(GL_TEXTURE1_ARB);
1867
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
1869
glEnable(GL_TEXTURE_2D);
1871
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1873
glMatrixMode(GL_TEXTURE);
1875
glScalef(1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f);
1876
glMatrixMode(GL_MODELVIEW);
1878
glActiveTexture_(GL_TEXTURE0_ARB);
1879
glClientActiveTexture_(GL_TEXTURE0_ARB);
1881
if(renderpath!=R_FIXEDFUNCTION)
1883
loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB+i); glEnable(GL_TEXTURE_2D); };
1884
glActiveTexture_(GL_TEXTURE0_ARB);
1885
glProgramEnvParameter4f_(GL_FRAGMENT_PROGRAM_ARB, 5, hdr.ambient/255.0f, hdr.ambient/255.0f, hdr.ambient/255.0f, 0);
1888
glColor4f(1, 1, 1, 1);
1895
glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
1896
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1898
glDisableClientState(GL_VERTEX_ARRAY);
1899
if(renderpath!=R_FIXEDFUNCTION)
1901
glDisableClientState(GL_COLOR_ARRAY);
1902
loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB+i); glDisable(GL_TEXTURE_2D); };
1905
glActiveTexture_(GL_TEXTURE1_ARB);
1906
glClientActiveTexture_(GL_TEXTURE1_ARB);
1908
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
1910
glDisable(GL_TEXTURE_2D);
1911
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1913
glActiveTexture_(GL_TEXTURE0_ARB);
1914
glClientActiveTexture_(GL_TEXTURE0_ARB);
1915
glEnable(GL_TEXTURE_2D);
1917
glDisable(GL_TEXTURE_GEN_S);
1918
glDisable(GL_TEXTURE_GEN_T);
1919
if(ati_texgen_bug) glDisable(GL_TEXTURE_GEN_R);
1923
VAR(showva, 0, 0, 1);
1928
glEnableClientState(GL_VERTEX_ARRAY);
1930
if(!zpass) setupTMUs();
1941
for(vtxarray *va = visibleva; va; va = va->next)
1943
lodlevel &lod = va->curlod ? va->l1 : va->l0;
1944
if(!lod.texs) continue;
1945
if(hasOQ && oqfrags && (zpass || va->distance > oqdist) && !insideva(va, camera1->o))
1947
if(!zpass && va->query && va->query->owner == va)
1948
va->occluded = checkquery(va->query) ? min(va->occluded+1, OCCLUDE_BB) : OCCLUDE_NOTHING;
1949
if(zpass && va->parent &&
1950
(va->parent->occluded == OCCLUDE_PARENT ||
1951
(va->parent->occluded >= OCCLUDE_BB &&
1952
va->parent->query && va->parent->query->owner == va->parent && va->parent->query->fragments < 0)))
1955
if(va->occluded >= OCCLUDE_GEOM)
1957
va->occluded = OCCLUDE_PARENT;
1961
else if(va->occluded >= OCCLUDE_GEOM)
1963
va->query = newquery(va);
1964
if(va->query) renderquery(cur, va->query, va);
1967
else va->query = newquery(va);
1972
va->occluded = OCCLUDE_NOTHING;
1976
if(va->query) startquery(va->query);
1978
renderva(cur, va, lod, zpass!=0);
1980
if(va->query) endquery(va->query);
1983
if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); };
1984
if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); };
1989
glDepthFunc(GL_LEQUAL);
1994
for(vtxarray *va = visibleva; va; va = va->next)
1996
lodlevel &lod = va->curlod ? va->l1 : va->l0;
1997
if(!lod.texs) continue;
1998
if(va->parent && va->parent->occluded >= OCCLUDE_BB && (!va->parent->query || va->parent->query->fragments >= 0))
2001
va->occluded = OCCLUDE_BB;
2006
va->occluded = checkquery(va->query) ? min(va->occluded+1, OCCLUDE_BB) : OCCLUDE_NOTHING;
2007
if(va->occluded >= OCCLUDE_GEOM) continue;
2009
else if(va->occluded == OCCLUDE_PARENT) va->occluded = OCCLUDE_NOTHING;
2012
if(showva && editmode && renderpath==R_FIXEDFUNCTION)
2014
if(insideva(va, worldpos))
2016
glColor3f(1, showvas/3.0f, 1-showvas/3.0f);
2019
else glColor3f(1, 1, 1);
2022
renderva(cur, va, lod);
2024
glDepthFunc(GL_LESS);
2031
void findreflectedvas(vector<vtxarray *> &vas, float z, bool refract, bool vfc = true)
2033
bool doOQ = hasOQ && oqfrags && oqreflect;
2036
vtxarray *va = vas[i];
2037
if(!vfc) va->curvfc = VFC_NOT_VISIBLE;
2038
if(va->curvfc == VFC_FOGGED || va->z+va->size <= z || isvisiblecube(vec(va->x, va->y, va->z), va->size) >= VFC_FOGGED) continue;
2040
if(va->curvfc == VFC_FULL_VISIBLE)
2042
if(va->occluded >= OCCLUDE_BB) continue;
2043
if(va->occluded >= OCCLUDE_GEOM) render = false;
2047
if(va->curvfc == VFC_NOT_VISIBLE) va->distance = (int)vadist(va, camera1->o);
2048
if(!doOQ && va->distance > reflectdist) continue;
2050
vtxarray **vprev = &reflectedva, *vcur = reflectedva;
2051
while(vcur && va->distance > vcur->distance)
2053
vprev = &vcur->rnext;
2059
if(va->children->length()) findreflectedvas(*va->children, z, refract, va->curvfc != VFC_NOT_VISIBLE);
2063
void renderreflectedgeom(float z, bool refract)
2065
glEnableClientState(GL_VERTEX_ARRAY);
2072
if(!refract && camera1->o.z >= z)
2076
findreflectedvas(varoot, z, refract);
2077
bool doOQ = hasOQ && oqfrags && oqreflect;
2078
for(vtxarray *va = reflectedva; va; va = va->rnext)
2080
lodlevel &lod = va->curlod ? va->l1 : va->l0;
2081
if(!lod.texs || va->max.z <= z) continue;
2084
va->rquery = newquery(&va->rquery);
2085
if(!va->rquery) continue;
2086
if(va->occluded >= OCCLUDE_BB || va->curvfc == VFC_NOT_VISIBLE)
2088
renderquery(cur, va->rquery, va);
2092
if(va->rquery) startquery(va->rquery);
2093
renderva(cur, va, lod, doOQ);
2094
if(va->rquery) endquery(va->rquery);
2098
glDepthFunc(GL_LEQUAL);
2099
if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); };
2100
if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); };
2102
for(vtxarray **prevva = &reflectedva, *va = reflectedva; va; prevva = &va->rnext, va = va->rnext)
2104
lodlevel &lod = va->curlod ? va->l1 : va->l0;
2105
if(!lod.texs || va->max.z <= z) continue;
2106
if(va->rquery && checkquery(va->rquery))
2108
if(va->occluded >= OCCLUDE_BB || va->curvfc == VFC_NOT_VISIBLE) *prevva = va->rnext;
2111
renderva(cur, va, lod);
2113
glDepthFunc(GL_LESS);
2119
for(vtxarray *va = visibleva; va; va = va->next)
2121
lodlevel &lod = va->curlod ? va->l1 : va->l0;
2122
if(!lod.texs) continue;
2123
if(va->curvfc == VFC_FOGGED || (refract && camera1->o.z >= z ? va->min.z > z : va->max.z <= z) || va->occluded >= OCCLUDE_GEOM) continue;
2124
if((!hasOQ || !oqfrags) && va->distance > reflectdist) break;
2125
renderva(cur, va, lod);
2133
static GLuint skyvbufGL, skyebufGL;
2135
void renderskyva(vtxarray *va, lodlevel &lod, bool explicitonly = false)
2139
bool vbufchanged = true;
2142
if(skyvbufGL == va->vbufGL) vbufchanged = false;
2145
glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbufGL);
2146
glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, floatvtx ? sizeof(fvertex) : sizeof(vertex), &(va->vbuf[0].x));
2147
skyvbufGL = va->vbufGL;
2149
if(skyebufGL != lod.skybufGL)
2151
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, lod.skybufGL);
2152
skyebufGL = lod.skybufGL;
2155
if(vbufchanged) glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, floatvtx ? sizeof(fvertex) : sizeof(vertex), &(va->vbuf[0].x));
2157
glDrawElements(GL_TRIANGLES, explicitonly ? lod.explicitsky : lod.sky+lod.explicitsky, GL_UNSIGNED_SHORT, explicitonly ? lod.skybuf+lod.sky : lod.skybuf);
2160
if(!explicitonly) xtraverts += lod.sky/3;
2161
xtraverts += lod.explicitsky/3;
2164
void renderreflectedskyvas(vector<vtxarray *> &vas, float z, bool vfc = true)
2168
vtxarray *va = vas[i];
2169
lodlevel &lod = va->curlod ? va->l1 : va->l0;
2170
if((vfc && va->curvfc == VFC_FULL_VISIBLE) && va->occluded >= OCCLUDE_BB) continue;
2171
if(va->z+va->size <= z || isvisiblecube(vec(va->x, va->y, va->z), va->size) == VFC_NOT_VISIBLE) continue;
2172
if(lod.sky+lod.explicitsky) renderskyva(va, lod);
2173
if(va->children->length()) renderreflectedskyvas(*va->children, z, vfc && va->curvfc != VFC_NOT_VISIBLE);
2177
void rendersky(bool explicitonly, float zreflect)
2179
glEnableClientState(GL_VERTEX_ARRAY);
2185
skyvbufGL = skyebufGL = 0;
2189
reflectvfcP(zreflect);
2190
renderreflectedskyvas(varoot, zreflect);
2193
else for(vtxarray *va = visibleva; va; va = va->next)
2195
lodlevel &lod = va->curlod ? va->l1 : va->l0;
2196
if(va->occluded >= OCCLUDE_BB || !(explicitonly ? lod.explicitsky : lod.sky+lod.explicitsky)) continue;
2198
renderskyva(va, lod, explicitonly);
2205
glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
2206
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
2208
glDisableClientState(GL_VERTEX_ARRAY);
2211
void writeobj(char *name)
2213
bool oldVBO = hasVBO;
2216
s_sprintfd(fname)("%s.obj", name);
2217
FILE *f = fopen(fname, "w");
2219
fprintf(f, "# obj file of sauerbraten level\n");
2222
vtxarray &v = *valist[i];
2223
vertex *verts = v.vbuf;
2226
loopj(v.verts) fprintf(f, "v %d %d %d\n", verts[j].x, verts[j].y, verts[j].z);
2227
lodlevel &lod = v.curlod ? v.l1 : v.l0;
2228
ushort *ebuf = lod.ebuf;
2229
loopi(lod.texs) loopl(3) loopj(lod.eslist[i].length[l]/3)
2232
for(int k = 3; k>=0; k--) fprintf(f, " %d", ebuf[k]-v.verts);
2243
COMMAND(writeobj, "s");