diff options
author | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
---|---|---|
committer | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
commit | 7028cbe09c688437910a25623098762bf0fa592d (patch) | |
tree | 10b5af58277d9880380c2251f109325542c4e6eb /src/others/irrlicht-1.8.1/source/Irrlicht/CSoftwareDriver2.cpp | |
parent | Move lemon to the src/others directory. (diff) | |
download | SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.zip SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.gz SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.bz2 SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.xz |
Move Irrlicht to src/others.
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CSoftwareDriver2.cpp')
-rw-r--r-- | src/others/irrlicht-1.8.1/source/Irrlicht/CSoftwareDriver2.cpp | 2723 |
1 files changed, 2723 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CSoftwareDriver2.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CSoftwareDriver2.cpp new file mode 100644 index 0000000..f90ede5 --- /dev/null +++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CSoftwareDriver2.cpp | |||
@@ -0,0 +1,2723 @@ | |||
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 | if ( texture1 ) | ||
547 | shader = ETR_TEXTURE_GOURAUD_DETAIL_MAP; | ||
548 | break; | ||
549 | |||
550 | case EMT_SPHERE_MAP: | ||
551 | TransformationFlag[ ETS_TEXTURE_0] |= ETF_TEXGEN_CAMERA_REFLECTION; // ETF_TEXGEN_CAMERA_NORMAL; | ||
552 | LightSpace.Flags |= VERTEXTRANSFORM; | ||
553 | break; | ||
554 | case EMT_REFLECTION_2_LAYER: | ||
555 | shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1; | ||
556 | TransformationFlag[ ETS_TEXTURE_1] |= ETF_TEXGEN_CAMERA_REFLECTION; | ||
557 | LightSpace.Flags |= VERTEXTRANSFORM; | ||
558 | break; | ||
559 | |||
560 | case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: | ||
561 | case EMT_NORMAL_MAP_SOLID: | ||
562 | case EMT_PARALLAX_MAP_SOLID: | ||
563 | case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: | ||
564 | shader = ETR_NORMAL_MAP_SOLID; | ||
565 | LightSpace.Flags |= VERTEXTRANSFORM; | ||
566 | break; | ||
567 | |||
568 | default: | ||
569 | break; | ||
570 | |||
571 | } | ||
572 | |||
573 | if ( !texture0 ) | ||
574 | { | ||
575 | shader = ETR_GOURAUD; | ||
576 | } | ||
577 | |||
578 | if ( Material.org.Wireframe ) | ||
579 | { | ||
580 | shader = ETR_TEXTURE_GOURAUD_WIRE; | ||
581 | } | ||
582 | |||
583 | //shader = ETR_REFERENCE; | ||
584 | |||
585 | // switchToTriangleRenderer | ||
586 | CurrentShader = BurningShader[shader]; | ||
587 | if ( CurrentShader ) | ||
588 | { | ||
589 | CurrentShader->setZCompareFunc ( Material.org.ZBuffer ); | ||
590 | CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); | ||
591 | CurrentShader->setMaterial ( Material ); | ||
592 | |||
593 | switch ( shader ) | ||
594 | { | ||
595 | case ETR_TEXTURE_GOURAUD_ALPHA: | ||
596 | case ETR_TEXTURE_GOURAUD_ALPHA_NOZ: | ||
597 | case ETR_TEXTURE_BLEND: | ||
598 | CurrentShader->setParam ( 0, Material.org.MaterialTypeParam ); | ||
599 | break; | ||
600 | default: | ||
601 | break; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | } | ||
606 | |||
607 | |||
608 | |||
609 | //! queries the features of the driver, returns true if feature is available | ||
610 | bool CBurningVideoDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const | ||
611 | { | ||
612 | if (!FeatureEnabled[feature]) | ||
613 | return false; | ||
614 | |||
615 | switch (feature) | ||
616 | { | ||
617 | #ifdef SOFTWARE_DRIVER_2_BILINEAR | ||
618 | case EVDF_BILINEAR_FILTER: | ||
619 | return true; | ||
620 | #endif | ||
621 | #ifdef SOFTWARE_DRIVER_2_MIPMAPPING | ||
622 | case EVDF_MIP_MAP: | ||
623 | return true; | ||
624 | #endif | ||
625 | case EVDF_STENCIL_BUFFER: | ||
626 | case EVDF_RENDER_TO_TARGET: | ||
627 | case EVDF_MULTITEXTURE: | ||
628 | case EVDF_HARDWARE_TL: | ||
629 | case EVDF_TEXTURE_NSQUARE: | ||
630 | return true; | ||
631 | |||
632 | default: | ||
633 | return false; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | |||
638 | |||
639 | //! sets transformation | ||
640 | void CBurningVideoDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) | ||
641 | { | ||
642 | Transformation[state] = mat; | ||
643 | core::setbit_cond ( TransformationFlag[state], mat.isIdentity(), ETF_IDENTITY ); | ||
644 | |||
645 | switch ( state ) | ||
646 | { | ||
647 | case ETS_VIEW: | ||
648 | Transformation[ETS_VIEW_PROJECTION].setbyproduct_nocheck ( | ||
649 | Transformation[ETS_PROJECTION], | ||
650 | Transformation[ETS_VIEW] | ||
651 | ); | ||
652 | getCameraPosWorldSpace (); | ||
653 | break; | ||
654 | |||
655 | case ETS_WORLD: | ||
656 | if ( TransformationFlag[state] & ETF_IDENTITY ) | ||
657 | { | ||
658 | Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; | ||
659 | TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; | ||
660 | Transformation[ETS_CURRENT] = Transformation[ETS_VIEW_PROJECTION]; | ||
661 | } | ||
662 | else | ||
663 | { | ||
664 | //Transformation[ETS_WORLD].getInversePrimitive ( Transformation[ETS_WORLD_INVERSE] ); | ||
665 | Transformation[ETS_CURRENT].setbyproduct_nocheck ( | ||
666 | Transformation[ETS_VIEW_PROJECTION], | ||
667 | Transformation[ETS_WORLD] | ||
668 | ); | ||
669 | } | ||
670 | TransformationFlag[ETS_CURRENT] = 0; | ||
671 | //getLightPosObjectSpace (); | ||
672 | break; | ||
673 | case ETS_TEXTURE_0: | ||
674 | case ETS_TEXTURE_1: | ||
675 | case ETS_TEXTURE_2: | ||
676 | case ETS_TEXTURE_3: | ||
677 | if ( 0 == (TransformationFlag[state] & ETF_IDENTITY ) ) | ||
678 | LightSpace.Flags |= VERTEXTRANSFORM; | ||
679 | default: | ||
680 | break; | ||
681 | } | ||
682 | } | ||
683 | |||
684 | |||
685 | //! clears the zbuffer | ||
686 | bool CBurningVideoDriver::beginScene(bool backBuffer, bool zBuffer, | ||
687 | SColor color, const SExposedVideoData& videoData, | ||
688 | core::rect<s32>* sourceRect) | ||
689 | { | ||
690 | CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect); | ||
691 | WindowId = videoData.D3D9.HWnd; | ||
692 | SceneSourceRect = sourceRect; | ||
693 | |||
694 | if (backBuffer && BackBuffer) | ||
695 | BackBuffer->fill(color); | ||
696 | |||
697 | if (zBuffer && DepthBuffer) | ||
698 | DepthBuffer->clear(); | ||
699 | |||
700 | memset ( TransformationFlag, 0, sizeof ( TransformationFlag ) ); | ||
701 | return true; | ||
702 | } | ||
703 | |||
704 | |||
705 | //! presents the rendered scene on the screen, returns false if failed | ||
706 | bool CBurningVideoDriver::endScene() | ||
707 | { | ||
708 | CNullDriver::endScene(); | ||
709 | |||
710 | return Presenter->present(BackBuffer, WindowId, SceneSourceRect); | ||
711 | } | ||
712 | |||
713 | |||
714 | //! sets a render target | ||
715 | bool CBurningVideoDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, | ||
716 | bool clearZBuffer, SColor color) | ||
717 | { | ||
718 | if (texture && texture->getDriverType() != EDT_BURNINGSVIDEO) | ||
719 | { | ||
720 | os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); | ||
721 | return false; | ||
722 | } | ||
723 | |||
724 | if (RenderTargetTexture) | ||
725 | RenderTargetTexture->drop(); | ||
726 | |||
727 | RenderTargetTexture = texture; | ||
728 | |||
729 | if (RenderTargetTexture) | ||
730 | { | ||
731 | RenderTargetTexture->grab(); | ||
732 | setRenderTarget(((CSoftwareTexture2*)RenderTargetTexture)->getTexture()); | ||
733 | } | ||
734 | else | ||
735 | { | ||
736 | setRenderTarget(BackBuffer); | ||
737 | } | ||
738 | |||
739 | if (RenderTargetSurface && (clearBackBuffer || clearZBuffer)) | ||
740 | { | ||
741 | if (clearZBuffer) | ||
742 | DepthBuffer->clear(); | ||
743 | |||
744 | if (clearBackBuffer) | ||
745 | RenderTargetSurface->fill( color ); | ||
746 | } | ||
747 | |||
748 | return true; | ||
749 | } | ||
750 | |||
751 | |||
752 | //! sets a render target | ||
753 | void CBurningVideoDriver::setRenderTarget(video::CImage* image) | ||
754 | { | ||
755 | if (RenderTargetSurface) | ||
756 | RenderTargetSurface->drop(); | ||
757 | |||
758 | RenderTargetSurface = image; | ||
759 | RenderTargetSize.Width = 0; | ||
760 | RenderTargetSize.Height = 0; | ||
761 | |||
762 | if (RenderTargetSurface) | ||
763 | { | ||
764 | RenderTargetSurface->grab(); | ||
765 | RenderTargetSize = RenderTargetSurface->getDimension(); | ||
766 | } | ||
767 | |||
768 | setViewPort(core::rect<s32>(0,0,RenderTargetSize.Width,RenderTargetSize.Height)); | ||
769 | |||
770 | if (DepthBuffer) | ||
771 | DepthBuffer->setSize(RenderTargetSize); | ||
772 | |||
773 | if (StencilBuffer) | ||
774 | StencilBuffer->setSize(RenderTargetSize); | ||
775 | } | ||
776 | |||
777 | |||
778 | |||
779 | //! sets a viewport | ||
780 | void CBurningVideoDriver::setViewPort(const core::rect<s32>& area) | ||
781 | { | ||
782 | ViewPort = area; | ||
783 | |||
784 | core::rect<s32> rendert(0,0,RenderTargetSize.Width,RenderTargetSize.Height); | ||
785 | ViewPort.clipAgainst(rendert); | ||
786 | |||
787 | Transformation [ ETS_CLIPSCALE ].buildNDCToDCMatrix ( ViewPort, 1 ); | ||
788 | |||
789 | if (CurrentShader) | ||
790 | CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); | ||
791 | } | ||
792 | |||
793 | /* | ||
794 | generic plane clipping in homogenous coordinates | ||
795 | special case ndc frustum <-w,w>,<-w,w>,<-w,w> | ||
796 | can be rewritten with compares e.q near plane, a.z < -a.w and b.z < -b.w | ||
797 | */ | ||
798 | |||
799 | const sVec4 CBurningVideoDriver::NDCPlane[6] = | ||
800 | { | ||
801 | sVec4( 0.f, 0.f, -1.f, -1.f ), // near | ||
802 | sVec4( 0.f, 0.f, 1.f, -1.f ), // far | ||
803 | sVec4( 1.f, 0.f, 0.f, -1.f ), // left | ||
804 | sVec4( -1.f, 0.f, 0.f, -1.f ), // right | ||
805 | sVec4( 0.f, 1.f, 0.f, -1.f ), // bottom | ||
806 | sVec4( 0.f, -1.f, 0.f, -1.f ) // top | ||
807 | }; | ||
808 | |||
809 | |||
810 | |||
811 | /* | ||
812 | test a vertex if it's inside the standard frustum | ||
813 | |||
814 | this is the generic one.. | ||
815 | |||
816 | f32 dotPlane; | ||
817 | for ( u32 i = 0; i!= 6; ++i ) | ||
818 | { | ||
819 | dotPlane = v->Pos.dotProduct ( NDCPlane[i] ); | ||
820 | core::setbit_cond( flag, dotPlane <= 0.f, 1 << i ); | ||
821 | } | ||
822 | |||
823 | // this is the base for ndc frustum <-w,w>,<-w,w>,<-w,w> | ||
824 | core::setbit_cond( flag, ( v->Pos.z - v->Pos.w ) <= 0.f, 1 ); | ||
825 | core::setbit_cond( flag, (-v->Pos.z - v->Pos.w ) <= 0.f, 2 ); | ||
826 | core::setbit_cond( flag, ( v->Pos.x - v->Pos.w ) <= 0.f, 4 ); | ||
827 | core::setbit_cond( flag, (-v->Pos.x - v->Pos.w ) <= 0.f, 8 ); | ||
828 | core::setbit_cond( flag, ( v->Pos.y - v->Pos.w ) <= 0.f, 16 ); | ||
829 | core::setbit_cond( flag, (-v->Pos.y - v->Pos.w ) <= 0.f, 32 ); | ||
830 | |||
831 | */ | ||
832 | #ifdef IRRLICHT_FAST_MATH | ||
833 | |||
834 | REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const | ||
835 | { | ||
836 | f32 test[6]; | ||
837 | u32 flag; | ||
838 | const f32 w = - v->Pos.w; | ||
839 | |||
840 | // a conditional move is needed....FCOMI ( but we don't have it ) | ||
841 | // so let the fpu calculate and write it back. | ||
842 | // cpu makes the compare, interleaving | ||
843 | |||
844 | test[0] = v->Pos.z + w; | ||
845 | test[1] = -v->Pos.z + w; | ||
846 | test[2] = v->Pos.x + w; | ||
847 | test[3] = -v->Pos.x + w; | ||
848 | test[4] = v->Pos.y + w; | ||
849 | test[5] = -v->Pos.y + w; | ||
850 | |||
851 | flag = (IR ( test[0] ) ) >> 31; | ||
852 | flag |= (IR ( test[1] ) & 0x80000000 ) >> 30; | ||
853 | flag |= (IR ( test[2] ) & 0x80000000 ) >> 29; | ||
854 | flag |= (IR ( test[3] ) & 0x80000000 ) >> 28; | ||
855 | flag |= (IR ( test[4] ) & 0x80000000 ) >> 27; | ||
856 | flag |= (IR ( test[5] ) & 0x80000000 ) >> 26; | ||
857 | |||
858 | /* | ||
859 | flag = F32_LOWER_EQUAL_0 ( test[0] ); | ||
860 | flag |= F32_LOWER_EQUAL_0 ( test[1] ) << 1; | ||
861 | flag |= F32_LOWER_EQUAL_0 ( test[2] ) << 2; | ||
862 | flag |= F32_LOWER_EQUAL_0 ( test[3] ) << 3; | ||
863 | flag |= F32_LOWER_EQUAL_0 ( test[4] ) << 4; | ||
864 | flag |= F32_LOWER_EQUAL_0 ( test[5] ) << 5; | ||
865 | */ | ||
866 | return flag; | ||
867 | } | ||
868 | |||
869 | #else | ||
870 | |||
871 | |||
872 | REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const | ||
873 | { | ||
874 | u32 flag = 0; | ||
875 | |||
876 | if ( v->Pos.z <= v->Pos.w ) flag |= 1; | ||
877 | if (-v->Pos.z <= v->Pos.w ) flag |= 2; | ||
878 | |||
879 | if ( v->Pos.x <= v->Pos.w ) flag |= 4; | ||
880 | if (-v->Pos.x <= v->Pos.w ) flag |= 8; | ||
881 | |||
882 | if ( v->Pos.y <= v->Pos.w ) flag |= 16; | ||
883 | if (-v->Pos.y <= v->Pos.w ) flag |= 32; | ||
884 | |||
885 | /* | ||
886 | for ( u32 i = 0; i!= 6; ++i ) | ||
887 | { | ||
888 | core::setbit_cond( flag, v->Pos.dotProduct ( NDCPlane[i] ) <= 0.f, 1 << i ); | ||
889 | } | ||
890 | */ | ||
891 | return flag; | ||
892 | } | ||
893 | |||
894 | #endif // _MSC_VER | ||
895 | |||
896 | u32 CBurningVideoDriver::clipToHyperPlane ( s4DVertex * dest, const s4DVertex * source, u32 inCount, const sVec4 &plane ) | ||
897 | { | ||
898 | u32 outCount = 0; | ||
899 | s4DVertex * out = dest; | ||
900 | |||
901 | const s4DVertex * a; | ||
902 | const s4DVertex * b = source; | ||
903 | |||
904 | f32 bDotPlane; | ||
905 | |||
906 | bDotPlane = b->Pos.dotProduct ( plane ); | ||
907 | |||
908 | for( u32 i = 1; i < inCount + 1; ++i) | ||
909 | { | ||
910 | const s32 condition = i - inCount; | ||
911 | const s32 index = (( ( condition >> 31 ) & ( i ^ condition ) ) ^ condition ) << 1; | ||
912 | |||
913 | a = &source[ index ]; | ||
914 | |||
915 | // current point inside | ||
916 | if ( a->Pos.dotProduct ( plane ) <= 0.f ) | ||
917 | { | ||
918 | // last point outside | ||
919 | if ( F32_GREATER_0 ( bDotPlane ) ) | ||
920 | { | ||
921 | // intersect line segment with plane | ||
922 | out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); | ||
923 | out += 2; | ||
924 | outCount += 1; | ||
925 | } | ||
926 | |||
927 | // copy current to out | ||
928 | //*out = *a; | ||
929 | irr::memcpy32_small ( out, a, SIZEOF_SVERTEX * 2 ); | ||
930 | b = out; | ||
931 | |||
932 | out += 2; | ||
933 | outCount += 1; | ||
934 | } | ||
935 | else | ||
936 | { | ||
937 | // current point outside | ||
938 | |||
939 | if ( F32_LOWER_EQUAL_0 ( bDotPlane ) ) | ||
940 | { | ||
941 | // previous was inside | ||
942 | // intersect line segment with plane | ||
943 | out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); | ||
944 | out += 2; | ||
945 | outCount += 1; | ||
946 | } | ||
947 | // pointer | ||
948 | b = a; | ||
949 | } | ||
950 | |||
951 | bDotPlane = b->Pos.dotProduct ( plane ); | ||
952 | |||
953 | } | ||
954 | |||
955 | return outCount; | ||
956 | } | ||
957 | |||
958 | |||
959 | u32 CBurningVideoDriver::clipToFrustum ( s4DVertex *v0, s4DVertex * v1, const u32 vIn ) | ||
960 | { | ||
961 | u32 vOut = vIn; | ||
962 | |||
963 | vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[0] ); if ( vOut < vIn ) return vOut; | ||
964 | vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[1] ); if ( vOut < vIn ) return vOut; | ||
965 | vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[2] ); if ( vOut < vIn ) return vOut; | ||
966 | vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[3] ); if ( vOut < vIn ) return vOut; | ||
967 | vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[4] ); if ( vOut < vIn ) return vOut; | ||
968 | vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[5] ); | ||
969 | return vOut; | ||
970 | } | ||
971 | |||
972 | /*! | ||
973 | Part I: | ||
974 | apply Clip Scale matrix | ||
975 | From Normalized Device Coordiante ( NDC ) Space to Device Coordinate Space ( DC ) | ||
976 | |||
977 | Part II: | ||
978 | Project homogeneous vector | ||
979 | homogeneous to non-homogenous coordinates ( dividebyW ) | ||
980 | |||
981 | Incoming: ( xw, yw, zw, w, u, v, 1, R, G, B, A ) | ||
982 | Outgoing: ( xw/w, yw/w, zw/w, w/w, u/w, v/w, 1/w, R/w, G/w, B/w, A/w ) | ||
983 | |||
984 | |||
985 | replace w/w by 1/w | ||
986 | */ | ||
987 | inline void CBurningVideoDriver::ndc_2_dc_and_project ( s4DVertex *dest,s4DVertex *source, u32 vIn ) const | ||
988 | { | ||
989 | u32 g; | ||
990 | |||
991 | for ( g = 0; g != vIn; g += 2 ) | ||
992 | { | ||
993 | if ( (dest[g].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) | ||
994 | continue; | ||
995 | |||
996 | dest[g].flag = source[g].flag | VERTEX4D_PROJECTED; | ||
997 | |||
998 | const f32 w = source[g].Pos.w; | ||
999 | const f32 iw = core::reciprocal ( w ); | ||
1000 | |||
1001 | // to device coordinates | ||
1002 | dest[g].Pos.x = iw * ( source[g].Pos.x * Transformation [ ETS_CLIPSCALE ][ 0] + w * Transformation [ ETS_CLIPSCALE ][12] ); | ||
1003 | dest[g].Pos.y = iw * ( source[g].Pos.y * Transformation [ ETS_CLIPSCALE ][ 5] + w * Transformation [ ETS_CLIPSCALE ][13] ); | ||
1004 | |||
1005 | #ifndef SOFTWARE_DRIVER_2_USE_WBUFFER | ||
1006 | dest[g].Pos.z = iw * source[g].Pos.z; | ||
1007 | #endif | ||
1008 | |||
1009 | #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR | ||
1010 | #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT | ||
1011 | dest[g].Color[0] = source[g].Color[0] * iw; | ||
1012 | #else | ||
1013 | dest[g].Color[0] = source[g].Color[0]; | ||
1014 | #endif | ||
1015 | |||
1016 | #endif | ||
1017 | dest[g].LightTangent[0] = source[g].LightTangent[0] * iw; | ||
1018 | dest[g].Pos.w = iw; | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | |||
1023 | inline void CBurningVideoDriver::ndc_2_dc_and_project2 ( const s4DVertex **v, const u32 size ) const | ||
1024 | { | ||
1025 | u32 g; | ||
1026 | |||
1027 | for ( g = 0; g != size; g += 1 ) | ||
1028 | { | ||
1029 | s4DVertex * a = (s4DVertex*) v[g]; | ||
1030 | |||
1031 | if ( (a[1].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) | ||
1032 | continue; | ||
1033 | |||
1034 | a[1].flag = a->flag | VERTEX4D_PROJECTED; | ||
1035 | |||
1036 | // project homogenous vertex, store 1/w | ||
1037 | const f32 w = a->Pos.w; | ||
1038 | const f32 iw = core::reciprocal ( w ); | ||
1039 | |||
1040 | // to device coordinates | ||
1041 | const f32 * p = Transformation [ ETS_CLIPSCALE ].pointer(); | ||
1042 | a[1].Pos.x = iw * ( a->Pos.x * p[ 0] + w * p[12] ); | ||
1043 | a[1].Pos.y = iw * ( a->Pos.y * p[ 5] + w * p[13] ); | ||
1044 | |||
1045 | #ifndef SOFTWARE_DRIVER_2_USE_WBUFFER | ||
1046 | a[1].Pos.z = a->Pos.z * iw; | ||
1047 | #endif | ||
1048 | |||
1049 | #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR | ||
1050 | #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT | ||
1051 | a[1].Color[0] = a->Color[0] * iw; | ||
1052 | #else | ||
1053 | a[1].Color[0] = a->Color[0]; | ||
1054 | #endif | ||
1055 | #endif | ||
1056 | |||
1057 | a[1].LightTangent[0] = a[0].LightTangent[0] * iw; | ||
1058 | a[1].Pos.w = iw; | ||
1059 | |||
1060 | } | ||
1061 | |||
1062 | } | ||
1063 | |||
1064 | |||
1065 | /*! | ||
1066 | crossproduct in projected 2D -> screen area triangle | ||
1067 | */ | ||
1068 | inline f32 CBurningVideoDriver::screenarea ( const s4DVertex *v ) const | ||
1069 | { | ||
1070 | return ( ( v[3].Pos.x - v[1].Pos.x ) * ( v[5].Pos.y - v[1].Pos.y ) ) - | ||
1071 | ( ( v[3].Pos.y - v[1].Pos.y ) * ( v[5].Pos.x - v[1].Pos.x ) ); | ||
1072 | } | ||
1073 | |||
1074 | |||
1075 | /*! | ||
1076 | */ | ||
1077 | inline f32 CBurningVideoDriver::texelarea ( const s4DVertex *v, int tex ) const | ||
1078 | { | ||
1079 | f32 z; | ||
1080 | |||
1081 | z = ( (v[2].Tex[tex].x - v[0].Tex[tex].x ) * (v[4].Tex[tex].y - v[0].Tex[tex].y ) ) | ||
1082 | - ( (v[4].Tex[tex].x - v[0].Tex[tex].x ) * (v[2].Tex[tex].y - v[0].Tex[tex].y ) ); | ||
1083 | |||
1084 | return MAT_TEXTURE ( tex )->getLODFactor ( z ); | ||
1085 | } | ||
1086 | |||
1087 | /*! | ||
1088 | crossproduct in projected 2D | ||
1089 | */ | ||
1090 | inline f32 CBurningVideoDriver::screenarea2 ( const s4DVertex **v ) const | ||
1091 | { | ||
1092 | return ( (( v[1] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) * ( (v[2] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) ) - | ||
1093 | ( (( v[1] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) * ( (v[2] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) ); | ||
1094 | } | ||
1095 | |||
1096 | /*! | ||
1097 | */ | ||
1098 | inline f32 CBurningVideoDriver::texelarea2 ( const s4DVertex **v, s32 tex ) const | ||
1099 | { | ||
1100 | f32 z; | ||
1101 | z = ( (v[1]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[2]->Tex[tex].y - v[0]->Tex[tex].y ) ) | ||
1102 | - ( (v[2]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[1]->Tex[tex].y - v[0]->Tex[tex].y ) ); | ||
1103 | |||
1104 | return MAT_TEXTURE ( tex )->getLODFactor ( z ); | ||
1105 | } | ||
1106 | |||
1107 | |||
1108 | /*! | ||
1109 | */ | ||
1110 | inline void CBurningVideoDriver::select_polygon_mipmap ( s4DVertex *v, u32 vIn, u32 tex, const core::dimension2du& texSize ) const | ||
1111 | { | ||
1112 | f32 f[2]; | ||
1113 | |||
1114 | f[0] = (f32) texSize.Width - 0.25f; | ||
1115 | f[1] = (f32) texSize.Height - 0.25f; | ||
1116 | |||
1117 | #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT | ||
1118 | for ( u32 g = 0; g != vIn; g += 2 ) | ||
1119 | { | ||
1120 | (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * ( v + g + 1 )->Pos.w * f[0]; | ||
1121 | (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * ( v + g + 1 )->Pos.w * f[1]; | ||
1122 | } | ||
1123 | #else | ||
1124 | for ( u32 g = 0; g != vIn; g += 2 ) | ||
1125 | { | ||
1126 | (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * f[0]; | ||
1127 | (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * f[1]; | ||
1128 | } | ||
1129 | #endif | ||
1130 | } | ||
1131 | |||
1132 | inline void CBurningVideoDriver::select_polygon_mipmap2 ( s4DVertex **v, u32 tex, const core::dimension2du& texSize ) const | ||
1133 | { | ||
1134 | f32 f[2]; | ||
1135 | |||
1136 | f[0] = (f32) texSize.Width - 0.25f; | ||
1137 | f[1] = (f32) texSize.Height - 0.25f; | ||
1138 | |||
1139 | #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT | ||
1140 | (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * ( v[0] + 1 )->Pos.w * f[0]; | ||
1141 | (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * ( v[0] + 1 )->Pos.w * f[1]; | ||
1142 | |||
1143 | (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * ( v[1] + 1 )->Pos.w * f[0]; | ||
1144 | (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * ( v[1] + 1 )->Pos.w * f[1]; | ||
1145 | |||
1146 | (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * ( v[2] + 1 )->Pos.w * f[0]; | ||
1147 | (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * ( v[2] + 1 )->Pos.w * f[1]; | ||
1148 | |||
1149 | #else | ||
1150 | (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * f[0]; | ||
1151 | (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * f[1]; | ||
1152 | |||
1153 | (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * f[0]; | ||
1154 | (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * f[1]; | ||
1155 | |||
1156 | (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * f[0]; | ||
1157 | (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * f[1]; | ||
1158 | #endif | ||
1159 | } | ||
1160 | |||
1161 | // Vertex Cache | ||
1162 | const SVSize CBurningVideoDriver::vSize[] = | ||
1163 | { | ||
1164 | { VERTEX4D_FORMAT_TEXTURE_1 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 1 }, | ||
1165 | { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex2TCoords),2 }, | ||
1166 | { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1 | VERTEX4D_FORMAT_BUMP_DOT3, sizeof(S3DVertexTangents),2 }, | ||
1167 | { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 2 }, // reflection map | ||
1168 | { 0, sizeof(f32) * 3, 0 }, // core::vector3df* | ||
1169 | }; | ||
1170 | |||
1171 | |||
1172 | |||
1173 | /*! | ||
1174 | fill a cache line with transformed, light and clipp test triangles | ||
1175 | */ | ||
1176 | void CBurningVideoDriver::VertexCache_fill(const u32 sourceIndex, const u32 destIndex) | ||
1177 | { | ||
1178 | u8 * source; | ||
1179 | s4DVertex *dest; | ||
1180 | |||
1181 | source = (u8*) VertexCache.vertices + ( sourceIndex * vSize[VertexCache.vType].Pitch ); | ||
1182 | |||
1183 | // it's a look ahead so we never hit it.. | ||
1184 | // but give priority... | ||
1185 | //VertexCache.info[ destIndex ].hit = hitCount; | ||
1186 | |||
1187 | // store info | ||
1188 | VertexCache.info[ destIndex ].index = sourceIndex; | ||
1189 | VertexCache.info[ destIndex ].hit = 0; | ||
1190 | |||
1191 | // destination Vertex | ||
1192 | dest = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( destIndex << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1193 | |||
1194 | // transform Model * World * Camera * Projection * NDCSpace matrix | ||
1195 | const S3DVertex *base = ((S3DVertex*) source ); | ||
1196 | Transformation [ ETS_CURRENT].transformVect ( &dest->Pos.x, base->Pos ); | ||
1197 | |||
1198 | //mhm ;-) maybe no goto | ||
1199 | if ( VertexCache.vType == 4 ) goto clipandproject; | ||
1200 | |||
1201 | |||
1202 | #if defined (SOFTWARE_DRIVER_2_LIGHTING) || defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) | ||
1203 | |||
1204 | // vertex normal in light space | ||
1205 | if ( Material.org.Lighting || (LightSpace.Flags & VERTEXTRANSFORM) ) | ||
1206 | { | ||
1207 | if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) | ||
1208 | { | ||
1209 | LightSpace.normal.set ( base->Normal.X, base->Normal.Y, base->Normal.Z, 1.f ); | ||
1210 | LightSpace.vertex.set ( base->Pos.X, base->Pos.Y, base->Pos.Z, 1.f ); | ||
1211 | } | ||
1212 | else | ||
1213 | { | ||
1214 | Transformation[ETS_WORLD].rotateVect ( &LightSpace.normal.x, base->Normal ); | ||
1215 | |||
1216 | // vertex in light space | ||
1217 | if ( LightSpace.Flags & ( POINTLIGHT | FOG | SPECULAR | VERTEXTRANSFORM) ) | ||
1218 | Transformation[ETS_WORLD].transformVect ( &LightSpace.vertex.x, base->Pos ); | ||
1219 | } | ||
1220 | |||
1221 | if ( LightSpace.Flags & NORMALIZE ) | ||
1222 | LightSpace.normal.normalize_xyz(); | ||
1223 | |||
1224 | } | ||
1225 | |||
1226 | #endif | ||
1227 | |||
1228 | #if defined ( SOFTWARE_DRIVER_2_USE_VERTEX_COLOR ) | ||
1229 | // apply lighting model | ||
1230 | #if defined (SOFTWARE_DRIVER_2_LIGHTING) | ||
1231 | if ( Material.org.Lighting ) | ||
1232 | { | ||
1233 | lightVertex ( dest, base->Color.color ); | ||
1234 | } | ||
1235 | else | ||
1236 | { | ||
1237 | dest->Color[0].setA8R8G8B8 ( base->Color.color ); | ||
1238 | } | ||
1239 | #else | ||
1240 | dest->Color[0].setA8R8G8B8 ( base->Color.color ); | ||
1241 | #endif | ||
1242 | #endif | ||
1243 | |||
1244 | // Texture Transform | ||
1245 | #if !defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) | ||
1246 | irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, | ||
1247 | vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) | ||
1248 | ); | ||
1249 | #else | ||
1250 | |||
1251 | if ( 0 == (LightSpace.Flags & VERTEXTRANSFORM) ) | ||
1252 | { | ||
1253 | irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, | ||
1254 | vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) | ||
1255 | ); | ||
1256 | } | ||
1257 | else | ||
1258 | { | ||
1259 | /* | ||
1260 | Generate texture coordinates as linear functions so that: | ||
1261 | u = Ux*x + Uy*y + Uz*z + Uw | ||
1262 | v = Vx*x + Vy*y + Vz*z + Vw | ||
1263 | The matrix M for this case is: | ||
1264 | Ux Vx 0 0 | ||
1265 | Uy Vy 0 0 | ||
1266 | Uz Vz 0 0 | ||
1267 | Uw Vw 0 0 | ||
1268 | */ | ||
1269 | |||
1270 | u32 t; | ||
1271 | sVec4 n; | ||
1272 | sVec2 srcT; | ||
1273 | |||
1274 | for ( t = 0; t != vSize[VertexCache.vType].TexSize; ++t ) | ||
1275 | { | ||
1276 | const core::matrix4& M = Transformation [ ETS_TEXTURE_0 + t ]; | ||
1277 | |||
1278 | // texgen | ||
1279 | if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & (ETF_TEXGEN_CAMERA_NORMAL|ETF_TEXGEN_CAMERA_REFLECTION) ) | ||
1280 | { | ||
1281 | n.x = LightSpace.campos.x - LightSpace.vertex.x; | ||
1282 | n.y = LightSpace.campos.x - LightSpace.vertex.y; | ||
1283 | n.z = LightSpace.campos.x - LightSpace.vertex.z; | ||
1284 | n.normalize_xyz(); | ||
1285 | n.x += LightSpace.normal.x; | ||
1286 | n.y += LightSpace.normal.y; | ||
1287 | n.z += LightSpace.normal.z; | ||
1288 | n.normalize_xyz(); | ||
1289 | |||
1290 | const f32 *view = Transformation[ETS_VIEW].pointer(); | ||
1291 | |||
1292 | if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & ETF_TEXGEN_CAMERA_REFLECTION ) | ||
1293 | { | ||
1294 | srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[4] + n.z * view[8] )); | ||
1295 | srcT.y = 0.5f * ( 1.f + (n.x * view[1] + n.y * view[5] + n.z * view[9] )); | ||
1296 | } | ||
1297 | else | ||
1298 | { | ||
1299 | srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[1] + n.z * view[2] )); | ||
1300 | srcT.y = 0.5f * ( 1.f + (n.x * view[4] + n.y * view[5] + n.z * view[6] )); | ||
1301 | } | ||
1302 | } | ||
1303 | else | ||
1304 | { | ||
1305 | irr::memcpy32_small ( &srcT,(&base->TCoords) + t, | ||
1306 | sizeof ( f32 ) * 2 ); | ||
1307 | } | ||
1308 | |||
1309 | switch ( Material.org.TextureLayer[t].TextureWrapU ) | ||
1310 | { | ||
1311 | case ETC_CLAMP: | ||
1312 | case ETC_CLAMP_TO_EDGE: | ||
1313 | case ETC_CLAMP_TO_BORDER: | ||
1314 | dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); | ||
1315 | break; | ||
1316 | case ETC_MIRROR: | ||
1317 | dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; | ||
1318 | if (core::fract(dest->Tex[t].x)>0.5f) | ||
1319 | dest->Tex[t].x=1.f-dest->Tex[t].x; | ||
1320 | break; | ||
1321 | case ETC_MIRROR_CLAMP: | ||
1322 | case ETC_MIRROR_CLAMP_TO_EDGE: | ||
1323 | case ETC_MIRROR_CLAMP_TO_BORDER: | ||
1324 | dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); | ||
1325 | if (core::fract(dest->Tex[t].x)>0.5f) | ||
1326 | dest->Tex[t].x=1.f-dest->Tex[t].x; | ||
1327 | break; | ||
1328 | case ETC_REPEAT: | ||
1329 | default: | ||
1330 | dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; | ||
1331 | break; | ||
1332 | } | ||
1333 | switch ( Material.org.TextureLayer[t].TextureWrapV ) | ||
1334 | { | ||
1335 | case ETC_CLAMP: | ||
1336 | case ETC_CLAMP_TO_EDGE: | ||
1337 | case ETC_CLAMP_TO_BORDER: | ||
1338 | dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); | ||
1339 | break; | ||
1340 | case ETC_MIRROR: | ||
1341 | dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; | ||
1342 | if (core::fract(dest->Tex[t].y)>0.5f) | ||
1343 | dest->Tex[t].y=1.f-dest->Tex[t].y; | ||
1344 | break; | ||
1345 | case ETC_MIRROR_CLAMP: | ||
1346 | case ETC_MIRROR_CLAMP_TO_EDGE: | ||
1347 | case ETC_MIRROR_CLAMP_TO_BORDER: | ||
1348 | dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); | ||
1349 | if (core::fract(dest->Tex[t].y)>0.5f) | ||
1350 | dest->Tex[t].y=1.f-dest->Tex[t].y; | ||
1351 | break; | ||
1352 | case ETC_REPEAT: | ||
1353 | default: | ||
1354 | dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; | ||
1355 | break; | ||
1356 | } | ||
1357 | } | ||
1358 | } | ||
1359 | |||
1360 | #if 0 | ||
1361 | // tangent space light vector, emboss | ||
1362 | if ( Lights.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) | ||
1363 | { | ||
1364 | const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); | ||
1365 | const SBurningShaderLight &light = LightSpace.Light[0]; | ||
1366 | |||
1367 | sVec4 vp; | ||
1368 | |||
1369 | vp.x = light.pos.x - LightSpace.vertex.x; | ||
1370 | vp.y = light.pos.y - LightSpace.vertex.y; | ||
1371 | vp.z = light.pos.z - LightSpace.vertex.z; | ||
1372 | |||
1373 | vp.normalize_xyz(); | ||
1374 | |||
1375 | LightSpace.tangent.x = vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z; | ||
1376 | LightSpace.tangent.y = vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z; | ||
1377 | //LightSpace.tangent.z = vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z; | ||
1378 | LightSpace.tangent.z = 0.f; | ||
1379 | LightSpace.tangent.normalize_xyz(); | ||
1380 | |||
1381 | f32 scale = 1.f / 128.f; | ||
1382 | if ( Material.org.MaterialTypeParam > 0.f ) | ||
1383 | scale = Material.org.MaterialTypeParam; | ||
1384 | |||
1385 | // emboss, shift coordinates | ||
1386 | dest->Tex[1].x = dest->Tex[0].x + LightSpace.tangent.x * scale; | ||
1387 | dest->Tex[1].y = dest->Tex[0].y + LightSpace.tangent.y * scale; | ||
1388 | //dest->Tex[1].z = LightSpace.tangent.z * scale; | ||
1389 | } | ||
1390 | #endif | ||
1391 | |||
1392 | if ( LightSpace.Light.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) | ||
1393 | { | ||
1394 | const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); | ||
1395 | |||
1396 | sVec4 vp; | ||
1397 | |||
1398 | dest->LightTangent[0].x = 0.f; | ||
1399 | dest->LightTangent[0].y = 0.f; | ||
1400 | dest->LightTangent[0].z = 0.f; | ||
1401 | for ( u32 i = 0; i < 2 && i < LightSpace.Light.size (); ++i ) | ||
1402 | { | ||
1403 | const SBurningShaderLight &light = LightSpace.Light[i]; | ||
1404 | |||
1405 | if ( !light.LightIsOn ) | ||
1406 | continue; | ||
1407 | |||
1408 | vp.x = light.pos.x - LightSpace.vertex.x; | ||
1409 | vp.y = light.pos.y - LightSpace.vertex.y; | ||
1410 | vp.z = light.pos.z - LightSpace.vertex.z; | ||
1411 | |||
1412 | /* | ||
1413 | vp.x = light.pos_objectspace.x - base->Pos.X; | ||
1414 | vp.y = light.pos_objectspace.y - base->Pos.Y; | ||
1415 | vp.z = light.pos_objectspace.z - base->Pos.Z; | ||
1416 | */ | ||
1417 | |||
1418 | vp.normalize_xyz(); | ||
1419 | |||
1420 | |||
1421 | // transform by tangent matrix | ||
1422 | sVec3 l; | ||
1423 | #if 1 | ||
1424 | l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z ); | ||
1425 | l.y = (vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z ); | ||
1426 | l.z = (vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z ); | ||
1427 | #else | ||
1428 | l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Binormal.X + vp.z * tangent->Normal.X ); | ||
1429 | l.y = (vp.x * tangent->Tangent.Y + vp.y * tangent->Binormal.Y + vp.z * tangent->Normal.Y ); | ||
1430 | l.z = (vp.x * tangent->Tangent.Z + vp.y * tangent->Binormal.Z + vp.z * tangent->Normal.Z ); | ||
1431 | #endif | ||
1432 | |||
1433 | |||
1434 | /* | ||
1435 | f32 scale = 1.f / 128.f; | ||
1436 | scale /= dest->LightTangent[0].b; | ||
1437 | |||
1438 | // emboss, shift coordinates | ||
1439 | dest->Tex[1].x = dest->Tex[0].x + l.r * scale; | ||
1440 | dest->Tex[1].y = dest->Tex[0].y + l.g * scale; | ||
1441 | */ | ||
1442 | dest->Tex[1].x = dest->Tex[0].x; | ||
1443 | dest->Tex[1].y = dest->Tex[0].y; | ||
1444 | |||
1445 | // scale bias | ||
1446 | dest->LightTangent[0].x += l.x; | ||
1447 | dest->LightTangent[0].y += l.y; | ||
1448 | dest->LightTangent[0].z += l.z; | ||
1449 | } | ||
1450 | dest->LightTangent[0].setLength ( 0.5f ); | ||
1451 | dest->LightTangent[0].x += 0.5f; | ||
1452 | dest->LightTangent[0].y += 0.5f; | ||
1453 | dest->LightTangent[0].z += 0.5f; | ||
1454 | } | ||
1455 | |||
1456 | |||
1457 | #endif | ||
1458 | |||
1459 | clipandproject: | ||
1460 | dest[0].flag = dest[1].flag = vSize[VertexCache.vType].Format; | ||
1461 | |||
1462 | // test vertex | ||
1463 | dest[0].flag |= clipToFrustumTest ( dest); | ||
1464 | |||
1465 | // to DC Space, project homogenous vertex | ||
1466 | if ( (dest[0].flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) | ||
1467 | { | ||
1468 | ndc_2_dc_and_project2 ( (const s4DVertex**) &dest, 1 ); | ||
1469 | } | ||
1470 | |||
1471 | //return dest; | ||
1472 | } | ||
1473 | |||
1474 | // | ||
1475 | |||
1476 | REALINLINE s4DVertex * CBurningVideoDriver::VertexCache_getVertex ( const u32 sourceIndex ) | ||
1477 | { | ||
1478 | for ( s32 i = 0; i < VERTEXCACHE_ELEMENT; ++i ) | ||
1479 | { | ||
1480 | if ( VertexCache.info[ i ].index == sourceIndex ) | ||
1481 | { | ||
1482 | return (s4DVertex *) ( (u8*) VertexCache.mem.data + ( i << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1483 | } | ||
1484 | } | ||
1485 | return 0; | ||
1486 | } | ||
1487 | |||
1488 | |||
1489 | /* | ||
1490 | Cache based on linear walk indices | ||
1491 | fill blockwise on the next 16(Cache_Size) unique vertices in indexlist | ||
1492 | merge the next 16 vertices with the current | ||
1493 | */ | ||
1494 | REALINLINE void CBurningVideoDriver::VertexCache_get(const s4DVertex ** face) | ||
1495 | { | ||
1496 | SCacheInfo info[VERTEXCACHE_ELEMENT]; | ||
1497 | |||
1498 | // next primitive must be complete in cache | ||
1499 | if ( VertexCache.indicesIndex - VertexCache.indicesRun < 3 && | ||
1500 | VertexCache.indicesIndex < VertexCache.indexCount | ||
1501 | ) | ||
1502 | { | ||
1503 | // rewind to start of primitive | ||
1504 | VertexCache.indicesIndex = VertexCache.indicesRun; | ||
1505 | |||
1506 | irr::memset32 ( info, VERTEXCACHE_MISS, sizeof ( info ) ); | ||
1507 | |||
1508 | // get the next unique vertices cache line | ||
1509 | u32 fillIndex = 0; | ||
1510 | u32 dIndex; | ||
1511 | u32 i; | ||
1512 | u32 sourceIndex; | ||
1513 | |||
1514 | while ( VertexCache.indicesIndex < VertexCache.indexCount && | ||
1515 | fillIndex < VERTEXCACHE_ELEMENT | ||
1516 | ) | ||
1517 | { | ||
1518 | switch ( VertexCache.iType ) | ||
1519 | { | ||
1520 | case 1: | ||
1521 | sourceIndex = ((u16*)VertexCache.indices) [ VertexCache.indicesIndex ]; | ||
1522 | break; | ||
1523 | case 2: | ||
1524 | sourceIndex = ((u32*)VertexCache.indices) [ VertexCache.indicesIndex ]; | ||
1525 | break; | ||
1526 | case 4: | ||
1527 | sourceIndex = VertexCache.indicesIndex; | ||
1528 | break; | ||
1529 | } | ||
1530 | |||
1531 | VertexCache.indicesIndex += 1; | ||
1532 | |||
1533 | // if not exist, push back | ||
1534 | s32 exist = 0; | ||
1535 | for ( dIndex = 0; dIndex < fillIndex; ++dIndex ) | ||
1536 | { | ||
1537 | if ( info[ dIndex ].index == sourceIndex ) | ||
1538 | { | ||
1539 | exist = 1; | ||
1540 | break; | ||
1541 | } | ||
1542 | } | ||
1543 | |||
1544 | if ( 0 == exist ) | ||
1545 | { | ||
1546 | info[fillIndex++].index = sourceIndex; | ||
1547 | } | ||
1548 | } | ||
1549 | |||
1550 | // clear marks | ||
1551 | for ( i = 0; i!= VERTEXCACHE_ELEMENT; ++i ) | ||
1552 | { | ||
1553 | VertexCache.info[i].hit = 0; | ||
1554 | } | ||
1555 | |||
1556 | // mark all existing | ||
1557 | for ( i = 0; i!= fillIndex; ++i ) | ||
1558 | { | ||
1559 | for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) | ||
1560 | { | ||
1561 | if ( VertexCache.info[ dIndex ].index == info[i].index ) | ||
1562 | { | ||
1563 | info[i].hit = dIndex; | ||
1564 | VertexCache.info[ dIndex ].hit = 1; | ||
1565 | break; | ||
1566 | } | ||
1567 | } | ||
1568 | } | ||
1569 | |||
1570 | // fill new | ||
1571 | for ( i = 0; i!= fillIndex; ++i ) | ||
1572 | { | ||
1573 | if ( info[i].hit != VERTEXCACHE_MISS ) | ||
1574 | continue; | ||
1575 | |||
1576 | for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) | ||
1577 | { | ||
1578 | if ( 0 == VertexCache.info[dIndex].hit ) | ||
1579 | { | ||
1580 | VertexCache_fill ( info[i].index, dIndex ); | ||
1581 | VertexCache.info[dIndex].hit += 1; | ||
1582 | info[i].hit = dIndex; | ||
1583 | break; | ||
1584 | } | ||
1585 | } | ||
1586 | } | ||
1587 | } | ||
1588 | |||
1589 | const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); | ||
1590 | |||
1591 | switch ( VertexCache.iType ) | ||
1592 | { | ||
1593 | case 1: | ||
1594 | { | ||
1595 | const u16 *p = (const u16 *) VertexCache.indices; | ||
1596 | face[0] = VertexCache_getVertex ( p[ i0 ] ); | ||
1597 | face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); | ||
1598 | face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); | ||
1599 | } | ||
1600 | break; | ||
1601 | |||
1602 | case 2: | ||
1603 | { | ||
1604 | const u32 *p = (const u32 *) VertexCache.indices; | ||
1605 | face[0] = VertexCache_getVertex ( p[ i0 ] ); | ||
1606 | face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); | ||
1607 | face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); | ||
1608 | } | ||
1609 | break; | ||
1610 | |||
1611 | case 4: | ||
1612 | face[0] = VertexCache_getVertex ( VertexCache.indicesRun + 0 ); | ||
1613 | face[1] = VertexCache_getVertex ( VertexCache.indicesRun + 1 ); | ||
1614 | face[2] = VertexCache_getVertex ( VertexCache.indicesRun + 2 ); | ||
1615 | break; | ||
1616 | default: | ||
1617 | face[0] = face[1] = face[2] = VertexCache_getVertex(VertexCache.indicesRun + 0); | ||
1618 | break; | ||
1619 | } | ||
1620 | |||
1621 | VertexCache.indicesRun += VertexCache.primitivePitch; | ||
1622 | } | ||
1623 | |||
1624 | /*! | ||
1625 | */ | ||
1626 | REALINLINE void CBurningVideoDriver::VertexCache_getbypass ( s4DVertex ** face ) | ||
1627 | { | ||
1628 | const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); | ||
1629 | |||
1630 | if ( VertexCache.iType == 1 ) | ||
1631 | { | ||
1632 | const u16 *p = (const u16 *) VertexCache.indices; | ||
1633 | VertexCache_fill ( p[ i0 ], 0 ); | ||
1634 | VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); | ||
1635 | VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); | ||
1636 | } | ||
1637 | else | ||
1638 | { | ||
1639 | const u32 *p = (const u32 *) VertexCache.indices; | ||
1640 | VertexCache_fill ( p[ i0 ], 0 ); | ||
1641 | VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); | ||
1642 | VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); | ||
1643 | } | ||
1644 | |||
1645 | VertexCache.indicesRun += VertexCache.primitivePitch; | ||
1646 | |||
1647 | face[0] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1648 | face[1] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1649 | face[2] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); | ||
1650 | |||
1651 | } | ||
1652 | |||
1653 | /*! | ||
1654 | */ | ||
1655 | void CBurningVideoDriver::VertexCache_reset ( const void* vertices, u32 vertexCount, | ||
1656 | const void* indices, u32 primitiveCount, | ||
1657 | E_VERTEX_TYPE vType, | ||
1658 | scene::E_PRIMITIVE_TYPE pType, | ||
1659 | E_INDEX_TYPE iType) | ||
1660 | { | ||
1661 | VertexCache.vertices = vertices; | ||
1662 | VertexCache.vertexCount = vertexCount; | ||
1663 | |||
1664 | VertexCache.indices = indices; | ||
1665 | VertexCache.indicesIndex = 0; | ||
1666 | VertexCache.indicesRun = 0; | ||
1667 | |||
1668 | if ( Material.org.MaterialType == video::EMT_REFLECTION_2_LAYER ) | ||
1669 | VertexCache.vType = 3; | ||
1670 | else | ||
1671 | VertexCache.vType = vType; | ||
1672 | VertexCache.pType = pType; | ||
1673 | |||
1674 | switch ( iType ) | ||
1675 | { | ||
1676 | case EIT_16BIT: VertexCache.iType = 1; break; | ||
1677 | case EIT_32BIT: VertexCache.iType = 2; break; | ||
1678 | default: | ||
1679 | VertexCache.iType = iType; break; | ||
1680 | } | ||
1681 | |||
1682 | switch ( VertexCache.pType ) | ||
1683 | { | ||
1684 | // most types here will not work as expected, only triangles/triangle_fan | ||
1685 | // is known to work. | ||
1686 | case scene::EPT_POINTS: | ||
1687 | VertexCache.indexCount = primitiveCount; | ||
1688 | VertexCache.primitivePitch = 1; | ||
1689 | break; | ||
1690 | case scene::EPT_LINE_STRIP: | ||
1691 | VertexCache.indexCount = primitiveCount+1; | ||
1692 | VertexCache.primitivePitch = 1; | ||
1693 | break; | ||
1694 | case scene::EPT_LINE_LOOP: | ||
1695 | VertexCache.indexCount = primitiveCount+1; | ||
1696 | VertexCache.primitivePitch = 1; | ||
1697 | break; | ||
1698 | case scene::EPT_LINES: | ||
1699 | VertexCache.indexCount = 2*primitiveCount; | ||
1700 | VertexCache.primitivePitch = 2; | ||
1701 | break; | ||
1702 | case scene::EPT_TRIANGLE_STRIP: | ||
1703 | VertexCache.indexCount = primitiveCount+2; | ||
1704 | VertexCache.primitivePitch = 1; | ||
1705 | break; | ||
1706 | case scene::EPT_TRIANGLES: | ||
1707 | VertexCache.indexCount = primitiveCount + primitiveCount + primitiveCount; | ||
1708 | VertexCache.primitivePitch = 3; | ||
1709 | break; | ||
1710 | case scene::EPT_TRIANGLE_FAN: | ||
1711 | VertexCache.indexCount = primitiveCount + 2; | ||
1712 | VertexCache.primitivePitch = 1; | ||
1713 | break; | ||
1714 | case scene::EPT_QUAD_STRIP: | ||
1715 | VertexCache.indexCount = 2*primitiveCount + 2; | ||
1716 | VertexCache.primitivePitch = 2; | ||
1717 | break; | ||
1718 | case scene::EPT_QUADS: | ||
1719 | VertexCache.indexCount = 4*primitiveCount; | ||
1720 | VertexCache.primitivePitch = 4; | ||
1721 | break; | ||
1722 | case scene::EPT_POLYGON: | ||
1723 | VertexCache.indexCount = primitiveCount+1; | ||
1724 | VertexCache.primitivePitch = 1; | ||
1725 | break; | ||
1726 | case scene::EPT_POINT_SPRITES: | ||
1727 | VertexCache.indexCount = primitiveCount; | ||
1728 | VertexCache.primitivePitch = 1; | ||
1729 | break; | ||
1730 | } | ||
1731 | |||
1732 | irr::memset32 ( VertexCache.info, VERTEXCACHE_MISS, sizeof ( VertexCache.info ) ); | ||
1733 | } | ||
1734 | |||
1735 | |||
1736 | void CBurningVideoDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, | ||
1737 | const void* indexList, u32 primitiveCount, | ||
1738 | E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) | ||
1739 | |||
1740 | { | ||
1741 | if (!checkPrimitiveCount(primitiveCount)) | ||
1742 | return; | ||
1743 | |||
1744 | CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); | ||
1745 | |||
1746 | // These calls would lead to crashes due to wrong index usage. | ||
1747 | // The vertex cache needs to be rewritten for these primitives. | ||
1748 | if (pType==scene::EPT_POINTS || pType==scene::EPT_LINE_STRIP || | ||
1749 | pType==scene::EPT_LINE_LOOP || pType==scene::EPT_LINES || pType==scene::EPT_POLYGON || | ||
1750 | pType==scene::EPT_POINT_SPRITES) | ||
1751 | return; | ||
1752 | |||
1753 | if ( 0 == CurrentShader ) | ||
1754 | return; | ||
1755 | |||
1756 | VertexCache_reset ( vertices, vertexCount, indexList, primitiveCount, vType, pType, iType ); | ||
1757 | |||
1758 | const s4DVertex * face[3]; | ||
1759 | |||
1760 | f32 dc_area; | ||
1761 | s32 lodLevel; | ||
1762 | u32 i; | ||
1763 | u32 g; | ||
1764 | u32 m; | ||
1765 | video::CSoftwareTexture2* tex; | ||
1766 | |||
1767 | for ( i = 0; i < (u32) primitiveCount; ++i ) | ||
1768 | { | ||
1769 | VertexCache_get(face); | ||
1770 | |||
1771 | // if fully outside or outside on same side | ||
1772 | if ( ( (face[0]->flag | face[1]->flag | face[2]->flag) & VERTEX4D_CLIPMASK ) | ||
1773 | != VERTEX4D_INSIDE | ||
1774 | ) | ||
1775 | continue; | ||
1776 | |||
1777 | // if fully inside | ||
1778 | if ( ( face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) | ||
1779 | { | ||
1780 | dc_area = screenarea2 ( face ); | ||
1781 | if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0( dc_area ) ) | ||
1782 | continue; | ||
1783 | else | ||
1784 | if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) | ||
1785 | continue; | ||
1786 | |||
1787 | // select mipmap | ||
1788 | dc_area = core::reciprocal ( dc_area ); | ||
1789 | for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) | ||
1790 | { | ||
1791 | if ( 0 == (tex = MAT_TEXTURE ( m )) ) | ||
1792 | { | ||
1793 | CurrentShader->setTextureParam(m, 0, 0); | ||
1794 | continue; | ||
1795 | } | ||
1796 | |||
1797 | lodLevel = s32_log2_f32 ( texelarea2 ( face, m ) * dc_area ); | ||
1798 | CurrentShader->setTextureParam(m, tex, lodLevel ); | ||
1799 | select_polygon_mipmap2 ( (s4DVertex**) face, m, tex->getSize() ); | ||
1800 | } | ||
1801 | |||
1802 | // rasterize | ||
1803 | CurrentShader->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); | ||
1804 | continue; | ||
1805 | } | ||
1806 | |||
1807 | // else if not complete inside clipping necessary | ||
1808 | irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[0], SIZEOF_SVERTEX * 2 ); | ||
1809 | irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[1], SIZEOF_SVERTEX * 2 ); | ||
1810 | irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[2], SIZEOF_SVERTEX * 2 ); | ||
1811 | |||
1812 | const u32 flag = CurrentOut.data->flag & VERTEX4D_FORMAT_MASK; | ||
1813 | |||
1814 | for ( g = 0; g != CurrentOut.ElementSize; ++g ) | ||
1815 | { | ||
1816 | CurrentOut.data[g].flag = flag; | ||
1817 | Temp.data[g].flag = flag; | ||
1818 | } | ||
1819 | |||
1820 | u32 vOut; | ||
1821 | vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); | ||
1822 | if ( vOut < 3 ) | ||
1823 | continue; | ||
1824 | |||
1825 | vOut <<= 1; | ||
1826 | |||
1827 | // to DC Space, project homogenous vertex | ||
1828 | ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); | ||
1829 | |||
1830 | /* | ||
1831 | // TODO: don't stick on 32 Bit Pointer | ||
1832 | #define PointerAsValue(x) ( (u32) (u32*) (x) ) | ||
1833 | |||
1834 | // if not complete inside clipping necessary | ||
1835 | if ( ( test & VERTEX4D_INSIDE ) != VERTEX4D_INSIDE ) | ||
1836 | { | ||
1837 | u32 v[2] = { PointerAsValue ( Temp ) , PointerAsValue ( CurrentOut ) }; | ||
1838 | for ( g = 0; g != 6; ++g ) | ||
1839 | { | ||
1840 | vOut = clipToHyperPlane ( (s4DVertex*) v[0], (s4DVertex*) v[1], vOut, NDCPlane[g] ); | ||
1841 | if ( vOut < 3 ) | ||
1842 | break; | ||
1843 | |||
1844 | v[0] ^= v[1]; | ||
1845 | v[1] ^= v[0]; | ||
1846 | v[0] ^= v[1]; | ||
1847 | } | ||
1848 | |||
1849 | if ( vOut < 3 ) | ||
1850 | continue; | ||
1851 | |||
1852 | } | ||
1853 | */ | ||
1854 | |||
1855 | // check 2d backface culling on first | ||
1856 | dc_area = screenarea ( CurrentOut.data ); | ||
1857 | if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0 ( dc_area ) ) | ||
1858 | continue; | ||
1859 | else if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) | ||
1860 | continue; | ||
1861 | |||
1862 | // select mipmap | ||
1863 | dc_area = core::reciprocal ( dc_area ); | ||
1864 | for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) | ||
1865 | { | ||
1866 | if ( 0 == (tex = MAT_TEXTURE ( m )) ) | ||
1867 | { | ||
1868 | CurrentShader->setTextureParam(m, 0, 0); | ||
1869 | continue; | ||
1870 | } | ||
1871 | |||
1872 | lodLevel = s32_log2_f32 ( texelarea ( CurrentOut.data, m ) * dc_area ); | ||
1873 | CurrentShader->setTextureParam(m, tex, lodLevel ); | ||
1874 | select_polygon_mipmap ( CurrentOut.data, vOut, m, tex->getSize() ); | ||
1875 | } | ||
1876 | |||
1877 | |||
1878 | // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) | ||
1879 | for ( g = 0; g <= vOut - 6; g += 2 ) | ||
1880 | { | ||
1881 | // rasterize | ||
1882 | CurrentShader->drawTriangle ( CurrentOut.data + 0 + 1, | ||
1883 | CurrentOut.data + g + 3, | ||
1884 | CurrentOut.data + g + 5); | ||
1885 | } | ||
1886 | |||
1887 | } | ||
1888 | |||
1889 | // dump statistics | ||
1890 | /* | ||
1891 | char buf [64]; | ||
1892 | sprintf ( buf,"VCount:%d PCount:%d CacheMiss: %d", | ||
1893 | vertexCount, primitiveCount, | ||
1894 | VertexCache.CacheMiss | ||
1895 | ); | ||
1896 | os::Printer::log( buf ); | ||
1897 | */ | ||
1898 | |||
1899 | } | ||
1900 | |||
1901 | |||
1902 | //! Sets the dynamic ambient light color. The default color is | ||
1903 | //! (0,0,0,0) which means it is dark. | ||
1904 | //! \param color: New color of the ambient light. | ||
1905 | void CBurningVideoDriver::setAmbientLight(const SColorf& color) | ||
1906 | { | ||
1907 | LightSpace.Global_AmbientLight.setColorf ( color ); | ||
1908 | } | ||
1909 | |||
1910 | |||
1911 | //! adds a dynamic light | ||
1912 | s32 CBurningVideoDriver::addDynamicLight(const SLight& dl) | ||
1913 | { | ||
1914 | (void) CNullDriver::addDynamicLight( dl ); | ||
1915 | |||
1916 | SBurningShaderLight l; | ||
1917 | // l.org = dl; | ||
1918 | l.Type = dl.Type; | ||
1919 | l.LightIsOn = true; | ||
1920 | |||
1921 | l.AmbientColor.setColorf ( dl.AmbientColor ); | ||
1922 | l.DiffuseColor.setColorf ( dl.DiffuseColor ); | ||
1923 | l.SpecularColor.setColorf ( dl.SpecularColor ); | ||
1924 | |||
1925 | switch ( dl.Type ) | ||
1926 | { | ||
1927 | case video::ELT_DIRECTIONAL: | ||
1928 | l.pos.x = -dl.Direction.X; | ||
1929 | l.pos.y = -dl.Direction.Y; | ||
1930 | l.pos.z = -dl.Direction.Z; | ||
1931 | l.pos.w = 1.f; | ||
1932 | break; | ||
1933 | case ELT_POINT: | ||
1934 | case ELT_SPOT: | ||
1935 | LightSpace.Flags |= POINTLIGHT; | ||
1936 | l.pos.x = dl.Position.X; | ||
1937 | l.pos.y = dl.Position.Y; | ||
1938 | l.pos.z = dl.Position.Z; | ||
1939 | l.pos.w = 1.f; | ||
1940 | /* | ||
1941 | l.radius = (1.f / dl.Attenuation.Y) * (1.f / dl.Attenuation.Y); | ||
1942 | l.constantAttenuation = dl.Attenuation.X; | ||
1943 | l.linearAttenuation = dl.Attenuation.Y; | ||
1944 | l.quadraticAttenuation = dl.Attenuation.Z; | ||
1945 | */ | ||
1946 | l.radius = dl.Radius * dl.Radius; | ||
1947 | l.constantAttenuation = dl.Attenuation.X; | ||
1948 | l.linearAttenuation = 1.f / dl.Radius; | ||
1949 | l.quadraticAttenuation = dl.Attenuation.Z; | ||
1950 | |||
1951 | break; | ||
1952 | default: | ||
1953 | break; | ||
1954 | } | ||
1955 | |||
1956 | LightSpace.Light.push_back ( l ); | ||
1957 | return LightSpace.Light.size() - 1; | ||
1958 | } | ||
1959 | |||
1960 | //! Turns a dynamic light on or off | ||
1961 | void CBurningVideoDriver::turnLightOn(s32 lightIndex, bool turnOn) | ||
1962 | { | ||
1963 | if(lightIndex > -1 && lightIndex < (s32)LightSpace.Light.size()) | ||
1964 | { | ||
1965 | LightSpace.Light[lightIndex].LightIsOn = turnOn; | ||
1966 | } | ||
1967 | } | ||
1968 | |||
1969 | //! deletes all dynamic lights there are | ||
1970 | void CBurningVideoDriver::deleteAllDynamicLights() | ||
1971 | { | ||
1972 | LightSpace.reset (); | ||
1973 | CNullDriver::deleteAllDynamicLights(); | ||
1974 | |||
1975 | } | ||
1976 | |||
1977 | //! returns the maximal amount of dynamic lights the device can handle | ||
1978 | u32 CBurningVideoDriver::getMaximalDynamicLightAmount() const | ||
1979 | { | ||
1980 | return 8; | ||
1981 | } | ||
1982 | |||
1983 | |||
1984 | //! sets a material | ||
1985 | void CBurningVideoDriver::setMaterial(const SMaterial& material) | ||
1986 | { | ||
1987 | Material.org = material; | ||
1988 | |||
1989 | #ifdef SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM | ||
1990 | for (u32 i = 0; i < 2; ++i) | ||
1991 | { | ||
1992 | setTransform((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i), | ||
1993 | material.getTextureMatrix(i)); | ||
1994 | } | ||
1995 | #endif | ||
1996 | |||
1997 | #ifdef SOFTWARE_DRIVER_2_LIGHTING | ||
1998 | Material.AmbientColor.setR8G8B8 ( Material.org.AmbientColor.color ); | ||
1999 | Material.DiffuseColor.setR8G8B8 ( Material.org.DiffuseColor.color ); | ||
2000 | Material.EmissiveColor.setR8G8B8 ( Material.org.EmissiveColor.color ); | ||
2001 | Material.SpecularColor.setR8G8B8 ( Material.org.SpecularColor.color ); | ||
2002 | |||
2003 | core::setbit_cond ( LightSpace.Flags, Material.org.Shininess != 0.f, SPECULAR ); | ||
2004 | core::setbit_cond ( LightSpace.Flags, Material.org.FogEnable, FOG ); | ||
2005 | core::setbit_cond ( LightSpace.Flags, Material.org.NormalizeNormals, NORMALIZE ); | ||
2006 | #endif | ||
2007 | |||
2008 | setCurrentShader(); | ||
2009 | } | ||
2010 | |||
2011 | |||
2012 | /*! | ||
2013 | Camera Position in World Space | ||
2014 | */ | ||
2015 | void CBurningVideoDriver::getCameraPosWorldSpace () | ||
2016 | { | ||
2017 | Transformation[ETS_VIEW_INVERSE] = Transformation[ ETS_VIEW ]; | ||
2018 | Transformation[ETS_VIEW_INVERSE].makeInverse (); | ||
2019 | TransformationFlag[ETS_VIEW_INVERSE] = 0; | ||
2020 | |||
2021 | const f32 *M = Transformation[ETS_VIEW_INVERSE].pointer (); | ||
2022 | |||
2023 | /* The viewpoint is at (0., 0., 0.) in eye space. | ||
2024 | Turning this into a vector [0 0 0 1] and multiply it by | ||
2025 | the inverse of the view matrix, the resulting vector is the | ||
2026 | object space location of the camera. | ||
2027 | */ | ||
2028 | |||
2029 | LightSpace.campos.x = M[12]; | ||
2030 | LightSpace.campos.y = M[13]; | ||
2031 | LightSpace.campos.z = M[14]; | ||
2032 | LightSpace.campos.w = 1.f; | ||
2033 | } | ||
2034 | |||
2035 | void CBurningVideoDriver::getLightPosObjectSpace () | ||
2036 | { | ||
2037 | if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) | ||
2038 | { | ||
2039 | Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; | ||
2040 | TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; | ||
2041 | } | ||
2042 | else | ||
2043 | { | ||
2044 | Transformation[ETS_WORLD].getInverse ( Transformation[ETS_WORLD_INVERSE] ); | ||
2045 | TransformationFlag[ETS_WORLD_INVERSE] &= ~ETF_IDENTITY; | ||
2046 | } | ||
2047 | |||
2048 | for ( u32 i = 0; i < 1 && i < LightSpace.Light.size(); ++i ) | ||
2049 | { | ||
2050 | SBurningShaderLight &l = LightSpace.Light[i]; | ||
2051 | |||
2052 | Transformation[ETS_WORLD_INVERSE].transformVec3 ( &l.pos_objectspace.x, &l.pos.x ); | ||
2053 | } | ||
2054 | } | ||
2055 | |||
2056 | |||
2057 | #ifdef SOFTWARE_DRIVER_2_LIGHTING | ||
2058 | |||
2059 | //! Sets the fog mode. | ||
2060 | void CBurningVideoDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, | ||
2061 | f32 end, f32 density, bool pixelFog, bool rangeFog) | ||
2062 | { | ||
2063 | CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog); | ||
2064 | LightSpace.FogColor.setA8R8G8B8 ( color.color ); | ||
2065 | } | ||
2066 | |||
2067 | /*! | ||
2068 | applies lighting model | ||
2069 | */ | ||
2070 | void CBurningVideoDriver::lightVertex ( s4DVertex *dest, u32 vertexargb ) | ||
2071 | { | ||
2072 | sVec3 dColor; | ||
2073 | |||
2074 | dColor = LightSpace.Global_AmbientLight; | ||
2075 | dColor.add ( Material.EmissiveColor ); | ||
2076 | |||
2077 | if ( Lights.size () == 0 ) | ||
2078 | { | ||
2079 | dColor.saturate( dest->Color[0], vertexargb); | ||
2080 | return; | ||
2081 | } | ||
2082 | |||
2083 | sVec3 ambient; | ||
2084 | sVec3 diffuse; | ||
2085 | sVec3 specular; | ||
2086 | |||
2087 | |||
2088 | // the universe started in darkness.. | ||
2089 | ambient.set ( 0.f, 0.f, 0.f ); | ||
2090 | diffuse.set ( 0.f, 0.f, 0.f ); | ||
2091 | specular.set ( 0.f, 0.f, 0.f ); | ||
2092 | |||
2093 | |||
2094 | u32 i; | ||
2095 | f32 dot; | ||
2096 | f32 len; | ||
2097 | f32 attenuation; | ||
2098 | sVec4 vp; // unit vector vertex to light | ||
2099 | sVec4 lightHalf; // blinn-phong reflection | ||
2100 | |||
2101 | for ( i = 0; i!= LightSpace.Light.size (); ++i ) | ||
2102 | { | ||
2103 | const SBurningShaderLight &light = LightSpace.Light[i]; | ||
2104 | |||
2105 | if ( !light.LightIsOn ) | ||
2106 | continue; | ||
2107 | |||
2108 | // accumulate ambient | ||
2109 | ambient.add ( light.AmbientColor ); | ||
2110 | |||
2111 | switch ( light.Type ) | ||
2112 | { | ||
2113 | case video::ELT_SPOT: | ||
2114 | case video::ELT_POINT: | ||
2115 | // surface to light | ||
2116 | vp.x = light.pos.x - LightSpace.vertex.x; | ||
2117 | vp.y = light.pos.y - LightSpace.vertex.y; | ||
2118 | vp.z = light.pos.z - LightSpace.vertex.z; | ||
2119 | //vp.x = light.pos_objectspace.x - LightSpace.vertex.x; | ||
2120 | //vp.y = light.pos_objectspace.y - LightSpace.vertex.x; | ||
2121 | //vp.z = light.pos_objectspace.z - LightSpace.vertex.x; | ||
2122 | |||
2123 | len = vp.get_length_xyz_square(); | ||
2124 | if ( light.radius < len ) | ||
2125 | continue; | ||
2126 | |||
2127 | len = core::reciprocal_squareroot ( len ); | ||
2128 | |||
2129 | // build diffuse reflection | ||
2130 | |||
2131 | //angle between normal and light vector | ||
2132 | vp.mul ( len ); | ||
2133 | dot = LightSpace.normal.dot_xyz ( vp ); | ||
2134 | if ( dot < 0.f ) | ||
2135 | continue; | ||
2136 | |||
2137 | attenuation = light.constantAttenuation + ( 1.f - ( len * light.linearAttenuation ) ); | ||
2138 | |||
2139 | // diffuse component | ||
2140 | diffuse.mulAdd ( light.DiffuseColor, 3.f * dot * attenuation ); | ||
2141 | |||
2142 | if ( !(LightSpace.Flags & SPECULAR) ) | ||
2143 | continue; | ||
2144 | |||
2145 | // build specular | ||
2146 | // surface to view | ||
2147 | lightHalf.x = LightSpace.campos.x - LightSpace.vertex.x; | ||
2148 | lightHalf.y = LightSpace.campos.y - LightSpace.vertex.y; | ||
2149 | lightHalf.z = LightSpace.campos.z - LightSpace.vertex.z; | ||
2150 | lightHalf.normalize_xyz(); | ||
2151 | lightHalf += vp; | ||
2152 | lightHalf.normalize_xyz(); | ||
2153 | |||
2154 | // specular | ||
2155 | dot = LightSpace.normal.dot_xyz ( lightHalf ); | ||
2156 | if ( dot < 0.f ) | ||
2157 | continue; | ||
2158 | |||
2159 | //specular += light.SpecularColor * ( powf ( Material.org.Shininess ,dot ) * attenuation ); | ||
2160 | specular.mulAdd ( light.SpecularColor, dot * attenuation ); | ||
2161 | break; | ||
2162 | |||
2163 | case video::ELT_DIRECTIONAL: | ||
2164 | |||
2165 | //angle between normal and light vector | ||
2166 | dot = LightSpace.normal.dot_xyz ( light.pos ); | ||
2167 | if ( dot < 0.f ) | ||
2168 | continue; | ||
2169 | |||
2170 | // diffuse component | ||
2171 | diffuse.mulAdd ( light.DiffuseColor, dot ); | ||
2172 | break; | ||
2173 | default: | ||
2174 | break; | ||
2175 | } | ||
2176 | |||
2177 | } | ||
2178 | |||
2179 | // sum up lights | ||
2180 | dColor.mulAdd (ambient, Material.AmbientColor ); | ||
2181 | dColor.mulAdd (diffuse, Material.DiffuseColor); | ||
2182 | dColor.mulAdd (specular, Material.SpecularColor); | ||
2183 | |||
2184 | dColor.saturate ( dest->Color[0], vertexargb ); | ||
2185 | } | ||
2186 | |||
2187 | #endif | ||
2188 | |||
2189 | |||
2190 | //! 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. | ||
2191 | void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos, | ||
2192 | const core::rect<s32>& sourceRect, | ||
2193 | const core::rect<s32>* clipRect, SColor color, | ||
2194 | bool useAlphaChannelOfTexture) | ||
2195 | { | ||
2196 | if (texture) | ||
2197 | { | ||
2198 | if (texture->getDriverType() != EDT_BURNINGSVIDEO) | ||
2199 | { | ||
2200 | os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); | ||
2201 | return; | ||
2202 | } | ||
2203 | |||
2204 | #if 0 | ||
2205 | // 2d methods don't use viewPort | ||
2206 | core::position2di dest = destPos; | ||
2207 | core::recti clip=ViewPort; | ||
2208 | if (ViewPort.getSize().Width != ScreenSize.Width) | ||
2209 | { | ||
2210 | dest.X=ViewPort.UpperLeftCorner.X+core::round32(destPos.X*ViewPort.getWidth()/(f32)ScreenSize.Width); | ||
2211 | dest.Y=ViewPort.UpperLeftCorner.Y+core::round32(destPos.Y*ViewPort.getHeight()/(f32)ScreenSize.Height); | ||
2212 | if (clipRect) | ||
2213 | { | ||
2214 | clip.constrainTo(*clipRect); | ||
2215 | } | ||
2216 | clipRect = &clip; | ||
2217 | } | ||
2218 | #endif | ||
2219 | if (useAlphaChannelOfTexture) | ||
2220 | ((CSoftwareTexture2*)texture)->getImage()->copyToWithAlpha( | ||
2221 | RenderTargetSurface, destPos, sourceRect, color, clipRect); | ||
2222 | else | ||
2223 | ((CSoftwareTexture2*)texture)->getImage()->copyTo( | ||
2224 | RenderTargetSurface, destPos, sourceRect, clipRect); | ||
2225 | } | ||
2226 | } | ||
2227 | |||
2228 | |||
2229 | //! Draws a part of the texture into the rectangle. | ||
2230 | void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect, | ||
2231 | const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect, | ||
2232 | const video::SColor* const colors, bool useAlphaChannelOfTexture) | ||
2233 | { | ||
2234 | if (texture) | ||
2235 | { | ||
2236 | if (texture->getDriverType() != EDT_BURNINGSVIDEO) | ||
2237 | { | ||
2238 | os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); | ||
2239 | return; | ||
2240 | } | ||
2241 | |||
2242 | if (useAlphaChannelOfTexture) | ||
2243 | StretchBlit(BLITTER_TEXTURE_ALPHA_BLEND, RenderTargetSurface, &destRect, &sourceRect, | ||
2244 | ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); | ||
2245 | else | ||
2246 | StretchBlit(BLITTER_TEXTURE, RenderTargetSurface, &destRect, &sourceRect, | ||
2247 | ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); | ||
2248 | } | ||
2249 | } | ||
2250 | |||
2251 | //! Draws a 2d line. | ||
2252 | void CBurningVideoDriver::draw2DLine(const core::position2d<s32>& start, | ||
2253 | const core::position2d<s32>& end, | ||
2254 | SColor color) | ||
2255 | { | ||
2256 | drawLine(BackBuffer, start, end, color ); | ||
2257 | } | ||
2258 | |||
2259 | |||
2260 | //! Draws a pixel | ||
2261 | void CBurningVideoDriver::drawPixel(u32 x, u32 y, const SColor & color) | ||
2262 | { | ||
2263 | BackBuffer->setPixel(x, y, color, true); | ||
2264 | } | ||
2265 | |||
2266 | |||
2267 | //! draw an 2d rectangle | ||
2268 | void CBurningVideoDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos, | ||
2269 | const core::rect<s32>* clip) | ||
2270 | { | ||
2271 | if (clip) | ||
2272 | { | ||
2273 | core::rect<s32> p(pos); | ||
2274 | |||
2275 | p.clipAgainst(*clip); | ||
2276 | |||
2277 | if(!p.isValid()) | ||
2278 | return; | ||
2279 | |||
2280 | drawRectangle(BackBuffer, p, color); | ||
2281 | } | ||
2282 | else | ||
2283 | { | ||
2284 | if(!pos.isValid()) | ||
2285 | return; | ||
2286 | |||
2287 | drawRectangle(BackBuffer, pos, color); | ||
2288 | } | ||
2289 | } | ||
2290 | |||
2291 | |||
2292 | //! Only used by the internal engine. Used to notify the driver that | ||
2293 | //! the window was resized. | ||
2294 | void CBurningVideoDriver::OnResize(const core::dimension2d<u32>& size) | ||
2295 | { | ||
2296 | // make sure width and height are multiples of 2 | ||
2297 | core::dimension2d<u32> realSize(size); | ||
2298 | |||
2299 | if (realSize.Width % 2) | ||
2300 | realSize.Width += 1; | ||
2301 | |||
2302 | if (realSize.Height % 2) | ||
2303 | realSize.Height += 1; | ||
2304 | |||
2305 | if (ScreenSize != realSize) | ||
2306 | { | ||
2307 | if (ViewPort.getWidth() == (s32)ScreenSize.Width && | ||
2308 | ViewPort.getHeight() == (s32)ScreenSize.Height) | ||
2309 | { | ||
2310 | ViewPort.UpperLeftCorner.X = 0; | ||
2311 | ViewPort.UpperLeftCorner.Y = 0; | ||
2312 | ViewPort.LowerRightCorner.X = realSize.Width; | ||
2313 | ViewPort.LowerRightCorner.X = realSize.Height; | ||
2314 | } | ||
2315 | |||
2316 | ScreenSize = realSize; | ||
2317 | |||
2318 | bool resetRT = (RenderTargetSurface == BackBuffer); | ||
2319 | |||
2320 | if (BackBuffer) | ||
2321 | BackBuffer->drop(); | ||
2322 | BackBuffer = new CImage(BURNINGSHADER_COLOR_FORMAT, realSize); | ||
2323 | |||
2324 | if (resetRT) | ||
2325 | setRenderTarget(BackBuffer); | ||
2326 | } | ||
2327 | } | ||
2328 | |||
2329 | |||
2330 | //! returns the current render target size | ||
2331 | const core::dimension2d<u32>& CBurningVideoDriver::getCurrentRenderTargetSize() const | ||
2332 | { | ||
2333 | return RenderTargetSize; | ||
2334 | } | ||
2335 | |||
2336 | |||
2337 | //!Draws an 2d rectangle with a gradient. | ||
2338 | void CBurningVideoDriver::draw2DRectangle(const core::rect<s32>& position, | ||
2339 | SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, | ||
2340 | const core::rect<s32>* clip) | ||
2341 | { | ||
2342 | #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR | ||
2343 | |||
2344 | core::rect<s32> pos = position; | ||
2345 | |||
2346 | if (clip) | ||
2347 | pos.clipAgainst(*clip); | ||
2348 | |||
2349 | if (!pos.isValid()) | ||
2350 | return; | ||
2351 | |||
2352 | const core::dimension2d<s32> renderTargetSize ( ViewPort.getSize() ); | ||
2353 | |||
2354 | const s32 xPlus = -(renderTargetSize.Width>>1); | ||
2355 | const f32 xFact = 1.0f / (renderTargetSize.Width>>1); | ||
2356 | |||
2357 | const s32 yPlus = renderTargetSize.Height-(renderTargetSize.Height>>1); | ||
2358 | const f32 yFact = 1.0f / (renderTargetSize.Height>>1); | ||
2359 | |||
2360 | // fill VertexCache direct | ||
2361 | s4DVertex *v; | ||
2362 | |||
2363 | VertexCache.vertexCount = 4; | ||
2364 | |||
2365 | VertexCache.info[0].index = 0; | ||
2366 | VertexCache.info[1].index = 1; | ||
2367 | VertexCache.info[2].index = 2; | ||
2368 | VertexCache.info[3].index = 3; | ||
2369 | |||
2370 | v = &VertexCache.mem.data [ 0 ]; | ||
2371 | |||
2372 | v[0].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); | ||
2373 | v[0].Color[0].setA8R8G8B8 ( colorLeftUp.color ); | ||
2374 | |||
2375 | v[2].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus- pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); | ||
2376 | v[2].Color[0].setA8R8G8B8 ( colorRightUp.color ); | ||
2377 | |||
2378 | v[4].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f ,1.f ); | ||
2379 | v[4].Color[0].setA8R8G8B8 ( colorRightDown.color ); | ||
2380 | |||
2381 | v[6].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f, 1.f ); | ||
2382 | v[6].Color[0].setA8R8G8B8 ( colorLeftDown.color ); | ||
2383 | |||
2384 | s32 i; | ||
2385 | u32 g; | ||
2386 | |||
2387 | for ( i = 0; i!= 8; i += 2 ) | ||
2388 | { | ||
2389 | v[i + 0].flag = clipToFrustumTest ( v + i ); | ||
2390 | v[i + 1].flag = 0; | ||
2391 | if ( (v[i].flag & VERTEX4D_INSIDE ) == VERTEX4D_INSIDE ) | ||
2392 | { | ||
2393 | ndc_2_dc_and_project ( v + i + 1, v + i, 2 ); | ||
2394 | } | ||
2395 | } | ||
2396 | |||
2397 | |||
2398 | IBurningShader * render; | ||
2399 | |||
2400 | render = BurningShader [ ETR_GOURAUD_ALPHA_NOZ ]; | ||
2401 | render->setRenderTarget(RenderTargetSurface, ViewPort); | ||
2402 | |||
2403 | static const s16 indexList[6] = {0,1,2,0,2,3}; | ||
2404 | |||
2405 | s4DVertex * face[3]; | ||
2406 | |||
2407 | for ( i = 0; i!= 6; i += 3 ) | ||
2408 | { | ||
2409 | face[0] = VertexCache_getVertex ( indexList [ i + 0 ] ); | ||
2410 | face[1] = VertexCache_getVertex ( indexList [ i + 1 ] ); | ||
2411 | face[2] = VertexCache_getVertex ( indexList [ i + 2 ] ); | ||
2412 | |||
2413 | // test clipping | ||
2414 | u32 test = face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_INSIDE; | ||
2415 | |||
2416 | if ( test == VERTEX4D_INSIDE ) | ||
2417 | { | ||
2418 | render->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); | ||
2419 | continue; | ||
2420 | } | ||
2421 | // Todo: all vertices are clipped in 2d.. | ||
2422 | // is this true ? | ||
2423 | u32 vOut = 6; | ||
2424 | memcpy ( CurrentOut.data + 0, face[0], sizeof ( s4DVertex ) * 2 ); | ||
2425 | memcpy ( CurrentOut.data + 2, face[1], sizeof ( s4DVertex ) * 2 ); | ||
2426 | memcpy ( CurrentOut.data + 4, face[2], sizeof ( s4DVertex ) * 2 ); | ||
2427 | |||
2428 | vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); | ||
2429 | if ( vOut < 3 ) | ||
2430 | continue; | ||
2431 | |||
2432 | vOut <<= 1; | ||
2433 | // to DC Space, project homogenous vertex | ||
2434 | ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); | ||
2435 | |||
2436 | // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) | ||
2437 | for ( g = 0; g <= vOut - 6; g += 2 ) | ||
2438 | { | ||
2439 | // rasterize | ||
2440 | render->drawTriangle ( CurrentOut.data + 1, &CurrentOut.data[g + 3], &CurrentOut.data[g + 5] ); | ||
2441 | } | ||
2442 | |||
2443 | } | ||
2444 | #else | ||
2445 | draw2DRectangle ( colorLeftUp, position, clip ); | ||
2446 | #endif | ||
2447 | } | ||
2448 | |||
2449 | |||
2450 | //! Draws a 3d line. | ||
2451 | void CBurningVideoDriver::draw3DLine(const core::vector3df& start, | ||
2452 | const core::vector3df& end, SColor color) | ||
2453 | { | ||
2454 | Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[0].Pos.x, start ); | ||
2455 | Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[2].Pos.x, end ); | ||
2456 | |||
2457 | u32 g; | ||
2458 | u32 vOut; | ||
2459 | |||
2460 | // no clipping flags | ||
2461 | for ( g = 0; g != CurrentOut.ElementSize; ++g ) | ||
2462 | { | ||
2463 | CurrentOut.data[g].flag = 0; | ||
2464 | Temp.data[g].flag = 0; | ||
2465 | } | ||
2466 | |||
2467 | // vertices count per line | ||
2468 | vOut = clipToFrustum ( CurrentOut.data, Temp.data, 2 ); | ||
2469 | if ( vOut < 2 ) | ||
2470 | return; | ||
2471 | |||
2472 | vOut <<= 1; | ||
2473 | |||
2474 | IBurningShader * line; | ||
2475 | line = BurningShader [ ETR_TEXTURE_GOURAUD_WIRE ]; | ||
2476 | line->setRenderTarget(RenderTargetSurface, ViewPort); | ||
2477 | |||
2478 | // to DC Space, project homogenous vertex | ||
2479 | ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); | ||
2480 | |||
2481 | // unproject vertex color | ||
2482 | #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR | ||
2483 | for ( g = 0; g != vOut; g+= 2 ) | ||
2484 | { | ||
2485 | CurrentOut.data[ g + 1].Color[0].setA8R8G8B8 ( color.color ); | ||
2486 | } | ||
2487 | #endif | ||
2488 | |||
2489 | |||
2490 | for ( g = 0; g <= vOut - 4; g += 2 ) | ||
2491 | { | ||
2492 | // rasterize | ||
2493 | line->drawLine ( CurrentOut.data + 1, CurrentOut.data + g + 3 ); | ||
2494 | } | ||
2495 | } | ||
2496 | |||
2497 | |||
2498 | //! \return Returns the name of the video driver. Example: In case of the DirectX8 | ||
2499 | //! driver, it would return "Direct3D8.1". | ||
2500 | const wchar_t* CBurningVideoDriver::getName() const | ||
2501 | { | ||
2502 | #ifdef BURNINGVIDEO_RENDERER_BEAUTIFUL | ||
2503 | return L"Burning's Video 0.47 beautiful"; | ||
2504 | #elif defined ( BURNINGVIDEO_RENDERER_ULTRA_FAST ) | ||
2505 | return L"Burning's Video 0.47 ultra fast"; | ||
2506 | #elif defined ( BURNINGVIDEO_RENDERER_FAST ) | ||
2507 | return L"Burning's Video 0.47 fast"; | ||
2508 | #else | ||
2509 | return L"Burning's Video 0.47"; | ||
2510 | #endif | ||
2511 | } | ||
2512 | |||
2513 | //! Returns the graphics card vendor name. | ||
2514 | core::stringc CBurningVideoDriver::getVendorInfo() | ||
2515 | { | ||
2516 | return "Burning's Video: Ing. Thomas Alten (c) 2006-2012"; | ||
2517 | } | ||
2518 | |||
2519 | |||
2520 | //! Returns type of video driver | ||
2521 | E_DRIVER_TYPE CBurningVideoDriver::getDriverType() const | ||
2522 | { | ||
2523 | return EDT_BURNINGSVIDEO; | ||
2524 | } | ||
2525 | |||
2526 | |||
2527 | //! returns color format | ||
2528 | ECOLOR_FORMAT CBurningVideoDriver::getColorFormat() const | ||
2529 | { | ||
2530 | return BURNINGSHADER_COLOR_FORMAT; | ||
2531 | } | ||
2532 | |||
2533 | |||
2534 | //! Returns the transformation set by setTransform | ||
2535 | const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE state) const | ||
2536 | { | ||
2537 | return Transformation[state]; | ||
2538 | } | ||
2539 | |||
2540 | |||
2541 | //! Creates a render target texture. | ||
2542 | ITexture* CBurningVideoDriver::addRenderTargetTexture(const core::dimension2d<u32>& size, | ||
2543 | const io::path& name, const ECOLOR_FORMAT format) | ||
2544 | { | ||
2545 | IImage* img = createImage(BURNINGSHADER_COLOR_FORMAT, size); | ||
2546 | ITexture* tex = new CSoftwareTexture2(img, name, CSoftwareTexture2::IS_RENDERTARGET ); | ||
2547 | img->drop(); | ||
2548 | addTexture(tex); | ||
2549 | tex->drop(); | ||
2550 | return tex; | ||
2551 | } | ||
2552 | |||
2553 | |||
2554 | //! Clears the DepthBuffer. | ||
2555 | void CBurningVideoDriver::clearZBuffer() | ||
2556 | { | ||
2557 | if (DepthBuffer) | ||
2558 | DepthBuffer->clear(); | ||
2559 | } | ||
2560 | |||
2561 | |||
2562 | //! Returns an image created from the last rendered frame. | ||
2563 | IImage* CBurningVideoDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) | ||
2564 | { | ||
2565 | if (target != video::ERT_FRAME_BUFFER) | ||
2566 | return 0; | ||
2567 | |||
2568 | if (BackBuffer) | ||
2569 | { | ||
2570 | IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension()); | ||
2571 | BackBuffer->copyTo(tmp); | ||
2572 | return tmp; | ||
2573 | } | ||
2574 | else | ||
2575 | return 0; | ||
2576 | } | ||
2577 | |||
2578 | |||
2579 | //! returns a device dependent texture from a software surface (IImage) | ||
2580 | //! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES | ||
2581 | ITexture* CBurningVideoDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData) | ||
2582 | { | ||
2583 | return new CSoftwareTexture2( | ||
2584 | surface, name, | ||
2585 | (getTextureCreationFlag(ETCF_CREATE_MIP_MAPS) ? CSoftwareTexture2::GEN_MIPMAP : 0 ) | | ||
2586 | (getTextureCreationFlag(ETCF_ALLOW_NON_POWER_2) ? 0 : CSoftwareTexture2::NP2_SIZE ), mipmapData); | ||
2587 | |||
2588 | } | ||
2589 | |||
2590 | |||
2591 | //! Returns the maximum amount of primitives (mostly vertices) which | ||
2592 | //! the device is able to render with one drawIndexedTriangleList | ||
2593 | //! call. | ||
2594 | u32 CBurningVideoDriver::getMaximalPrimitiveCount() const | ||
2595 | { | ||
2596 | return 0xFFFFFFFF; | ||
2597 | } | ||
2598 | |||
2599 | |||
2600 | //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do | ||
2601 | //! this: First, draw all geometry. Then use this method, to draw the shadow | ||
2602 | //! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. | ||
2603 | void CBurningVideoDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible) | ||
2604 | { | ||
2605 | const u32 count = triangles.size(); | ||
2606 | IBurningShader *shader = BurningShader [ ETR_STENCIL_SHADOW ]; | ||
2607 | |||
2608 | CurrentShader = shader; | ||
2609 | shader->setRenderTarget(RenderTargetSurface, ViewPort); | ||
2610 | |||
2611 | Material.org.MaterialType = video::EMT_SOLID; | ||
2612 | Material.org.Lighting = false; | ||
2613 | Material.org.ZWriteEnable = false; | ||
2614 | Material.org.ZBuffer = ECFN_LESSEQUAL; | ||
2615 | LightSpace.Flags &= ~VERTEXTRANSFORM; | ||
2616 | |||
2617 | //glStencilMask(~0); | ||
2618 | //glStencilFunc(GL_ALWAYS, 0, ~0); | ||
2619 | |||
2620 | if (true)// zpass does not work yet | ||
2621 | { | ||
2622 | Material.org.BackfaceCulling = true; | ||
2623 | Material.org.FrontfaceCulling = false; | ||
2624 | shader->setParam ( 0, 0 ); | ||
2625 | shader->setParam ( 1, 1 ); | ||
2626 | shader->setParam ( 2, 0 ); | ||
2627 | drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); | ||
2628 | //glStencilOp(GL_KEEP, incr, GL_KEEP); | ||
2629 | //glDrawArrays(GL_TRIANGLES,0,count); | ||
2630 | |||
2631 | Material.org.BackfaceCulling = false; | ||
2632 | Material.org.FrontfaceCulling = true; | ||
2633 | shader->setParam ( 0, 0 ); | ||
2634 | shader->setParam ( 1, 2 ); | ||
2635 | shader->setParam ( 2, 0 ); | ||
2636 | drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); | ||
2637 | //glStencilOp(GL_KEEP, decr, GL_KEEP); | ||
2638 | //glDrawArrays(GL_TRIANGLES,0,count); | ||
2639 | } | ||
2640 | else // zpass | ||
2641 | { | ||
2642 | Material.org.BackfaceCulling = true; | ||
2643 | Material.org.FrontfaceCulling = false; | ||
2644 | shader->setParam ( 0, 0 ); | ||
2645 | shader->setParam ( 1, 0 ); | ||
2646 | shader->setParam ( 2, 1 ); | ||
2647 | //glStencilOp(GL_KEEP, GL_KEEP, incr); | ||
2648 | //glDrawArrays(GL_TRIANGLES,0,count); | ||
2649 | |||
2650 | Material.org.BackfaceCulling = false; | ||
2651 | Material.org.FrontfaceCulling = true; | ||
2652 | shader->setParam ( 0, 0 ); | ||
2653 | shader->setParam ( 1, 0 ); | ||
2654 | shader->setParam ( 2, 2 ); | ||
2655 | //glStencilOp(GL_KEEP, GL_KEEP, decr); | ||
2656 | //glDrawArrays(GL_TRIANGLES,0,count); | ||
2657 | } | ||
2658 | } | ||
2659 | |||
2660 | //! Fills the stencil shadow with color. After the shadow volume has been drawn | ||
2661 | //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this | ||
2662 | //! to draw the color of the shadow. | ||
2663 | void CBurningVideoDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, | ||
2664 | video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) | ||
2665 | { | ||
2666 | if (!StencilBuffer) | ||
2667 | return; | ||
2668 | // draw a shadow rectangle covering the entire screen using stencil buffer | ||
2669 | const u32 h = RenderTargetSurface->getDimension().Height; | ||
2670 | const u32 w = RenderTargetSurface->getDimension().Width; | ||
2671 | tVideoSample *dst; | ||
2672 | u32 *stencil; | ||
2673 | u32* const stencilBase=(u32*) StencilBuffer->lock(); | ||
2674 | |||
2675 | for ( u32 y = 0; y < h; ++y ) | ||
2676 | { | ||
2677 | dst = (tVideoSample*)RenderTargetSurface->lock() + ( y * w ); | ||
2678 | stencil = stencilBase + ( y * w ); | ||
2679 | |||
2680 | for ( u32 x = 0; x < w; ++x ) | ||
2681 | { | ||
2682 | if ( stencil[x] > 1 ) | ||
2683 | { | ||
2684 | dst[x] = PixelBlend32 ( dst[x], leftUpEdge.color ); | ||
2685 | } | ||
2686 | } | ||
2687 | } | ||
2688 | |||
2689 | StencilBuffer->clear(); | ||
2690 | } | ||
2691 | |||
2692 | |||
2693 | core::dimension2du CBurningVideoDriver::getMaxTextureSize() const | ||
2694 | { | ||
2695 | return core::dimension2du(SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE, SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE); | ||
2696 | } | ||
2697 | |||
2698 | |||
2699 | } // end namespace video | ||
2700 | } // end namespace irr | ||
2701 | |||
2702 | #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ | ||
2703 | |||
2704 | namespace irr | ||
2705 | { | ||
2706 | namespace video | ||
2707 | { | ||
2708 | |||
2709 | //! creates a video driver | ||
2710 | IVideoDriver* createBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter) | ||
2711 | { | ||
2712 | #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ | ||
2713 | return new CBurningVideoDriver(params, io, presenter); | ||
2714 | #else | ||
2715 | return 0; | ||
2716 | #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ | ||
2717 | } | ||
2718 | |||
2719 | |||
2720 | |||
2721 | } // end namespace video | ||
2722 | } // end namespace irr | ||
2723 | |||