1 // Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "IrrCompileConfig.h"
\r
6 #include "CSoftwareDriver2.h"
\r
8 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
10 #include "SoftwareDriver2_helper.h"
\r
11 #include "CSoftwareTexture.h"
\r
12 #include "CSoftwareTexture2.h"
\r
13 #include "CSoftware2MaterialRenderer.h"
\r
14 #include "S3DVertex.h"
\r
15 #include "S4DVertex.h"
\r
22 bool mat44_transposed_inverse(irr::core::CMatrix4<T>& out, const irr::core::CMatrix4<T>& M)
\r
24 const T* burning_restrict m = M.pointer();
\r
27 (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
\r
28 (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) +
\r
29 (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) +
\r
30 (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) -
\r
31 (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
\r
32 (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
\r
34 if (fabs(d) < DBL_MIN)
\r
41 T* burning_restrict o = out.pointer();
\r
42 o[0] = (T)(d * (m[5] * (m[10] * m[15] - m[11] * m[14]) + m[6] * (m[11] * m[13] - m[9] * m[15]) + m[7] * (m[9] * m[14] - m[10] * m[13])));
\r
43 o[4] = (T)(d * (m[9] * (m[2] * m[15] - m[3] * m[14]) + m[10] * (m[3] * m[13] - m[1] * m[15]) + m[11] * (m[1] * m[14] - m[2] * m[13])));
\r
44 o[8] = (T)(d * (m[13] * (m[2] * m[7] - m[3] * m[6]) + m[14] * (m[3] * m[5] - m[1] * m[7]) + m[15] * (m[1] * m[6] - m[2] * m[5])));
\r
45 o[12] = (T)(d * (m[1] * (m[7] * m[10] - m[6] * m[11]) + m[2] * (m[5] * m[11] - m[7] * m[9]) + m[3] * (m[6] * m[9] - m[5] * m[10])));
\r
47 o[1] = (T)(d * (m[6] * (m[8] * m[15] - m[11] * m[12]) + m[7] * (m[10] * m[12] - m[8] * m[14]) + m[4] * (m[11] * m[14] - m[10] * m[15])));
\r
48 o[5] = (T)(d * (m[10] * (m[0] * m[15] - m[3] * m[12]) + m[11] * (m[2] * m[12] - m[0] * m[14]) + m[8] * (m[3] * m[14] - m[2] * m[15])));
\r
49 o[9] = (T)(d * (m[14] * (m[0] * m[7] - m[3] * m[4]) + m[15] * (m[2] * m[4] - m[0] * m[6]) + m[12] * (m[3] * m[6] - m[2] * m[7])));
\r
50 o[13] = (T)(d * (m[2] * (m[7] * m[8] - m[4] * m[11]) + m[3] * (m[4] * m[10] - m[6] * m[8]) + m[0] * (m[6] * m[11] - m[7] * m[10])));
\r
52 o[2] = (T)(d * (m[7] * (m[8] * m[13] - m[9] * m[12]) + m[4] * (m[9] * m[15] - m[11] * m[13]) + m[5] * (m[11] * m[12] - m[8] * m[15])));
\r
53 o[6] = (T)(d * (m[11] * (m[0] * m[13] - m[1] * m[12]) + m[8] * (m[1] * m[15] - m[3] * m[13]) + m[9] * (m[3] * m[12] - m[0] * m[15])));
\r
54 o[10] = (T)(d * (m[15] * (m[0] * m[5] - m[1] * m[4]) + m[12] * (m[1] * m[7] - m[3] * m[5]) + m[13] * (m[3] * m[4] - m[0] * m[7])));
\r
55 o[14] = (T)(d * (m[3] * (m[5] * m[8] - m[4] * m[9]) + m[0] * (m[7] * m[9] - m[5] * m[11]) + m[1] * (m[4] * m[11] - m[7] * m[8])));
\r
57 o[3] = (T)(d * (m[4] * (m[10] * m[13] - m[9] * m[14]) + m[5] * (m[8] * m[14] - m[10] * m[12]) + m[6] * (m[9] * m[12] - m[8] * m[13])));
\r
58 o[7] = (T)(d * (m[8] * (m[2] * m[13] - m[1] * m[14]) + m[9] * (m[0] * m[14] - m[2] * m[12]) + m[10] * (m[1] * m[12] - m[0] * m[13])));
\r
59 o[11] = (T)(d * (m[12] * (m[2] * m[5] - m[1] * m[6]) + m[13] * (m[0] * m[6] - m[2] * m[4]) + m[14] * (m[1] * m[4] - m[0] * m[5])));
\r
60 o[15] = (T)(d * (m[0] * (m[5] * m[10] - m[6] * m[9]) + m[1] * (m[6] * m[8] - m[4] * m[10]) + m[2] * (m[4] * m[9] - m[5] * m[8])));
\r
66 // difference to CMatrix4<T>::getInverse . higher precision in determinant. return identity on failure
\r
68 bool mat44_inverse(CMatrix4<T>& out, const CMatrix4<T>& M)
\r
70 const T* m = M.pointer();
\r
73 (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
\r
74 (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) +
\r
75 (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) +
\r
76 (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) -
\r
77 (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
\r
78 (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
\r
80 if (fabs(d) < DBL_MIN)
\r
87 T* o = out.pointer();
\r
88 o[0] = (T)(d * (m[5] * (m[10] * m[15] - m[11] * m[14]) + m[6] * (m[11] * m[13] - m[9] * m[15]) + m[7] * (m[9] * m[14] - m[10] * m[13])));
\r
89 o[1] = (T)(d * (m[9] * (m[2] * m[15] - m[3] * m[14]) + m[10] * (m[3] * m[13] - m[1] * m[15]) + m[11] * (m[1] * m[14] - m[2] * m[13])));
\r
90 o[2] = (T)(d * (m[13] * (m[2] * m[7] - m[3] * m[6]) + m[14] * (m[3] * m[5] - m[1] * m[7]) + m[15] * (m[1] * m[6] - m[2] * m[5])));
\r
91 o[3] = (T)(d * (m[1] * (m[7] * m[10] - m[6] * m[11]) + m[2] * (m[5] * m[11] - m[7] * m[9]) + m[3] * (m[6] * m[9] - m[5] * m[10])));
\r
93 o[4] = (T)(d * (m[6] * (m[8] * m[15] - m[11] * m[12]) + m[7] * (m[10] * m[12] - m[8] * m[14]) + m[4] * (m[11] * m[14] - m[10] * m[15])));
\r
94 o[5] = (T)(d * (m[10] * (m[0] * m[15] - m[3] * m[12]) + m[11] * (m[2] * m[12] - m[0] * m[14]) + m[8] * (m[3] * m[14] - m[2] * m[15])));
\r
95 o[6] = (T)(d * (m[14] * (m[0] * m[7] - m[3] * m[4]) + m[15] * (m[2] * m[4] - m[0] * m[6]) + m[12] * (m[3] * m[6] - m[2] * m[7])));
\r
96 o[7] = (T)(d * (m[2] * (m[7] * m[8] - m[4] * m[11]) + m[3] * (m[4] * m[10] - m[6] * m[8]) + m[0] * (m[6] * m[11] - m[7] * m[10])));
\r
98 o[8] = (T)(d * (m[7] * (m[8] * m[13] - m[9] * m[12]) + m[4] * (m[9] * m[15] - m[11] * m[13]) + m[5] * (m[11] * m[12] - m[8] * m[15])));
\r
99 o[9] = (T)(d * (m[11] * (m[0] * m[13] - m[1] * m[12]) + m[8] * (m[1] * m[15] - m[3] * m[13]) + m[9] * (m[3] * m[12] - m[0] * m[15])));
\r
100 o[10] = (T)(d * (m[15] * (m[0] * m[5] - m[1] * m[4]) + m[12] * (m[1] * m[7] - m[3] * m[5]) + m[13] * (m[3] * m[4] - m[0] * m[7])));
\r
101 o[11] = (T)(d * (m[3] * (m[5] * m[8] - m[4] * m[9]) + m[0] * (m[7] * m[9] - m[5] * m[11]) + m[1] * (m[4] * m[11] - m[7] * m[8])));
\r
103 o[12] = (T)(d * (m[4] * (m[10] * m[13] - m[9] * m[14]) + m[5] * (m[8] * m[14] - m[10] * m[12]) + m[6] * (m[9] * m[12] - m[8] * m[13])));
\r
104 o[13] = (T)(d * (m[8] * (m[2] * m[13] - m[1] * m[14]) + m[9] * (m[0] * m[14] - m[2] * m[12]) + m[10] * (m[1] * m[12] - m[0] * m[13])));
\r
105 o[14] = (T)(d * (m[12] * (m[2] * m[5] - m[1] * m[6]) + m[13] * (m[0] * m[6] - m[2] * m[4]) + m[14] * (m[1] * m[4] - m[0] * m[5])));
\r
106 o[15] = (T)(d * (m[0] * (m[5] * m[10] - m[6] * m[9]) + m[1] * (m[6] * m[8] - m[4] * m[10]) + m[2] * (m[4] * m[9] - m[5] * m[8])));
\r
112 // void CMatrix4<T>::transformVec4(T *out, const T * in) const
\r
114 inline void transformVec4Vec4(const irr::core::CMatrix4<T>& m, T* burning_restrict out, const T* burning_restrict in)
\r
116 const T* burning_restrict M = m.pointer();
\r
118 out[0] = in[0] * M[0] + in[1] * M[4] + in[2] * M[8] + in[3] * M[12];
\r
119 out[1] = in[0] * M[1] + in[1] * M[5] + in[2] * M[9] + in[3] * M[13];
\r
120 out[2] = in[0] * M[2] + in[1] * M[6] + in[2] * M[10] + in[3] * M[14];
\r
121 out[3] = in[0] * M[3] + in[1] * M[7] + in[2] * M[11] + in[3] * M[15];
\r
125 // void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
\r
127 inline void transformVec3Vec4(const irr::core::CMatrix4<T>& m, T* burning_restrict out, const core::vector3df& in)
\r
129 const T* burning_restrict M = m.pointer();
\r
130 out[0] = in.X * M[0] + in.Y * M[4] + in.Z * M[8] + M[12];
\r
131 out[1] = in.X * M[1] + in.Y * M[5] + in.Z * M[9] + M[13];
\r
132 out[2] = in.X * M[2] + in.Y * M[6] + in.Z * M[10] + M[14];
\r
133 out[3] = in.X * M[3] + in.Y * M[7] + in.Z * M[11] + M[15];
\r
138 inline void rotateVec3Vec4(const irr::core::CMatrix4<T>& m, T* burning_restrict out, const T* burning_restrict in)
\r
140 const T* burning_restrict M = m.pointer();
\r
142 out[0] = in[0] * M[0] + in[1] * M[4] + in[2] * M[8];
\r
143 out[1] = in[0] * M[1] + in[1] * M[5] + in[2] * M[9];
\r
144 out[2] = in[0] * M[2] + in[1] * M[6] + in[2] * M[10];
\r
148 //based on https://github.com/ekmett/approximate/blob/master/cbits/fast.c powf_fast_precise
\r
149 static inline float powf_limit(const float a, const float b)
\r
151 if (a <= 0.0000001f) return 0.f;
\r
152 else if (a >= 1.f) return 1.f;
\r
154 /* calculate approximation with fraction of the exponent */
\r
156 union { float f; int x; } u = { a };
\r
157 u.x = (int)((b - e) * (u.x - 1065353216) + 1065353216);
\r
165 if (ua < 0.00000001f)
\r
175 //! clamp(value,0,1)
\r
176 static inline const float clampf01(const float v)
\r
178 return v < 0.f ? 0.f : v > 1.f ? 1.f : v;
\r
182 static void image_fill(irr::video::IImage* image, const irr::video::SColor& color, const interlaced_control interlaced)
\r
187 unsigned int c = color.color;
\r
189 switch (image->getColorFormat())
\r
191 case irr::video::ECF_A1R5G5B5:
\r
192 c = color.toA1R5G5B5();
\r
198 irr::memset32_interlaced(image->getData(), c, image->getPitch(), image->getDimension().Height, interlaced);
\r
206 unsigned char x : 3;
\r
207 unsigned char y : 3;
\r
208 unsigned char i : 2;
\r
213 //setup Antialias. v0.52 uses as Interlaced
\r
214 void get_scale(scale_setup& s, const irr::SIrrlichtCreationParameters& params)
\r
219 if (params.AntiAlias && params.WindowSize.Width <= 160 && params.WindowSize.Height <= 120)
\r
224 switch (params.AntiAlias)
\r
226 case 2: s.x = 1; s.y = 1; s.i = 1; break;
\r
227 case 4: s.x = 2; s.y = 2; s.i = 0; break;
\r
228 case 8: s.x = 2; s.y = 2; s.i = 1; break;
\r
229 case 16:s.x = 4; s.y = 4; s.i = 0; break;
\r
230 case 32:s.x = 4; s.y = 4; s.i = 1; break;
\r
232 case 3: s.x = 3; s.y = 3; s.i = 0; break;
\r
233 case 5: s.x = 3; s.y = 3; s.i = 1; break;
\r
237 //turn on/off fpu exception
\r
238 void fpu_exception(int on)
\r
241 #if defined(_WIN32)
\r
243 _controlfp(on ? _EM_INEXACT : -1, _MCW_EM);
\r
253 CBurningVideoDriver::CBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter)
\r
254 : CNullDriver(io, params.WindowSize), BackBuffer(0), Presenter(presenter),
\r
255 WindowId(0), SceneSourceRect(0),
\r
256 RenderTargetTexture(0), RenderTargetSurface(0), CurrentShader(0),
\r
257 DepthBuffer(0), StencilBuffer(0)
\r
259 //enable fpu exception
\r
263 setDebugName("CBurningVideoDriver");
\r
266 VertexCache_map_source_format();
\r
268 //Use AntiAlias(hack) to shrink BackBuffer Size and keep ScreenSize the same as Input
\r
270 get_scale(scale, params);
\r
272 //Control Interlaced BackBuffer
\r
273 Interlaced.enable = scale.i;
\r
274 Interlaced.bypass = !Interlaced.enable;
\r
277 // create backbuffer.
\r
278 core::dimension2du use(params.WindowSize.Width / scale.x, params.WindowSize.Height / scale.y);
\r
279 BackBuffer = new CImage(SOFTWARE_DRIVER_2_RENDERTARGET_COLOR_FORMAT, use);
\r
282 //BackBuffer->fill(SColor(0));
\r
283 image_fill(BackBuffer, SColor(0), interlace_disabled());
\r
286 if (params.ZBufferBits)
\r
287 DepthBuffer = video::createDepthBuffer(BackBuffer->getDimension());
\r
289 // create stencil buffer
\r
290 if (params.Stencilbuffer)
\r
291 StencilBuffer = video::createStencilBuffer(BackBuffer->getDimension(), 8);
\r
294 DriverAttributes->setAttribute("MaxIndices", 1 << 16);
\r
295 DriverAttributes->setAttribute("MaxTextures", BURNING_MATERIAL_MAX_TEXTURES);
\r
296 DriverAttributes->setAttribute("MaxTextureSize", SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE);
\r
297 DriverAttributes->setAttribute("MaxLights", 1024); //glsl::gl_MaxLights);
\r
298 DriverAttributes->setAttribute("MaxTextureLODBias", 16.f);
\r
299 DriverAttributes->setAttribute("Version", 50);
\r
301 // create triangle renderers
\r
303 memset(BurningShader, 0, sizeof(BurningShader));
\r
304 //BurningShader[ETR_FLAT] = createTRFlat2(DepthBuffer);
\r
305 //BurningShader[ETR_FLAT_WIRE] = createTRFlatWire2(DepthBuffer);
\r
306 BurningShader[ETR_GOURAUD] = createTriangleRendererGouraud2(this);
\r
307 BurningShader[ETR_GOURAUD_NOZ] = createTriangleRendererGouraudNoZ2(this);
\r
308 //BurningShader[ETR_GOURAUD_ALPHA] = createTriangleRendererGouraudAlpha2(this );
\r
309 BurningShader[ETR_GOURAUD_ALPHA_NOZ] = createTRGouraudAlphaNoZ2(this); // 2D
\r
310 //BurningShader[ETR_GOURAUD_WIRE] = createTriangleRendererGouraudWire2(DepthBuffer);
\r
311 //BurningShader[ETR_TEXTURE_FLAT] = createTriangleRendererTextureFlat2(DepthBuffer);
\r
312 //BurningShader[ETR_TEXTURE_FLAT_WIRE] = createTriangleRendererTextureFlatWire2(DepthBuffer);
\r
313 BurningShader[ETR_TEXTURE_GOURAUD] = createTriangleRendererTextureGouraud2(this);
\r
314 BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M1] = createTriangleRendererTextureLightMap2_M1(this);
\r
315 BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M2] = createTriangleRendererTextureLightMap2_M2(this);
\r
316 BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M4] = createTriangleRendererGTextureLightMap2_M4(this);
\r
317 BurningShader[ETR_TEXTURE_LIGHTMAP_M4] = createTriangleRendererTextureLightMap2_M4(this);
\r
318 BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD] = createTriangleRendererTextureLightMap2_Add(this);
\r
319 BurningShader[ETR_TEXTURE_GOURAUD_DETAIL_MAP] = createTriangleRendererTextureDetailMap2(this);
\r
321 BurningShader[ETR_TEXTURE_GOURAUD_WIRE] = createTriangleRendererTextureGouraudWire2(this);
\r
322 BurningShader[ETR_TEXTURE_GOURAUD_NOZ] = createTRTextureGouraudNoZ2(this);
\r
323 BurningShader[ETR_TEXTURE_GOURAUD_ADD] = createTRTextureGouraudAdd2(this);
\r
324 BurningShader[ETR_TEXTURE_GOURAUD_ADD_NO_Z] = createTRTextureGouraudAddNoZ2(this);
\r
325 BurningShader[ETR_TEXTURE_GOURAUD_VERTEX_ALPHA] = createTriangleRendererTextureVertexAlpha2(this);
\r
327 BurningShader[ETR_TEXTURE_GOURAUD_ALPHA] = createTRTextureGouraudAlpha(this);
\r
328 BurningShader[ETR_TEXTURE_GOURAUD_ALPHA_NOZ] = createTRTextureGouraudAlphaNoZ(this);
\r
330 BurningShader[ETR_NORMAL_MAP_SOLID] = createTRNormalMap(this);
\r
331 BurningShader[ETR_STENCIL_SHADOW] = createTRStencilShadow(this);
\r
332 BurningShader[ETR_TEXTURE_BLEND] = createTRTextureBlend(this);
\r
334 BurningShader[ETR_TRANSPARENT_REFLECTION_2_LAYER] = createTriangleRendererTexture_transparent_reflection_2_layer(this);
\r
335 //BurningShader[ETR_REFERENCE] = createTriangleRendererReference ( this );
\r
337 BurningShader[ETR_COLOR] = create_burning_shader_color(this);
\r
339 // add the same renderer for all solid types
\r
340 CSoftware2MaterialRenderer_SOLID* smr = new CSoftware2MaterialRenderer_SOLID(this);
\r
341 CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR* tmr = new CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR(this);
\r
342 //CSoftware2MaterialRenderer_UNSUPPORTED * umr = new CSoftware2MaterialRenderer_UNSUPPORTED ( this );
\r
344 //!TODO: addMaterialRenderer depends on pushing order....
\r
345 addMaterialRenderer(smr); // EMT_SOLID
\r
346 addMaterialRenderer(smr); // EMT_SOLID_2_LAYER,
\r
347 addMaterialRenderer(smr); // EMT_LIGHTMAP,
\r
348 addMaterialRenderer(tmr); // EMT_LIGHTMAP_ADD,
\r
349 addMaterialRenderer(smr); // EMT_LIGHTMAP_M2,
\r
350 addMaterialRenderer(smr); // EMT_LIGHTMAP_M4,
\r
351 addMaterialRenderer(smr); // EMT_LIGHTMAP_LIGHTING,
\r
352 addMaterialRenderer(smr); // EMT_LIGHTMAP_LIGHTING_M2,
\r
353 addMaterialRenderer(smr); // EMT_LIGHTMAP_LIGHTING_M4,
\r
354 addMaterialRenderer(smr); // EMT_DETAIL_MAP,
\r
355 addMaterialRenderer(smr); // EMT_SPHERE_MAP,
\r
356 addMaterialRenderer(smr); // EMT_REFLECTION_2_LAYER,
\r
357 addMaterialRenderer(tmr); // EMT_TRANSPARENT_ADD_COLOR,
\r
358 addMaterialRenderer(tmr); // EMT_TRANSPARENT_ALPHA_CHANNEL,
\r
359 addMaterialRenderer(tmr); // EMT_TRANSPARENT_ALPHA_CHANNEL_REF,
\r
360 addMaterialRenderer(tmr); // EMT_TRANSPARENT_VERTEX_ALPHA,
\r
361 addMaterialRenderer(tmr); // EMT_TRANSPARENT_REFLECTION_2_LAYER,
\r
362 addMaterialRenderer(smr); // EMT_NORMAL_MAP_SOLID,
\r
363 addMaterialRenderer(tmr); // EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR,
\r
364 addMaterialRenderer(tmr); // EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA,
\r
365 addMaterialRenderer(smr); // EMT_PARALLAX_MAP_SOLID,
\r
366 addMaterialRenderer(tmr); // EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR,
\r
367 addMaterialRenderer(tmr); // EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA,
\r
368 addMaterialRenderer(tmr); // EMT_ONETEXTURE_BLEND
\r
374 // select render target
\r
375 setRenderTargetImage2(BackBuffer,0, 0);
\r
379 EyeSpace.resetFog();
\r
381 // select the right renderer
\r
382 setMaterial(Material.org);
\r
387 CBurningVideoDriver::~CBurningVideoDriver()
\r
389 // delete Backbuffer
\r
392 BackBuffer->drop();
\r
396 // delete triangle renderers
\r
397 for (s32 i = 0; i < ETR2_COUNT; ++i)
\r
399 if (BurningShader[i])
\r
401 BurningShader[i]->drop();
\r
402 BurningShader[i] = 0;
\r
406 // delete Additional buffer
\r
409 StencilBuffer->drop();
\r
415 DepthBuffer->drop();
\r
419 if (RenderTargetTexture)
\r
421 RenderTargetTexture->drop();
\r
422 RenderTargetTexture = 0;
\r
425 if (RenderTargetSurface)
\r
427 RenderTargetSurface->drop();
\r
428 RenderTargetSurface = 0;
\r
437 //! queries the features of the driver, returns true if feature is available
\r
438 bool CBurningVideoDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
\r
443 #ifdef SOFTWARE_DRIVER_2_BILINEAR
\r
444 case EVDF_BILINEAR_FILTER:
\r
448 #if SOFTWARE_DRIVER_2_MIPMAPPING_MAX > 1
\r
453 case EVDF_STENCIL_BUFFER:
\r
454 on = StencilBuffer != 0;
\r
457 case EVDF_RENDER_TO_TARGET:
\r
458 case EVDF_MULTITEXTURE:
\r
459 case EVDF_HARDWARE_TL:
\r
460 case EVDF_TEXTURE_NSQUARE:
\r
461 case EVDF_TEXTURE_MATRIX:
\r
465 case EVDF_DEPTH_CLAMP: // shadow
\r
469 case EVDF_ARB_FRAGMENT_PROGRAM_1:
\r
470 case EVDF_ARB_VERTEX_PROGRAM_1:
\r
473 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
\r
474 case EVDF_TEXTURE_NPOT:
\r
475 case EVDF_ARB_GLSL:
\r
479 case EVDF_TEXTURE_NPOT: // for 2D
\r
484 #if defined(SOFTWARE_DRIVER_2_2D_AS_3D)
\r
485 #if defined(IRRLICHT_FREE_CANVAS)
\r
486 case EVDF_VIEWPORT_SCALE_GUI:
\r
496 return on && FeatureEnabled[feature];
\r
500 //matrix multiplication
\r
501 void CBurningVideoDriver::transform_calc(E_TRANSFORMATION_STATE_BURNING_VIDEO state)
\r
503 size_t* flag = TransformationFlag[TransformationStack];
\r
504 if (flag[state] & ETF_VALID) return;
\r
510 case ETS_PROJ_MODEL_VIEW:
\r
511 if (0 == (flag[ETS_VIEW_PROJECTION] & ETF_VALID)) transform_calc(ETS_VIEW_PROJECTION);
\r
512 ok = flag[ETS_WORLD] & flag[ETS_VIEW] & flag[ETS_PROJECTION] & flag[ETS_VIEW_PROJECTION] & ETF_VALID;
\r
514 case ETS_VIEW_PROJECTION:
\r
515 ok = flag[ETS_VIEW] & flag[ETS_PROJECTION] & ETF_VALID;
\r
517 case ETS_MODEL_VIEW:
\r
518 ok = flag[ETS_WORLD] & flag[ETS_VIEW] & ETF_VALID;
\r
521 ok = flag[ETS_MODEL_VIEW] & ETF_VALID;
\r
530 sprintf(buf, "transform_calc not valid for %d\n", state);
\r
531 os::Printer::log(buf, ELL_WARNING);
\r
534 core::matrix4* matrix = Transformation[TransformationStack];
\r
538 case ETS_PROJ_MODEL_VIEW:
\r
539 if (flag[ETS_WORLD] & ETF_IDENTITY)
\r
541 matrix[state] = matrix[ETS_VIEW_PROJECTION];
\r
545 matrix[state].setbyproduct_nocheck(matrix[ETS_VIEW_PROJECTION], matrix[ETS_WORLD]);
\r
549 case ETS_VIEW_PROJECTION:
\r
550 matrix[state].setbyproduct_nocheck(matrix[ETS_PROJECTION], matrix[ETS_VIEW]);
\r
552 case ETS_MODEL_VIEW:
\r
553 if (flag[ETS_WORLD] & ETF_IDENTITY)
\r
555 matrix[state] = matrix[ETS_VIEW];
\r
559 matrix[state].setbyproduct_nocheck(matrix[ETS_VIEW], matrix[ETS_WORLD]);
\r
563 mat44_transposed_inverse(matrix[state], matrix[ETS_MODEL_VIEW]);
\r
569 flag[state] |= ETF_VALID;
\r
573 //! sets transformation
\r
574 void CBurningVideoDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)
\r
576 size_t* flag = TransformationFlag[TransformationStack];
\r
577 core::matrix4* matrix = Transformation[TransformationStack];
\r
581 if (flag[state] & ETF_VALID)
\r
583 changed = memcmp(mat.pointer(), matrix[state].pointer(), sizeof(mat));
\r
588 matrix[state] = mat;
\r
589 flag[state] |= ETF_VALID;
\r
592 //maybe identity (mostly for texturematrix to avoid costly multiplication)
\r
593 #if defined ( USE_MATRIX_TEST )
\r
594 burning_setbit(TransformationFlag[state], mat.getDefinitelyIdentityMatrix(), ETF_IDENTITY);
\r
596 burning_setbit(flag[state],
\r
597 !memcmp(mat.pointer(), core::IdentityMatrix.pointer(), sizeof(mat)), ETF_IDENTITY
\r
606 case ETS_PROJECTION:
\r
607 flag[ETS_PROJ_MODEL_VIEW] &= ~ETF_VALID;
\r
608 flag[ETS_VIEW_PROJECTION] &= ~ETF_VALID;
\r
611 flag[ETS_PROJ_MODEL_VIEW] &= ~ETF_VALID;
\r
612 flag[ETS_VIEW_PROJECTION] &= ~ETF_VALID;
\r
613 flag[ETS_MODEL_VIEW] &= ~ETF_VALID;
\r
614 flag[ETS_NORMAL] &= ~ETF_VALID;
\r
617 flag[ETS_PROJ_MODEL_VIEW] &= ~ETF_VALID;
\r
618 flag[ETS_MODEL_VIEW] &= ~ETF_VALID;
\r
619 flag[ETS_NORMAL] &= ~ETF_VALID;
\r
621 case ETS_TEXTURE_0:
\r
622 case ETS_TEXTURE_1:
\r
623 case ETS_TEXTURE_2:
\r
624 case ETS_TEXTURE_3:
\r
625 #if _IRR_MATERIAL_MAX_TEXTURES_>4
\r
626 case ETS_TEXTURE_4:
\r
628 #if _IRR_MATERIAL_MAX_TEXTURES_>5
\r
629 case ETS_TEXTURE_5:
\r
631 #if _IRR_MATERIAL_MAX_TEXTURES_>6
\r
632 case ETS_TEXTURE_6:
\r
634 #if _IRR_MATERIAL_MAX_TEXTURES_>7
\r
635 case ETS_TEXTURE_7:
\r
637 if (0 == (flag[state] & ETF_IDENTITY))
\r
639 EyeSpace.TL_Flag |= TL_TEXTURE_TRANSFORM;
\r
648 //! Returns the transformation set by setTransform
\r
649 const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE state) const
\r
651 return Transformation[TransformationStack][state];
\r
655 bool CBurningVideoDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
\r
657 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
\r
658 CNullDriver::beginScene(clearFlag & ECBF_COLOR, clearFlag & ECBF_DEPTH, clearColor, videoData, sourceRect);
\r
660 CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect);
\r
663 Interlaced.nr = (Interlaced.nr + 1) & interlace_control_mask;
\r
664 WindowId = videoData.D3D9.HWnd;
\r
665 SceneSourceRect = sourceRect;
\r
667 clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);
\r
669 //memset ( TransformationFlag, 0, sizeof ( TransformationFlag ) );
\r
673 bool CBurningVideoDriver::endScene()
\r
675 CNullDriver::endScene();
\r
677 return Presenter->present(BackBuffer, WindowId, SceneSourceRect);
\r
681 //! Create render target.
\r
682 IRenderTarget* CBurningVideoDriver::addRenderTarget()
\r
684 CSoftwareRenderTarget2* renderTarget = new CSoftwareRenderTarget2(this);
\r
685 RenderTargets.push_back(renderTarget);
\r
687 return renderTarget;
\r
690 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
\r
691 bool CBurningVideoDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, bool clearZBuffer, SColor color)
\r
693 CSoftwareRenderTarget2 target(this);
\r
694 target.RenderTexture = texture;
\r
695 target.TargetType = ERT_RENDER_TEXTURE;
\r
696 target.Texture[0] = texture;
\r
702 if (clearBackBuffer) flag |= ECBF_COLOR;
\r
703 if (clearZBuffer) flag |= ECBF_DEPTH;
\r
705 return setRenderTargetEx(texture ? &target : 0, flag, color, 1.f, true);
\r
709 bool CBurningVideoDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
711 #if !defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
\r
712 if (target && target->getDriverType() != EDT_BURNINGSVIDEO)
\r
714 os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR);
\r
718 if (RenderTargetTexture)
\r
720 //switching from texture to backbuffer
\r
723 RenderTargetTexture->regenerateMipMapLevels();
\r
725 RenderTargetTexture->drop();
\r
728 #if !defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
\r
729 RenderTargetTexture = target ? target->getTexture()[0] : 0;
\r
731 RenderTargetTexture = target ? ((CSoftwareRenderTarget2*)target)->Texture[0] : 0;
\r
734 if (RenderTargetTexture)
\r
736 RenderTargetTexture->grab();
\r
737 Interlaced.bypass = 1;
\r
738 setRenderTargetImage2(((CSoftwareTexture2*)RenderTargetTexture)->getImage());
\r
742 Interlaced.bypass = !Interlaced.enable;
\r
743 setRenderTargetImage2(BackBuffer);
\r
746 clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);
\r
751 static inline f32 map_value(f32 x, f32 in_min, f32 in_max, f32 out_min, f32 out_max) {
\r
752 return (x - in_min) * (out_max - out_min) / (f32)(in_max - in_min) + out_min;
\r
755 //! sets a render target
\r
756 void CBurningVideoDriver::setRenderTargetImage2(video::IImage* color, video::IImage* depth, video::IImage* stencil)
\r
758 if (RenderTargetSurface)
\r
759 RenderTargetSurface->drop();
\r
761 core::dimension2d<u32> current = RenderTargetSize;
\r
762 RenderTargetSurface = color;
\r
763 RenderTargetSize.Width = 0;
\r
764 RenderTargetSize.Height = 0;
\r
766 if (RenderTargetSurface)
\r
768 RenderTargetSurface->grab();
\r
769 RenderTargetSize = RenderTargetSurface->getDimension();
\r
772 RatioRenderTargetScreen.x = ScreenSize.Width ? (f32)RenderTargetSize.Width / ScreenSize.Width : 1.f;
\r
773 RatioRenderTargetScreen.y = ScreenSize.Height ? (f32)RenderTargetSize.Height / ScreenSize.Height : 1.f;
\r
775 int not_changed = current == RenderTargetSize;
\r
776 burning_setbit(TransformationFlag[0][ETS_PROJECTION], not_changed, ETF_VALID);
\r
777 burning_setbit(TransformationFlag[1][ETS_PROJECTION], not_changed, ETF_VALID);
\r
779 setViewPort(core::recti(RenderTargetSize));
\r
782 DepthBuffer->setSize(RenderTargetSize);
\r
785 StencilBuffer->setSize(RenderTargetSize);
\r
789 //--------- Transform from NDC to DC, transform TexCoo ----------------------------------------------
\r
792 //! Blur 2D Image with PixelOffset. (default 0.375f for OpenGL and Burning)
\r
794 * if IRRLICHT_2D_TEXEL_OFFSET > 0 is applied to OpenGL/Burning, Pixel-exact Texture Coordinates do not match.
\r
795 * Currently Version 1.8,1.9 has that in the Irrlicht 2D Examples where you get a Magenta Border on the Sprites
\r
796 * and in the draw2DImage4cFilter Tests
\r
798 #define IRRLICHT_2D_TEXEL_OFFSET 0.f
\r
801 //--------- Transform from NDC to DC ----------------------------------------------
\r
803 // used to scale <-1,-1><1,1> to viewport [center,scale]
\r
804 // controls subtexel and fill convention.
\r
805 // Don't tweak SOFTWARE_DRIVER_2_SUBTEXEL (-0.5f in m[1]) anymore to control texture blur effect, it's used for viewport scaling.
\r
806 // naming is misleading. it will write outside memory location..
\r
808 void buildNDCToDCMatrix(f32* m, const core::rect<s32>& viewport, f32 tx)
\r
810 m[0] = (viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X + tx) * 0.5f;
\r
811 m[1] = (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X-1) * 0.5f;
\r
813 m[2] = (viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y + tx) * -0.5f;
\r
814 m[3] = (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y-1) * 0.5f;
\r
819 //! sets a viewport
\r
820 void CBurningVideoDriver::setViewPort(const core::rect<s32>& area)
\r
824 core::rect<s32> rendert(0, 0, RenderTargetSize.Width, RenderTargetSize.Height);
\r
825 ViewPort.clipAgainst(rendert);
\r
827 buildNDCToDCMatrix(Transformation_ETS_CLIPSCALE[0], ViewPort, 1.f/2048.f); //SkyBox,Billboard 90° problem
\r
828 buildNDCToDCMatrix(Transformation_ETS_CLIPSCALE[1], ViewPort, 0.f); // OverrideMaterial2DEnabled ? -IRRLICHT_2D_TEXEL_OFFSET : 0.f);
\r
831 CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort, Interlaced);
\r
834 void CBurningVideoDriver::setScissor(int x, int y, int width, int height)
\r
837 //y = rt.Height - y - height;
\r
841 v0.x0 = core::floor32(x * RatioRenderTargetScreen.x);
\r
842 v0.y0 = core::floor32(y * RatioRenderTargetScreen.y);
\r
843 v0.x1 = core::floor32((x + width) * RatioRenderTargetScreen.x);
\r
844 v0.y1 = core::floor32((y + height) * RatioRenderTargetScreen.y);
\r
849 v1.x1 = RenderTargetSize.Width;
\r
850 v1.y1 = RenderTargetSize.Height;
\r
852 intersect(Scissor, v0, v1);
\r
856 generic plane clipping in homogenous coordinates
\r
857 special case ndc frustum <-w,w>,<-w,w>,<-w,w>
\r
858 can be rewritten with compares e.q near plane, a.z < -a.w and b.z < -b.w
\r
863 const sVec4 CBurningVideoDriver::NDCPlane[6 + 2] =
\r
865 sVec4(0.f, 0.f, -1.f, -1.f), // near
\r
866 sVec4(0.f, 0.f, 1.f, -1.f), // far
\r
867 sVec4(1.f, 0.f, 0.f, -1.f), // left
\r
868 sVec4(-1.f, 0.f, 0.f, -1.f), // right
\r
869 sVec4(0.f, 1.f, 0.f, -1.f), // bottom
\r
870 sVec4(0.f, -1.f, 0.f, -1.f) // top
\r
875 test a vertex if it's inside the standard frustum
\r
877 this is the generic one..
\r
880 for ( u32 i = 0; i!= 6; ++i )
\r
882 dotPlane = v->Pos.dotProduct ( NDCPlane[i] );
\r
883 burning_setbit32( flag, dotPlane <= 0.f, 1 << i );
\r
886 // this is the base for ndc frustum <-w,w>,<-w,w>,<-w,w>
\r
887 burning_setbit32( flag, ( v->Pos.z - v->Pos.w ) <= 0.f, 1 );
\r
888 burning_setbit32( flag, (-v->Pos.z - v->Pos.w ) <= 0.f, 2 );
\r
889 burning_setbit32( flag, ( v->Pos.x - v->Pos.w ) <= 0.f, 4 );
\r
890 burning_setbit32( flag, (-v->Pos.x - v->Pos.w ) <= 0.f, 8 );
\r
891 burning_setbit32( flag, ( v->Pos.y - v->Pos.w ) <= 0.f, 16 );
\r
892 burning_setbit32( flag, (-v->Pos.y - v->Pos.w ) <= 0.f, 32 );
\r
895 #ifdef IRRLICHT_FAST_MATH
\r
897 REALINLINE size_t CBurningVideoDriver::clipToFrustumTest(const s4DVertex* v) const
\r
901 const f32 w = -v->Pos.w;
\r
903 // a conditional move is needed....FCOMI ( but we don't have it )
\r
904 // so let the fpu calculate and write it back.
\r
905 // cpu makes the compare, interleaving
\r
907 test[0] = v->Pos.z + w;
\r
908 test[1] = -v->Pos.z + w;
\r
909 test[2] = v->Pos.x + w;
\r
910 test[3] = -v->Pos.x + w;
\r
911 test[4] = v->Pos.y + w;
\r
912 test[5] = -v->Pos.y + w;
\r
914 const u32* a = F32_AS_U32_POINTER(test);
\r
915 flag = (a[0]) >> 31;
\r
916 flag |= (a[1] & 0x80000000) >> 30;
\r
917 flag |= (a[2] & 0x80000000) >> 29;
\r
918 flag |= (a[3] & 0x80000000) >> 28;
\r
919 flag |= (a[4] & 0x80000000) >> 27;
\r
920 flag |= (a[5] & 0x80000000) >> 26;
\r
923 flag = (IR ( test[0] ) ) >> 31;
\r
924 flag |= (IR ( test[1] ) & 0x80000000 ) >> 30;
\r
925 flag |= (IR ( test[2] ) & 0x80000000 ) >> 29;
\r
926 flag |= (IR ( test[3] ) & 0x80000000 ) >> 28;
\r
927 flag |= (IR ( test[4] ) & 0x80000000 ) >> 27;
\r
928 flag |= (IR ( test[5] ) & 0x80000000 ) >> 26;
\r
931 flag = F32_LOWER_EQUAL_0 ( test[0] );
\r
932 flag |= F32_LOWER_EQUAL_0 ( test[1] ) << 1;
\r
933 flag |= F32_LOWER_EQUAL_0 ( test[2] ) << 2;
\r
934 flag |= F32_LOWER_EQUAL_0 ( test[3] ) << 3;
\r
935 flag |= F32_LOWER_EQUAL_0 ( test[4] ) << 4;
\r
936 flag |= F32_LOWER_EQUAL_0 ( test[5] ) << 5;
\r
944 REALINLINE size_t clipToFrustumTest(const s4DVertex* v)
\r
948 flag |= v->Pos.z <= v->Pos.w ? VERTEX4D_CLIP_NEAR : 0;
\r
949 flag |= -v->Pos.z <= v->Pos.w ? VERTEX4D_CLIP_FAR : 0;
\r
951 flag |= v->Pos.x <= v->Pos.w ? VERTEX4D_CLIP_LEFT : 0;
\r
952 flag |= -v->Pos.x <= v->Pos.w ? VERTEX4D_CLIP_RIGHT : 0;
\r
954 flag |= v->Pos.y <= v->Pos.w ? VERTEX4D_CLIP_BOTTOM : 0;
\r
955 flag |= -v->Pos.y <= v->Pos.w ? VERTEX4D_CLIP_TOP : 0;
\r
959 for ( u32 i = 0; i <= 6; ++i )
\r
961 if (v->Pos.dot_xyzw(NDCPlane[i]) <= 0.f) flag |= ((size_t)1) << i;
\r
970 size_t clipToHyperPlane(
\r
971 s4DVertexPair* burning_restrict dest,
\r
972 const s4DVertexPair* burning_restrict source,
\r
973 const size_t inCount,
\r
977 size_t outCount = 0;
\r
978 s4DVertexPair* out = dest;
\r
980 const s4DVertex* a;
\r
981 const s4DVertex* b = source;
\r
983 ipoltype bDotPlane;
\r
984 bDotPlane = b->Pos.dot_xyzw(plane);
\r
987 for( u32 i = 1; i < inCount + 1; ++i)
\r
990 a = source + (i%inCount)*2;
\r
992 const s32 condition = i - inCount;
\r
993 const s32 index = (( ( condition >> 31 ) & ( i ^ condition ) ) ^ condition ) << 1;
\r
994 a = source + index;
\r
997 //Sutherland
\96Hodgman
\r
998 for (size_t i = 0; i < inCount; ++i)
\r
1000 a = source + (i == inCount - 1 ? 0 : s4DVertex_ofs(i + 1));
\r
1002 // current point inside
\r
1003 if (ipol_lower_equal_0(a->Pos.dot_xyzw(plane)))
\r
1005 // last point outside
\r
1006 if (ipol_greater_0(bDotPlane))
\r
1008 // intersect line segment with plane
\r
1009 out->interpolate(*b, *a, bDotPlane / (b->Pos - a->Pos).dot_xyzw(plane));
\r
1010 out += sizeof_s4DVertexPairRel;
\r
1014 // copy current to out
\r
1016 memcpy_s4DVertexPair(out, a);
\r
1019 out += sizeof_s4DVertexPairRel;
\r
1024 // current point outside
\r
1025 if (ipol_lower_equal_0(bDotPlane))
\r
1027 // previous was inside
\r
1028 // intersect line segment with plane
\r
1029 out->interpolate(*b, *a, bDotPlane / (b->Pos - a->Pos).dot_xyzw(plane));
\r
1030 out += sizeof_s4DVertexPairRel;
\r
1037 bDotPlane = b->Pos.dot_xyzw(plane);
\r
1045 Clip on all planes. Clipper.data
\r
1048 size_t CBurningVideoDriver::clipToFrustum(const size_t vIn /*, const size_t clipmask_for_face*/)
\r
1050 s4DVertexPair* v0 = Clipper.data;
\r
1051 s4DVertexPair* v1 = Clipper_temp.data;
\r
1052 size_t vOut = vIn;
\r
1054 //clear all clipping & projected flags
\r
1055 const u32 flag = v0[0].flag & VERTEX4D_FORMAT_MASK;
\r
1056 for (size_t g = 0; g != Clipper.ElementSize; ++g)
\r
1058 v0[g].flag = flag;
\r
1059 v1[g].flag = flag;
\r
1063 for (size_t i = 0; i < 6; ++i)
\r
1065 v0 = i & 1 ? Clipper_temp.data : Clipper.data;
\r
1066 v1 = i & 1 ? Clipper.data : Clipper_temp.data;
\r
1068 //clipMask checked outside - always clip all planes
\r
1070 if (0 == (clipMask & ((size_t)1 << i)))
\r
1073 memcpy_s4DVertexPair(v1, v0);
\r
1078 vOut = clipToHyperPlane(v1, v0, vOut, NDCPlane[i]);
\r
1079 if (vOut < vIn) return vOut;
\r
1085 vOut = clipToHyperPlane(v1, v0, vOut, NDCPlane[0]); if (vOut < vIn) return vOut;
\r
1086 vOut = clipToHyperPlane(v0, v1, vOut, NDCPlane[1]); if (vOut < vIn) return vOut;
\r
1087 vOut = clipToHyperPlane(v1, v0, vOut, NDCPlane[2]); if (vOut < vIn) return vOut;
\r
1088 vOut = clipToHyperPlane(v0, v1, vOut, NDCPlane[3]); if (vOut < vIn) return vOut;
\r
1089 vOut = clipToHyperPlane(v1, v0, vOut, NDCPlane[4]); if (vOut < vIn) return vOut;
\r
1090 vOut = clipToHyperPlane(v0, v1, vOut, NDCPlane[5]);
\r
1097 apply Clip Scale matrix
\r
1098 From Normalized Device Coordiante ( NDC ) Space to Device Coordinate ( DC ) Space
\r
1101 Project homogeneous vector
\r
1102 homogeneous to non-homogenous coordinates ( dividebyW )
\r
1104 Incoming: ( xw, yw, zw, w, u, v, 1, R, G, B, A )
\r
1105 Outgoing: ( xw/w, yw/w, zw/w, w/w, u/w, v/w, 1/w, R/w, G/w, B/w, A/w )
\r
1107 replace w/w by 1/w
\r
1109 //aliasing problems! [dest = source + 1]
\r
1110 inline void CBurningVideoDriver::ndc_2_dc_and_project(s4DVertexPair* dest, const s4DVertexPair* source, const size_t vIn) const
\r
1112 const f32* dc = Transformation_ETS_CLIPSCALE[TransformationStack];
\r
1114 for (size_t g = 0; g != vIn; g += sizeof_s4DVertexPairRel)
\r
1116 //cache doesn't work anymore?
\r
1117 //if ( dest[g].flag & VERTEX4D_PROJECTED )
\r
1119 //dest[g].flag = source[g].flag | VERTEX4D_PROJECTED;
\r
1121 const f32 iw = reciprocal_zero(source[g].Pos.w);
\r
1123 // to device coordinates
\r
1124 dest[g].Pos.x = iw * source[g].Pos.x * dc[0] + dc[1];
\r
1125 dest[g].Pos.y = iw * source[g].Pos.y * dc[2] + dc[3];
\r
1127 //burning uses direct Z. for OpenGL it should be -Z,[-1;1] and texture flip
\r
1128 #if !defined(SOFTWARE_DRIVER_2_USE_WBUFFER) || 1
\r
1129 dest[g].Pos.z = -iw * source[g].Pos.z * 0.5f + 0.5f;
\r
1131 dest[g].Pos.w = iw;
\r
1133 // Texture Coordinates will be projected after mipmap selection
\r
1134 // satisfy write-combiner
\r
1136 #if BURNING_MATERIAL_MAX_TEXTURES > 0
\r
1137 dest[g].Tex[0] = source[g].Tex[0];
\r
1139 #if BURNING_MATERIAL_MAX_TEXTURES > 1
\r
1140 dest[g].Tex[1] = source[g].Tex[1];
\r
1142 #if BURNING_MATERIAL_MAX_TEXTURES > 2
\r
1143 dest[g].Tex[2] = source[g].Tex[2];
\r
1145 #if BURNING_MATERIAL_MAX_TEXTURES > 3
\r
1146 dest[g].Tex[3] = source[g].Tex[3];
\r
1151 #if BURNING_MATERIAL_MAX_COLORS > 0
\r
1152 #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
\r
1153 dest[g].Color[0] = source[g].Color[0] * iw; // alpha?
\r
1155 dest[g].Color[0] = source[g].Color[0];
\r
1159 #if BURNING_MATERIAL_MAX_COLORS > 1
\r
1160 #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
\r
1161 dest[g].Color[1] = source[g].Color[1] * iw; // alpha?
\r
1163 dest[g].Color[1] = source[g].Color[1];
\r
1167 #if BURNING_MATERIAL_MAX_COLORS > 2
\r
1168 #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
\r
1169 dest[g].Color[2] = source[g].Color[2] * iw; // alpha?
\r
1171 dest[g].Color[2] = source[g].Color[2];
\r
1175 #if BURNING_MATERIAL_MAX_COLORS > 3
\r
1176 #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
\r
1177 dest[g].Color[3] = source[g].Color[3] * iw; // alpha?
\r
1179 dest[g].Color[3] = source[g].Color[3];
\r
1183 #if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0
\r
1184 dest[g].LightTangent[0] = source[g].LightTangent[0] * iw;
\r
1194 crossproduct in projected 2D, face
\r
1196 REALINLINE f32 CBurningVideoDriver::screenarea_inside(const s4DVertexPair* burning_restrict const face[]) const
\r
1198 return (((face[1] + 1)->Pos.x - (face[0] + 1)->Pos.x) * ((face[2] + 1)->Pos.y - (face[0] + 1)->Pos.y)) -
\r
1199 (((face[2] + 1)->Pos.x - (face[0] + 1)->Pos.x) * ((face[1] + 1)->Pos.y - (face[0] + 1)->Pos.y));
\r
1201 float signedArea = 0;
\r
1202 for (int k = 1; k < output->count; k++) {
\r
1203 signedArea += (output->vertices[k - 1].values[0] * output->vertices[k - 0].values[1]);
\r
1204 signedArea -= (output->vertices[k - 0].values[0] * output->vertices[k - 1].values[1]);
\r
1210 static inline f32 dot(const sVec2& a, const sVec2& b) { return a.x * b.x + a.y * b.y; }
\r
1211 sVec2 dFdx(const sVec2& v) { return v; }
\r
1212 sVec2 dFdy(const sVec2& v) { return v; }
\r
1214 f32 MipmapLevel(const sVec2& uv, const sVec2& textureSize)
\r
1216 sVec2 dx = dFdx(uv * textureSize.x);
\r
1217 sVec2 dy = dFdy(uv * textureSize.y);
\r
1218 f32 d = core::max_(dot(dx, dx), dot(dy, dy));
\r
1219 return log2f(sqrtf(d));
\r
1223 //#define MAT_TEXTURE(tex) ( (video::CSoftwareTexture2*) Material.org.getTexture ( (u32)tex ) )
\r
1224 #define MAT_TEXTURE(tex) ( (video::CSoftwareTexture2*) Material.org.TextureLayer[tex].Texture )
\r
1227 calculate from unprojected.
\r
1228 attribute need not to follow winding rule from position.
\r
1229 Edge-walking problem
\r
1230 Texture Wrapping problem
\r
1233 REALINLINE s32 CBurningVideoDriver::lodFactor_inside(const s4DVertexPair* burning_restrict const face[],
\r
1234 const size_t m, const f32 dc_area, const f32 lod_bias) const
\r
1237 sVec2 a(v[1]->Tex[tex].x - v[0]->Tex[tex].x,v[1]->Tex[tex].y - v[0]->Tex[tex].y);
\r
1238 sVec2 b(v[2]->Tex[tex].x - v[0]->Tex[tex].x,v[2]->Tex[tex].y - v[0]->Tex[tex].y);
\r
1239 f32 area = a.x * b.y - b.x * a.y;
\r
1244 degenerate(A, B, C, minarea) = ((B - A).cross(C - A)).lengthSquared() < (4.0f * minarea * minarea);
\r
1245 check for collapsed or "long thin triangles"
\r
1247 ieee754 signedArea;
\r
1250 t[0].f = face[1]->Tex[m].x - face[0]->Tex[m].x;
\r
1251 t[1].f = face[1]->Tex[m].y - face[0]->Tex[m].y;
\r
1253 t[2].f = face[2]->Tex[m].x - face[0]->Tex[m].x;
\r
1254 t[3].f = face[2]->Tex[m].y - face[0]->Tex[m].y;
\r
1256 //crossproduct in projected 2D -> screen area triangle
\r
1257 signedArea.f = t[0].f * t[3].f - t[2].f * t[1].f;
\r
1260 // ((face[1]->Tex[m].x - face[0]->Tex[m].x) * (face[2]->Tex[m].y - face[0]->Tex[m].y))
\r
1261 // - ((face[2]->Tex[m].x - face[0]->Tex[m].x) * (face[1]->Tex[m].y - face[0]->Tex[m].y));
\r
1263 //if (signedArea*signedArea <= 0.00000000001f)
\r
1264 if (signedArea.fields.exp == 0)
\r
1267 _max.u = t[0].abs.frac_exp;
\r
1268 if (t[1].abs.frac_exp > _max.u) _max.u = t[1].abs.frac_exp;
\r
1269 if (t[2].abs.frac_exp > _max.u) _max.u = t[2].abs.frac_exp;
\r
1270 if (t[3].abs.frac_exp > _max.u) _max.u = t[3].abs.frac_exp;
\r
1272 signedArea.u = _max.fields.exp ? _max.u : ieee754_one;
\r
1277 v[0].f = t[0] * t[2];
\r
1278 v[1].f = t[1] * t[3];
\r
1280 //signedArea.f = t[4] > t[5] ? t[4] : t[5];
\r
1281 signedArea.u = v[0].fields.frac > v[1].fields.frac ? v[0].u : v[1].u;
\r
1282 if (signedArea.fields.exp == 0)
\r
1289 //only guessing: take more detail (lower mipmap) in light+bump textures
\r
1290 //assume transparent add is ~50% transparent -> more detail
\r
1292 // 2.f from dc_area, 2.f from tex triangle ( parallelogram area)
\r
1293 const u32* d = MAT_TEXTURE(m)->getMipMap0_Area();
\r
1294 f32 texelspace = d[0] * d[1] * lod_bias; //(m ? 0.5f : 0.5f);
\r
1297 ratio.f = (signedArea.f * texelspace) * dc_area;
\r
1298 ratio.fields.sign = 0;
\r
1300 //log2(0)==denormal [ use high lod] [ only if dc_area == 0 checked outside ]
\r
1301 return (ratio.fields.exp & 0x80) ? ratio.fields.exp - 127 : 0; /*denormal very high lod*/
\r
1307 texcoo in current mipmap dimension (face, already clipped)
\r
1308 -> want to help fixpoint
\r
1310 inline void CBurningVideoDriver::select_polygon_mipmap_inside(s4DVertex* burning_restrict face[], const size_t tex, const CSoftwareTexture2_Bound& b) const
\r
1312 #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
\r
1313 (face[0] + 1)->Tex[tex].x = face[0]->Tex[tex].x * (face[0] + 1)->Pos.w * b.w + b.cx;
\r
1314 (face[0] + 1)->Tex[tex].y = face[0]->Tex[tex].y * (face[0] + 1)->Pos.w * b.h + b.cy;
\r
1316 (face[1] + 1)->Tex[tex].x = face[1]->Tex[tex].x * (face[1] + 1)->Pos.w * b.w + b.cx;
\r
1317 (face[1] + 1)->Tex[tex].y = face[1]->Tex[tex].y * (face[1] + 1)->Pos.w * b.h + b.cy;
\r
1319 (face[2] + 1)->Tex[tex].x = face[2]->Tex[tex].x * (face[2] + 1)->Pos.w * b.w + b.cx;
\r
1320 (face[2] + 1)->Tex[tex].y = face[2]->Tex[tex].y * (face[2] + 1)->Pos.w * b.h + b.cy;
\r
1322 (face[0] + 1)->Tex[tex].x = face[0]->Tex[tex].x * b.w;
\r
1323 (face[0] + 1)->Tex[tex].y = face[0]->Tex[tex].y * b.h;
\r
1325 (face[1] + 1)->Tex[tex].x = face[1]->Tex[tex].x * b.w;
\r
1326 (face[1] + 1)->Tex[tex].y = face[1]->Tex[tex].y * b.h;
\r
1328 (face[2] + 1)->Tex[tex].x = face[2]->Tex[tex].x * b.w;
\r
1329 (face[2] + 1)->Tex[tex].y = face[2]->Tex[tex].y * b.h;
\r
1337 //! setup Vertex Format
\r
1338 void CBurningVideoDriver::VertexCache_map_source_format()
\r
1340 u32 s0 = sizeof(s4DVertex);
\r
1341 u32 s1 = sizeof(s4DVertex_proxy);
\r
1343 if (s1 <= sizeof_s4DVertex / 2)
\r
1345 os::Printer::log("BurningVideo vertex format unnecessary to large", ELL_WARNING);
\r
1349 if (s0 != sizeof_s4DVertex || ((sizeof_s4DVertex * sizeof_s4DVertexPairRel) & 31))
\r
1351 os::Printer::log("BurningVideo vertex format compile problem", ELL_ERROR);
\r
1352 _IRR_DEBUG_BREAK_IF(1);
\r
1355 #if defined(ENV64BIT)
\r
1356 if (sizeof(void*) != 8)
\r
1358 os::Printer::log("BurningVideo pointer should be 8 bytes", ELL_ERROR);
\r
1359 _IRR_DEBUG_BREAK_IF(1);
\r
1362 if (((unsigned long long)Transformation&15) || ((unsigned long long)TransformationFlag & 15))
\r
1364 os::Printer::log("BurningVideo Matrix Stack not 16 byte aligned", ELL_ERROR);
\r
1365 _IRR_DEBUG_BREAK_IF(1);
\r
1370 SVSize* vSize = VertexCache.vSize;
\r
1371 //vSize[E4VT_STANDARD].Format = VERTEX4D_FORMAT_TEXTURE_1 | VERTEX4D_FORMAT_COLOR_1 | VERTEX4D_FORMAT_LIGHT_1 | VERTEX4D_FORMAT_SPECULAR;
\r
1372 vSize[E4VT_STANDARD].Format = VERTEX4D_FORMAT_TEXTURE_1 | VERTEX4D_FORMAT_COLOR_2_FOG;
\r
1373 vSize[E4VT_STANDARD].Pitch = sizeof(S3DVertex);
\r
1374 vSize[E4VT_STANDARD].TexSize = 1;
\r
1375 vSize[E4VT_STANDARD].TexCooSize = 1;
\r
1377 vSize[E4VT_2TCOORDS].Format = VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1;
\r
1378 vSize[E4VT_2TCOORDS].Pitch = sizeof(S3DVertex2TCoords);
\r
1379 vSize[E4VT_2TCOORDS].TexSize = 2;
\r
1380 vSize[E4VT_2TCOORDS].TexCooSize = 2;
\r
1382 //vSize[E4VT_TANGENTS].Format = VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1 | VERTEX4D_FORMAT_LIGHT_1 | VERTEX4D_FORMAT_BUMP_DOT3;
\r
1383 vSize[E4VT_TANGENTS].Format = VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_2_FOG | VERTEX4D_FORMAT_LIGHT_1 | VERTEX4D_FORMAT_BUMP_DOT3;
\r
1384 vSize[E4VT_TANGENTS].Pitch = sizeof(S3DVertexTangents);
\r
1385 vSize[E4VT_TANGENTS].TexSize = 2;
\r
1386 vSize[E4VT_TANGENTS].TexCooSize = 2;
\r
1389 vSize[E4VT_REFLECTION_MAP].Format = VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1;
\r
1390 vSize[E4VT_REFLECTION_MAP].Pitch = sizeof(S3DVertex);
\r
1391 vSize[E4VT_REFLECTION_MAP].TexSize = 2;
\r
1392 vSize[E4VT_REFLECTION_MAP].TexCooSize = 1; //TexCoo2 generated
\r
1395 vSize[E4VT_SHADOW].Format = 0;
\r
1396 vSize[E4VT_SHADOW].Pitch = sizeof(f32) * 3; // core::vector3df*
\r
1397 vSize[E4VT_SHADOW].TexSize = 0;
\r
1398 vSize[E4VT_SHADOW].TexCooSize = 0;
\r
1400 // color shading only (no texture)
\r
1401 vSize[E4VT_NO_TEXTURE].Format = VERTEX4D_FORMAT_COLOR_1 | VERTEX4D_FORMAT_LIGHT_1 | VERTEX4D_FORMAT_SPECULAR;
\r
1402 vSize[E4VT_NO_TEXTURE].Pitch = sizeof(S3DVertex);
\r
1403 vSize[E4VT_NO_TEXTURE].TexSize = 0;
\r
1404 vSize[E4VT_NO_TEXTURE].TexCooSize = 0;
\r
1407 vSize[E4VT_LINE].Format = VERTEX4D_FORMAT_COLOR_1;
\r
1408 vSize[E4VT_LINE].Pitch = sizeof(S3DVertex);
\r
1409 vSize[E4VT_LINE].TexSize = 0;
\r
1410 vSize[E4VT_LINE].TexCooSize = 0;
\r
1413 for (size_t i = 0; i < E4VT_COUNT; ++i)
\r
1415 size_t& flag = vSize[i].Format;
\r
1417 #if !defined(SOFTWARE_DRIVER_2_USE_SEPARATE_SPECULAR_COLOR)
\r
1418 flag &= ~VERTEX4D_FORMAT_SPECULAR;
\r
1420 if (vSize[i].TexSize > BURNING_MATERIAL_MAX_TEXTURES)
\r
1421 vSize[i].TexSize = BURNING_MATERIAL_MAX_TEXTURES;
\r
1423 size = (flag & VERTEX4D_FORMAT_MASK_TEXTURE) >> 16;
\r
1424 if (size > BURNING_MATERIAL_MAX_TEXTURES)
\r
1426 flag = (flag & ~VERTEX4D_FORMAT_MASK_TEXTURE) | (BURNING_MATERIAL_MAX_TEXTURES << 16);
\r
1429 size = (flag & VERTEX4D_FORMAT_MASK_COLOR) >> 20;
\r
1430 if (size > BURNING_MATERIAL_MAX_COLORS)
\r
1432 flag = (flag & ~VERTEX4D_FORMAT_MASK_COLOR) | (BURNING_MATERIAL_MAX_COLORS << 20);
\r
1435 size = (flag & VERTEX4D_FORMAT_MASK_LIGHT) >> 24;
\r
1436 if (size > BURNING_MATERIAL_MAX_LIGHT_TANGENT)
\r
1438 flag = (flag & ~VERTEX4D_FORMAT_MASK_LIGHT) | (BURNING_MATERIAL_MAX_LIGHT_TANGENT << 24);
\r
1442 VertexCache.mem.resize(VERTEXCACHE_ELEMENT * 2);
\r
1443 VertexCache.vType = E4VT_STANDARD;
\r
1445 Clipper.resize(VERTEXCACHE_ELEMENT * 2);
\r
1446 Clipper_temp.resize(VERTEXCACHE_ELEMENT * 2);
\r
1448 TransformationStack = 0;
\r
1449 memset(TransformationFlag, 0, sizeof(TransformationFlag));
\r
1450 memset(Transformation_ETS_CLIPSCALE, 0, sizeof(Transformation_ETS_CLIPSCALE));
\r
1452 Material.resetRenderStates = true;
\r
1453 Material.Fallback_MaterialType = EMT_SOLID;
\r
1459 fill a cache line with transformed, light and clip test triangles
\r
1460 overhead - if primitive is outside or culled, vertexLighting and TextureTransform is still done
\r
1462 void CBurningVideoDriver::VertexCache_fill(const u32 sourceIndex, const u32 destIndex)
\r
1464 u8* burning_restrict source;
\r
1465 s4DVertex* burning_restrict dest;
\r
1467 source = (u8*)VertexCache.vertices + (sourceIndex * VertexCache.vSize[VertexCache.vType].Pitch);
\r
1469 // it's a look ahead so we never hit it..
\r
1470 // but give priority...
\r
1471 //VertexCache.info[ destIndex ].hit = hitCount;
\r
1474 VertexCache.info[destIndex].index = sourceIndex;
\r
1475 VertexCache.info[destIndex].hit = 0;
\r
1477 // destination Vertex
\r
1478 dest = VertexCache.mem.data + s4DVertex_ofs(destIndex);
\r
1480 //Irrlicht S3DVertex,S3DVertex2TCoords,S3DVertexTangents
\r
1481 const S3DVertex* base = ((S3DVertex*)source);
\r
1483 // transform Model * World * Camera * Projection * NDCSpace matrix
\r
1484 const core::matrix4* matrix = Transformation[TransformationStack];
\r
1485 matrix[ETS_PROJ_MODEL_VIEW].transformVect(&dest->Pos.x, base->Pos);
\r
1487 //mhm ... maybe no goto
\r
1488 if (VertexCache.vType == E4VT_SHADOW)
\r
1490 //core::vector3df i = base->Pos;
\r
1492 //matrix[ETS_PROJ_MODEL_VIEW].transformVect(&dest->Pos.x, i);
\r
1494 //GL_DEPTH_CLAMP,EVDF_DEPTH_CLAMP
\r
1495 //if ( dest->Pos.z < dest->Pos.w)
\r
1496 // dest->Pos.z = dest->Pos.w*0.99f;
\r
1498 //glPolygonOffset // self shadow wanted or not?
\r
1499 dest->Pos.w *= 1.005f;
\r
1501 //flag |= v->Pos.z <= v->Pos.w ? VERTEX4D_CLIP_NEAR : 0;
\r
1502 //flag |= -v->Pos.z <= v->Pos.w ? VERTEX4D_CLIP_FAR : 0;
\r
1504 goto clipandproject;
\r
1508 #if defined (SOFTWARE_DRIVER_2_LIGHTING) || defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM )
\r
1510 // vertex, normal in light(eye) space
\r
1511 if (Material.org.Lighting || (EyeSpace.TL_Flag & (TL_TEXTURE_TRANSFORM | TL_FOG)))
\r
1513 sVec4 vertex4; //eye coordinate position of vertex
\r
1514 matrix[ETS_MODEL_VIEW].transformVect(&vertex4.x, base->Pos);
\r
1516 const f32 iw = reciprocal_zero(vertex4.w);
\r
1517 EyeSpace.vertex.x = vertex4.x * iw;
\r
1518 EyeSpace.vertex.y = vertex4.y * iw;
\r
1519 EyeSpace.vertex.z = vertex4.z * iw;
\r
1520 EyeSpace.vertex.w = iw;
\r
1522 //EyeSpace.cam_distance = EyeSpace.vertex.length_xyz();
\r
1523 EyeSpace.cam_dir = EyeSpace.vertex;
\r
1524 EyeSpace.cam_dir.normalize_dir_xyz();
\r
1526 matrix[ETS_NORMAL].rotateVect(&EyeSpace.normal.x, base->Normal);
\r
1527 if (EyeSpace.TL_Flag & TL_NORMALIZE_NORMALS)
\r
1528 EyeSpace.normal.normalize_dir_xyz();
\r
1534 #if BURNING_MATERIAL_MAX_COLORS > 1
\r
1535 dest->Color[1].a = 1.f;
\r
1536 dest->Color[1].r = 0.f;
\r
1537 dest->Color[1].g = 0.f;
\r
1538 dest->Color[1].b = 0.f;
\r
1541 #if BURNING_MATERIAL_MAX_COLORS > 2
\r
1542 dest->Color[2].a = 1.f;
\r
1543 dest->Color[2].r = 0.f;
\r
1544 dest->Color[2].g = 0.f;
\r
1545 dest->Color[2].b = 0.f;
\r
1548 #if BURNING_MATERIAL_MAX_COLORS > 3
\r
1549 dest->Color[3].a = 1.f;
\r
1550 dest->Color[3].r = 0.f;
\r
1551 dest->Color[3].g = 0.f;
\r
1552 dest->Color[3].b = 0.f;
\r
1555 #if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0
\r
1556 dest->LightTangent[0].x = 0.f;
\r
1557 dest->LightTangent[0].y = 0.f;
\r
1558 dest->LightTangent[0].z = 0.f;
\r
1562 #if BURNING_MATERIAL_MAX_COLORS > 0
\r
1563 // apply lighting model
\r
1564 #if defined (SOFTWARE_DRIVER_2_LIGHTING)
\r
1565 if (Material.org.Lighting)
\r
1567 lightVertex_eye(dest, base->Color.color);
\r
1571 dest->Color[0].setA8R8G8B8(base->Color.color);
\r
1574 dest->Color[0].setA8R8G8B8(base->Color.color);
\r
1579 if (EyeSpace.TL_Flag & TL_FOG) //Material.org.FogEnable
\r
1581 f32 fog_factor = 1.f;
\r
1583 // GL_FRAGMENT_DEPTH -> abs(EyeSpace.vertex.z)
\r
1584 ieee754 fog_frag_coord;
\r
1585 fog_frag_coord.f = EyeSpace.vertex.z;
\r
1586 fog_frag_coord.fields.sign = 0;
\r
1590 case EFT_FOG_LINEAR:
\r
1591 fog_factor = (FogEnd - fog_frag_coord.f) * EyeSpace.fog_scale;
\r
1594 fog_factor = (f32)exp(-FogDensity * fog_frag_coord.f);
\r
1596 case EFT_FOG_EXP2:
\r
1597 fog_factor = (f32)exp(-FogDensity * FogDensity * fog_frag_coord.f * fog_frag_coord.f);
\r
1601 sVec4* a = dest->Color + ((VertexCache.vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_COLOR_2_FOG) ? 1 : 0);
\r
1602 a->a = clampf01(fog_factor);
\r
1605 // Texture Coo Transform
\r
1606 // Always set all internal uv (v1.9 SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM always on)
\r
1607 for (size_t t = 0; t < BURNING_MATERIAL_MAX_TEXTURES; ++t)
\r
1613 const size_t flag = TransformationFlag[TransformationStack][ETS_TEXTURE_0 + t];
\r
1614 if (flag & ETF_TEXGEN_CAMERA_SPHERE)
\r
1616 //reflect(u,N) u - 2.0 * dot(N, u) * N
\r
1617 // cam is (0,0,-1), tex flipped
\r
1619 const sVec4& u = EyeSpace.cam_dir; // EyeSpace.vertex.normalized
\r
1620 const sVec4& n = EyeSpace.normal;
\r
1622 f32 dot = -2.f * n.dot_xyz(u);
\r
1623 r.x = u.x + dot * n.x;
\r
1624 r.y = u.y + dot * n.y;
\r
1625 r.z = u.z + dot * n.z;
\r
1628 f32 m = 2.f * sqrtf(r.x * r.x + r.y * r.y + (r.z + 1.f) * (r.z + 1.f));
\r
1629 tx = r.x / m + 0.5f;
\r
1630 ty = -r.y / m + 0.5f;
\r
1633 //~d3d with spheremap scale
\r
1634 f32 m = 0.25f / (0.00001f + sqrtf(r.x*r.x+r.y*r.y+r.z*r.z));
\r
1635 dest[0].Tex[t].x = r.x * m + 0.5f;
\r
1636 dest[0].Tex[t].y = -r.y * m + 0.5f;
\r
1639 else if (flag & ETF_TEXGEN_CAMERA_REFLECTION)
\r
1641 //reflect(u,N) u - 2.0 * dot(N, u) * N
\r
1642 // cam is (0,0,-1), tex flipped
\r
1644 const sVec4& u = EyeSpace.cam_dir; // EyeSpace.vertex.normalized
\r
1645 const sVec4& n = EyeSpace.normal;
\r
1647 f32 dot = -2.f * n.dot_xyz(u);
\r
1648 r.x = u.x + dot * n.x;
\r
1649 r.y = u.y + dot * n.y;
\r
1650 r.z = u.z + dot * n.z;
\r
1656 //~d3d with spheremap scale
\r
1657 dest[0].Tex[t].x = r.x;
\r
1658 dest[0].Tex[t].y = r.y;
\r
1662 if (t < VertexCache.vSize[VertexCache.vType].TexCooSize)
\r
1664 // Irrlicht TCoords and TCoords2 must be contiguous memory. baseTCoord has no 4 byte aligned start address!
\r
1665 const sVec2Pack* baseTCoord = (const sVec2Pack*)&base->TCoords.X;
\r
1667 tx = baseTCoord[t].x;
\r
1668 ty = baseTCoord[t].y;
\r
1677 if (!(flag & ETF_IDENTITY))
\r
1680 Generate texture coordinates as linear functions so that:
\r
1681 u = Ux*x + Uy*y + Uz*z + Uw
\r
1682 v = Vx*x + Vy*y + Vz*z + Vw
\r
1683 The matrix M for this case is:
\r
1690 const f32* M = matrix[ETS_TEXTURE_0 + t].pointer();
\r
1694 tx = M[0] * _tx + M[4] * _ty + M[8];
\r
1695 ty = M[1] * _tx + M[5] * _ty + M[9];
\r
1698 switch (Material.org.TextureLayer[t].TextureWrapU)
\r
1701 case ETC_CLAMP_TO_EDGE:
\r
1702 case ETC_CLAMP_TO_BORDER:
\r
1703 tx = clampf01(tx);
\r
1706 if (core::fract(tx) > 0.5f)
\r
1709 case ETC_MIRROR_CLAMP:
\r
1710 case ETC_MIRROR_CLAMP_TO_EDGE:
\r
1711 case ETC_MIRROR_CLAMP_TO_BORDER:
\r
1712 tx = clampf01(tx);
\r
1713 if (core::fract(tx) > 0.5f)
\r
1717 // texel access is always modulo
\r
1721 switch (Material.org.TextureLayer[t].TextureWrapV)
\r
1724 case ETC_CLAMP_TO_EDGE:
\r
1725 case ETC_CLAMP_TO_BORDER:
\r
1726 ty = clampf01(ty);
\r
1729 if (core::fract(ty) > 0.5f)
\r
1732 case ETC_MIRROR_CLAMP:
\r
1733 case ETC_MIRROR_CLAMP_TO_EDGE:
\r
1734 case ETC_MIRROR_CLAMP_TO_BORDER:
\r
1735 ty = clampf01(ty);
\r
1736 if (core::fract(ty) > 0.5f)
\r
1740 // texel access is always modulo
\r
1745 dest->Tex[t].x = tx;
\r
1746 dest->Tex[t].y = ty;
\r
1750 #if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0
\r
1751 if ((EyeSpace.TL_Flag & TL_LIGHT0_IS_NORMAL_MAP) &&
\r
1752 ((VertexCache.vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_MASK_TANGENT) == VERTEX4D_FORMAT_BUMP_DOT3)
\r
1755 const S3DVertexTangents* tangent = ((S3DVertexTangents*)source);
\r
1759 light_accu.x = 0.f;
\r
1760 light_accu.y = 0.f;
\r
1761 light_accu.z = 0.f;
\r
1762 light_accu.w = 0.f;
\r
1763 for (u32 i = 0; i < 2 && i < EyeSpace.Light.size(); ++i)
\r
1765 const SBurningShaderLight& light = EyeSpace.Light[i];
\r
1766 if (!light.LightIsOn)
\r
1769 // lightcolor with standard model
\r
1770 // but shader is different. treating light and vertex in same space
\r
1772 vp.x = light.pos.x - base->Pos.X;
\r
1773 vp.y = light.pos.y - base->Pos.Y;
\r
1774 vp.z = light.pos.z - base->Pos.Z;
\r
1776 vp.x = light.pos4.x - EyeSpace.vertex.x;
\r
1777 vp.y = light.pos4.y - EyeSpace.vertex.y;
\r
1778 vp.z = light.pos4.z - EyeSpace.vertex.z;
\r
1781 // transform by tangent matrix
\r
1782 light_accu.x += (vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z);
\r
1783 light_accu.y += (vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z);
\r
1784 light_accu.z += (vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z);
\r
1786 //normalize [-1,+1] to [0,1] -> obsolete
\r
1787 light_accu.normalize_pack_xyz(dest->LightTangent[0], 1.f, 0.f);
\r
1788 dest->Tex[1].x = dest->Tex[0].x;
\r
1789 dest->Tex[1].y = dest->Tex[0].y;
\r
1792 else if (Material.org.Lighting)
\r
1794 //dest->LightTangent[0].x = 0.f;
\r
1795 //dest->LightTangent[0].y = 0.f;
\r
1796 //dest->LightTangent[0].z = 0.f;
\r
1798 #endif //if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0
\r
1800 //#endif // SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM
\r
1804 // test vertex visible
\r
1805 dest[0].flag = (u32)(clipToFrustumTest(dest) | VertexCache.vSize[VertexCache.vType].Format);
\r
1806 dest[1].flag = dest[0].flag;
\r
1808 // to DC Space, project homogenous vertex
\r
1809 if ((dest[0].flag & VERTEX4D_CLIPMASK) == VERTEX4D_INSIDE)
\r
1811 ndc_2_dc_and_project(dest + s4DVertex_proj(0), dest + s4DVertex_ofs(0), s4DVertex_ofs(1));
\r
1817 //todo: this should return only index
\r
1818 s4DVertexPair* CBurningVideoDriver::VertexCache_getVertex(const u32 sourceIndex) const
\r
1820 for (size_t i = 0; i < VERTEXCACHE_ELEMENT; ++i)
\r
1822 if (VertexCache.info[i].index == sourceIndex)
\r
1824 return VertexCache.mem.data + s4DVertex_ofs(i);
\r
1827 return VertexCache.mem.data; //error
\r
1832 Cache based on linear walk indices
\r
1833 fill blockwise on the next 16(Cache_Size) unique vertices in indexlist
\r
1834 merge the next 16 vertices with the current
\r
1836 void CBurningVideoDriver::VertexCache_get(s4DVertexPair* face[4])
\r
1838 // next primitive must be complete in cache
\r
1839 if (VertexCache.indicesIndex - VertexCache.indicesRun < VertexCache.primitiveHasVertex &&
\r
1840 VertexCache.indicesIndex < VertexCache.indexCount
\r
1845 //memset(info, VERTEXCACHE_MISS, sizeof(info));
\r
1846 for (i = 0; i != VERTEXCACHE_ELEMENT; ++i)
\r
1848 VertexCache.info_temp[i].hit = VERTEXCACHE_MISS;
\r
1849 VertexCache.info_temp[i].index = VERTEXCACHE_MISS;
\r
1852 // rewind to start of primitive
\r
1853 VertexCache.indicesIndex = VertexCache.indicesRun;
\r
1856 // get the next unique vertices cache line
\r
1857 u32 fillIndex = 0;
\r
1859 u32 sourceIndex = 0;
\r
1861 while (VertexCache.indicesIndex < VertexCache.indexCount &&
\r
1862 fillIndex < VERTEXCACHE_ELEMENT
\r
1865 switch (VertexCache.iType)
\r
1868 sourceIndex = ((u16*)VertexCache.indices)[VertexCache.indicesIndex];
\r
1871 sourceIndex = ((u32*)VertexCache.indices)[VertexCache.indicesIndex];
\r
1875 sourceIndex = VertexCache.indicesIndex;
\r
1879 VertexCache.indicesIndex += 1;
\r
1881 // if not exist, push back
\r
1883 for (dIndex = 0; dIndex < fillIndex; ++dIndex)
\r
1885 if (VertexCache.info_temp[dIndex].index == sourceIndex)
\r
1894 VertexCache.info_temp[fillIndex++].index = sourceIndex;
\r
1899 for (i = 0; i != VERTEXCACHE_ELEMENT; ++i)
\r
1901 VertexCache.info[i].hit = 0;
\r
1904 // mark all existing
\r
1905 for (i = 0; i != fillIndex; ++i)
\r
1907 for (dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex)
\r
1909 if (VertexCache.info[dIndex].index == VertexCache.info_temp[i].index)
\r
1911 VertexCache.info_temp[i].hit = dIndex;
\r
1912 VertexCache.info[dIndex].hit = 1;
\r
1919 for (i = 0; i != fillIndex; ++i)
\r
1921 if (VertexCache.info_temp[i].hit != VERTEXCACHE_MISS)
\r
1924 for (dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex)
\r
1926 if (0 == VertexCache.info[dIndex].hit)
\r
1928 VertexCache_fill(VertexCache.info_temp[i].index, dIndex);
\r
1929 VertexCache.info[dIndex].hit += 1;
\r
1930 VertexCache.info_temp[i].hit = dIndex;
\r
1937 //const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun );
\r
1938 const u32 i0 = VertexCache.pType != scene::EPT_TRIANGLE_FAN ? VertexCache.indicesRun : 0;
\r
1940 switch (VertexCache.iType)
\r
1944 const u16* p = (const u16*)VertexCache.indices;
\r
1945 face[0] = VertexCache_getVertex(p[i0]);
\r
1946 face[1] = VertexCache_getVertex(p[VertexCache.indicesRun + 1]);
\r
1947 face[2] = VertexCache_getVertex(p[VertexCache.indicesRun + 2]);
\r
1953 const u32* p = (const u32*)VertexCache.indices;
\r
1954 face[0] = VertexCache_getVertex(p[i0]);
\r
1955 face[1] = VertexCache_getVertex(p[VertexCache.indicesRun + 1]);
\r
1956 face[2] = VertexCache_getVertex(p[VertexCache.indicesRun + 2]);
\r
1961 face[0] = VertexCache_getVertex(VertexCache.indicesRun + 0);
\r
1962 face[1] = VertexCache_getVertex(VertexCache.indicesRun + 1);
\r
1963 face[2] = VertexCache_getVertex(VertexCache.indicesRun + 2);
\r
1966 face[0] = face[1] = face[2] = VertexCache_getVertex(VertexCache.indicesRun + 0);
\r
1969 face[3] = face[0]; // quad unsupported
\r
1970 VertexCache.indicesRun += VertexCache.indicesPitch;
\r
1976 int CBurningVideoDriver::VertexCache_reset(const void* vertices, u32 vertexCount,
\r
1977 const void* indices, u32 primitiveCount,
\r
1978 E_VERTEX_TYPE vType,
\r
1979 scene::E_PRIMITIVE_TYPE pType,
\r
1980 E_INDEX_TYPE iType)
\r
1983 // These calls would lead to crashes due to wrong index usage.
\r
1984 // The vertex cache needs to be rewritten for these primitives.
\r
1985 if (0 == CurrentShader ||
\r
1986 pType == scene::EPT_POINTS || pType == scene::EPT_LINE_STRIP ||
\r
1987 pType == scene::EPT_LINE_LOOP || pType == scene::EPT_LINES ||
\r
1988 pType == scene::EPT_POLYGON ||
\r
1989 pType == scene::EPT_POINT_SPRITES)
\r
1994 VertexCache.vertices = vertices;
\r
1995 VertexCache.vertexCount = vertexCount;
\r
1997 switch (Material.org.MaterialType) // (Material.Fallback_MaterialType)
\r
1999 case EMT_REFLECTION_2_LAYER:
\r
2000 case EMT_TRANSPARENT_REFLECTION_2_LAYER:
\r
2001 VertexCache.vType = E4VT_REFLECTION_MAP;
\r
2004 VertexCache.vType = (e4DVertexType)vType;
\r
2009 SVSize* vSize = VertexCache.vSize;
\r
2010 for (int m = (int)vSize[VertexCache.vType].TexSize - 1; m >= 0; --m)
\r
2012 ITexture* tex = MAT_TEXTURE(m);
\r
2015 vSize[E4VT_NO_TEXTURE] = vSize[VertexCache.vType];
\r
2016 vSize[E4VT_NO_TEXTURE].TexSize = m;
\r
2017 vSize[E4VT_NO_TEXTURE].TexCooSize = m;
\r
2018 VertexCache.vType = E4VT_NO_TEXTURE;
\r
2019 //flags downconvert?
\r
2023 VertexCache.indices = indices;
\r
2024 VertexCache.indicesIndex = 0;
\r
2025 VertexCache.indicesRun = 0;
\r
2029 case EIT_16BIT: VertexCache.iType = E4IT_16BIT; break;
\r
2030 case EIT_32BIT: VertexCache.iType = E4IT_32BIT; break;
\r
2032 VertexCache.iType = (e4DIndexType)iType; break;
\r
2034 if (!VertexCache.indices)
\r
2035 VertexCache.iType = E4IT_NONE;
\r
2037 VertexCache.pType = pType;
\r
2038 VertexCache.primitiveHasVertex = 3;
\r
2039 VertexCache.indicesPitch = 1;
\r
2040 switch (VertexCache.pType)
\r
2042 // most types here will not work as expected, only triangles/triangle_fan
\r
2043 // is known to work.
\r
2044 case scene::EPT_POINTS:
\r
2045 VertexCache.indexCount = primitiveCount;
\r
2046 VertexCache.indicesPitch = 1;
\r
2047 VertexCache.primitiveHasVertex = 1;
\r
2049 case scene::EPT_LINE_STRIP:
\r
2050 VertexCache.indexCount = primitiveCount + 1;
\r
2051 VertexCache.indicesPitch = 1;
\r
2052 VertexCache.primitiveHasVertex = 2;
\r
2054 case scene::EPT_LINE_LOOP:
\r
2055 VertexCache.indexCount = primitiveCount + 1;
\r
2056 VertexCache.indicesPitch = 1;
\r
2057 VertexCache.primitiveHasVertex = 2;
\r
2059 case scene::EPT_LINES:
\r
2060 VertexCache.indexCount = 2 * primitiveCount;
\r
2061 VertexCache.indicesPitch = 2;
\r
2062 VertexCache.primitiveHasVertex = 2;
\r
2064 case scene::EPT_TRIANGLE_STRIP:
\r
2065 VertexCache.indexCount = primitiveCount + 2;
\r
2066 VertexCache.indicesPitch = 1;
\r
2067 VertexCache.primitiveHasVertex = 3;
\r
2069 case scene::EPT_TRIANGLES:
\r
2070 VertexCache.indexCount = primitiveCount + primitiveCount + primitiveCount;
\r
2071 VertexCache.indicesPitch = 3;
\r
2072 VertexCache.primitiveHasVertex = 3;
\r
2074 case scene::EPT_TRIANGLE_FAN:
\r
2075 VertexCache.indexCount = primitiveCount + 2;
\r
2076 VertexCache.indicesPitch = 1;
\r
2077 VertexCache.primitiveHasVertex = 3;
\r
2079 case scene::EPT_QUAD_STRIP:
\r
2080 VertexCache.indexCount = 2 * primitiveCount + 2;
\r
2081 VertexCache.indicesPitch = 2;
\r
2082 VertexCache.primitiveHasVertex = 4;
\r
2084 case scene::EPT_QUADS:
\r
2085 VertexCache.indexCount = 4 * primitiveCount;
\r
2086 VertexCache.indicesPitch = 4;
\r
2087 VertexCache.primitiveHasVertex = 4;
\r
2089 case scene::EPT_POLYGON:
\r
2090 VertexCache.indexCount = primitiveCount + 1;
\r
2091 VertexCache.indicesPitch = 1;
\r
2092 VertexCache.primitiveHasVertex = primitiveCount;
\r
2094 case scene::EPT_POINT_SPRITES:
\r
2095 VertexCache.indexCount = primitiveCount;
\r
2096 VertexCache.indicesPitch = 1;
\r
2097 VertexCache.primitiveHasVertex = 1;
\r
2101 //memset( VertexCache.info, VERTEXCACHE_MISS, sizeof ( VertexCache.info ) );
\r
2102 for (size_t i = 0; i != VERTEXCACHE_ELEMENT; ++i)
\r
2104 VertexCache.info[i].hit = VERTEXCACHE_MISS;
\r
2105 VertexCache.info[i].index = VERTEXCACHE_MISS;
\r
2111 //! draws a vertex primitive list
\r
2112 void CBurningVideoDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount,
\r
2113 const void* indexList, u32 primitiveCount,
\r
2114 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
\r
2117 if (!checkPrimitiveCount(primitiveCount))
\r
2120 CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);
\r
2122 if (VertexCache_reset(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType))
\r
2125 if ((u32)Material.org.MaterialType < MaterialRenderers.size())
\r
2127 MaterialRenderers[Material.org.MaterialType].Renderer->OnRender(this, vType);
\r
2130 //Matrices needed for this primitive
\r
2131 transform_calc(ETS_PROJ_MODEL_VIEW);
\r
2132 if (Material.org.Lighting || (EyeSpace.TL_Flag & (TL_TEXTURE_TRANSFORM | TL_FOG)))
\r
2134 transform_calc(ETS_MODEL_VIEW);
\r
2135 transform_calc(ETS_NORMAL);
\r
2139 s4DVertexPair* face[4];
\r
2142 size_t vertex_from_clipper; // from VertexCache or CurrentOut
\r
2143 size_t has_vertex_run;
\r
2145 for (size_t primitive_run = 0; primitive_run < primitiveCount; ++primitive_run)
\r
2147 //collect pointer to face vertices
\r
2148 VertexCache_get(face);
\r
2150 size_t clipMask_i;
\r
2151 size_t clipMask_o;
\r
2153 clipMask_i = face[0]->flag;
\r
2154 clipMask_o = face[0]->flag;
\r
2156 for (has_vertex_run = 1; has_vertex_run < VertexCache.primitiveHasVertex; ++has_vertex_run)
\r
2158 clipMask_i |= face[has_vertex_run]->flag; // if fully outside or outside on same side
\r
2159 clipMask_o &= face[has_vertex_run]->flag; // if fully inside
\r
2162 clipMask_i &= VERTEX4D_CLIPMASK;
\r
2163 clipMask_o &= VERTEX4D_CLIPMASK;
\r
2165 if (clipMask_i != VERTEX4D_INSIDE)
\r
2167 // if primitive fully outside or outside on same side
\r
2170 vertex_from_clipper = 0;
\r
2172 else if (clipMask_o == VERTEX4D_INSIDE)
\r
2174 // if primitive fully inside
\r
2175 vOut = VertexCache.primitiveHasVertex;
\r
2176 vertex_from_clipper = 0;
\r
2179 #if defined(SOFTWARE_DRIVER_2_CLIPPING)
\r
2181 // else if not complete inside clipping necessary
\r
2182 // check: clipping should reuse vertexcache (try to minimize clipping)
\r
2183 for (has_vertex_run = 0; has_vertex_run < VertexCache.primitiveHasVertex; ++has_vertex_run)
\r
2185 memcpy_s4DVertexPair(Clipper.data + s4DVertex_ofs(has_vertex_run), face[has_vertex_run]);
\r
2188 vOut = clipToFrustum(VertexCache.primitiveHasVertex);
\r
2189 vertex_from_clipper = 1;
\r
2191 // to DC Space, project homogenous vertex
\r
2192 ndc_2_dc_and_project(Clipper.data + s4DVertex_proj(0), Clipper.data + s4DVertex_ofs(0), s4DVertex_ofs(vOut));
\r
2198 vertex_from_clipper = 0;
\r
2201 // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. )
\r
2202 for (has_vertex_run = 0; (has_vertex_run + VertexCache.primitiveHasVertex) <= vOut; has_vertex_run += 1)
\r
2204 // set from clipped geometry
\r
2205 if (vertex_from_clipper)
\r
2207 face[0] = Clipper.data + s4DVertex_ofs(0);
\r
2208 face[1] = Clipper.data + s4DVertex_ofs(has_vertex_run + 1);
\r
2209 face[2] = Clipper.data + s4DVertex_ofs(has_vertex_run + 2);
\r
2212 //area of primitive in device space
\r
2213 // projected triangle screen area is used for culling ( sign of normal ) and mipmap selection
\r
2214 //f32 dc_area = screenarea_inside(face);
\r
2216 // crossproduct (area of parallelogram * 0.5 = triangle screen size)
\r
2219 const sVec4& v0 = (face[0] + s4DVertex_proj(0))->Pos;
\r
2220 const sVec4& v1 = (face[1] + s4DVertex_proj(0))->Pos;
\r
2221 const sVec4& v2 = (face[2] + s4DVertex_proj(0))->Pos;
\r
2223 //dc_area = a.x * b.y - b.x * a.y;
\r
2224 dc_area = ((v1.x - v0.x) * (v2.y - v0.y) - (v2.x - v0.x) * (v1.y - v0.y)) * 0.5f;
\r
2227 //geometric clipping has problem with invisible or very small Triangles
\r
2228 //size_t sign = dc_area < 0.001f ? CULL_BACK : dc_area > 0.001f ? CULL_FRONT : CULL_INVISIBLE;
\r
2231 size_t sign = t.fields.sign ? CULL_BACK : CULL_FRONT;
\r
2232 sign |= t.abs.frac_exp < 981668463 /*0.01f*/ ? CULL_INVISIBLE : 0;
\r
2233 if (Material.CullFlag & sign)
\r
2234 break; //continue;
\r
2236 //select mipmap ratio between drawing space and texture space (for multiply divide here)
\r
2237 dc_area = reciprocal_zero(dc_area);
\r
2240 for (size_t m = 0; m < VertexCache.vSize[VertexCache.vType].TexSize; ++m)
\r
2242 video::CSoftwareTexture2* tex = MAT_TEXTURE(m);
\r
2244 //only guessing: take more detail (lower mipmap) in light+bump textures
\r
2245 f32 lod_bias = 0.100f;// core::clamp(map_value((f32)ScreenSize.Width * ScreenSize.Height, 160 * 120, 640 * 480, 1.f / 8.f, 1.f / 8.f), 0.01f, 1.f);
\r
2247 //assume transparent add is ~50% transparent -> more detail
\r
2248 switch (Material.org.MaterialType)
\r
2250 case EMT_TRANSPARENT_ADD_COLOR:
\r
2251 case EMT_TRANSPARENT_ALPHA_CHANNEL:
\r
2257 lod_bias *= tex->get_lod_bias();
\r
2258 //lod_bias += Material.org.TextureLayer[m].LODBias * 0.125f;
\r
2260 s32 lodFactor = lodFactor_inside(face, m, dc_area, lod_bias);
\r
2262 CurrentShader->setTextureParam(m, tex, lodFactor);
\r
2263 //currently shader receives texture coordinate as Pixelcoo of 1 Texture
\r
2264 select_polygon_mipmap_inside(face, m, tex->getTexBound());
\r
2267 CurrentShader->drawWireFrameTriangle(face[0] + s4DVertex_proj(0), face[1] + s4DVertex_proj(0), face[2] + s4DVertex_proj(0));
\r
2268 vertex_from_clipper = 1;
\r
2274 for (size_t m = 0; m < VertexCache.vSize[VertexCache.vType].TexSize; ++m)
\r
2276 CurrentShader->setTextureParam(m, 0, 0);
\r
2282 //! Sets the dynamic ambient light color. The default color is
\r
2283 //! (0,0,0,0) which means it is dark.
\r
2284 //! \param color: New color of the ambient light.
\r
2285 void CBurningVideoDriver::setAmbientLight(const SColorf& color)
\r
2287 EyeSpace.Global_AmbientLight.setColorf(color);
\r
2291 //! adds a dynamic light
\r
2292 s32 CBurningVideoDriver::addDynamicLight(const SLight& dl)
\r
2294 (void)CNullDriver::addDynamicLight(dl);
\r
2296 SBurningShaderLight l;
\r
2299 l.LightIsOn = true;
\r
2301 l.AmbientColor.setColorf(dl.AmbientColor);
\r
2302 l.DiffuseColor.setColorf(dl.DiffuseColor);
\r
2303 l.SpecularColor.setColorf(dl.SpecularColor);
\r
2305 //should always be valid?
\r
2307 nDirection.x = dl.Direction.X;
\r
2308 nDirection.y = dl.Direction.Y;
\r
2309 nDirection.z = dl.Direction.Z;
\r
2310 nDirection.normalize_dir_xyz();
\r
2315 case ELT_DIRECTIONAL:
\r
2316 l.pos.x = dl.Position.X;
\r
2317 l.pos.y = dl.Position.Y;
\r
2318 l.pos.z = dl.Position.Z;
\r
2321 l.constantAttenuation = 1.f;
\r
2322 l.linearAttenuation = 0.f;
\r
2323 l.quadraticAttenuation = 0.f;
\r
2325 l.spotDirection.x = -nDirection.x;
\r
2326 l.spotDirection.y = -nDirection.y;
\r
2327 l.spotDirection.z = -nDirection.z;
\r
2328 l.spotDirection.w = 0.f;
\r
2329 l.spotCosCutoff = -1.f;
\r
2330 l.spotCosInnerCutoff = 1.f;
\r
2331 l.spotExponent = 0.f;
\r
2335 l.pos.x = dl.Position.X;
\r
2336 l.pos.y = dl.Position.Y;
\r
2337 l.pos.z = dl.Position.Z;
\r
2340 l.constantAttenuation = dl.Attenuation.X;
\r
2341 l.linearAttenuation = dl.Attenuation.Y;
\r
2342 l.quadraticAttenuation = dl.Attenuation.Z;
\r
2344 l.spotDirection.x = -nDirection.x;
\r
2345 l.spotDirection.y = -nDirection.y;
\r
2346 l.spotDirection.z = -nDirection.z;
\r
2347 l.spotDirection.w = 0.f;
\r
2348 l.spotCosCutoff = -1.f;
\r
2349 l.spotCosInnerCutoff = 1.f;
\r
2350 l.spotExponent = 0.f;
\r
2354 l.pos.x = dl.Position.X;
\r
2355 l.pos.y = dl.Position.Y;
\r
2356 l.pos.z = dl.Position.Z;
\r
2359 l.constantAttenuation = dl.Attenuation.X;
\r
2360 l.linearAttenuation = dl.Attenuation.Y;
\r
2361 l.quadraticAttenuation = dl.Attenuation.Z;
\r
2363 l.spotDirection.x = nDirection.x;
\r
2364 l.spotDirection.y = nDirection.y;
\r
2365 l.spotDirection.z = nDirection.z;
\r
2366 l.spotDirection.w = 0.0f;
\r
2367 l.spotCosCutoff = cosf(dl.OuterCone * 2.0f * core::DEGTORAD * 0.5f);
\r
2368 l.spotCosInnerCutoff = cosf(dl.InnerCone * 2.0f * core::DEGTORAD * 0.5f);
\r
2369 l.spotExponent = dl.Falloff;
\r
2375 //which means ETS_VIEW
\r
2376 setTransform(ETS_WORLD, irr::core::IdentityMatrix);
\r
2377 transform_calc(ETS_MODEL_VIEW);
\r
2379 const core::matrix4* matrix = Transformation[TransformationStack];
\r
2380 transformVec4Vec4(matrix[ETS_MODEL_VIEW], &l.pos4.x, &l.pos.x);
\r
2381 rotateVec3Vec4(matrix[ETS_MODEL_VIEW], &l.spotDirection4.x, &l.spotDirection.x);
\r
2383 EyeSpace.Light.push_back(l);
\r
2384 return EyeSpace.Light.size() - 1;
\r
2388 //! Turns a dynamic light on or off
\r
2389 void CBurningVideoDriver::turnLightOn(s32 lightIndex, bool turnOn)
\r
2391 if ((u32)lightIndex < EyeSpace.Light.size())
\r
2393 EyeSpace.Light[lightIndex].LightIsOn = turnOn;
\r
2397 //! deletes all dynamic lights there are
\r
2398 void CBurningVideoDriver::deleteAllDynamicLights()
\r
2401 CNullDriver::deleteAllDynamicLights();
\r
2405 //! returns the maximal amount of dynamic lights the device can handle
\r
2406 u32 CBurningVideoDriver::getMaximalDynamicLightAmount() const
\r
2408 return 8; //no limit 8 only for convenience
\r
2412 //! sets a material
\r
2413 void CBurningVideoDriver::setMaterial(const SMaterial& material)
\r
2415 // ---------- Override
\r
2416 Material.org = material;
\r
2417 OverrideMaterial.apply(Material.org);
\r
2419 const SMaterial& in = Material.org;
\r
2421 // ---------- Notify Shader
\r
2422 // unset old material
\r
2424 mi = (u32)Material.lastMaterial.MaterialType;
\r
2425 if (mi != material.MaterialType && mi < MaterialRenderers.size())
\r
2426 MaterialRenderers[mi].Renderer->OnUnsetMaterial();
\r
2428 // set new material.
\r
2429 mi = (u32)in.MaterialType;
\r
2430 if (mi < MaterialRenderers.size())
\r
2431 MaterialRenderers[mi].Renderer->OnSetMaterial(
\r
2432 in, Material.lastMaterial, Material.resetRenderStates, this);
\r
2434 Material.lastMaterial = in;
\r
2435 Material.resetRenderStates = false;
\r
2437 //CSoftware2MaterialRenderer sets Material.Fallback_MaterialType
\r
2439 //Material.Fallback_MaterialType = material.MaterialType;
\r
2441 //-----------------
\r
2443 //Material.org = material;
\r
2444 Material.CullFlag = CULL_INVISIBLE | (in.BackfaceCulling ? CULL_BACK : 0) | (in.FrontfaceCulling ? CULL_FRONT : 0);
\r
2446 size_t* flag = TransformationFlag[TransformationStack];
\r
2448 #ifdef SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM
\r
2449 for (u32 m = 0; m < BURNING_MATERIAL_MAX_TEXTURES /*&& m < vSize[VertexCache.vType].TexSize*/; ++m)
\r
2451 setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + m), in.getTextureMatrix(m));
\r
2452 flag[ETS_TEXTURE_0 + m] &= ~ETF_TEXGEN_MASK;
\r
2456 #ifdef SOFTWARE_DRIVER_2_LIGHTING
\r
2458 Material.AmbientColor.setA8R8G8B8(in.AmbientColor.color);
\r
2459 Material.DiffuseColor.setA8R8G8B8(in.ColorMaterial ? 0xFFFFFFFF : in.DiffuseColor.color);
\r
2460 Material.EmissiveColor.setA8R8G8B8(in.EmissiveColor.color);
\r
2461 Material.SpecularColor.setA8R8G8B8(in.SpecularColor.color);
\r
2463 burning_setbit(EyeSpace.TL_Flag, in.Lighting, TL_LIGHT);
\r
2464 burning_setbit(EyeSpace.TL_Flag, (in.Shininess != 0.f) && (in.SpecularColor.color & 0x00ffffff), TL_SPECULAR);
\r
2465 burning_setbit(EyeSpace.TL_Flag, in.FogEnable, TL_FOG);
\r
2466 burning_setbit(EyeSpace.TL_Flag, in.NormalizeNormals, TL_NORMALIZE_NORMALS);
\r
2467 //if (EyeSpace.Flags & SPECULAR ) EyeSpace.Flags |= NORMALIZE_NORMALS;
\r
2471 //--------------- setCurrentShader
\r
2473 ITexture* texture0 = in.getTexture(0);
\r
2474 ITexture* texture1 = in.getTexture(1);
\r
2475 //ITexture* texture2 = in.getTexture(2);
\r
2476 //ITexture* texture3 = in.getTexture(3);
\r
2478 //visual studio code analysis
\r
2479 u32 maxTex = BURNING_MATERIAL_MAX_TEXTURES;
\r
2480 if (maxTex < 1) texture0 = 0;
\r
2481 if (maxTex < 2) texture1 = 0;
\r
2482 //if (maxTex < 3) texture2 = 0;
\r
2483 //if (maxTex < 4) texture3 = 0;
\r
2485 EyeSpace.TL_Flag &= ~(TL_TEXTURE_TRANSFORM | TL_LIGHT0_IS_NORMAL_MAP);
\r
2487 //todo: seperate depth test from depth write
\r
2488 Material.depth_write = getWriteZBuffer(in);
\r
2489 Material.depth_test = in.ZBuffer != ECFN_DISABLED && Material.depth_write;
\r
2491 EBurningFFShader shader = Material.depth_test ? ETR_TEXTURE_GOURAUD : ETR_TEXTURE_GOURAUD_NOZ;
\r
2493 switch (Material.Fallback_MaterialType) //(Material.org.MaterialType)
\r
2495 case EMT_ONETEXTURE_BLEND:
\r
2496 shader = ETR_TEXTURE_BLEND;
\r
2499 case EMT_TRANSPARENT_ALPHA_CHANNEL_REF:
\r
2500 Material.org.MaterialTypeParam = 0.5f;
\r
2503 case EMT_TRANSPARENT_ALPHA_CHANNEL:
\r
2504 if (texture0 && texture0->hasAlpha())
\r
2506 shader = Material.depth_test ? ETR_TEXTURE_GOURAUD_ALPHA : ETR_TEXTURE_GOURAUD_ALPHA_NOZ;
\r
2510 //fall back to EMT_TRANSPARENT_VERTEX_ALPHA
\r
2511 shader = ETR_TEXTURE_GOURAUD_VERTEX_ALPHA;
\r
2515 case EMT_TRANSPARENT_ADD_COLOR:
\r
2516 shader = Material.depth_test ? ETR_TEXTURE_GOURAUD_ADD : ETR_TEXTURE_GOURAUD_ADD_NO_Z;
\r
2519 case EMT_TRANSPARENT_VERTEX_ALPHA:
\r
2520 shader = ETR_TEXTURE_GOURAUD_VERTEX_ALPHA;
\r
2523 case EMT_LIGHTMAP:
\r
2524 case EMT_LIGHTMAP_LIGHTING:
\r
2526 shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1;
\r
2529 case EMT_LIGHTMAP_M2:
\r
2530 case EMT_LIGHTMAP_LIGHTING_M2:
\r
2532 shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M2;
\r
2535 case EMT_LIGHTMAP_LIGHTING_M4:
\r
2537 shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M4;
\r
2539 case EMT_LIGHTMAP_M4:
\r
2541 shader = ETR_TEXTURE_LIGHTMAP_M4;
\r
2544 case EMT_LIGHTMAP_ADD:
\r
2546 shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD;
\r
2549 case EMT_DETAIL_MAP:
\r
2551 shader = ETR_TEXTURE_GOURAUD_DETAIL_MAP;
\r
2554 case EMT_SPHERE_MAP:
\r
2555 flag[ETS_TEXTURE_0] |= ETF_TEXGEN_CAMERA_SPHERE;
\r
2556 EyeSpace.TL_Flag |= TL_TEXTURE_TRANSFORM;
\r
2558 case EMT_REFLECTION_2_LAYER:
\r
2559 case EMT_TRANSPARENT_REFLECTION_2_LAYER:
\r
2562 shader = ETR_TRANSPARENT_REFLECTION_2_LAYER;
\r
2563 flag[ETS_TEXTURE_1] |= ETF_TEXGEN_CAMERA_REFLECTION;
\r
2564 EyeSpace.TL_Flag |= TL_TEXTURE_TRANSFORM;
\r
2568 case EMT_NORMAL_MAP_SOLID:
\r
2569 case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR:
\r
2570 case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA:
\r
2573 shader = ETR_NORMAL_MAP_SOLID;
\r
2574 EyeSpace.TL_Flag |= TL_TEXTURE_TRANSFORM | TL_LIGHT0_IS_NORMAL_MAP;
\r
2577 case EMT_PARALLAX_MAP_SOLID:
\r
2578 case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR:
\r
2579 case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA:
\r
2582 shader = ETR_NORMAL_MAP_SOLID;
\r
2583 EyeSpace.TL_Flag |= TL_TEXTURE_TRANSFORM | TL_LIGHT0_IS_NORMAL_MAP;
\r
2594 shader = Material.depth_test ? ETR_GOURAUD :
\r
2595 shader == ETR_TEXTURE_GOURAUD_VERTEX_ALPHA ?
\r
2596 ETR_GOURAUD_ALPHA_NOZ : // 2D Gradient
\r
2599 shader = ETR_COLOR;
\r
2604 IBurningShader* candidate = BurningShader[shader];
\r
2605 if (!candidate || (candidate && !candidate->canWireFrame()))
\r
2607 shader = ETR_TEXTURE_GOURAUD_WIRE;
\r
2611 if (in.PointCloud)
\r
2613 IBurningShader* candidate = BurningShader[shader];
\r
2614 if (!candidate || (candidate && !candidate->canPointCloud()))
\r
2616 shader = ETR_TEXTURE_GOURAUD_WIRE;
\r
2620 //shader = ETR_REFERENCE;
\r
2622 // switchToTriangleRenderer
\r
2623 CurrentShader = BurningShader[shader];
\r
2624 if (CurrentShader)
\r
2626 CurrentShader->setTLFlag(EyeSpace.TL_Flag);
\r
2627 if (EyeSpace.TL_Flag & TL_FOG) CurrentShader->setFog(FogColor);
\r
2628 if (EyeSpace.TL_Flag & TL_SCISSOR) CurrentShader->setScissor(Scissor);
\r
2629 CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort, Interlaced);
\r
2630 CurrentShader->OnSetMaterial(Material);
\r
2631 CurrentShader->pushEdgeTest(in.Wireframe, in.PointCloud, 0);
\r
2636 mi = (u32)Material.org.MaterialType;
\r
2637 if (mi < MaterialRenderers.size())
\r
2638 MaterialRenderers[mi].Renderer->OnRender(this, (video::E_VERTEX_TYPE)VertexCache.vType);
\r
2643 //! Sets the fog mode.
\r
2644 void CBurningVideoDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start,
\r
2645 f32 end, f32 density, bool pixelFog, bool rangeFog)
\r
2647 CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog);
\r
2649 EyeSpace.fog_scale = reciprocal_zero(FogEnd - FogStart);
\r
2654 #if defined(SOFTWARE_DRIVER_2_LIGHTING) && BURNING_MATERIAL_MAX_COLORS > 0
\r
2658 applies lighting model
\r
2660 void CBurningVideoDriver::lightVertex_eye(s4DVertex* dest, u32 vertexargb)
\r
2662 //gl_FrontLightModelProduct.sceneColor = gl_FrontMaterial.emission + gl_FrontMaterial.ambient * gl_LightModel.ambient
\r
2664 sVec3Color ambient;
\r
2665 sVec3Color diffuse;
\r
2666 sVec3Color specular;
\r
2669 // the universe started in darkness..
\r
2670 ambient = EyeSpace.Global_AmbientLight;
\r
2672 specular.set(0.f);
\r
2679 sVec4 vp; // unit vector vertex to light
\r
2680 sVec4 lightHalf; // blinn-phong reflection
\r
2682 f32 spotDot; // cos of angle between spotlight and point on surface
\r
2684 for (i = 0; i < EyeSpace.Light.size(); ++i)
\r
2686 const SBurningShaderLight& light = EyeSpace.Light[i];
\r
2687 if (!light.LightIsOn)
\r
2690 switch (light.Type)
\r
2692 case ELT_DIRECTIONAL:
\r
2694 //angle between normal and light vector
\r
2695 dot = EyeSpace.normal.dot_xyz(light.spotDirection4);
\r
2697 // accumulate ambient
\r
2698 ambient.add_rgb(light.AmbientColor);
\r
2700 // diffuse component
\r
2702 diffuse.mad_rgb(light.DiffuseColor, dot);
\r
2706 // surface to light
\r
2707 vp.x = light.pos4.x - EyeSpace.vertex.x;
\r
2708 vp.y = light.pos4.y - EyeSpace.vertex.y;
\r
2709 vp.z = light.pos4.z - EyeSpace.vertex.z;
\r
2711 distance = vp.length_xyz();
\r
2713 attenuation = light.constantAttenuation
\r
2714 + light.linearAttenuation * distance
\r
2715 + light.quadraticAttenuation * (distance * distance);
\r
2716 attenuation = reciprocal_one(attenuation);
\r
2718 //att = clamp(1.0 - dist/radius, 0.0, 1.0); att *= att
\r
2720 // accumulate ambient
\r
2721 ambient.mad_rgb(light.AmbientColor, attenuation);
\r
2723 // build diffuse reflection
\r
2725 //angle between normal and light vector
\r
2726 vp.mul_xyz(reciprocal_zero(distance)); //normalize
\r
2727 dot = EyeSpace.normal.dot_xyz(vp);
\r
2728 if (dot <= 0.f) continue;
\r
2730 // diffuse component
\r
2731 diffuse.mad_rgb(light.DiffuseColor, dot * attenuation);
\r
2733 if (!(EyeSpace.TL_Flag & TL_SPECULAR))
\r
2736 lightHalf.x = vp.x + 0.f; // EyeSpace.cam_eye_pos.x;
\r
2737 lightHalf.y = vp.y + 0.f; // EyeSpace.cam_eye_pos.y;
\r
2738 lightHalf.z = vp.z - 1.f; // EyeSpace.cam_eye_pos.z;
\r
2739 lightHalf.normalize_dir_xyz();
\r
2741 //specular += light.SpecularColor * pow(max(dot(Eyespace.normal,lighthalf),0,Material.org.Shininess)*attenuation
\r
2742 specular.mad_rgb(light.SpecularColor,
\r
2743 powf_limit(EyeSpace.normal.dot_xyz(lightHalf), Material.org.Shininess) * attenuation
\r
2748 // surface to light
\r
2749 vp.x = light.pos4.x - EyeSpace.vertex.x;
\r
2750 vp.y = light.pos4.y - EyeSpace.vertex.y;
\r
2751 vp.z = light.pos4.z - EyeSpace.vertex.z;
\r
2753 distance = vp.length_xyz();
\r
2756 vp.mul_xyz(reciprocal_zero(distance));
\r
2758 // point on surface inside cone of illumination
\r
2759 spotDot = vp.dot_minus_xyz(light.spotDirection4);
\r
2760 if (spotDot < light.spotCosCutoff)
\r
2763 attenuation = light.constantAttenuation
\r
2764 + light.linearAttenuation * distance
\r
2765 + light.quadraticAttenuation * distance * distance;
\r
2766 attenuation = reciprocal_one(attenuation);
\r
2767 attenuation *= powf_limit(spotDot, light.spotExponent);
\r
2769 // accumulate ambient
\r
2770 ambient.mad_rgb(light.AmbientColor, attenuation);
\r
2773 // build diffuse reflection
\r
2774 //angle between normal and light vector
\r
2775 dot = EyeSpace.normal.dot_xyz(vp);
\r
2776 if (dot < 0.f) continue;
\r
2778 // diffuse component
\r
2779 diffuse.mad_rgb(light.DiffuseColor, dot * attenuation);
\r
2781 if (!(EyeSpace.TL_Flag & TL_SPECULAR))
\r
2784 lightHalf.x = vp.x + 0.f; // EyeSpace.cam_eye_pos.x;
\r
2785 lightHalf.y = vp.y + 0.f; // EyeSpace.cam_eye_pos.y;
\r
2786 lightHalf.z = vp.z - 1.f; // EyeSpace.cam_eye_pos.z;
\r
2787 lightHalf.normalize_dir_xyz();
\r
2789 //specular += light.SpecularColor * pow(max(dot(Eyespace.normal,lighthalf),0,Material.org.Shininess)*attenuation
\r
2790 specular.mad_rgb(light.SpecularColor,
\r
2791 powf_limit(EyeSpace.normal.dot_xyz(lightHalf), Material.org.Shininess) * attenuation
\r
2802 sVec3Color dColor;
\r
2804 dColor.mad_rgbv(diffuse, Material.DiffuseColor);
\r
2806 //diffuse * vertex color.
\r
2807 //has to move to shader (for vertex color only this will fit [except clamping])
\r
2810 c.setA8R8G8B8(vertexargb);
\r
2815 //separate specular
\r
2816 #if defined(SOFTWARE_DRIVER_2_USE_SEPARATE_SPECULAR_COLOR)
\r
2817 if ((VertexCache.vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_COLOR_2_FOG))
\r
2819 specular.sat_xyz(dest->Color[1], Material.SpecularColor);
\r
2822 if (!(EyeSpace.TL_Flag & TL_LIGHT0_IS_NORMAL_MAP) &&
\r
2823 (VertexCache.vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_MASK_LIGHT)
\r
2826 specular.sat_xyz(dest->LightTangent[0], Material.SpecularColor);
\r
2831 dColor.mad_rgbv(specular, Material.SpecularColor);
\r
2835 dColor.mad_rgbv(ambient, Material.AmbientColor);
\r
2836 dColor.add_rgb(Material.EmissiveColor);
\r
2839 dColor.sat(dest->Color[0], vertexargb);
\r
2845 CImage* getImage(const video::ITexture* texture)
\r
2847 if (!texture) return 0;
\r
2850 switch (texture->getDriverType())
\r
2852 case EDT_BURNINGSVIDEO:
\r
2853 img = ((CSoftwareTexture2*)texture)->getImage();
\r
2855 case EDT_SOFTWARE:
\r
2856 img = ((CSoftwareTexture*)texture)->getImage();
\r
2859 os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR);
\r
2866 draw2DImage with single color scales into destination quad & cliprect(more like viewport)
\r
2867 draw2DImage with 4 color scales on destination and cliprect is scissor
\r
2870 static const u16 quad_triangle_indexList[6] = { 0,1,2,0,2,3 };
\r
2873 #if defined(SOFTWARE_DRIVER_2_2D_AS_2D)
\r
2875 //! 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.
\r
2876 void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
\r
2877 const core::rect<s32>& sourceRect,
\r
2878 const core::rect<s32>* clipRect, SColor color,
\r
2879 bool useAlphaChannelOfTexture)
\r
2883 if (texture->getOriginalSize() != texture->getSize())
\r
2885 core::rect<s32> destRect(destPos, sourceRect.getSize());
\r
2886 SColor c4[4] = { color,color,color,color };
\r
2887 draw2DImage(texture, destRect, sourceRect, clipRect, c4, useAlphaChannelOfTexture);
\r
2891 if (texture->getDriverType() != EDT_BURNINGSVIDEO)
\r
2893 os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR);
\r
2897 if (useAlphaChannelOfTexture)
\r
2898 ((CSoftwareTexture2*)texture)->getImage()->copyToWithAlpha(
\r
2899 RenderTargetSurface, destPos, sourceRect, color, clipRect);
\r
2901 ((CSoftwareTexture2*)texture)->getImage()->copyTo(
\r
2902 RenderTargetSurface, destPos, sourceRect, clipRect);
\r
2907 //! Draws a part of the texture into the rectangle.
\r
2908 void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
\r
2909 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
\r
2910 const video::SColor* const colors, bool useAlphaChannelOfTexture)
\r
2914 if (texture->getDriverType() != EDT_BURNINGSVIDEO)
\r
2916 os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR);
\r
2920 u32 argb = (colors ? colors[0].color : 0xFFFFFFFF);
\r
2921 eBlitter op = useAlphaChannelOfTexture ?
\r
2922 (argb == 0xFFFFFFFF ? BLITTER_TEXTURE_ALPHA_BLEND : BLITTER_TEXTURE_ALPHA_COLOR_BLEND) : BLITTER_TEXTURE;
\r
2924 StretchBlit(op, RenderTargetSurface, clipRect, &destRect,
\r
2925 ((CSoftwareTexture2*)texture)->getImage(), &sourceRect, &texture->getOriginalSize(), argb);
\r
2930 //!Draws an 2d rectangle with a gradient.
\r
2931 void CBurningVideoDriver::draw2DRectangle(const core::rect<s32>& position,
\r
2932 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
\r
2933 const core::rect<s32>* clip)
\r
2935 core::rect<s32> p(position);
\r
2936 if (clip) p.clipAgainst(*clip);
\r
2937 if (p.isValid()) drawRectangle(RenderTargetSurface, p, colorLeftUp);
\r
2940 #endif //defined(SOFTWARE_DRIVER_2_2D_AS_2D)
\r
2944 //! Enable the 2d override material
\r
2945 void CBurningVideoDriver::enableMaterial2D(bool enable)
\r
2947 CNullDriver::enableMaterial2D(enable);
\r
2948 burning_setbit(TransformationFlag[1][ETS_PROJECTION], 0, ETF_VALID);
\r
2951 size_t compare_2d_material(const SMaterial& a, const SMaterial& b)
\r
2954 flag |= a.MaterialType == b.MaterialType ? 0 : 1;
\r
2955 flag |= a.ZBuffer == b.ZBuffer ? 0 : 2;
\r
2956 flag |= a.TextureLayer[0].Texture == b.TextureLayer[0].Texture ? 0 : 4;
\r
2957 flag |= a.TextureLayer[0].BilinearFilter == b.TextureLayer[0].BilinearFilter ? 0 : 8;
\r
2958 flag |= a.MaterialTypeParam == b.MaterialTypeParam ? 0 : 16;
\r
2959 if (flag) return flag;
\r
2961 flag |= a.TextureLayer[1].Texture == b.TextureLayer[1].Texture ? 0 : 32;
\r
2962 flag |= a.ZWriteEnable == b.ZWriteEnable ? 0 : 64;
\r
2967 void CBurningVideoDriver::setRenderStates2DMode(const video::SColor& color, const video::ITexture* texture, bool useAlphaChannelOfTexture)
\r
2969 //save current 3D Material
\r
2970 //Material.save3D = Material.org;
\r
2972 //build new 2D Material
\r
2974 bool vertexAlpha = color.getAlpha() < 255;
\r
2976 //2D uses textureAlpa*vertexAlpha 3D not..
\r
2977 if (useAlphaChannelOfTexture && texture && texture->hasAlpha())
\r
2979 Material.mat2D.MaterialType = EMT_TRANSPARENT_ALPHA_CHANNEL;
\r
2981 else if (vertexAlpha)
\r
2983 Material.mat2D.MaterialType = EMT_TRANSPARENT_VERTEX_ALPHA;
\r
2987 Material.mat2D.MaterialType = EMT_SOLID;
\r
2990 Material.mat2D.ZBuffer = ECFN_DISABLED;
\r
2991 Material.mat2D.ZWriteEnable = EZW_OFF;
\r
2992 Material.mat2D.Lighting = false;
\r
2994 Material.mat2D.setTexture(0, (video::ITexture*)texture);
\r
2996 //used for text. so stay as sharp as possible (like HW Driver)
\r
2999 const SMaterial& currentMaterial = (!OverrideMaterial2DEnabled) ? InitMaterial2D : OverrideMaterial2D;
\r
3000 mip = currentMaterial.TextureLayer[0].Texture && currentMaterial.TextureLayer[0].BilinearFilter;
\r
3002 Material.mat2D.setFlag(video::EMF_BILINEAR_FILTER, mip);
\r
3005 //switch to 2D Matrix Stack [ Material set Texture Matrix ]
\r
3006 TransformationStack = 1;
\r
3009 if (!(TransformationFlag[TransformationStack][ETS_PROJECTION] & ETF_VALID))
\r
3011 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
\r
3012 core::matrix4 m(core::matrix4::EM4CONST_NOTHING);
\r
3013 m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f);
\r
3014 m.setTranslation(core::vector3df(-1.f, 1.f, 0));
\r
3015 setTransform(ETS_PROJECTION, m);
\r
3018 setTransform(ETS_WORLD, m);
\r
3021 m.setTranslation(core::vector3df(IRRLICHT_2D_TEXEL_OFFSET, IRRLICHT_2D_TEXEL_OFFSET, 0.0f));
\r
3023 setTransform(ETS_VIEW, m);
\r
3025 //Tweak 2D Pixel Center for openGL compatibility (guessing)
\r
3026 //buildNDCToDCMatrix(Transformation_ETS_CLIPSCALE[TransformationStack], ViewPort, mip ? (IRRLICHT_2D_TEXEL_OFFSET) * 0.5f : 0.f);
\r
3030 if (compare_2d_material(Material.org, Material.mat2D))
\r
3032 setMaterial(Material.mat2D);
\r
3034 if (CurrentShader)
\r
3036 CurrentShader->setPrimitiveColor(color.color);
\r
3037 CurrentShader->setTLFlag(EyeSpace.TL_Flag);
\r
3038 if (EyeSpace.TL_Flag & TL_SCISSOR) CurrentShader->setScissor(Scissor);
\r
3043 void CBurningVideoDriver::setRenderStates3DMode()
\r
3045 //restoreRenderStates3DMode
\r
3047 //setMaterial(Material.save3D);
\r
3048 //switch to 3D Matrix Stack
\r
3049 TransformationStack = 0;
\r
3052 //! draws a vertex primitive list in 2d
\r
3053 void CBurningVideoDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount,
\r
3054 const void* indexList, u32 primitiveCount,
\r
3055 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
\r
3057 if (!checkPrimitiveCount(primitiveCount))
\r
3060 CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);
\r
3062 bool useAlphaChannelOfTexture = false;
\r
3063 video::SColor color(0xFFFFFFFF);
\r
3064 switch (Material.org.MaterialType)
\r
3066 case EMT_TRANSPARENT_ALPHA_CHANNEL:
\r
3067 useAlphaChannelOfTexture = true;
\r
3069 case EMT_TRANSPARENT_VERTEX_ALPHA:
\r
3070 color.setAlpha(127);
\r
3075 setRenderStates2DMode(color, Material.org.getTexture(0), useAlphaChannelOfTexture);
\r
3077 drawVertexPrimitiveList(vertices, vertexCount,
\r
3078 indexList, primitiveCount,
\r
3079 vType, pType, iType);
\r
3081 setRenderStates3DMode();
\r
3086 #if defined(SOFTWARE_DRIVER_2_2D_AS_3D)
\r
3088 //! 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.
\r
3089 void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
\r
3090 const core::rect<s32>& sourceRect,
\r
3091 const core::rect<s32>* clipRect, SColor color,
\r
3092 bool useAlphaChannelOfTexture)
\r
3097 if (!sourceRect.isValid())
\r
3100 // clip these coordinates
\r
3101 core::rect<s32> targetRect(destPos, sourceRect.getSize());
\r
3104 targetRect.clipAgainst(*clipRect);
\r
3105 if (targetRect.getWidth() < 0 || targetRect.getHeight() < 0)
\r
3109 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
\r
3110 targetRect.clipAgainst(core::rect<s32>(0, 0, (s32)renderTargetSize.Width, (s32)renderTargetSize.Height));
\r
3111 if (targetRect.getWidth() < 0 || targetRect.getHeight() < 0)
\r
3114 // ok, we've clipped everything.
\r
3116 const core::dimension2d<s32> sourceSize(targetRect.getSize());
\r
3117 const core::position2d<s32> sourcePos(sourceRect.UpperLeftCorner + (targetRect.UpperLeftCorner - destPos));
\r
3119 const core::dimension2d<u32>& tex_orgsize = texture->getOriginalSize();
\r
3120 const f32 invW = 1.f / static_cast<f32>(tex_orgsize.Width);
\r
3121 const f32 invH = 1.f / static_cast<f32>(tex_orgsize.Height);
\r
3122 const core::rect<f32> tcoords(
\r
3123 sourcePos.X * invW,
\r
3124 sourcePos.Y * invH,
\r
3125 (sourcePos.X + sourceSize.Width) * invW,
\r
3126 (sourcePos.Y + sourceSize.Height) * invH);
\r
3129 Quad2DVertices[0].Color = color;
\r
3130 Quad2DVertices[1].Color = color;
\r
3131 Quad2DVertices[2].Color = color;
\r
3132 Quad2DVertices[3].Color = color;
\r
3134 Quad2DVertices[0].Pos = core::vector3df((f32)targetRect.UpperLeftCorner.X, (f32)targetRect.UpperLeftCorner.Y, 0.0f);
\r
3135 Quad2DVertices[1].Pos = core::vector3df((f32)targetRect.LowerRightCorner.X, (f32)targetRect.UpperLeftCorner.Y, 0.0f);
\r
3136 Quad2DVertices[2].Pos = core::vector3df((f32)targetRect.LowerRightCorner.X, (f32)targetRect.LowerRightCorner.Y, 0.0f);
\r
3137 Quad2DVertices[3].Pos = core::vector3df((f32)targetRect.UpperLeftCorner.X, (f32)targetRect.LowerRightCorner.Y, 0.0f);
\r
3139 Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
\r
3140 Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
\r
3141 Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
\r
3142 Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
\r
3144 setRenderStates2DMode(color, texture, useAlphaChannelOfTexture);
\r
3146 drawVertexPrimitiveList(Quad2DVertices, 4,
\r
3147 quad_triangle_indexList, 2,
\r
3148 EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);
\r
3150 setRenderStates3DMode();
\r
3155 //! Draws a part of the texture into the rectangle.
\r
3156 void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
\r
3157 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
\r
3158 const video::SColor* const colors, bool useAlphaChannelOfTexture)
\r
3160 const core::dimension2d<u32>& st = texture->getOriginalSize();
\r
3161 const f32 invW = 1.f / static_cast<f32>(st.Width);
\r
3162 const f32 invH = 1.f / static_cast<f32>(st.Height);
\r
3163 const core::rect<f32> tcoords(
\r
3164 sourceRect.UpperLeftCorner.X * invW,
\r
3165 sourceRect.UpperLeftCorner.Y * invH,
\r
3166 sourceRect.LowerRightCorner.X * invW,
\r
3167 sourceRect.LowerRightCorner.Y * invH);
\r
3169 const video::SColor temp[4] =
\r
3177 const video::SColor* const useColor = colors ? colors : temp;
\r
3180 Quad2DVertices[0].Color = useColor[0];
\r
3181 Quad2DVertices[1].Color = useColor[3];
\r
3182 Quad2DVertices[2].Color = useColor[2];
\r
3183 Quad2DVertices[3].Color = useColor[1];
\r
3185 Quad2DVertices[0].Pos = core::vector3df((f32)destRect.UpperLeftCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f);
\r
3186 Quad2DVertices[1].Pos = core::vector3df((f32)destRect.LowerRightCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f);
\r
3187 Quad2DVertices[2].Pos = core::vector3df((f32)destRect.LowerRightCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f);
\r
3188 Quad2DVertices[3].Pos = core::vector3df((f32)destRect.UpperLeftCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f);
\r
3190 Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
\r
3191 Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
\r
3192 Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
\r
3193 Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
\r
3198 if (!clipRect->isValid())
\r
3201 //glEnable(GL_SCISSOR_TEST);
\r
3202 EyeSpace.TL_Flag |= TL_SCISSOR;
\r
3203 setScissor(clipRect->UpperLeftCorner.X, clipRect->UpperLeftCorner.Y,//renderTargetSize.Height - clipRect->LowerRightCorner.Y
\r
3204 clipRect->getWidth(), clipRect->getHeight());
\r
3207 video::SColor alphaTest;
\r
3208 alphaTest.color = useColor[0].color & useColor[0].color & useColor[0].color & useColor[0].color;
\r
3211 setRenderStates2DMode(alphaTest,texture, useAlphaChannelOfTexture);
\r
3213 drawVertexPrimitiveList(Quad2DVertices, 4,
\r
3214 quad_triangle_indexList, 2,
\r
3215 EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);
\r
3218 EyeSpace.TL_Flag &= ~TL_SCISSOR;
\r
3220 setRenderStates3DMode();
\r
3225 //!Draws an 2d rectangle with a gradient.
\r
3226 void CBurningVideoDriver::draw2DRectangle(const core::rect<s32>& position,
\r
3227 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
\r
3228 const core::rect<s32>* clip)
\r
3230 core::rect<s32> pos = position;
\r
3233 pos.clipAgainst(*clip);
\r
3235 if (!pos.isValid())
\r
3238 Quad2DVertices[0].Color = colorLeftUp;
\r
3239 Quad2DVertices[1].Color = colorRightUp;
\r
3240 Quad2DVertices[2].Color = colorRightDown;
\r
3241 Quad2DVertices[3].Color = colorLeftDown;
\r
3243 Quad2DVertices[0].Pos = core::vector3df((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f);
\r
3244 Quad2DVertices[1].Pos = core::vector3df((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f);
\r
3245 Quad2DVertices[2].Pos = core::vector3df((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f);
\r
3246 Quad2DVertices[3].Pos = core::vector3df((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f);
\r
3248 Quad2DVertices[0].TCoords.X = 0.f;
\r
3249 Quad2DVertices[0].TCoords.Y = 0.f;
\r
3250 Quad2DVertices[1].TCoords.X = 0.f;
\r
3251 Quad2DVertices[1].TCoords.Y = 0.f;
\r
3252 Quad2DVertices[2].TCoords.X = 0.f;
\r
3253 Quad2DVertices[3].TCoords.Y = 0.f;
\r
3254 Quad2DVertices[3].TCoords.X = 0.f;
\r
3255 Quad2DVertices[3].TCoords.Y = 0.f;
\r
3258 video::SColor alphaTest;
\r
3259 alphaTest.color = colorLeftUp.color & colorRightUp.color & colorRightDown.color & colorLeftDown.color;
\r
3260 setRenderStates2DMode(alphaTest, 0, 0);
\r
3262 drawVertexPrimitiveList(Quad2DVertices, 4,
\r
3263 quad_triangle_indexList, 2,
\r
3264 EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);
\r
3266 setRenderStates3DMode();
\r
3271 #endif // SOFTWARE_DRIVER_2_2D_AS_3D
\r
3277 //! Draws a 2d line.
\r
3278 void CBurningVideoDriver::draw2DLine(const core::position2d<s32>& start,
\r
3279 const core::position2d<s32>& end,
\r
3282 drawLine(RenderTargetSurface, start, end, color);
\r
3287 void CBurningVideoDriver::drawPixel(u32 x, u32 y, const SColor& color)
\r
3289 RenderTargetSurface->setPixel(x, y, color, true);
\r
3293 //! Only used by the internal engine. Used to notify the driver that
\r
3294 //! the window was resized.
\r
3295 void CBurningVideoDriver::OnResize(const core::dimension2d<u32>& size)
\r
3297 // make sure width and height are multiples of 2
\r
3298 core::dimension2d<u32> realSize(size);
\r
3300 if (realSize.Width % 2)
\r
3301 realSize.Width += 1;
\r
3303 if (realSize.Height % 2)
\r
3304 realSize.Height += 1;
\r
3306 if (ScreenSize != realSize)
\r
3308 if (ViewPort.getWidth() == (s32)ScreenSize.Width &&
\r
3309 ViewPort.getHeight() == (s32)ScreenSize.Height)
\r
3311 ViewPort.UpperLeftCorner.X = 0;
\r
3312 ViewPort.UpperLeftCorner.Y = 0;
\r
3313 ViewPort.LowerRightCorner.X = realSize.Width;
\r
3314 ViewPort.LowerRightCorner.X = realSize.Height;
\r
3317 ScreenSize = realSize;
\r
3319 bool resetRT = (RenderTargetSurface == BackBuffer);
\r
3322 BackBuffer->drop();
\r
3323 BackBuffer = new CImage(SOFTWARE_DRIVER_2_RENDERTARGET_COLOR_FORMAT, realSize);
\r
3326 setRenderTargetImage2(BackBuffer);
\r
3331 //! returns the current render target size
\r
3332 const core::dimension2d<u32>& CBurningVideoDriver::getCurrentRenderTargetSize() const
\r
3334 return (RenderTargetSurface == BackBuffer) ? ScreenSize : RenderTargetSize;
\r
3339 //! Draws a 3d line.
\r
3340 void CBurningVideoDriver::draw3DLine(const core::vector3df& start,
\r
3341 const core::vector3df& end, SColor color_start)
\r
3343 SColor color_end = color_start;
\r
3345 VertexCache.primitiveHasVertex = 2;
\r
3346 VertexCache.vType = E4VT_LINE;
\r
3348 s4DVertex* v = Clipper.data;
\r
3350 transform_calc(ETS_PROJ_MODEL_VIEW);
\r
3351 const core::matrix4* matrix = Transformation[TransformationStack];
\r
3352 matrix[ETS_PROJ_MODEL_VIEW].transformVect(&v[s4DVertex_ofs(0)].Pos.x, start);
\r
3353 matrix[ETS_PROJ_MODEL_VIEW].transformVect(&v[s4DVertex_ofs(1)].Pos.x, end);
\r
3355 #if BURNING_MATERIAL_MAX_COLORS > 0
\r
3356 v[s4DVertex_ofs(0)].Color[0].setA8R8G8B8(color_start.color);
\r
3357 v[s4DVertex_ofs(1)].Color[0].setA8R8G8B8(color_end.color);
\r
3360 size_t has_vertex_run;
\r
3361 for (has_vertex_run = 0; has_vertex_run < VertexCache.primitiveHasVertex; has_vertex_run += 1)
\r
3363 v[s4DVertex_ofs(has_vertex_run)].flag = (u32)(VertexCache.vSize[VertexCache.vType].Format);
\r
3364 v[s4DVertex_proj(has_vertex_run)].flag = v[s4DVertex_ofs(has_vertex_run)].flag;
\r
3370 // vertices count per line
\r
3371 vOut = clipToFrustum(VertexCache.primitiveHasVertex);
\r
3372 if (vOut < VertexCache.primitiveHasVertex)
\r
3375 // to DC Space, project homogenous vertex
\r
3376 ndc_2_dc_and_project(v + s4DVertex_proj(0), v+ s4DVertex_ofs(0), s4DVertex_ofs(vOut));
\r
3378 // unproject vertex color
\r
3380 #if BURNING_MATERIAL_MAX_COLORS > 0
\r
3381 for (g = 0; g != vOut; g += 2)
\r
3383 v[g + 1].Color[0].setA8R8G8B8(color.color);
\r
3388 IBurningShader* shader = 0;
\r
3389 if (CurrentShader && CurrentShader->canWireFrame()) shader = CurrentShader;
\r
3390 else shader = BurningShader[ETR_TEXTURE_GOURAUD_WIRE];
\r
3391 shader = BurningShader[ETR_TEXTURE_GOURAUD_WIRE];
\r
3393 shader->pushEdgeTest(1, 0, 1);
\r
3394 shader->setRenderTarget(RenderTargetSurface, ViewPort, Interlaced);
\r
3396 for (has_vertex_run = 0; (has_vertex_run + VertexCache.primitiveHasVertex) <= vOut; has_vertex_run += 1)
\r
3398 shader->drawLine(v + s4DVertex_proj(has_vertex_run), v + s4DVertex_proj(has_vertex_run+1));
\r
3401 shader->popEdgeTest();
\r
3406 //! \return Returns the name of the video driver. Example: In case of the DirectX8
\r
3407 //! driver, it would return "Direct3D8.1".
\r
3408 const wchar_t* CBurningVideoDriver::getName() const
\r
3410 #ifdef BURNINGVIDEO_RENDERER_BEAUTIFUL
\r
3411 return L"Burning's Video 0.52 beautiful";
\r
3412 #elif defined ( BURNINGVIDEO_RENDERER_ULTRA_FAST )
\r
3413 return L"Burning's Video 0.52 ultra fast";
\r
3414 #elif defined ( BURNINGVIDEO_RENDERER_FAST )
\r
3415 return L"Burning's Video 0.52 fast";
\r
3416 #elif defined ( BURNINGVIDEO_RENDERER_CE )
\r
3417 return L"Burning's Video 0.52 CE";
\r
3419 return L"Burning's Video 0.52";
\r
3423 //! Returns the graphics card vendor name.
\r
3424 core::stringc CBurningVideoDriver::getVendorInfo()
\r
3426 return "Burning's Video: Ing. Thomas Alten (c) 2006-2020";
\r
3430 //! Returns type of video driver
\r
3431 E_DRIVER_TYPE CBurningVideoDriver::getDriverType() const
\r
3433 return EDT_BURNINGSVIDEO;
\r
3437 //! returns color format
\r
3438 ECOLOR_FORMAT CBurningVideoDriver::getColorFormat() const
\r
3440 return BackBuffer ? BackBuffer->getColorFormat() : CNullDriver::getColorFormat();
\r
3444 //! Creates a render target texture.
\r
3445 ITexture* CBurningVideoDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
\r
3446 const io::path& name, const ECOLOR_FORMAT format
\r
3447 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
\r
3448 , const bool useStencil
\r
3452 //IImage* img = createImage(SOFTWARE_DRIVER_2_RENDERTARGET_COLOR_FORMAT, size);
\r
3453 //empty proxy image
\r
3454 IImage* img = createImageFromData(format, size, 0, true, false);
\r
3455 ITexture* tex = new CSoftwareTexture2(img, name, CSoftwareTexture2::IS_RENDERTARGET /*| CSoftwareTexture2::GEN_MIPMAP */, this);
\r
3456 if ( img ) img->drop();
\r
3462 void CBurningVideoDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)
\r
3464 if ((flag & ECBF_COLOR) && RenderTargetSurface) image_fill(RenderTargetSurface, color, Interlaced);
\r
3465 if ((flag & ECBF_DEPTH) && DepthBuffer) DepthBuffer->clear(depth, Interlaced);
\r
3466 if ((flag & ECBF_STENCIL) && StencilBuffer) StencilBuffer->clear(stencil, Interlaced);
\r
3470 void CBurningVideoDriver::saveBuffer()
\r
3472 static int shotCount = 0;
\r
3476 sprintf(buf, "shot/%04d_b.png", shotCount);
\r
3477 writeImageToFile(BackBuffer, buf);
\r
3479 if (StencilBuffer)
\r
3481 CImage stencil(ECF_A8R8G8B8, StencilBuffer->getSize(), StencilBuffer->lock(), true, false);
\r
3482 sprintf(buf, "shot/%04d_s.ppm", shotCount);
\r
3483 writeImageToFile(&stencil, buf);
\r
3489 //! Returns an image created from the last rendered frame.
\r
3490 IImage* CBurningVideoDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
\r
3492 if (target != video::ERT_FRAME_BUFFER)
\r
3497 IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension());
\r
3498 BackBuffer->copyTo(tmp);
\r
3505 ITexture* CBurningVideoDriver::createDeviceDependentTexture(const io::path& name, IImage* image)
\r
3508 ((TextureCreationFlags & ETCF_CREATE_MIP_MAPS) ? CSoftwareTexture2::GEN_MIPMAP : 0)
\r
3509 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
\r
3510 | CSoftwareTexture2::GEN_MIPMAP_AUTO
\r
3512 | ((TextureCreationFlags & ETCF_AUTO_GENERATE_MIP_MAPS) ? CSoftwareTexture2::GEN_MIPMAP_AUTO : 0)
\r
3514 | ((TextureCreationFlags & ETCF_ALLOW_NON_POWER_2) ? CSoftwareTexture2::ALLOW_NPOT : 0)
\r
3515 #if defined(IRRLICHT_sRGB)
\r
3516 | ((TextureCreationFlags & ETCF_IMAGE_IS_LINEAR) ? CSoftwareTexture2::IMAGE_IS_LINEAR : 0)
\r
3517 | ((TextureCreationFlags & ETCF_TEXTURE_IS_LINEAR) ? CSoftwareTexture2::TEXTURE_IS_LINEAR : 0)
\r
3521 CSoftwareTexture2* texture = new CSoftwareTexture2(image, name, flags, this);
\r
3525 ITexture* CBurningVideoDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)
\r
3530 //! Returns the maximum amount of primitives (mostly vertices) which
\r
3531 //! the device is able to render with one drawIndexedTriangleList
\r
3533 u32 CBurningVideoDriver::getMaximalPrimitiveCount() const
\r
3535 return 0x7FFFFFFF;
\r
3539 //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do
\r
3540 //! this: First, draw all geometry. Then use this method, to draw the shadow
\r
3541 //! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow.
\r
3542 void CBurningVideoDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)
\r
3544 const u32 count = triangles.size();
\r
3545 if (!StencilBuffer || !count)
\r
3548 Material.org.MaterialType = video::EMT_SOLID;
\r
3549 Material.org.Lighting = false;
\r
3550 Material.org.ZWriteEnable = video::EZW_OFF;
\r
3551 Material.org.ZBuffer = ECFN_LESS;
\r
3553 CurrentShader = BurningShader[ETR_STENCIL_SHADOW];
\r
3555 CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort, Interlaced);
\r
3556 CurrentShader->pushEdgeTest(Material.org.Wireframe, 0, 0);
\r
3559 EyeSpace.TL_Flag &= ~(TL_TEXTURE_TRANSFORM | TL_LIGHT0_IS_NORMAL_MAP);
\r
3560 CurrentShader->setTLFlag(EyeSpace.TL_Flag);
\r
3561 //glStencilMask(~0);
\r
3562 //glStencilFunc(GL_ALWAYS, 0, ~0);
\r
3564 //glEnable(GL_DEPTH_CLAMP);
\r
3568 Material.org.BackfaceCulling = false;
\r
3569 Material.org.FrontfaceCulling = true;
\r
3570 Material.CullFlag = CULL_FRONT | CULL_INVISIBLE;
\r
3572 CurrentShader->setStencilOp(StencilOp_KEEP, StencilOp_INCR, StencilOp_KEEP);
\r
3573 drawVertexPrimitiveList(triangles.const_pointer(), count, 0, count / 3, (video::E_VERTEX_TYPE) E4VT_SHADOW, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) E4IT_NONE);
\r
3575 Material.org.BackfaceCulling = true;
\r
3576 Material.org.FrontfaceCulling = false;
\r
3577 Material.CullFlag = CULL_BACK | CULL_INVISIBLE;
\r
3579 CurrentShader->setStencilOp(StencilOp_KEEP, StencilOp_DECR, StencilOp_KEEP);
\r
3580 drawVertexPrimitiveList(triangles.const_pointer(), count, 0, count / 3, (video::E_VERTEX_TYPE) E4VT_SHADOW, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) E4IT_NONE);
\r
3584 Material.org.BackfaceCulling = true;
\r
3585 Material.org.FrontfaceCulling = false;
\r
3586 Material.CullFlag = CULL_BACK | CULL_INVISIBLE;
\r
3588 CurrentShader->setStencilOp(StencilOp_KEEP, StencilOp_KEEP, StencilOp_INCR);
\r
3589 drawVertexPrimitiveList(triangles.const_pointer(), count, 0, count / 3, (video::E_VERTEX_TYPE) E4VT_SHADOW, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) E4IT_NONE);
\r
3591 Material.org.BackfaceCulling = false;
\r
3592 Material.org.FrontfaceCulling = true;
\r
3593 Material.CullFlag = CULL_FRONT | CULL_INVISIBLE;
\r
3595 CurrentShader->setStencilOp(StencilOp_KEEP, StencilOp_KEEP, StencilOp_DECR);
\r
3596 drawVertexPrimitiveList(triangles.const_pointer(), count, 0, count / 3, (video::E_VERTEX_TYPE) E4VT_SHADOW, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) E4IT_NONE);
\r
3598 //glDisable(GL_DEPTH_CLAMP);
\r
3602 //! Fills the stencil shadow with color. After the shadow volume has been drawn
\r
3603 //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this
\r
3604 //! to draw the color of the shadow.
\r
3605 void CBurningVideoDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge,
\r
3606 video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge)
\r
3608 if (!StencilBuffer)
\r
3611 // draw a shadow rectangle covering the entire screen using stencil buffer
\r
3612 const u32 h = RenderTargetSurface->getDimension().Height;
\r
3613 const u32 w = RenderTargetSurface->getDimension().Width;
\r
3615 const bool bit32 = RenderTargetSurface->getColorFormat() == ECF_A8R8G8B8;
\r
3616 const tVideoSample alpha = extractAlpha(leftUpEdge.color) >> (bit32 ? 0 : 3);
\r
3617 const tVideoSample src = bit32 ? leftUpEdge.color : video::A8R8G8B8toA1R5G5B5(leftUpEdge.color);
\r
3619 interlace_scanline_data line;
\r
3620 for (line.y = 0; line.y < h; line.y += SOFTWARE_DRIVER_2_STEP_Y)
\r
3622 interlace_scanline
\r
3624 tVideoSample * dst = (tVideoSample*)RenderTargetSurface->getData() + (line.y * w);
\r
3625 const tStencilSample* stencil = (tStencilSample*)StencilBuffer->lock() + (line.y * w);
\r
3629 for (u32 x = 0; x < w; x += SOFTWARE_DRIVER_2_STEP_X)
\r
3631 if (stencil[x]) dst[x] = PixelBlend32(dst[x], src, alpha);
\r
3636 for (u32 x = 0; x < w; x += SOFTWARE_DRIVER_2_STEP_X)
\r
3638 if (stencil[x]) dst[x] = PixelBlend16(dst[x], src, alpha);
\r
3645 if (clearStencilBuffer)
\r
3646 StencilBuffer->clear(0, Interlaced);
\r
3650 core::dimension2du CBurningVideoDriver::getMaxTextureSize() const
\r
3652 return core::dimension2du(SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE, SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE);
\r
3655 bool CBurningVideoDriver::queryTextureFormat(ECOLOR_FORMAT format) const
\r
3657 return format == SOFTWARE_DRIVER_2_RENDERTARGET_COLOR_FORMAT || format == SOFTWARE_DRIVER_2_TEXTURE_COLOR_FORMAT;
\r
3660 #if !defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
\r
3661 bool CBurningVideoDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const
\r
3663 return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation(); // || material.isTransparent();
\r
3667 s32 CBurningVideoDriver::addShaderMaterial(const c8* vertexShaderProgram,
\r
3668 const c8* pixelShaderProgram,
\r
3669 IShaderConstantSetCallBack* callback,
\r
3670 E_MATERIAL_TYPE baseMaterial,
\r
3673 s32 materialID = -1;
\r
3675 IBurningShader* shader = new IBurningShader(
\r
3677 vertexShaderProgram, 0, video::EVST_VS_1_1,
\r
3678 pixelShaderProgram, 0, video::EPST_PS_1_1,
\r
3679 0, 0, EGST_GS_4_0,
\r
3680 scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0,
\r
3681 callback, baseMaterial, userData);
\r
3685 return materialID;
\r
3688 //! Adds a new material renderer to the VideoDriver, based on a high level shading language.
\r
3689 s32 CBurningVideoDriver::addHighLevelShaderMaterial(
\r
3690 const c8* vertexShaderProgram,
\r
3691 const c8* vertexShaderEntryPointName,
\r
3692 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
3693 const c8* pixelShaderProgram,
\r
3694 const c8* pixelShaderEntryPointName,
\r
3695 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
3696 const c8* geometryShaderProgram,
\r
3697 const c8* geometryShaderEntryPointName,
\r
3698 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
3699 scene::E_PRIMITIVE_TYPE inType,
\r
3700 scene::E_PRIMITIVE_TYPE outType,
\r
3702 IShaderConstantSetCallBack* callback,
\r
3703 E_MATERIAL_TYPE baseMaterial,
\r
3705 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
\r
3706 , E_GPU_SHADING_LANGUAGE shadingLang
\r
3710 s32 materialID = -1;
\r
3712 IBurningShader* shader = new IBurningShader(
\r
3714 vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget,
\r
3715 pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget,
\r
3716 geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget,
\r
3717 inType, outType, verticesOut,
\r
3718 callback, baseMaterial, userData);
\r
3722 return materialID;
\r
3726 void CBurningVideoDriver::setFallback_Material(E_MATERIAL_TYPE fallback_MaterialType)
\r
3728 //this should be in material....
\r
3729 Material.Fallback_MaterialType = fallback_MaterialType;
\r
3732 void CBurningVideoDriver::setBasicRenderStates(const SMaterial& material,
\r
3733 const SMaterial& lastMaterial,
\r
3734 bool resetAllRenderstates)
\r
3739 //! Return an index constant for the vertex shader based on a name.
\r
3740 s32 CBurningVideoDriver::getVertexShaderConstantID(const c8* name)
\r
3745 bool CBurningVideoDriver::setVertexShaderConstant(s32 index, const f32* floats, int count)
\r
3750 bool CBurningVideoDriver::setVertexShaderConstant(s32 index, const s32* ints, int count)
\r
3755 bool CBurningVideoDriver::setVertexShaderConstant(s32 index, const u32* ints, int count)
\r
3760 void CBurningVideoDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
3764 //! Return an index constant for the pixel shader based on a name.
\r
3765 s32 CBurningVideoDriver::getPixelShaderConstantID(const c8* name)
\r
3770 bool CBurningVideoDriver::setPixelShaderConstant(s32 index, const f32* floats, int count)
\r
3775 bool CBurningVideoDriver::setPixelShaderConstant(s32 index, const s32* ints, int count)
\r
3780 bool CBurningVideoDriver::setPixelShaderConstant(s32 index, const u32* ints, int count)
\r
3785 void CBurningVideoDriver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount = 1)
\r
3789 //! Get pointer to the IVideoDriver interface
\r
3790 /** \return Pointer to the IVideoDriver interface */
\r
3791 IVideoDriver* CBurningVideoDriver::getVideoDriver()
\r
3796 } // end namespace video
\r
3797 } // end namespace irr
\r
3799 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
3807 //! creates a video driver
\r
3808 IVideoDriver* createBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter)
\r
3810 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
3811 return new CBurningVideoDriver(params, io, presenter);
\r
3814 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
3819 } // end namespace video
\r
3820 } // end namespace irr
\r