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