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