]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/IBurningShader.cpp
Fix Windows, Android build
[irrlicht.git] / source / Irrlicht / IBurningShader.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 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_\r
7 \r
8 #include "SoftwareDriver2_compile_config.h"\r
9 #include "IBurningShader.h"\r
10 #include "CSoftwareDriver2.h"\r
11 #include "IShaderConstantSetCallBack.h"\r
12 \r
13 namespace irr\r
14 {\r
15 namespace video\r
16 {\r
17 \r
18 const tFixPointu IBurningShader::dithermask[] =\r
19 {\r
20         0x00,0x80,0x20,0xa0,\r
21         0xc0,0x40,0xe0,0x60,\r
22         0x30,0xb0,0x10,0x90,\r
23         0xf0,0x70,0xd0,0x50\r
24 };\r
25 \r
26 void IBurningShader::constructor_IBurningShader(CBurningVideoDriver* driver)\r
27 {\r
28 #ifdef _DEBUG\r
29         setDebugName("IBurningShader");\r
30 #endif\r
31 \r
32 #if defined(ENV64BIT)\r
33         if (((unsigned long long)&scan & 15) || ((unsigned long long)&line & 15))\r
34         {\r
35                 os::Printer::log("BurningVideo Shader not 16 byte aligned", ELL_ERROR);\r
36                 _IRR_DEBUG_BREAK_IF(1);\r
37         }\r
38 #endif\r
39 \r
40         Interlaced.enable = 0;\r
41         Interlaced.bypass = 1;\r
42         Interlaced.nr = 0;\r
43 \r
44         EdgeTestPass = edge_test_pass;\r
45         EdgeTestPass_stack = edge_test_pass;\r
46 \r
47         for (u32 i = 0; i < BURNING_MATERIAL_MAX_TEXTURES; ++i)\r
48         {\r
49                 IT[i].Texture = 0;\r
50         }\r
51 \r
52         Driver = driver;\r
53         CallBack = 0;\r
54 \r
55         RenderTarget = 0;\r
56         ColorMask = COLOR_BRIGHT_WHITE;\r
57         DepthBuffer = (CDepthBuffer*)driver->getDepthBuffer();\r
58         if (DepthBuffer)\r
59                 DepthBuffer->grab();\r
60 \r
61         Stencil = (CStencilBuffer*)driver->getStencilBuffer();\r
62         if (Stencil)\r
63                 Stencil->grab();\r
64 \r
65         stencilOp[0] = StencilOp_KEEP;\r
66         stencilOp[1] = StencilOp_KEEP;\r
67         stencilOp[2] = StencilOp_KEEP;\r
68         AlphaRef = 0;\r
69         RenderPass_ShaderIsTransparent = 0;\r
70         PrimitiveColor = COLOR_BRIGHT_WHITE;\r
71         TL_Flag = 0;\r
72 }\r
73 \r
74 IBurningShader::IBurningShader(CBurningVideoDriver* driver)\r
75 {\r
76         constructor_IBurningShader(driver);\r
77 }\r
78 \r
79 //! Constructor\r
80 IBurningShader::IBurningShader(\r
81         CBurningVideoDriver* driver,\r
82         s32& outMaterialTypeNr,\r
83         const c8* vertexShaderProgram,\r
84         const c8* vertexShaderEntryPointName,\r
85         E_VERTEX_SHADER_TYPE vsCompileTarget,\r
86         const c8* pixelShaderProgram,\r
87         const c8* pixelShaderEntryPointName,\r
88         E_PIXEL_SHADER_TYPE psCompileTarget,\r
89         const c8* geometryShaderProgram,\r
90         const c8* geometryShaderEntryPointName,\r
91         E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
92         scene::E_PRIMITIVE_TYPE inType,\r
93         scene::E_PRIMITIVE_TYPE outType,\r
94         u32 verticesOut,\r
95         IShaderConstantSetCallBack* callback,\r
96         E_MATERIAL_TYPE baseMaterial,\r
97         s32 userData)\r
98 {\r
99         constructor_IBurningShader(driver);\r
100         BaseMaterial = baseMaterial;\r
101         UserData = userData;\r
102         CallBack = callback;\r
103         if (CallBack)\r
104                 CallBack->grab();\r
105 \r
106         // register myself as new material\r
107         outMaterialTypeNr = Driver->addMaterialRenderer(this);\r
108 }\r
109 \r
110 \r
111 //! destructor\r
112 IBurningShader::~IBurningShader()\r
113 {\r
114         if (RenderTarget)\r
115                 RenderTarget->drop();\r
116 \r
117         if (DepthBuffer)\r
118                 DepthBuffer->drop();\r
119 \r
120         if (Stencil)\r
121                 Stencil->drop();\r
122 \r
123         for (u32 i = 0; i != BURNING_MATERIAL_MAX_TEXTURES; ++i)\r
124         {\r
125                 if (IT[i].Texture)\r
126                         IT[i].Texture->drop();\r
127         }\r
128 \r
129         if (CallBack)\r
130                 CallBack->drop();\r
131 \r
132 }\r
133 \r
134 //! sets a render target\r
135 void IBurningShader::setRenderTarget(video::IImage* surface, const core::rect<s32>& viewPort, const interlaced_control interlaced)\r
136 {\r
137         Interlaced = interlaced;\r
138 \r
139         if (RenderTarget)\r
140                 RenderTarget->drop();\r
141 \r
142         RenderTarget = (video::CImage*) surface;\r
143 \r
144         if (RenderTarget)\r
145         {\r
146                 RenderTarget->grab();\r
147 \r
148                 //(fp24*) DepthBuffer->lock() = DepthBuffer->lock();\r
149         }\r
150 }\r
151 \r
152 \r
153 //! sets the Texture\r
154 void IBurningShader::setTextureParam(const size_t stage, video::CSoftwareTexture2* texture, s32 lodFactor)\r
155 {\r
156         sInternalTexture* it = &IT[stage];\r
157 \r
158         if (it->Texture)\r
159                 it->Texture->drop();\r
160 \r
161         it->Texture = texture;\r
162 \r
163         if (it->Texture)\r
164         {\r
165                 it->Texture->grab();\r
166 \r
167                 // select mignify and magnify\r
168                 it->lodFactor = lodFactor;\r
169 \r
170                 //only mipmap chain (means positive lodFactor)\r
171                 u32 existing_level = it->Texture->getMipmapLevel(lodFactor);\r
172 #if !defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)\r
173                 it->data = (tVideoSample*)it->Texture->lock(ETLM_READ_ONLY, existing_level, 0);\r
174 #else\r
175                 it->data = (tVideoSample*)it->Texture->lock(ETLM_READ_ONLY, existing_level);\r
176 #endif\r
177 \r
178                 // prepare for optimal fixpoint\r
179                 it->pitchlog2 = s32_log2_s32(it->Texture->getPitch());\r
180 \r
181                 const core::dimension2d<u32>& dim = it->Texture->getSize();\r
182                 it->textureXMask = s32_to_fixPoint(dim.Width - 1) & FIX_POINT_UNSIGNED_MASK;\r
183                 it->textureYMask = s32_to_fixPoint(dim.Height - 1) & FIX_POINT_UNSIGNED_MASK;\r
184         }\r
185 }\r
186 \r
187 //emulate a line with degenerate triangle and special shader mode (not perfect...)\r
188 void IBurningShader::drawLine(const s4DVertex* a, const s4DVertex* b)\r
189 {\r
190         sVec2 d;\r
191         d.x = b->Pos.x - a->Pos.x;      d.x *= d.x;\r
192         d.y = b->Pos.y - a->Pos.y;      d.y *= d.y;\r
193         //if ( d.x * d.y < 0.001f ) return;\r
194 \r
195         if (a->Pos.x > b->Pos.x) swapVertexPointer(&a, &b);\r
196 \r
197         s4DVertex c = *a;\r
198 \r
199         const f32 w = (f32)RenderTarget->getDimension().Width - 1;\r
200         const f32 h = (f32)RenderTarget->getDimension().Height - 1;\r
201 \r
202         if (d.x < 2.f) { c.Pos.x = b->Pos.x + 1.f + d.y; if (c.Pos.x > w) c.Pos.x = w; }\r
203         else c.Pos.x = b->Pos.x;\r
204         if (d.y < 2.f) { c.Pos.y = b->Pos.y + 1.f; if (c.Pos.y > h) c.Pos.y = h; EdgeTestPass |= edge_test_first_line; }\r
205 \r
206         drawTriangle(a, b, &c);\r
207         EdgeTestPass &= ~edge_test_first_line;\r
208 \r
209 }\r
210 \r
211 void IBurningShader::drawPoint(const s4DVertex* a)\r
212 {\r
213 }\r
214 \r
215 void IBurningShader::drawWireFrameTriangle(const s4DVertex* a, const s4DVertex* b, const s4DVertex* c)\r
216 {\r
217         if (EdgeTestPass & edge_test_pass) drawTriangle(a, b, c);\r
218         else if (EdgeTestPass & edge_test_point)\r
219         {\r
220                 drawPoint(a);\r
221                 drawPoint(b);\r
222                 drawPoint(c);\r
223         }\r
224         else\r
225         {\r
226                 drawLine(a, b);\r
227                 drawLine(b, c);\r
228                 drawLine(a, c);\r
229         }\r
230 }\r
231 \r
232 \r
233 void IBurningShader::OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,\r
234         bool resetAllRenderstates, IMaterialRendererServices* services)\r
235 {\r
236         if (Driver)\r
237                 Driver->setFallback_Material(BaseMaterial);\r
238         services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);\r
239         if (CallBack)\r
240                 CallBack->OnSetMaterial(material);\r
241 \r
242 }\r
243 \r
244 void IBurningShader::OnUnsetMaterial()\r
245 {\r
246 }\r
247 \r
248 bool IBurningShader::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)\r
249 {\r
250         // call callback to set shader constants\r
251         if (CallBack)\r
252                 CallBack->OnSetConstants(this, UserData);\r
253         return true;\r
254 }\r
255 \r
256 \r
257 //! Returns if the material is transparent.\r
258 bool IBurningShader::isTransparent() const\r
259 {\r
260         return RenderPass_ShaderIsTransparent != 0;\r
261 }\r
262 \r
263 //! Access the callback provided by the users when creating shader materials\r
264 IShaderConstantSetCallBack* IBurningShader::getShaderConstantSetCallBack() const\r
265 {\r
266         return CallBack;\r
267 }\r
268 \r
269 // implementations for the render services\r
270 void IBurningShader::setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial, bool resetAllRenderstates)\r
271 {\r
272         // forward\r
273         Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);\r
274 }\r
275 \r
276 s32 IBurningShader::getShaderConstantID(EBurningUniformFlags flags, const c8* name)\r
277 {\r
278         if (!name || !name[0])\r
279                 return -1;\r
280 \r
281         BurningUniform add;\r
282         tiny_strcpy(add.name, name);\r
283         add.type = flags;\r
284 \r
285         s32 index = UniformInfo.linear_search(add);\r
286         if (index < 0)\r
287         {\r
288                 UniformInfo.push_back(add);\r
289                 index = UniformInfo.size() - 1;\r
290         }\r
291 \r
292         return index;\r
293 }\r
294 \r
295 const char* tiny_itoa(s32 value, int base)\r
296 {\r
297         static char b[32];\r
298         int p = 31;\r
299 \r
300         //int sign = 0;\r
301         //if (value < 0) { sign = 1; value = -value; }\r
302 \r
303         b[p] = '\0';\r
304         do {\r
305                 b[--p] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[value % base];\r
306                 value /= base;\r
307         } while (value && p > 0);\r
308 \r
309         //if (sign && p > 0) { b[--p] = '-'; }\r
310 \r
311         return b + p;\r
312 }\r
313 \r
314 bool IBurningShader::setShaderConstantID(EBurningUniformFlags flags, s32 index, const void* data, size_t u32_count)\r
315 {\r
316         if ((u32)index >= UniformInfo.size())\r
317                 return false;\r
318 #if 0\r
319         BurningUniform add;\r
320         while ((u32)index >= UniformInfo.size())\r
321         {\r
322                 tiny_strcpy(add.name, tiny_itoa(UniformInfo.size(), 10));\r
323                 add.type = flags;\r
324                 UniformInfo.push_back(add);\r
325         }\r
326 #endif\r
327 \r
328         BurningUniform& use = UniformInfo[index];\r
329         use.type = flags;\r
330 \r
331         const u32* s = (u32*)data;\r
332         u32* d = (u32*)use.data;\r
333 \r
334         if (!s) u32_count = 0;\r
335         if (u32_count > array_size(use.data)) u32_count = array_size(use.data);\r
336         for (size_t i = 0; i < u32_count; ++i)\r
337         {\r
338                 d[i] = s[i];\r
339         }\r
340 \r
341         return true;\r
342 }\r
343 \r
344 \r
345 s32 IBurningShader::getVertexShaderConstantID(const c8* name)\r
346 {\r
347         return getShaderConstantID(BL_VERTEX_PROGRAM, name);\r
348 }\r
349 \r
350 s32 IBurningShader::getPixelShaderConstantID(const c8* name)\r
351 {\r
352         return getShaderConstantID(BL_FRAGMENT_PROGRAM, name);\r
353 }\r
354 \r
355 void IBurningShader::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
356 {\r
357         c8 name[BL_ACTIVE_UNIFORM_MAX_LENGTH];\r
358         tiny_strcpy(name, tiny_itoa(startRegister, 10));\r
359 \r
360         setShaderConstantID(BL_VERTEX_FLOAT, getShaderConstantID(BL_VERTEX_PROGRAM, name), data, constantAmount);\r
361 }\r
362 \r
363 void IBurningShader::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
364 {\r
365         c8 name[BL_ACTIVE_UNIFORM_MAX_LENGTH];\r
366         tiny_strcpy(name, tiny_itoa(startRegister, 10));\r
367 \r
368         setShaderConstantID(BL_FRAGMENT_FLOAT, getShaderConstantID(BL_FRAGMENT_PROGRAM, name), data, constantAmount);\r
369 }\r
370 \r
371 bool IBurningShader::setVertexShaderConstant(s32 index, const f32* floats, int count)\r
372 {\r
373         return setShaderConstantID(BL_VERTEX_FLOAT, index, floats, count);\r
374 }\r
375 \r
376 bool IBurningShader::setVertexShaderConstant(s32 index, const s32* ints, int count)\r
377 {\r
378         return setShaderConstantID(BL_VERTEX_INT, index, ints, count);\r
379 }\r
380 \r
381 bool IBurningShader::setVertexShaderConstant(s32 index, const u32* ints, int count)\r
382 {\r
383         return setShaderConstantID(BL_VERTEX_UINT, index, ints, count);\r
384 }\r
385 \r
386 bool IBurningShader::setPixelShaderConstant(s32 index, const f32* floats, int count)\r
387 {\r
388         return setShaderConstantID(BL_FRAGMENT_FLOAT, index, floats, count);\r
389 }\r
390 \r
391 bool IBurningShader::setPixelShaderConstant(s32 index, const s32* ints, int count)\r
392 {\r
393         return setShaderConstantID(BL_FRAGMENT_INT, index, ints, count);\r
394 }\r
395 \r
396 bool IBurningShader::setPixelShaderConstant(s32 index, const u32* ints, int count)\r
397 {\r
398         return setShaderConstantID(BL_FRAGMENT_UINT, index, ints, count);\r
399 }\r
400 \r
401 void IBurningShader::setStencilOp(eBurningStencilOp sfail, eBurningStencilOp dpfail, eBurningStencilOp dppass)\r
402 {\r
403         stencilOp[0] = sfail;\r
404         stencilOp[1] = dpfail;\r
405         stencilOp[2] = dppass;\r
406 }\r
407 \r
408 \r
409 IVideoDriver* IBurningShader::getVideoDriver()\r
410 {\r
411         return Driver;\r
412 }\r
413 \r
414 \r
415 } // end namespace video\r
416 } // end namespace irr\r
417 \r
418 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_\r