Line data Source code
1 : /**
2 : * @brief alpha geoemtry rendering
3 : *
4 : * Libprimis has support for a single level of alpha geometry, which is rendered
5 : * using a single stencil layer over the base geometry
6 : *
7 : * Combinations of alpha materials (glass, alpha, water) therefore do not stack
8 : * since there is only one stencil and only the nearest layer in the view frustum
9 : * is rendered
10 : *
11 : * All of the methods and variables in this file are part of the GBuffer object.
12 : * See renderlights.h for the declaration of this object.
13 : *
14 : */
15 : #include "../libprimis-headers/cube.h"
16 : #include "../../shared/geomexts.h"
17 : #include "../../shared/glexts.h"
18 :
19 : #include "hdr.h"
20 : #include "rendergl.h"
21 : #include "renderlights.h"
22 : #include "rendermodel.h"
23 : #include "renderparticles.h"
24 : #include "rendertimers.h"
25 : #include "renderva.h"
26 : #include "shader.h"
27 : #include "shaderparam.h"
28 : #include "stain.h"
29 : #include "texture.h"
30 :
31 : #include "world/material.h"
32 : #include "world/octaedit.h"
33 :
34 : FVAR(GBuffer::refractmargin, 0, 0.1f, 1); //margin for gl scissoring around refractive materials
35 : FVAR(GBuffer::refractdepth, 1e-3f, 16, 1e3f); //sets depth for refract shader effect
36 :
37 : //sets up alpha handling as needed then executes main particle rendering routine
38 : //private method of gbuffer
39 0 : void GBuffer::alphaparticles(float allsx1, float allsy1, float allsx2, float allsy2) const
40 : {
41 0 : if(particlelayers && ghasstencil)
42 : {
43 0 : bool scissor = allsx1 > -1 || allsy1 > -1 || allsx2 < 1 || allsy2 < 1;
44 0 : if(scissor)
45 : {
46 0 : int x1 = static_cast<int>(std::floor((allsx1*0.5f+0.5f)*static_cast<float>(vieww))),
47 0 : y1 = static_cast<int>(std::floor((allsy1*0.5f+0.5f)*static_cast<float>(viewh))),
48 0 : x2 = static_cast<int>(std::ceil((allsx2*0.5f+0.5f)*static_cast<float>(vieww))),
49 0 : y2 = static_cast<int>(std::ceil((allsy2*0.5f+0.5f)*static_cast<float>(viewh)));
50 0 : glEnable(GL_SCISSOR_TEST);
51 0 : glScissor(x1, y1, x2 - x1, y2 - y1);
52 : }
53 0 : glStencilFunc(GL_NOTEQUAL, 0, 0x07);
54 0 : glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
55 0 : glEnable(GL_STENCIL_TEST);
56 0 : renderparticles(ParticleLayer_Over);
57 0 : glDisable(GL_STENCIL_TEST);
58 0 : if(scissor)
59 : {
60 0 : glDisable(GL_SCISSOR_TEST);
61 : }
62 0 : renderparticles(ParticleLayer_NoLayer);
63 0 : }
64 : else
65 : {
66 0 : renderparticles();
67 : }
68 0 : }
69 :
70 : //externally relevant functionality
71 :
72 0 : void GBuffer::rendertransparent()
73 : {
74 0 : const MaterialInfo &mi = findmaterials(); //generate mat* vars
75 0 : const AlphaInfo &ai = findalphavas(); //generate mat* vars
76 0 : int hasalphavas = ai.hasalphavas;
77 0 : int hasmats = mi.hasmats;
78 0 : bool hasmodels = tmodelinfo.mdlsx1 < tmodelinfo.mdlsx2 && tmodelinfo.mdlsy1 < tmodelinfo.mdlsy2;
79 0 : if(!hasalphavas && !hasmats && !hasmodels) //don't transparent render if there is no alpha
80 : {
81 0 : if(!editmode)
82 : {
83 0 : renderparticles();
84 : }
85 0 : return;
86 : }
87 0 : if(!editmode && particlelayers && ghasstencil)
88 : {
89 0 : renderparticles(ParticleLayer_Under);
90 : }
91 0 : timer *transtimer = begintimer("transparent");
92 0 : if(hasalphavas&4 || hasmats&4)
93 : {
94 0 : glBindFramebuffer(GL_FRAMEBUFFER, msaalight ? msrefractfbo : refractfbo);
95 0 : glDepthMask(GL_FALSE);
96 0 : if(msaalight)
97 : {
98 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
99 : }
100 : else
101 : {
102 0 : glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
103 : }
104 0 : float sx1 = std::min(ai.alpharefractsx1, mi.matrefractsx1),
105 0 : sy1 = std::min(ai.alpharefractsy1, mi.matrefractsy1),
106 0 : sx2 = std::max(ai.alpharefractsx2, mi.matrefractsx2),
107 0 : sy2 = std::max(ai.alpharefractsy2, mi.matrefractsy2);
108 0 : bool scissor = sx1 > -1 || sy1 > -1 || sx2 < 1 || sy2 < 1;
109 0 : if(scissor)
110 : {
111 0 : int x1 = static_cast<int>(std::floor(std::max(sx1*0.5f+0.5f-refractmargin*static_cast<float>(viewh)/static_cast<float>(vieww), 0.0f)*static_cast<float>(vieww))),
112 0 : y1 = static_cast<int>(std::floor(std::max(sy1*0.5f+0.5f-refractmargin, 0.0f)*static_cast<float>(viewh))),
113 0 : x2 = static_cast<int>(std::ceil(std::min(sx2*0.5f+0.5f+refractmargin*static_cast<float>(viewh)/static_cast<float>(vieww), 1.0f)*static_cast<float>(vieww))),
114 0 : y2 = static_cast<int>(std::ceil(std::min(sy2*0.5f+0.5f+refractmargin, 1.0f)*static_cast<float>(viewh)));
115 0 : glEnable(GL_SCISSOR_TEST);
116 0 : glScissor(x1, y1, x2 - x1, y2 - y1);
117 : }
118 0 : glClearColor(0, 0, 0, 0);
119 0 : glClear(GL_COLOR_BUFFER_BIT);
120 0 : if(scissor)
121 : {
122 0 : glDisable(GL_SCISSOR_TEST);
123 : }
124 0 : GLOBALPARAMF(refractdepth, 1.0f/refractdepth);
125 0 : SETSHADER(refractmask);
126 0 : if(hasalphavas&4)
127 : {
128 0 : renderrefractmask();
129 : }
130 0 : if(hasmats&4)
131 : {
132 0 : rendermaterialmask();
133 : }
134 0 : glDepthMask(GL_TRUE);
135 : }
136 :
137 0 : glActiveTexture(GL_TEXTURE7);
138 0 : if(msaalight)
139 : {
140 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msrefracttex);
141 : }
142 : else
143 : {
144 0 : glBindTexture(GL_TEXTURE_RECTANGLE, refracttex);
145 : }
146 0 : glActiveTexture(GL_TEXTURE8);
147 0 : if(msaalight)
148 : {
149 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mshdrtex);
150 : }
151 : else
152 : {
153 0 : glBindTexture(GL_TEXTURE_RECTANGLE, hdrtex);
154 : }
155 0 : glActiveTexture(GL_TEXTURE9);
156 0 : if(msaalight)
157 : {
158 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
159 : }
160 : else
161 : {
162 0 : glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
163 : }
164 0 : glActiveTexture(GL_TEXTURE0);
165 0 : if(ghasstencil)
166 : {
167 0 : glEnable(GL_STENCIL_TEST);
168 : }
169 0 : matrix4 raymatrix(vec(-0.5f*static_cast<float>(vieww)*projmatrix.a.x, 0, 0.5f*static_cast<float>(vieww) - 0.5f*static_cast<float>(vieww)*projmatrix.c.x),
170 0 : vec(0, -0.5f*static_cast<float>(viewh)*projmatrix.b.y, 0.5f*static_cast<float>(viewh) - 0.5f*static_cast<float>(viewh)*projmatrix.c.y));
171 0 : raymatrix.muld(cammatrix);
172 0 : GLOBALPARAM(raymatrix, raymatrix);
173 0 : GLOBALPARAM(linearworldmatrix, linearworldmatrix);
174 :
175 : std::array<uint, lighttilemaxheight> tiles;
176 0 : float allsx1 = 1,
177 0 : allsy1 = 1,
178 0 : allsx2 = -1,
179 0 : allsy2 = -1;
180 : float sx1, sy1, sx2, sy2;
181 :
182 0 : for(int layer = 0; layer < 4; ++layer)
183 : {
184 0 : switch(layer)
185 : {
186 0 : case 0:
187 : {
188 0 : if(!(hasmats&1))
189 : {
190 0 : continue;
191 : }
192 0 : sx1 = mi.matliquidsx1;
193 0 : sy1 = mi.matliquidsy1;
194 0 : sx2 = mi.matliquidsx2;
195 0 : sy2 = mi.matliquidsy2;
196 0 : std::memcpy(tiles.data(), mi.matliquidtiles, sizeof(tiles));
197 0 : break;
198 : }
199 0 : case 1:
200 : {
201 0 : if(!(hasalphavas&1))
202 : {
203 0 : continue;
204 : }
205 0 : sx1 = ai.alphabacksx1;
206 0 : sy1 = ai.alphabacksy1;
207 0 : sx2 = ai.alphabacksx2;
208 0 : sy2 = ai.alphabacksy2;
209 0 : std::memcpy(tiles.data(), alphatiles, tiles.size()*sizeof(uint));
210 0 : break;
211 : }
212 0 : case 2:
213 : {
214 0 : if(!(hasalphavas&2) && !(hasmats&2))
215 : {
216 0 : continue;
217 : }
218 0 : sx1 = ai.alphafrontsx1;
219 0 : sy1 = ai.alphafrontsy1;
220 0 : sx2 = ai.alphafrontsx2;
221 0 : sy2 = ai.alphafrontsy2;
222 0 : std::memcpy(tiles.data(), alphatiles, tiles.size()*sizeof(uint));
223 0 : if(hasmats&2)
224 : {
225 0 : sx1 = std::min(sx1, mi.matsolidsx1);
226 0 : sy1 = std::min(sy1, mi.matsolidsy1);
227 0 : sx2 = std::max(sx2, mi.matsolidsx2);
228 0 : sy2 = std::max(sy2, mi.matsolidsy2);
229 0 : for(int j = 0; j < lighttilemaxheight; ++j)
230 : {
231 0 : tiles[j] |= mi.matsolidtiles[j];
232 : }
233 : }
234 0 : break;
235 : }
236 0 : case 3:
237 : {
238 0 : if(!hasmodels)
239 : {
240 0 : continue;
241 : }
242 0 : sx1 = tmodelinfo.mdlsx1;
243 0 : sy1 = tmodelinfo.mdlsy1;
244 0 : sx2 = tmodelinfo.mdlsx2;
245 0 : sy2 = tmodelinfo.mdlsy2;
246 0 : std::memcpy(tiles.data(), tmodelinfo.mdltiles.data(), tiles.size()*sizeof(uint));
247 0 : break;
248 : }
249 0 : default:
250 : {
251 0 : continue;
252 : }
253 0 : }
254 0 : transparentlayer = layer+1;
255 0 : allsx1 = std::min(allsx1, sx1);
256 0 : allsy1 = std::min(allsy1, sy1);
257 0 : allsx2 = std::max(allsx2, sx2);
258 0 : allsy2 = std::max(allsy2, sy2);
259 :
260 0 : glBindFramebuffer(GL_FRAMEBUFFER, msaalight ? msfbo : gfbo);
261 0 : if(ghasstencil)
262 : {
263 0 : glStencilFunc(GL_ALWAYS, layer+1, ~0);
264 0 : glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
265 : }
266 : else
267 : {
268 0 : bool scissor = sx1 > -1 || sy1 > -1 || sx2 < 1 || sy2 < 1;
269 0 : if(scissor)
270 : {
271 0 : int x1 = static_cast<int>(std::floor((sx1*0.5f+0.5f)*static_cast<float>(vieww))),
272 0 : y1 = static_cast<int>(std::floor((sy1*0.5f+0.5f)*static_cast<float>(viewh))),
273 0 : x2 = static_cast<int>(std::ceil((sx2*0.5f+0.5f)*static_cast<float>(vieww))),
274 0 : y2 = static_cast<int>(std::ceil((sy2*0.5f+0.5f)*static_cast<float>(viewh)));
275 0 : glEnable(GL_SCISSOR_TEST);
276 0 : glScissor(x1, y1, x2 - x1, y2 - y1);
277 : }
278 :
279 0 : maskgbuffer("n");
280 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
281 0 : glClearColor(0, 0, 0, 0);
282 0 : glClear(GL_COLOR_BUFFER_BIT);
283 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
284 0 : if(scissor)
285 : {
286 0 : glDisable(GL_SCISSOR_TEST);
287 : }
288 : }
289 0 : maskgbuffer("cndg");
290 :
291 0 : if(wireframe && editmode)
292 : {
293 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
294 : }
295 :
296 0 : switch(layer)
297 : {
298 0 : case 0:
299 : {
300 0 : renderliquidmaterials();
301 0 : break;
302 : }
303 0 : case 1:
304 : {
305 0 : renderalphageom(1);
306 0 : break;
307 : }
308 0 : case 2:
309 : {
310 0 : if(hasalphavas&2)
311 : {
312 0 : renderalphageom(2);
313 : }
314 0 : if(hasmats&2)
315 : {
316 0 : rendersolidmaterials();
317 : }
318 0 : renderstains(StainBuffer_Transparent, true, layer+1);
319 0 : break;
320 : }
321 0 : case 3:
322 : {
323 0 : batching::rendertransparentmodelbatches(layer+1);
324 0 : break;
325 : }
326 : }
327 :
328 0 : if(wireframe && editmode)
329 : {
330 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
331 : }
332 :
333 0 : if(msaalight)
334 : {
335 0 : glBindFramebuffer(GL_FRAMEBUFFER, mshdrfbo);
336 0 : if((ghasstencil && msaaedgedetect) || msaalight==2)
337 : {
338 0 : for(int i = 0; i < 2; ++i)
339 : {
340 0 : renderlights(sx1, sy1, sx2, sy2, tiles.data(), layer+1, i+1, true);
341 : }
342 0 : }
343 : else
344 : {
345 0 : renderlights(sx1, sy1, sx2, sy2, tiles.data(), layer+1, 3, true);
346 : }
347 : }
348 : else
349 : {
350 0 : glBindFramebuffer(GL_FRAMEBUFFER, hdrfbo);
351 0 : renderlights(sx1, sy1, sx2, sy2, tiles.data(), layer+1, 0, true);
352 : }
353 :
354 0 : switch(layer)
355 : {
356 0 : case 2:
357 : {
358 0 : renderstains(StainBuffer_Transparent, false, layer+1);
359 0 : break;
360 : }
361 : }
362 : }
363 :
364 0 : transparentlayer = 0;
365 :
366 0 : if(ghasstencil)
367 : {
368 0 : glDisable(GL_STENCIL_TEST);
369 : }
370 :
371 0 : endtimer(transtimer);
372 :
373 0 : if(editmode)
374 : {
375 0 : return;
376 : }
377 0 : alphaparticles(allsx1, allsy1, allsx2, allsy2);
378 : }
|