diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8.1/source/Irrlicht/CD3D9NormalMapRenderer.cpp | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8.1/source/Irrlicht/CD3D9NormalMapRenderer.cpp b/libraries/irrlicht-1.8.1/source/Irrlicht/CD3D9NormalMapRenderer.cpp new file mode 100644 index 0000000..eb6f732 --- /dev/null +++ b/libraries/irrlicht-1.8.1/source/Irrlicht/CD3D9NormalMapRenderer.cpp | |||
@@ -0,0 +1,306 @@ | |||
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_9_ | ||
7 | |||
8 | #include "CD3D9NormalMapRenderer.h" | ||
9 | #include "IVideoDriver.h" | ||
10 | #include "IMaterialRendererServices.h" | ||
11 | #include "os.h" | ||
12 | #include "SLight.h" | ||
13 | |||
14 | namespace irr | ||
15 | { | ||
16 | namespace video | ||
17 | { | ||
18 | |||
19 | // 1.1 Shaders with two lights and vertex based attenuation | ||
20 | |||
21 | // Irrlicht Engine D3D9 render path normal map vertex shader | ||
22 | const char D3D9_NORMAL_MAP_VSH[] = | ||
23 | ";Irrlicht Engine 0.8 D3D9 render path normal map vertex shader\n"\ | ||
24 | "; c0-3: Transposed world matrix \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 | "dcl_position v0 ; position \n"\ | ||
32 | "dcl_normal v1 ; normal \n"\ | ||
33 | "dcl_color v2 ; color \n"\ | ||
34 | "dcl_texcoord0 v3 ; texture coord \n"\ | ||
35 | "dcl_texcoord1 v4 ; tangent \n"\ | ||
36 | "dcl_texcoord2 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 | "\n"\ | ||
40 | "m4x4 oPos, v0, c8 ; transform position to clip space with worldViewProj matrix\n"\ | ||
41 | "\n"\ | ||
42 | "m3x3 r5, v4, c0 ; transform tangent U\n"\ | ||
43 | "m3x3 r7, v1, c0 ; transform normal W\n"\ | ||
44 | "m3x3 r6, v5, c0 ; transform binormal V\n"\ | ||
45 | "\n"\ | ||
46 | "m4x4 r4, v0, c0 ; vertex into world position\n"\ | ||
47 | "add r2, c12, -r4 ; vtxpos - lightpos1\n"\ | ||
48 | "add r3, c14, -r4 ; vtxpos - lightpos2\n"\ | ||
49 | "\n"\ | ||
50 | "dp3 r8.x, r5, r2 ; transform the light vector 1 with U, V, W\n"\ | ||
51 | "dp3 r8.y, r6, r2 \n"\ | ||
52 | "dp3 r8.z, r7, r2 \n"\ | ||
53 | "dp3 r9.x, r5, r3 ; transform the light vector 2 with U, V, W\n"\ | ||
54 | "dp3 r9.y, r6, r3 \n"\ | ||
55 | "dp3 r9.z, r7, r3 \n"\ | ||
56 | "\n"\ | ||
57 | "dp3 r8.w, r8, r8 ; normalize light vector 1 (r8)\n"\ | ||
58 | "rsq r8.w, r8.w \n"\ | ||
59 | "mul r8, r8, r8.w \n"\ | ||
60 | "dp3 r9.w, r9, r9 ; normalize light vector 2 (r9)\n"\ | ||
61 | "rsq r9.w, r9.w \n"\ | ||
62 | "mul r9, r9, r9.w \n"\ | ||
63 | "\n"\ | ||
64 | "mad oT2.xyz, r8.xyz, c95, c95 ; move light vector 1 from -1..1 into 0..1 \n"\ | ||
65 | "mad oT3.xyz, r9.xyz, c95, c95 ; move light vector 2 from -1..1 into 0..1 \n"\ | ||
66 | "\n"\ | ||
67 | " ; calculate attenuation of light 1 \n"\ | ||
68 | "dp3 r2.x, r2.xyz, r2.xyz ; r2.x = r2.x˛ + r2.y˛ + r2.z˛ \n"\ | ||
69 | "mul r2.x, r2.x, c13.w ; r2.x * attenutation \n"\ | ||
70 | "rsq r2, r2.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\ | ||
71 | "mul oD0, r2, c13 ; resulting light color = lightcolor * attenuation \n"\ | ||
72 | "\n"\ | ||
73 | " ; calculate attenuation of light 2 \n"\ | ||
74 | "dp3 r3.x, r3.xyz, r3.xyz ; r3.x = r3.x˛ + r3.y˛ + r3.z˛ \n"\ | ||
75 | "mul r3.x, r3.x, c15.w ; r2.x * attenutation \n"\ | ||
76 | "rsq r3, r3.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\ | ||
77 | "mul oD1, r3, c15 ; resulting light color = lightcolor * attenuation \n"\ | ||
78 | "\n"\ | ||
79 | "mov oT0.xy, v3.xy ; move out texture coordinates 1\n"\ | ||
80 | "mov oT1.xy, v3.xy ; move out texture coordinates 2\n"\ | ||
81 | "mov oD0.a, v2.a ; move out original alpha value \n"\ | ||
82 | "\n"; | ||
83 | |||
84 | // Irrlicht Engine D3D9 render path normal map pixel shader | ||
85 | const char D3D9_NORMAL_MAP_PSH_1_1[] = | ||
86 | ";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\ | ||
87 | ";Input: \n"\ | ||
88 | ";t0: color map texture coord \n"\ | ||
89 | ";t1: normal map texture coords \n"\ | ||
90 | ";t2: light 1 vector in tangent space \n"\ | ||
91 | ";v0: light 1 color \n"\ | ||
92 | ";t3: light 2 vector in tangent space \n"\ | ||
93 | ";v1: light 2 color \n"\ | ||
94 | ";v0.a: vertex alpha value \n"\ | ||
95 | "ps.1.1 \n"\ | ||
96 | "tex t0 ; sample color map \n"\ | ||
97 | "tex t1 ; sample normal map\n"\ | ||
98 | "texcoord t2 ; fetch light vector 1\n"\ | ||
99 | "texcoord t3 ; fetch light vector 2\n"\ | ||
100 | "\n"\ | ||
101 | "dp3_sat r0, t1_bx2, t2_bx2 ; normal dot light 1 (_bx2 because moved into 0..1)\n"\ | ||
102 | "mul r0, r0, v0 ; luminance1 * light color 1 \n"\ | ||
103 | "\n"\ | ||
104 | "dp3_sat r1, t1_bx2, t3_bx2 ; normal dot light 2 (_bx2 because moved into 0..1)\n"\ | ||
105 | "mad r0, r1, v1, r0 ; (luminance2 * light color 2) + luminance 1 \n"\ | ||
106 | "\n"\ | ||
107 | "mul r0.xyz, t0, r0 ; total luminance * base color\n"\ | ||
108 | "+mov r0.a, v0.a ; write interpolated vertex alpha value \n"\ | ||
109 | "\n"\ | ||
110 | ""; | ||
111 | |||
112 | // Higher-quality normal map pixel shader (requires PS 2.0) | ||
113 | // uses per-pixel normalization for improved accuracy | ||
114 | const char D3D9_NORMAL_MAP_PSH_2_0[] = | ||
115 | ";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\ | ||
116 | ";Input: \n"\ | ||
117 | ";t0: color map texture coord \n"\ | ||
118 | ";t1: normal map texture coords \n"\ | ||
119 | ";t2: light 1 vector in tangent space \n"\ | ||
120 | ";v0: light 1 color \n"\ | ||
121 | ";t3: light 2 vector in tangent space \n"\ | ||
122 | ";v1: light 2 color \n"\ | ||
123 | ";v0.a: vertex alpha value \n"\ | ||
124 | |||
125 | "ps_2_0 \n"\ | ||
126 | "def c0, 0, 0, 0, 0\n"\ | ||
127 | "def c1, 1.0, 1.0, 1.0, 1.0\n"\ | ||
128 | "def c2, 2.0, 2.0, 2.0, 2.0\n"\ | ||
129 | "def c3, -.5, -.5, -.5, -.5\n"\ | ||
130 | "dcl t0\n"\ | ||
131 | "dcl t1\n"\ | ||
132 | "dcl t2\n"\ | ||
133 | "dcl t3\n"\ | ||
134 | "dcl v1\n"\ | ||
135 | "dcl v0\n"\ | ||
136 | "dcl_2d s0\n"\ | ||
137 | "dcl_2d s1\n"\ | ||
138 | |||
139 | "texld r0, t0, s0 ; sample color map into r0 \n"\ | ||
140 | "texld r4, t0, s1 ; sample normal map into r4\n"\ | ||
141 | "add r4, r4, c3 ; bias the normal vector\n"\ | ||
142 | "add r5, t2, c3 ; bias the light 1 vector into r5\n"\ | ||
143 | "add r6, t3, c3 ; bias the light 2 vector into r6\n"\ | ||
144 | |||
145 | "nrm r1, r4 ; normalize the normal vector into r1\n"\ | ||
146 | "nrm r2, r5 ; normalize the light1 vector into r2\n"\ | ||
147 | "nrm r3, r6 ; normalize the light2 vector into r3\n"\ | ||
148 | |||
149 | "dp3 r2, r2, r1 ; let r2 = normal DOT light 1 vector\n"\ | ||
150 | "max r2, r2, c0 ; clamp result to positive numbers\n"\ | ||
151 | "mul r2, r2, v0 ; let r2 = luminance1 * light color 1 \n"\ | ||
152 | |||
153 | "dp3 r3, r3, r1 ; let r3 = normal DOT light 2 vector\n"\ | ||
154 | "max r3, r3, c0 ; clamp result to positive numbers\n"\ | ||
155 | |||
156 | "mad r2, r3, v1, r2 ; let r2 = (luminance2 * light color 2) + (luminance2 * light color 1) \n"\ | ||
157 | |||
158 | "mul r2, r2, r0 ; let r2 = total luminance * base color\n"\ | ||
159 | "mov r2.w, v0.w ; write interpolated vertex alpha value \n"\ | ||
160 | |||
161 | "mov oC0, r2 ; copy r2 to the output register \n"\ | ||
162 | |||
163 | "\n"\ | ||
164 | ""; | ||
165 | |||
166 | CD3D9NormalMapRenderer::CD3D9NormalMapRenderer( | ||
167 | IDirect3DDevice9* d3ddev, video::IVideoDriver* driver, | ||
168 | s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial) | ||
169 | : CD3D9ShaderMaterialRenderer(d3ddev, driver, 0, baseMaterial) | ||
170 | { | ||
171 | #ifdef _DEBUG | ||
172 | setDebugName("CD3D9NormalMapRenderer"); | ||
173 | #endif | ||
174 | |||
175 | // set this as callback. We could have done this in | ||
176 | // the initialization list, but some compilers don't like it. | ||
177 | |||
178 | CallBack = this; | ||
179 | |||
180 | // basically, this thing simply compiles the hardcoded shaders | ||
181 | // if the hardware is able to do them, otherwise it maps to the | ||
182 | // base material | ||
183 | |||
184 | if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) || | ||
185 | !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1)) | ||
186 | { | ||
187 | // this hardware is not able to do shaders. Fall back to | ||
188 | // base material. | ||
189 | outMaterialTypeNr = driver->addMaterialRenderer(this); | ||
190 | return; | ||
191 | } | ||
192 | |||
193 | // check if already compiled normal map shaders are there. | ||
194 | |||
195 | video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_NORMAL_MAP_SOLID); | ||
196 | if (renderer) | ||
197 | { | ||
198 | // use the already compiled shaders | ||
199 | video::CD3D9NormalMapRenderer* nmr = (video::CD3D9NormalMapRenderer*)renderer; | ||
200 | VertexShader = nmr->VertexShader; | ||
201 | if (VertexShader) | ||
202 | VertexShader->AddRef(); | ||
203 | |||
204 | PixelShader = nmr->PixelShader; | ||
205 | if (PixelShader) | ||
206 | PixelShader->AddRef(); | ||
207 | |||
208 | outMaterialTypeNr = driver->addMaterialRenderer(this); | ||
209 | } | ||
210 | else | ||
211 | { | ||
212 | // compile shaders on our own | ||
213 | if (driver->queryFeature(video::EVDF_PIXEL_SHADER_2_0)) | ||
214 | { | ||
215 | init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_2_0); | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_1_1); | ||
220 | } | ||
221 | } | ||
222 | // something failed, use base material | ||
223 | if (-1==outMaterialTypeNr) | ||
224 | driver->addMaterialRenderer(this); | ||
225 | } | ||
226 | |||
227 | |||
228 | CD3D9NormalMapRenderer::~CD3D9NormalMapRenderer() | ||
229 | { | ||
230 | if (CallBack == this) | ||
231 | CallBack = 0; | ||
232 | } | ||
233 | |||
234 | |||
235 | bool CD3D9NormalMapRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) | ||
236 | { | ||
237 | if (vtxtype != video::EVT_TANGENTS) | ||
238 | { | ||
239 | os::Printer::log("Error: Normal map renderer only supports vertices of type EVT_TANGENTS", ELL_ERROR); | ||
240 | return false; | ||
241 | } | ||
242 | |||
243 | return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype); | ||
244 | } | ||
245 | |||
246 | |||
247 | //! Returns the render capability of the material. | ||
248 | s32 CD3D9NormalMapRenderer::getRenderCapability() const | ||
249 | { | ||
250 | if (Driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) && | ||
251 | Driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1)) | ||
252 | return 0; | ||
253 | |||
254 | return 1; | ||
255 | } | ||
256 | |||
257 | |||
258 | //! Called by the engine when the vertex and/or pixel shader constants | ||
259 | //! for an material renderer should be set. | ||
260 | void CD3D9NormalMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData) | ||
261 | { | ||
262 | video::IVideoDriver* driver = services->getVideoDriver(); | ||
263 | |||
264 | // set transposed world matrix | ||
265 | services->setVertexShaderConstant(driver->getTransform(video::ETS_WORLD).getTransposed().pointer(), 0, 4); | ||
266 | |||
267 | // set transposed worldViewProj matrix | ||
268 | core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION)); | ||
269 | worldViewProj *= driver->getTransform(video::ETS_VIEW); | ||
270 | worldViewProj *= driver->getTransform(video::ETS_WORLD); | ||
271 | services->setVertexShaderConstant(worldViewProj.getTransposed().pointer(), 8, 4); | ||
272 | |||
273 | // here we've got to fetch the fixed function lights from the | ||
274 | // driver and set them as constants | ||
275 | |||
276 | u32 cnt = driver->getDynamicLightCount(); | ||
277 | |||
278 | for (u32 i=0; i<2; ++i) | ||
279 | { | ||
280 | SLight light; | ||
281 | |||
282 | if (i<cnt) | ||
283 | light = driver->getDynamicLight(i); | ||
284 | else | ||
285 | { | ||
286 | light.DiffuseColor.set(0,0,0); // make light dark | ||
287 | light.Radius = 1.0f; | ||
288 | } | ||
289 | |||
290 | light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation | ||
291 | |||
292 | services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1); | ||
293 | services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1); | ||
294 | } | ||
295 | |||
296 | // this is not really necessary in d3d9 (used a def instruction), but to be sure: | ||
297 | f32 c95[] = {0.5f, 0.5f, 0.5f, 0.5f}; | ||
298 | services->setVertexShaderConstant(c95, 95, 1); | ||
299 | } | ||
300 | |||
301 | |||
302 | } // end namespace video | ||
303 | } // end namespace irr | ||
304 | |||
305 | #endif // _IRR_COMPILE_WITH_DIRECT3D_9_ | ||
306 | |||