]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CSoftwareDriver2.cpp
Merging r6186 through r6192 from trunk to ogl-es branch
[irrlicht.git] / source / Irrlicht / CSoftwareDriver2.cpp
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
4 \r
5 #include "IrrCompileConfig.h"\r
6 #include "CSoftwareDriver2.h"\r
7 \r
8 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_\r
9 \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
16 #include "CBlit.h"\r
17 \r
18 \r
19 // Matrix now here\r
20 \r
21 template <class T>\r
22 bool mat44_transposed_inverse(irr::core::CMatrix4<T>& out, const irr::core::CMatrix4<T>& M)\r
23 {\r
24         const T* burning_restrict m = M.pointer();\r
25 \r
26         double d =\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
33 \r
34         if (fabs(d) < DBL_MIN)\r
35         {\r
36                 out.makeIdentity();\r
37                 return false;\r
38         }\r
39 \r
40         d = 1.0 / d;\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
46 \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
51 \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
56 \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
61 \r
62         return true;\r
63 }\r
64 \r
65 #if 0\r
66 // difference to CMatrix4<T>::getInverse . higher precision in determinant. return identity on failure\r
67 template <class T>\r
68 bool mat44_inverse(CMatrix4<T>& out, const CMatrix4<T>& M)\r
69 {\r
70         const T* m = M.pointer();\r
71 \r
72         double d =\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
79 \r
80         if (fabs(d) < DBL_MIN)\r
81         {\r
82                 out.makeIdentity();\r
83                 return false;\r
84         }\r
85 \r
86         d = 1.0 / d;\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
92 \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
97 \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
102 \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
107 \r
108         return true;\r
109 }\r
110 #endif\r
111 \r
112 // void CMatrix4<T>::transformVec4(T *out, const T * in) const\r
113 template <class T>\r
114 inline void transformVec4Vec4(const irr::core::CMatrix4<T>& m, T* burning_restrict out, const T* burning_restrict in)\r
115 {\r
116         const T* burning_restrict M = m.pointer();\r
117 \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
122 }\r
123 \r
124 #if 0\r
125 // void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const\r
126 template <class T>\r
127 inline void transformVec3Vec4(const irr::core::CMatrix4<T>& m, T* burning_restrict out, const core::vector3df& in)\r
128 {\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
134 }\r
135 #endif\r
136 \r
137 template <class T>\r
138 inline void rotateVec3Vec4(const irr::core::CMatrix4<T>& m, T* burning_restrict out, const T* burning_restrict in)\r
139 {\r
140         const T* burning_restrict M = m.pointer();\r
141 \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
145         out[3] = 0.f;\r
146 }\r
147 \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
150 {\r
151         if (a <= 0.0000001f) return 0.f;\r
152         else if (a >= 1.f) return 1.f;\r
153 \r
154         /* calculate approximation with fraction of the exponent */\r
155         int e = (int)b;\r
156         union { float f; int x; } u = { a };\r
157         u.x = (int)((b - e) * (u.x - 1065353216) + 1065353216);\r
158 \r
159         float r = 1.0f;\r
160         float ua = a;\r
161         while (e) {\r
162                 if (e & 1) {\r
163                         r *= ua;\r
164                 }\r
165                 if (ua < 0.00000001f)\r
166                         break;\r
167                 ua *= ua;\r
168                 e >>= 1;\r
169         }\r
170 \r
171         r *= u.f;\r
172         return r;\r
173 }\r
174 \r
175 //! clamp(value,0,1)\r
176 static inline const float clampf01(const float v)\r
177 {\r
178         return v < 0.f ? 0.f : v > 1.f ? 1.f : v;\r
179 }\r
180 \r
181 // IImage::fill\r
182 static void image_fill(irr::video::IImage* image, const irr::video::SColor& color, const interlaced_control interlaced)\r
183 {\r
184         if (0 == image)\r
185                 return;\r
186 \r
187         unsigned int c = color.color;\r
188 \r
189         switch (image->getColorFormat())\r
190         {\r
191         case irr::video::ECF_A1R5G5B5:\r
192                 c = color.toA1R5G5B5();\r
193                 c |= c << 16;\r
194                 break;\r
195         default:\r
196                 break;\r
197         }\r
198         irr::memset32_interlaced(image->getData(), c, image->getPitch(), image->getDimension().Height, interlaced);\r
199 }\r
200 \r
201 \r
202 union scale_setup\r
203 {\r
204         struct\r
205         {\r
206                 unsigned char x : 3;\r
207                 unsigned char y : 3;\r
208                 unsigned char i : 2;\r
209         };\r
210         unsigned char v;\r
211 };\r
212 \r
213 //setup Antialias. v0.52 uses as Interlaced\r
214 void get_scale(scale_setup& s, const irr::SIrrlichtCreationParameters& params)\r
215 {\r
216         s.x = 1;\r
217         s.y = 1;\r
218         s.i = 0;\r
219         if (params.AntiAlias && params.WindowSize.Width <= 160 && params.WindowSize.Height <= 120)\r
220         {\r
221                 return;\r
222         }\r
223 \r
224         switch (params.AntiAlias)\r
225         {\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
231 \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
234         }\r
235 }\r
236 \r
237 //turn on/off fpu exception\r
238 void fpu_exception(int on)\r
239 {\r
240         return;\r
241 #if defined(_WIN32)\r
242         _clearfp();\r
243         _controlfp(on ? _EM_INEXACT : -1, _MCW_EM);\r
244 #endif\r
245 }\r
246 \r
247 namespace irr\r
248 {\r
249 namespace video\r
250 {\r
251 \r
252 //! constructor\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
258 {\r
259         //enable fpu exception\r
260         fpu_exception(1);\r
261 \r
262 #ifdef _DEBUG\r
263         setDebugName("CBurningVideoDriver");\r
264 #endif\r
265 \r
266         VertexCache_map_source_format();\r
267 \r
268         //Use AntiAlias(hack) to shrink BackBuffer Size and keep ScreenSize the same as Input\r
269         scale_setup scale;\r
270         get_scale(scale, params);\r
271 \r
272         //Control Interlaced BackBuffer\r
273         Interlaced.enable = scale.i;\r
274         Interlaced.bypass = !Interlaced.enable;\r
275         Interlaced.nr = 0;\r
276 \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
280         if (BackBuffer)\r
281         {\r
282                 //BackBuffer->fill(SColor(0));\r
283                 image_fill(BackBuffer, SColor(0), interlace_disabled());\r
284 \r
285                 // create z buffer\r
286                 if (params.ZBufferBits)\r
287                         DepthBuffer = video::createDepthBuffer(BackBuffer->getDimension());\r
288 \r
289                 // create stencil buffer\r
290                 if (params.Stencilbuffer)\r
291                         StencilBuffer = video::createStencilBuffer(BackBuffer->getDimension(), 8);\r
292         }\r
293 \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
300 \r
301         // create triangle renderers\r
302 \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
320 \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
326 \r
327         BurningShader[ETR_TEXTURE_GOURAUD_ALPHA] = createTRTextureGouraudAlpha(this);\r
328         BurningShader[ETR_TEXTURE_GOURAUD_ALPHA_NOZ] = createTRTextureGouraudAlphaNoZ(this);\r
329 \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
333 \r
334         BurningShader[ETR_TRANSPARENT_REFLECTION_2_LAYER] = createTriangleRendererTexture_transparent_reflection_2_layer(this);\r
335         //BurningShader[ETR_REFERENCE] = createTriangleRendererReference ( this );\r
336 \r
337         BurningShader[ETR_COLOR] = create_burning_shader_color(this);\r
338 \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
343 \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
369 \r
370         smr->drop();\r
371         tmr->drop();\r
372         //umr->drop ();\r
373 \r
374         // select render target\r
375         setRenderTargetImage2(BackBuffer,0, 0);\r
376 \r
377         //reset Lightspace\r
378         EyeSpace.reset();\r
379         EyeSpace.resetFog();\r
380 \r
381         // select the right renderer\r
382         setMaterial(Material.org);\r
383 }\r
384 \r
385 \r
386 //! destructor\r
387 CBurningVideoDriver::~CBurningVideoDriver()\r
388 {\r
389         // delete Backbuffer\r
390         if (BackBuffer)\r
391         {\r
392                 BackBuffer->drop();\r
393                 BackBuffer = 0;\r
394         }\r
395 \r
396         // delete triangle renderers\r
397         for (s32 i = 0; i < ETR2_COUNT; ++i)\r
398         {\r
399                 if (BurningShader[i])\r
400                 {\r
401                         BurningShader[i]->drop();\r
402                         BurningShader[i] = 0;\r
403                 }\r
404         }\r
405 \r
406         // delete Additional buffer\r
407         if (StencilBuffer)\r
408         {\r
409                 StencilBuffer->drop();\r
410                 StencilBuffer = 0;\r
411         }\r
412 \r
413         if (DepthBuffer)\r
414         {\r
415                 DepthBuffer->drop();\r
416                 DepthBuffer = 0;\r
417         }\r
418 \r
419         if (RenderTargetTexture)\r
420         {\r
421                 RenderTargetTexture->drop();\r
422                 RenderTargetTexture = 0;\r
423         }\r
424 \r
425         if (RenderTargetSurface)\r
426         {\r
427                 RenderTargetSurface->drop();\r
428                 RenderTargetSurface = 0;\r
429         }\r
430 \r
431         fpu_exception(0);\r
432 \r
433 }\r
434 \r
435 \r
436 \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
439 {\r
440         int on = 0;\r
441         switch (feature)\r
442         {\r
443 #ifdef SOFTWARE_DRIVER_2_BILINEAR\r
444         case EVDF_BILINEAR_FILTER:\r
445                 on = 1;\r
446                 break;\r
447 #endif\r
448 #if SOFTWARE_DRIVER_2_MIPMAPPING_MAX > 1\r
449         case EVDF_MIP_MAP:\r
450                 on = 1;\r
451                 break;\r
452 #endif\r
453         case EVDF_STENCIL_BUFFER:\r
454                 on = StencilBuffer != 0;\r
455                 break;\r
456 \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
462                 on = 1;\r
463                 break;\r
464 \r
465         case EVDF_DEPTH_CLAMP: // shadow\r
466                 on = 1;\r
467                 break;\r
468 \r
469         case EVDF_ARB_FRAGMENT_PROGRAM_1:\r
470         case EVDF_ARB_VERTEX_PROGRAM_1:\r
471                 on = 1;\r
472                 break;\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
476                 on = 1;\r
477                 break;\r
478 #else\r
479         case EVDF_TEXTURE_NPOT: // for 2D\r
480                 on = 0;\r
481                 break;\r
482 #endif\r
483 \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
487                 on = 1;\r
488                 break;\r
489 #endif\r
490 #endif\r
491         default:\r
492                 on = 0;\r
493                 break;\r
494         }\r
495 \r
496         return on && FeatureEnabled[feature];\r
497 }\r
498 \r
499 \r
500 //matrix multiplication\r
501 void CBurningVideoDriver::transform_calc(E_TRANSFORMATION_STATE_BURNING_VIDEO state)\r
502 {\r
503         size_t* flag = TransformationFlag[TransformationStack];\r
504         if (flag[state] & ETF_VALID) return;\r
505 \r
506         //check\r
507         size_t ok = 0;\r
508         switch (state)\r
509         {\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
513                 break;\r
514         case ETS_VIEW_PROJECTION:\r
515                 ok = flag[ETS_VIEW] & flag[ETS_PROJECTION] & ETF_VALID;\r
516                 break;\r
517         case ETS_MODEL_VIEW:\r
518                 ok = flag[ETS_WORLD] & flag[ETS_VIEW] & ETF_VALID;\r
519                 break;\r
520         case ETS_NORMAL:\r
521                 ok = flag[ETS_MODEL_VIEW] & ETF_VALID;\r
522                 break;\r
523         default:\r
524                 break;\r
525         }\r
526 \r
527         if (!ok)\r
528         {\r
529                 char buf[256];\r
530                 sprintf(buf, "transform_calc not valid for %d\n", state);\r
531                 os::Printer::log(buf, ELL_WARNING);\r
532         }\r
533 \r
534         core::matrix4* matrix = Transformation[TransformationStack];\r
535 \r
536         switch (state)\r
537         {\r
538         case ETS_PROJ_MODEL_VIEW:\r
539                 if (flag[ETS_WORLD] & ETF_IDENTITY)\r
540                 {\r
541                         matrix[state] = matrix[ETS_VIEW_PROJECTION];\r
542                 }\r
543                 else\r
544                 {\r
545                         matrix[state].setbyproduct_nocheck(matrix[ETS_VIEW_PROJECTION], matrix[ETS_WORLD]);\r
546                 }\r
547                 break;\r
548 \r
549         case ETS_VIEW_PROJECTION:\r
550                 matrix[state].setbyproduct_nocheck(matrix[ETS_PROJECTION], matrix[ETS_VIEW]);\r
551                 break;\r
552         case ETS_MODEL_VIEW:\r
553                 if (flag[ETS_WORLD] & ETF_IDENTITY)\r
554                 {\r
555                         matrix[state] = matrix[ETS_VIEW];\r
556                 }\r
557                 else\r
558                 {\r
559                         matrix[state].setbyproduct_nocheck(matrix[ETS_VIEW], matrix[ETS_WORLD]);\r
560                 }\r
561                 break;\r
562         case ETS_NORMAL:\r
563                 mat44_transposed_inverse(matrix[state], matrix[ETS_MODEL_VIEW]);\r
564                 break;\r
565 \r
566         default:\r
567                 break;\r
568         }\r
569         flag[state] |= ETF_VALID;\r
570 }\r
571 \r
572 \r
573 //! sets transformation\r
574 void CBurningVideoDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)\r
575 {\r
576         size_t* flag = TransformationFlag[TransformationStack];\r
577         core::matrix4* matrix = Transformation[TransformationStack];\r
578 \r
579 #if 0\r
580         int changed = 1;\r
581         if (flag[state] & ETF_VALID)\r
582         {\r
583                 changed = memcmp(mat.pointer(), matrix[state].pointer(), sizeof(mat));\r
584         }\r
585         if (changed)\r
586 #endif\r
587         {\r
588                 matrix[state] = mat;\r
589                 flag[state] |= ETF_VALID;\r
590         }\r
591 \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
595 #else\r
596         burning_setbit(flag[state],\r
597                 !memcmp(mat.pointer(), core::IdentityMatrix.pointer(), sizeof(mat)), ETF_IDENTITY\r
598         );\r
599 #endif\r
600 \r
601 #if 0\r
602         if (changed)\r
603 #endif\r
604                 switch (state)\r
605                 {\r
606                 case ETS_PROJECTION:\r
607                         flag[ETS_PROJ_MODEL_VIEW] &= ~ETF_VALID;\r
608                         flag[ETS_VIEW_PROJECTION] &= ~ETF_VALID;\r
609                         break;\r
610                 case ETS_VIEW:\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
615                         break;\r
616                 case ETS_WORLD:\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
620                         break;\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
627 #endif\r
628 #if _IRR_MATERIAL_MAX_TEXTURES_>5\r
629                 case ETS_TEXTURE_5:\r
630 #endif\r
631 #if _IRR_MATERIAL_MAX_TEXTURES_>6\r
632                 case ETS_TEXTURE_6:\r
633 #endif\r
634 #if _IRR_MATERIAL_MAX_TEXTURES_>7\r
635                 case ETS_TEXTURE_7:\r
636 #endif\r
637                         if (0 == (flag[state] & ETF_IDENTITY))\r
638                         {\r
639                                 EyeSpace.TL_Flag |= TL_TEXTURE_TRANSFORM;\r
640                         }\r
641                         break;\r
642                 default:\r
643                         break;\r
644                 }\r
645 \r
646 }\r
647 \r
648 //! Returns the transformation set by setTransform\r
649 const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE state) const\r
650 {\r
651         return Transformation[TransformationStack][state];\r
652 }\r
653 \r
654 \r
655 bool CBurningVideoDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)\r
656 {\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
659 #else\r
660         CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect);\r
661 #endif\r
662 \r
663         Interlaced.nr = (Interlaced.nr + 1) & interlace_control_mask;\r
664         WindowId = videoData.D3D9.HWnd;\r
665         SceneSourceRect = sourceRect;\r
666 \r
667         clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);\r
668 \r
669         //memset ( TransformationFlag, 0, sizeof ( TransformationFlag ) );\r
670         return true;\r
671 }\r
672 \r
673 bool CBurningVideoDriver::endScene()\r
674 {\r
675         CNullDriver::endScene();\r
676 \r
677         return Presenter->present(BackBuffer, WindowId, SceneSourceRect);\r
678 }\r
679 \r
680 \r
681 //! Create render target.\r
682 IRenderTarget* CBurningVideoDriver::addRenderTarget()\r
683 {\r
684         CSoftwareRenderTarget2* renderTarget = new CSoftwareRenderTarget2(this);\r
685         RenderTargets.push_back(renderTarget);\r
686 \r
687         return renderTarget;\r
688 }\r
689 \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
692 {\r
693         CSoftwareRenderTarget2 target(this);\r
694         target.RenderTexture = texture;\r
695         target.TargetType = ERT_RENDER_TEXTURE;\r
696         target.Texture[0] = texture;\r
697 \r
698         if (texture)\r
699                 texture->grab();\r
700 \r
701         u16 flag = 0;\r
702         if (clearBackBuffer) flag |= ECBF_COLOR;\r
703         if (clearZBuffer) flag |= ECBF_DEPTH;\r
704 \r
705         return setRenderTargetEx(texture ? &target : 0, flag, color, 1.f, true);\r
706 }\r
707 #endif\r
708 \r
709 bool CBurningVideoDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)\r
710 {\r
711 #if !defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)\r
712         if (target && target->getDriverType() != EDT_BURNINGSVIDEO)\r
713         {\r
714                 os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR);\r
715                 return false;\r
716         }\r
717 #endif\r
718         if (RenderTargetTexture)\r
719         {\r
720                 //switching from texture to backbuffer\r
721                 if (target == 0)\r
722                 {\r
723                         RenderTargetTexture->regenerateMipMapLevels();\r
724                 }\r
725                 RenderTargetTexture->drop();\r
726         }\r
727 \r
728 #if !defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)\r
729         RenderTargetTexture = target ? target->getTexture()[0] : 0;\r
730 #else\r
731         RenderTargetTexture = target ? ((CSoftwareRenderTarget2*)target)->Texture[0] : 0;\r
732 #endif\r
733 \r
734         if (RenderTargetTexture)\r
735         {\r
736                 RenderTargetTexture->grab();\r
737                 Interlaced.bypass = 1;\r
738                 setRenderTargetImage2(((CSoftwareTexture2*)RenderTargetTexture)->getImage());\r
739         }\r
740         else\r
741         {\r
742                 Interlaced.bypass = !Interlaced.enable;\r
743                 setRenderTargetImage2(BackBuffer);\r
744         }\r
745 \r
746         clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);\r
747 \r
748         return true;\r
749 }\r
750 \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
753 }\r
754 \r
755 //! sets a render target\r
756 void CBurningVideoDriver::setRenderTargetImage2(video::IImage* color, video::IImage* depth, video::IImage* stencil)\r
757 {\r
758         if (RenderTargetSurface)\r
759                 RenderTargetSurface->drop();\r
760 \r
761         core::dimension2d<u32> current = RenderTargetSize;\r
762         RenderTargetSurface = color;\r
763         RenderTargetSize.Width = 0;\r
764         RenderTargetSize.Height = 0;\r
765 \r
766         if (RenderTargetSurface)\r
767         {\r
768                 RenderTargetSurface->grab();\r
769                 RenderTargetSize = RenderTargetSurface->getDimension();\r
770         }\r
771 \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
774 \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
778 \r
779         setViewPort(core::recti(RenderTargetSize));\r
780 \r
781         if (DepthBuffer)\r
782                 DepthBuffer->setSize(RenderTargetSize);\r
783 \r
784         if (StencilBuffer)\r
785                 StencilBuffer->setSize(RenderTargetSize);\r
786 }\r
787 \r
788 \r
789 //--------- Transform from NDC to DC, transform TexCoo ----------------------------------------------\r
790 \r
791 \r
792 //! Blur 2D Image with PixelOffset. (default 0.375f for OpenGL and Burning)\r
793 /** SideEffects:\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
797 */\r
798 #define IRRLICHT_2D_TEXEL_OFFSET 0.f\r
799 \r
800 \r
801 //--------- Transform from NDC to DC ----------------------------------------------\r
802 \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
807 \r
808 void buildNDCToDCMatrix(f32* m, const core::rect<s32>& viewport, f32 tx)\r
809 {\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
812 \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
815 }\r
816 \r
817 \r
818 \r
819 //! sets a viewport\r
820 void CBurningVideoDriver::setViewPort(const core::rect<s32>& area)\r
821 {\r
822         ViewPort = area;\r
823 \r
824         core::rect<s32> rendert(0, 0, RenderTargetSize.Width, RenderTargetSize.Height);\r
825         ViewPort.clipAgainst(rendert);\r
826 \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
829 \r
830         if (CurrentShader)\r
831                 CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort, Interlaced);\r
832 }\r
833 \r
834 void CBurningVideoDriver::setScissor(int x, int y, int width, int height)\r
835 {\r
836         //openGL\r
837         //y = rt.Height - y - height;\r
838 \r
839         //coming from GUI\r
840         AbsRectangle v0;\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
845 \r
846         AbsRectangle v1;\r
847         v1.x0 = 0;\r
848         v1.y0 = 0;\r
849         v1.x1 = RenderTargetSize.Width;\r
850         v1.y1 = RenderTargetSize.Height;\r
851 \r
852         intersect(Scissor, v0, v1);\r
853 }\r
854 \r
855 /*\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
859 \r
860         cam is (0,0,-1)\r
861 */\r
862 \r
863 const sVec4 CBurningVideoDriver::NDCPlane[6 + 2] =\r
864 {\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
871 };\r
872 \r
873 \r
874 /*\r
875         test a vertex if it's inside the standard frustum\r
876 \r
877         this is the generic one..\r
878 \r
879         f32 dotPlane;\r
880         for ( u32 i = 0; i!= 6; ++i )\r
881         {\r
882                 dotPlane = v->Pos.dotProduct ( NDCPlane[i] );\r
883                 burning_setbit32( flag, dotPlane <= 0.f, 1 << i );\r
884         }\r
885 \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
893 \r
894 */\r
895 #ifdef IRRLICHT_FAST_MATH\r
896 \r
897 REALINLINE size_t CBurningVideoDriver::clipToFrustumTest(const s4DVertex* v) const\r
898 {\r
899         size_t flag;\r
900         f32 test[8];\r
901         const f32 w = -v->Pos.w;\r
902 \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
906 \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
913 \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
921 \r
922         /*\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
929         */\r
930         /*\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
937         */\r
938         return flag;\r
939 }\r
940 \r
941 #else\r
942 \r
943 \r
944 REALINLINE size_t clipToFrustumTest(const s4DVertex* v)\r
945 {\r
946         size_t flag = 0;\r
947 \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
950 \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
953 \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
956 \r
957 \r
958         /*\r
959                 for ( u32 i = 0; i <= 6; ++i )\r
960                 {\r
961                         if (v->Pos.dot_xyzw(NDCPlane[i]) <= 0.f) flag |= ((size_t)1) << i;\r
962                 }\r
963         */\r
964         return flag;\r
965 }\r
966 \r
967 #endif // _MSC_VER\r
968 \r
969 \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
974         const sVec4& plane\r
975 )\r
976 {\r
977         size_t outCount = 0;\r
978         s4DVertexPair* out = dest;\r
979 \r
980         const s4DVertex* a;\r
981         const s4DVertex* b = source;\r
982 \r
983         ipoltype bDotPlane;\r
984         bDotPlane = b->Pos.dot_xyzw(plane);\r
985 \r
986         /*\r
987                 for( u32 i = 1; i < inCount + 1; ++i)\r
988                 {\r
989         #if 0\r
990                         a = source + (i%inCount)*2;\r
991         #else\r
992                         const s32 condition = i - inCount;\r
993                         const s32 index = (( ( condition >> 31 ) & ( i ^ condition ) ) ^ condition ) << 1;\r
994                         a = source + index;\r
995         #endif\r
996         */\r
997         //Sutherland\96Hodgman\r
998         for (size_t i = 0; i < inCount; ++i)\r
999         {\r
1000                 a = source + (i == inCount - 1 ? 0 : s4DVertex_ofs(i + 1));\r
1001 \r
1002                 // current point inside\r
1003                 if (ipol_lower_equal_0(a->Pos.dot_xyzw(plane)))\r
1004                 {\r
1005                         // last point outside\r
1006                         if (ipol_greater_0(bDotPlane))\r
1007                         {\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
1011                                 outCount += 1;\r
1012                         }\r
1013 \r
1014                         // copy current to out\r
1015                         //*out = *a;\r
1016                         memcpy_s4DVertexPair(out, a);\r
1017                         b = out;\r
1018 \r
1019                         out += sizeof_s4DVertexPairRel;\r
1020                         outCount += 1;\r
1021                 }\r
1022                 else\r
1023                 {\r
1024                         // current point outside\r
1025                         if (ipol_lower_equal_0(bDotPlane))\r
1026                         {\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
1031                                 outCount += 1;\r
1032                         }\r
1033                         // pointer\r
1034                         b = a;\r
1035                 }\r
1036 \r
1037                 bDotPlane = b->Pos.dot_xyzw(plane);\r
1038         }\r
1039 \r
1040         return outCount;\r
1041 }\r
1042 \r
1043 \r
1044 /*\r
1045         Clip on all planes. Clipper.data\r
1046         clipmask per face\r
1047 */\r
1048 size_t CBurningVideoDriver::clipToFrustum(const size_t vIn /*, const size_t clipmask_for_face*/)\r
1049 {\r
1050         s4DVertexPair* v0 = Clipper.data;\r
1051         s4DVertexPair* v1 = Clipper_temp.data;\r
1052         size_t vOut = vIn;\r
1053 \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
1057         {\r
1058                 v0[g].flag = flag;\r
1059                 v1[g].flag = flag;\r
1060         }\r
1061 \r
1062 #if 0\r
1063         for (size_t i = 0; i < 6; ++i)\r
1064         {\r
1065                 v0 = i & 1 ? Clipper_temp.data : Clipper.data;\r
1066                 v1 = i & 1 ? Clipper.data : Clipper_temp.data;\r
1067 \r
1068                 //clipMask checked outside - always clip all planes\r
1069 #if 0\r
1070                 if (0 == (clipMask & ((size_t)1 << i)))\r
1071                 {\r
1072                         vOut = vIn;\r
1073                         memcpy_s4DVertexPair(v1, v0);\r
1074                 }\r
1075                 else\r
1076 #endif\r
1077                 {\r
1078                         vOut = clipToHyperPlane(v1, v0, vOut, NDCPlane[i]);\r
1079                         if (vOut < vIn) return vOut;\r
1080                 }\r
1081         }\r
1082 #endif\r
1083 \r
1084 \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
1091 \r
1092         return vOut;\r
1093 }\r
1094 \r
1095 /*!\r
1096         Part I:\r
1097         apply Clip Scale matrix\r
1098         From Normalized Device Coordiante ( NDC ) Space to Device Coordinate ( DC ) Space\r
1099 \r
1100         Part II:\r
1101         Project homogeneous vector\r
1102         homogeneous to non-homogenous coordinates ( dividebyW )\r
1103 \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
1106 \r
1107         replace w/w by 1/w\r
1108 */\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
1111 {\r
1112         const f32* dc = Transformation_ETS_CLIPSCALE[TransformationStack];\r
1113 \r
1114         for (size_t g = 0; g != vIn; g += sizeof_s4DVertexPairRel)\r
1115         {\r
1116                 //cache doesn't work anymore?\r
1117                 //if ( dest[g].flag & VERTEX4D_PROJECTED )\r
1118                 //      continue;\r
1119                 //dest[g].flag = source[g].flag | VERTEX4D_PROJECTED;\r
1120 \r
1121                 const f32 iw = reciprocal_zero(source[g].Pos.w);\r
1122 \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
1126 \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
1130 #endif\r
1131                 dest[g].Pos.w = iw;\r
1132 \r
1133                 // Texture Coordinates will be projected after mipmap selection\r
1134                 // satisfy write-combiner\r
1135 #if 1\r
1136 #if BURNING_MATERIAL_MAX_TEXTURES > 0\r
1137                 dest[g].Tex[0] = source[g].Tex[0];\r
1138 #endif\r
1139 #if BURNING_MATERIAL_MAX_TEXTURES > 1\r
1140                 dest[g].Tex[1] = source[g].Tex[1];\r
1141 #endif\r
1142 #if BURNING_MATERIAL_MAX_TEXTURES > 2\r
1143                 dest[g].Tex[2] = source[g].Tex[2];\r
1144 #endif\r
1145 #if BURNING_MATERIAL_MAX_TEXTURES > 3\r
1146                 dest[g].Tex[3] = source[g].Tex[3];\r
1147 #endif\r
1148 \r
1149 #endif\r
1150 \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
1154 #else\r
1155                 dest[g].Color[0] = source[g].Color[0];\r
1156 #endif\r
1157 #endif\r
1158 \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
1162 #else\r
1163                 dest[g].Color[1] = source[g].Color[1];\r
1164 #endif\r
1165 #endif\r
1166 \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
1170 #else\r
1171                 dest[g].Color[2] = source[g].Color[2];\r
1172 #endif\r
1173 #endif\r
1174 \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
1178 #else\r
1179                 dest[g].Color[3] = source[g].Color[3];\r
1180 #endif\r
1181 #endif\r
1182 \r
1183 #if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0\r
1184                 dest[g].LightTangent[0] = source[g].LightTangent[0] * iw;\r
1185 #endif\r
1186 \r
1187         }\r
1188 }\r
1189 \r
1190 \r
1191 \r
1192 #if 0\r
1193 /*!\r
1194         crossproduct in projected 2D, face\r
1195 */\r
1196 REALINLINE f32 CBurningVideoDriver::screenarea_inside(const s4DVertexPair* burning_restrict const face[]) const\r
1197 {\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
1200         /*\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
1205                 }\r
1206         */\r
1207 }\r
1208 \r
1209 \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
1213 \r
1214 f32 MipmapLevel(const sVec2& uv, const sVec2& textureSize)\r
1215 {\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
1220 }\r
1221 #endif\r
1222 \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
1225 \r
1226 /*!\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
1231         Atlas problem\r
1232 */\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
1235 {\r
1236         /*\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
1240         */\r
1241 \r
1242 \r
1243         /*\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
1246         */\r
1247         ieee754 signedArea;\r
1248 \r
1249         ieee754 t[4];\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
1252 \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
1255 \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
1258 \r
1259         //signedArea =\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
1262 \r
1263         //if (signedArea*signedArea <= 0.00000000001f)\r
1264         if (signedArea.fields.exp == 0)\r
1265         {\r
1266                 ieee754 _max;\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
1271 \r
1272                 signedArea.u = _max.fields.exp ? _max.u : ieee754_one;\r
1273 \r
1274                 /*\r
1275                                 //dot,length\r
1276                                 ieee754 v[2];\r
1277                                 v[0].f = t[0] * t[2];\r
1278                                 v[1].f = t[1] * t[3];\r
1279 \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
1283                                 {\r
1284                                         return -1;\r
1285                                 }\r
1286                 */\r
1287         }\r
1288 \r
1289         //only guessing: take more detail (lower mipmap) in light+bump textures\r
1290         //assume transparent add is ~50% transparent -> more detail\r
1291 \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
1295 \r
1296         ieee754 ratio;\r
1297         ratio.f = (signedArea.f * texelspace) * dc_area;\r
1298         ratio.fields.sign = 0;\r
1299 \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
1302 \r
1303 }\r
1304 \r
1305 \r
1306 /*!\r
1307         texcoo in current mipmap dimension (face, already clipped)\r
1308         -> want to help fixpoint\r
1309 */\r
1310 inline void CBurningVideoDriver::select_polygon_mipmap_inside(s4DVertex* burning_restrict face[], const size_t tex, const CSoftwareTexture2_Bound& b) const\r
1311 {\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
1315 \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
1318 \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
1321 #else\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
1324 \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
1327 \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
1330 #endif\r
1331 \r
1332 }\r
1333 \r
1334 \r
1335 // Vertex Cache\r
1336 \r
1337 //! setup Vertex Format\r
1338 void CBurningVideoDriver::VertexCache_map_source_format()\r
1339 {\r
1340         u32 s0 = sizeof(s4DVertex);\r
1341         u32 s1 = sizeof(s4DVertex_proxy);\r
1342 \r
1343         if (s1 <= sizeof_s4DVertex / 2)\r
1344         {\r
1345                 os::Printer::log("BurningVideo vertex format unnecessary to large", ELL_WARNING);\r
1346         }\r
1347 \r
1348         //memcpy_vertex\r
1349         if (s0 != sizeof_s4DVertex || ((sizeof_s4DVertex * sizeof_s4DVertexPairRel) & 31))\r
1350         {\r
1351                 os::Printer::log("BurningVideo vertex format compile problem", ELL_ERROR);\r
1352                 _IRR_DEBUG_BREAK_IF(1);\r
1353         }\r
1354 \r
1355 #if defined(ENV64BIT)\r
1356         if (sizeof(void*) != 8)\r
1357         {\r
1358                 os::Printer::log("BurningVideo pointer should be 8 bytes", ELL_ERROR);\r
1359                 _IRR_DEBUG_BREAK_IF(1);\r
1360         }\r
1361 \r
1362         if (((unsigned long long)Transformation&15) || ((unsigned long long)TransformationFlag & 15))\r
1363         {\r
1364                 os::Printer::log("BurningVideo Matrix Stack not 16 byte aligned", ELL_ERROR);\r
1365                 _IRR_DEBUG_BREAK_IF(1);\r
1366         }\r
1367 #endif\r
1368 \r
1369 \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
1376 \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
1381 \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
1387 \r
1388         // reflection map\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
1393 \r
1394         // shadow\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
1399 \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
1405 \r
1406         //Line\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
1411 \r
1412         size_t size;\r
1413         for (size_t i = 0; i < E4VT_COUNT; ++i)\r
1414         {\r
1415                 size_t& flag = vSize[i].Format;\r
1416 \r
1417 #if !defined(SOFTWARE_DRIVER_2_USE_SEPARATE_SPECULAR_COLOR)\r
1418                 flag &= ~VERTEX4D_FORMAT_SPECULAR;\r
1419 #endif\r
1420                 if (vSize[i].TexSize > BURNING_MATERIAL_MAX_TEXTURES)\r
1421                         vSize[i].TexSize = BURNING_MATERIAL_MAX_TEXTURES;\r
1422 \r
1423                 size = (flag & VERTEX4D_FORMAT_MASK_TEXTURE) >> 16;\r
1424                 if (size > BURNING_MATERIAL_MAX_TEXTURES)\r
1425                 {\r
1426                         flag = (flag & ~VERTEX4D_FORMAT_MASK_TEXTURE) | (BURNING_MATERIAL_MAX_TEXTURES << 16);\r
1427                 }\r
1428 \r
1429                 size = (flag & VERTEX4D_FORMAT_MASK_COLOR) >> 20;\r
1430                 if (size > BURNING_MATERIAL_MAX_COLORS)\r
1431                 {\r
1432                         flag = (flag & ~VERTEX4D_FORMAT_MASK_COLOR) | (BURNING_MATERIAL_MAX_COLORS << 20);\r
1433                 }\r
1434 \r
1435                 size = (flag & VERTEX4D_FORMAT_MASK_LIGHT) >> 24;\r
1436                 if (size > BURNING_MATERIAL_MAX_LIGHT_TANGENT)\r
1437                 {\r
1438                         flag = (flag & ~VERTEX4D_FORMAT_MASK_LIGHT) | (BURNING_MATERIAL_MAX_LIGHT_TANGENT << 24);\r
1439                 }\r
1440         }\r
1441 \r
1442         VertexCache.mem.resize(VERTEXCACHE_ELEMENT * 2);\r
1443         VertexCache.vType = E4VT_STANDARD;\r
1444 \r
1445         Clipper.resize(VERTEXCACHE_ELEMENT * 2);\r
1446         Clipper_temp.resize(VERTEXCACHE_ELEMENT * 2);\r
1447 \r
1448         TransformationStack = 0;\r
1449         memset(TransformationFlag, 0, sizeof(TransformationFlag));\r
1450         memset(Transformation_ETS_CLIPSCALE, 0, sizeof(Transformation_ETS_CLIPSCALE));\r
1451 \r
1452         Material.resetRenderStates = true;\r
1453         Material.Fallback_MaterialType = EMT_SOLID;\r
1454 }\r
1455 \r
1456 \r
1457 \r
1458 /*!\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
1461 */\r
1462 void CBurningVideoDriver::VertexCache_fill(const u32 sourceIndex, const u32 destIndex)\r
1463 {\r
1464         u8* burning_restrict source;\r
1465         s4DVertex* burning_restrict dest;\r
1466 \r
1467         source = (u8*)VertexCache.vertices + (sourceIndex * VertexCache.vSize[VertexCache.vType].Pitch);\r
1468 \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
1472 \r
1473         // store info\r
1474         VertexCache.info[destIndex].index = sourceIndex;\r
1475         VertexCache.info[destIndex].hit = 0;\r
1476 \r
1477         // destination Vertex\r
1478         dest = VertexCache.mem.data + s4DVertex_ofs(destIndex);\r
1479 \r
1480         //Irrlicht S3DVertex,S3DVertex2TCoords,S3DVertexTangents\r
1481         const S3DVertex* base = ((S3DVertex*)source);\r
1482 \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
1486 \r
1487         //mhm ... maybe no goto\r
1488         if (VertexCache.vType == E4VT_SHADOW)\r
1489         {\r
1490                 //core::vector3df i = base->Pos;\r
1491                 //i.Z -= 0.5f;\r
1492                 //matrix[ETS_PROJ_MODEL_VIEW].transformVect(&dest->Pos.x, i);\r
1493 \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
1497 \r
1498                 //glPolygonOffset // self shadow wanted or not?\r
1499                 dest->Pos.w *= 1.005f;\r
1500 \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
1503 \r
1504                 goto clipandproject;\r
1505         }\r
1506 \r
1507 \r
1508 #if defined (SOFTWARE_DRIVER_2_LIGHTING) || defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM )\r
1509 \r
1510         // vertex, normal in light(eye) space\r
1511         if (Material.org.Lighting || (EyeSpace.TL_Flag & (TL_TEXTURE_TRANSFORM | TL_FOG)))\r
1512         {\r
1513                 sVec4 vertex4; //eye coordinate position of vertex\r
1514                 matrix[ETS_MODEL_VIEW].transformVect(&vertex4.x, base->Pos);\r
1515 \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
1521 \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
1525 \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
1529 \r
1530         }\r
1531 \r
1532 #endif\r
1533 \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
1539 #endif\r
1540 \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
1546 #endif\r
1547 \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
1553 #endif\r
1554 \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
1559 #endif\r
1560 \r
1561 \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
1566         {\r
1567                 lightVertex_eye(dest, base->Color.color);\r
1568         }\r
1569         else\r
1570         {\r
1571                 dest->Color[0].setA8R8G8B8(base->Color.color);\r
1572         }\r
1573 #else\r
1574         dest->Color[0].setA8R8G8B8(base->Color.color);\r
1575 #endif\r
1576 #endif\r
1577 \r
1578         //vertex fog\r
1579         if (EyeSpace.TL_Flag & TL_FOG) //Material.org.FogEnable\r
1580         {\r
1581                 f32 fog_factor = 1.f;\r
1582 \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
1587 \r
1588                 switch (FogType)\r
1589                 {\r
1590                 case EFT_FOG_LINEAR:\r
1591                         fog_factor = (FogEnd - fog_frag_coord.f) * EyeSpace.fog_scale;\r
1592                         break;\r
1593                 case EFT_FOG_EXP:\r
1594                         fog_factor = (f32)exp(-FogDensity * fog_frag_coord.f);\r
1595                         break;\r
1596                 case EFT_FOG_EXP2:\r
1597                         fog_factor = (f32)exp(-FogDensity * FogDensity * fog_frag_coord.f * fog_frag_coord.f);\r
1598                         break;\r
1599                 }\r
1600 \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
1603         }\r
1604 \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
1608         {\r
1609                 sVec4 r;\r
1610                 f32 tx, ty;\r
1611 \r
1612                 // texgen\r
1613                 const size_t flag = TransformationFlag[TransformationStack][ETS_TEXTURE_0 + t];\r
1614                 if (flag & ETF_TEXGEN_CAMERA_SPHERE)\r
1615                 {\r
1616                         //reflect(u,N) u - 2.0 * dot(N, u) * N\r
1617                         // cam is (0,0,-1), tex flipped\r
1618 \r
1619                         const sVec4& u = EyeSpace.cam_dir; // EyeSpace.vertex.normalized\r
1620                         const sVec4& n = EyeSpace.normal;\r
1621 \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
1626 \r
1627                         //openGL\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
1631 \r
1632                         /*\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
1637                         */\r
1638                 }\r
1639                 else if (flag & ETF_TEXGEN_CAMERA_REFLECTION)\r
1640                 {\r
1641                         //reflect(u,N) u - 2.0 * dot(N, u) * N\r
1642                         // cam is (0,0,-1), tex flipped\r
1643 \r
1644                         const sVec4& u = EyeSpace.cam_dir; // EyeSpace.vertex.normalized\r
1645                         const sVec4& n = EyeSpace.normal;\r
1646 \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
1651 \r
1652                         //openGL\r
1653                         tx = r.x;\r
1654                         ty = -r.y;\r
1655                         /*\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
1659                         */\r
1660                 }\r
1661                 else\r
1662                 if (t < VertexCache.vSize[VertexCache.vType].TexCooSize)\r
1663                 {\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
1666 \r
1667                         tx = baseTCoord[t].x;\r
1668                         ty = baseTCoord[t].y;\r
1669                 }\r
1670                 else\r
1671                 {\r
1672                         tx = 0.f;\r
1673                         ty = 0.f;\r
1674                 }\r
1675 \r
1676                 //transform\r
1677                 if (!(flag & ETF_IDENTITY))\r
1678                 {\r
1679                         /*\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
1684                                         Ux  Vx  0  0\r
1685                                         Uy  Vy  0  0\r
1686                                         Uz  Vz  0  0\r
1687                                         Uw  Vw  0  0\r
1688                         */\r
1689 \r
1690                         const f32* M = matrix[ETS_TEXTURE_0 + t].pointer();\r
1691 \r
1692                         f32 _tx = tx;\r
1693                         f32 _ty = ty;\r
1694                         tx = M[0] * _tx + M[4] * _ty + M[8];\r
1695                         ty = M[1] * _tx + M[5] * _ty + M[9];\r
1696                 }\r
1697 \r
1698                 switch (Material.org.TextureLayer[t].TextureWrapU)\r
1699                 {\r
1700                 case ETC_CLAMP:\r
1701                 case ETC_CLAMP_TO_EDGE:\r
1702                 case ETC_CLAMP_TO_BORDER:\r
1703                         tx = clampf01(tx);\r
1704                         break;\r
1705                 case ETC_MIRROR:\r
1706                         if (core::fract(tx) > 0.5f)\r
1707                                 tx = 1.f - tx;\r
1708                         break;\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
1714                                 tx = 1.f - tx;\r
1715                         break;\r
1716                 case ETC_REPEAT:\r
1717                         // texel access is always modulo\r
1718                 default:\r
1719                         break;\r
1720                 }\r
1721                 switch (Material.org.TextureLayer[t].TextureWrapV)\r
1722                 {\r
1723                 case ETC_CLAMP:\r
1724                 case ETC_CLAMP_TO_EDGE:\r
1725                 case ETC_CLAMP_TO_BORDER:\r
1726                         ty = clampf01(ty);\r
1727                         break;\r
1728                 case ETC_MIRROR:\r
1729                         if (core::fract(ty) > 0.5f)\r
1730                                 ty = 1.f - ty;\r
1731                         break;\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
1737                                 ty = 1.f - ty;\r
1738                         break;\r
1739                 case ETC_REPEAT:\r
1740                         // texel access is always modulo\r
1741                 default:\r
1742                         break;\r
1743                 }\r
1744 \r
1745                 dest->Tex[t].x = tx;\r
1746                 dest->Tex[t].y = ty;\r
1747         }\r
1748 \r
1749 \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
1753                 )\r
1754         {\r
1755                 const S3DVertexTangents* tangent = ((S3DVertexTangents*)source);\r
1756 \r
1757                 sVec4 vp;\r
1758                 sVec4 light_accu;\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
1764                 {\r
1765                         const SBurningShaderLight& light = EyeSpace.Light[i];\r
1766                         if (!light.LightIsOn)\r
1767                                 continue;\r
1768 \r
1769                         // lightcolor with standard model\r
1770                         // but shader is different. treating light and vertex in same space\r
1771 #if 1\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
1775 #else\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
1779 #endif\r
1780 \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
1785                 }\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
1790 \r
1791         }\r
1792         else if (Material.org.Lighting)\r
1793         {\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
1797         }\r
1798 #endif //if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0\r
1799 \r
1800 //#endif // SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM\r
1801 \r
1802 clipandproject:\r
1803 \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
1807 \r
1808         // to DC Space, project homogenous vertex\r
1809         if ((dest[0].flag & VERTEX4D_CLIPMASK) == VERTEX4D_INSIDE)\r
1810         {\r
1811                 ndc_2_dc_and_project(dest + s4DVertex_proj(0), dest + s4DVertex_ofs(0), s4DVertex_ofs(1));\r
1812         }\r
1813 \r
1814 }\r
1815 \r
1816 \r
1817 //todo: this should return only index\r
1818 s4DVertexPair* CBurningVideoDriver::VertexCache_getVertex(const u32 sourceIndex) const\r
1819 {\r
1820         for (size_t i = 0; i < VERTEXCACHE_ELEMENT; ++i)\r
1821         {\r
1822                 if (VertexCache.info[i].index == sourceIndex)\r
1823                 {\r
1824                         return VertexCache.mem.data + s4DVertex_ofs(i);\r
1825                 }\r
1826         }\r
1827         return VertexCache.mem.data; //error\r
1828 }\r
1829 \r
1830 \r
1831 /*\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
1835 */\r
1836 void CBurningVideoDriver::VertexCache_get(s4DVertexPair* face[4])\r
1837 {\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
1841                 )\r
1842         {\r
1843 \r
1844                 size_t i;\r
1845                 //memset(info, VERTEXCACHE_MISS, sizeof(info));\r
1846                 for (i = 0; i != VERTEXCACHE_ELEMENT; ++i)\r
1847                 {\r
1848                         VertexCache.info_temp[i].hit = VERTEXCACHE_MISS;\r
1849                         VertexCache.info_temp[i].index = VERTEXCACHE_MISS;\r
1850                 }\r
1851 \r
1852                 // rewind to start of primitive\r
1853                 VertexCache.indicesIndex = VertexCache.indicesRun;\r
1854 \r
1855 \r
1856                 // get the next unique vertices cache line\r
1857                 u32 fillIndex = 0;\r
1858                 u32 dIndex = 0;\r
1859                 u32 sourceIndex = 0;\r
1860 \r
1861                 while (VertexCache.indicesIndex < VertexCache.indexCount &&\r
1862                         fillIndex < VERTEXCACHE_ELEMENT\r
1863                         )\r
1864                 {\r
1865                         switch (VertexCache.iType)\r
1866                         {\r
1867                         case E4IT_16BIT:\r
1868                                 sourceIndex = ((u16*)VertexCache.indices)[VertexCache.indicesIndex];\r
1869                                 break;\r
1870                         case E4IT_32BIT:\r
1871                                 sourceIndex = ((u32*)VertexCache.indices)[VertexCache.indicesIndex];\r
1872                                 break;\r
1873                         default:\r
1874                         case E4IT_NONE:\r
1875                                 sourceIndex = VertexCache.indicesIndex;\r
1876                                 break;\r
1877                         }\r
1878 \r
1879                         VertexCache.indicesIndex += 1;\r
1880 \r
1881                         // if not exist, push back\r
1882                         s32 exist = 0;\r
1883                         for (dIndex = 0; dIndex < fillIndex; ++dIndex)\r
1884                         {\r
1885                                 if (VertexCache.info_temp[dIndex].index == sourceIndex)\r
1886                                 {\r
1887                                         exist = 1;\r
1888                                         break;\r
1889                                 }\r
1890                         }\r
1891 \r
1892                         if (0 == exist)\r
1893                         {\r
1894                                 VertexCache.info_temp[fillIndex++].index = sourceIndex;\r
1895                         }\r
1896                 }\r
1897 \r
1898                 // clear marks\r
1899                 for (i = 0; i != VERTEXCACHE_ELEMENT; ++i)\r
1900                 {\r
1901                         VertexCache.info[i].hit = 0;\r
1902                 }\r
1903 \r
1904                 // mark all existing\r
1905                 for (i = 0; i != fillIndex; ++i)\r
1906                 {\r
1907                         for (dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex)\r
1908                         {\r
1909                                 if (VertexCache.info[dIndex].index == VertexCache.info_temp[i].index)\r
1910                                 {\r
1911                                         VertexCache.info_temp[i].hit = dIndex;\r
1912                                         VertexCache.info[dIndex].hit = 1;\r
1913                                         break;\r
1914                                 }\r
1915                         }\r
1916                 }\r
1917 \r
1918                 // fill new\r
1919                 for (i = 0; i != fillIndex; ++i)\r
1920                 {\r
1921                         if (VertexCache.info_temp[i].hit != VERTEXCACHE_MISS)\r
1922                                 continue;\r
1923 \r
1924                         for (dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex)\r
1925                         {\r
1926                                 if (0 == VertexCache.info[dIndex].hit)\r
1927                                 {\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
1931                                         break;\r
1932                                 }\r
1933                         }\r
1934                 }\r
1935         }\r
1936 \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
1939 \r
1940         switch (VertexCache.iType)\r
1941         {\r
1942         case E4IT_16BIT:\r
1943         {\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
1948         }\r
1949         break;\r
1950 \r
1951         case E4IT_32BIT:\r
1952         {\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
1957         }\r
1958         break;\r
1959 \r
1960         case E4IT_NONE:\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
1964                 break;\r
1965         default:\r
1966                 face[0] = face[1] = face[2] = VertexCache_getVertex(VertexCache.indicesRun + 0);\r
1967                 break;\r
1968         }\r
1969         face[3] = face[0]; // quad unsupported\r
1970         VertexCache.indicesRun += VertexCache.indicesPitch;\r
1971 }\r
1972 \r
1973 \r
1974 /*!\r
1975 */\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
1981 {\r
1982 \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
1990         {\r
1991                 return 1;\r
1992         }\r
1993 \r
1994         VertexCache.vertices = vertices;\r
1995         VertexCache.vertexCount = vertexCount;\r
1996 \r
1997         switch (Material.org.MaterialType) // (Material.Fallback_MaterialType)\r
1998         {\r
1999         case EMT_REFLECTION_2_LAYER:\r
2000         case EMT_TRANSPARENT_REFLECTION_2_LAYER:\r
2001                 VertexCache.vType = E4VT_REFLECTION_MAP;\r
2002                 break;\r
2003         default:\r
2004                 VertexCache.vType = (e4DVertexType)vType;\r
2005                 break;\r
2006         }\r
2007 \r
2008         //check material\r
2009         SVSize* vSize = VertexCache.vSize;\r
2010         for (int m = (int)vSize[VertexCache.vType].TexSize - 1; m >= 0; --m)\r
2011         {\r
2012                 ITexture* tex = MAT_TEXTURE(m);\r
2013                 if (!tex)\r
2014                 {\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
2020                 }\r
2021         }\r
2022 \r
2023         VertexCache.indices = indices;\r
2024         VertexCache.indicesIndex = 0;\r
2025         VertexCache.indicesRun = 0;\r
2026 \r
2027         switch (iType)\r
2028         {\r
2029         case EIT_16BIT: VertexCache.iType = E4IT_16BIT; break;\r
2030         case EIT_32BIT: VertexCache.iType = E4IT_32BIT; break;\r
2031         default:\r
2032                 VertexCache.iType = (e4DIndexType)iType; break;\r
2033         }\r
2034         if (!VertexCache.indices)\r
2035                 VertexCache.iType = E4IT_NONE;\r
2036 \r
2037         VertexCache.pType = pType;\r
2038         VertexCache.primitiveHasVertex = 3;\r
2039         VertexCache.indicesPitch = 1;\r
2040         switch (VertexCache.pType)\r
2041         {\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
2048                 break;\r
2049         case scene::EPT_LINE_STRIP:\r
2050                 VertexCache.indexCount = primitiveCount + 1;\r
2051                 VertexCache.indicesPitch = 1;\r
2052                 VertexCache.primitiveHasVertex = 2;\r
2053                 break;\r
2054         case scene::EPT_LINE_LOOP:\r
2055                 VertexCache.indexCount = primitiveCount + 1;\r
2056                 VertexCache.indicesPitch = 1;\r
2057                 VertexCache.primitiveHasVertex = 2;\r
2058                 break;\r
2059         case scene::EPT_LINES:\r
2060                 VertexCache.indexCount = 2 * primitiveCount;\r
2061                 VertexCache.indicesPitch = 2;\r
2062                 VertexCache.primitiveHasVertex = 2;\r
2063                 break;\r
2064         case scene::EPT_TRIANGLE_STRIP:\r
2065                 VertexCache.indexCount = primitiveCount + 2;\r
2066                 VertexCache.indicesPitch = 1;\r
2067                 VertexCache.primitiveHasVertex = 3;\r
2068                 break;\r
2069         case scene::EPT_TRIANGLES:\r
2070                 VertexCache.indexCount = primitiveCount + primitiveCount + primitiveCount;\r
2071                 VertexCache.indicesPitch = 3;\r
2072                 VertexCache.primitiveHasVertex = 3;\r
2073                 break;\r
2074         case scene::EPT_TRIANGLE_FAN:\r
2075                 VertexCache.indexCount = primitiveCount + 2;\r
2076                 VertexCache.indicesPitch = 1;\r
2077                 VertexCache.primitiveHasVertex = 3;\r
2078                 break;\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
2083                 break;\r
2084         case scene::EPT_QUADS:\r
2085                 VertexCache.indexCount = 4 * primitiveCount;\r
2086                 VertexCache.indicesPitch = 4;\r
2087                 VertexCache.primitiveHasVertex = 4;\r
2088                 break;\r
2089         case scene::EPT_POLYGON:\r
2090                 VertexCache.indexCount = primitiveCount + 1;\r
2091                 VertexCache.indicesPitch = 1;\r
2092                 VertexCache.primitiveHasVertex = primitiveCount;\r
2093                 break;\r
2094         case scene::EPT_POINT_SPRITES:\r
2095                 VertexCache.indexCount = primitiveCount;\r
2096                 VertexCache.indicesPitch = 1;\r
2097                 VertexCache.primitiveHasVertex = 1;\r
2098                 break;\r
2099         }\r
2100 \r
2101         //memset( VertexCache.info, VERTEXCACHE_MISS, sizeof ( VertexCache.info ) );\r
2102         for (size_t i = 0; i != VERTEXCACHE_ELEMENT; ++i)\r
2103         {\r
2104                 VertexCache.info[i].hit = VERTEXCACHE_MISS;\r
2105                 VertexCache.info[i].index = VERTEXCACHE_MISS;\r
2106         }\r
2107         return 0;\r
2108 }\r
2109 \r
2110 \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
2115 \r
2116 {\r
2117         if (!checkPrimitiveCount(primitiveCount))\r
2118                 return;\r
2119 \r
2120         CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);\r
2121 \r
2122         if (VertexCache_reset(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType))\r
2123                 return;\r
2124 \r
2125         if ((u32)Material.org.MaterialType < MaterialRenderers.size())\r
2126         {\r
2127                 MaterialRenderers[Material.org.MaterialType].Renderer->OnRender(this, vType);\r
2128         }\r
2129 \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
2133         {\r
2134                 transform_calc(ETS_MODEL_VIEW);\r
2135                 transform_calc(ETS_NORMAL);\r
2136         }\r
2137 \r
2138 \r
2139         s4DVertexPair* face[4];\r
2140 \r
2141         size_t vOut;\r
2142         size_t vertex_from_clipper; // from VertexCache or CurrentOut\r
2143         size_t has_vertex_run;\r
2144 \r
2145         for (size_t primitive_run = 0; primitive_run < primitiveCount; ++primitive_run)\r
2146         {\r
2147                 //collect pointer to face vertices\r
2148                 VertexCache_get(face);\r
2149 \r
2150                 size_t clipMask_i;\r
2151                 size_t clipMask_o;\r
2152 \r
2153                 clipMask_i = face[0]->flag;\r
2154                 clipMask_o = face[0]->flag;\r
2155 \r
2156                 for (has_vertex_run = 1; has_vertex_run < VertexCache.primitiveHasVertex; ++has_vertex_run)\r
2157                 {\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
2160                 }\r
2161 \r
2162                 clipMask_i &= VERTEX4D_CLIPMASK;\r
2163                 clipMask_o &= VERTEX4D_CLIPMASK;\r
2164 \r
2165                 if (clipMask_i != VERTEX4D_INSIDE)\r
2166                 {\r
2167                         // if primitive fully outside or outside on same side\r
2168                         continue;\r
2169                         vOut = 0;\r
2170                         vertex_from_clipper = 0;\r
2171                 }\r
2172                 else if (clipMask_o == VERTEX4D_INSIDE)\r
2173                 {\r
2174                         // if primitive fully inside\r
2175                         vOut = VertexCache.primitiveHasVertex;\r
2176                         vertex_from_clipper = 0;\r
2177                 }\r
2178                 else\r
2179 #if defined(SOFTWARE_DRIVER_2_CLIPPING)\r
2180                 {\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
2184                         {\r
2185                                 memcpy_s4DVertexPair(Clipper.data + s4DVertex_ofs(has_vertex_run), face[has_vertex_run]);\r
2186                         }\r
2187 \r
2188                         vOut = clipToFrustum(VertexCache.primitiveHasVertex);\r
2189                         vertex_from_clipper = 1;\r
2190 \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
2193                 }\r
2194 #else\r
2195                 {\r
2196                         continue;\r
2197                         vOut = 0;\r
2198                         vertex_from_clipper = 0;\r
2199                 }\r
2200 #endif\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
2203                 {\r
2204                         // set from clipped geometry\r
2205                         if (vertex_from_clipper)\r
2206                         {\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
2210                         }\r
2211 \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
2215 \r
2216                         // crossproduct (area of parallelogram * 0.5 = triangle screen size)\r
2217                         f32 dc_area;\r
2218                         {\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
2222 \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
2225                         }\r
2226 \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
2229                         ieee754 t;\r
2230                         t.f = dc_area;\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
2235 \r
2236                         //select mipmap ratio between drawing space and texture space (for multiply divide here)\r
2237                         dc_area = reciprocal_zero(dc_area);\r
2238 \r
2239                         // select mipmap\r
2240                         for (size_t m = 0; m < VertexCache.vSize[VertexCache.vType].TexSize; ++m)\r
2241                         {\r
2242                                 video::CSoftwareTexture2* tex = MAT_TEXTURE(m);\r
2243 \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
2246 \r
2247                                 //assume transparent add is ~50% transparent -> more detail\r
2248                                 switch (Material.org.MaterialType)\r
2249                                 {\r
2250                                         case EMT_TRANSPARENT_ADD_COLOR:\r
2251                                         case EMT_TRANSPARENT_ALPHA_CHANNEL:\r
2252                                                 lod_bias *= 0.5f;\r
2253                                                 break;\r
2254                                         default:\r
2255                                                 break;\r
2256                                 }\r
2257                                 lod_bias *= tex->get_lod_bias();\r
2258                                 //lod_bias += Material.org.TextureLayer[m].LODBias * 0.125f;\r
2259         \r
2260                                 s32 lodFactor = lodFactor_inside(face, m, dc_area, lod_bias);\r
2261 \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
2265                         }\r
2266                         \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
2269                 }\r
2270 \r
2271         }\r
2272 \r
2273         //release texture\r
2274         for (size_t m = 0; m < VertexCache.vSize[VertexCache.vType].TexSize; ++m)\r
2275         {\r
2276                 CurrentShader->setTextureParam(m, 0, 0);\r
2277         }\r
2278 \r
2279 }\r
2280 \r
2281 \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
2286 {\r
2287         EyeSpace.Global_AmbientLight.setColorf(color);\r
2288 }\r
2289 \r
2290 \r
2291 //! adds a dynamic light\r
2292 s32 CBurningVideoDriver::addDynamicLight(const SLight& dl)\r
2293 {\r
2294         (void)CNullDriver::addDynamicLight(dl);\r
2295 \r
2296         SBurningShaderLight l;\r
2297         //      l.org = dl;\r
2298         l.Type = dl.Type;\r
2299         l.LightIsOn = true;\r
2300 \r
2301         l.AmbientColor.setColorf(dl.AmbientColor);\r
2302         l.DiffuseColor.setColorf(dl.DiffuseColor);\r
2303         l.SpecularColor.setColorf(dl.SpecularColor);\r
2304 \r
2305         //should always be valid?\r
2306         sVec4 nDirection;\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
2311 \r
2312 \r
2313         switch (dl.Type)\r
2314         {\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
2319                 l.pos.w = 0.f;\r
2320 \r
2321                 l.constantAttenuation = 1.f;\r
2322                 l.linearAttenuation = 0.f;\r
2323                 l.quadraticAttenuation = 0.f;\r
2324 \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
2332                 break;\r
2333 \r
2334         case ELT_POINT:\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
2338                 l.pos.w = 1.f;\r
2339 \r
2340                 l.constantAttenuation = dl.Attenuation.X;\r
2341                 l.linearAttenuation = dl.Attenuation.Y;\r
2342                 l.quadraticAttenuation = dl.Attenuation.Z;\r
2343 \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
2351                 break;\r
2352 \r
2353         case ELT_SPOT:\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
2357                 l.pos.w = 1.f;\r
2358 \r
2359                 l.constantAttenuation = dl.Attenuation.X;\r
2360                 l.linearAttenuation = dl.Attenuation.Y;\r
2361                 l.quadraticAttenuation = dl.Attenuation.Z;\r
2362 \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
2370                 break;\r
2371         default:\r
2372                 break;\r
2373         }\r
2374 \r
2375         //which means ETS_VIEW\r
2376         setTransform(ETS_WORLD, irr::core::IdentityMatrix);\r
2377         transform_calc(ETS_MODEL_VIEW);\r
2378 \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
2382 \r
2383         EyeSpace.Light.push_back(l);\r
2384         return EyeSpace.Light.size() - 1;\r
2385 }\r
2386 \r
2387 \r
2388 //! Turns a dynamic light on or off\r
2389 void CBurningVideoDriver::turnLightOn(s32 lightIndex, bool turnOn)\r
2390 {\r
2391         if ((u32)lightIndex < EyeSpace.Light.size())\r
2392         {\r
2393                 EyeSpace.Light[lightIndex].LightIsOn = turnOn;\r
2394         }\r
2395 }\r
2396 \r
2397 //! deletes all dynamic lights there are\r
2398 void CBurningVideoDriver::deleteAllDynamicLights()\r
2399 {\r
2400         EyeSpace.reset();\r
2401         CNullDriver::deleteAllDynamicLights();\r
2402 \r
2403 }\r
2404 \r
2405 //! returns the maximal amount of dynamic lights the device can handle\r
2406 u32 CBurningVideoDriver::getMaximalDynamicLightAmount() const\r
2407 {\r
2408         return 8; //no limit 8 only for convenience\r
2409 }\r
2410 \r
2411 \r
2412 //! sets a material\r
2413 void CBurningVideoDriver::setMaterial(const SMaterial& material)\r
2414 {\r
2415         // ---------- Override\r
2416         Material.org = material;\r
2417         OverrideMaterial.apply(Material.org);\r
2418 \r
2419         const SMaterial& in = Material.org;\r
2420 \r
2421         // ---------- Notify Shader\r
2422                 // unset old material\r
2423         u32 mi;\r
2424         mi = (u32)Material.lastMaterial.MaterialType;\r
2425         if (mi != material.MaterialType && mi < MaterialRenderers.size())\r
2426                 MaterialRenderers[mi].Renderer->OnUnsetMaterial();\r
2427 \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
2433 \r
2434         Material.lastMaterial = in;\r
2435         Material.resetRenderStates = false;\r
2436 \r
2437         //CSoftware2MaterialRenderer sets Material.Fallback_MaterialType\r
2438 \r
2439         //Material.Fallback_MaterialType = material.MaterialType;\r
2440 \r
2441 //-----------------\r
2442 \r
2443         //Material.org = material;\r
2444         Material.CullFlag = CULL_INVISIBLE | (in.BackfaceCulling ? CULL_BACK : 0) | (in.FrontfaceCulling ? CULL_FRONT : 0);\r
2445 \r
2446         size_t* flag = TransformationFlag[TransformationStack];\r
2447 \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
2450         {\r
2451                 setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + m), in.getTextureMatrix(m));\r
2452                 flag[ETS_TEXTURE_0 + m] &= ~ETF_TEXGEN_MASK;\r
2453         }\r
2454 #endif\r
2455 \r
2456 #ifdef SOFTWARE_DRIVER_2_LIGHTING\r
2457 \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
2462 \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
2468 \r
2469 #endif\r
2470 \r
2471 //--------------- setCurrentShader\r
2472 \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
2477 \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
2484 \r
2485         EyeSpace.TL_Flag &= ~(TL_TEXTURE_TRANSFORM | TL_LIGHT0_IS_NORMAL_MAP);\r
2486 \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
2490 \r
2491         EBurningFFShader shader = Material.depth_test ? ETR_TEXTURE_GOURAUD : ETR_TEXTURE_GOURAUD_NOZ;\r
2492 \r
2493         switch (Material.Fallback_MaterialType) //(Material.org.MaterialType)\r
2494         {\r
2495         case EMT_ONETEXTURE_BLEND:\r
2496                 shader = ETR_TEXTURE_BLEND;\r
2497                 break;\r
2498 \r
2499         case EMT_TRANSPARENT_ALPHA_CHANNEL_REF:\r
2500                 Material.org.MaterialTypeParam = 0.5f;\r
2501                 //fallthrough\r
2502 \r
2503         case EMT_TRANSPARENT_ALPHA_CHANNEL:\r
2504                 if (texture0 && texture0->hasAlpha())\r
2505                 {\r
2506                         shader = Material.depth_test ? ETR_TEXTURE_GOURAUD_ALPHA : ETR_TEXTURE_GOURAUD_ALPHA_NOZ;\r
2507                 }\r
2508                 else\r
2509                 {\r
2510                         //fall back to EMT_TRANSPARENT_VERTEX_ALPHA\r
2511                         shader = ETR_TEXTURE_GOURAUD_VERTEX_ALPHA;\r
2512                 }\r
2513                 break;\r
2514 \r
2515         case EMT_TRANSPARENT_ADD_COLOR:\r
2516                 shader = Material.depth_test ? ETR_TEXTURE_GOURAUD_ADD : ETR_TEXTURE_GOURAUD_ADD_NO_Z;\r
2517                 break;\r
2518 \r
2519         case EMT_TRANSPARENT_VERTEX_ALPHA:\r
2520                 shader = ETR_TEXTURE_GOURAUD_VERTEX_ALPHA;\r
2521                 break;\r
2522 \r
2523         case EMT_LIGHTMAP:\r
2524         case EMT_LIGHTMAP_LIGHTING:\r
2525                 if (texture1)\r
2526                         shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1;\r
2527                 break;\r
2528 \r
2529         case EMT_LIGHTMAP_M2:\r
2530         case EMT_LIGHTMAP_LIGHTING_M2:\r
2531                 if (texture1)\r
2532                         shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M2;\r
2533                 break;\r
2534 \r
2535         case EMT_LIGHTMAP_LIGHTING_M4:\r
2536                 if (texture1)\r
2537                         shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M4;\r
2538                 break;\r
2539         case EMT_LIGHTMAP_M4:\r
2540                 if (texture1)\r
2541                         shader = ETR_TEXTURE_LIGHTMAP_M4;\r
2542                 break;\r
2543 \r
2544         case EMT_LIGHTMAP_ADD:\r
2545                 if (texture1)\r
2546                         shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD;\r
2547                 break;\r
2548 \r
2549         case EMT_DETAIL_MAP:\r
2550                 if (texture1)\r
2551                         shader = ETR_TEXTURE_GOURAUD_DETAIL_MAP;\r
2552                 break;\r
2553 \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
2557                 break;\r
2558         case EMT_REFLECTION_2_LAYER:\r
2559         case EMT_TRANSPARENT_REFLECTION_2_LAYER:\r
2560                 if (texture1)\r
2561                 {\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
2565                 }\r
2566                 break;\r
2567 \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
2571                 if (texture1)\r
2572                 {\r
2573                         shader = ETR_NORMAL_MAP_SOLID;\r
2574                         EyeSpace.TL_Flag |= TL_TEXTURE_TRANSFORM | TL_LIGHT0_IS_NORMAL_MAP;\r
2575                 }\r
2576                 break;\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
2580                 if (texture1)\r
2581                 {\r
2582                         shader = ETR_NORMAL_MAP_SOLID;\r
2583                         EyeSpace.TL_Flag |= TL_TEXTURE_TRANSFORM | TL_LIGHT0_IS_NORMAL_MAP;\r
2584                 }\r
2585                 break;\r
2586 \r
2587         default:\r
2588                 break;\r
2589 \r
2590         }\r
2591 \r
2592         if (!texture0)\r
2593         {\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
2597                         ETR_GOURAUD_NOZ;\r
2598 \r
2599                 shader = ETR_COLOR;\r
2600         }\r
2601 \r
2602         if (in.Wireframe)\r
2603         {\r
2604                 IBurningShader* candidate = BurningShader[shader];\r
2605                 if (!candidate || (candidate && !candidate->canWireFrame()))\r
2606                 {\r
2607                         shader = ETR_TEXTURE_GOURAUD_WIRE;\r
2608                 }\r
2609         }\r
2610 \r
2611         if (in.PointCloud)\r
2612         {\r
2613                 IBurningShader* candidate = BurningShader[shader];\r
2614                 if (!candidate || (candidate && !candidate->canPointCloud()))\r
2615                 {\r
2616                         shader = ETR_TEXTURE_GOURAUD_WIRE;\r
2617                 }\r
2618         }\r
2619 \r
2620         //shader = ETR_REFERENCE;\r
2621 \r
2622         // switchToTriangleRenderer\r
2623         CurrentShader = BurningShader[shader];\r
2624         if (CurrentShader)\r
2625         {\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
2632         }\r
2633 \r
2634 \r
2635         /*\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
2639         */\r
2640 }\r
2641 \r
2642 \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
2646 {\r
2647         CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog);\r
2648 \r
2649         EyeSpace.fog_scale = reciprocal_zero(FogEnd - FogStart);\r
2650 }\r
2651 \r
2652 \r
2653 \r
2654 #if defined(SOFTWARE_DRIVER_2_LIGHTING) && BURNING_MATERIAL_MAX_COLORS > 0\r
2655 \r
2656 \r
2657 /*!\r
2658         applies lighting model\r
2659 */\r
2660 void CBurningVideoDriver::lightVertex_eye(s4DVertex* dest, u32 vertexargb)\r
2661 {\r
2662         //gl_FrontLightModelProduct.sceneColor = gl_FrontMaterial.emission + gl_FrontMaterial.ambient * gl_LightModel.ambient\r
2663 \r
2664         sVec3Color ambient;\r
2665         sVec3Color diffuse;\r
2666         sVec3Color specular;\r
2667 \r
2668 \r
2669         // the universe started in darkness..\r
2670         ambient = EyeSpace.Global_AmbientLight;\r
2671         diffuse.set(0.f);\r
2672         specular.set(0.f);\r
2673 \r
2674 \r
2675         u32 i;\r
2676         f32 dot;\r
2677         f32 distance;\r
2678         f32 attenuation;\r
2679         sVec4 vp;                       // unit vector vertex to light\r
2680         sVec4 lightHalf;        // blinn-phong reflection\r
2681 \r
2682         f32 spotDot;                    // cos of angle between spotlight and point on surface\r
2683 \r
2684         for (i = 0; i < EyeSpace.Light.size(); ++i)\r
2685         {\r
2686                 const SBurningShaderLight& light = EyeSpace.Light[i];\r
2687                 if (!light.LightIsOn)\r
2688                         continue;\r
2689 \r
2690                 switch (light.Type)\r
2691                 {\r
2692                 case ELT_DIRECTIONAL:\r
2693 \r
2694                         //angle between normal and light vector\r
2695                         dot = EyeSpace.normal.dot_xyz(light.spotDirection4);\r
2696 \r
2697                         // accumulate ambient\r
2698                         ambient.add_rgb(light.AmbientColor);\r
2699 \r
2700                         // diffuse component\r
2701                         if (dot > 0.f)\r
2702                                 diffuse.mad_rgb(light.DiffuseColor, dot);\r
2703                         break;\r
2704 \r
2705                 case ELT_POINT:\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
2710 \r
2711                         distance = vp.length_xyz();\r
2712 \r
2713                         attenuation = light.constantAttenuation\r
2714                                 + light.linearAttenuation * distance\r
2715                                 + light.quadraticAttenuation * (distance * distance);\r
2716                         attenuation = reciprocal_one(attenuation);\r
2717 \r
2718                         //att = clamp(1.0 - dist/radius, 0.0, 1.0); att *= att\r
2719 \r
2720                         // accumulate ambient\r
2721                         ambient.mad_rgb(light.AmbientColor, attenuation);\r
2722 \r
2723                         // build diffuse reflection\r
2724 \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
2729 \r
2730                         // diffuse component\r
2731                         diffuse.mad_rgb(light.DiffuseColor, dot * attenuation);\r
2732 \r
2733                         if (!(EyeSpace.TL_Flag & TL_SPECULAR))\r
2734                                 continue;\r
2735 \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
2740 \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
2744                         );\r
2745                         break;\r
2746 \r
2747                 case ELT_SPOT:\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
2752 \r
2753                         distance = vp.length_xyz();\r
2754 \r
2755                         //normalize\r
2756                         vp.mul_xyz(reciprocal_zero(distance));\r
2757 \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
2761                                 continue;\r
2762 \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
2768 \r
2769                         // accumulate ambient\r
2770                         ambient.mad_rgb(light.AmbientColor, attenuation);\r
2771 \r
2772 \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
2777 \r
2778                         // diffuse component\r
2779                         diffuse.mad_rgb(light.DiffuseColor, dot * attenuation);\r
2780 \r
2781                         if (!(EyeSpace.TL_Flag & TL_SPECULAR))\r
2782                                 continue;\r
2783 \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
2788 \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
2792                         );\r
2793                         break;\r
2794 \r
2795                 default:\r
2796                         break;\r
2797                 }\r
2798 \r
2799         }\r
2800 \r
2801         // sum up lights\r
2802         sVec3Color dColor;\r
2803         dColor.set(0.f);\r
2804         dColor.mad_rgbv(diffuse, Material.DiffuseColor);\r
2805 \r
2806         //diffuse * vertex color.\r
2807         //has to move to shader (for vertex color only this will fit [except clamping])\r
2808 \r
2809         sVec3Color c;\r
2810         c.setA8R8G8B8(vertexargb);\r
2811         dColor.r *= c.r;\r
2812         dColor.g *= c.g;\r
2813         dColor.b *= c.b;\r
2814 \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
2818         {\r
2819                 specular.sat_xyz(dest->Color[1], Material.SpecularColor);\r
2820         }\r
2821         else\r
2822                 if (!(EyeSpace.TL_Flag & TL_LIGHT0_IS_NORMAL_MAP) &&\r
2823                         (VertexCache.vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_MASK_LIGHT)\r
2824                         )\r
2825                 {\r
2826                         specular.sat_xyz(dest->LightTangent[0], Material.SpecularColor);\r
2827                 }\r
2828                 else\r
2829 #endif\r
2830                 {\r
2831                         dColor.mad_rgbv(specular, Material.SpecularColor);\r
2832                 }\r
2833 \r
2834 \r
2835         dColor.mad_rgbv(ambient, Material.AmbientColor);\r
2836         dColor.add_rgb(Material.EmissiveColor);\r
2837 \r
2838 \r
2839         dColor.sat(dest->Color[0], vertexargb);\r
2840 \r
2841 }\r
2842 \r
2843 #endif\r
2844 /*\r
2845 CImage* getImage(const video::ITexture* texture)\r
2846 {\r
2847         if (!texture) return 0;\r
2848 \r
2849         CImage* img = 0;\r
2850         switch (texture->getDriverType())\r
2851         {\r
2852         case EDT_BURNINGSVIDEO:\r
2853                 img = ((CSoftwareTexture2*)texture)->getImage();\r
2854                 break;\r
2855         case EDT_SOFTWARE:\r
2856                 img = ((CSoftwareTexture*)texture)->getImage();\r
2857                 break;\r
2858         default:\r
2859                 os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR);\r
2860                 break;\r
2861         }\r
2862         return img;\r
2863 }\r
2864 */\r
2865 /*\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
2868 */\r
2869 \r
2870 static const u16 quad_triangle_indexList[6] = { 0,1,2,0,2,3 };\r
2871 \r
2872 \r
2873 #if defined(SOFTWARE_DRIVER_2_2D_AS_2D)\r
2874 \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
2880 {\r
2881         if (texture)\r
2882         {\r
2883                 if (texture->getOriginalSize() != texture->getSize())\r
2884                 {\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
2888                         return;\r
2889                 }\r
2890 \r
2891                 if (texture->getDriverType() != EDT_BURNINGSVIDEO)\r
2892                 {\r
2893                         os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR);\r
2894                         return;\r
2895                 }\r
2896 \r
2897                 if (useAlphaChannelOfTexture)\r
2898                         ((CSoftwareTexture2*)texture)->getImage()->copyToWithAlpha(\r
2899                                 RenderTargetSurface, destPos, sourceRect, color, clipRect);\r
2900                 else\r
2901                         ((CSoftwareTexture2*)texture)->getImage()->copyTo(\r
2902                                 RenderTargetSurface, destPos, sourceRect, clipRect);\r
2903         }\r
2904 }\r
2905 \r
2906 \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
2911 {\r
2912         if (texture)\r
2913         {\r
2914                 if (texture->getDriverType() != EDT_BURNINGSVIDEO)\r
2915                 {\r
2916                         os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR);\r
2917                         return;\r
2918                 }\r
2919 \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
2923 \r
2924                 StretchBlit(op, RenderTargetSurface, clipRect, &destRect,\r
2925                         ((CSoftwareTexture2*)texture)->getImage(), &sourceRect, &texture->getOriginalSize(), argb);\r
2926 \r
2927         }\r
2928 }\r
2929 \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
2934 {\r
2935         core::rect<s32> p(position);\r
2936         if (clip) p.clipAgainst(*clip);\r
2937         if (p.isValid()) drawRectangle(RenderTargetSurface, p, colorLeftUp);\r
2938 }\r
2939 \r
2940 #endif //defined(SOFTWARE_DRIVER_2_2D_AS_2D)\r
2941 \r
2942 \r
2943 \r
2944 //! Enable the 2d override material\r
2945 void CBurningVideoDriver::enableMaterial2D(bool enable)\r
2946 {\r
2947         CNullDriver::enableMaterial2D(enable);\r
2948         burning_setbit(TransformationFlag[1][ETS_PROJECTION], 0, ETF_VALID);\r
2949 }\r
2950 \r
2951 size_t compare_2d_material(const SMaterial& a, const SMaterial& b)\r
2952 {\r
2953         size_t flag = 0;\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
2960 \r
2961         flag |= a.TextureLayer[1].Texture == b.TextureLayer[1].Texture ? 0 : 32;\r
2962         flag |= a.ZWriteEnable == b.ZWriteEnable ? 0 : 64;\r
2963 \r
2964         return flag;\r
2965 }\r
2966 \r
2967 void CBurningVideoDriver::setRenderStates2DMode(const video::SColor& color, const video::ITexture* texture, bool useAlphaChannelOfTexture)\r
2968 {\r
2969         //save current 3D Material\r
2970         //Material.save3D = Material.org;\r
2971 \r
2972         //build new 2D Material\r
2973 \r
2974         bool vertexAlpha = color.getAlpha() < 255;\r
2975 \r
2976         //2D uses textureAlpa*vertexAlpha 3D not..\r
2977         if (useAlphaChannelOfTexture && texture && texture->hasAlpha())\r
2978         {\r
2979                 Material.mat2D.MaterialType = EMT_TRANSPARENT_ALPHA_CHANNEL;\r
2980         }\r
2981         else if (vertexAlpha)\r
2982         {\r
2983                 Material.mat2D.MaterialType = EMT_TRANSPARENT_VERTEX_ALPHA;\r
2984         }\r
2985         else\r
2986         {\r
2987                 Material.mat2D.MaterialType = EMT_SOLID;\r
2988         }\r
2989 \r
2990         Material.mat2D.ZBuffer = ECFN_DISABLED;\r
2991         Material.mat2D.ZWriteEnable = EZW_OFF;\r
2992         Material.mat2D.Lighting = false;\r
2993 \r
2994         Material.mat2D.setTexture(0, (video::ITexture*)texture);\r
2995 \r
2996         //used for text. so stay as sharp as possible (like HW Driver)\r
2997         bool mip = false;\r
2998 \r
2999         const SMaterial& currentMaterial = (!OverrideMaterial2DEnabled) ? InitMaterial2D : OverrideMaterial2D;\r
3000         mip = currentMaterial.TextureLayer[0].Texture && currentMaterial.TextureLayer[0].BilinearFilter;\r
3001 \r
3002         Material.mat2D.setFlag(video::EMF_BILINEAR_FILTER, mip);\r
3003 \r
3004 \r
3005         //switch to 2D Matrix Stack [ Material set Texture Matrix ]\r
3006         TransformationStack = 1;\r
3007 \r
3008         //2D GUI Matrix\r
3009         if (!(TransformationFlag[TransformationStack][ETS_PROJECTION] & ETF_VALID))\r
3010         {\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
3016 \r
3017                 m.makeIdentity();\r
3018                 setTransform(ETS_WORLD, m);\r
3019 \r
3020                 if (mip)\r
3021                         m.setTranslation(core::vector3df(IRRLICHT_2D_TEXEL_OFFSET, IRRLICHT_2D_TEXEL_OFFSET, 0.0f));\r
3022 \r
3023                 setTransform(ETS_VIEW, m);\r
3024 \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
3027         }\r
3028 \r
3029         //compare\r
3030         if (compare_2d_material(Material.org, Material.mat2D))\r
3031         {\r
3032                 setMaterial(Material.mat2D);\r
3033         }\r
3034         if (CurrentShader)\r
3035         {\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
3039         }\r
3040 \r
3041 }\r
3042 \r
3043 void CBurningVideoDriver::setRenderStates3DMode()\r
3044 {\r
3045         //restoreRenderStates3DMode\r
3046 \r
3047         //setMaterial(Material.save3D);\r
3048         //switch to 3D Matrix Stack\r
3049         TransformationStack = 0;\r
3050 }\r
3051 \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
3056 {\r
3057         if (!checkPrimitiveCount(primitiveCount))\r
3058                 return;\r
3059 \r
3060         CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);\r
3061 \r
3062         bool useAlphaChannelOfTexture = false;\r
3063         video::SColor color(0xFFFFFFFF);\r
3064         switch (Material.org.MaterialType)\r
3065         {\r
3066         case EMT_TRANSPARENT_ALPHA_CHANNEL:\r
3067                 useAlphaChannelOfTexture = true;\r
3068                 break;\r
3069         case EMT_TRANSPARENT_VERTEX_ALPHA:\r
3070                 color.setAlpha(127);\r
3071                 break;\r
3072         default:\r
3073                 break;\r
3074         }\r
3075         setRenderStates2DMode(color, Material.org.getTexture(0), useAlphaChannelOfTexture);\r
3076 \r
3077         drawVertexPrimitiveList(vertices, vertexCount,\r
3078                 indexList, primitiveCount,\r
3079                 vType, pType, iType);\r
3080 \r
3081         setRenderStates3DMode();\r
3082 \r
3083 }\r
3084 \r
3085 //setup a quad\r
3086 #if defined(SOFTWARE_DRIVER_2_2D_AS_3D)\r
3087 \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
3093 {\r
3094         if (!texture)\r
3095                 return;\r
3096 \r
3097         if (!sourceRect.isValid())\r
3098                 return;\r
3099 \r
3100         // clip these coordinates\r
3101         core::rect<s32> targetRect(destPos, sourceRect.getSize());\r
3102         if (clipRect)\r
3103         {\r
3104                 targetRect.clipAgainst(*clipRect);\r
3105                 if (targetRect.getWidth() < 0 || targetRect.getHeight() < 0)\r
3106                         return;\r
3107         }\r
3108 \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
3112                 return;\r
3113 \r
3114         // ok, we've clipped everything.\r
3115         // now draw it.\r
3116         const core::dimension2d<s32> sourceSize(targetRect.getSize());\r
3117         const core::position2d<s32> sourcePos(sourceRect.UpperLeftCorner + (targetRect.UpperLeftCorner - destPos));\r
3118 \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
3127 \r
3128 \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
3133 \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
3138 \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
3143 \r
3144         setRenderStates2DMode(color, texture, useAlphaChannelOfTexture);\r
3145 \r
3146         drawVertexPrimitiveList(Quad2DVertices, 4,\r
3147                 quad_triangle_indexList, 2,\r
3148                 EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);\r
3149 \r
3150         setRenderStates3DMode();\r
3151 \r
3152 }\r
3153 \r
3154 \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
3159 {\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
3168 \r
3169         const video::SColor temp[4] =\r
3170         {\r
3171                 0xFFFFFFFF,\r
3172                 0xFFFFFFFF,\r
3173                 0xFFFFFFFF,\r
3174                 0xFFFFFFFF\r
3175         };\r
3176 \r
3177         const video::SColor* const useColor = colors ? colors : temp;\r
3178 \r
3179 \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
3184 \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
3189 \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
3194 \r
3195 \r
3196         if (clipRect)\r
3197         {\r
3198                 if (!clipRect->isValid())\r
3199                         return;\r
3200 \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
3205         }\r
3206 \r
3207         video::SColor alphaTest;\r
3208         alphaTest.color = useColor[0].color & useColor[0].color & useColor[0].color & useColor[0].color;\r
3209 \r
3210 \r
3211         setRenderStates2DMode(alphaTest,texture, useAlphaChannelOfTexture);\r
3212 \r
3213         drawVertexPrimitiveList(Quad2DVertices, 4,\r
3214                 quad_triangle_indexList, 2,\r
3215                 EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);\r
3216 \r
3217         if (clipRect)\r
3218                 EyeSpace.TL_Flag &= ~TL_SCISSOR;\r
3219 \r
3220         setRenderStates3DMode();\r
3221 \r
3222 }\r
3223 \r
3224 \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
3229 {\r
3230         core::rect<s32> pos = position;\r
3231 \r
3232         if (clip)\r
3233                 pos.clipAgainst(*clip);\r
3234 \r
3235         if (!pos.isValid())\r
3236                 return;\r
3237 \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
3242 \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
3247 \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
3256 \r
3257 \r
3258         video::SColor alphaTest;\r
3259         alphaTest.color = colorLeftUp.color & colorRightUp.color & colorRightDown.color & colorLeftDown.color;\r
3260         setRenderStates2DMode(alphaTest, 0, 0);\r
3261 \r
3262         drawVertexPrimitiveList(Quad2DVertices, 4,\r
3263                 quad_triangle_indexList, 2,\r
3264                 EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);\r
3265 \r
3266         setRenderStates3DMode();\r
3267 \r
3268 }\r
3269 \r
3270 \r
3271 #endif // SOFTWARE_DRIVER_2_2D_AS_3D\r
3272 \r
3273 \r
3274 \r
3275 \r
3276 \r
3277 //! Draws a 2d line.\r
3278 void CBurningVideoDriver::draw2DLine(const core::position2d<s32>& start,\r
3279         const core::position2d<s32>& end,\r
3280         SColor color)\r
3281 {\r
3282         drawLine(RenderTargetSurface, start, end, color);\r
3283 }\r
3284 \r
3285 \r
3286 //! Draws a pixel\r
3287 void CBurningVideoDriver::drawPixel(u32 x, u32 y, const SColor& color)\r
3288 {\r
3289         RenderTargetSurface->setPixel(x, y, color, true);\r
3290 }\r
3291 \r
3292 \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
3296 {\r
3297         // make sure width and height are multiples of 2\r
3298         core::dimension2d<u32> realSize(size);\r
3299         /*\r
3300                 if (realSize.Width % 2)\r
3301                         realSize.Width += 1;\r
3302 \r
3303                 if (realSize.Height % 2)\r
3304                         realSize.Height += 1;\r
3305         */\r
3306         if (ScreenSize != realSize)\r
3307         {\r
3308                 if (ViewPort.getWidth() == (s32)ScreenSize.Width &&\r
3309                         ViewPort.getHeight() == (s32)ScreenSize.Height)\r
3310                 {\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
3315                 }\r
3316 \r
3317                 ScreenSize = realSize;\r
3318 \r
3319                 bool resetRT = (RenderTargetSurface == BackBuffer);\r
3320 \r
3321                 if (BackBuffer)\r
3322                         BackBuffer->drop();\r
3323                 BackBuffer = new CImage(SOFTWARE_DRIVER_2_RENDERTARGET_COLOR_FORMAT, realSize);\r
3324 \r
3325                 if (resetRT)\r
3326                         setRenderTargetImage2(BackBuffer);\r
3327         }\r
3328 }\r
3329 \r
3330 \r
3331 //! returns the current render target size\r
3332 const core::dimension2d<u32>& CBurningVideoDriver::getCurrentRenderTargetSize() const\r
3333 {\r
3334         return (RenderTargetSurface == BackBuffer) ? ScreenSize : RenderTargetSize;\r
3335 }\r
3336 \r
3337 \r
3338 \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
3342 {\r
3343         SColor color_end = color_start;\r
3344 \r
3345         VertexCache.primitiveHasVertex = 2;\r
3346         VertexCache.vType = E4VT_LINE;\r
3347 \r
3348         s4DVertex* v = Clipper.data;\r
3349 \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
3354 \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
3358 #endif\r
3359 \r
3360         size_t has_vertex_run;\r
3361         for (has_vertex_run = 0; has_vertex_run < VertexCache.primitiveHasVertex; has_vertex_run += 1)\r
3362         {\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
3365         }\r
3366 \r
3367         \r
3368         size_t vOut;\r
3369 \r
3370         // vertices count per line\r
3371         vOut = clipToFrustum(VertexCache.primitiveHasVertex);\r
3372         if (vOut < VertexCache.primitiveHasVertex)\r
3373                 return;\r
3374 \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
3377 \r
3378         // unproject vertex color\r
3379 #if 0\r
3380 #if BURNING_MATERIAL_MAX_COLORS > 0\r
3381         for (g = 0; g != vOut; g += 2)\r
3382         {\r
3383                 v[g + 1].Color[0].setA8R8G8B8(color.color);\r
3384         }\r
3385 #endif\r
3386 #endif\r
3387 \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
3392 \r
3393         shader->pushEdgeTest(1, 0, 1);\r
3394         shader->setRenderTarget(RenderTargetSurface, ViewPort, Interlaced);\r
3395 \r
3396         for (has_vertex_run = 0; (has_vertex_run + VertexCache.primitiveHasVertex) <= vOut; has_vertex_run += 1)\r
3397         {\r
3398                 shader->drawLine(v + s4DVertex_proj(has_vertex_run), v + s4DVertex_proj(has_vertex_run+1));\r
3399         }\r
3400 \r
3401         shader->popEdgeTest();\r
3402 \r
3403 }\r
3404 \r
3405 \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
3409 {\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
3418 #else\r
3419         return L"Burning's Video 0.52";\r
3420 #endif\r
3421 }\r
3422 \r
3423 //! Returns the graphics card vendor name.\r
3424 core::stringc CBurningVideoDriver::getVendorInfo()\r
3425 {\r
3426         return "Burning's Video: Ing. Thomas Alten (c) 2006-2020";\r
3427 }\r
3428 \r
3429 \r
3430 //! Returns type of video driver\r
3431 E_DRIVER_TYPE CBurningVideoDriver::getDriverType() const\r
3432 {\r
3433         return EDT_BURNINGSVIDEO;\r
3434 }\r
3435 \r
3436 \r
3437 //! returns color format\r
3438 ECOLOR_FORMAT CBurningVideoDriver::getColorFormat() const\r
3439 {\r
3440         return BackBuffer ? BackBuffer->getColorFormat() : CNullDriver::getColorFormat();\r
3441 }\r
3442 \r
3443 \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
3449 #endif\r
3450 )\r
3451 {\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
3457         addTexture(tex);\r
3458         tex->drop();\r
3459         return tex;\r
3460 }\r
3461 \r
3462 void CBurningVideoDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)\r
3463 {\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
3467 }\r
3468 \r
3469 #if 0\r
3470 void CBurningVideoDriver::saveBuffer()\r
3471 {\r
3472         static int shotCount = 0;\r
3473         char buf[256];\r
3474         if (BackBuffer)\r
3475         {\r
3476                 sprintf(buf, "shot/%04d_b.png", shotCount);\r
3477                 writeImageToFile(BackBuffer, buf);\r
3478         }\r
3479         if (StencilBuffer)\r
3480         {\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
3484         }\r
3485         shotCount += 1;\r
3486 }\r
3487 #endif\r
3488 \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
3491 {\r
3492         if (target != video::ERT_FRAME_BUFFER)\r
3493                 return 0;\r
3494 \r
3495         if (BackBuffer)\r
3496         {\r
3497                 IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension());\r
3498                 BackBuffer->copyTo(tmp);\r
3499                 return tmp;\r
3500         }\r
3501         else\r
3502                 return 0;\r
3503 }\r
3504 \r
3505 ITexture* CBurningVideoDriver::createDeviceDependentTexture(const io::path& name, IImage* image)\r
3506 {\r
3507         u32 flags =\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
3511 #else\r
3512                 | ((TextureCreationFlags & ETCF_AUTO_GENERATE_MIP_MAPS) ? CSoftwareTexture2::GEN_MIPMAP_AUTO : 0)\r
3513 #endif\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
3518 #endif\r
3519                 ;\r
3520 \r
3521         CSoftwareTexture2* texture = new CSoftwareTexture2(image, name, flags, this);\r
3522         return texture;\r
3523 }\r
3524 \r
3525 ITexture* CBurningVideoDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)\r
3526 {\r
3527         return 0;\r
3528 }\r
3529 \r
3530 //! Returns the maximum amount of primitives (mostly vertices) which\r
3531 //! the device is able to render with one drawIndexedTriangleList\r
3532 //! call.\r
3533 u32 CBurningVideoDriver::getMaximalPrimitiveCount() const\r
3534 {\r
3535         return 0x7FFFFFFF;\r
3536 }\r
3537 \r
3538 \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
3543 {\r
3544         const u32 count = triangles.size();\r
3545         if (!StencilBuffer || !count)\r
3546                 return;\r
3547 \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
3552 \r
3553         CurrentShader = BurningShader[ETR_STENCIL_SHADOW];\r
3554 \r
3555         CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort, Interlaced);\r
3556         CurrentShader->pushEdgeTest(Material.org.Wireframe, 0, 0);\r
3557 \r
3558         //setMaterial\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
3563 \r
3564         //glEnable(GL_DEPTH_CLAMP);\r
3565 \r
3566         if (zfail)\r
3567         {\r
3568                 Material.org.BackfaceCulling = false;\r
3569                 Material.org.FrontfaceCulling = true;\r
3570                 Material.CullFlag = CULL_FRONT | CULL_INVISIBLE;\r
3571 \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
3574 \r
3575                 Material.org.BackfaceCulling = true;\r
3576                 Material.org.FrontfaceCulling = false;\r
3577                 Material.CullFlag = CULL_BACK | CULL_INVISIBLE;\r
3578 \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
3581         }\r
3582         else // zpass\r
3583         {\r
3584                 Material.org.BackfaceCulling = true;\r
3585                 Material.org.FrontfaceCulling = false;\r
3586                 Material.CullFlag = CULL_BACK | CULL_INVISIBLE;\r
3587 \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
3590 \r
3591                 Material.org.BackfaceCulling = false;\r
3592                 Material.org.FrontfaceCulling = true;\r
3593                 Material.CullFlag = CULL_FRONT | CULL_INVISIBLE;\r
3594 \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
3597         }\r
3598         //glDisable(GL_DEPTH_CLAMP);\r
3599 \r
3600 }\r
3601 \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
3607 {\r
3608         if (!StencilBuffer)\r
3609                 return;\r
3610 \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
3614 \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
3618 \r
3619         interlace_scanline_data line;\r
3620         for (line.y = 0; line.y < h; line.y += SOFTWARE_DRIVER_2_STEP_Y)\r
3621         {\r
3622                 interlace_scanline\r
3623                 {\r
3624                         tVideoSample * dst = (tVideoSample*)RenderTargetSurface->getData() + (line.y * w);\r
3625                         const tStencilSample* stencil = (tStencilSample*)StencilBuffer->lock() + (line.y * w);\r
3626 \r
3627                         if (bit32)\r
3628                         {\r
3629                                 for (u32 x = 0; x < w; x += SOFTWARE_DRIVER_2_STEP_X)\r
3630                                 {\r
3631                                         if (stencil[x]) dst[x] = PixelBlend32(dst[x], src, alpha);\r
3632                                 }\r
3633                         }\r
3634                         else\r
3635                         {\r
3636                                 for (u32 x = 0; x < w; x += SOFTWARE_DRIVER_2_STEP_X)\r
3637                                 {\r
3638                                         if (stencil[x]) dst[x] = PixelBlend16(dst[x], src, alpha);\r
3639                                 }\r
3640                         }\r
3641 \r
3642                 }\r
3643         }\r
3644 \r
3645         if (clearStencilBuffer)\r
3646                 StencilBuffer->clear(0, Interlaced);\r
3647 }\r
3648 \r
3649 \r
3650 core::dimension2du CBurningVideoDriver::getMaxTextureSize() const\r
3651 {\r
3652         return core::dimension2du(SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE, SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE);\r
3653 }\r
3654 \r
3655 bool CBurningVideoDriver::queryTextureFormat(ECOLOR_FORMAT format) const\r
3656 {\r
3657         return format == SOFTWARE_DRIVER_2_RENDERTARGET_COLOR_FORMAT || format == SOFTWARE_DRIVER_2_TEXTURE_COLOR_FORMAT;\r
3658 }\r
3659 \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
3662 {\r
3663         return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation(); // || material.isTransparent();\r
3664 }\r
3665 #endif\r
3666 \r
3667 s32 CBurningVideoDriver::addShaderMaterial(const c8* vertexShaderProgram,\r
3668         const c8* pixelShaderProgram,\r
3669         IShaderConstantSetCallBack* callback,\r
3670         E_MATERIAL_TYPE baseMaterial,\r
3671         s32 userData)\r
3672 {\r
3673         s32 materialID = -1;\r
3674 \r
3675         IBurningShader* shader = new IBurningShader(\r
3676                 this, materialID,\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
3682 \r
3683         shader->drop();\r
3684 \r
3685         return materialID;\r
3686 }\r
3687 \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
3701         u32 verticesOut,\r
3702         IShaderConstantSetCallBack* callback,\r
3703         E_MATERIAL_TYPE baseMaterial,\r
3704         s32 userData\r
3705 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)\r
3706         , E_GPU_SHADING_LANGUAGE shadingLang\r
3707 #endif\r
3708 )\r
3709 {\r
3710         s32 materialID = -1;\r
3711 \r
3712         IBurningShader* shader = new IBurningShader(\r
3713                 this, materialID,\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
3719 \r
3720         shader->drop();\r
3721 \r
3722         return materialID;\r
3723 }\r
3724 \r
3725 \r
3726 void CBurningVideoDriver::setFallback_Material(E_MATERIAL_TYPE fallback_MaterialType)\r
3727 {\r
3728         //this should be in material....\r
3729         Material.Fallback_MaterialType = fallback_MaterialType;\r
3730 }\r
3731 \r
3732 void CBurningVideoDriver::setBasicRenderStates(const SMaterial& material,\r
3733         const SMaterial& lastMaterial,\r
3734         bool resetAllRenderstates)\r
3735 {\r
3736 \r
3737 }\r
3738 \r
3739 //! Return an index constant for the vertex shader based on a name.\r
3740 s32 CBurningVideoDriver::getVertexShaderConstantID(const c8* name)\r
3741 {\r
3742         return -1;\r
3743 }\r
3744 \r
3745 bool CBurningVideoDriver::setVertexShaderConstant(s32 index, const f32* floats, int count)\r
3746 {\r
3747         return true;\r
3748 }\r
3749 \r
3750 bool CBurningVideoDriver::setVertexShaderConstant(s32 index, const s32* ints, int count)\r
3751 {\r
3752         return true;\r
3753 }\r
3754 \r
3755 bool CBurningVideoDriver::setVertexShaderConstant(s32 index, const u32* ints, int count)\r
3756 {\r
3757         return true;\r
3758 }\r
3759 \r
3760 void CBurningVideoDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
3761 {\r
3762 }\r
3763 \r
3764 //! Return an index constant for the pixel shader based on a name.\r
3765 s32 CBurningVideoDriver::getPixelShaderConstantID(const c8* name)\r
3766 {\r
3767         return -1;\r
3768 }\r
3769 \r
3770 bool CBurningVideoDriver::setPixelShaderConstant(s32 index, const f32* floats, int count)\r
3771 {\r
3772         return false;\r
3773 }\r
3774 \r
3775 bool CBurningVideoDriver::setPixelShaderConstant(s32 index, const s32* ints, int count)\r
3776 {\r
3777         return false;\r
3778 }\r
3779 \r
3780 bool CBurningVideoDriver::setPixelShaderConstant(s32 index, const u32* ints, int count)\r
3781 {\r
3782         return false;\r
3783 }\r
3784 \r
3785 void CBurningVideoDriver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount = 1)\r
3786 {\r
3787 }\r
3788 \r
3789 //! Get pointer to the IVideoDriver interface\r
3790 /** \return Pointer to the IVideoDriver interface */\r
3791 IVideoDriver* CBurningVideoDriver::getVideoDriver()\r
3792 {\r
3793         return this;\r
3794 }\r
3795 \r
3796 } // end namespace video\r
3797 } // end namespace irr\r
3798 \r
3799 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_\r
3800 \r
3801 \r
3802 namespace irr\r
3803 {\r
3804 namespace video\r
3805 {\r
3806 \r
3807 //! creates a video driver\r
3808 IVideoDriver* createBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter)\r
3809 {\r
3810 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_\r
3811         return new CBurningVideoDriver(params, io, presenter);\r
3812 #else\r
3813         return 0;\r
3814 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_\r
3815 }\r
3816 \r
3817 \r
3818 \r
3819 } // end namespace video\r
3820 } // end namespace irr\r
3821 \r