1
// rendercubes.cpp: sits in between worldrender.cpp and rendergl.cpp and fills the vertex array for different cube surfaces.
14
glEnableClientState(GL_VERTEX_ARRAY);
15
glEnableClientState(GL_COLOR_ARRAY);
16
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
18
vertex *buf = verts.getbuf();
19
glVertexPointer(3, GL_FLOAT, sizeof(vertex), &buf->x);
20
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), &buf->r);
21
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), &buf->u);
24
struct strips { vector<GLint> first; vector<GLsizei> count; };
29
strips tris, tristrips, quads;
32
stripbatch skystrips = { DEFAULT_SKY };
33
stripbatch stripbatches[256];
34
uchar renderedtex[256];
37
extern int ati_mda_bug;
39
#define RENDERSTRIPS(strips, type) \
40
if(strips.first.length()) \
42
if(hasMDA && !ati_mda_bug) glMultiDrawArrays_(type, strips.first.getbuf(), strips.count.getbuf(), strips.first.length()); \
43
else loopv(strips.first) glDrawArrays(type, strips.first[i], strips.count[i]); \
44
strips.first.setsizenodelete(0); \
45
strips.count.setsizenodelete(0); \
48
void renderstripssky()
50
if(skystrips.tris.first.empty() && skystrips.tristrips.first.empty() && skystrips.quads.first.empty()) return;
51
glDisable(GL_TEXTURE_2D);
52
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
53
RENDERSTRIPS(skystrips.tris, GL_TRIANGLES);
54
RENDERSTRIPS(skystrips.tristrips, GL_TRIANGLE_STRIP);
55
RENDERSTRIPS(skystrips.quads, GL_QUADS);
56
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
57
glEnable(GL_TEXTURE_2D);
64
stripbatch &sb = stripbatches[j];
65
glBindTexture(GL_TEXTURE_2D, lookupworldtexture(sb.tex)->id);
66
RENDERSTRIPS(sb.tris, GL_TRIANGLES);
67
RENDERSTRIPS(sb.tristrips, GL_TRIANGLE_STRIP);
68
RENDERSTRIPS(sb.quads, GL_QUADS);
72
glDisableClientState(GL_VERTEX_ARRAY);
73
glDisableClientState(GL_COLOR_ARRAY);
74
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
77
void addstrip(int type, int tex, int start, int n)
79
stripbatch *sb = NULL;
84
loopi(n) skyfloor = min(skyfloor, verts[start + i].z);
88
sb = &stripbatches[renderedtex[tex]];
89
if(sb->tex!=tex || sb>=&stripbatches[renderedtexs])
91
sb = &stripbatches[renderedtex[tex] = renderedtexs++];
95
strips &s = (type==GL_QUADS ? sb->quads : (type==GL_TRIANGLES ? sb->tris : sb->tristrips));
96
if(type!=GL_TRIANGLE_STRIP && s.first.length() && s.first.last()+s.count.last() == start)
105
// generating the actual vertices is done dynamically every frame and sits at the
106
// leaves of all these functions, and are part of the cpu bottleneck on really slow
107
// machines, hence the macros.
109
#define vert(v1, v2, v3, ls, t1, t2) { \
110
vertex &v = verts.add(); \
111
v.u = t1; v.v = t2; \
112
v.x = (float)(v1); v.y = (float)(v2); v.z = (float)(v3); \
113
v.r = ls->r; v.g = ls->g; v.b = ls->b; v.a = 255; \
124
const float TEXTURESCALE = 32.0f;
125
int striptype = 0, striptex, oh, oy, ox, odir; // the o* vars are used by the stripification
126
int ol1r, ol1g, ol1b, ol2r, ol2g, ol2b;
132
void showmip() { showm = !showm; }
133
void mipstats(int a, int b, int c) { if(showm) conoutf("1x1/2x2/4x4: %d / %d / %d", a, b, c); }
135
COMMAND(showmip, ARG_NONE);
137
VAR(mergestrips, 0, 1, 1);
139
#define stripend(verts) \
141
int type = GL_TRIANGLE_STRIP, len = verts.length()-firstindex; \
142
if(mergestrips) switch(len) { \
143
case 3: type = GL_TRIANGLES; break; \
144
case 4: type = GL_QUADS; swap(verts.last(), verts[verts.length()-2]); break; \
146
addstrip(type, striptex, firstindex, len); \
150
void finishstrips() { stripend(verts); }
153
VARP(lighterror, 1, 4, 100);
155
void render_flat(int wtex, int x, int y, int size, int h, sqr *l1, sqr *l4, sqr *l3, sqr *l2, bool isceil) // floor/ceil quads
157
if(showm) { l3 = l1 = &sbright; l4 = l2 = &sdark; }
159
Texture *t = lookupworldtexture(wtex);
160
float xf = TEXTURESCALE/t->xs;
161
float yf = TEXTURESCALE/t->ys;
167
bool first = striptype!=STRIP_FLOOR || x!=ox+size || striptex!=wtex || h!=oh || y!=oy;
169
if(first) // start strip here
172
firstindex = verts.length();
176
striptype = STRIP_FLOOR;
179
vert(x, y, h, l1, xo, yo);
180
vert(x, y+size, h, l2, xo, yo+ys);
184
vert(x, y+size, h, l2, xo, yo+ys);
185
vert(x, y, h, l1, xo, yo);
194
else // continue strip
196
int lighterr = lighterror*2;
197
if((abs(ol1r-l3->r)<lighterr && abs(ol2r-l4->r)<lighterr // skip vertices if light values are close enough
198
&& abs(ol1g-l3->g)<lighterr && abs(ol2g-l4->g)<lighterr
199
&& abs(ol1b-l3->b)<lighterr && abs(ol2b-l4->b)<lighterr) || !wtex)
201
verts.setsizenodelete(verts.length()-2);
206
uchar *p1 = (uchar *)(&verts[verts.length()-1].r);
210
uchar *p2 = (uchar *)(&verts[verts.length()-2].r);
219
vert(x+size, y, h, l4, xo+xs, yo);
220
vert(x+size, y+size, h, l3, xo+xs, yo+ys);
224
vert(x+size, y+size, h, l3, xo+xs, yo+ys);
225
vert(x+size, y, h, l4, xo+xs, yo);
232
void render_flatdelta(int wtex, int x, int y, int size, float h1, float h4, float h3, float h2, sqr *l1, sqr *l4, sqr *l3, sqr *l2, bool isceil) // floor/ceil quads on a slope
234
if(showm) { l3 = l1 = &sbright; l4 = l2 = &sdark; }
236
Texture *t = lookupworldtexture(wtex);
237
float xf = TEXTURESCALE/t->xs;
238
float yf = TEXTURESCALE/t->ys;
244
bool first = striptype!=STRIP_DELTA || x!=ox+size || striptex!=wtex || y!=oy;
249
firstindex = verts.length();
252
striptype = STRIP_DELTA;
255
vert(x, y, h1, l1, xo, yo);
256
vert(x, y+size, h2, l2, xo, yo+ys);
260
vert(x, y+size, h2, l2, xo, yo+ys);
261
vert(x, y, h1, l1, xo, yo);
267
vert(x+size, y, h4, l4, xo+xs, yo);
268
vert(x+size, y+size, h3, l3, xo+xs, yo+ys);
272
vert(x+size, y+size, h3, l3, xo+xs, yo+ys);
273
vert(x+size, y, h4, l4, xo+xs, yo);
280
void render_2tris(sqr *h, sqr *s, int x1, int y1, int x2, int y2, int x3, int y3, sqr *l1, sqr *l2, sqr *l3) // floor/ceil tris on a corner cube
284
Texture *t = lookupworldtexture(h->ftex);
285
float xf = TEXTURESCALE/t->xs;
286
float yf = TEXTURESCALE/t->ys;
287
vert(x1, y1, h->floor, l1, xf*x1, yf*y1);
288
vert(x2, y2, h->floor, l2, xf*x2, yf*y2);
289
vert(x3, y3, h->floor, l3, xf*x3, yf*y3);
290
addstrip(mergestrips ? GL_TRIANGLES : GL_TRIANGLE_STRIP, h->ftex, verts.length()-3, 3);
292
t = lookupworldtexture(h->ctex);
293
xf = TEXTURESCALE/t->xs;
294
yf = TEXTURESCALE/t->ys;
296
vert(x3, y3, h->ceil, l3, xf*x3, yf*y3);
297
vert(x2, y2, h->ceil, l2, xf*x2, yf*y2);
298
vert(x1, y1, h->ceil, l1, xf*x1, yf*y1);
299
addstrip(mergestrips ? GL_TRIANGLES : GL_TRIANGLE_STRIP, h->ctex, verts.length()-3, 3);
303
void render_tris(int x, int y, int size, bool topleft,
304
sqr *h1, sqr *h2, sqr *s, sqr *t, sqr *u, sqr *v)
308
if(h1) render_2tris(h1, s, x+size, y+size, x, y+size, x, y, u, v, s);
309
if(h2) render_2tris(h2, s, x, y, x+size, y, x+size, y+size, s, t, v);
313
if(h1) render_2tris(h1, s, x, y, x+size, y, x, y+size, s, t, u);
314
if(h2) render_2tris(h2, s, x+size, y, x+size, y+size, x, y+size, t, u, v);
318
void render_square(int wtex, float floor1, float floor2, float ceil1, float ceil2, int x1, int y1, int x2, int y2, int size, sqr *l1, sqr *l2, bool flip, int dir) // wall quads
320
if(showm) { l1 = &sbright; l2 = &sdark; }
322
Texture *t = lookupworldtexture(wtex);
323
float xf = TEXTURESCALE/t->xs;
324
float yf = -TEXTURESCALE/t->ys;
326
float xo = xf*(x1==x2 ? min(y1,y2) : min(x1,x2));
328
bool first = striptype!=STRIP_WALL || striptex!=wtex || ox!=x1 || oy!=y1 || ofloor!=floor1 || oceil!=ceil1 || odir!=dir,
329
hf = floor1!=floor2 || ceil1!=ceil2;
334
firstindex = verts.length();
336
striptype = STRIP_WALL;
340
vert(x1, y1, ceil1, l1, xo, yf*ceil1);
341
vert(x1, y1, floor1, l1, xo, yf*floor1);
345
vert(x1, y1, floor1, l1, xo, yf*floor1);
346
vert(x1, y1, ceil1, l1, xo, yf*ceil1);
352
else // continue strip
354
int lighterr = lighterror*2;
356
&& ((abs(ol1r-l2->r)<lighterr && abs(ol1g-l2->g)<lighterr && abs(ol1b-l2->b)<lighterr) || !wtex)) // skip vertices if light values are close enough
358
verts.setsizenodelete(verts.length()-2);
363
uchar *p1 = (uchar *)(&verts[verts.length()-1].r);
372
vert(x2, y2, ceil2, l2, xo+xs, yf*ceil2);
373
vert(x2, y2, floor2, l2, xo+xs, yf*floor2);
377
vert(x2, y2, floor2, l2, xo+xs, yf*floor2);
378
vert(x2, y2, ceil2, l2, xo+xs, yf*ceil2);
392
verts.setsizenodelete(0);
397
sbright.r = sbright.g = sbright.b = 255;
398
sdark.r = sdark.g = sdark.b = 0;
403
struct shadowvertex { float u, v, x, y, z; };
404
vector<shadowvertex> shadowverts;
406
static void resetshadowverts()
408
shadowverts.setsizenodelete(0);
413
static void rendershadowstrips()
415
glEnableClientState(GL_VERTEX_ARRAY);
416
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
418
shadowvertex *buf = shadowverts.getbuf();
419
glVertexPointer(3, GL_FLOAT, sizeof(shadowvertex), &buf->x);
420
glTexCoordPointer(2, GL_FLOAT, sizeof(shadowvertex), &buf->u);
424
stripbatch &sb = stripbatches[j];
425
RENDERSTRIPS(sb.tris, GL_TRIANGLES);
426
RENDERSTRIPS(sb.tristrips, GL_TRIANGLE_STRIP);
427
RENDERSTRIPS(sb.quads, GL_QUADS);
431
glDisableClientState(GL_VERTEX_ARRAY);
432
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
434
xtraverts += shadowverts.length();
437
#define shadowvert(v1, v2, v3) { \
438
shadowvertex &v = shadowverts.add(); \
439
v.x = (float)(v1); v.y = (float)(v2); v.z = (float)(v3); \
442
void rendershadow_tri(sqr *h, int x1, int y1, int x2, int y2, int x3, int y3) // floor tris on a corner cube
444
stripend(shadowverts);
446
shadowvert(x1, y1, h->floor);
447
shadowvert(x2, y2, h->floor);
448
shadowvert(x3, y3, h->floor);
449
addstrip(mergestrips ? GL_TRIANGLES : GL_TRIANGLE_STRIP, DEFAULT_FLOOR, shadowverts.length()-3, 3);
452
void rendershadow_tris(int x, int y, bool topleft, sqr *h1, sqr *h2)
456
if(h1) rendershadow_tri(h1, x+1, y+1, x, y+1, x, y);
457
if(h2) rendershadow_tri(h2, x, y, x+1, y, x+1, y+1);
461
if(h1) rendershadow_tri(h1, x, y, x+1, y, x, y+1);
462
if(h2) rendershadow_tri(h2, x+1, y, x+1, y+1, x, y+1);
466
static void rendershadow_flat(int x, int y, int h) // floor quads
468
bool first = striptype!=STRIP_FLOOR || x!=ox+1 || h!=oh || y!=oy;
470
if(first) // start strip here
472
stripend(shadowverts);
473
firstindex = shadowverts.length();
474
striptex = DEFAULT_FLOOR;
477
striptype = STRIP_FLOOR;
478
shadowvert(x, y+1, h);
481
else // continue strip
483
shadowverts.setsizenodelete(shadowverts.length()-2);
486
shadowvert(x+1, y+1, h);
487
shadowvert(x+1, y, h);
492
static void rendershadow_flatdelta(int x, int y, float h1, float h4, float h3, float h2) // floor quads on a slope
494
bool first = striptype!=STRIP_DELTA || x!=ox+1 || y!=oy;
498
stripend(shadowverts);
499
firstindex = shadowverts.length();
500
striptex = DEFAULT_FLOOR;
502
striptype = STRIP_DELTA;
503
shadowvert(x, y+1, h2);
504
shadowvert(x, y, h1);
507
shadowvert(x+1, y+1, h3);
508
shadowvert(x+1, y, h4);
513
void rendershadow(int x, int y, int xs, int ys, const vec &texgenS, const vec &texgenT)
517
xs = min(xs, ssize-1);
518
ys = min(ys, ssize-1);
522
#define df(x) s->floor-(x->vdelta/4.0f)
525
for(int yy = y; yy<ys; yy++) for(int xx = x; xx<xs; xx++)
527
sqr *s = SW(w,xx,yy);
528
if(s->type==SPACE || s->type==CHF)
530
rendershadow_flat(xx, yy, s->floor);
532
else if(s->type==FHF)
534
sqr *t = SW(s,1,0), *u = SW(s,1,1), *v = SW(s,0,1);
535
rendershadow_flatdelta(xx, yy, df(s), df(t), df(u), df(v));
537
else if(s->type==CORNER)
539
sqr *t = SW(s,1,0), *v = SW(s,0,1), *w = SW(s,0,-1), *z = SW(s,-1,0);
541
sqr *h1 = NULL, *h2 = NULL;
544
if(SOLID(w)) { h2 = s; topleft = false; }
545
else if(SOLID(v)) { h2 = s; }
549
if(SOLID(w)) { h1 = s; }
550
else if(SOLID(v)) { h1 = s; topleft = false; }
554
bool wv = w->ceil-w->floor < v->ceil-v->floor;
555
if(z->ceil-z->floor < t->ceil-t->floor)
557
if(wv) { h1 = s; h2 = v; topleft = false; }
558
else { h1 = s; h2 = w; }
562
if(wv) { h2 = s; h1 = v; }
563
else { h2 = s; h1 = w; topleft = false; }
566
rendershadow_tris(xx, yy, topleft, h1, h2);
570
stripend(shadowverts);
572
for(shadowvertex *v = shadowverts.getbuf(), *end = &v[shadowverts.length()]; v < end; v++)
574
float vx = v->x, vy = v->y;
575
v->u = vx*texgenS.x + vy*texgenS.y + texgenS.z;
576
v->v = vx*texgenT.x + vy*texgenT.y + texgenT.z;
579
rendershadowstrips();