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 
operator *irr::video::glsl::mat445    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 
operator *irr::video::glsl::mat356    vec3 operator* ( const vec3 &in ) const
57    {
58 	   vec3 out;
59 	   return out;
60    }
61 };
62 
63 const int gl_MaxLights = 8;
64 
65 
dot(float x,float y)66 inline float dot (float x, float y) { return x * y; }
dot(const vec2 & x,const vec2 & y)67 inline float dot ( const vec2 &x, const vec2 &y) { return x.x * y.x + x.y * y.y; }
dot(const vec3 & x,const vec3 & y)68 inline float dot ( const vec3 &x, const vec3 &y) { return x.x * y.x + x.y * y.y + x.z * y.z; }
dot(const vec4 & x,const vec4 & y)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 
reflect(float I,float N)71 inline float reflect (float I, float N)				{ return I - 2.0 * dot (N, I) * N; }
reflect(const vec2 & I,const vec2 & N)72 inline vec2 reflect (const vec2 &I, const vec2 &N)	{ return I - N * 2.0 * dot (N, I); }
reflect(const vec3 & I,const vec3 & N)73 inline vec3 reflect (const vec3 &I, const vec3 &N)	{ return I - N * 2.0 * dot (N, I); }
reflect(const vec4 & I,const vec4 & N)74 inline vec4 reflect (const vec4 &I, const vec4 &N)	{ return I - N * 2.0 * dot (N, I); }
75 
76 
refract(float I,float N,float eta)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 
refract(const vec2 & I,const vec2 & N,float eta)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 
refract(const vec3 & I,const vec3 & N,float eta)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 
refract(const vec4 & I,const vec4 & N,float eta)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 
length(const vec3 & v)106 inline float length ( const vec3 &v ) { return sqrtf ( v.x * v.x + v.y * v.y + v.z * v.z ); }
normalize(const vec3 & v)107 vec3 normalize ( const vec3 &v ) { 	float l = 1.f / length ( v ); return vec3 ( v.x * l, v.y * l, v.z * l ); }
max(float a,float b)108 float max ( float a, float b ) { return a > b ? a : b; }
min(float a,float b)109 float min ( float a, float b ) { return a < b ? a : b; }
clamp(const vec4 & a,f32 low,f32 high)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 
texture2D(sampler2D sampler,const vec2 & coord)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 
ftransform(void)196 vec4 ftransform(void)
197 {
198 	return gl_ModelViewProjectionMatrix * gl_Vertex;
199 }
200 
fnormal(void)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 
pointLightirr::video::glsl::program1216 	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 
fnormalirr::video::glsl::program1259 	vec3 fnormal(void)
260 	{
261 		//Compute the normal
262 		vec3 normal = gl_NormalMatrix * gl_Normal;
263 		normal = normalize(normal);
264 		return normal;
265 	}
266 
ftexgenirr::video::glsl::program1267 	void ftexgen(in vec3 normal, in vec4 ecPosition)
268 	{
269 
270 		gl_TexCoord[0] = gl_MultiTexCoord0;
271 	}
272 
flightirr::video::glsl::program1273 	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 
vertexshader_mainirr::video::glsl::program1302 	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 
fragmentshader_mainirr::video::glsl::program1317 	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
CBurningVideoDriver(const irr::SIrrlichtCreationParameters & params,io::IFileSystem * io,video::IImagePresenter * presenter)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
~CBurningVideoDriver()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 */
setCurrentShader()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
queryFeature(E_VIDEO_DRIVER_FEATURE feature) const610 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
setTransform(E_TRANSFORMATION_STATE state,const core::matrix4 & mat)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
beginScene(bool backBuffer,bool zBuffer,SColor color,const SExposedVideoData & videoData,core::rect<s32> * sourceRect)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
endScene()706 bool CBurningVideoDriver::endScene()
707 {
708 	CNullDriver::endScene();
709 
710 	return Presenter->present(BackBuffer, WindowId, SceneSourceRect);
711 }
712 
713 
714 //! sets a render target
setRenderTarget(video::ITexture * texture,bool clearBackBuffer,bool clearZBuffer,SColor color)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
setRenderTarget(video::CImage * image)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
setViewPort(const core::rect<s32> & area)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 
clipToFrustumTest(const s4DVertex * v) const834 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 
clipToFrustumTest(const s4DVertex * v) const872 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 
clipToHyperPlane(s4DVertex * dest,const s4DVertex * source,u32 inCount,const sVec4 & plane)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 
clipToFrustum(s4DVertex * v0,s4DVertex * v1,const u32 vIn)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 */
ndc_2_dc_and_project(s4DVertex * dest,s4DVertex * source,u32 vIn) const987 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 
ndc_2_dc_and_project2(const s4DVertex ** v,const u32 size) const1023 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 */
screenarea(const s4DVertex * v) const1068 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 */
texelarea(const s4DVertex * v,int tex) const1077 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 */
screenarea2(const s4DVertex ** v) const1090 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 */
texelarea2(const s4DVertex ** v,s32 tex) const1098 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 */
select_polygon_mipmap(s4DVertex * v,u32 vIn,u32 tex,const core::dimension2du & texSize) const1110 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 
select_polygon_mipmap2(s4DVertex ** v,u32 tex,const core::dimension2du & texSize) const1132 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 */
VertexCache_fill(const u32 sourceIndex,const u32 destIndex)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 
VertexCache_getVertex(const u32 sourceIndex)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 */
VertexCache_get(const s4DVertex ** face)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 */
VertexCache_getbypass(s4DVertex ** face)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 */
VertexCache_reset(const void * vertices,u32 vertexCount,const void * indices,u32 primitiveCount,E_VERTEX_TYPE vType,scene::E_PRIMITIVE_TYPE pType,E_INDEX_TYPE iType)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 
drawVertexPrimitiveList(const void * vertices,u32 vertexCount,const void * indexList,u32 primitiveCount,E_VERTEX_TYPE vType,scene::E_PRIMITIVE_TYPE pType,E_INDEX_TYPE iType)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.
setAmbientLight(const SColorf & color)1905 void CBurningVideoDriver::setAmbientLight(const SColorf& color)
1906 {
1907 	LightSpace.Global_AmbientLight.setColorf ( color );
1908 }
1909 
1910 
1911 //! adds a dynamic light
addDynamicLight(const SLight & dl)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
turnLightOn(s32 lightIndex,bool turnOn)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
deleteAllDynamicLights()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
getMaximalDynamicLightAmount() const1978 u32 CBurningVideoDriver::getMaximalDynamicLightAmount() const
1979 {
1980 	return 8;
1981 }
1982 
1983 
1984 //! sets a material
setMaterial(const SMaterial & 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 */
getCameraPosWorldSpace()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 
getLightPosObjectSpace()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.
setFog(SColor color,E_FOG_TYPE fogType,f32 start,f32 end,f32 density,bool pixelFog,bool rangeFog)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 */
lightVertex(s4DVertex * dest,u32 vertexargb)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.
draw2DImage(const video::ITexture * texture,const core::position2d<s32> & destPos,const core::rect<s32> & sourceRect,const core::rect<s32> * clipRect,SColor color,bool useAlphaChannelOfTexture)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.
draw2DImage(const video::ITexture * texture,const core::rect<s32> & destRect,const core::rect<s32> & sourceRect,const core::rect<s32> * clipRect,const video::SColor * const colors,bool useAlphaChannelOfTexture)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.
draw2DLine(const core::position2d<s32> & start,const core::position2d<s32> & end,SColor color)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
drawPixel(u32 x,u32 y,const SColor & color)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
draw2DRectangle(SColor color,const core::rect<s32> & pos,const core::rect<s32> * clip)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.
OnResize(const core::dimension2d<u32> & size)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
getCurrentRenderTargetSize() const2331 const core::dimension2d<u32>& CBurningVideoDriver::getCurrentRenderTargetSize() const
2332 {
2333 	return RenderTargetSize;
2334 }
2335 
2336 
2337 //!Draws an 2d rectangle with a gradient.
draw2DRectangle(const core::rect<s32> & position,SColor colorLeftUp,SColor colorRightUp,SColor colorLeftDown,SColor colorRightDown,const core::rect<s32> * clip)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.
draw3DLine(const core::vector3df & start,const core::vector3df & end,SColor color)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".
getName() const2500 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.
getVendorInfo()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
getDriverType() const2521 E_DRIVER_TYPE CBurningVideoDriver::getDriverType() const
2522 {
2523 	return EDT_BURNINGSVIDEO;
2524 }
2525 
2526 
2527 //! returns color format
getColorFormat() const2528 ECOLOR_FORMAT CBurningVideoDriver::getColorFormat() const
2529 {
2530 	return BURNINGSHADER_COLOR_FORMAT;
2531 }
2532 
2533 
2534 //! Returns the transformation set by setTransform
getTransform(E_TRANSFORMATION_STATE state) const2535 const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE state) const
2536 {
2537 	return Transformation[state];
2538 }
2539 
2540 
2541 //! Creates a render target texture.
addRenderTargetTexture(const core::dimension2d<u32> & size,const io::path & name,const ECOLOR_FORMAT format)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.
clearZBuffer()2555 void CBurningVideoDriver::clearZBuffer()
2556 {
2557 	if (DepthBuffer)
2558 		DepthBuffer->clear();
2559 }
2560 
2561 
2562 //! Returns an image created from the last rendered frame.
createScreenShot(video::ECOLOR_FORMAT format,video::E_RENDER_TARGET target)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
createDeviceDependentTexture(IImage * surface,const io::path & name,void * mipmapData)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.
getMaximalPrimitiveCount() const2594 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.
drawStencilShadowVolume(const core::array<core::vector3df> & triangles,bool zfail,u32 debugDataVisible)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.
drawStencilShadow(bool clearStencilBuffer,video::SColor leftUpEdge,video::SColor rightUpEdge,video::SColor leftDownEdge,video::SColor rightDownEdge)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 
getMaxTextureSize() const2693 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
createBurningVideoDriver(const irr::SIrrlichtCreationParameters & params,io::IFileSystem * io,video::IImagePresenter * presenter)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 
2724