diff options
author | David Walter Seikel | 2013-01-13 17:24:39 +1000 |
---|---|---|
committer | David Walter Seikel | 2013-01-13 17:24:39 +1000 |
commit | 393b5cd1dc438872af89d334ef6e5fcc59f27d47 (patch) | |
tree | 6a14521219942a08a1b95cb2f5a923a9edd60f63 /libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp | |
parent | Add a note about rasters suggested start up code. (diff) | |
download | SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.zip SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.gz SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.bz2 SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.xz |
Added Irrlicht 1.8, but without all the Windows binaries.
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp | 2722 |
1 files changed, 2722 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp new file mode 100644 index 0000000..bdde929 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp | |||
@@ -0,0 +1,2722 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten | ||
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 | #include "CSoftwareDriver2.h" | ||
7 | |||
8 | #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ | ||
9 | |||
10 | #include "SoftwareDriver2_helper.h" | ||
11 | #include "CSoftwareTexture2.h" | ||
12 | #include "CSoftware2MaterialRenderer.h" | ||
13 | #include "S3DVertex.h" | ||
14 | #include "S4DVertex.h" | ||
15 | #include "CBlit.h" | ||
16 | |||
17 | |||
18 | #define MAT_TEXTURE(tex) ( (video::CSoftwareTexture2*) Material.org.getTexture ( tex ) ) | ||
19 | |||
20 | |||
21 | namespace irr | ||
22 | { | ||
23 | namespace video | ||
24 | { | ||
25 | |||
26 | namespace glsl | ||
27 | { | ||
28 | |||
29 | typedef sVec4 vec4; | ||
30 | typedef sVec3 vec3; | ||
31 | typedef sVec2 vec2; | ||
32 | |||
33 | #define in | ||
34 | #define uniform | ||
35 | #define attribute | ||
36 | #define varying | ||
37 | |||
38 | #ifdef _MSC_VER | ||
39 | #pragma warning(disable:4244) | ||
40 | #endif | ||
41 | |||
42 | struct mat4{ | ||
43 | float m[4][4]; | ||
44 | |||
45 | vec4 operator* ( const vec4 &in ) const | ||
46 | { | ||
47 | vec4 out; | ||
48 | return out; | ||
49 | } | ||
50 | |||
51 | }; | ||
52 | |||
53 | struct mat3{ | ||
54 | float m[3][3]; | ||
55 | |||
56 | vec3 operator* ( const vec3 &in ) const | ||
57 | { | ||
58 | vec3 out; | ||
59 | return out; | ||
60 | } | ||
61 | }; | ||
62 | |||
63 | const int gl_MaxLights = 8; | ||
64 | |||
65 | |||
66 | inline float dot (float x, float y) { return x * y; } | ||
67 | inline float dot ( const vec2 &x, const vec2 &y) { return x.x * y.x + x.y * y.y; } | ||
68 | inline float dot ( const vec3 &x, const vec3 &y) { return x.x * y.x + x.y * y.y + x.z * y.z; } | ||
69 | inline float dot ( const vec4 &x, const vec4 &y) { return x.x * y.x + x.y * y.y + x.z * y.z + x.w * y.w; } | ||
70 | |||
71 | inline float reflect (float I, float N) { return I - 2.0 * dot (N, I) * N; } | ||
72 | inline vec2 reflect (const vec2 &I, const vec2 &N) { return I - N * 2.0 * dot (N, I); } | ||
73 | inline vec3 reflect (const vec3 &I, const vec3 &N) { return I - N * 2.0 * dot (N, I); } | ||
74 | inline vec4 reflect (const vec4 &I, const vec4 &N) { return I - N * 2.0 * dot (N, I); } | ||
75 | |||
76 | |||
77 | inline float refract (float I, float N, float eta){ | ||
78 | const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); | ||
79 | if (k < 0.0) | ||
80 | return 0.0; | ||
81 | return eta * I - (eta * dot (N, I) + sqrt (k)) * N; | ||
82 | } | ||
83 | |||
84 | inline vec2 refract (const vec2 &I, const vec2 &N, float eta){ | ||
85 | const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); | ||
86 | if (k < 0.0) | ||
87 | return vec2 (0.0); | ||
88 | return I * eta - N * (eta * dot (N, I) + sqrt (k)); | ||
89 | } | ||
90 | |||
91 | inline vec3 refract (const vec3 &I, const vec3 &N, float eta) { | ||
92 | const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); | ||
93 | if (k < 0.0) | ||
94 | return vec3 (0.0); | ||
95 | return I * eta - N * (eta * dot (N, I) + sqrt (k)); | ||
96 | } | ||
97 | |||
98 | inline vec4 refract (const vec4 &I, const vec4 &N, float eta) { | ||
99 | const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); | ||
100 | if (k < 0.0) | ||
101 | return vec4 (0.0); | ||
102 | return I * eta - N * (eta * dot (N, I) + sqrt (k)); | ||
103 | } | ||
104 | |||
105 | |||
106 | inline float length ( const vec3 &v ) { return sqrtf ( v.x * v.x + v.y * v.y + v.z * v.z ); } | ||
107 | vec3 normalize ( const vec3 &v ) { float l = 1.f / length ( v ); return vec3 ( v.x * l, v.y * l, v.z * l ); } | ||
108 | float max ( float a, float b ) { return a > b ? a : b; } | ||
109 | float min ( float a, float b ) { return a < b ? a : b; } | ||
110 | vec4 clamp ( const vec4 &a, f32 low, f32 high ) { return vec4 ( min (max(a.x,low), high), min (max(a.y,low), high), min (max(a.z,low), high), min (max(a.w,low), high) ); } | ||
111 | |||
112 | |||
113 | |||
114 | typedef int sampler2D; | ||
115 | sampler2D texUnit0; | ||
116 | |||
117 | vec4 texture2D (sampler2D sampler, const vec2 &coord) { return vec4 (0.0); } | ||
118 | |||
119 | struct gl_LightSourceParameters { | ||
120 | vec4 ambient; // Acli | ||
121 | vec4 diffuse; // Dcli | ||
122 | vec4 specular; // Scli | ||
123 | vec4 position; // Ppli | ||
124 | vec4 halfVector; // Derived: Hi | ||
125 | vec3 spotDirection; // Sdli | ||
126 | float spotExponent; // Srli | ||
127 | float spotCutoff; // Crli | ||
128 | // (range: [0.0,90.0], 180.0) | ||
129 | float spotCosCutoff; // Derived: cos(Crli) | ||
130 | // (range: [1.0,0.0],-1.0) | ||
131 | float constantAttenuation; // K0 | ||
132 | float linearAttenuation; // K1 | ||
133 | float quadraticAttenuation;// K2 | ||
134 | }; | ||
135 | |||
136 | uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights]; | ||
137 | |||
138 | struct gl_LightModelParameters { | ||
139 | vec4 ambient; | ||
140 | }; | ||
141 | uniform gl_LightModelParameters gl_LightModel; | ||
142 | |||
143 | struct gl_LightModelProducts { | ||
144 | vec4 sceneColor; | ||
145 | }; | ||
146 | |||
147 | uniform gl_LightModelProducts gl_FrontLightModelProduct; | ||
148 | uniform gl_LightModelProducts gl_BackLightModelProduct; | ||
149 | |||
150 | struct gl_LightProducts { | ||
151 | vec4 ambient; | ||
152 | vec4 diffuse; | ||
153 | vec4 specular; | ||
154 | }; | ||
155 | |||
156 | uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights]; | ||
157 | uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights]; | ||
158 | |||
159 | struct gl_MaterialParameters | ||
160 | { | ||
161 | vec4 emission; // Ecm | ||
162 | vec4 ambient; // Acm | ||
163 | vec4 diffuse; // Dcm | ||
164 | vec4 specular; // Scm | ||
165 | float shininess; // Srm | ||
166 | }; | ||
167 | uniform gl_MaterialParameters gl_FrontMaterial; | ||
168 | uniform gl_MaterialParameters gl_BackMaterial; | ||
169 | |||
170 | // GLSL has some built-in attributes in a vertex shader: | ||
171 | attribute vec4 gl_Vertex; // 4D vector representing the vertex position | ||
172 | attribute vec3 gl_Normal; // 3D vector representing the vertex normal | ||
173 | attribute vec4 gl_Color; // 4D vector representing the vertex color | ||
174 | attribute vec4 gl_MultiTexCoord0; // 4D vector representing the texture coordinate of texture unit X | ||
175 | attribute vec4 gl_MultiTexCoord1; // 4D vector representing the texture coordinate of texture unit X | ||
176 | |||
177 | uniform mat4 gl_ModelViewMatrix; //4x4 Matrix representing the model-view matrix. | ||
178 | uniform mat4 gl_ModelViewProjectionMatrix; //4x4 Matrix representing the model-view-projection matrix. | ||
179 | uniform mat3 gl_NormalMatrix; //3x3 Matrix representing the inverse transpose model-view matrix. This matrix is used for normal transformation. | ||
180 | |||
181 | |||
182 | varying vec4 gl_FrontColor; // 4D vector representing the primitives front color | ||
183 | varying vec4 gl_FrontSecondaryColor; // 4D vector representing the primitives second front color | ||
184 | varying vec4 gl_BackColor; // 4D vector representing the primitives back color | ||
185 | varying vec4 gl_TexCoord[4]; // 4D vector representing the Xth texture coordinate | ||
186 | |||
187 | // shader output | ||
188 | varying vec4 gl_Position; // 4D vector representing the final processed vertex position. Only available in vertex shader. | ||
189 | varying vec4 gl_FragColor; // 4D vector representing the final color which is written in the frame buffer. Only available in fragment shader. | ||
190 | varying float gl_FragDepth; // float representing the depth which is written in the depth buffer. Only available in fragment shader. | ||
191 | |||
192 | varying vec4 gl_SecondaryColor; | ||
193 | varying float gl_FogFragCoord; | ||
194 | |||
195 | |||
196 | vec4 ftransform(void) | ||
197 | { | ||
198 | return gl_ModelViewProjectionMatrix * gl_Vertex; | ||
199 | } | ||
200 | |||
201 | vec3 fnormal(void) | ||
202 | { | ||
203 | //Compute the normal | ||
204 | vec3 normal = gl_NormalMatrix * gl_Normal; | ||
205 | normal = normalize(normal); | ||
206 | return normal; | ||
207 | } | ||
208 | |||
209 | |||
210 | struct program1 | ||
211 | { | ||
212 | vec4 Ambient; | ||
213 | vec4 Diffuse; | ||
214 | vec4 Specular; | ||
215 | |||
216 | void pointLight(in int i, in vec3 normal, in vec3 eye, in vec3 ecPosition3) | ||
217 | { | ||
218 | float nDotVP; // normal . light direction | ||
219 | float nDotHV; // normal . light half vector | ||
220 | float pf; // power factor | ||
221 | float attenuation; // computed attenuation factor | ||
222 | float d; // distance from surface to light source | ||
223 | vec3 VP; // direction from surface to light position | ||
224 | vec3 halfVector; // direction of maximum highlights | ||
225 | |||
226 | // Compute vector from surface to light position | ||
227 | VP = vec3 (gl_LightSource[i].position) - ecPosition3; | ||
228 | |||
229 | // Compute distance between surface and light position | ||
230 | d = length(VP); | ||
231 | |||
232 | // Normalize the vector from surface to light position | ||
233 | VP = normalize(VP); | ||
234 | |||
235 | // Compute attenuation | ||
236 | attenuation = 1.0 / (gl_LightSource[i].constantAttenuation + | ||
237 | gl_LightSource[i].linearAttenuation * d + | ||
238 | gl_LightSource[i].quadraticAttenuation * d * d); | ||
239 | |||
240 | halfVector = normalize(VP + eye); | ||
241 | |||
242 | nDotVP = max(0.0, dot(normal, VP)); | ||
243 | nDotHV = max(0.0, dot(normal, halfVector)); | ||
244 | |||
245 | if (nDotVP == 0.0) | ||
246 | { | ||
247 | pf = 0.0; | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | pf = pow(nDotHV, gl_FrontMaterial.shininess); | ||
252 | |||
253 | } | ||
254 | Ambient += gl_LightSource[i].ambient * attenuation; | ||
255 | Diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation; | ||
256 | Specular += gl_LightSource[i].specular * pf * attenuation; | ||
257 | } | ||
258 | |||
259 | vec3 fnormal(void) | ||
260 | { | ||
261 | //Compute the normal | ||
262 | vec3 normal = gl_NormalMatrix * gl_Normal; | ||
263 | normal = normalize(normal); | ||
264 | return normal; | ||
265 | } | ||
266 | |||
267 | void ftexgen(in vec3 normal, in vec4 ecPosition) | ||
268 | { | ||
269 | |||
270 | gl_TexCoord[0] = gl_MultiTexCoord0; | ||
271 | } | ||
272 | |||
273 | void flight(in vec3 normal, in vec4 ecPosition, float alphaFade) | ||
274 | { | ||
275 | vec4 color; | ||
276 | vec3 ecPosition3; | ||
277 | vec3 eye; | ||
278 | |||
279 | ecPosition3 = (vec3 (ecPosition)) / ecPosition.w; | ||
280 | eye = vec3 (0.0, 0.0, 1.0); | ||
281 | |||
282 | // Clear the light intensity accumulators | ||
283 | Ambient = vec4 (0.0); | ||
284 | Diffuse = vec4 (0.0); | ||
285 | Specular = vec4 (0.0); | ||
286 | |||
287 | pointLight(0, normal, eye, ecPosition3); | ||
288 | |||
289 | pointLight(1, normal, eye, ecPosition3); | ||
290 | |||
291 | color = gl_FrontLightModelProduct.sceneColor + | ||
292 | Ambient * gl_FrontMaterial.ambient + | ||
293 | Diffuse * gl_FrontMaterial.diffuse; | ||
294 | gl_FrontSecondaryColor = Specular * gl_FrontMaterial.specular; | ||
295 | color = clamp( color, 0.0, 1.0 ); | ||
296 | gl_FrontColor = color; | ||
297 | |||
298 | gl_FrontColor.a *= alphaFade; | ||
299 | } | ||
300 | |||
301 | |||
302 | void vertexshader_main (void) | ||
303 | { | ||
304 | vec3 transformedNormal; | ||
305 | float alphaFade = 1.0; | ||
306 | |||
307 | // Eye-coordinate position of vertex, needed in various calculations | ||
308 | vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex; | ||
309 | |||
310 | // Do fixed functionality vertex transform | ||
311 | gl_Position = ftransform(); | ||
312 | transformedNormal = fnormal(); | ||
313 | flight(transformedNormal, ecPosition, alphaFade); | ||
314 | ftexgen(transformedNormal, ecPosition); | ||
315 | } | ||
316 | |||
317 | void fragmentshader_main (void) | ||
318 | { | ||
319 | vec4 color; | ||
320 | |||
321 | color = gl_Color; | ||
322 | |||
323 | color *= texture2D(texUnit0, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y) ); | ||
324 | |||
325 | color += gl_SecondaryColor; | ||
326 | color = clamp(color, 0.0, 1.0); | ||
327 | |||
328 | gl_FragColor = color; | ||
329 | } | ||
330 | }; | ||
331 | |||
332 | } | ||
333 | |||
334 | //! constructor | ||
335 | CBurningVideoDriver::CBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter) | ||
336 | : CNullDriver(io, params.WindowSize), BackBuffer(0), Presenter(presenter), | ||
337 | WindowId(0), SceneSourceRect(0), | ||
338 | RenderTargetTexture(0), RenderTargetSurface(0), CurrentShader(0), | ||
339 | DepthBuffer(0), StencilBuffer ( 0 ), | ||
340 | CurrentOut ( 12 * 2, 128 ), Temp ( 12 * 2, 128 ) | ||
341 | { | ||
342 | #ifdef _DEBUG | ||
343 | setDebugName("CBurningVideoDriver"); | ||
344 | #endif | ||
345 | |||
346 | // create backbuffer | ||
347 | BackBuffer = new CImage(BURNINGSHADER_COLOR_FORMAT, params.WindowSize); | ||
348 | if (BackBuffer) | ||
349 | { | ||
350 | BackBuffer->fill(SColor(0)); | ||
351 | |||
352 | // create z buffer | ||
353 | if ( params.ZBufferBits ) | ||
354 | DepthBuffer = video::createDepthBuffer(BackBuffer->getDimension()); | ||
355 | |||
356 | // create stencil buffer | ||
357 | if ( params.Stencilbuffer ) | ||
358 | StencilBuffer = video::createStencilBuffer(BackBuffer->getDimension()); | ||
359 | } | ||
360 | |||
361 | DriverAttributes->setAttribute("MaxTextures", 2); | ||
362 | DriverAttributes->setAttribute("MaxIndices", 1<<16); | ||
363 | DriverAttributes->setAttribute("MaxTextureSize", 1024); | ||
364 | DriverAttributes->setAttribute("MaxLights", glsl::gl_MaxLights); | ||
365 | DriverAttributes->setAttribute("MaxTextureLODBias", 16.f); | ||
366 | DriverAttributes->setAttribute("Version", 47); | ||
367 | |||
368 | // create triangle renderers | ||
369 | |||
370 | irr::memset32 ( BurningShader, 0, sizeof ( BurningShader ) ); | ||
371 | //BurningShader[ETR_FLAT] = createTRFlat2(DepthBuffer); | ||
372 | //BurningShader[ETR_FLAT_WIRE] = createTRFlatWire2(DepthBuffer); | ||
373 | BurningShader[ETR_GOURAUD] = createTriangleRendererGouraud2(this); | ||
374 | BurningShader[ETR_GOURAUD_ALPHA] = createTriangleRendererGouraudAlpha2(this ); | ||
375 | BurningShader[ETR_GOURAUD_ALPHA_NOZ] = createTRGouraudAlphaNoZ2(this ); | ||
376 | //BurningShader[ETR_GOURAUD_WIRE] = createTriangleRendererGouraudWire2(DepthBuffer); | ||
377 | //BurningShader[ETR_TEXTURE_FLAT] = createTriangleRendererTextureFlat2(DepthBuffer); | ||
378 | //BurningShader[ETR_TEXTURE_FLAT_WIRE] = createTriangleRendererTextureFlatWire2(DepthBuffer); | ||
379 | BurningShader[ETR_TEXTURE_GOURAUD] = createTriangleRendererTextureGouraud2(this); | ||
380 | BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M1] = createTriangleRendererTextureLightMap2_M1(this); | ||
381 | BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M2] = createTriangleRendererTextureLightMap2_M2(this); | ||
382 | BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M4] = createTriangleRendererGTextureLightMap2_M4(this); | ||
383 | BurningShader[ETR_TEXTURE_LIGHTMAP_M4] = createTriangleRendererTextureLightMap2_M4(this); | ||
384 | BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD] = createTriangleRendererTextureLightMap2_Add(this); | ||
385 | BurningShader[ETR_TEXTURE_GOURAUD_DETAIL_MAP] = createTriangleRendererTextureDetailMap2(this); | ||
386 | |||
387 | BurningShader[ETR_TEXTURE_GOURAUD_WIRE] = createTriangleRendererTextureGouraudWire2(this); | ||
388 | BurningShader[ETR_TEXTURE_GOURAUD_NOZ] = createTRTextureGouraudNoZ2(this); | ||
389 | BurningShader[ETR_TEXTURE_GOURAUD_ADD] = createTRTextureGouraudAdd2(this); | ||
390 | BurningShader[ETR_TEXTURE_GOURAUD_ADD_NO_Z] = createTRTextureGouraudAddNoZ2(this); | ||
391 | BurningShader[ETR_TEXTURE_GOURAUD_VERTEX_ALPHA] = createTriangleRendererTextureVertexAlpha2 ( this ); | ||
392 | |||
393 | BurningShader[ETR_TEXTURE_GOURAUD_ALPHA] = createTRTextureGouraudAlpha(this ); | ||
394 | BurningShader[ETR_TEXTURE_GOURAUD_ALPHA_NOZ] = createTRTextureGouraudAlphaNoZ( this ); | ||
395 | |||
396 | BurningShader[ETR_NORMAL_MAP_SOLID] = createTRNormalMap ( this ); | ||
397 | BurningShader[ETR_STENCIL_SHADOW] = createTRStencilShadow ( this ); | ||
398 | BurningShader[ETR_TEXTURE_BLEND] = createTRTextureBlend( this ); | ||
399 | |||
400 | BurningShader[ETR_REFERENCE] = createTriangleRendererReference ( this ); | ||
401 | |||
402 | |||
403 | // add the same renderer for all solid types | ||
404 | CSoftware2MaterialRenderer_SOLID* smr = new CSoftware2MaterialRenderer_SOLID( this); | ||
405 | CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR* tmr = new CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR( this); | ||
406 | CSoftware2MaterialRenderer_UNSUPPORTED * umr = new CSoftware2MaterialRenderer_UNSUPPORTED ( this ); | ||
407 | |||
408 | //!TODO: addMaterialRenderer depends on pushing order.... | ||
409 | addMaterialRenderer ( smr ); // EMT_SOLID | ||
410 | addMaterialRenderer ( smr ); // EMT_SOLID_2_LAYER, | ||
411 | addMaterialRenderer ( smr ); // EMT_LIGHTMAP, | ||
412 | addMaterialRenderer ( tmr ); // EMT_LIGHTMAP_ADD, | ||
413 | addMaterialRenderer ( smr ); // EMT_LIGHTMAP_M2, | ||
414 | addMaterialRenderer ( smr ); // EMT_LIGHTMAP_M4, | ||
415 | addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING, | ||
416 | addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING_M2, | ||
417 | addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING_M4, | ||
418 | addMaterialRenderer ( smr ); // EMT_DETAIL_MAP, | ||
419 | addMaterialRenderer ( umr ); // EMT_SPHERE_MAP, | ||
420 | addMaterialRenderer ( smr ); // EMT_REFLECTION_2_LAYER, | ||
421 | addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ADD_COLOR, | ||
422 | addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ALPHA_CHANNEL, | ||
423 | addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ALPHA_CHANNEL_REF, | ||
424 | addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_VERTEX_ALPHA, | ||
425 | addMaterialRenderer ( smr ); // EMT_TRANSPARENT_REFLECTION_2_LAYER, | ||
426 | addMaterialRenderer ( smr ); // EMT_NORMAL_MAP_SOLID, | ||
427 | addMaterialRenderer ( umr ); // EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR, | ||
428 | addMaterialRenderer ( tmr ); // EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA, | ||
429 | addMaterialRenderer ( smr ); // EMT_PARALLAX_MAP_SOLID, | ||
430 | addMaterialRenderer ( tmr ); // EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR, | ||
431 | addMaterialRenderer ( tmr ); // EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA, | ||
432 | addMaterialRenderer ( tmr ); // EMT_ONETEXTURE_BLEND | ||
433 | |||
434 | smr->drop (); | ||
435 | tmr->drop (); | ||
436 | umr->drop (); | ||
437 | |||
438 | // select render target | ||
439 | setRenderTarget(BackBuffer); | ||
440 | |||
441 | //reset Lightspace | ||
442 | LightSpace.reset (); | ||
443 | |||
444 | // select the right renderer | ||
445 | setCurrentShader(); | ||
446 | } | ||
447 | |||
448 | |||
449 | //! destructor | ||
450 | CBurningVideoDriver::~CBurningVideoDriver() | ||
451 | { | ||
452 | // delete Backbuffer | ||
453 | if (BackBuffer) | ||
454 | BackBuffer->drop(); | ||
455 | |||
456 | // delete triangle renderers | ||
457 | |||
458 | for (s32 i=0; i<ETR2_COUNT; ++i) | ||
459 | { | ||
460 | if (BurningShader[i]) | ||
461 | BurningShader[i]->drop(); | ||
462 | } | ||
463 | |||
464 | // delete Additional buffer | ||
465 | if (StencilBuffer) | ||
466 | StencilBuffer->drop(); | ||
467 | |||
468 | if (DepthBuffer) | ||
469 | DepthBuffer->drop(); | ||
470 | |||
471 | if (RenderTargetTexture) | ||
472 | RenderTargetTexture->drop(); | ||
473 | |||
474 | if (RenderTargetSurface) | ||
475 | RenderTargetSurface->drop(); | ||
476 | } | ||
477 | |||
478 | |||
479 | /*! | ||
480 | selects the right triangle renderer based on the render states. | ||
481 | */ | ||
482 | void CBurningVideoDriver::setCurrentShader() | ||
483 | { | ||
484 | ITexture *texture0 = Material.org.getTexture(0); | ||
485 | ITexture *texture1 = Material.org.getTexture(1); | ||
486 | |||
487 | bool zMaterialTest = Material.org.ZBuffer != ECFN_NEVER && | ||
488 | Material.org.ZWriteEnable && | ||
489 | ( AllowZWriteOnTransparent || !Material.org.isTransparent() ); | ||
490 | |||
491 | EBurningFFShader shader = zMaterialTest ? ETR_TEXTURE_GOURAUD : ETR_TEXTURE_GOURAUD_NOZ; | ||
492 | |||
493 | TransformationFlag[ ETS_TEXTURE_0] &= ~(ETF_TEXGEN_CAMERA_NORMAL|ETF_TEXGEN_CAMERA_REFLECTION); | ||
494 | LightSpace.Flags &= ~VERTEXTRANSFORM; | ||
495 | |||
496 | switch ( Material.org.MaterialType ) | ||
497 | { | ||
498 | case EMT_ONETEXTURE_BLEND: | ||
499 | shader = ETR_TEXTURE_BLEND; | ||
500 | break; | ||
501 | |||
502 | case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: | ||
503 | Material.org.MaterialTypeParam = 0.5f; | ||
504 | // fall through | ||
505 | case EMT_TRANSPARENT_ALPHA_CHANNEL: | ||
506 | if ( texture0 && texture0->hasAlpha () ) | ||
507 | { | ||
508 | shader = zMaterialTest ? ETR_TEXTURE_GOURAUD_ALPHA : ETR_TEXTURE_GOURAUD_ALPHA_NOZ; | ||
509 | break; | ||
510 | } | ||
511 | // fall through | ||
512 | |||
513 | case EMT_TRANSPARENT_ADD_COLOR: | ||
514 | shader = zMaterialTest ? ETR_TEXTURE_GOURAUD_ADD : ETR_TEXTURE_GOURAUD_ADD_NO_Z; | ||
515 | break; | ||
516 | |||
517 | case EMT_TRANSPARENT_VERTEX_ALPHA: | ||
518 | shader = ETR_TEXTURE_GOURAUD_VERTEX_ALPHA; | ||
519 | break; | ||
520 | |||
521 | case EMT_LIGHTMAP: | ||
522 | case EMT_LIGHTMAP_LIGHTING: | ||
523 | shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1; | ||
524 | break; | ||
525 | |||
526 | case EMT_LIGHTMAP_M2: | ||
527 | case EMT_LIGHTMAP_LIGHTING_M2: | ||
528 | shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M2; | ||
529 | break; | ||
530 | |||
531 | case EMT_LIGHTMAP_LIGHTING_M4: | ||
532 | if ( texture1 ) | ||
533 | shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M4; | ||
534 | break; | ||
535 | case EMT_LIGHTMAP_M4: | ||
536 | if ( texture1 ) | ||
537 | shader = ETR_TEXTURE_LIGHTMAP_M4; | ||
538 | break; | ||
539 | |||
540 | case EMT_LIGHTMAP_ADD: | ||
541 | if ( texture1 ) | ||
542 | shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD; | ||
543 | break; | ||
544 | |||
545 | case EMT_DETAIL_MAP: | ||
546 | shader = ETR_TEXTURE_GOURAUD_DETAIL_MAP; | ||
547 | break; | ||
548 | |||
549 | case EMT_SPHERE_MAP: | ||
550 | TransformationFlag[ ETS_TEXTURE_0] |= ETF_TEXGEN_CAMERA_REFLECTION; // ETF_TEXGEN_CAMERA_NORMAL; | ||
551 | LightSpace.Flags |= VERTEXTRANSFORM; | ||
552 | break; | ||
553 | case EMT_REFLECTION_2_LAYER: | ||
554 | shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1; | ||
555 | TransformationFlag[ ETS_TEXTURE_1] |= ETF_TEXGEN_CAMERA_REFLECTION; | ||
556 | LightSpace.Flags |= VERTEXTRANSFORM; | ||
557 | break; | ||
558 | |||
559 | case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: | ||
560 | case EMT_NORMAL_MAP_SOLID: | ||
561 | case EMT_PARALLAX_MAP_SOLID: | ||
562 | case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: | ||
563 | shader = ETR_NORMAL_MAP_SOLID; | ||
564 | LightSpace.Flags |= VERTEXTRANSFORM; | ||
565 | break; | ||
566 | |||
567 | default: | ||
568 | break; | ||
569 | |||
570 | } | ||
571 | |||
572 | if ( !texture0 ) | ||
573 | { | ||
574 | shader = ETR_GOURAUD; | ||
575 | } | ||
576 | |||
577 | if ( Material.org.Wireframe ) | ||
578 | { | ||
579 | shader = ETR_TEXTURE_GOURAUD_WIRE; | ||
580 | } | ||
581 | |||
582 | //shader = ETR_REFERENCE; | ||
583 | |||
584 | // switchToTriangleRenderer | ||
585 | CurrentShader = BurningShader[shader]; | ||
586 | if ( CurrentShader ) | ||
587 | { | ||
588 | CurrentShader->setZCompareFunc ( Material.org.ZBuffer ); | ||
589 | CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); | ||
590 | CurrentShader->setMaterial ( Material ); | ||
591 | |||
592 | switch ( shader ) | ||
593 | { | ||
594 | case ETR_TEXTURE_GOURAUD_ALPHA: | ||
595 | case ETR_TEXTURE_GOURAUD_ALPHA_NOZ: | ||
596 | case ETR_TEXTURE_BLEND: | ||
597 | CurrentShader->setParam ( 0, Material.org.MaterialTypeParam ); | ||
598 | break; | ||
599 | default: | ||
600 | break; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | } | ||
605 | |||
606 | |||
607 | |||
608 | //! queries the features of the driver, returns true if feature is available | ||
609 | bool CBurningVideoDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const | ||
610 | { | ||
611 | if (!FeatureEnabled[feature]) | ||
612 | return false; | ||
613 | |||
614 | switch (feature) | ||
615 | { | ||
616 | #ifdef SOFTWARE_DRIVER_2_BILINEAR | ||
617 | case EVDF_BILINEAR_FILTER: | ||
618 | return true; | ||
619 | #endif | ||
620 | #ifdef SOFTWARE_DRIVER_2_MIPMAPPING | ||
621 | case EVDF_MIP_MAP: | ||
622 | return true; | ||
623 | #endif | ||
624 | case EVDF_STENCIL_BUFFER: | ||
625 | case EVDF_RENDER_TO_TARGET: | ||
626 | case EVDF_MULTITEXTURE: | ||
627 | case EVDF_HARDWARE_TL: | ||
628 | case EVDF_TEXTURE_NSQUARE: | ||
629 | return true; | ||
630 | |||
631 | default: | ||
632 | return false; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | |||
637 | |||
638 | //! sets transformation | ||
639 | void CBurningVideoDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) | ||
640 | { | ||
641 | Transformation[state] = mat; | ||
642 | core::setbit_cond ( TransformationFlag[state], mat.isIdentity(), ETF_IDENTITY ); | ||
643 | |||
644 | switch ( state ) | ||
645 | { | ||
646 | case ETS_VIEW: | ||
647 | Transformation[ETS_VIEW_PROJECTION].setbyproduct_nocheck ( | ||
648 | Transformation[ETS_PROJECTION], | ||
649 | Transformation[ETS_VIEW] | ||
650 | ); | ||
651 | getCameraPosWorldSpace (); | ||
652 | break; | ||
653 | |||
654 | case ETS_WORLD: | ||
655 | if ( TransformationFlag[state] & ETF_IDENTITY ) | ||
656 | { | ||
657 | Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; | ||
658 | TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; | ||
659 | Transformation[ETS_CURRENT] = Transformation[ETS_VIEW_PROJECTION]; | ||
660 | } | ||
661 | else | ||
662 | { | ||
663 | //Transformation[ETS_WORLD].getInversePrimitive ( Transformation[ETS_WORLD_INVERSE] ); | ||
664 | Transformation[ETS_CURRENT].setbyproduct_nocheck ( | ||
665 | Transformation[ETS_VIEW_PROJECTION], | ||
666 | Transformation[ETS_WORLD] | ||
667 | ); | ||
668 | } | ||
669 | TransformationFlag[ETS_CURRENT] = 0; | ||
670 | //getLightPosObjectSpace (); | ||
671 | break; | ||
672 | case ETS_TEXTURE_0: | ||
673 | case ETS_TEXTURE_1: | ||
674 | case ETS_TEXTURE_2: | ||
675 | case ETS_TEXTURE_3: | ||
676 | if ( 0 == (TransformationFlag[state] & ETF_IDENTITY ) ) | ||
677 | LightSpace.Flags |= VERTEXTRANSFORM; | ||
678 | default: | ||
679 | break; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | |||
684 | //! clears the zbuffer | ||
685 | bool CBurningVideoDriver::beginScene(bool backBuffer, bool zBuffer, | ||
686 | SColor color, const SExposedVideoData& videoData, | ||
687 | core::rect<s32>* sourceRect) | ||
688 | { | ||
689 | CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect); | ||
690 | WindowId = videoData.D3D9.HWnd; | ||
691 | SceneSourceRect = sourceRect; | ||
692 | |||
693 | if (backBuffer && BackBuffer) | ||
694 | BackBuffer->fill(color); | ||
695 | |||
696 | if (zBuffer && DepthBuffer) | ||
697 | DepthBuffer->clear(); | ||
698 | |||
699 | memset ( TransformationFlag, 0, sizeof ( TransformationFlag ) ); | ||
700 | return true; | ||
701 | } | ||
702 | |||
703 | |||
704 | //! presents the rendered scene on the screen, returns false if failed | ||
705 | bool CBurningVideoDriver::endScene() | ||
706 | { | ||
707 | CNullDriver::endScene(); | ||
708 | |||
709 | return Presenter->present(BackBuffer, WindowId, SceneSourceRect); | ||
710 | } | ||
711 | |||
712 | |||
713 | //! sets a render target | ||
714 | bool CBurningVideoDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, | ||
715 | bool clearZBuffer, SColor color) | ||
716 | { | ||
717 | if (texture && texture->getDriverType() != EDT_BURNINGSVIDEO) | ||
718 | { | ||
719 | os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); | ||
720 | return false; | ||
721 | } | ||
722 | |||
723 | if (RenderTargetTexture) | ||
724 | RenderTargetTexture->drop(); | ||
725 | |||
726 | RenderTargetTexture = texture; | ||
727 | |||
728 | if (RenderTargetTexture) | ||
729 | { | ||
730 | RenderTargetTexture->grab(); | ||
731 | setRenderTarget(((CSoftwareTexture2*)RenderTargetTexture)->getTexture()); | ||
732 | } | ||
733 | else | ||
734 | { | ||
735 | setRenderTarget(BackBuffer); | ||
736 | } | ||
737 | |||
738 | if (RenderTargetSurface && (clearBackBuffer || clearZBuffer)) | ||
739 | { | ||
740 | if (clearZBuffer) | ||
741 | DepthBuffer->clear(); | ||
742 | |||
743 | if (clearBackBuffer) | ||
744 | RenderTargetSurface->fill( color ); | ||
745 | } | ||
746 | |||
747 | return true; | ||
748 | } | ||
749 | |||
750 | |||
751 | //! sets a render target | ||
752 | void CBurningVideoDriver::setRenderTarget(video::CImage* image) | ||
753 | { | ||
754 | if (RenderTargetSurface) | ||
755 | RenderTargetSurface->drop(); | ||
756 | |||
757 | RenderTargetSurface = image; | ||
758 | RenderTargetSize.Width = 0; | ||
759 | RenderTargetSize.Height = 0; | ||
760 | |||
761 | if (RenderTargetSurface) | ||
762 | { | ||
763 | RenderTargetSurface->grab(); | ||
764 | RenderTargetSize = RenderTargetSurface->getDimension(); | ||
765 | } | ||
766 | |||
767 | setViewPort(core::rect<s32>(0,0,RenderTargetSize.Width,RenderTargetSize.Height)); | ||
768 | |||
769 | if (DepthBuffer) | ||
770 | DepthBuffer->setSize(RenderTargetSize); | ||
771 | |||
772 | if (StencilBuffer) | ||
773 | StencilBuffer->setSize(RenderTargetSize); | ||
774 | } | ||
775 | |||
776 | |||
777 | |||
778 | //! sets a viewport | ||
779 | void CBurningVideoDriver::setViewPort(const core::rect<s32>& area) | ||
780 | { | ||
781 | ViewPort = area; | ||
782 | |||
783 | core::rect<s32> rendert(0,0,RenderTargetSize.Width,RenderTargetSize.Height); | ||
784 | ViewPort.clipAgainst(rendert); | ||
785 | |||
786 | Transformation [ ETS_CLIPSCALE ].buildNDCToDCMatrix ( ViewPort, 1 ); | ||
787 | |||
788 | if (CurrentShader) | ||
789 | CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); | ||
790 | } | ||
791 | |||
792 | /* | ||
793 | generic plane clipping in homogenous coordinates | ||
794 | special case ndc frustum <-w,w>,<-w,w>,<-w,w> | ||
795 | can be rewritten with compares e.q near plane, a.z < -a.w and b.z < -b.w | ||
796 | */ | ||
797 | |||
798 | const sVec4 CBurningVideoDriver::NDCPlane[6] = | ||
799 | { | ||
800 | sVec4( 0.f, 0.f, -1.f, -1.f ), // near | ||
801 | sVec4( 0.f, 0.f, 1.f, -1.f ), // far | ||
802 | sVec4( 1.f, 0.f, 0.f, -1.f ), // left | ||
803 | sVec4( -1.f, 0.f, 0.f, -1.f ), // right | ||
804 | sVec4( 0.f, 1.f, 0.f, -1.f ), // bottom | ||
805 | sVec4( 0.f, -1.f, 0.f, -1.f ) // top | ||
806 | }; | ||
807 | |||
808 | |||
809 | |||
810 | /* | ||
811 | test a vertex if it's inside the standard frustum | ||
812 | |||
813 | this is the generic one.. | ||
814 | |||
815 | f32 dotPlane; | ||
816 | for ( u32 i = 0; i!= 6; ++i ) | ||
817 | { | ||
818 | dotPlane = v->Pos.dotProduct ( NDCPlane[i] ); | ||
819 | core::setbit_cond( flag, dotPlane <= 0.f, 1 << i ); | ||
820 | } | ||
821 | |||
822 | // this is the base for ndc frustum <-w,w>,<-w,w>,<-w,w> | ||
823 | core::setbit_cond( flag, ( v->Pos.z - v->Pos.w ) <= 0.f, 1 ); | ||
824 | core::setbit_cond( flag, (-v->Pos.z - v->Pos.w ) <= 0.f, 2 ); | ||
825 | core::setbit_cond( flag, ( v->Pos.x - v->Pos.w ) <= 0.f, 4 ); | ||
826 | core::setbit_cond( flag, (-v->Pos.x - v->Pos.w ) <= 0.f, 8 ); | ||
827 | core::setbit_cond( flag, ( v->Pos.y - v->Pos.w ) <= 0.f, 16 ); | ||
828 | core::setbit_cond( flag, (-v->Pos.y - v->Pos.w ) <= 0.f, 32 ); | ||
829 | |||
830 | */ | ||
831 | #ifdef IRRLICHT_FAST_MATH | ||
832 | |||
833 | REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const | ||
834 | { | ||
835 | f32 test[6]; | ||
836 | u32 flag; | ||
837 | const f32 w = - v->Pos.w; | ||
838 | |||
839 | // a conditional move is needed....FCOMI ( but we don't have it ) | ||
840 | // so let the fpu calculate and write it back. | ||
841 | // cpu makes the compare, interleaving | ||
842 | |||
843 | test[0] = v->Pos.z + w; | ||
844 | test[1] = -v->Pos.z + w; | ||
845 | test[2] = v->Pos.x + w; | ||
846 | test[3] = -v->Pos.x + w; | ||
847 | test[4] = v->Pos.y + w; | ||
848 | test[5] = -v->Pos.y + w; | ||
849 | |||
850 | flag = (IR ( test[0] ) ) >> 31; | ||
851 | flag |= (IR ( test[1] ) & 0x80000000 ) >> 30; | ||
852 | flag |= (IR ( test[2] ) & 0x80000000 ) >> 29; | ||
853 | flag |= (IR ( test[3] ) & 0x80000000 ) >> 28; | ||
854 | flag |= (IR ( test[4] ) & 0x80000000 ) >> 27; | ||
855 | flag |= (IR ( test[5] ) & 0x80000000 ) >> 26; | ||
856 | |||
857 | /* | ||
858 | flag = F32_LOWER_EQUAL_0 ( test[0] ); | ||
859 | flag |= F32_LOWER_EQUAL_0 ( test[1] ) << 1; | ||
860 | flag |= F32_LOWER_EQUAL_0 ( test[2] ) << 2; | ||
861 | flag |= F32_LOWER_EQUAL_0 ( test[3] ) << 3; | ||
862 | flag |= F32_LOWER_EQUAL_0 ( test[4] ) << 4; | ||
863 | flag |= F32_LOWER_EQUAL_0 ( test[5] ) << 5; | ||
864 | */ | ||
865 | return flag; | ||
866 | } | ||
867 | |||
868 | #else | ||
869 | |||
870 | |||
871 | REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const | ||
872 | { | ||
873 | u32 flag = 0; | ||
874 | |||
875 | if ( v->Pos.z <= v->Pos.w ) flag |= 1; | ||
876 | if (-v->Pos.z <= v->Pos.w ) flag |= 2; | ||
877 | |||
878 | if ( v->Pos.x <= v->Pos.w ) flag |= 4; | ||
879 | if (-v->Pos.x <= v->Pos.w ) flag |= 8; | ||
880 | |||
881 | if ( v->Pos.y <= v->Pos.w ) flag |= 16; | ||
882 | if (-v->Pos.y <= v->Pos.w ) flag |= 32; | ||
883 | |||
884 | /* | ||
885 | for ( u32 i = 0; i!= 6; ++i ) | ||
886 | { | ||
887 | core::setbit_cond( flag, v->Pos.dotProduct ( NDCPlane[i] ) <= 0.f, 1 << i ); | ||
888 | } | ||
889 | */ | ||
890 | return flag; | ||
891 | } | ||
892 | |||
893 | #endif // _MSC_VER | ||
894 | |||
895 | u32 CBurningVideoDriver::clipToHyperPlane ( s4DVertex * dest, const s4DVertex * source, u32 inCount, const sVec4 &plane ) | ||
896 | { | ||
897 | u32 outCount = 0; | ||
898 | s4DVertex * out = dest; | ||
899 | |||
900 | const s4DVertex * a; | ||
901 | const s4DVertex * b = source; | ||
902 | |||
903 | f32 bDotPlane; | ||
904 | |||
905 | bDotPlane = b->Pos.dotProduct ( plane ); | ||
906 | |||
907 | for( u32 i = 1; i < inCount + 1; ++i) | ||
908 | { | ||
909 | const s32 condition = i - inCount; | ||
910 | const s32 index = (( ( condition >> 31 ) & ( i ^ condition ) ) ^ condition ) << 1; | ||
911 | |||
912 | a = &source[ index ]; | ||
913 | |||
914 | // current point inside | ||
915 | if ( a->Pos.dotProduct ( plane ) <= 0.f ) | ||
916 | { | ||
917 | // last point outside | ||
918 | if ( F32_GREATER_0 ( bDotPlane ) ) | ||
919 | { | ||
920 | // intersect line segment with plane | ||
921 | out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); | ||
922 | out += 2; | ||
923 | outCount += 1; | ||
924 | } | ||
925 | |||
926 | // copy current to out | ||
927 | //*out = *a; | ||
928 | irr::memcpy32_small ( out, a, SIZEOF_SVERTEX * 2 ); | ||
929 | b = out; | ||
930 | |||
931 | out += 2; | ||
932 | outCount += 1; | ||
933 | } | ||
934 | else | ||
935 | { | ||
936 | // current point outside | ||
937 | |||
938 | if ( F32_LOWER_EQUAL_0 ( bDotPlane ) ) | ||
939 | { | ||
940 | // previous was inside | ||
941 | // intersect line segment with plane | ||
942 | out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); | ||
943 | out += 2; | ||
944 | outCount += 1; | ||
945 | } | ||
946 | // pointer | ||
947 | b = a; | ||
948 | } | ||
949 | |||
950 | bDotPlane = b->Pos.dotProduct ( plane ); | ||
951 | |||
952 | } | ||
953 | |||
954 | return outCount; | ||
955 | } | ||
956 | |||
957 | |||
958 | u32 CBurningVideoDriver::clipToFrustum ( s4DVertex *v0, s4DVertex * v1, const u32 vIn ) | ||
959 | { | ||
960 | u32 vOut = vIn; | ||
961 | |||
962 | vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[0] ); if ( vOut < vIn ) return vOut; | ||
963 | vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[1] ); if ( vOut < vIn ) return vOut; | ||
964 | vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[2] ); if ( vOut < vIn ) return vOut; | ||
965 | vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[3] ); if ( vOut < vIn ) return vOut; | ||
966 | vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[4] ); if ( vOut < vIn ) return vOut; | ||
967 | vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[5] ); | ||
968 | return vOut; | ||
969 | } | ||
970 | |||
971 | /*! | ||
972 | Part I: | ||
973 | apply Clip Scale matrix | ||
974 | From Normalized Device Coordiante ( NDC ) Space to Device Coordinate Space ( DC ) | ||
975 | |||
976 | Part II: | ||
977 | Project homogeneous vector | ||
978 | homogeneous to non-homogenous coordinates ( dividebyW ) | ||
979 | |||
980 | Incoming: ( xw, yw, zw, w, u, v, 1, R, G, B, A ) | ||
981 | Outgoing: ( xw/w, yw/w, zw/w, w/w, u/w, v/w, 1/w, R/w, G/w, B/w, A/w ) | ||
982 | |||
983 | |||
984 | replace w/w by 1/w | ||
985 | */ | ||
986 | inline void CBurningVideoDriver::ndc_2_dc_and_project ( s4DVertex *dest,s4DVertex *source, u32 vIn ) const | ||
987 | { | ||
988 | u32 g; | ||
989 | |||
990 | for ( g = 0; g != vIn; g += 2 ) | ||
991 | { | ||
992 | if ( (dest[g].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) | ||
993 | continue; | ||
994 | |||
995 | dest[g].flag = source[g].flag | VERTEX4D_PROJECTED; | ||
996 | |||
997 | const f32 w = source[g].Pos.w; | ||
998 | const f32 iw = core::reciprocal ( w ); | ||
999 | |||
1000 | // to device coordinates | ||
1001 | dest[g].Pos.x = iw * ( source[g].Pos.x * Transformation [ ETS_CLIPSCALE ][ 0] + w * Transformation [ ETS_CLIPSCALE ][12] ); | ||
1002 | dest[g].Pos.y = iw * ( source[g].Pos.y * Transformation [ ETS_CLIPSCALE ][ 5] + w * Transformation [ ETS_CLIPSCALE ][13] ); | ||
1003 | |||
1004 | #ifndef SOFTWARE_DRIVER_2_USE_WBUFFER | ||
1005 | dest[g].Pos.z = iw * source[g].Pos.z; | ||
1006 | #endif | ||
1007 | |||
1008 | #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR | ||
1009 | #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT | ||
1010 | dest[g].Color[0] = source[g].Color[0] * iw; | ||
1011 | #else | ||
1012 | dest[g].Color[0] = source[g].Color[0]; | ||
1013 | #endif | ||
1014 | |||
1015 | #endif | ||
1016 | dest[g].LightTangent[0] = source[g].LightTangent[0] * iw; | ||
1017 | dest[g].Pos.w = iw; | ||
1018 | } | ||
1019 | } | ||
1020 | |||
1021 | |||
1022 | inline void CBurningVideoDriver::ndc_2_dc_and_project2 ( const s4DVertex **v, const u32 size ) const | ||
1023 | { | ||
1024 | u32 g; | ||
1025 | |||
1026 | for ( g = 0; g != size; g += 1 ) | ||
1027 | { | ||
1028 | s4DVertex * a = (s4DVertex*) v[g]; | ||
1029 | |||
1030 | if ( (a[1].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) | ||
1031 | continue; | ||
1032 | |||
1033 | a[1].flag = a->flag | VERTEX4D_PROJECTED; | ||
1034 | |||
1035 | // project homogenous vertex, store 1/w | ||
1036 | const f32 w = a->Pos.w; | ||
1037 | const f32 iw = core::reciprocal ( w ); | ||
1038 | |||
1039 | // to device coordinates | ||
1040 | const f32 * p = Transformation [ ETS_CLIPSCALE ].pointer(); | ||
1041 | a[1].Pos.x = iw * ( a->Pos.x * p[ 0] + w * p[12] ); | ||
1042 | a[1].Pos.y = iw * ( a->Pos.y * p[ 5] + w * p[13] ); | ||
1043 | |||
1044 | #ifndef SOFTWARE_DRIVER_2_USE_WBUFFER | ||
1045 | a[1].Pos.z = a->Pos.z * iw; | ||
1046 | #endif | ||
1047 | |||
1048 | #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR | ||
1049 | #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT | ||
1050 | a[1].Color[0] = a->Color[0] * iw; | ||
1051 | #else | ||
1052 | a[1].Color[0] = a->Color[0]; | ||
1053 | #endif | ||
1054 | #endif | ||
1055 | |||
1056 | a[1].LightTangent[0] = a[0].LightTangent[0] * iw; | ||
1057 | a[1].Pos.w = iw; | ||
1058 | |||
1059 | } | ||
1060 | |||
1061 | } | ||
1062 | |||
1063 | |||
1064 | /*! | ||
1065 | crossproduct in projected 2D -> screen area triangle | ||
1066 | */ | ||
1067 | inline f32 CBurningVideoDriver::screenarea ( const s4DVertex *v ) const | ||
1068 | { | ||
1069 | return ( ( v[3].Pos.x - v[1].Pos.x ) * ( v[5].Pos.y - v[1].Pos.y ) ) - | ||
1070 | ( ( v[3].Pos.y - v[1].Pos.y ) * ( v[5].Pos.x - v[1].Pos.x ) ); | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | /*! | ||
1075 | */ | ||
1076 | inline f32 CBurningVideoDriver::texelarea ( const s4DVertex *v, int tex ) const | ||
1077 | { | ||
1078 | f32 z; | ||
1079 | |||
1080 | z = ( (v[2].Tex[tex].x - v[0].Tex[tex].x ) * (v[4].Tex[tex].y - v[0].Tex[tex].y ) ) | ||
1081 | - ( (v[4].Tex[tex].x - v[0].Tex[tex].x ) * (v[2].Tex[tex].y - v[0].Tex[tex].y ) ); | ||
1082 | |||
1083 | return MAT_TEXTURE ( tex )->getLODFactor ( z ); | ||
1084 | } | ||
1085 | |||
1086 | /*! | ||
1087 | crossproduct in projected 2D | ||
1088 | */ | ||
1089 | inline f32 CBurningVideoDriver::screenarea2 ( const s4DVertex **v ) const | ||
1090 | { | ||
1091 | return ( (( v[1] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) * ( (v[2] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) ) - | ||
1092 | ( (( v[1] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) * ( (v[2] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) ); | ||
1093 | } | ||
1094 | |||
1095 | /*! | ||
1096 | */ | ||
1097 | inline f32 CBurningVideoDriver::texelarea2 ( const s4DVertex **v, s32 tex ) const | ||
1098 | { | ||
1099 | f32 z; | ||
1100 | z = ( (v[1]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[2]->Tex[tex].y - v[0]->Tex[tex].y ) ) | ||
1101 | - ( (v[2]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[1]->Tex[tex].y - v[0]->Tex[tex].y ) ); | ||
1102 | |||
1103 | return MAT_TEXTURE ( tex )->getLODFactor ( z ); | ||
1104 | } | ||
1105 | |||
1106 | |||
1107 | /*! | ||
1108 | */ | ||
1109 | inline void CBurningVideoDriver::select_polygon_mipmap ( s4DVertex *v, u32 vIn, u32 tex, const core::dimension2du& texSize ) const | ||
1110 | { | ||
1111 | f32 f[2]; | ||
1112 | |||
1113 | f[0] = (f32) texSize.Width - 0.25f; | ||
1114 | f[1] = (f32) texSize.Height - 0.25f; | ||
1115 | |||
1116 | #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT | ||
1117 | for ( u32 g = 0; g != vIn; g += 2 ) | ||
1118 | { | ||
1119 | (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * ( v + g + 1 )->Pos.w * f[0]; | ||
1120 | (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * ( v + g + 1 )->Pos.w * f[1]; | ||
1121 | } | ||
1122 | #else | ||
1123 | for ( u32 g = 0; g != vIn; g += 2 ) | ||
1124 | { | ||
1125 | (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * f[0]; | ||
1126 | (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * f[1]; | ||
1127 | } | ||
1128 | #endif | ||
1129 | } | ||
1130 | |||
1131 | inline void CBurningVideoDriver::select_polygon_mipmap2 ( s4DVertex **v, u32 tex, const core::dimension2du& texSize ) const | ||
1132 | { | ||
1133 | f32 f[2]; | ||
1134 | |||
1135 | f[0] = (f32) texSize.Width - 0.25f; | ||
1136 | f[1] = (f32) texSize.Height - 0.25f; | ||
1137 | |||
1138 | #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT | ||
1139 | (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * ( v[0] + 1 )->Pos.w * f[0]; | ||
1140 | (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * ( v[0] + 1 )->Pos.w * f[1]; | ||
1141 | |||
1142 | (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * ( v[1] + 1 )->Pos.w * f[0]; | ||
1143 | (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * ( v[1] + 1 )->Pos.w * f[1]; | ||
1144 | |||
1145 | (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * ( v[2] + 1 )->Pos.w * f[0]; | ||
1146 | (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * ( v[2] + 1 )->Pos.w * f[1]; | ||
1147 | |||
1148 | #else | ||
1149 | (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * f[0]; | ||
1150 | (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * f[1]; | ||
1151 | |||
1152 | (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * f[0]; | ||
1153 | (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * f[1]; | ||
1154 | |||
1155 | (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * f[0]; | ||
1156 | (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * f[1]; | ||
1157 | #endif | ||
1158 | } | ||
1159 | |||
1160 | // Vertex Cache | ||
1161 | const SVSize CBurningVideoDriver::vSize[] = | ||
1162 | { | ||
1163 | { VERTEX4D_FORMAT_TEXTURE_1 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 1 }, | ||
1164 | { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex2TCoords),2 }, | ||
1165 | { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1 | VERTEX4D_FORMAT_BUMP_DOT3, sizeof(S3DVertexTangents),2 }, | ||
1166 | { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 2 }, // reflection map | ||
1167 | { 0, sizeof(f32) * 3, 0 }, // core::vector3df* | ||
1168 | }; | ||
1169 | |||
1170 | |||
1171 | |||
1172 | /*! | ||
1173 | fill a cache line with transformed, light and clipp test triangles | ||
1174 | */ | ||
1175 | void CBurningVideoDriver::VertexCache_fill(const u32 sourceIndex, const u32 destIndex) | ||
1176 | { | ||
1177 | u8 * source; | ||
1178 | s4DVertex *dest; | ||
1179 | |||
1180 | source = (u8*) VertexCache.vertices + ( sourceIndex * vSize[VertexCache.vType].Pitch ); | ||
1181 | |||
1182 | // it's a look ahead so we never hit it.. | ||
1183 | // but give priority... | ||
1184 | //VertexCache.info[ destIndex ].hit = hitCount; | ||
1185 | |||
1186 | // store info | ||
1187 | VertexCache.info[ destIndex ].index = sourceIndex; | ||
1188 | VertexCache.info[ destIndex ].hit = 0; | ||
1189 | |||
1190 | // destination Vertex | ||
1191 | dest = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( destIndex << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1192 | |||
1193 | // transform Model * World * Camera * Projection * NDCSpace matrix | ||
1194 | const S3DVertex *base = ((S3DVertex*) source ); | ||
1195 | Transformation [ ETS_CURRENT].transformVect ( &dest->Pos.x, base->Pos ); | ||
1196 | |||
1197 | //mhm ;-) maybe no goto | ||
1198 | if ( VertexCache.vType == 4 ) goto clipandproject; | ||
1199 | |||
1200 | |||
1201 | #if defined (SOFTWARE_DRIVER_2_LIGHTING) || defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) | ||
1202 | |||
1203 | // vertex normal in light space | ||
1204 | if ( Material.org.Lighting || (LightSpace.Flags & VERTEXTRANSFORM) ) | ||
1205 | { | ||
1206 | if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) | ||
1207 | { | ||
1208 | LightSpace.normal.set ( base->Normal.X, base->Normal.Y, base->Normal.Z, 1.f ); | ||
1209 | LightSpace.vertex.set ( base->Pos.X, base->Pos.Y, base->Pos.Z, 1.f ); | ||
1210 | } | ||
1211 | else | ||
1212 | { | ||
1213 | Transformation[ETS_WORLD].rotateVect ( &LightSpace.normal.x, base->Normal ); | ||
1214 | |||
1215 | // vertex in light space | ||
1216 | if ( LightSpace.Flags & ( POINTLIGHT | FOG | SPECULAR | VERTEXTRANSFORM) ) | ||
1217 | Transformation[ETS_WORLD].transformVect ( &LightSpace.vertex.x, base->Pos ); | ||
1218 | } | ||
1219 | |||
1220 | if ( LightSpace.Flags & NORMALIZE ) | ||
1221 | LightSpace.normal.normalize_xyz(); | ||
1222 | |||
1223 | } | ||
1224 | |||
1225 | #endif | ||
1226 | |||
1227 | #if defined ( SOFTWARE_DRIVER_2_USE_VERTEX_COLOR ) | ||
1228 | // apply lighting model | ||
1229 | #if defined (SOFTWARE_DRIVER_2_LIGHTING) | ||
1230 | if ( Material.org.Lighting ) | ||
1231 | { | ||
1232 | lightVertex ( dest, base->Color.color ); | ||
1233 | } | ||
1234 | else | ||
1235 | { | ||
1236 | dest->Color[0].setA8R8G8B8 ( base->Color.color ); | ||
1237 | } | ||
1238 | #else | ||
1239 | dest->Color[0].setA8R8G8B8 ( base->Color.color ); | ||
1240 | #endif | ||
1241 | #endif | ||
1242 | |||
1243 | // Texture Transform | ||
1244 | #if !defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) | ||
1245 | irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, | ||
1246 | vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) | ||
1247 | ); | ||
1248 | #else | ||
1249 | |||
1250 | if ( 0 == (LightSpace.Flags & VERTEXTRANSFORM) ) | ||
1251 | { | ||
1252 | irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, | ||
1253 | vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) | ||
1254 | ); | ||
1255 | } | ||
1256 | else | ||
1257 | { | ||
1258 | /* | ||
1259 | Generate texture coordinates as linear functions so that: | ||
1260 | u = Ux*x + Uy*y + Uz*z + Uw | ||
1261 | v = Vx*x + Vy*y + Vz*z + Vw | ||
1262 | The matrix M for this case is: | ||
1263 | Ux Vx 0 0 | ||
1264 | Uy Vy 0 0 | ||
1265 | Uz Vz 0 0 | ||
1266 | Uw Vw 0 0 | ||
1267 | */ | ||
1268 | |||
1269 | u32 t; | ||
1270 | sVec4 n; | ||
1271 | sVec2 srcT; | ||
1272 | |||
1273 | for ( t = 0; t != vSize[VertexCache.vType].TexSize; ++t ) | ||
1274 | { | ||
1275 | const core::matrix4& M = Transformation [ ETS_TEXTURE_0 + t ]; | ||
1276 | |||
1277 | // texgen | ||
1278 | if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & (ETF_TEXGEN_CAMERA_NORMAL|ETF_TEXGEN_CAMERA_REFLECTION) ) | ||
1279 | { | ||
1280 | n.x = LightSpace.campos.x - LightSpace.vertex.x; | ||
1281 | n.y = LightSpace.campos.x - LightSpace.vertex.y; | ||
1282 | n.z = LightSpace.campos.x - LightSpace.vertex.z; | ||
1283 | n.normalize_xyz(); | ||
1284 | n.x += LightSpace.normal.x; | ||
1285 | n.y += LightSpace.normal.y; | ||
1286 | n.z += LightSpace.normal.z; | ||
1287 | n.normalize_xyz(); | ||
1288 | |||
1289 | const f32 *view = Transformation[ETS_VIEW].pointer(); | ||
1290 | |||
1291 | if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & ETF_TEXGEN_CAMERA_REFLECTION ) | ||
1292 | { | ||
1293 | srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[4] + n.z * view[8] )); | ||
1294 | srcT.y = 0.5f * ( 1.f + (n.x * view[1] + n.y * view[5] + n.z * view[9] )); | ||
1295 | } | ||
1296 | else | ||
1297 | { | ||
1298 | srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[1] + n.z * view[2] )); | ||
1299 | srcT.y = 0.5f * ( 1.f + (n.x * view[4] + n.y * view[5] + n.z * view[6] )); | ||
1300 | } | ||
1301 | } | ||
1302 | else | ||
1303 | { | ||
1304 | irr::memcpy32_small ( &srcT,(&base->TCoords) + t, | ||
1305 | sizeof ( f32 ) * 2 ); | ||
1306 | } | ||
1307 | |||
1308 | switch ( Material.org.TextureLayer[t].TextureWrapU ) | ||
1309 | { | ||
1310 | case ETC_CLAMP: | ||
1311 | case ETC_CLAMP_TO_EDGE: | ||
1312 | case ETC_CLAMP_TO_BORDER: | ||
1313 | dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); | ||
1314 | break; | ||
1315 | case ETC_MIRROR: | ||
1316 | dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; | ||
1317 | if (core::fract(dest->Tex[t].x)>0.5f) | ||
1318 | dest->Tex[t].x=1.f-dest->Tex[t].x; | ||
1319 | break; | ||
1320 | case ETC_MIRROR_CLAMP: | ||
1321 | case ETC_MIRROR_CLAMP_TO_EDGE: | ||
1322 | case ETC_MIRROR_CLAMP_TO_BORDER: | ||
1323 | dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); | ||
1324 | if (core::fract(dest->Tex[t].x)>0.5f) | ||
1325 | dest->Tex[t].x=1.f-dest->Tex[t].x; | ||
1326 | break; | ||
1327 | case ETC_REPEAT: | ||
1328 | default: | ||
1329 | dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; | ||
1330 | break; | ||
1331 | } | ||
1332 | switch ( Material.org.TextureLayer[t].TextureWrapV ) | ||
1333 | { | ||
1334 | case ETC_CLAMP: | ||
1335 | case ETC_CLAMP_TO_EDGE: | ||
1336 | case ETC_CLAMP_TO_BORDER: | ||
1337 | dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); | ||
1338 | break; | ||
1339 | case ETC_MIRROR: | ||
1340 | dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; | ||
1341 | if (core::fract(dest->Tex[t].y)>0.5f) | ||
1342 | dest->Tex[t].y=1.f-dest->Tex[t].y; | ||
1343 | break; | ||
1344 | case ETC_MIRROR_CLAMP: | ||
1345 | case ETC_MIRROR_CLAMP_TO_EDGE: | ||
1346 | case ETC_MIRROR_CLAMP_TO_BORDER: | ||
1347 | dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); | ||
1348 | if (core::fract(dest->Tex[t].y)>0.5f) | ||
1349 | dest->Tex[t].y=1.f-dest->Tex[t].y; | ||
1350 | break; | ||
1351 | case ETC_REPEAT: | ||
1352 | default: | ||
1353 | dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; | ||
1354 | break; | ||
1355 | } | ||
1356 | } | ||
1357 | } | ||
1358 | |||
1359 | #if 0 | ||
1360 | // tangent space light vector, emboss | ||
1361 | if ( Lights.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) | ||
1362 | { | ||
1363 | const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); | ||
1364 | const SBurningShaderLight &light = LightSpace.Light[0]; | ||
1365 | |||
1366 | sVec4 vp; | ||
1367 | |||
1368 | vp.x = light.pos.x - LightSpace.vertex.x; | ||
1369 | vp.y = light.pos.y - LightSpace.vertex.y; | ||
1370 | vp.z = light.pos.z - LightSpace.vertex.z; | ||
1371 | |||
1372 | vp.normalize_xyz(); | ||
1373 | |||
1374 | LightSpace.tangent.x = vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z; | ||
1375 | LightSpace.tangent.y = vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z; | ||
1376 | //LightSpace.tangent.z = vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z; | ||
1377 | LightSpace.tangent.z = 0.f; | ||
1378 | LightSpace.tangent.normalize_xyz(); | ||
1379 | |||
1380 | f32 scale = 1.f / 128.f; | ||
1381 | if ( Material.org.MaterialTypeParam > 0.f ) | ||
1382 | scale = Material.org.MaterialTypeParam; | ||
1383 | |||
1384 | // emboss, shift coordinates | ||
1385 | dest->Tex[1].x = dest->Tex[0].x + LightSpace.tangent.x * scale; | ||
1386 | dest->Tex[1].y = dest->Tex[0].y + LightSpace.tangent.y * scale; | ||
1387 | //dest->Tex[1].z = LightSpace.tangent.z * scale; | ||
1388 | } | ||
1389 | #endif | ||
1390 | |||
1391 | if ( LightSpace.Light.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) | ||
1392 | { | ||
1393 | const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); | ||
1394 | |||
1395 | sVec4 vp; | ||
1396 | |||
1397 | dest->LightTangent[0].x = 0.f; | ||
1398 | dest->LightTangent[0].y = 0.f; | ||
1399 | dest->LightTangent[0].z = 0.f; | ||
1400 | for ( u32 i = 0; i < 2 && i < LightSpace.Light.size (); ++i ) | ||
1401 | { | ||
1402 | const SBurningShaderLight &light = LightSpace.Light[i]; | ||
1403 | |||
1404 | if ( !light.LightIsOn ) | ||
1405 | continue; | ||
1406 | |||
1407 | vp.x = light.pos.x - LightSpace.vertex.x; | ||
1408 | vp.y = light.pos.y - LightSpace.vertex.y; | ||
1409 | vp.z = light.pos.z - LightSpace.vertex.z; | ||
1410 | |||
1411 | /* | ||
1412 | vp.x = light.pos_objectspace.x - base->Pos.X; | ||
1413 | vp.y = light.pos_objectspace.y - base->Pos.Y; | ||
1414 | vp.z = light.pos_objectspace.z - base->Pos.Z; | ||
1415 | */ | ||
1416 | |||
1417 | vp.normalize_xyz(); | ||
1418 | |||
1419 | |||
1420 | // transform by tangent matrix | ||
1421 | sVec3 l; | ||
1422 | #if 1 | ||
1423 | l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z ); | ||
1424 | l.y = (vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z ); | ||
1425 | l.z = (vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z ); | ||
1426 | #else | ||
1427 | l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Binormal.X + vp.z * tangent->Normal.X ); | ||
1428 | l.y = (vp.x * tangent->Tangent.Y + vp.y * tangent->Binormal.Y + vp.z * tangent->Normal.Y ); | ||
1429 | l.z = (vp.x * tangent->Tangent.Z + vp.y * tangent->Binormal.Z + vp.z * tangent->Normal.Z ); | ||
1430 | #endif | ||
1431 | |||
1432 | |||
1433 | /* | ||
1434 | f32 scale = 1.f / 128.f; | ||
1435 | scale /= dest->LightTangent[0].b; | ||
1436 | |||
1437 | // emboss, shift coordinates | ||
1438 | dest->Tex[1].x = dest->Tex[0].x + l.r * scale; | ||
1439 | dest->Tex[1].y = dest->Tex[0].y + l.g * scale; | ||
1440 | */ | ||
1441 | dest->Tex[1].x = dest->Tex[0].x; | ||
1442 | dest->Tex[1].y = dest->Tex[0].y; | ||
1443 | |||
1444 | // scale bias | ||
1445 | dest->LightTangent[0].x += l.x; | ||
1446 | dest->LightTangent[0].y += l.y; | ||
1447 | dest->LightTangent[0].z += l.z; | ||
1448 | } | ||
1449 | dest->LightTangent[0].setLength ( 0.5f ); | ||
1450 | dest->LightTangent[0].x += 0.5f; | ||
1451 | dest->LightTangent[0].y += 0.5f; | ||
1452 | dest->LightTangent[0].z += 0.5f; | ||
1453 | } | ||
1454 | |||
1455 | |||
1456 | #endif | ||
1457 | |||
1458 | clipandproject: | ||
1459 | dest[0].flag = dest[1].flag = vSize[VertexCache.vType].Format; | ||
1460 | |||
1461 | // test vertex | ||
1462 | dest[0].flag |= clipToFrustumTest ( dest); | ||
1463 | |||
1464 | // to DC Space, project homogenous vertex | ||
1465 | if ( (dest[0].flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) | ||
1466 | { | ||
1467 | ndc_2_dc_and_project2 ( (const s4DVertex**) &dest, 1 ); | ||
1468 | } | ||
1469 | |||
1470 | //return dest; | ||
1471 | } | ||
1472 | |||
1473 | // | ||
1474 | |||
1475 | REALINLINE s4DVertex * CBurningVideoDriver::VertexCache_getVertex ( const u32 sourceIndex ) | ||
1476 | { | ||
1477 | for ( s32 i = 0; i < VERTEXCACHE_ELEMENT; ++i ) | ||
1478 | { | ||
1479 | if ( VertexCache.info[ i ].index == sourceIndex ) | ||
1480 | { | ||
1481 | return (s4DVertex *) ( (u8*) VertexCache.mem.data + ( i << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1482 | } | ||
1483 | } | ||
1484 | return 0; | ||
1485 | } | ||
1486 | |||
1487 | |||
1488 | /* | ||
1489 | Cache based on linear walk indices | ||
1490 | fill blockwise on the next 16(Cache_Size) unique vertices in indexlist | ||
1491 | merge the next 16 vertices with the current | ||
1492 | */ | ||
1493 | REALINLINE void CBurningVideoDriver::VertexCache_get(const s4DVertex ** face) | ||
1494 | { | ||
1495 | SCacheInfo info[VERTEXCACHE_ELEMENT]; | ||
1496 | |||
1497 | // next primitive must be complete in cache | ||
1498 | if ( VertexCache.indicesIndex - VertexCache.indicesRun < 3 && | ||
1499 | VertexCache.indicesIndex < VertexCache.indexCount | ||
1500 | ) | ||
1501 | { | ||
1502 | // rewind to start of primitive | ||
1503 | VertexCache.indicesIndex = VertexCache.indicesRun; | ||
1504 | |||
1505 | irr::memset32 ( info, VERTEXCACHE_MISS, sizeof ( info ) ); | ||
1506 | |||
1507 | // get the next unique vertices cache line | ||
1508 | u32 fillIndex = 0; | ||
1509 | u32 dIndex; | ||
1510 | u32 i; | ||
1511 | u32 sourceIndex; | ||
1512 | |||
1513 | while ( VertexCache.indicesIndex < VertexCache.indexCount && | ||
1514 | fillIndex < VERTEXCACHE_ELEMENT | ||
1515 | ) | ||
1516 | { | ||
1517 | switch ( VertexCache.iType ) | ||
1518 | { | ||
1519 | case 1: | ||
1520 | sourceIndex = ((u16*)VertexCache.indices) [ VertexCache.indicesIndex ]; | ||
1521 | break; | ||
1522 | case 2: | ||
1523 | sourceIndex = ((u32*)VertexCache.indices) [ VertexCache.indicesIndex ]; | ||
1524 | break; | ||
1525 | case 4: | ||
1526 | sourceIndex = VertexCache.indicesIndex; | ||
1527 | break; | ||
1528 | } | ||
1529 | |||
1530 | VertexCache.indicesIndex += 1; | ||
1531 | |||
1532 | // if not exist, push back | ||
1533 | s32 exist = 0; | ||
1534 | for ( dIndex = 0; dIndex < fillIndex; ++dIndex ) | ||
1535 | { | ||
1536 | if ( info[ dIndex ].index == sourceIndex ) | ||
1537 | { | ||
1538 | exist = 1; | ||
1539 | break; | ||
1540 | } | ||
1541 | } | ||
1542 | |||
1543 | if ( 0 == exist ) | ||
1544 | { | ||
1545 | info[fillIndex++].index = sourceIndex; | ||
1546 | } | ||
1547 | } | ||
1548 | |||
1549 | // clear marks | ||
1550 | for ( i = 0; i!= VERTEXCACHE_ELEMENT; ++i ) | ||
1551 | { | ||
1552 | VertexCache.info[i].hit = 0; | ||
1553 | } | ||
1554 | |||
1555 | // mark all existing | ||
1556 | for ( i = 0; i!= fillIndex; ++i ) | ||
1557 | { | ||
1558 | for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) | ||
1559 | { | ||
1560 | if ( VertexCache.info[ dIndex ].index == info[i].index ) | ||
1561 | { | ||
1562 | info[i].hit = dIndex; | ||
1563 | VertexCache.info[ dIndex ].hit = 1; | ||
1564 | break; | ||
1565 | } | ||
1566 | } | ||
1567 | } | ||
1568 | |||
1569 | // fill new | ||
1570 | for ( i = 0; i!= fillIndex; ++i ) | ||
1571 | { | ||
1572 | if ( info[i].hit != VERTEXCACHE_MISS ) | ||
1573 | continue; | ||
1574 | |||
1575 | for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) | ||
1576 | { | ||
1577 | if ( 0 == VertexCache.info[dIndex].hit ) | ||
1578 | { | ||
1579 | VertexCache_fill ( info[i].index, dIndex ); | ||
1580 | VertexCache.info[dIndex].hit += 1; | ||
1581 | info[i].hit = dIndex; | ||
1582 | break; | ||
1583 | } | ||
1584 | } | ||
1585 | } | ||
1586 | } | ||
1587 | |||
1588 | const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); | ||
1589 | |||
1590 | switch ( VertexCache.iType ) | ||
1591 | { | ||
1592 | case 1: | ||
1593 | { | ||
1594 | const u16 *p = (const u16 *) VertexCache.indices; | ||
1595 | face[0] = VertexCache_getVertex ( p[ i0 ] ); | ||
1596 | face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); | ||
1597 | face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); | ||
1598 | } | ||
1599 | break; | ||
1600 | |||
1601 | case 2: | ||
1602 | { | ||
1603 | const u32 *p = (const u32 *) VertexCache.indices; | ||
1604 | face[0] = VertexCache_getVertex ( p[ i0 ] ); | ||
1605 | face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); | ||
1606 | face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); | ||
1607 | } | ||
1608 | break; | ||
1609 | |||
1610 | case 4: | ||
1611 | face[0] = VertexCache_getVertex ( VertexCache.indicesRun + 0 ); | ||
1612 | face[1] = VertexCache_getVertex ( VertexCache.indicesRun + 1 ); | ||
1613 | face[2] = VertexCache_getVertex ( VertexCache.indicesRun + 2 ); | ||
1614 | break; | ||
1615 | default: | ||
1616 | face[0] = face[1] = face[2] = VertexCache_getVertex(VertexCache.indicesRun + 0); | ||
1617 | break; | ||
1618 | } | ||
1619 | |||
1620 | VertexCache.indicesRun += VertexCache.primitivePitch; | ||
1621 | } | ||
1622 | |||
1623 | /*! | ||
1624 | */ | ||
1625 | REALINLINE void CBurningVideoDriver::VertexCache_getbypass ( s4DVertex ** face ) | ||
1626 | { | ||
1627 | const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); | ||
1628 | |||
1629 | if ( VertexCache.iType == 1 ) | ||
1630 | { | ||
1631 | const u16 *p = (const u16 *) VertexCache.indices; | ||
1632 | VertexCache_fill ( p[ i0 ], 0 ); | ||
1633 | VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); | ||
1634 | VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); | ||
1635 | } | ||
1636 | else | ||
1637 | { | ||
1638 | const u32 *p = (const u32 *) VertexCache.indices; | ||
1639 | VertexCache_fill ( p[ i0 ], 0 ); | ||
1640 | VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); | ||
1641 | VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); | ||
1642 | } | ||
1643 | |||
1644 | VertexCache.indicesRun += VertexCache.primitivePitch; | ||
1645 | |||
1646 | face[0] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1647 | face[1] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1648 | face[2] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1649 | |||
1650 | } | ||
1651 | |||
1652 | /*! | ||
1653 | */ | ||
1654 | void CBurningVideoDriver::VertexCache_reset ( const void* vertices, u32 vertexCount, | ||
1655 | const void* indices, u32 primitiveCount, | ||
1656 | E_VERTEX_TYPE vType, | ||
1657 | scene::E_PRIMITIVE_TYPE pType, | ||
1658 | E_INDEX_TYPE iType) | ||
1659 | { | ||
1660 | VertexCache.vertices = vertices; | ||
1661 | VertexCache.vertexCount = vertexCount; | ||
1662 | |||
1663 | VertexCache.indices = indices; | ||
1664 | VertexCache.indicesIndex = 0; | ||
1665 | VertexCache.indicesRun = 0; | ||
1666 | |||
1667 | if ( Material.org.MaterialType == video::EMT_REFLECTION_2_LAYER ) | ||
1668 | VertexCache.vType = 3; | ||
1669 | else | ||
1670 | VertexCache.vType = vType; | ||
1671 | VertexCache.pType = pType; | ||
1672 | |||
1673 | switch ( iType ) | ||
1674 | { | ||
1675 | case EIT_16BIT: VertexCache.iType = 1; break; | ||
1676 | case EIT_32BIT: VertexCache.iType = 2; break; | ||
1677 | default: | ||
1678 | VertexCache.iType = iType; break; | ||
1679 | } | ||
1680 | |||
1681 | switch ( VertexCache.pType ) | ||
1682 | { | ||
1683 | // most types here will not work as expected, only triangles/triangle_fan | ||
1684 | // is known to work. | ||
1685 | case scene::EPT_POINTS: | ||
1686 | VertexCache.indexCount = primitiveCount; | ||
1687 | VertexCache.primitivePitch = 1; | ||
1688 | break; | ||
1689 | case scene::EPT_LINE_STRIP: | ||
1690 | VertexCache.indexCount = primitiveCount+1; | ||
1691 | VertexCache.primitivePitch = 1; | ||
1692 | break; | ||
1693 | case scene::EPT_LINE_LOOP: | ||
1694 | VertexCache.indexCount = primitiveCount+1; | ||
1695 | VertexCache.primitivePitch = 1; | ||
1696 | break; | ||
1697 | case scene::EPT_LINES: | ||
1698 | VertexCache.indexCount = 2*primitiveCount; | ||
1699 | VertexCache.primitivePitch = 2; | ||
1700 | break; | ||
1701 | case scene::EPT_TRIANGLE_STRIP: | ||
1702 | VertexCache.indexCount = primitiveCount+2; | ||
1703 | VertexCache.primitivePitch = 1; | ||
1704 | break; | ||
1705 | case scene::EPT_TRIANGLES: | ||
1706 | VertexCache.indexCount = primitiveCount + primitiveCount + primitiveCount; | ||
1707 | VertexCache.primitivePitch = 3; | ||
1708 | break; | ||
1709 | case scene::EPT_TRIANGLE_FAN: | ||
1710 | VertexCache.indexCount = primitiveCount + 2; | ||
1711 | VertexCache.primitivePitch = 1; | ||
1712 | break; | ||
1713 | case scene::EPT_QUAD_STRIP: | ||
1714 | VertexCache.indexCount = 2*primitiveCount + 2; | ||
1715 | VertexCache.primitivePitch = 2; | ||
1716 | break; | ||
1717 | case scene::EPT_QUADS: | ||
1718 | VertexCache.indexCount = 4*primitiveCount; | ||
1719 | VertexCache.primitivePitch = 4; | ||
1720 | break; | ||
1721 | case scene::EPT_POLYGON: | ||
1722 | VertexCache.indexCount = primitiveCount+1; | ||
1723 | VertexCache.primitivePitch = 1; | ||
1724 | break; | ||
1725 | case scene::EPT_POINT_SPRITES: | ||
1726 | VertexCache.indexCount = primitiveCount; | ||
1727 | VertexCache.primitivePitch = 1; | ||
1728 | break; | ||
1729 | } | ||
1730 | |||
1731 | irr::memset32 ( VertexCache.info, VERTEXCACHE_MISS, sizeof ( VertexCache.info ) ); | ||
1732 | } | ||
1733 | |||
1734 | |||
1735 | void CBurningVideoDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, | ||
1736 | const void* indexList, u32 primitiveCount, | ||
1737 | E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) | ||
1738 | |||
1739 | { | ||
1740 | if (!checkPrimitiveCount(primitiveCount)) | ||
1741 | return; | ||
1742 | |||
1743 | CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); | ||
1744 | |||
1745 | // These calls would lead to crashes due to wrong index usage. | ||
1746 | // The vertex cache needs to be rewritten for these primitives. | ||
1747 | if (pType==scene::EPT_POINTS || pType==scene::EPT_LINE_STRIP || | ||
1748 | pType==scene::EPT_LINE_LOOP || pType==scene::EPT_LINES || pType==scene::EPT_POLYGON || | ||
1749 | pType==scene::EPT_POINT_SPRITES) | ||
1750 | return; | ||
1751 | |||
1752 | if ( 0 == CurrentShader ) | ||
1753 | return; | ||
1754 | |||
1755 | VertexCache_reset ( vertices, vertexCount, indexList, primitiveCount, vType, pType, iType ); | ||
1756 | |||
1757 | const s4DVertex * face[3]; | ||
1758 | |||
1759 | f32 dc_area; | ||
1760 | s32 lodLevel; | ||
1761 | u32 i; | ||
1762 | u32 g; | ||
1763 | u32 m; | ||
1764 | video::CSoftwareTexture2* tex; | ||
1765 | |||
1766 | for ( i = 0; i < (u32) primitiveCount; ++i ) | ||
1767 | { | ||
1768 | VertexCache_get(face); | ||
1769 | |||
1770 | // if fully outside or outside on same side | ||
1771 | if ( ( (face[0]->flag | face[1]->flag | face[2]->flag) & VERTEX4D_CLIPMASK ) | ||
1772 | != VERTEX4D_INSIDE | ||
1773 | ) | ||
1774 | continue; | ||
1775 | |||
1776 | // if fully inside | ||
1777 | if ( ( face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) | ||
1778 | { | ||
1779 | dc_area = screenarea2 ( face ); | ||
1780 | if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0( dc_area ) ) | ||
1781 | continue; | ||
1782 | else | ||
1783 | if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) | ||
1784 | continue; | ||
1785 | |||
1786 | // select mipmap | ||
1787 | dc_area = core::reciprocal ( dc_area ); | ||
1788 | for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) | ||
1789 | { | ||
1790 | if ( 0 == (tex = MAT_TEXTURE ( m )) ) | ||
1791 | { | ||
1792 | CurrentShader->setTextureParam(m, 0, 0); | ||
1793 | continue; | ||
1794 | } | ||
1795 | |||
1796 | lodLevel = s32_log2_f32 ( texelarea2 ( face, m ) * dc_area ); | ||
1797 | CurrentShader->setTextureParam(m, tex, lodLevel ); | ||
1798 | select_polygon_mipmap2 ( (s4DVertex**) face, m, tex->getSize() ); | ||
1799 | } | ||
1800 | |||
1801 | // rasterize | ||
1802 | CurrentShader->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); | ||
1803 | continue; | ||
1804 | } | ||
1805 | |||
1806 | // else if not complete inside clipping necessary | ||
1807 | irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[0], SIZEOF_SVERTEX * 2 ); | ||
1808 | irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[1], SIZEOF_SVERTEX * 2 ); | ||
1809 | irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[2], SIZEOF_SVERTEX * 2 ); | ||
1810 | |||
1811 | const u32 flag = CurrentOut.data->flag & VERTEX4D_FORMAT_MASK; | ||
1812 | |||
1813 | for ( g = 0; g != CurrentOut.ElementSize; ++g ) | ||
1814 | { | ||
1815 | CurrentOut.data[g].flag = flag; | ||
1816 | Temp.data[g].flag = flag; | ||
1817 | } | ||
1818 | |||
1819 | u32 vOut; | ||
1820 | vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); | ||
1821 | if ( vOut < 3 ) | ||
1822 | continue; | ||
1823 | |||
1824 | vOut <<= 1; | ||
1825 | |||
1826 | // to DC Space, project homogenous vertex | ||
1827 | ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); | ||
1828 | |||
1829 | /* | ||
1830 | // TODO: don't stick on 32 Bit Pointer | ||
1831 | #define PointerAsValue(x) ( (u32) (u32*) (x) ) | ||
1832 | |||
1833 | // if not complete inside clipping necessary | ||
1834 | if ( ( test & VERTEX4D_INSIDE ) != VERTEX4D_INSIDE ) | ||
1835 | { | ||
1836 | u32 v[2] = { PointerAsValue ( Temp ) , PointerAsValue ( CurrentOut ) }; | ||
1837 | for ( g = 0; g != 6; ++g ) | ||
1838 | { | ||
1839 | vOut = clipToHyperPlane ( (s4DVertex*) v[0], (s4DVertex*) v[1], vOut, NDCPlane[g] ); | ||
1840 | if ( vOut < 3 ) | ||
1841 | break; | ||
1842 | |||
1843 | v[0] ^= v[1]; | ||
1844 | v[1] ^= v[0]; | ||
1845 | v[0] ^= v[1]; | ||
1846 | } | ||
1847 | |||
1848 | if ( vOut < 3 ) | ||
1849 | continue; | ||
1850 | |||
1851 | } | ||
1852 | */ | ||
1853 | |||
1854 | // check 2d backface culling on first | ||
1855 | dc_area = screenarea ( CurrentOut.data ); | ||
1856 | if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0 ( dc_area ) ) | ||
1857 | continue; | ||
1858 | else if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) | ||
1859 | continue; | ||
1860 | |||
1861 | // select mipmap | ||
1862 | dc_area = core::reciprocal ( dc_area ); | ||
1863 | for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) | ||
1864 | { | ||
1865 | if ( 0 == (tex = MAT_TEXTURE ( m )) ) | ||
1866 | { | ||
1867 | CurrentShader->setTextureParam(m, 0, 0); | ||
1868 | continue; | ||
1869 | } | ||
1870 | |||
1871 | lodLevel = s32_log2_f32 ( texelarea ( CurrentOut.data, m ) * dc_area ); | ||
1872 | CurrentShader->setTextureParam(m, tex, lodLevel ); | ||
1873 | select_polygon_mipmap ( CurrentOut.data, vOut, m, tex->getSize() ); | ||
1874 | } | ||
1875 | |||
1876 | |||
1877 | // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) | ||
1878 | for ( g = 0; g <= vOut - 6; g += 2 ) | ||
1879 | { | ||
1880 | // rasterize | ||
1881 | CurrentShader->drawTriangle ( CurrentOut.data + 0 + 1, | ||
1882 | CurrentOut.data + g + 3, | ||
1883 | CurrentOut.data + g + 5); | ||
1884 | } | ||
1885 | |||
1886 | } | ||
1887 | |||
1888 | // dump statistics | ||
1889 | /* | ||
1890 | char buf [64]; | ||
1891 | sprintf ( buf,"VCount:%d PCount:%d CacheMiss: %d", | ||
1892 | vertexCount, primitiveCount, | ||
1893 | VertexCache.CacheMiss | ||
1894 | ); | ||
1895 | os::Printer::log( buf ); | ||
1896 | */ | ||
1897 | |||
1898 | } | ||
1899 | |||
1900 | |||
1901 | //! Sets the dynamic ambient light color. The default color is | ||
1902 | //! (0,0,0,0) which means it is dark. | ||
1903 | //! \param color: New color of the ambient light. | ||
1904 | void CBurningVideoDriver::setAmbientLight(const SColorf& color) | ||
1905 | { | ||
1906 | LightSpace.Global_AmbientLight.setColorf ( color ); | ||
1907 | } | ||
1908 | |||
1909 | |||
1910 | //! adds a dynamic light | ||
1911 | s32 CBurningVideoDriver::addDynamicLight(const SLight& dl) | ||
1912 | { | ||
1913 | (void) CNullDriver::addDynamicLight( dl ); | ||
1914 | |||
1915 | SBurningShaderLight l; | ||
1916 | // l.org = dl; | ||
1917 | l.Type = dl.Type; | ||
1918 | l.LightIsOn = true; | ||
1919 | |||
1920 | l.AmbientColor.setColorf ( dl.AmbientColor ); | ||
1921 | l.DiffuseColor.setColorf ( dl.DiffuseColor ); | ||
1922 | l.SpecularColor.setColorf ( dl.SpecularColor ); | ||
1923 | |||
1924 | switch ( dl.Type ) | ||
1925 | { | ||
1926 | case video::ELT_DIRECTIONAL: | ||
1927 | l.pos.x = -dl.Direction.X; | ||
1928 | l.pos.y = -dl.Direction.Y; | ||
1929 | l.pos.z = -dl.Direction.Z; | ||
1930 | l.pos.w = 1.f; | ||
1931 | break; | ||
1932 | case ELT_POINT: | ||
1933 | case ELT_SPOT: | ||
1934 | LightSpace.Flags |= POINTLIGHT; | ||
1935 | l.pos.x = dl.Position.X; | ||
1936 | l.pos.y = dl.Position.Y; | ||
1937 | l.pos.z = dl.Position.Z; | ||
1938 | l.pos.w = 1.f; | ||
1939 | /* | ||
1940 | l.radius = (1.f / dl.Attenuation.Y) * (1.f / dl.Attenuation.Y); | ||
1941 | l.constantAttenuation = dl.Attenuation.X; | ||
1942 | l.linearAttenuation = dl.Attenuation.Y; | ||
1943 | l.quadraticAttenuation = dl.Attenuation.Z; | ||
1944 | */ | ||
1945 | l.radius = dl.Radius * dl.Radius; | ||
1946 | l.constantAttenuation = dl.Attenuation.X; | ||
1947 | l.linearAttenuation = 1.f / dl.Radius; | ||
1948 | l.quadraticAttenuation = dl.Attenuation.Z; | ||
1949 | |||
1950 | break; | ||
1951 | default: | ||
1952 | break; | ||
1953 | } | ||
1954 | |||
1955 | LightSpace.Light.push_back ( l ); | ||
1956 | return LightSpace.Light.size() - 1; | ||
1957 | } | ||
1958 | |||
1959 | //! Turns a dynamic light on or off | ||
1960 | void CBurningVideoDriver::turnLightOn(s32 lightIndex, bool turnOn) | ||
1961 | { | ||
1962 | if(lightIndex > -1 && lightIndex < (s32)LightSpace.Light.size()) | ||
1963 | { | ||
1964 | LightSpace.Light[lightIndex].LightIsOn = turnOn; | ||
1965 | } | ||
1966 | } | ||
1967 | |||
1968 | //! deletes all dynamic lights there are | ||
1969 | void CBurningVideoDriver::deleteAllDynamicLights() | ||
1970 | { | ||
1971 | LightSpace.reset (); | ||
1972 | CNullDriver::deleteAllDynamicLights(); | ||
1973 | |||
1974 | } | ||
1975 | |||
1976 | //! returns the maximal amount of dynamic lights the device can handle | ||
1977 | u32 CBurningVideoDriver::getMaximalDynamicLightAmount() const | ||
1978 | { | ||
1979 | return 8; | ||
1980 | } | ||
1981 | |||
1982 | |||
1983 | //! sets a material | ||
1984 | void CBurningVideoDriver::setMaterial(const SMaterial& material) | ||
1985 | { | ||
1986 | Material.org = material; | ||
1987 | |||
1988 | #ifdef SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM | ||
1989 | for (u32 i = 0; i < 2; ++i) | ||
1990 | { | ||
1991 | setTransform((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i), | ||
1992 | material.getTextureMatrix(i)); | ||
1993 | } | ||
1994 | #endif | ||
1995 | |||
1996 | #ifdef SOFTWARE_DRIVER_2_LIGHTING | ||
1997 | Material.AmbientColor.setR8G8B8 ( Material.org.AmbientColor.color ); | ||
1998 | Material.DiffuseColor.setR8G8B8 ( Material.org.DiffuseColor.color ); | ||
1999 | Material.EmissiveColor.setR8G8B8 ( Material.org.EmissiveColor.color ); | ||
2000 | Material.SpecularColor.setR8G8B8 ( Material.org.SpecularColor.color ); | ||
2001 | |||
2002 | core::setbit_cond ( LightSpace.Flags, Material.org.Shininess != 0.f, SPECULAR ); | ||
2003 | core::setbit_cond ( LightSpace.Flags, Material.org.FogEnable, FOG ); | ||
2004 | core::setbit_cond ( LightSpace.Flags, Material.org.NormalizeNormals, NORMALIZE ); | ||
2005 | #endif | ||
2006 | |||
2007 | setCurrentShader(); | ||
2008 | } | ||
2009 | |||
2010 | |||
2011 | /*! | ||
2012 | Camera Position in World Space | ||
2013 | */ | ||
2014 | void CBurningVideoDriver::getCameraPosWorldSpace () | ||
2015 | { | ||
2016 | Transformation[ETS_VIEW_INVERSE] = Transformation[ ETS_VIEW ]; | ||
2017 | Transformation[ETS_VIEW_INVERSE].makeInverse (); | ||
2018 | TransformationFlag[ETS_VIEW_INVERSE] = 0; | ||
2019 | |||
2020 | const f32 *M = Transformation[ETS_VIEW_INVERSE].pointer (); | ||
2021 | |||
2022 | /* The viewpoint is at (0., 0., 0.) in eye space. | ||
2023 | Turning this into a vector [0 0 0 1] and multiply it by | ||
2024 | the inverse of the view matrix, the resulting vector is the | ||
2025 | object space location of the camera. | ||
2026 | */ | ||
2027 | |||
2028 | LightSpace.campos.x = M[12]; | ||
2029 | LightSpace.campos.y = M[13]; | ||
2030 | LightSpace.campos.z = M[14]; | ||
2031 | LightSpace.campos.w = 1.f; | ||
2032 | } | ||
2033 | |||
2034 | void CBurningVideoDriver::getLightPosObjectSpace () | ||
2035 | { | ||
2036 | if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) | ||
2037 | { | ||
2038 | Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; | ||
2039 | TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; | ||
2040 | } | ||
2041 | else | ||
2042 | { | ||
2043 | Transformation[ETS_WORLD].getInverse ( Transformation[ETS_WORLD_INVERSE] ); | ||
2044 | TransformationFlag[ETS_WORLD_INVERSE] &= ~ETF_IDENTITY; | ||
2045 | } | ||
2046 | |||
2047 | for ( u32 i = 0; i < 1 && i < LightSpace.Light.size(); ++i ) | ||
2048 | { | ||
2049 | SBurningShaderLight &l = LightSpace.Light[i]; | ||
2050 | |||
2051 | Transformation[ETS_WORLD_INVERSE].transformVec3 ( &l.pos_objectspace.x, &l.pos.x ); | ||
2052 | } | ||
2053 | } | ||
2054 | |||
2055 | |||
2056 | #ifdef SOFTWARE_DRIVER_2_LIGHTING | ||
2057 | |||
2058 | //! Sets the fog mode. | ||
2059 | void CBurningVideoDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, | ||
2060 | f32 end, f32 density, bool pixelFog, bool rangeFog) | ||
2061 | { | ||
2062 | CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog); | ||
2063 | LightSpace.FogColor.setA8R8G8B8 ( color.color ); | ||
2064 | } | ||
2065 | |||
2066 | /*! | ||
2067 | applies lighting model | ||
2068 | */ | ||
2069 | void CBurningVideoDriver::lightVertex ( s4DVertex *dest, u32 vertexargb ) | ||
2070 | { | ||
2071 | sVec3 dColor; | ||
2072 | |||
2073 | dColor = LightSpace.Global_AmbientLight; | ||
2074 | dColor.add ( Material.EmissiveColor ); | ||
2075 | |||
2076 | if ( Lights.size () == 0 ) | ||
2077 | { | ||
2078 | dColor.saturate( dest->Color[0], vertexargb); | ||
2079 | return; | ||
2080 | } | ||
2081 | |||
2082 | sVec3 ambient; | ||
2083 | sVec3 diffuse; | ||
2084 | sVec3 specular; | ||
2085 | |||
2086 | |||
2087 | // the universe started in darkness.. | ||
2088 | ambient.set ( 0.f, 0.f, 0.f ); | ||
2089 | diffuse.set ( 0.f, 0.f, 0.f ); | ||
2090 | specular.set ( 0.f, 0.f, 0.f ); | ||
2091 | |||
2092 | |||
2093 | u32 i; | ||
2094 | f32 dot; | ||
2095 | f32 len; | ||
2096 | f32 attenuation; | ||
2097 | sVec4 vp; // unit vector vertex to light | ||
2098 | sVec4 lightHalf; // blinn-phong reflection | ||
2099 | |||
2100 | for ( i = 0; i!= LightSpace.Light.size (); ++i ) | ||
2101 | { | ||
2102 | const SBurningShaderLight &light = LightSpace.Light[i]; | ||
2103 | |||
2104 | if ( !light.LightIsOn ) | ||
2105 | continue; | ||
2106 | |||
2107 | // accumulate ambient | ||
2108 | ambient.add ( light.AmbientColor ); | ||
2109 | |||
2110 | switch ( light.Type ) | ||
2111 | { | ||
2112 | case video::ELT_SPOT: | ||
2113 | case video::ELT_POINT: | ||
2114 | // surface to light | ||
2115 | vp.x = light.pos.x - LightSpace.vertex.x; | ||
2116 | vp.y = light.pos.y - LightSpace.vertex.y; | ||
2117 | vp.z = light.pos.z - LightSpace.vertex.z; | ||
2118 | //vp.x = light.pos_objectspace.x - LightSpace.vertex.x; | ||
2119 | //vp.y = light.pos_objectspace.y - LightSpace.vertex.x; | ||
2120 | //vp.z = light.pos_objectspace.z - LightSpace.vertex.x; | ||
2121 | |||
2122 | len = vp.get_length_xyz_square(); | ||
2123 | if ( light.radius < len ) | ||
2124 | continue; | ||
2125 | |||
2126 | len = core::reciprocal_squareroot ( len ); | ||
2127 | |||
2128 | // build diffuse reflection | ||
2129 | |||
2130 | //angle between normal and light vector | ||
2131 | vp.mul ( len ); | ||
2132 | dot = LightSpace.normal.dot_xyz ( vp ); | ||
2133 | if ( dot < 0.f ) | ||
2134 | continue; | ||
2135 | |||
2136 | attenuation = light.constantAttenuation + ( 1.f - ( len * light.linearAttenuation ) ); | ||
2137 | |||
2138 | // diffuse component | ||
2139 | diffuse.mulAdd ( light.DiffuseColor, 3.f * dot * attenuation ); | ||
2140 | |||
2141 | if ( !(LightSpace.Flags & SPECULAR) ) | ||
2142 | continue; | ||
2143 | |||
2144 | // build specular | ||
2145 | // surface to view | ||
2146 | lightHalf.x = LightSpace.campos.x - LightSpace.vertex.x; | ||
2147 | lightHalf.y = LightSpace.campos.y - LightSpace.vertex.y; | ||
2148 | lightHalf.z = LightSpace.campos.z - LightSpace.vertex.z; | ||
2149 | lightHalf.normalize_xyz(); | ||
2150 | lightHalf += vp; | ||
2151 | lightHalf.normalize_xyz(); | ||
2152 | |||
2153 | // specular | ||
2154 | dot = LightSpace.normal.dot_xyz ( lightHalf ); | ||
2155 | if ( dot < 0.f ) | ||
2156 | continue; | ||
2157 | |||
2158 | //specular += light.SpecularColor * ( powf ( Material.org.Shininess ,dot ) * attenuation ); | ||
2159 | specular.mulAdd ( light.SpecularColor, dot * attenuation ); | ||
2160 | break; | ||
2161 | |||
2162 | case video::ELT_DIRECTIONAL: | ||
2163 | |||
2164 | //angle between normal and light vector | ||
2165 | dot = LightSpace.normal.dot_xyz ( light.pos ); | ||
2166 | if ( dot < 0.f ) | ||
2167 | continue; | ||
2168 | |||
2169 | // diffuse component | ||
2170 | diffuse.mulAdd ( light.DiffuseColor, dot ); | ||
2171 | break; | ||
2172 | default: | ||
2173 | break; | ||
2174 | } | ||
2175 | |||
2176 | } | ||
2177 | |||
2178 | // sum up lights | ||
2179 | dColor.mulAdd (ambient, Material.AmbientColor ); | ||
2180 | dColor.mulAdd (diffuse, Material.DiffuseColor); | ||
2181 | dColor.mulAdd (specular, Material.SpecularColor); | ||
2182 | |||
2183 | dColor.saturate ( dest->Color[0], vertexargb ); | ||
2184 | } | ||
2185 | |||
2186 | #endif | ||
2187 | |||
2188 | |||
2189 | //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. | ||
2190 | void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos, | ||
2191 | const core::rect<s32>& sourceRect, | ||
2192 | const core::rect<s32>* clipRect, SColor color, | ||
2193 | bool useAlphaChannelOfTexture) | ||
2194 | { | ||
2195 | if (texture) | ||
2196 | { | ||
2197 | if (texture->getDriverType() != EDT_BURNINGSVIDEO) | ||
2198 | { | ||
2199 | os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); | ||
2200 | return; | ||
2201 | } | ||
2202 | |||
2203 | #if 0 | ||
2204 | // 2d methods don't use viewPort | ||
2205 | core::position2di dest = destPos; | ||
2206 | core::recti clip=ViewPort; | ||
2207 | if (ViewPort.getSize().Width != ScreenSize.Width) | ||
2208 | { | ||
2209 | dest.X=ViewPort.UpperLeftCorner.X+core::round32(destPos.X*ViewPort.getWidth()/(f32)ScreenSize.Width); | ||
2210 | dest.Y=ViewPort.UpperLeftCorner.Y+core::round32(destPos.Y*ViewPort.getHeight()/(f32)ScreenSize.Height); | ||
2211 | if (clipRect) | ||
2212 | { | ||
2213 | clip.constrainTo(*clipRect); | ||
2214 | } | ||
2215 | clipRect = &clip; | ||
2216 | } | ||
2217 | #endif | ||
2218 | if (useAlphaChannelOfTexture) | ||
2219 | ((CSoftwareTexture2*)texture)->getImage()->copyToWithAlpha( | ||
2220 | RenderTargetSurface, destPos, sourceRect, color, clipRect); | ||
2221 | else | ||
2222 | ((CSoftwareTexture2*)texture)->getImage()->copyTo( | ||
2223 | RenderTargetSurface, destPos, sourceRect, clipRect); | ||
2224 | } | ||
2225 | } | ||
2226 | |||
2227 | |||
2228 | //! Draws a part of the texture into the rectangle. | ||
2229 | void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect, | ||
2230 | const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect, | ||
2231 | const video::SColor* const colors, bool useAlphaChannelOfTexture) | ||
2232 | { | ||
2233 | if (texture) | ||
2234 | { | ||
2235 | if (texture->getDriverType() != EDT_BURNINGSVIDEO) | ||
2236 | { | ||
2237 | os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); | ||
2238 | return; | ||
2239 | } | ||
2240 | |||
2241 | if (useAlphaChannelOfTexture) | ||
2242 | StretchBlit(BLITTER_TEXTURE_ALPHA_BLEND, RenderTargetSurface, &destRect, &sourceRect, | ||
2243 | ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); | ||
2244 | else | ||
2245 | StretchBlit(BLITTER_TEXTURE, RenderTargetSurface, &destRect, &sourceRect, | ||
2246 | ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); | ||
2247 | } | ||
2248 | } | ||
2249 | |||
2250 | //! Draws a 2d line. | ||
2251 | void CBurningVideoDriver::draw2DLine(const core::position2d<s32>& start, | ||
2252 | const core::position2d<s32>& end, | ||
2253 | SColor color) | ||
2254 | { | ||
2255 | drawLine(BackBuffer, start, end, color ); | ||
2256 | } | ||
2257 | |||
2258 | |||
2259 | //! Draws a pixel | ||
2260 | void CBurningVideoDriver::drawPixel(u32 x, u32 y, const SColor & color) | ||
2261 | { | ||
2262 | BackBuffer->setPixel(x, y, color, true); | ||
2263 | } | ||
2264 | |||
2265 | |||
2266 | //! draw an 2d rectangle | ||
2267 | void CBurningVideoDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos, | ||
2268 | const core::rect<s32>* clip) | ||
2269 | { | ||
2270 | if (clip) | ||
2271 | { | ||
2272 | core::rect<s32> p(pos); | ||
2273 | |||
2274 | p.clipAgainst(*clip); | ||
2275 | |||
2276 | if(!p.isValid()) | ||
2277 | return; | ||
2278 | |||
2279 | drawRectangle(BackBuffer, p, color); | ||
2280 | } | ||
2281 | else | ||
2282 | { | ||
2283 | if(!pos.isValid()) | ||
2284 | return; | ||
2285 | |||
2286 | drawRectangle(BackBuffer, pos, color); | ||
2287 | } | ||
2288 | } | ||
2289 | |||
2290 | |||
2291 | //! Only used by the internal engine. Used to notify the driver that | ||
2292 | //! the window was resized. | ||
2293 | void CBurningVideoDriver::OnResize(const core::dimension2d<u32>& size) | ||
2294 | { | ||
2295 | // make sure width and height are multiples of 2 | ||
2296 | core::dimension2d<u32> realSize(size); | ||
2297 | |||
2298 | if (realSize.Width % 2) | ||
2299 | realSize.Width += 1; | ||
2300 | |||
2301 | if (realSize.Height % 2) | ||
2302 | realSize.Height += 1; | ||
2303 | |||
2304 | if (ScreenSize != realSize) | ||
2305 | { | ||
2306 | if (ViewPort.getWidth() == (s32)ScreenSize.Width && | ||
2307 | ViewPort.getHeight() == (s32)ScreenSize.Height) | ||
2308 | { | ||
2309 | ViewPort.UpperLeftCorner.X = 0; | ||
2310 | ViewPort.UpperLeftCorner.Y = 0; | ||
2311 | ViewPort.LowerRightCorner.X = realSize.Width; | ||
2312 | ViewPort.LowerRightCorner.X = realSize.Height; | ||
2313 | } | ||
2314 | |||
2315 | ScreenSize = realSize; | ||
2316 | |||
2317 | bool resetRT = (RenderTargetSurface == BackBuffer); | ||
2318 | |||
2319 | if (BackBuffer) | ||
2320 | BackBuffer->drop(); | ||
2321 | BackBuffer = new CImage(BURNINGSHADER_COLOR_FORMAT, realSize); | ||
2322 | |||
2323 | if (resetRT) | ||
2324 | setRenderTarget(BackBuffer); | ||
2325 | } | ||
2326 | } | ||
2327 | |||
2328 | |||
2329 | //! returns the current render target size | ||
2330 | const core::dimension2d<u32>& CBurningVideoDriver::getCurrentRenderTargetSize() const | ||
2331 | { | ||
2332 | return RenderTargetSize; | ||
2333 | } | ||
2334 | |||
2335 | |||
2336 | //!Draws an 2d rectangle with a gradient. | ||
2337 | void CBurningVideoDriver::draw2DRectangle(const core::rect<s32>& position, | ||
2338 | SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, | ||
2339 | const core::rect<s32>* clip) | ||
2340 | { | ||
2341 | #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR | ||
2342 | |||
2343 | core::rect<s32> pos = position; | ||
2344 | |||
2345 | if (clip) | ||
2346 | pos.clipAgainst(*clip); | ||
2347 | |||
2348 | if (!pos.isValid()) | ||
2349 | return; | ||
2350 | |||
2351 | const core::dimension2d<s32> renderTargetSize ( ViewPort.getSize() ); | ||
2352 | |||
2353 | const s32 xPlus = -(renderTargetSize.Width>>1); | ||
2354 | const f32 xFact = 1.0f / (renderTargetSize.Width>>1); | ||
2355 | |||
2356 | const s32 yPlus = renderTargetSize.Height-(renderTargetSize.Height>>1); | ||
2357 | const f32 yFact = 1.0f / (renderTargetSize.Height>>1); | ||
2358 | |||
2359 | // fill VertexCache direct | ||
2360 | s4DVertex *v; | ||
2361 | |||
2362 | VertexCache.vertexCount = 4; | ||
2363 | |||
2364 | VertexCache.info[0].index = 0; | ||
2365 | VertexCache.info[1].index = 1; | ||
2366 | VertexCache.info[2].index = 2; | ||
2367 | VertexCache.info[3].index = 3; | ||
2368 | |||
2369 | v = &VertexCache.mem.data [ 0 ]; | ||
2370 | |||
2371 | v[0].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); | ||
2372 | v[0].Color[0].setA8R8G8B8 ( colorLeftUp.color ); | ||
2373 | |||
2374 | v[2].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus- pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); | ||
2375 | v[2].Color[0].setA8R8G8B8 ( colorRightUp.color ); | ||
2376 | |||
2377 | v[4].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f ,1.f ); | ||
2378 | v[4].Color[0].setA8R8G8B8 ( colorRightDown.color ); | ||
2379 | |||
2380 | v[6].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f, 1.f ); | ||
2381 | v[6].Color[0].setA8R8G8B8 ( colorLeftDown.color ); | ||
2382 | |||
2383 | s32 i; | ||
2384 | u32 g; | ||
2385 | |||
2386 | for ( i = 0; i!= 8; i += 2 ) | ||
2387 | { | ||
2388 | v[i + 0].flag = clipToFrustumTest ( v + i ); | ||
2389 | v[i + 1].flag = 0; | ||
2390 | if ( (v[i].flag & VERTEX4D_INSIDE ) == VERTEX4D_INSIDE ) | ||
2391 | { | ||
2392 | ndc_2_dc_and_project ( v + i + 1, v + i, 2 ); | ||
2393 | } | ||
2394 | } | ||
2395 | |||
2396 | |||
2397 | IBurningShader * render; | ||
2398 | |||
2399 | render = BurningShader [ ETR_GOURAUD_ALPHA_NOZ ]; | ||
2400 | render->setRenderTarget(RenderTargetSurface, ViewPort); | ||
2401 | |||
2402 | static const s16 indexList[6] = {0,1,2,0,2,3}; | ||
2403 | |||
2404 | s4DVertex * face[3]; | ||
2405 | |||
2406 | for ( i = 0; i!= 6; i += 3 ) | ||
2407 | { | ||
2408 | face[0] = VertexCache_getVertex ( indexList [ i + 0 ] ); | ||
2409 | face[1] = VertexCache_getVertex ( indexList [ i + 1 ] ); | ||
2410 | face[2] = VertexCache_getVertex ( indexList [ i + 2 ] ); | ||
2411 | |||
2412 | // test clipping | ||
2413 | u32 test = face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_INSIDE; | ||
2414 | |||
2415 | if ( test == VERTEX4D_INSIDE ) | ||
2416 | { | ||
2417 | render->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); | ||
2418 | continue; | ||
2419 | } | ||
2420 | // Todo: all vertices are clipped in 2d.. | ||
2421 | // is this true ? | ||
2422 | u32 vOut = 6; | ||
2423 | memcpy ( CurrentOut.data + 0, face[0], sizeof ( s4DVertex ) * 2 ); | ||
2424 | memcpy ( CurrentOut.data + 2, face[1], sizeof ( s4DVertex ) * 2 ); | ||
2425 | memcpy ( CurrentOut.data + 4, face[2], sizeof ( s4DVertex ) * 2 ); | ||
2426 | |||
2427 | vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); | ||
2428 | if ( vOut < 3 ) | ||
2429 | continue; | ||
2430 | |||
2431 | vOut <<= 1; | ||
2432 | // to DC Space, project homogenous vertex | ||
2433 | ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); | ||
2434 | |||
2435 | // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) | ||
2436 | for ( g = 0; g <= vOut - 6; g += 2 ) | ||
2437 | { | ||
2438 | // rasterize | ||
2439 | render->drawTriangle ( CurrentOut.data + 1, &CurrentOut.data[g + 3], &CurrentOut.data[g + 5] ); | ||
2440 | } | ||
2441 | |||
2442 | } | ||
2443 | #else | ||
2444 | draw2DRectangle ( colorLeftUp, position, clip ); | ||
2445 | #endif | ||
2446 | } | ||
2447 | |||
2448 | |||
2449 | //! Draws a 3d line. | ||
2450 | void CBurningVideoDriver::draw3DLine(const core::vector3df& start, | ||
2451 | const core::vector3df& end, SColor color) | ||
2452 | { | ||
2453 | Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[0].Pos.x, start ); | ||
2454 | Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[2].Pos.x, end ); | ||
2455 | |||
2456 | u32 g; | ||
2457 | u32 vOut; | ||
2458 | |||
2459 | // no clipping flags | ||
2460 | for ( g = 0; g != CurrentOut.ElementSize; ++g ) | ||
2461 | { | ||
2462 | CurrentOut.data[g].flag = 0; | ||
2463 | Temp.data[g].flag = 0; | ||
2464 | } | ||
2465 | |||
2466 | // vertices count per line | ||
2467 | vOut = clipToFrustum ( CurrentOut.data, Temp.data, 2 ); | ||
2468 | if ( vOut < 2 ) | ||
2469 | return; | ||
2470 | |||
2471 | vOut <<= 1; | ||
2472 | |||
2473 | IBurningShader * line; | ||
2474 | line = BurningShader [ ETR_TEXTURE_GOURAUD_WIRE ]; | ||
2475 | line->setRenderTarget(RenderTargetSurface, ViewPort); | ||
2476 | |||
2477 | // to DC Space, project homogenous vertex | ||
2478 | ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); | ||
2479 | |||
2480 | // unproject vertex color | ||
2481 | #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR | ||
2482 | for ( g = 0; g != vOut; g+= 2 ) | ||
2483 | { | ||
2484 | CurrentOut.data[ g + 1].Color[0].setA8R8G8B8 ( color.color ); | ||
2485 | } | ||
2486 | #endif | ||
2487 | |||
2488 | |||
2489 | for ( g = 0; g <= vOut - 4; g += 2 ) | ||
2490 | { | ||
2491 | // rasterize | ||
2492 | line->drawLine ( CurrentOut.data + 1, CurrentOut.data + g + 3 ); | ||
2493 | } | ||
2494 | } | ||
2495 | |||
2496 | |||
2497 | //! \return Returns the name of the video driver. Example: In case of the DirectX8 | ||
2498 | //! driver, it would return "Direct3D8.1". | ||
2499 | const wchar_t* CBurningVideoDriver::getName() const | ||
2500 | { | ||
2501 | #ifdef BURNINGVIDEO_RENDERER_BEAUTIFUL | ||
2502 | return L"Burning's Video 0.47 beautiful"; | ||
2503 | #elif defined ( BURNINGVIDEO_RENDERER_ULTRA_FAST ) | ||
2504 | return L"Burning's Video 0.47 ultra fast"; | ||
2505 | #elif defined ( BURNINGVIDEO_RENDERER_FAST ) | ||
2506 | return L"Burning's Video 0.47 fast"; | ||
2507 | #else | ||
2508 | return L"Burning's Video 0.47"; | ||
2509 | #endif | ||
2510 | } | ||
2511 | |||
2512 | //! Returns the graphics card vendor name. | ||
2513 | core::stringc CBurningVideoDriver::getVendorInfo() | ||
2514 | { | ||
2515 | return "Burning's Video: Ing. Thomas Alten (c) 2006-2012"; | ||
2516 | } | ||
2517 | |||
2518 | |||
2519 | //! Returns type of video driver | ||
2520 | E_DRIVER_TYPE CBurningVideoDriver::getDriverType() const | ||
2521 | { | ||
2522 | return EDT_BURNINGSVIDEO; | ||
2523 | } | ||
2524 | |||
2525 | |||
2526 | //! returns color format | ||
2527 | ECOLOR_FORMAT CBurningVideoDriver::getColorFormat() const | ||
2528 | { | ||
2529 | return BURNINGSHADER_COLOR_FORMAT; | ||
2530 | } | ||
2531 | |||
2532 | |||
2533 | //! Returns the transformation set by setTransform | ||
2534 | const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE state) const | ||
2535 | { | ||
2536 | return Transformation[state]; | ||
2537 | } | ||
2538 | |||
2539 | |||
2540 | //! Creates a render target texture. | ||
2541 | ITexture* CBurningVideoDriver::addRenderTargetTexture(const core::dimension2d<u32>& size, | ||
2542 | const io::path& name, const ECOLOR_FORMAT format) | ||
2543 | { | ||
2544 | IImage* img = createImage(BURNINGSHADER_COLOR_FORMAT, size); | ||
2545 | ITexture* tex = new CSoftwareTexture2(img, name, CSoftwareTexture2::IS_RENDERTARGET ); | ||
2546 | img->drop(); | ||
2547 | addTexture(tex); | ||
2548 | tex->drop(); | ||
2549 | return tex; | ||
2550 | } | ||
2551 | |||
2552 | |||
2553 | //! Clears the DepthBuffer. | ||
2554 | void CBurningVideoDriver::clearZBuffer() | ||
2555 | { | ||
2556 | if (DepthBuffer) | ||
2557 | DepthBuffer->clear(); | ||
2558 | } | ||
2559 | |||
2560 | |||
2561 | //! Returns an image created from the last rendered frame. | ||
2562 | IImage* CBurningVideoDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) | ||
2563 | { | ||
2564 | if (target != video::ERT_FRAME_BUFFER) | ||
2565 | return 0; | ||
2566 | |||
2567 | if (BackBuffer) | ||
2568 | { | ||
2569 | IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension()); | ||
2570 | BackBuffer->copyTo(tmp); | ||
2571 | return tmp; | ||
2572 | } | ||
2573 | else | ||
2574 | return 0; | ||
2575 | } | ||
2576 | |||
2577 | |||
2578 | //! returns a device dependent texture from a software surface (IImage) | ||
2579 | //! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES | ||
2580 | ITexture* CBurningVideoDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData) | ||
2581 | { | ||
2582 | return new CSoftwareTexture2( | ||
2583 | surface, name, | ||
2584 | (getTextureCreationFlag(ETCF_CREATE_MIP_MAPS) ? CSoftwareTexture2::GEN_MIPMAP : 0 ) | | ||
2585 | (getTextureCreationFlag(ETCF_ALLOW_NON_POWER_2) ? 0 : CSoftwareTexture2::NP2_SIZE ), mipmapData); | ||
2586 | |||
2587 | } | ||
2588 | |||
2589 | |||
2590 | //! Returns the maximum amount of primitives (mostly vertices) which | ||
2591 | //! the device is able to render with one drawIndexedTriangleList | ||
2592 | //! call. | ||
2593 | u32 CBurningVideoDriver::getMaximalPrimitiveCount() const | ||
2594 | { | ||
2595 | return 0xFFFFFFFF; | ||
2596 | } | ||
2597 | |||
2598 | |||
2599 | //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do | ||
2600 | //! this: First, draw all geometry. Then use this method, to draw the shadow | ||
2601 | //! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. | ||
2602 | void CBurningVideoDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible) | ||
2603 | { | ||
2604 | const u32 count = triangles.size(); | ||
2605 | IBurningShader *shader = BurningShader [ ETR_STENCIL_SHADOW ]; | ||
2606 | |||
2607 | CurrentShader = shader; | ||
2608 | shader->setRenderTarget(RenderTargetSurface, ViewPort); | ||
2609 | |||
2610 | Material.org.MaterialType = video::EMT_SOLID; | ||
2611 | Material.org.Lighting = false; | ||
2612 | Material.org.ZWriteEnable = false; | ||
2613 | Material.org.ZBuffer = ECFN_LESSEQUAL; | ||
2614 | LightSpace.Flags &= ~VERTEXTRANSFORM; | ||
2615 | |||
2616 | //glStencilMask(~0); | ||
2617 | //glStencilFunc(GL_ALWAYS, 0, ~0); | ||
2618 | |||
2619 | if (true)// zpass does not work yet | ||
2620 | { | ||
2621 | Material.org.BackfaceCulling = true; | ||
2622 | Material.org.FrontfaceCulling = false; | ||
2623 | shader->setParam ( 0, 0 ); | ||
2624 | shader->setParam ( 1, 1 ); | ||
2625 | shader->setParam ( 2, 0 ); | ||
2626 | drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); | ||
2627 | //glStencilOp(GL_KEEP, incr, GL_KEEP); | ||
2628 | //glDrawArrays(GL_TRIANGLES,0,count); | ||
2629 | |||
2630 | Material.org.BackfaceCulling = false; | ||
2631 | Material.org.FrontfaceCulling = true; | ||
2632 | shader->setParam ( 0, 0 ); | ||
2633 | shader->setParam ( 1, 2 ); | ||
2634 | shader->setParam ( 2, 0 ); | ||
2635 | drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); | ||
2636 | //glStencilOp(GL_KEEP, decr, GL_KEEP); | ||
2637 | //glDrawArrays(GL_TRIANGLES,0,count); | ||
2638 | } | ||
2639 | else // zpass | ||
2640 | { | ||
2641 | Material.org.BackfaceCulling = true; | ||
2642 | Material.org.FrontfaceCulling = false; | ||
2643 | shader->setParam ( 0, 0 ); | ||
2644 | shader->setParam ( 1, 0 ); | ||
2645 | shader->setParam ( 2, 1 ); | ||
2646 | //glStencilOp(GL_KEEP, GL_KEEP, incr); | ||
2647 | //glDrawArrays(GL_TRIANGLES,0,count); | ||
2648 | |||
2649 | Material.org.BackfaceCulling = false; | ||
2650 | Material.org.FrontfaceCulling = true; | ||
2651 | shader->setParam ( 0, 0 ); | ||
2652 | shader->setParam ( 1, 0 ); | ||
2653 | shader->setParam ( 2, 2 ); | ||
2654 | //glStencilOp(GL_KEEP, GL_KEEP, decr); | ||
2655 | //glDrawArrays(GL_TRIANGLES,0,count); | ||
2656 | } | ||
2657 | } | ||
2658 | |||
2659 | //! Fills the stencil shadow with color. After the shadow volume has been drawn | ||
2660 | //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this | ||
2661 | //! to draw the color of the shadow. | ||
2662 | void CBurningVideoDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, | ||
2663 | video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) | ||
2664 | { | ||
2665 | if (!StencilBuffer) | ||
2666 | return; | ||
2667 | // draw a shadow rectangle covering the entire screen using stencil buffer | ||
2668 | const u32 h = RenderTargetSurface->getDimension().Height; | ||
2669 | const u32 w = RenderTargetSurface->getDimension().Width; | ||
2670 | tVideoSample *dst; | ||
2671 | u32 *stencil; | ||
2672 | u32* const stencilBase=(u32*) StencilBuffer->lock(); | ||
2673 | |||
2674 | for ( u32 y = 0; y < h; ++y ) | ||
2675 | { | ||
2676 | dst = (tVideoSample*)RenderTargetSurface->lock() + ( y * w ); | ||
2677 | stencil = stencilBase + ( y * w ); | ||
2678 | |||
2679 | for ( u32 x = 0; x < w; ++x ) | ||
2680 | { | ||
2681 | if ( stencil[x] > 1 ) | ||
2682 | { | ||
2683 | dst[x] = PixelBlend32 ( dst[x], leftUpEdge.color ); | ||
2684 | } | ||
2685 | } | ||
2686 | } | ||
2687 | |||
2688 | StencilBuffer->clear(); | ||
2689 | } | ||
2690 | |||
2691 | |||
2692 | core::dimension2du CBurningVideoDriver::getMaxTextureSize() const | ||
2693 | { | ||
2694 | return core::dimension2du(SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE, SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE); | ||
2695 | } | ||
2696 | |||
2697 | |||
2698 | } // end namespace video | ||
2699 | } // end namespace irr | ||
2700 | |||
2701 | #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ | ||
2702 | |||
2703 | namespace irr | ||
2704 | { | ||
2705 | namespace video | ||
2706 | { | ||
2707 | |||
2708 | //! creates a video driver | ||
2709 | IVideoDriver* createBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter) | ||
2710 | { | ||
2711 | #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ | ||
2712 | return new CBurningVideoDriver(params, io, presenter); | ||
2713 | #else | ||
2714 | return 0; | ||
2715 | #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ | ||
2716 | } | ||
2717 | |||
2718 | |||
2719 | |||
2720 | } // end namespace video | ||
2721 | } // end namespace irr | ||
2722 | |||