mirror of
https://github.com/minetest/irrlicht.git
synced 2024-11-09 11:50:37 +01:00
12a94ed5b7
git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6191 dfc29bdd-3216-0410-991c-e03cc46cb475
419 lines
10 KiB
C++
419 lines
10 KiB
C++
// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
|
|
// This file is part of the "Irrlicht Engine".
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
#include "IrrCompileConfig.h"
|
|
#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
|
|
|
|
#include "SoftwareDriver2_compile_config.h"
|
|
#include "IBurningShader.h"
|
|
#include "CSoftwareDriver2.h"
|
|
#include "IShaderConstantSetCallBack.h"
|
|
|
|
namespace irr
|
|
{
|
|
namespace video
|
|
{
|
|
|
|
const tFixPointu IBurningShader::dithermask[] =
|
|
{
|
|
0x00,0x80,0x20,0xa0,
|
|
0xc0,0x40,0xe0,0x60,
|
|
0x30,0xb0,0x10,0x90,
|
|
0xf0,0x70,0xd0,0x50
|
|
};
|
|
|
|
void IBurningShader::constructor_IBurningShader(CBurningVideoDriver* driver)
|
|
{
|
|
#ifdef _DEBUG
|
|
setDebugName("IBurningShader");
|
|
#endif
|
|
|
|
#if defined(ENV64BIT)
|
|
if (((unsigned long long)&scan & 15) || ((unsigned long long)&line & 15))
|
|
{
|
|
os::Printer::log("BurningVideo Shader not 16 byte aligned", ELL_ERROR);
|
|
_IRR_DEBUG_BREAK_IF(1);
|
|
}
|
|
#endif
|
|
|
|
Interlaced.enable = 0;
|
|
Interlaced.bypass = 1;
|
|
Interlaced.nr = 0;
|
|
|
|
EdgeTestPass = edge_test_pass;
|
|
EdgeTestPass_stack = edge_test_pass;
|
|
|
|
for (u32 i = 0; i < BURNING_MATERIAL_MAX_TEXTURES; ++i)
|
|
{
|
|
IT[i].Texture = 0;
|
|
}
|
|
|
|
Driver = driver;
|
|
CallBack = 0;
|
|
|
|
RenderTarget = 0;
|
|
ColorMask = COLOR_BRIGHT_WHITE;
|
|
DepthBuffer = (CDepthBuffer*)driver->getDepthBuffer();
|
|
if (DepthBuffer)
|
|
DepthBuffer->grab();
|
|
|
|
Stencil = (CStencilBuffer*)driver->getStencilBuffer();
|
|
if (Stencil)
|
|
Stencil->grab();
|
|
|
|
stencilOp[0] = StencilOp_KEEP;
|
|
stencilOp[1] = StencilOp_KEEP;
|
|
stencilOp[2] = StencilOp_KEEP;
|
|
AlphaRef = 0;
|
|
RenderPass_ShaderIsTransparent = 0;
|
|
PrimitiveColor = COLOR_BRIGHT_WHITE;
|
|
TL_Flag = 0;
|
|
}
|
|
|
|
IBurningShader::IBurningShader(CBurningVideoDriver* driver)
|
|
{
|
|
constructor_IBurningShader(driver);
|
|
}
|
|
|
|
//! Constructor
|
|
IBurningShader::IBurningShader(
|
|
CBurningVideoDriver* driver,
|
|
s32& outMaterialTypeNr,
|
|
const c8* vertexShaderProgram,
|
|
const c8* vertexShaderEntryPointName,
|
|
E_VERTEX_SHADER_TYPE vsCompileTarget,
|
|
const c8* pixelShaderProgram,
|
|
const c8* pixelShaderEntryPointName,
|
|
E_PIXEL_SHADER_TYPE psCompileTarget,
|
|
const c8* geometryShaderProgram,
|
|
const c8* geometryShaderEntryPointName,
|
|
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
|
|
scene::E_PRIMITIVE_TYPE inType,
|
|
scene::E_PRIMITIVE_TYPE outType,
|
|
u32 verticesOut,
|
|
IShaderConstantSetCallBack* callback,
|
|
E_MATERIAL_TYPE baseMaterial,
|
|
s32 userData)
|
|
{
|
|
constructor_IBurningShader(driver);
|
|
BaseMaterial = baseMaterial;
|
|
UserData = userData;
|
|
CallBack = callback;
|
|
if (CallBack)
|
|
CallBack->grab();
|
|
|
|
// register myself as new material
|
|
outMaterialTypeNr = Driver->addMaterialRenderer(this);
|
|
}
|
|
|
|
|
|
//! destructor
|
|
IBurningShader::~IBurningShader()
|
|
{
|
|
if (RenderTarget)
|
|
RenderTarget->drop();
|
|
|
|
if (DepthBuffer)
|
|
DepthBuffer->drop();
|
|
|
|
if (Stencil)
|
|
Stencil->drop();
|
|
|
|
for (u32 i = 0; i != BURNING_MATERIAL_MAX_TEXTURES; ++i)
|
|
{
|
|
if (IT[i].Texture)
|
|
IT[i].Texture->drop();
|
|
}
|
|
|
|
if (CallBack)
|
|
CallBack->drop();
|
|
|
|
}
|
|
|
|
//! sets a render target
|
|
void IBurningShader::setRenderTarget(video::IImage* surface, const core::rect<s32>& viewPort, const interlaced_control interlaced)
|
|
{
|
|
Interlaced = interlaced;
|
|
|
|
if (RenderTarget)
|
|
RenderTarget->drop();
|
|
|
|
RenderTarget = (video::CImage*) surface;
|
|
|
|
if (RenderTarget)
|
|
{
|
|
RenderTarget->grab();
|
|
|
|
//(fp24*) DepthBuffer->lock() = DepthBuffer->lock();
|
|
}
|
|
}
|
|
|
|
|
|
//! sets the Texture
|
|
void IBurningShader::setTextureParam(const size_t stage, video::CSoftwareTexture2* texture, s32 lodFactor)
|
|
{
|
|
sInternalTexture* it = &IT[stage];
|
|
|
|
if (it->Texture)
|
|
it->Texture->drop();
|
|
|
|
it->Texture = texture;
|
|
|
|
if (it->Texture)
|
|
{
|
|
it->Texture->grab();
|
|
|
|
// select mignify and magnify
|
|
it->lodFactor = lodFactor;
|
|
|
|
//only mipmap chain (means positive lodFactor)
|
|
u32 existing_level = it->Texture->getMipmapLevel(lodFactor);
|
|
#if !defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)
|
|
it->data = (tVideoSample*)it->Texture->lock(ETLM_READ_ONLY, existing_level, 0);
|
|
#else
|
|
it->data = (tVideoSample*)it->Texture->lock(ETLM_READ_ONLY, existing_level);
|
|
#endif
|
|
|
|
// prepare for optimal fixpoint
|
|
it->pitchlog2 = s32_log2_s32(it->Texture->getPitch());
|
|
|
|
const core::dimension2d<u32>& dim = it->Texture->getSize();
|
|
it->textureXMask = s32_to_fixPoint(dim.Width - 1) & FIX_POINT_UNSIGNED_MASK;
|
|
it->textureYMask = s32_to_fixPoint(dim.Height - 1) & FIX_POINT_UNSIGNED_MASK;
|
|
}
|
|
}
|
|
|
|
//emulate a line with degenerate triangle and special shader mode (not perfect...)
|
|
void IBurningShader::drawLine(const s4DVertex* a, const s4DVertex* b)
|
|
{
|
|
sVec2 d;
|
|
d.x = b->Pos.x - a->Pos.x; d.x *= d.x;
|
|
d.y = b->Pos.y - a->Pos.y; d.y *= d.y;
|
|
//if ( d.x * d.y < 0.001f ) return;
|
|
|
|
if (a->Pos.x > b->Pos.x) swapVertexPointer(&a, &b);
|
|
|
|
s4DVertex c = *a;
|
|
|
|
const f32 w = (f32)RenderTarget->getDimension().Width - 1;
|
|
const f32 h = (f32)RenderTarget->getDimension().Height - 1;
|
|
|
|
if (d.x < 2.f) { c.Pos.x = b->Pos.x + 1.f + d.y; if (c.Pos.x > w) c.Pos.x = w; }
|
|
else c.Pos.x = b->Pos.x;
|
|
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; }
|
|
|
|
drawTriangle(a, b, &c);
|
|
EdgeTestPass &= ~edge_test_first_line;
|
|
|
|
}
|
|
|
|
void IBurningShader::drawPoint(const s4DVertex* a)
|
|
{
|
|
}
|
|
|
|
void IBurningShader::drawWireFrameTriangle(const s4DVertex* a, const s4DVertex* b, const s4DVertex* c)
|
|
{
|
|
if (EdgeTestPass & edge_test_pass) drawTriangle(a, b, c);
|
|
else if (EdgeTestPass & edge_test_point)
|
|
{
|
|
drawPoint(a);
|
|
drawPoint(b);
|
|
drawPoint(c);
|
|
}
|
|
else
|
|
{
|
|
drawLine(a, b);
|
|
drawLine(b, c);
|
|
drawLine(a, c);
|
|
}
|
|
}
|
|
|
|
|
|
void IBurningShader::OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
|
|
bool resetAllRenderstates, IMaterialRendererServices* services)
|
|
{
|
|
if (Driver)
|
|
Driver->setFallback_Material(BaseMaterial);
|
|
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
|
|
if (CallBack)
|
|
CallBack->OnSetMaterial(material);
|
|
|
|
}
|
|
|
|
void IBurningShader::OnUnsetMaterial()
|
|
{
|
|
}
|
|
|
|
bool IBurningShader::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
|
|
{
|
|
// call callback to set shader constants
|
|
if (CallBack)
|
|
CallBack->OnSetConstants(this, UserData);
|
|
return true;
|
|
}
|
|
|
|
|
|
//! Returns if the material is transparent.
|
|
bool IBurningShader::isTransparent() const
|
|
{
|
|
return RenderPass_ShaderIsTransparent != 0;
|
|
}
|
|
|
|
//! Access the callback provided by the users when creating shader materials
|
|
IShaderConstantSetCallBack* IBurningShader::getShaderConstantSetCallBack() const
|
|
{
|
|
return CallBack;
|
|
}
|
|
|
|
// implementations for the render services
|
|
void IBurningShader::setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial, bool resetAllRenderstates)
|
|
{
|
|
// forward
|
|
Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
|
|
}
|
|
|
|
s32 IBurningShader::getShaderConstantID(EBurningUniformFlags flags, const c8* name)
|
|
{
|
|
if (!name || !name[0])
|
|
return -1;
|
|
|
|
BurningUniform add;
|
|
tiny_strcpy(add.name, name);
|
|
add.type = flags;
|
|
|
|
s32 index = UniformInfo.linear_search(add);
|
|
if (index < 0)
|
|
{
|
|
UniformInfo.push_back(add);
|
|
index = UniformInfo.size() - 1;
|
|
}
|
|
|
|
return index;
|
|
}
|
|
|
|
const char* tiny_itoa(s32 value, int base)
|
|
{
|
|
static char b[32];
|
|
int p = 31;
|
|
|
|
//int sign = 0;
|
|
//if (value < 0) { sign = 1; value = -value; }
|
|
|
|
b[p] = '\0';
|
|
do {
|
|
b[--p] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[value % base];
|
|
value /= base;
|
|
} while (value && p > 0);
|
|
|
|
//if (sign && p > 0) { b[--p] = '-'; }
|
|
|
|
return b + p;
|
|
}
|
|
|
|
bool IBurningShader::setShaderConstantID(EBurningUniformFlags flags, s32 index, const void* data, size_t u32_count)
|
|
{
|
|
if ((u32)index >= UniformInfo.size())
|
|
return false;
|
|
#if 0
|
|
BurningUniform add;
|
|
while ((u32)index >= UniformInfo.size())
|
|
{
|
|
tiny_strcpy(add.name, tiny_itoa(UniformInfo.size(), 10));
|
|
add.type = flags;
|
|
UniformInfo.push_back(add);
|
|
}
|
|
#endif
|
|
|
|
BurningUniform& use = UniformInfo[index];
|
|
use.type = flags;
|
|
|
|
const u32* s = (u32*)data;
|
|
u32* d = (u32*)use.data;
|
|
|
|
if (!s) u32_count = 0;
|
|
if (u32_count > array_size(use.data)) u32_count = array_size(use.data);
|
|
for (size_t i = 0; i < u32_count; ++i)
|
|
{
|
|
d[i] = s[i];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
s32 IBurningShader::getVertexShaderConstantID(const c8* name)
|
|
{
|
|
return getShaderConstantID(BL_VERTEX_PROGRAM, name);
|
|
}
|
|
|
|
s32 IBurningShader::getPixelShaderConstantID(const c8* name)
|
|
{
|
|
return getShaderConstantID(BL_FRAGMENT_PROGRAM, name);
|
|
}
|
|
|
|
void IBurningShader::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
|
|
{
|
|
c8 name[BL_ACTIVE_UNIFORM_MAX_LENGTH];
|
|
tiny_strcpy(name, tiny_itoa(startRegister, 10));
|
|
|
|
setShaderConstantID(BL_VERTEX_FLOAT, getShaderConstantID(BL_VERTEX_PROGRAM, name), data, constantAmount);
|
|
}
|
|
|
|
void IBurningShader::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
|
|
{
|
|
c8 name[BL_ACTIVE_UNIFORM_MAX_LENGTH];
|
|
tiny_strcpy(name, tiny_itoa(startRegister, 10));
|
|
|
|
setShaderConstantID(BL_FRAGMENT_FLOAT, getShaderConstantID(BL_FRAGMENT_PROGRAM, name), data, constantAmount);
|
|
}
|
|
|
|
bool IBurningShader::setVertexShaderConstant(s32 index, const f32* floats, int count)
|
|
{
|
|
return setShaderConstantID(BL_VERTEX_FLOAT, index, floats, count);
|
|
}
|
|
|
|
bool IBurningShader::setVertexShaderConstant(s32 index, const s32* ints, int count)
|
|
{
|
|
return setShaderConstantID(BL_VERTEX_INT, index, ints, count);
|
|
}
|
|
|
|
bool IBurningShader::setVertexShaderConstant(s32 index, const u32* ints, int count)
|
|
{
|
|
return setShaderConstantID(BL_VERTEX_UINT, index, ints, count);
|
|
}
|
|
|
|
bool IBurningShader::setPixelShaderConstant(s32 index, const f32* floats, int count)
|
|
{
|
|
return setShaderConstantID(BL_FRAGMENT_FLOAT, index, floats, count);
|
|
}
|
|
|
|
bool IBurningShader::setPixelShaderConstant(s32 index, const s32* ints, int count)
|
|
{
|
|
return setShaderConstantID(BL_FRAGMENT_INT, index, ints, count);
|
|
}
|
|
|
|
bool IBurningShader::setPixelShaderConstant(s32 index, const u32* ints, int count)
|
|
{
|
|
return setShaderConstantID(BL_FRAGMENT_UINT, index, ints, count);
|
|
}
|
|
|
|
void IBurningShader::setStencilOp(eBurningStencilOp sfail, eBurningStencilOp dpfail, eBurningStencilOp dppass)
|
|
{
|
|
stencilOp[0] = sfail;
|
|
stencilOp[1] = dpfail;
|
|
stencilOp[2] = dppass;
|
|
}
|
|
|
|
|
|
IVideoDriver* IBurningShader::getVideoDriver()
|
|
{
|
|
return Driver;
|
|
}
|
|
|
|
|
|
} // end namespace video
|
|
} // end namespace irr
|
|
|
|
#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
|