4 VARFP(waterreflect
, 0, 1, 1, cleanreflections());
5 VARFP(waterrefract
, 0, 1, 1, cleanreflections());
6 VARP(refractfog
, 0, 1, 1);
9 VARP(watersubdiv
, 0, 2, 3);
10 VARP(waterlod
, 0, 1, 3);
12 static int wx1
, wy1
, wx2
, wy2
, wsize
;
15 #define VERTW(vertw, body) \
16 inline void vertw(float v1, float v2, float v3, float t) \
18 float angle = (v1-wx1)/wsize*(v2-wy1)/wsize*(v1-wx2)*(v2-wy2)*59/23+t; \
19 float s = sinf(angle), h = WATER_AMPLITUDE*s-WATER_OFFSET; \
21 glVertex3f(v1, v2, v3+h); \
23 #define VERTWN(vertw, body) \
24 inline void vertw(float v1, float v2, float v3) \
26 float h = -WATER_OFFSET; \
28 glVertex3f(v1, v2, v3+h); \
30 #define VERTWT(vertwt, body) VERTW(vertwt, { float v = cosf(angle); float duv = 0.5f*v; body; })
32 glTexCoord2f(v1
/8.0f
, v2
/8.0f
);
35 glTexCoord2f(v1
/8.0f
, v2
/8.0f
);
38 glColor4f(wcol
[0], wcol
[1], wcol
[2], wcol
[3] + fabs(s
)*0.1f
);
41 glColor4f(wcol
[0], wcol
[1], wcol
[2], wcol
[3]);
44 glColor4f(1, 1, 1, 0.2f
+ fabs(s
)*0.1f
);
45 glTexCoord3f(v1
+duv
, v2
+duv
, v3
+h
);
48 glColor4f(1, 1, 1, 0.2f
);
49 glTexCoord3f(v1
, v2
, v3
+h
);
52 glColor4f(1, 1, 1, 0.2f
+ fabs(s
)*0.1f
);
53 glMultiTexCoord3f_(GL_TEXTURE0_ARB
, v1
-duv
, v2
+duv
, v3
+h
);
54 glMultiTexCoord3f_(GL_TEXTURE1_ARB
, v1
+duv
, v2
+duv
, v3
+h
);
57 glColor4f(1, 1, 1, 0.2f
);
58 glMultiTexCoord3f_(GL_TEXTURE0_ARB
, v1
, v2
, v3
+h
);
59 glMultiTexCoord3f_(GL_TEXTURE1_ARB
, v1
, v2
, v3
+h
);
62 static float lavaxk
= 1.0f
, lavayk
= 1.0f
, lavascroll
= 0.0f
;
65 glTexCoord2f(lavaxk
*(v1
+lavascroll
), lavayk
*(v2
+lavascroll
));
68 glTexCoord2f(lavaxk
*(v1
+lavascroll
), lavayk
*(v2
+lavascroll
));
71 #define renderwaterstrips(vertw, z, t) \
72 for(int x = wx1; x<wx2; x += subdiv) \
74 glBegin(GL_TRIANGLE_STRIP); \
75 vertw(x, wy1, z, t); \
76 vertw(x+subdiv, wy1, z, t); \
77 for(int y = wy1; y<wy2; y += subdiv) \
79 vertw(x, y+subdiv, z, t); \
80 vertw(x+subdiv, y+subdiv, z, t); \
83 int n = (wy2-wy1-1)/subdiv; \
88 void rendervertwater(uint subdiv
, int xo
, int yo
, int z
, uint size
, uchar mat
= MAT_WATER
)
96 ASSERT((wx1
& (subdiv
- 1)) == 0);
97 ASSERT((wy1
& (subdiv
- 1)) == 0);
103 float t
= lastmillis
/(renderpath
!=R_FIXEDFUNCTION
? 600.0f
: 300.0f
);
104 if(renderpath
!=R_FIXEDFUNCTION
) { renderwaterstrips(vertwt
, z
, t
); }
105 else if(nowater
|| (!waterrefract
&& !waterreflect
)) { renderwaterstrips(vertwc
, z
, t
); }
106 else if(waterrefract
) { renderwaterstrips(vertwmtc
, z
, t
); }
107 else { renderwaterstrips(vertwtc
, z
, t
); }
113 float t
= lastmillis
/2000.0f
;
114 renderwaterstrips(vertl
, z
, t
);
120 uint
calcwatersubdiv(int x
, int y
, int z
, uint size
)
123 if(camera1
->o
.x
>= x
&& camera1
->o
.x
< x
+ size
&&
124 camera1
->o
.y
>= y
&& camera1
->o
.y
< y
+ size
)
125 dist
= fabs(camera1
->o
.z
- float(z
));
128 vec
t(x
+ size
/2, y
+ size
/2, z
+ size
/2);
129 dist
= t
.dist(camera1
->o
) - size
*1.42f
/2;
131 uint subdiv
= watersubdiv
+ int(dist
) / (32 << waterlod
);
132 if(subdiv
>= 8*sizeof(subdiv
))
135 subdiv
= 1 << subdiv
;
139 uint
renderwaterlod(int x
, int y
, int z
, uint size
, uchar mat
= MAT_WATER
)
141 if(size
<= (uint
)(32 << waterlod
))
143 uint subdiv
= calcwatersubdiv(x
, y
, z
, size
);
144 if(subdiv
< size
* 2) rendervertwater(min(subdiv
, size
), x
, y
, z
, size
, mat
);
149 uint subdiv
= calcwatersubdiv(x
, y
, z
, size
);
152 if(subdiv
< size
* 2) rendervertwater(size
, x
, y
, z
, size
, mat
);
155 uint childsize
= size
/ 2,
156 subdiv1
= renderwaterlod(x
, y
, z
, childsize
, mat
),
157 subdiv2
= renderwaterlod(x
+ childsize
, y
, z
, childsize
, mat
),
158 subdiv3
= renderwaterlod(x
+ childsize
, y
+ childsize
, z
, childsize
, mat
),
159 subdiv4
= renderwaterlod(x
, y
+ childsize
, z
, childsize
, mat
),
161 minsubdiv
= min(minsubdiv
, subdiv2
);
162 minsubdiv
= min(minsubdiv
, subdiv3
);
163 minsubdiv
= min(minsubdiv
, subdiv4
);
164 if(minsubdiv
< size
* 2)
166 if(minsubdiv
>= size
) rendervertwater(size
, x
, y
, z
, size
, mat
);
169 if(subdiv1
>= size
) rendervertwater(childsize
, x
, y
, z
, childsize
, mat
);
170 if(subdiv2
>= size
) rendervertwater(childsize
, x
+ childsize
, y
, z
, childsize
, mat
);
171 if(subdiv3
>= size
) rendervertwater(childsize
, x
+ childsize
, y
+ childsize
, z
, childsize
, mat
);
172 if(subdiv4
>= size
) rendervertwater(childsize
, x
, y
+ childsize
, z
, childsize
, mat
);
179 #define renderwaterquad(vertwn, z) \
182 vertwn(x+rsize, y, z); \
183 vertwn(x+rsize, y+csize, z); \
184 vertwn(x, y+csize, z); \
188 void renderflatwater(int x
, int y
, int z
, uint rsize
, uint csize
, uchar mat
= MAT_WATER
)
193 if(renderpath
!=R_FIXEDFUNCTION
) { renderwaterquad(vertwtn
, z
); }
194 else if(nowater
|| (!waterrefract
&& !waterreflect
)) { renderwaterquad(vertwcn
, z
); }
195 else if(waterrefract
) { renderwaterquad(vertwmtcn
, z
); }
196 else { renderwaterquad(vertwtcn
, z
); }
200 renderwaterquad(vertln
, z
);
205 VARFP(vertwater
, 0, 1, 1, allchanged());
207 void renderlava(materialsurface
&m
, Texture
*tex
, float scale
)
209 lavaxk
= 8.0f
/(tex
->xs
*scale
);
210 lavayk
= 8.0f
/(tex
->ys
*scale
);
211 lavascroll
= lastmillis
/1000.0f
;
214 if(renderwaterlod(m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.csize
, MAT_LAVA
) >= (uint
)m
.csize
* 2)
215 rendervertwater(m
.csize
, m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.csize
, MAT_LAVA
);
217 else renderflatwater(m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.rsize
, m
.csize
, MAT_LAVA
);
220 /* reflective/refractive water */
222 #define MAXREFLECTIONS 16
226 GLuint fb
, refractfb
;
227 GLuint tex
, refracttex
;
228 int height
, lastupdate
, lastused
;
231 vector
<materialsurface
*> matsurfs
;
233 Reflection() : fb(0), refractfb(0), height(-1), lastused(0), query(NULL
)
236 Reflection
*findreflection(int height
);
238 VARP(reflectdist
, 0, 2000, 10000);
239 VAR(waterfog
, 0, 150, 10000);
241 void getwatercolour(uchar
*wcol
)
243 static const uchar defaultwcol
[3] = { 20, 70, 80};
244 if(hdr
.watercolour
[0] || hdr
.watercolour
[1] || hdr
.watercolour
[2]) memcpy(wcol
, hdr
.watercolour
, 3);
245 else memcpy(wcol
, defaultwcol
, 3);
248 void watercolour(int *r
, int *g
, int *b
)
250 hdr
.watercolour
[0] = *r
;
251 hdr
.watercolour
[1] = *g
;
252 hdr
.watercolour
[2] = *b
;
255 COMMAND(watercolour
, "iii");
257 VAR(lavafog
, 0, 50, 10000);
259 void getlavacolour(uchar
*lcol
)
261 static const uchar defaultlcol
[3] = { 255, 64, 0 };
262 if(hdr
.lavacolour
[0] || hdr
.lavacolour
[1] || hdr
.lavacolour
[2]) memcpy(lcol
, hdr
.lavacolour
, 3);
263 else memcpy(lcol
, defaultlcol
, 3);
266 void lavacolour(int *r
, int *g
, int *b
)
268 hdr
.lavacolour
[0] = *r
;
269 hdr
.lavacolour
[1] = *g
;
270 hdr
.lavacolour
[2] = *b
;
273 COMMAND(lavacolour
, "iii");
275 Shader
*watershader
= NULL
, *waterreflectshader
= NULL
, *waterrefractshader
= NULL
, *waterfadeshader
= NULL
;
277 void setprojtexmatrix(Reflection
&ref
, bool init
= true)
279 if(init
&& ref
.lastupdate
==totalmillis
)
281 GLfloat pm
[16], mm
[16];
282 glGetFloatv(GL_PROJECTION_MATRIX
, pm
);
283 glGetFloatv(GL_MODELVIEW_MATRIX
, mm
);
286 glTranslatef(0.5f
, 0.5f
, 0);
287 glScalef(0.5f
, 0.5f
, 1);
291 glGetFloatv(GL_TEXTURE_MATRIX
, ref
.tm
);
293 else glLoadMatrixf(ref
.tm
);
296 void setuprefractTMUs()
298 if(!refractfog
) setuptmu(0, "K , T @ Ka");
300 glActiveTexture_(GL_TEXTURE1_ARB
);
301 glEnable(GL_TEXTURE_2D
);
303 setuptmu(1, "P , T @ C~a");
305 glActiveTexture_(GL_TEXTURE0_ARB
);
308 void setupreflectTMUs()
310 setuptmu(0, "T , K @ Ca", "Ka * P~a");
312 glDepthMask(GL_FALSE
);
314 glBlendFunc(GL_ONE
, GL_SRC_ALPHA
);
317 void cleanupwaterTMUs(bool refract
)
323 glActiveTexture_(GL_TEXTURE1_ARB
);
326 glDisable(GL_TEXTURE_2D
);
327 glActiveTexture_(GL_TEXTURE0_ARB
);
332 glDepthMask(GL_TRUE
);
336 VAR(waterspec
, 0, 150, 1000);
338 Reflection reflections
[MAXREFLECTIONS
];
339 GLuint reflectiondb
= 0;
341 VAR(oqwater
, 0, 1, 1);
347 glDisable(GL_CULL_FACE
);
349 if(!nowater
&& (waterreflect
|| waterrefract
))
351 if(waterrefract
) setuprefractTMUs();
352 else setupreflectTMUs();
354 glMatrixMode(GL_TEXTURE
);
358 glDisable(GL_TEXTURE_2D
);
359 glDepthMask(GL_FALSE
);
361 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
365 float offset
= -WATER_OFFSET
;
368 getwatercolour(wcolub
);
369 loopi(3) wcol
[i
] = wcolub
[i
]/255.0f
;
372 loopi(MAXREFLECTIONS
)
374 Reflection
&ref
= reflections
[i
];
375 if(ref
.height
<0 || ref
.lastused
<totalmillis
|| ref
.matsurfs
.empty()) continue;
377 if(!nowater
&& (waterreflect
|| waterrefract
))
379 if(hasOQ
&& oqfrags
&& oqwater
&& ref
.query
&& ref
.query
->owner
==&ref
&& checkquery(ref
.query
)) continue;
380 if(waterrefract
) glActiveTexture_(GL_TEXTURE1_ARB
);
381 glBindTexture(GL_TEXTURE_2D
, ref
.tex
);
382 setprojtexmatrix(ref
);
386 glActiveTexture_(GL_TEXTURE0_ARB
);
387 glBindTexture(GL_TEXTURE_2D
, camera1
->o
.z
>=ref
.height
+offset
? ref
.refracttex
: ref
.tex
);
388 setprojtexmatrix(ref
, !waterreflect
);
392 if(camera1
->o
.z
< ref
.height
+offset
) { if(blended
) { glDepthMask(GL_TRUE
); glDisable(GL_BLEND
); blended
= false; } }
393 else if(!blended
) { glDepthMask(GL_FALSE
); glEnable(GL_BLEND
); blended
= true; }
399 materialsurface
&m
= *ref
.matsurfs
[j
];
401 if(m
.depth
!=lastdepth
)
403 float depth
= !waterfog
? 1.0f
: min(0.75f
*m
.depth
/waterfog
, 0.95f
);
404 if(nowater
|| !waterrefract
) depth
= max(depth
, nowater
|| !waterreflect
? 0.6f
: 0.3f
);
406 if(!nowater
&& (waterreflect
|| waterrefract
))
408 if(begin
) { glEnd(); begin
= false; }
409 float ec
[4] = { wcol
[0], wcol
[1], wcol
[2], depth
};
410 if(!waterrefract
) { loopk(3) ec
[k
] *= depth
; ec
[3] = 1-ec
[3]; }
411 colortmu(0, ec
[0], ec
[1], ec
[2], ec
[3]);
418 if(!begin
) { glBegin(GL_QUADS
); begin
= true; }
419 renderflatwater(m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.rsize
, m
.csize
);
421 else if(renderwaterlod(m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.csize
) >= (uint
)m
.csize
* 2)
422 rendervertwater(m
.csize
, m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.csize
);
427 if(!nowater
&& (waterreflect
|| waterrefract
))
429 cleanupwaterTMUs(waterrefract
!=0);
431 glMatrixMode(GL_MODELVIEW
);
435 glEnable(GL_TEXTURE_2D
);
436 glDepthMask(GL_TRUE
);
440 glEnable(GL_CULL_FACE
);
443 VARFP(waterfade
, 0, 1, 1, cleanreflections());
447 if(editmode
&& showmat
) return;
450 if(renderpath
==R_FIXEDFUNCTION
) { renderwaterff(); return; }
452 glDisable(GL_CULL_FACE
);
454 uchar wcol
[3] = { 20, 70, 80 };
455 if(hdr
.watercolour
[0] || hdr
.watercolour
[1] || hdr
.watercolour
[2]) memcpy(wcol
, hdr
.watercolour
, 3);
458 Slot
&s
= lookuptexture(-MAT_WATER
);
460 glActiveTexture_(GL_TEXTURE1_ARB
);
461 glEnable(GL_TEXTURE_2D
);
462 glBindTexture(GL_TEXTURE_2D
, s
.sts
[2].t
->gl
);
463 glActiveTexture_(GL_TEXTURE2_ARB
);
464 glEnable(GL_TEXTURE_2D
);
465 glBindTexture(GL_TEXTURE_2D
, s
.sts
[3].t
->gl
);
468 glActiveTexture_(GL_TEXTURE3_ARB
);
469 glEnable(GL_TEXTURE_2D
);
470 if(hasFBO
&& renderpath
!=R_FIXEDFUNCTION
&& waterfade
)
473 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
478 glDepthMask(GL_FALSE
);
480 glBlendFunc(GL_ONE
, GL_SRC_ALPHA
);
482 glActiveTexture_(GL_TEXTURE0_ARB
);
484 setenvparamf("camera", SHPARAM_VERTEX
, 0, camera1
->o
.x
, camera1
->o
.y
, camera1
->o
.z
);
485 setenvparamf("millis", SHPARAM_VERTEX
, 1, lastmillis
/1000.0f
, lastmillis
/1000.0f
, lastmillis
/1000.0f
);
487 if(!watershader
) watershader
= lookupshaderbyname("water");
488 if(!waterreflectshader
) waterreflectshader
= lookupshaderbyname("waterreflect");
489 if(!waterrefractshader
) waterrefractshader
= lookupshaderbyname("waterrefract");
490 if(!waterfadeshader
) waterfadeshader
= lookupshaderbyname("waterfade");
492 (waterrefract
? (waterfade
&& hasFBO
? waterfadeshader
: waterrefractshader
) : (waterreflect
? waterreflectshader
: watershader
))->set();
494 if(waterreflect
|| waterrefract
) glMatrixMode(GL_TEXTURE
);
497 glGetFloatv(GL_FOG_COLOR
, oldfogc
);
498 vec
ambient(max(hdr
.skylight
[0], hdr
.ambient
), max(hdr
.skylight
[1], hdr
.ambient
), max(hdr
.skylight
[2], hdr
.ambient
));
499 entity
*lastlight
= (entity
*)-1;
501 float offset
= -WATER_OFFSET
;
503 loopi(MAXREFLECTIONS
)
505 Reflection
&ref
= reflections
[i
];
506 if(ref
.height
<0 || ref
.lastused
<totalmillis
|| ref
.matsurfs
.empty()) continue;
508 if(waterreflect
|| waterrefract
)
510 if(hasOQ
&& oqfrags
&& oqwater
&& ref
.query
&& ref
.query
->owner
==&ref
&& checkquery(ref
.query
)) continue;
511 glBindTexture(GL_TEXTURE_2D
, ref
.tex
);
512 setprojtexmatrix(ref
);
517 glActiveTexture_(GL_TEXTURE3_ARB
);
518 glBindTexture(GL_TEXTURE_2D
, camera1
->o
.z
>=ref
.height
+offset
? ref
.refracttex
: ref
.tex
);
519 glActiveTexture_(GL_TEXTURE0_ARB
);
520 if(waterfade
) setlocalparamf("waterheight", SHPARAM_VERTEX
, 7, ref
.height
+offset
+2, ref
.height
+offset
+2, ref
.height
+offset
+2);
522 else if(waterreflect
)
524 GLfloat fogc
[4] = { 0, 0, 0, 1 };
525 if(camera1
->o
.z
< ref
.height
+offset
)
527 if(blended
) { glDepthMask(GL_TRUE
); glDisable(GL_BLEND
); blended
= false; }
528 loopk(3) fogc
[k
] = oldfogc
[k
];
530 else if(!blended
) { glDepthMask(GL_FALSE
); glEnable(GL_BLEND
); blended
= true; }
531 setlocalparamfv("rgbafog", SHPARAM_PIXEL
, 6, fogc
);
537 materialsurface
&m
= *ref
.matsurfs
[j
];
539 entity
*light
= (m
.light
&& m
.light
->type
==ET_LIGHT
? m
.light
: NULL
);
542 if(begin
) { glEnd(); begin
= false; }
543 const vec
&lightpos
= light
? light
->o
: vec(hdr
.worldsize
/2, hdr
.worldsize
/2, hdr
.worldsize
);
544 float lightrad
= light
&& light
->attr1
? light
->attr1
: hdr
.worldsize
*8.0f
;
545 const vec
&lightcol
= (light
? vec(light
->attr2
, light
->attr3
, light
->attr4
) : vec(ambient
)).div(255.0f
).mul(waterspec
/100.0f
);
546 setlocalparamf("lightpos", SHPARAM_VERTEX
, 2, lightpos
.x
, lightpos
.y
, lightpos
.z
);
547 setlocalparamf("lightcolor", SHPARAM_PIXEL
, 3, lightcol
.x
, lightcol
.y
, lightcol
.z
);
548 setlocalparamf("lightradius", SHPARAM_PIXEL
, 4, lightrad
, lightrad
, lightrad
);
552 if(!waterrefract
&& m
.depth
!=lastdepth
)
554 if(begin
) { glEnd(); begin
= false; }
555 float depth
= !waterfog
? 1.0f
: min(0.75f
*m
.depth
/waterfog
, 0.95f
);
556 depth
= max(depth
, waterreflect
? 0.3f
: 0.6f
);
557 setlocalparamf("depth", SHPARAM_PIXEL
, 5, depth
, 1.0f
-depth
);
563 if(!begin
) { glBegin(GL_QUADS
); begin
= true; }
564 renderflatwater(m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.rsize
, m
.csize
);
566 else if(renderwaterlod(m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.csize
) >= (uint
)m
.csize
* 2)
567 rendervertwater(m
.csize
, m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.csize
);
572 if(waterreflect
|| waterrefract
)
575 glMatrixMode(GL_MODELVIEW
);
580 glActiveTexture_(GL_TEXTURE3_ARB
);
581 glDisable(GL_TEXTURE_2D
);
582 if(hasFBO
&& renderpath
!=R_FIXEDFUNCTION
&& waterfade
) glDisable(GL_BLEND
);
586 glDepthMask(GL_TRUE
);
592 glActiveTexture_(GL_TEXTURE1_ARB
+i
);
593 glDisable(GL_TEXTURE_2D
);
595 glActiveTexture_(GL_TEXTURE0_ARB
);
597 glEnable(GL_CULL_FACE
);
600 Reflection
*findreflection(int height
)
602 loopi(MAXREFLECTIONS
)
604 if(reflections
[i
].height
==height
) return &reflections
[i
];
609 void cleanreflections()
611 loopi(MAXREFLECTIONS
)
613 Reflection
&ref
= reflections
[i
];
616 glDeleteFramebuffers_(1, &ref
.fb
);
621 glDeleteTextures(1, &ref
.tex
);
628 glDeleteFramebuffers_(1, &ref
.refractfb
);
633 glDeleteTextures(1, &ref
.refracttex
);
639 glDeleteRenderbuffers_(1, &reflectiondb
);
644 VARFP(reflectsize
, 6, 8, 10, cleanreflections());
646 void invalidatereflections()
649 loopi(MAXREFLECTIONS
) reflections
[i
].matsurfs
.setsizenodelete(0);
652 void addreflection(materialsurface
&m
)
655 Reflection
*ref
= NULL
, *oldest
= NULL
;
656 loopi(MAXREFLECTIONS
)
658 Reflection
&r
= reflections
[i
];
663 else if(r
.height
==height
)
666 if(r
.lastused
==totalmillis
) return;
670 else if(!oldest
|| r
.lastused
<oldest
->lastused
) oldest
= &r
;
674 if(!oldest
|| oldest
->lastused
==totalmillis
) return;
677 if(ref
->height
!=height
) ref
->height
= height
;
679 ref
->lastused
= totalmillis
;
680 ref
->matsurfs
.setsizenodelete(0);
681 ref
->matsurfs
.add(&m
);
684 static const GLenum colorfmts
[] = { GL_RGBA
, GL_RGBA8
, GL_RGB
, GL_RGB8
, GL_FALSE
},
685 depthfmts
[] = { GL_DEPTH_STENCIL_EXT
, GL_DEPTH24_STENCIL8_EXT
, GL_DEPTH_COMPONENT24
, GL_DEPTH_COMPONENT
, GL_DEPTH_COMPONENT16
, GL_DEPTH_COMPONENT32
, GL_FALSE
};
686 const int stencilfmts
= 2;
687 static GLenum reflectfmt
= GL_FALSE
, refractfmt
= GL_FALSE
, depthfmt
= GL_FALSE
, stencilfmt
= GL_FALSE
;
689 int size
= 1<<reflectsize
;
690 if(!hasFBO
) while(size
>screen
->w
|| size
>screen
->h
) size
/= 2;
691 while(size
>hwtexsize
) size
/= 2;
692 if((waterreflect
|| waterrefract
) && !ref
->tex
)
694 glGenTextures(1, &ref
->tex
);
695 buf
= new char[size
*size
*4];
696 memset(buf
, 0, size
*size
*4);
700 if(!ref
->fb
) glGenFramebuffers_(1, &ref
->fb
);
701 glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, ref
->fb
);
705 createtexture(ref
->tex
, size
, size
, buf
, 3, false, reflectfmt
? reflectfmt
: colorfmts
[find
]);
709 glFramebufferTexture2D_(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
, GL_TEXTURE_2D
, ref
->tex
, 0);
710 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER_EXT
)==GL_FRAMEBUFFER_COMPLETE_EXT
) break;
713 while(!reflectfmt
&& colorfmts
[++find
]);
714 if(!reflectfmt
) reflectfmt
= colorfmts
[find
];
718 if(!reflectiondb
) { glGenRenderbuffers_(1, &reflectiondb
); depthfmt
= stencilfmt
= GL_FALSE
; }
719 if(!depthfmt
) glBindRenderbuffer_(GL_RENDERBUFFER_EXT
, reflectiondb
);
720 find
= hasstencil
&& hasDS
? 0 : stencilfmts
;
723 if(!depthfmt
) glRenderbufferStorage_(GL_RENDERBUFFER_EXT
, depthfmts
[find
], size
, size
);
724 glFramebufferRenderbuffer_(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, reflectiondb
);
725 if(depthfmt
? stencilfmt
: find
<stencilfmts
) glFramebufferRenderbuffer_(GL_FRAMEBUFFER_EXT
, GL_STENCIL_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, reflectiondb
);
726 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER_EXT
)==GL_FRAMEBUFFER_COMPLETE_EXT
) break;
728 while(!depthfmt
&& depthfmts
[++find
]);
731 glBindRenderbuffer_(GL_RENDERBUFFER_EXT
, 0);
732 depthfmt
= depthfmts
[find
];
733 stencilfmt
= find
<stencilfmts
? depthfmt
: GL_FALSE
;
736 glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, 0);
739 if(waterrefract
&& !ref
->refracttex
)
741 glGenTextures(1, &ref
->refracttex
);
743 int find
= hasFBO
&& renderpath
!=R_FIXEDFUNCTION
&& waterrefract
&& waterfade
? 0 : 2;
746 if(!ref
->refractfb
) glGenFramebuffers_(1, &ref
->refractfb
);
747 glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, ref
->refractfb
);
751 createtexture(ref
->refracttex
, size
, size
, buf
, 3, false, refractfmt
? refractfmt
: colorfmts
[find
]);
755 glFramebufferTexture2D_(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
, GL_TEXTURE_2D
, ref
->refracttex
, 0);
756 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER_EXT
)==GL_FRAMEBUFFER_COMPLETE_EXT
) break;
759 while(!refractfmt
&& colorfmts
[++find
]);
760 if(!refractfmt
) refractfmt
= colorfmts
[find
];
764 glFramebufferRenderbuffer_(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, reflectiondb
);
765 if(stencilfmt
) glFramebufferRenderbuffer_(GL_FRAMEBUFFER_EXT
, GL_STENCIL_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, reflectiondb
);
766 glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, 0);
769 if(buf
) delete[] buf
;
772 extern vtxarray
*visibleva
;
773 extern void drawreflection(float z
, bool refract
, bool clear
);
777 static int lastquery
= 0;
779 void queryreflections()
783 static int lastsize
= 0, size
= 1<<reflectsize
;
784 if(!hasFBO
) while(size
>screen
->w
|| size
>screen
->h
) size
/= 2;
785 if(size
!=lastsize
) { if(lastsize
) cleanreflections(); lastsize
= size
; }
787 for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
789 lodlevel
&lod
= va
->l0
;
790 if(!lod
.matsurfs
&& va
->occluded
>= OCCLUDE_BB
) continue;
793 materialsurface
&m
= lod
.matbuf
[i
];
794 if(m
.material
==MAT_WATER
&& m
.orient
==O_TOP
) addreflection(m
);
798 lastquery
= totalmillis
;
800 if((editmode
&& showmat
) || !hasOQ
|| !oqfrags
|| !oqwater
|| nowater
|| (!waterreflect
&& !waterrefract
)) return;
802 float offset
= vertwater
? 0.1f
: WATER_OFFSET
;
804 loopi(MAXREFLECTIONS
)
806 Reflection
&ref
= reflections
[i
];
807 if(ref
.height
<0 || ref
.lastused
<totalmillis
|| ref
.matsurfs
.empty())
812 ref
.query
= newquery(&ref
);
813 if(!ref
.query
) continue;
817 nocolorshader
->set();
818 glDepthMask(GL_FALSE
);
819 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
820 glDisable(GL_CULL_FACE
);
823 startquery(ref
.query
);
827 materialsurface
&m
= *ref
.matsurfs
[j
];
828 drawmaterial(m
.orient
, m
.o
.x
, m
.o
.y
, m
.o
.z
, m
.csize
, m
.rsize
, offset
);
836 defaultshader
->set();
837 glDepthMask(GL_TRUE
);
838 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
839 glEnable(GL_CULL_FACE
);
843 VARP(maxreflect
, 1, 1, 8);
845 float reflecting
= 0, refracting
= 0;
847 VAR(maskreflect
, 0, 2, 16);
849 void maskreflection(Reflection
&ref
, float offset
, bool reflect
)
853 glClear(GL_DEPTH_BUFFER_BIT
| (hasstencil
&& hasDS
? GL_STENCIL_BUFFER_BIT
: 0));
857 glClear(GL_DEPTH_BUFFER_BIT
| (hasstencil
&& hasDS
? GL_STENCIL_BUFFER_BIT
: 0));
860 glDepthFunc(GL_ALWAYS
);
861 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
862 glDisable(GL_TEXTURE_2D
);
863 glDisable(GL_CULL_FACE
);
864 nocolorshader
->set();
868 glTranslatef(0, 0, 2*(ref
.height
+offset
));
871 int border
= maskreflect
;
875 materialsurface
&m
= *ref
.matsurfs
[i
];
877 o
[R
[dimension(m
.orient
)]] -= border
;
878 o
[C
[dimension(m
.orient
)]] -= border
;
879 drawmaterial(m
.orient
, o
.x
, o
.y
, o
.z
, m
.csize
+2*border
, m
.rsize
+2*border
, -offset
);
882 if(reflect
) glPopMatrix();
883 defaultshader
->set();
884 glEnable(GL_CULL_FACE
);
885 glEnable(GL_TEXTURE_2D
);
886 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
887 glDepthFunc(GL_LESS
);
891 void drawreflections()
893 if(editmode
&& showmat
) return;
894 if(nowater
|| (!waterreflect
&& !waterrefract
)) return;
896 static int lastdrawn
= 0;
897 int refs
= 0, n
= lastdrawn
;
898 float offset
= -WATER_OFFSET
;
899 loopi(MAXREFLECTIONS
)
901 Reflection
&ref
= reflections
[++n
%MAXREFLECTIONS
];
902 if(ref
.height
<0 || ref
.lastused
<lastquery
|| ref
.matsurfs
.empty()) continue;
903 if(hasOQ
&& oqfrags
&& oqwater
&& ref
.query
&& ref
.query
->owner
==&ref
&& checkquery(ref
.query
)) continue;
905 bool hasbottom
= true;
908 materialsurface
&m
= *ref
.matsurfs
[j
];
909 if(m
.depth
>=10000) hasbottom
= false;
912 int size
= 1<<reflectsize
;
913 if(!hasFBO
) while(size
>screen
->w
|| size
>screen
->h
) size
/= 2;
915 if(!refs
) glViewport(hasFBO
? 0 : screen
->w
-size
, hasFBO
? 0 : screen
->h
-size
, size
, size
);
918 ref
.lastupdate
= totalmillis
;
921 if(waterreflect
&& ref
.tex
)
923 if(ref
.fb
) glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, ref
.fb
);
924 maskreflection(ref
, offset
, camera1
->o
.z
>= ref
.height
+offset
);
925 drawreflection(ref
.height
+offset
, false, false);
928 glBindTexture(GL_TEXTURE_2D
, ref
.tex
);
929 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, screen
->w
-size
, screen
->h
-size
, size
, size
);
933 if(waterrefract
&& ref
.refracttex
&& camera1
->o
.z
>= ref
.height
+offset
)
935 if(ref
.refractfb
) glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, ref
.refractfb
);
936 maskreflection(ref
, offset
, false);
937 drawreflection(ref
.height
+offset
, true, !hasbottom
);
940 glBindTexture(GL_TEXTURE_2D
, ref
.refracttex
);
941 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, screen
->w
-size
, screen
->h
-size
, size
, size
);
945 if(refs
>=maxreflect
) break;
949 glViewport(0, 0, screen
->w
, screen
->h
);
950 if(hasFBO
) glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, 0);
952 defaultshader
->set();