aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CSoftwareDriver2.cpp
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-03-28 22:28:34 +1000
committerDavid Walter Seikel2016-03-28 22:28:34 +1000
commit7028cbe09c688437910a25623098762bf0fa592d (patch)
tree10b5af58277d9880380c2251f109325542c4e6eb /src/others/irrlicht-1.8.1/source/Irrlicht/CSoftwareDriver2.cpp
parentMove lemon to the src/others directory. (diff)
downloadSledjHamr-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.cpp2723
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
21namespace irr
22{
23namespace video
24{
25
26namespace glsl
27{
28
29typedef sVec4 vec4;
30typedef sVec3 vec3;
31typedef 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
42struct 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
53struct mat3{
54 float m[3][3];
55
56 vec3 operator* ( const vec3 &in ) const
57 {
58 vec3 out;
59 return out;
60 }
61};
62
63const int gl_MaxLights = 8;
64
65
66inline float dot (float x, float y) { return x * y; }
67inline float dot ( const vec2 &x, const vec2 &y) { return x.x * y.x + x.y * y.y; }
68inline float dot ( const vec3 &x, const vec3 &y) { return x.x * y.x + x.y * y.y + x.z * y.z; }
69inline 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
71inline float reflect (float I, float N) { return I - 2.0 * dot (N, I) * N; }
72inline vec2 reflect (const vec2 &I, const vec2 &N) { return I - N * 2.0 * dot (N, I); }
73inline vec3 reflect (const vec3 &I, const vec3 &N) { return I - N * 2.0 * dot (N, I); }
74inline vec4 reflect (const vec4 &I, const vec4 &N) { return I - N * 2.0 * dot (N, I); }
75
76
77inline 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
84inline 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
91inline 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
98inline 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
106inline float length ( const vec3 &v ) { return sqrtf ( v.x * v.x + v.y * v.y + v.z * v.z ); }
107vec3 normalize ( const vec3 &v ) { float l = 1.f / length ( v ); return vec3 ( v.x * l, v.y * l, v.z * l ); }
108float max ( float a, float b ) { return a > b ? a : b; }
109float min ( float a, float b ) { return a < b ? a : b; }
110vec4 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
114typedef int sampler2D;
115sampler2D texUnit0;
116
117vec4 texture2D (sampler2D sampler, const vec2 &coord) { return vec4 (0.0); }
118
119struct 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
136uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];
137
138struct gl_LightModelParameters {
139 vec4 ambient;
140};
141uniform gl_LightModelParameters gl_LightModel;
142
143struct gl_LightModelProducts {
144 vec4 sceneColor;
145};
146
147uniform gl_LightModelProducts gl_FrontLightModelProduct;
148uniform gl_LightModelProducts gl_BackLightModelProduct;
149
150struct gl_LightProducts {
151 vec4 ambient;
152 vec4 diffuse;
153 vec4 specular;
154};
155
156uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights];
157uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights];
158
159struct gl_MaterialParameters
160{
161 vec4 emission; // Ecm
162 vec4 ambient; // Acm
163 vec4 diffuse; // Dcm
164 vec4 specular; // Scm
165 float shininess; // Srm
166};
167uniform gl_MaterialParameters gl_FrontMaterial;
168uniform gl_MaterialParameters gl_BackMaterial;
169
170// GLSL has some built-in attributes in a vertex shader:
171attribute vec4 gl_Vertex; // 4D vector representing the vertex position
172attribute vec3 gl_Normal; // 3D vector representing the vertex normal
173attribute vec4 gl_Color; // 4D vector representing the vertex color
174attribute vec4 gl_MultiTexCoord0; // 4D vector representing the texture coordinate of texture unit X
175attribute vec4 gl_MultiTexCoord1; // 4D vector representing the texture coordinate of texture unit X
176
177uniform mat4 gl_ModelViewMatrix; //4x4 Matrix representing the model-view matrix.
178uniform mat4 gl_ModelViewProjectionMatrix; //4x4 Matrix representing the model-view-projection matrix.
179uniform mat3 gl_NormalMatrix; //3x3 Matrix representing the inverse transpose model-view matrix. This matrix is used for normal transformation.
180
181
182varying vec4 gl_FrontColor; // 4D vector representing the primitives front color
183varying vec4 gl_FrontSecondaryColor; // 4D vector representing the primitives second front color
184varying vec4 gl_BackColor; // 4D vector representing the primitives back color
185varying vec4 gl_TexCoord[4]; // 4D vector representing the Xth texture coordinate
186
187// shader output
188varying vec4 gl_Position; // 4D vector representing the final processed vertex position. Only available in vertex shader.
189varying vec4 gl_FragColor; // 4D vector representing the final color which is written in the frame buffer. Only available in fragment shader.
190varying float gl_FragDepth; // float representing the depth which is written in the depth buffer. Only available in fragment shader.
191
192varying vec4 gl_SecondaryColor;
193varying float gl_FogFragCoord;
194
195
196vec4 ftransform(void)
197{
198 return gl_ModelViewProjectionMatrix * gl_Vertex;
199}
200
201vec3 fnormal(void)
202{
203 //Compute the normal
204 vec3 normal = gl_NormalMatrix * gl_Normal;
205 normal = normalize(normal);
206 return normal;
207}
208
209
210struct 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
335CBurningVideoDriver::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
450CBurningVideoDriver::~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*/
482void 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
610bool 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
640void 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
686bool 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
706bool CBurningVideoDriver::endScene()
707{
708 CNullDriver::endScene();
709
710 return Presenter->present(BackBuffer, WindowId, SceneSourceRect);
711}
712
713
714//! sets a render target
715bool 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
753void 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
780void 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
799const 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
834REALINLINE 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
872REALINLINE 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
896u32 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
959u32 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*/
987inline 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
1023inline 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*/
1068inline 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*/
1077inline 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*/
1090inline 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*/
1098inline 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*/
1110inline 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
1132inline 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
1162const 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*/
1176void 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
1459clipandproject:
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
1476REALINLINE 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*/
1494REALINLINE 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*/
1626REALINLINE 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*/
1655void 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
1736void 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.
1905void CBurningVideoDriver::setAmbientLight(const SColorf& color)
1906{
1907 LightSpace.Global_AmbientLight.setColorf ( color );
1908}
1909
1910
1911//! adds a dynamic light
1912s32 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
1961void 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
1970void CBurningVideoDriver::deleteAllDynamicLights()
1971{
1972 LightSpace.reset ();
1973 CNullDriver::deleteAllDynamicLights();
1974
1975}
1976
1977//! returns the maximal amount of dynamic lights the device can handle
1978u32 CBurningVideoDriver::getMaximalDynamicLightAmount() const
1979{
1980 return 8;
1981}
1982
1983
1984//! sets a material
1985void 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*/
2015void 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
2035void 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.
2060void 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*/
2070void 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.
2191void 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.
2230void 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.
2252void 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
2261void 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
2268void 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.
2294void 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
2331const core::dimension2d<u32>& CBurningVideoDriver::getCurrentRenderTargetSize() const
2332{
2333 return RenderTargetSize;
2334}
2335
2336
2337//!Draws an 2d rectangle with a gradient.
2338void 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.
2451void 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".
2500const 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.
2514core::stringc CBurningVideoDriver::getVendorInfo()
2515{
2516 return "Burning's Video: Ing. Thomas Alten (c) 2006-2012";
2517}
2518
2519
2520//! Returns type of video driver
2521E_DRIVER_TYPE CBurningVideoDriver::getDriverType() const
2522{
2523 return EDT_BURNINGSVIDEO;
2524}
2525
2526
2527//! returns color format
2528ECOLOR_FORMAT CBurningVideoDriver::getColorFormat() const
2529{
2530 return BURNINGSHADER_COLOR_FORMAT;
2531}
2532
2533
2534//! Returns the transformation set by setTransform
2535const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE state) const
2536{
2537 return Transformation[state];
2538}
2539
2540
2541//! Creates a render target texture.
2542ITexture* 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.
2555void CBurningVideoDriver::clearZBuffer()
2556{
2557 if (DepthBuffer)
2558 DepthBuffer->clear();
2559}
2560
2561
2562//! Returns an image created from the last rendered frame.
2563IImage* 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
2581ITexture* 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.
2594u32 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.
2603void 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.
2663void 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
2693core::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
2704namespace irr
2705{
2706namespace video
2707{
2708
2709//! creates a video driver
2710IVideoDriver* 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