aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp318
1 files changed, 318 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp
new file mode 100644
index 0000000..ca30966
--- /dev/null
+++ b/libraries/irrlicht-1.8/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp
@@ -0,0 +1,318 @@
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_DIRECT3D_8_
7
8#include "CD3D8ParallaxMapRenderer.h"
9#include "IMaterialRendererServices.h"
10#include "IVideoDriver.h"
11#include "os.h"
12#include "SLight.h"
13
14namespace irr
15{
16namespace video
17{
18 // 1.1/1.4 Shaders with two lights and vertex based attenuation
19
20 // Irrlicht Engine D3D8 render path normal map vertex shader
21 const char D3D8_PARALLAX_MAP_VSH[] =
22 ";Irrlicht Engine 0.10 D3D8 render path parallax mapping vertex shader\n"\
23 "; c0-3: Transposed world matrix \n"\
24 "; c4: Eye position \n"\
25 "; c8-11: Transposed worldViewProj matrix (Projection * View * World) \n"\
26 "; c12: Light01 position \n"\
27 "; c13: x,y,z: Light01 color; .w: 1/LightRadius˛ \n"\
28 "; c14: Light02 position \n"\
29 "; c15: x,y,z: Light02 color; .w: 1/LightRadius˛ \n"\
30 "vs.1.1\n"\
31 "; v0 ; position \n"\
32 "; v1 ; normal \n"\
33 "; v2 ; color \n"\
34 "; v3 ; texture coord \n"\
35 "; v4 ; tangent \n"\
36 "; v5 ; binormal \n"\
37 "\n"\
38 "def c95, 0.5, 0.5, 0.5, 0.5 ; used for moving light vector to ps \n"\
39 "def c96, -1, 1, 1, 1 ; somewhere I've got a bug. flipping the vectors with this fixes it. \n"\
40 "\n"\
41 "m4x4 oPos, v0, c8 ; transform position to clip space with worldViewProj matrix\n"\
42 "\n"\
43 "m3x3 r5, v4, c0 ; transform tangent U\n"\
44 "m3x3 r7, v1, c0 ; transform normal W\n"\
45 "m3x3 r6, v5, c0 ; transform binormal V\n"\
46 "\n"\
47 "m4x4 r4, v0, c0 ; vertex into world position\n"\
48 "add r2, c12, -r4 ; vtxpos - light1 pos\n"\
49 "add r3, c14, -r4 ; vtxpos - light2 pos\n"\
50 "add r1, -c4, r4 ; eye - vtxpos \n"\
51 "\n"\
52 "dp3 r8.x, r5, r2 ; transform the light1 vector with U, V, W\n"\
53 "dp3 r8.y, r6, r2 \n"\
54 "dp3 r8.z, r7, r2 \n"\
55 "dp3 r9.x, r5, r3 ; transform the light2 vector with U, V, W\n"\
56 "dp3 r9.y, r6, r3 \n"\
57 "dp3 r9.z, r7, r3 \n"\
58 "dp3 r10.x, r5, r1 ; transform the eye vector with U, V, W\n"\
59 "dp3 r10.y, r6, r1 \n"\
60 "dp3 r10.z, r7, r1 \n"\
61 "\n"\
62 "dp3 r8.w, r8, r8 ; normalize light vector 1 (r8)\n"\
63 "rsq r8.w, r8.w \n"\
64 "mul r8, r8, r8.w \n"\
65 ";mul r8, r8, c96 \n"\
66 "dp3 r9.w, r9, r9 ; normalize light vector 2 (r9)\n"\
67 "rsq r9.w, r9.w \n"\
68 "mul r9, r9, r9.w \n"\
69 ";mul r9, r9, c96 \n"\
70 "dp3 r10.w, r10, r10 ; normalize eye vector (r10)\n"\
71 "rsq r10.w, r10.w \n"\
72 "mul r10, r10, r10.w \n"\
73 "mul r10, r10, c96 \n"\
74 "\n"\
75 "\n"\
76 "mad oT2.xyz, r8.xyz, c95, c95 ; move light vector 1 from -1..1 into 0..1 \n"\
77 "mad oT3.xyz, r9.xyz, c95, c95 ; move light vector 2 from -1..1 into 0..1 \n"\
78 "mad oT4.xyz, r10.xyz, c95, c95 ; move eye vector from -1..1 into 0..1 \n"\
79 "\n"\
80 " ; calculate attenuation of light 1 \n"\
81 "dp3 r2.x, r2.xyz, r2.xyz ; r2.x = r2.x˛ + r2.y˛ + r2.z˛ \n"\
82 "mul r2.x, r2.x, c13.w ; r2.x * attenutation \n"\
83 "rsq r2, r2.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
84 "mul oD0, r2, c13 ; resulting light color = lightcolor * attenuation \n"\
85 "\n"\
86 " ; calculate attenuation of light 2 \n"\
87 "dp3 r3.x, r3.xyz, r3.xyz ; r3.x = r3.x˛ + r3.y˛ + r3.z˛ \n"\
88 "mul r3.x, r3.x, c15.w ; r2.x * attenutation \n"\
89 "rsq r3, r3.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
90 "mul oD1, r3, c15 ; resulting light color = lightcolor * attenuation \n"\
91 "\n"\
92 "mov oT0.xy, v3.xy ; move out texture coordinates 1\n"\
93 "mov oT1.xy, v3.xy ; move out texture coordinates 2\n"\
94 "mov oD0.a, v2.a ; move out original alpha value \n"\
95 "\n";
96
97
98 // Irrlicht Engine D3D8 render path normal map pixel shader version 1.4
99 const char D3D8_PARALLAX_MAP_PSH[] =
100 ";Irrlicht Engine 0.10 D3D8 render path parallax mapping pixel shader \n"\
101 ";Input: \n"\
102 ";t0: color map texture coord \n"\
103 ";t1: normal map texture coords \n"\
104 ";t2: light 1 vector in tangent space \n"\
105 ";t4: eye vector in tangent space \n"\
106 ";v0: light 1 color \n"\
107 ";t3: light 2 vector in tangent space \n"\
108 ";v1: light 2 color \n"\
109 ";v0.a: vertex alpha value \n"\
110 " \n"\
111 "ps.1.4 \n"\
112 " \n"\
113 ";def c6, 0.02f, 0.02f, 0.02f, 0.0f ; scale factor, now set in callback \n"\
114 " \n"\
115 "texld r1, t1 ; sample (normal.x, normal.y, normal.z, height) \n"\
116 "texcrd r4.xyz, t4 ; fetch eye vector \n"\
117 "texcrd r0.xyz, t0 ; color map \n"\
118 " \n"\
119 "; original parallax mapping: \n"\
120 ";mul r3, r1_bx2.wwww, c6; ; r3 = (height, height, height) * scale \n"\
121 ";mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
122 " \n"\
123 "; modified parallax mapping to reduce swimming effect: \n"\
124 "mul r3, r1_bx2.wwww, r1_bx2.zzzz ; (nh,nh,nh,nh) = (h,h,h,h) * (n.z,n.z,n.z,n.z,) \n"\
125 "mul r3, r3, c6; ; r3 = (nh, nh, nh) * scale \n"\
126 "mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
127 " \n"\
128 "phase \n"\
129 " \n"\
130 "texld r0, r2 ; load diffuse texture with new tex coord \n"\
131 "texld r1, r2 ; sample normal map \n"\
132 "texcrd r2.xyz, t2 ; fetch light vector 1 \n"\
133 "texcrd r3.xyz, t3 ; fetch light vector 2 \n"\
134 " \n"\
135 "dp3_sat r2, r1_bx2, r2_bx2 ; normal dot light 1 (_bx2 because moved into 0..1) \n"\
136 "mul r2, r2, v0 ; luminance1 * light color 1 \n"\
137 " \n"\
138 "dp3_sat r3, r1_bx2, r3_bx2 ; normal dot light 2 (_bx2 because moved into 0..1) \n"\
139 "mad r3, r3, v1, r2 ; (luminance2 * light color 2) + luminance1 \n"\
140 " \n"\
141 "mul r0.xyz, r0, r3 ; total luminance * base color \n"\
142 "+mov r0.a, v0.a ; write original alpha value \n"\
143 "\n";
144
145
146 CD3D8ParallaxMapRenderer::CD3D8ParallaxMapRenderer(
147 IDirect3DDevice8* d3ddev, video::IVideoDriver* driver,
148 s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial)
149 : CD3D8ShaderMaterialRenderer(d3ddev, driver, 0, baseMaterial),
150 CompiledShaders(true), CurrentScale(0.0f)
151 {
152
153 #ifdef _DEBUG
154 setDebugName("CD3D8ParallaxMapRenderer");
155 #endif
156
157 // set this as callback. We could have done this in
158 // the initialization list, but some compilers don't like it.
159
160 CallBack = this;
161
162 // basicly, this thing simply compiles these hardcoded shaders if the
163 // hardware is able to do them, otherwise it maps to the base material
164
165 if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_4) ||
166 !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
167 {
168 // this hardware is not able to do shaders. Fall back to
169 // base material.
170 outMaterialTypeNr = driver->addMaterialRenderer(this);
171 return;
172 }
173
174 // check if already compiled parallax map shaders are there.
175
176 video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_PARALLAX_MAP_SOLID);
177 if (renderer)
178 {
179 // use the already compiled shaders
180 video::CD3D8ParallaxMapRenderer* nmr = (video::CD3D8ParallaxMapRenderer*)renderer;
181 CompiledShaders = false;
182
183 VertexShader = nmr->VertexShader;
184 PixelShader = nmr->PixelShader;
185
186 outMaterialTypeNr = driver->addMaterialRenderer(this);
187 }
188 else
189 {
190 // compile shaders on our own
191 init(outMaterialTypeNr, D3D8_PARALLAX_MAP_VSH, D3D8_PARALLAX_MAP_PSH, EVT_TANGENTS);
192 }
193 // something failed, use base material
194 if (-1==outMaterialTypeNr)
195 driver->addMaterialRenderer(this);
196 }
197
198
199 CD3D8ParallaxMapRenderer::~CD3D8ParallaxMapRenderer()
200 {
201 if (CallBack == this)
202 CallBack = 0;
203
204 if (!CompiledShaders)
205 {
206 // prevent this from deleting shaders we did not create
207 VertexShader = 0;
208 PixelShader = 0;
209 }
210 }
211
212
213 bool CD3D8ParallaxMapRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
214 {
215 if (vtxtype != video::EVT_TANGENTS)
216 {
217 os::Printer::log("Error: Normal map renderer only supports vertices of type EVT_TANGENTS", ELL_ERROR);
218 return false;
219 }
220
221 return CD3D8ShaderMaterialRenderer::OnRender(service, vtxtype);
222 }
223
224
225 void CD3D8ParallaxMapRenderer::OnSetMaterial(const video::SMaterial& material,
226 const video::SMaterial& lastMaterial,
227 bool resetAllRenderstates, video::IMaterialRendererServices* services)
228 {
229 CD3D8ShaderMaterialRenderer::OnSetMaterial(material, lastMaterial,
230 resetAllRenderstates, services);
231
232 CurrentScale = material.MaterialTypeParam;
233 }
234
235
236 //! Returns the render capability of the material.
237 s32 CD3D8ParallaxMapRenderer::getRenderCapability() const
238 {
239 if (Driver->queryFeature(video::EVDF_PIXEL_SHADER_1_4) &&
240 Driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
241 return 0;
242
243 return 1;
244 }
245
246
247 //! Called by the engine when the vertex and/or pixel shader constants
248 //! for an material renderer should be set.
249 void CD3D8ParallaxMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData)
250 {
251 video::IVideoDriver* driver = services->getVideoDriver();
252
253 // set transposed world matrix
254 services->setVertexShaderConstant(driver->getTransform(video::ETS_WORLD).getTransposed().pointer(), 0, 4);
255
256 // set eye position
257
258 // The viewpoint is at (0., 0., 0.) in eye space.
259 // Turning this into a vector [0 0 0 1] and multiply it by
260 // the inverse of the view matrix, the resulting vector is the
261 // object space location of the camera.
262
263 f32 floats[4] = {0,0,0,1};
264 core::matrix4 minv(driver->getTransform(video::ETS_VIEW));
265 minv.makeInverse();
266 minv.multiplyWith1x4Matrix(floats);
267 services->setVertexShaderConstant(floats, 4, 1);
268
269 // set transposed worldViewProj matrix
270 core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION));
271 worldViewProj *= driver->getTransform(video::ETS_VIEW);
272 worldViewProj *= driver->getTransform(video::ETS_WORLD);
273 services->setVertexShaderConstant(worldViewProj.getTransposed().pointer(), 8, 4);
274
275 // here we've got to fetch the fixed function lights from the driver
276 // and set them as constants
277
278 const u32 cnt = driver->getDynamicLightCount();
279
280 for (u32 i=0; i<2; ++i)
281 {
282 SLight light;
283
284 if (i<cnt)
285 light = driver->getDynamicLight(i);
286 else
287 {
288 light.DiffuseColor.set(0,0,0); // make light dark
289 light.Radius = 1.0f;
290 }
291
292 light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation
293
294 services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1);
295 services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1);
296 }
297
298 // this is not really necessary in d3d9 (used a def instruction), but to be sure:
299 f32 c95[] = {0.5f, 0.5f, 0.5f, 0.5f};
300 services->setVertexShaderConstant(c95, 95, 1);
301 f32 c96[] = {-1, 1, 1, 1};
302 services->setVertexShaderConstant(c96, 96, 1);
303
304 // set scale factor
305 f32 factor = 0.02f; // default value
306 if (CurrentScale != 0)
307 factor = CurrentScale;
308
309 f32 c6[] = {factor, factor, factor, 0};
310 services->setPixelShaderConstant(c6, 6, 1);
311 }
312
313
314} // end namespace video
315} // end namespace irr
316
317#endif // _IRR_COMPILE_WITH_DIRECT3D_8_
318