diff options
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/COpenGLParallaxMapRenderer.cpp')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/COpenGLParallaxMapRenderer.cpp | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/COpenGLParallaxMapRenderer.cpp b/libraries/irrlicht-1.8/source/Irrlicht/COpenGLParallaxMapRenderer.cpp new file mode 100644 index 0000000..15eae29 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/COpenGLParallaxMapRenderer.cpp | |||
@@ -0,0 +1,354 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "IrrCompileConfig.h" | ||
6 | #ifdef _IRR_COMPILE_WITH_OPENGL_ | ||
7 | |||
8 | #include "COpenGLParallaxMapRenderer.h" | ||
9 | #include "COpenGLDriver.h" | ||
10 | #include "IGPUProgrammingServices.h" | ||
11 | #include "IShaderConstantSetCallBack.h" | ||
12 | #include "IVideoDriver.h" | ||
13 | #include "os.h" | ||
14 | |||
15 | namespace irr | ||
16 | { | ||
17 | namespace video | ||
18 | { | ||
19 | |||
20 | // Irrlicht Engine OpenGL render path parallax map vertex shader | ||
21 | // I guess it could be optimized a lot, because I wrote it in D3D ASM and | ||
22 | // transferred it 1:1 to OpenGL | ||
23 | const char OPENGL_PARALLAX_MAP_VSH[] = | ||
24 | "!!ARBvp1.0\n"\ | ||
25 | "#input\n"\ | ||
26 | "# 0-3: transposed world matrix;\n"\ | ||
27 | "#;12: Light01 position \n"\ | ||
28 | "#;13: x,y,z: Light01 color; .w: 1/LightRadius^2 \n"\ | ||
29 | "#;14: Light02 position \n"\ | ||
30 | "#;15: x,y,z: Light02 color; .w: 1/LightRadius^2 \n"\ | ||
31 | "#;16: Eye position \n"\ | ||
32 | "\n"\ | ||
33 | "ATTRIB InPos = vertex.position;\n"\ | ||
34 | "ATTRIB InColor = vertex.color;\n"\ | ||
35 | "ATTRIB InNormal = vertex.normal;\n"\ | ||
36 | "ATTRIB InTexCoord = vertex.texcoord[0];\n"\ | ||
37 | "ATTRIB InTangent = vertex.texcoord[1];\n"\ | ||
38 | "ATTRIB InBinormal = vertex.texcoord[2];\n"\ | ||
39 | "\n"\ | ||
40 | "#output\n"\ | ||
41 | "OUTPUT OutPos = result.position;\n"\ | ||
42 | "OUTPUT OutLightColor1 = result.color.primary;\n"\ | ||
43 | "OUTPUT OutLightColor2 = result.color.secondary;\n"\ | ||
44 | "OUTPUT OutTexCoord = result.texcoord[0];\n"\ | ||
45 | "OUTPUT OutLightVector1 = result.texcoord[1];\n"\ | ||
46 | "OUTPUT OutLightVector2 = result.texcoord[2];\n"\ | ||
47 | "OUTPUT OutEyeVector = result.texcoord[3];\n"\ | ||
48 | "\n"\ | ||
49 | "PARAM MVP[4] = { state.matrix.mvp }; # modelViewProjection matrix.\n"\ | ||
50 | "TEMP Temp;\n"\ | ||
51 | "TEMP TempColor;\n"\ | ||
52 | "TEMP TempLightVector1;\n"\ | ||
53 | "TEMP TempLightVector2;\n"\ | ||
54 | "TEMP TempEyeVector;\n"\ | ||
55 | "TEMP TempTransLightV1;\n"\ | ||
56 | "TEMP TempTransLightV2;\n"\ | ||
57 | "\n"\ | ||
58 | "# transform position to clip space \n"\ | ||
59 | "DP4 OutPos.x, MVP[0], InPos;\n"\ | ||
60 | "DP4 OutPos.y, MVP[1], InPos;\n"\ | ||
61 | "DP4 Temp.z, MVP[2], InPos;\n"\ | ||
62 | "DP4 OutPos.w, MVP[3], InPos;\n"\ | ||
63 | "MOV OutPos.z, Temp.z;\n"\ | ||
64 | "MOV result.fogcoord.x, Temp.z;\n"\ | ||
65 | "\n"\ | ||
66 | "# vertex - lightpositions \n"\ | ||
67 | "SUB TempLightVector1, program.local[12], InPos; \n"\ | ||
68 | "SUB TempLightVector2, program.local[14], InPos; \n"\ | ||
69 | "\n"\ | ||
70 | "# eye vector \n"\ | ||
71 | "SUB Temp, program.local[16], InPos; \n"\ | ||
72 | "\n"\ | ||
73 | "# transform the light vector 1 with U, V, W \n"\ | ||
74 | "DP3 TempTransLightV1.x, InTangent, TempLightVector1; \n"\ | ||
75 | "DP3 TempTransLightV1.y, InBinormal, TempLightVector1; \n"\ | ||
76 | "DP3 TempTransLightV1.z, InNormal, TempLightVector1; \n"\ | ||
77 | "\n"\ | ||
78 | "# transform the light vector 2 with U, V, W \n"\ | ||
79 | "DP3 TempTransLightV2.x, InTangent, TempLightVector2; \n"\ | ||
80 | "DP3 TempTransLightV2.y, InBinormal, TempLightVector2; \n"\ | ||
81 | "DP3 TempTransLightV2.z, InNormal, TempLightVector2; \n"\ | ||
82 | "\n"\ | ||
83 | "# transform the eye vector with U, V, W \n"\ | ||
84 | "DP3 TempEyeVector.x, InTangent, Temp; \n"\ | ||
85 | "DP3 TempEyeVector.y, InBinormal, Temp; \n"\ | ||
86 | "DP3 TempEyeVector.z, InNormal, Temp; \n"\ | ||
87 | "\n"\ | ||
88 | "# normalize light vector 1 \n"\ | ||
89 | "DP3 TempTransLightV1.w, TempTransLightV1, TempTransLightV1; \n"\ | ||
90 | "RSQ TempTransLightV1.w, TempTransLightV1.w; \n"\ | ||
91 | "MUL TempTransLightV1, TempTransLightV1, TempTransLightV1.w;\n"\ | ||
92 | "\n"\ | ||
93 | "# normalize light vector 2 \n"\ | ||
94 | "DP3 TempTransLightV2.w, TempTransLightV2, TempTransLightV2; \n"\ | ||
95 | "RSQ TempTransLightV2.w, TempTransLightV2.w; \n"\ | ||
96 | "MUL TempTransLightV2, TempTransLightV2, TempTransLightV2.w;\n"\ | ||
97 | "\n"\ | ||
98 | "# normalize eye vector \n"\ | ||
99 | "DP3 TempEyeVector.w, TempEyeVector, TempEyeVector; \n"\ | ||
100 | "RSQ TempEyeVector.w, TempEyeVector.w; \n"\ | ||
101 | "MUL TempEyeVector, TempEyeVector, TempEyeVector.w;\n"\ | ||
102 | "MUL TempEyeVector, TempEyeVector, {1,-1,-1,1}; # flip x \n"\ | ||
103 | "\n"\ | ||
104 | "\n"\ | ||
105 | "# move light and eye vectors out\n"\ | ||
106 | "MAD OutLightVector1, TempTransLightV1, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\ | ||
107 | "MAD OutLightVector2, TempTransLightV2, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\ | ||
108 | "MAD OutEyeVector, TempEyeVector, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\ | ||
109 | "\n"\ | ||
110 | "# calculate attenuation of light 1\n"\ | ||
111 | "MOV TempLightVector1.w, {0,0,0,0}; \n"\ | ||
112 | "DP3 TempLightVector1.x, TempLightVector1, TempLightVector1; \n"\ | ||
113 | "MUL TempLightVector1.x, TempLightVector1.x, program.local[13].w; \n"\ | ||
114 | "RSQ TempLightVector1, TempLightVector1.x; \n"\ | ||
115 | "MUL OutLightColor1, TempLightVector1, program.local[13]; # resulting light color = lightcolor * attenuation \n"\ | ||
116 | "\n"\ | ||
117 | "# calculate attenuation of light 2\n"\ | ||
118 | "MOV TempLightVector2.w, {0,0,0,0}; \n"\ | ||
119 | "DP3 TempLightVector2.x, TempLightVector2, TempLightVector2; \n"\ | ||
120 | "MUL TempLightVector2.x, TempLightVector2.x, program.local[15].w; \n"\ | ||
121 | "RSQ TempLightVector2, TempLightVector2.x; \n"\ | ||
122 | "MUL OutLightColor2, TempLightVector2, program.local[15]; # resulting light color = lightcolor * attenuation \n"\ | ||
123 | "\n"\ | ||
124 | "# move out texture coordinates and original alpha value\n"\ | ||
125 | "MOV OutTexCoord, InTexCoord; \n"\ | ||
126 | "MOV OutLightColor1.w, InColor.w; \n"\ | ||
127 | "\n"\ | ||
128 | "END\n"; | ||
129 | |||
130 | // Irrlicht Engine OpenGL render path parallax map pixel shader | ||
131 | // I guess it could be optimized a bit, because I wrote it in D3D ASM and | ||
132 | // transfered it 1:1 to OpenGL | ||
133 | const char OPENGL_PARALLAX_MAP_PSH[] = | ||
134 | "!!ARBfp1.0\n"\ | ||
135 | "#_IRR_FOG_MODE_\n"\ | ||
136 | "\n"\ | ||
137 | "#Input\n"\ | ||
138 | "ATTRIB inTexCoord = fragment.texcoord[0]; \n"\ | ||
139 | "ATTRIB light1Vector = fragment.texcoord[1]; \n"\ | ||
140 | "ATTRIB light2Vector = fragment.texcoord[2]; \n"\ | ||
141 | "ATTRIB eyeVector = fragment.texcoord[3]; \n"\ | ||
142 | "ATTRIB light1Color = fragment.color.primary; \n"\ | ||
143 | "ATTRIB light2Color = fragment.color.secondary; \n"\ | ||
144 | "\n"\ | ||
145 | "#Output\n"\ | ||
146 | "OUTPUT outColor = result.color;\n"\ | ||
147 | "TEMP temp;\n"\ | ||
148 | "TEMP temp2;\n"\ | ||
149 | "TEMP colorMapColor;\n"\ | ||
150 | "TEMP normalMapColor;\n"\ | ||
151 | "\n"\ | ||
152 | "PARAM height_scale = program.local[0]; \n"\ | ||
153 | "# fetch color and normal map; \n"\ | ||
154 | "TXP normalMapColor, inTexCoord, texture[1], 2D; \n"\ | ||
155 | "MAD normalMapColor, normalMapColor, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ | ||
156 | "\n"\ | ||
157 | "\n"\ | ||
158 | "# extract eye vector (so substract 0.5f and multiply by 2)\n"\ | ||
159 | "MAD temp, eyeVector, {2,2,2,2}, {-1,-1,-1,-1};\n"\ | ||
160 | "\n"\ | ||
161 | "# height = height * scale \n"\ | ||
162 | "MUL normalMapColor, normalMapColor, height_scale;\n"\ | ||
163 | "\n"\ | ||
164 | "# calculate new texture coord: height * eye + oldTexCoord\n"\ | ||
165 | "MAD temp, temp, normalMapColor.wwww, inTexCoord;\n"\ | ||
166 | "\n"\ | ||
167 | "# fetch new textures \n"\ | ||
168 | "TXP colorMapColor, temp, texture[0], 2D; \n"\ | ||
169 | "TXP normalMapColor, temp, texture[1], 2D; \n"\ | ||
170 | "\n"\ | ||
171 | "# calculate color of light1; \n"\ | ||
172 | "MAD normalMapColor, normalMapColor, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ | ||
173 | "MAD temp, light1Vector, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ | ||
174 | "DP3_SAT temp, normalMapColor, temp; \n"\ | ||
175 | "MUL temp, light1Color, temp; \n"\ | ||
176 | "\n"\ | ||
177 | "# calculate color of light2; \n"\ | ||
178 | "MAD temp2, light2Vector, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ | ||
179 | "DP3_SAT temp2, normalMapColor, temp2; \n"\ | ||
180 | "MAD temp, light2Color, temp2, temp; \n"\ | ||
181 | "\n"\ | ||
182 | "# luminance * base color; \n"\ | ||
183 | "MUL outColor, temp, colorMapColor; \n"\ | ||
184 | "MOV outColor.a, light1Color.a; #write interpolated vertex alpha value\n"\ | ||
185 | "\n"\ | ||
186 | "END\n"; | ||
187 | |||
188 | //! Constructor | ||
189 | COpenGLParallaxMapRenderer::COpenGLParallaxMapRenderer(video::COpenGLDriver* driver, | ||
190 | s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial) | ||
191 | : COpenGLShaderMaterialRenderer(driver, 0, baseMaterial), CompiledShaders(true) | ||
192 | { | ||
193 | |||
194 | #ifdef _DEBUG | ||
195 | setDebugName("COpenGLParallaxMapRenderer"); | ||
196 | #endif | ||
197 | |||
198 | // set this as callback. We could have done this in | ||
199 | // the initialization list, but some compilers don't like it. | ||
200 | |||
201 | CallBack = this; | ||
202 | |||
203 | // basically, this simply compiles the hard coded shaders if the | ||
204 | // hardware is able to do them, otherwise it maps to the base material | ||
205 | |||
206 | if (!driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1) || | ||
207 | !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) | ||
208 | { | ||
209 | // this hardware is not able to do shaders. Fall back to | ||
210 | // base material. | ||
211 | outMaterialTypeNr = driver->addMaterialRenderer(this); | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | // check if already compiled normal map shaders are there. | ||
216 | |||
217 | video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_PARALLAX_MAP_SOLID); | ||
218 | |||
219 | if (renderer) | ||
220 | { | ||
221 | // use the already compiled shaders | ||
222 | video::COpenGLParallaxMapRenderer* nmr = reinterpret_cast<video::COpenGLParallaxMapRenderer*>(renderer); | ||
223 | CompiledShaders = false; | ||
224 | |||
225 | VertexShader = nmr->VertexShader; | ||
226 | PixelShader = nmr->PixelShader; | ||
227 | |||
228 | outMaterialTypeNr = driver->addMaterialRenderer(this); | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | // compile shaders on our own | ||
233 | init(outMaterialTypeNr, OPENGL_PARALLAX_MAP_VSH, OPENGL_PARALLAX_MAP_PSH, EVT_TANGENTS); | ||
234 | } | ||
235 | |||
236 | // fallback if compilation has failed | ||
237 | if (-1==outMaterialTypeNr) | ||
238 | outMaterialTypeNr = driver->addMaterialRenderer(this); | ||
239 | } | ||
240 | |||
241 | |||
242 | //! Destructor | ||
243 | COpenGLParallaxMapRenderer::~COpenGLParallaxMapRenderer() | ||
244 | { | ||
245 | if (CallBack == this) | ||
246 | CallBack = 0; | ||
247 | |||
248 | if (!CompiledShaders) | ||
249 | { | ||
250 | // prevent this from deleting shaders we did not create | ||
251 | VertexShader = 0; | ||
252 | PixelShader.clear(); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | |||
257 | void COpenGLParallaxMapRenderer::OnSetMaterial(const video::SMaterial& material, | ||
258 | const video::SMaterial& lastMaterial, | ||
259 | bool resetAllRenderstates, video::IMaterialRendererServices* services) | ||
260 | { | ||
261 | COpenGLShaderMaterialRenderer::OnSetMaterial(material, lastMaterial, | ||
262 | resetAllRenderstates, services); | ||
263 | |||
264 | CurrentScale = material.MaterialTypeParam; | ||
265 | } | ||
266 | |||
267 | |||
268 | |||
269 | //! Returns the render capability of the material. | ||
270 | s32 COpenGLParallaxMapRenderer::getRenderCapability() const | ||
271 | { | ||
272 | if (Driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1) && | ||
273 | Driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) | ||
274 | return 0; | ||
275 | |||
276 | return 1; | ||
277 | } | ||
278 | |||
279 | |||
280 | //! Called by the engine when the vertex and/or pixel shader constants for an | ||
281 | //! material renderer should be set. | ||
282 | void COpenGLParallaxMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData) | ||
283 | { | ||
284 | video::IVideoDriver* driver = services->getVideoDriver(); | ||
285 | |||
286 | // set transposed world matrix | ||
287 | const core::matrix4& tWorld = driver->getTransform(video::ETS_WORLD).getTransposed(); | ||
288 | services->setVertexShaderConstant(tWorld.pointer(), 0, 4); | ||
289 | |||
290 | // set transposed worldViewProj matrix | ||
291 | core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION)); | ||
292 | worldViewProj *= driver->getTransform(video::ETS_VIEW); | ||
293 | worldViewProj *= driver->getTransform(video::ETS_WORLD); | ||
294 | core::matrix4 tr(worldViewProj.getTransposed()); | ||
295 | services->setVertexShaderConstant(tr.pointer(), 8, 4); | ||
296 | |||
297 | // here we fetch the fixed function lights from the driver | ||
298 | // and set them as constants | ||
299 | |||
300 | u32 cnt = driver->getDynamicLightCount(); | ||
301 | |||
302 | // Load the inverse world matrix. | ||
303 | core::matrix4 invWorldMat; | ||
304 | driver->getTransform(video::ETS_WORLD).getInverse(invWorldMat); | ||
305 | |||
306 | for (u32 i=0; i<2; ++i) | ||
307 | { | ||
308 | video::SLight light; | ||
309 | |||
310 | if (i<cnt) | ||
311 | light = driver->getDynamicLight(i); | ||
312 | else | ||
313 | { | ||
314 | light.DiffuseColor.set(0,0,0); // make light dark | ||
315 | light.Radius = 1.0f; | ||
316 | } | ||
317 | |||
318 | light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation | ||
319 | |||
320 | // Transform the light by the inverse world matrix to get it into object space. | ||
321 | invWorldMat.transformVect(light.Position); | ||
322 | |||
323 | services->setVertexShaderConstant( | ||
324 | reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1); | ||
325 | |||
326 | services->setVertexShaderConstant( | ||
327 | reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1); | ||
328 | } | ||
329 | |||
330 | // Obtain the view position by transforming 0,0,0 by the inverse view matrix | ||
331 | // and then multiply this by the inverse world matrix. | ||
332 | core::vector3df viewPos(0.0f, 0.0f, 0.0f); | ||
333 | core::matrix4 inverseView; | ||
334 | driver->getTransform(video::ETS_VIEW).getInverse(inverseView); | ||
335 | inverseView.transformVect(viewPos); | ||
336 | invWorldMat.transformVect(viewPos); | ||
337 | services->setVertexShaderConstant(reinterpret_cast<const f32*>(&viewPos.X), 16, 1); | ||
338 | |||
339 | // set scale factor | ||
340 | f32 factor = 0.02f; // default value | ||
341 | if (CurrentScale != 0.0f) | ||
342 | factor = CurrentScale; | ||
343 | |||
344 | f32 c6[] = {factor, factor, factor, factor}; | ||
345 | services->setPixelShaderConstant(c6, 0, 1); | ||
346 | } | ||
347 | |||
348 | |||
349 | } // end namespace video | ||
350 | } // end namespace irr | ||
351 | |||
352 | |||
353 | #endif | ||
354 | |||