1 // Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "IrrCompileConfig.h"
\r
6 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
8 #include "SoftwareDriver2_compile_config.h"
\r
9 #include "IBurningShader.h"
\r
10 #include "CSoftwareDriver2.h"
\r
11 #include "IShaderConstantSetCallBack.h"
\r
18 const tFixPointu IBurningShader::dithermask[] =
\r
20 0x00,0x80,0x20,0xa0,
\r
21 0xc0,0x40,0xe0,0x60,
\r
22 0x30,0xb0,0x10,0x90,
\r
26 void IBurningShader::constructor_IBurningShader(CBurningVideoDriver* driver)
\r
29 setDebugName("IBurningShader");
\r
32 #if defined(ENV64BIT)
\r
33 if (((unsigned long long)&scan & 15) || ((unsigned long long)&line & 15))
\r
35 os::Printer::log("BurningVideo Shader not 16 byte aligned", ELL_ERROR);
\r
36 _IRR_DEBUG_BREAK_IF(1);
\r
40 Interlaced.enable = 0;
\r
41 Interlaced.bypass = 1;
\r
44 EdgeTestPass = edge_test_pass;
\r
45 EdgeTestPass_stack = edge_test_pass;
\r
47 for (u32 i = 0; i < BURNING_MATERIAL_MAX_TEXTURES; ++i)
\r
56 ColorMask = COLOR_BRIGHT_WHITE;
\r
57 DepthBuffer = (CDepthBuffer*)driver->getDepthBuffer();
\r
59 DepthBuffer->grab();
\r
61 Stencil = (CStencilBuffer*)driver->getStencilBuffer();
\r
65 stencilOp[0] = StencilOp_KEEP;
\r
66 stencilOp[1] = StencilOp_KEEP;
\r
67 stencilOp[2] = StencilOp_KEEP;
\r
69 RenderPass_ShaderIsTransparent = 0;
\r
70 PrimitiveColor = COLOR_BRIGHT_WHITE;
\r
74 IBurningShader::IBurningShader(CBurningVideoDriver* driver)
\r
76 constructor_IBurningShader(driver);
\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
95 IShaderConstantSetCallBack* callback,
\r
96 E_MATERIAL_TYPE baseMaterial,
\r
99 constructor_IBurningShader(driver);
\r
100 BaseMaterial = baseMaterial;
\r
101 UserData = userData;
\r
102 CallBack = callback;
\r
106 // register myself as new material
\r
107 outMaterialTypeNr = Driver->addMaterialRenderer(this);
\r
112 IBurningShader::~IBurningShader()
\r
115 RenderTarget->drop();
\r
118 DepthBuffer->drop();
\r
123 for (u32 i = 0; i != BURNING_MATERIAL_MAX_TEXTURES; ++i)
\r
126 IT[i].Texture->drop();
\r
134 //! sets a render target
\r
135 void IBurningShader::setRenderTarget(video::IImage* surface, const core::rect<s32>& viewPort, const interlaced_control interlaced)
\r
137 Interlaced = interlaced;
\r
140 RenderTarget->drop();
\r
142 RenderTarget = (video::CImage*) surface;
\r
146 RenderTarget->grab();
\r
148 //(fp24*) DepthBuffer->lock() = DepthBuffer->lock();
\r
153 //! sets the Texture
\r
154 void IBurningShader::setTextureParam(const size_t stage, video::CSoftwareTexture2* texture, s32 lodFactor)
\r
156 sInternalTexture* it = &IT[stage];
\r
159 it->Texture->drop();
\r
161 it->Texture = texture;
\r
165 it->Texture->grab();
\r
167 // select mignify and magnify
\r
168 it->lodFactor = lodFactor;
\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
175 it->data = (tVideoSample*)it->Texture->lock(ETLM_READ_ONLY, existing_level);
\r
178 // prepare for optimal fixpoint
\r
179 it->pitchlog2 = s32_log2_s32(it->Texture->getPitch());
\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
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
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
195 if (a->Pos.x > b->Pos.x) swapVertexPointer(&a, &b);
\r
199 const f32 w = (f32)RenderTarget->getDimension().Width - 1;
\r
200 const f32 h = (f32)RenderTarget->getDimension().Height - 1;
\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
206 drawTriangle(a, b, &c);
\r
207 EdgeTestPass &= ~edge_test_first_line;
\r
211 void IBurningShader::drawPoint(const s4DVertex* a)
\r
215 void IBurningShader::drawWireFrameTriangle(const s4DVertex* a, const s4DVertex* b, const s4DVertex* c)
\r
217 if (EdgeTestPass & edge_test_pass) drawTriangle(a, b, c);
\r
218 else if (EdgeTestPass & edge_test_point)
\r
233 void IBurningShader::OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
\r
234 bool resetAllRenderstates, IMaterialRendererServices* services)
\r
237 Driver->setFallback_Material(BaseMaterial);
\r
238 services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
\r
240 CallBack->OnSetMaterial(material);
\r
244 void IBurningShader::OnUnsetMaterial()
\r
248 bool IBurningShader::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
\r
250 // call callback to set shader constants
\r
252 CallBack->OnSetConstants(this, UserData);
\r
257 //! Returns if the material is transparent.
\r
258 bool IBurningShader::isTransparent() const
\r
260 return RenderPass_ShaderIsTransparent != 0;
\r
263 //! Access the callback provided by the users when creating shader materials
\r
264 IShaderConstantSetCallBack* IBurningShader::getShaderConstantSetCallBack() const
\r
269 // implementations for the render services
\r
270 void IBurningShader::setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial, bool resetAllRenderstates)
\r
273 Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
\r
276 s32 IBurningShader::getShaderConstantID(EBurningUniformFlags flags, const c8* name)
\r
278 if (!name || !name[0])
\r
281 BurningUniform add;
\r
282 tiny_strcpy(add.name, name);
\r
285 s32 index = UniformInfo.linear_search(add);
\r
288 UniformInfo.push_back(add);
\r
289 index = UniformInfo.size() - 1;
\r
295 const char* tiny_itoa(s32 value, int base)
\r
301 //if (value < 0) { sign = 1; value = -value; }
\r
305 b[--p] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[value % base];
\r
307 } while (value && p > 0);
\r
309 //if (sign && p > 0) { b[--p] = '-'; }
\r
314 bool IBurningShader::setShaderConstantID(EBurningUniformFlags flags, s32 index, const void* data, size_t u32_count)
\r
316 if ((u32)index >= UniformInfo.size())
\r
319 BurningUniform add;
\r
320 while ((u32)index >= UniformInfo.size())
\r
322 tiny_strcpy(add.name, tiny_itoa(UniformInfo.size(), 10));
\r
324 UniformInfo.push_back(add);
\r
328 BurningUniform& use = UniformInfo[index];
\r
331 const u32* s = (u32*)data;
\r
332 u32* d = (u32*)use.data;
\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
345 s32 IBurningShader::getVertexShaderConstantID(const c8* name)
\r
347 return getShaderConstantID(BL_VERTEX_PROGRAM, name);
\r
350 s32 IBurningShader::getPixelShaderConstantID(const c8* name)
\r
352 return getShaderConstantID(BL_FRAGMENT_PROGRAM, name);
\r
355 void IBurningShader::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
357 c8 name[BL_ACTIVE_UNIFORM_MAX_LENGTH];
\r
358 tiny_strcpy(name, tiny_itoa(startRegister, 10));
\r
360 setShaderConstantID(BL_VERTEX_FLOAT, getShaderConstantID(BL_VERTEX_PROGRAM, name), data, constantAmount);
\r
363 void IBurningShader::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
365 c8 name[BL_ACTIVE_UNIFORM_MAX_LENGTH];
\r
366 tiny_strcpy(name, tiny_itoa(startRegister, 10));
\r
368 setShaderConstantID(BL_FRAGMENT_FLOAT, getShaderConstantID(BL_FRAGMENT_PROGRAM, name), data, constantAmount);
\r
371 bool IBurningShader::setVertexShaderConstant(s32 index, const f32* floats, int count)
\r
373 return setShaderConstantID(BL_VERTEX_FLOAT, index, floats, count);
\r
376 bool IBurningShader::setVertexShaderConstant(s32 index, const s32* ints, int count)
\r
378 return setShaderConstantID(BL_VERTEX_INT, index, ints, count);
\r
381 bool IBurningShader::setVertexShaderConstant(s32 index, const u32* ints, int count)
\r
383 return setShaderConstantID(BL_VERTEX_UINT, index, ints, count);
\r
386 bool IBurningShader::setPixelShaderConstant(s32 index, const f32* floats, int count)
\r
388 return setShaderConstantID(BL_FRAGMENT_FLOAT, index, floats, count);
\r
391 bool IBurningShader::setPixelShaderConstant(s32 index, const s32* ints, int count)
\r
393 return setShaderConstantID(BL_FRAGMENT_INT, index, ints, count);
\r
396 bool IBurningShader::setPixelShaderConstant(s32 index, const u32* ints, int count)
\r
398 return setShaderConstantID(BL_FRAGMENT_UINT, index, ints, count);
\r
401 void IBurningShader::setStencilOp(eBurningStencilOp sfail, eBurningStencilOp dpfail, eBurningStencilOp dppass)
\r
403 stencilOp[0] = sfail;
\r
404 stencilOp[1] = dpfail;
\r
405 stencilOp[2] = dppass;
\r
409 IVideoDriver* IBurningShader::getVideoDriver()
\r
415 } // end namespace video
\r
416 } // end namespace irr
\r
418 #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r