From 959831f4ef5a3e797f576c3de08cd65032c997ad Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 13 Jan 2013 18:54:10 +1000 Subject: Remove damned ancient DOS line endings from Irrlicht. Hopefully I did not go overboard. --- .../source/Irrlicht/CSoftwareDriver2.cpp | 5444 ++++++++++---------- 1 file changed, 2722 insertions(+), 2722 deletions(-) (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp') diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp index bdde929..9f0015f 100644 --- a/libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp +++ b/libraries/irrlicht-1.8/source/Irrlicht/CSoftwareDriver2.cpp @@ -1,2722 +1,2722 @@ -// 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" -#include "CSoftwareDriver2.h" - -#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ - -#include "SoftwareDriver2_helper.h" -#include "CSoftwareTexture2.h" -#include "CSoftware2MaterialRenderer.h" -#include "S3DVertex.h" -#include "S4DVertex.h" -#include "CBlit.h" - - -#define MAT_TEXTURE(tex) ( (video::CSoftwareTexture2*) Material.org.getTexture ( tex ) ) - - -namespace irr -{ -namespace video -{ - -namespace glsl -{ - -typedef sVec4 vec4; -typedef sVec3 vec3; -typedef sVec2 vec2; - -#define in -#define uniform -#define attribute -#define varying - -#ifdef _MSC_VER -#pragma warning(disable:4244) -#endif - -struct mat4{ - float m[4][4]; - - vec4 operator* ( const vec4 &in ) const - { - vec4 out; - return out; - } - -}; - -struct mat3{ - float m[3][3]; - - vec3 operator* ( const vec3 &in ) const - { - vec3 out; - return out; - } -}; - -const int gl_MaxLights = 8; - - -inline float dot (float x, float y) { return x * y; } -inline float dot ( const vec2 &x, const vec2 &y) { return x.x * y.x + x.y * y.y; } -inline float dot ( const vec3 &x, const vec3 &y) { return x.x * y.x + x.y * y.y + x.z * y.z; } -inline float dot ( const vec4 &x, const vec4 &y) { return x.x * y.x + x.y * y.y + x.z * y.z + x.w * y.w; } - -inline float reflect (float I, float N) { return I - 2.0 * dot (N, I) * N; } -inline vec2 reflect (const vec2 &I, const vec2 &N) { return I - N * 2.0 * dot (N, I); } -inline vec3 reflect (const vec3 &I, const vec3 &N) { return I - N * 2.0 * dot (N, I); } -inline vec4 reflect (const vec4 &I, const vec4 &N) { return I - N * 2.0 * dot (N, I); } - - -inline float refract (float I, float N, float eta){ - const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); - if (k < 0.0) - return 0.0; - return eta * I - (eta * dot (N, I) + sqrt (k)) * N; -} - -inline vec2 refract (const vec2 &I, const vec2 &N, float eta){ - const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); - if (k < 0.0) - return vec2 (0.0); - return I * eta - N * (eta * dot (N, I) + sqrt (k)); -} - -inline vec3 refract (const vec3 &I, const vec3 &N, float eta) { - const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); - if (k < 0.0) - return vec3 (0.0); - return I * eta - N * (eta * dot (N, I) + sqrt (k)); -} - -inline vec4 refract (const vec4 &I, const vec4 &N, float eta) { - const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); - if (k < 0.0) - return vec4 (0.0); - return I * eta - N * (eta * dot (N, I) + sqrt (k)); -} - - -inline float length ( const vec3 &v ) { return sqrtf ( v.x * v.x + v.y * v.y + v.z * v.z ); } -vec3 normalize ( const vec3 &v ) { float l = 1.f / length ( v ); return vec3 ( v.x * l, v.y * l, v.z * l ); } -float max ( float a, float b ) { return a > b ? a : b; } -float min ( float a, float b ) { return a < b ? a : b; } -vec4 clamp ( const vec4 &a, f32 low, f32 high ) { return vec4 ( min (max(a.x,low), high), min (max(a.y,low), high), min (max(a.z,low), high), min (max(a.w,low), high) ); } - - - -typedef int sampler2D; -sampler2D texUnit0; - -vec4 texture2D (sampler2D sampler, const vec2 &coord) { return vec4 (0.0); } - -struct gl_LightSourceParameters { - vec4 ambient; // Acli - vec4 diffuse; // Dcli - vec4 specular; // Scli - vec4 position; // Ppli - vec4 halfVector; // Derived: Hi - vec3 spotDirection; // Sdli - float spotExponent; // Srli - float spotCutoff; // Crli - // (range: [0.0,90.0], 180.0) - float spotCosCutoff; // Derived: cos(Crli) - // (range: [1.0,0.0],-1.0) - float constantAttenuation; // K0 - float linearAttenuation; // K1 - float quadraticAttenuation;// K2 -}; - -uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights]; - -struct gl_LightModelParameters { - vec4 ambient; -}; -uniform gl_LightModelParameters gl_LightModel; - -struct gl_LightModelProducts { - vec4 sceneColor; -}; - -uniform gl_LightModelProducts gl_FrontLightModelProduct; -uniform gl_LightModelProducts gl_BackLightModelProduct; - -struct gl_LightProducts { - vec4 ambient; - vec4 diffuse; - vec4 specular; -}; - -uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights]; -uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights]; - -struct gl_MaterialParameters -{ - vec4 emission; // Ecm - vec4 ambient; // Acm - vec4 diffuse; // Dcm - vec4 specular; // Scm - float shininess; // Srm -}; -uniform gl_MaterialParameters gl_FrontMaterial; -uniform gl_MaterialParameters gl_BackMaterial; - -// GLSL has some built-in attributes in a vertex shader: -attribute vec4 gl_Vertex; // 4D vector representing the vertex position -attribute vec3 gl_Normal; // 3D vector representing the vertex normal -attribute vec4 gl_Color; // 4D vector representing the vertex color -attribute vec4 gl_MultiTexCoord0; // 4D vector representing the texture coordinate of texture unit X -attribute vec4 gl_MultiTexCoord1; // 4D vector representing the texture coordinate of texture unit X - -uniform mat4 gl_ModelViewMatrix; //4x4 Matrix representing the model-view matrix. -uniform mat4 gl_ModelViewProjectionMatrix; //4x4 Matrix representing the model-view-projection matrix. -uniform mat3 gl_NormalMatrix; //3x3 Matrix representing the inverse transpose model-view matrix. This matrix is used for normal transformation. - - -varying vec4 gl_FrontColor; // 4D vector representing the primitives front color -varying vec4 gl_FrontSecondaryColor; // 4D vector representing the primitives second front color -varying vec4 gl_BackColor; // 4D vector representing the primitives back color -varying vec4 gl_TexCoord[4]; // 4D vector representing the Xth texture coordinate - -// shader output -varying vec4 gl_Position; // 4D vector representing the final processed vertex position. Only available in vertex shader. -varying vec4 gl_FragColor; // 4D vector representing the final color which is written in the frame buffer. Only available in fragment shader. -varying float gl_FragDepth; // float representing the depth which is written in the depth buffer. Only available in fragment shader. - -varying vec4 gl_SecondaryColor; -varying float gl_FogFragCoord; - - -vec4 ftransform(void) -{ - return gl_ModelViewProjectionMatrix * gl_Vertex; -} - -vec3 fnormal(void) -{ - //Compute the normal - vec3 normal = gl_NormalMatrix * gl_Normal; - normal = normalize(normal); - return normal; -} - - -struct program1 -{ - vec4 Ambient; - vec4 Diffuse; - vec4 Specular; - - void pointLight(in int i, in vec3 normal, in vec3 eye, in vec3 ecPosition3) - { - float nDotVP; // normal . light direction - float nDotHV; // normal . light half vector - float pf; // power factor - float attenuation; // computed attenuation factor - float d; // distance from surface to light source - vec3 VP; // direction from surface to light position - vec3 halfVector; // direction of maximum highlights - - // Compute vector from surface to light position - VP = vec3 (gl_LightSource[i].position) - ecPosition3; - - // Compute distance between surface and light position - d = length(VP); - - // Normalize the vector from surface to light position - VP = normalize(VP); - - // Compute attenuation - attenuation = 1.0 / (gl_LightSource[i].constantAttenuation + - gl_LightSource[i].linearAttenuation * d + - gl_LightSource[i].quadraticAttenuation * d * d); - - halfVector = normalize(VP + eye); - - nDotVP = max(0.0, dot(normal, VP)); - nDotHV = max(0.0, dot(normal, halfVector)); - - if (nDotVP == 0.0) - { - pf = 0.0; - } - else - { - pf = pow(nDotHV, gl_FrontMaterial.shininess); - - } - Ambient += gl_LightSource[i].ambient * attenuation; - Diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation; - Specular += gl_LightSource[i].specular * pf * attenuation; - } - - vec3 fnormal(void) - { - //Compute the normal - vec3 normal = gl_NormalMatrix * gl_Normal; - normal = normalize(normal); - return normal; - } - - void ftexgen(in vec3 normal, in vec4 ecPosition) - { - - gl_TexCoord[0] = gl_MultiTexCoord0; - } - - void flight(in vec3 normal, in vec4 ecPosition, float alphaFade) - { - vec4 color; - vec3 ecPosition3; - vec3 eye; - - ecPosition3 = (vec3 (ecPosition)) / ecPosition.w; - eye = vec3 (0.0, 0.0, 1.0); - - // Clear the light intensity accumulators - Ambient = vec4 (0.0); - Diffuse = vec4 (0.0); - Specular = vec4 (0.0); - - pointLight(0, normal, eye, ecPosition3); - - pointLight(1, normal, eye, ecPosition3); - - color = gl_FrontLightModelProduct.sceneColor + - Ambient * gl_FrontMaterial.ambient + - Diffuse * gl_FrontMaterial.diffuse; - gl_FrontSecondaryColor = Specular * gl_FrontMaterial.specular; - color = clamp( color, 0.0, 1.0 ); - gl_FrontColor = color; - - gl_FrontColor.a *= alphaFade; - } - - - void vertexshader_main (void) - { - vec3 transformedNormal; - float alphaFade = 1.0; - - // Eye-coordinate position of vertex, needed in various calculations - vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex; - - // Do fixed functionality vertex transform - gl_Position = ftransform(); - transformedNormal = fnormal(); - flight(transformedNormal, ecPosition, alphaFade); - ftexgen(transformedNormal, ecPosition); - } - - void fragmentshader_main (void) - { - vec4 color; - - color = gl_Color; - - color *= texture2D(texUnit0, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y) ); - - color += gl_SecondaryColor; - color = clamp(color, 0.0, 1.0); - - gl_FragColor = color; - } -}; - -} - -//! constructor -CBurningVideoDriver::CBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter) -: CNullDriver(io, params.WindowSize), BackBuffer(0), Presenter(presenter), - WindowId(0), SceneSourceRect(0), - RenderTargetTexture(0), RenderTargetSurface(0), CurrentShader(0), - DepthBuffer(0), StencilBuffer ( 0 ), - CurrentOut ( 12 * 2, 128 ), Temp ( 12 * 2, 128 ) -{ - #ifdef _DEBUG - setDebugName("CBurningVideoDriver"); - #endif - - // create backbuffer - BackBuffer = new CImage(BURNINGSHADER_COLOR_FORMAT, params.WindowSize); - if (BackBuffer) - { - BackBuffer->fill(SColor(0)); - - // create z buffer - if ( params.ZBufferBits ) - DepthBuffer = video::createDepthBuffer(BackBuffer->getDimension()); - - // create stencil buffer - if ( params.Stencilbuffer ) - StencilBuffer = video::createStencilBuffer(BackBuffer->getDimension()); - } - - DriverAttributes->setAttribute("MaxTextures", 2); - DriverAttributes->setAttribute("MaxIndices", 1<<16); - DriverAttributes->setAttribute("MaxTextureSize", 1024); - DriverAttributes->setAttribute("MaxLights", glsl::gl_MaxLights); - DriverAttributes->setAttribute("MaxTextureLODBias", 16.f); - DriverAttributes->setAttribute("Version", 47); - - // create triangle renderers - - irr::memset32 ( BurningShader, 0, sizeof ( BurningShader ) ); - //BurningShader[ETR_FLAT] = createTRFlat2(DepthBuffer); - //BurningShader[ETR_FLAT_WIRE] = createTRFlatWire2(DepthBuffer); - BurningShader[ETR_GOURAUD] = createTriangleRendererGouraud2(this); - BurningShader[ETR_GOURAUD_ALPHA] = createTriangleRendererGouraudAlpha2(this ); - BurningShader[ETR_GOURAUD_ALPHA_NOZ] = createTRGouraudAlphaNoZ2(this ); - //BurningShader[ETR_GOURAUD_WIRE] = createTriangleRendererGouraudWire2(DepthBuffer); - //BurningShader[ETR_TEXTURE_FLAT] = createTriangleRendererTextureFlat2(DepthBuffer); - //BurningShader[ETR_TEXTURE_FLAT_WIRE] = createTriangleRendererTextureFlatWire2(DepthBuffer); - BurningShader[ETR_TEXTURE_GOURAUD] = createTriangleRendererTextureGouraud2(this); - BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M1] = createTriangleRendererTextureLightMap2_M1(this); - BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M2] = createTriangleRendererTextureLightMap2_M2(this); - BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M4] = createTriangleRendererGTextureLightMap2_M4(this); - BurningShader[ETR_TEXTURE_LIGHTMAP_M4] = createTriangleRendererTextureLightMap2_M4(this); - BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD] = createTriangleRendererTextureLightMap2_Add(this); - BurningShader[ETR_TEXTURE_GOURAUD_DETAIL_MAP] = createTriangleRendererTextureDetailMap2(this); - - BurningShader[ETR_TEXTURE_GOURAUD_WIRE] = createTriangleRendererTextureGouraudWire2(this); - BurningShader[ETR_TEXTURE_GOURAUD_NOZ] = createTRTextureGouraudNoZ2(this); - BurningShader[ETR_TEXTURE_GOURAUD_ADD] = createTRTextureGouraudAdd2(this); - BurningShader[ETR_TEXTURE_GOURAUD_ADD_NO_Z] = createTRTextureGouraudAddNoZ2(this); - BurningShader[ETR_TEXTURE_GOURAUD_VERTEX_ALPHA] = createTriangleRendererTextureVertexAlpha2 ( this ); - - BurningShader[ETR_TEXTURE_GOURAUD_ALPHA] = createTRTextureGouraudAlpha(this ); - BurningShader[ETR_TEXTURE_GOURAUD_ALPHA_NOZ] = createTRTextureGouraudAlphaNoZ( this ); - - BurningShader[ETR_NORMAL_MAP_SOLID] = createTRNormalMap ( this ); - BurningShader[ETR_STENCIL_SHADOW] = createTRStencilShadow ( this ); - BurningShader[ETR_TEXTURE_BLEND] = createTRTextureBlend( this ); - - BurningShader[ETR_REFERENCE] = createTriangleRendererReference ( this ); - - - // add the same renderer for all solid types - CSoftware2MaterialRenderer_SOLID* smr = new CSoftware2MaterialRenderer_SOLID( this); - CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR* tmr = new CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR( this); - CSoftware2MaterialRenderer_UNSUPPORTED * umr = new CSoftware2MaterialRenderer_UNSUPPORTED ( this ); - - //!TODO: addMaterialRenderer depends on pushing order.... - addMaterialRenderer ( smr ); // EMT_SOLID - addMaterialRenderer ( smr ); // EMT_SOLID_2_LAYER, - addMaterialRenderer ( smr ); // EMT_LIGHTMAP, - addMaterialRenderer ( tmr ); // EMT_LIGHTMAP_ADD, - addMaterialRenderer ( smr ); // EMT_LIGHTMAP_M2, - addMaterialRenderer ( smr ); // EMT_LIGHTMAP_M4, - addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING, - addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING_M2, - addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING_M4, - addMaterialRenderer ( smr ); // EMT_DETAIL_MAP, - addMaterialRenderer ( umr ); // EMT_SPHERE_MAP, - addMaterialRenderer ( smr ); // EMT_REFLECTION_2_LAYER, - addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ADD_COLOR, - addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ALPHA_CHANNEL, - addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ALPHA_CHANNEL_REF, - addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_VERTEX_ALPHA, - addMaterialRenderer ( smr ); // EMT_TRANSPARENT_REFLECTION_2_LAYER, - addMaterialRenderer ( smr ); // EMT_NORMAL_MAP_SOLID, - addMaterialRenderer ( umr ); // EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR, - addMaterialRenderer ( tmr ); // EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA, - addMaterialRenderer ( smr ); // EMT_PARALLAX_MAP_SOLID, - addMaterialRenderer ( tmr ); // EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR, - addMaterialRenderer ( tmr ); // EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA, - addMaterialRenderer ( tmr ); // EMT_ONETEXTURE_BLEND - - smr->drop (); - tmr->drop (); - umr->drop (); - - // select render target - setRenderTarget(BackBuffer); - - //reset Lightspace - LightSpace.reset (); - - // select the right renderer - setCurrentShader(); -} - - -//! destructor -CBurningVideoDriver::~CBurningVideoDriver() -{ - // delete Backbuffer - if (BackBuffer) - BackBuffer->drop(); - - // delete triangle renderers - - for (s32 i=0; idrop(); - } - - // delete Additional buffer - if (StencilBuffer) - StencilBuffer->drop(); - - if (DepthBuffer) - DepthBuffer->drop(); - - if (RenderTargetTexture) - RenderTargetTexture->drop(); - - if (RenderTargetSurface) - RenderTargetSurface->drop(); -} - - -/*! - selects the right triangle renderer based on the render states. -*/ -void CBurningVideoDriver::setCurrentShader() -{ - ITexture *texture0 = Material.org.getTexture(0); - ITexture *texture1 = Material.org.getTexture(1); - - bool zMaterialTest = Material.org.ZBuffer != ECFN_NEVER && - Material.org.ZWriteEnable && - ( AllowZWriteOnTransparent || !Material.org.isTransparent() ); - - EBurningFFShader shader = zMaterialTest ? ETR_TEXTURE_GOURAUD : ETR_TEXTURE_GOURAUD_NOZ; - - TransformationFlag[ ETS_TEXTURE_0] &= ~(ETF_TEXGEN_CAMERA_NORMAL|ETF_TEXGEN_CAMERA_REFLECTION); - LightSpace.Flags &= ~VERTEXTRANSFORM; - - switch ( Material.org.MaterialType ) - { - case EMT_ONETEXTURE_BLEND: - shader = ETR_TEXTURE_BLEND; - break; - - case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: - Material.org.MaterialTypeParam = 0.5f; - // fall through - case EMT_TRANSPARENT_ALPHA_CHANNEL: - if ( texture0 && texture0->hasAlpha () ) - { - shader = zMaterialTest ? ETR_TEXTURE_GOURAUD_ALPHA : ETR_TEXTURE_GOURAUD_ALPHA_NOZ; - break; - } - // fall through - - case EMT_TRANSPARENT_ADD_COLOR: - shader = zMaterialTest ? ETR_TEXTURE_GOURAUD_ADD : ETR_TEXTURE_GOURAUD_ADD_NO_Z; - break; - - case EMT_TRANSPARENT_VERTEX_ALPHA: - shader = ETR_TEXTURE_GOURAUD_VERTEX_ALPHA; - break; - - case EMT_LIGHTMAP: - case EMT_LIGHTMAP_LIGHTING: - shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1; - break; - - case EMT_LIGHTMAP_M2: - case EMT_LIGHTMAP_LIGHTING_M2: - shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M2; - break; - - case EMT_LIGHTMAP_LIGHTING_M4: - if ( texture1 ) - shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M4; - break; - case EMT_LIGHTMAP_M4: - if ( texture1 ) - shader = ETR_TEXTURE_LIGHTMAP_M4; - break; - - case EMT_LIGHTMAP_ADD: - if ( texture1 ) - shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD; - break; - - case EMT_DETAIL_MAP: - shader = ETR_TEXTURE_GOURAUD_DETAIL_MAP; - break; - - case EMT_SPHERE_MAP: - TransformationFlag[ ETS_TEXTURE_0] |= ETF_TEXGEN_CAMERA_REFLECTION; // ETF_TEXGEN_CAMERA_NORMAL; - LightSpace.Flags |= VERTEXTRANSFORM; - break; - case EMT_REFLECTION_2_LAYER: - shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1; - TransformationFlag[ ETS_TEXTURE_1] |= ETF_TEXGEN_CAMERA_REFLECTION; - LightSpace.Flags |= VERTEXTRANSFORM; - break; - - case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: - case EMT_NORMAL_MAP_SOLID: - case EMT_PARALLAX_MAP_SOLID: - case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: - shader = ETR_NORMAL_MAP_SOLID; - LightSpace.Flags |= VERTEXTRANSFORM; - break; - - default: - break; - - } - - if ( !texture0 ) - { - shader = ETR_GOURAUD; - } - - if ( Material.org.Wireframe ) - { - shader = ETR_TEXTURE_GOURAUD_WIRE; - } - - //shader = ETR_REFERENCE; - - // switchToTriangleRenderer - CurrentShader = BurningShader[shader]; - if ( CurrentShader ) - { - CurrentShader->setZCompareFunc ( Material.org.ZBuffer ); - CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); - CurrentShader->setMaterial ( Material ); - - switch ( shader ) - { - case ETR_TEXTURE_GOURAUD_ALPHA: - case ETR_TEXTURE_GOURAUD_ALPHA_NOZ: - case ETR_TEXTURE_BLEND: - CurrentShader->setParam ( 0, Material.org.MaterialTypeParam ); - break; - default: - break; - } - } - -} - - - -//! queries the features of the driver, returns true if feature is available -bool CBurningVideoDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const -{ - if (!FeatureEnabled[feature]) - return false; - - switch (feature) - { -#ifdef SOFTWARE_DRIVER_2_BILINEAR - case EVDF_BILINEAR_FILTER: - return true; -#endif -#ifdef SOFTWARE_DRIVER_2_MIPMAPPING - case EVDF_MIP_MAP: - return true; -#endif - case EVDF_STENCIL_BUFFER: - case EVDF_RENDER_TO_TARGET: - case EVDF_MULTITEXTURE: - case EVDF_HARDWARE_TL: - case EVDF_TEXTURE_NSQUARE: - return true; - - default: - return false; - } -} - - - -//! sets transformation -void CBurningVideoDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) -{ - Transformation[state] = mat; - core::setbit_cond ( TransformationFlag[state], mat.isIdentity(), ETF_IDENTITY ); - - switch ( state ) - { - case ETS_VIEW: - Transformation[ETS_VIEW_PROJECTION].setbyproduct_nocheck ( - Transformation[ETS_PROJECTION], - Transformation[ETS_VIEW] - ); - getCameraPosWorldSpace (); - break; - - case ETS_WORLD: - if ( TransformationFlag[state] & ETF_IDENTITY ) - { - Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; - TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; - Transformation[ETS_CURRENT] = Transformation[ETS_VIEW_PROJECTION]; - } - else - { - //Transformation[ETS_WORLD].getInversePrimitive ( Transformation[ETS_WORLD_INVERSE] ); - Transformation[ETS_CURRENT].setbyproduct_nocheck ( - Transformation[ETS_VIEW_PROJECTION], - Transformation[ETS_WORLD] - ); - } - TransformationFlag[ETS_CURRENT] = 0; - //getLightPosObjectSpace (); - break; - case ETS_TEXTURE_0: - case ETS_TEXTURE_1: - case ETS_TEXTURE_2: - case ETS_TEXTURE_3: - if ( 0 == (TransformationFlag[state] & ETF_IDENTITY ) ) - LightSpace.Flags |= VERTEXTRANSFORM; - default: - break; - } -} - - -//! clears the zbuffer -bool CBurningVideoDriver::beginScene(bool backBuffer, bool zBuffer, - SColor color, const SExposedVideoData& videoData, - core::rect* sourceRect) -{ - CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect); - WindowId = videoData.D3D9.HWnd; - SceneSourceRect = sourceRect; - - if (backBuffer && BackBuffer) - BackBuffer->fill(color); - - if (zBuffer && DepthBuffer) - DepthBuffer->clear(); - - memset ( TransformationFlag, 0, sizeof ( TransformationFlag ) ); - return true; -} - - -//! presents the rendered scene on the screen, returns false if failed -bool CBurningVideoDriver::endScene() -{ - CNullDriver::endScene(); - - return Presenter->present(BackBuffer, WindowId, SceneSourceRect); -} - - -//! sets a render target -bool CBurningVideoDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, - bool clearZBuffer, SColor color) -{ - if (texture && texture->getDriverType() != EDT_BURNINGSVIDEO) - { - os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); - return false; - } - - if (RenderTargetTexture) - RenderTargetTexture->drop(); - - RenderTargetTexture = texture; - - if (RenderTargetTexture) - { - RenderTargetTexture->grab(); - setRenderTarget(((CSoftwareTexture2*)RenderTargetTexture)->getTexture()); - } - else - { - setRenderTarget(BackBuffer); - } - - if (RenderTargetSurface && (clearBackBuffer || clearZBuffer)) - { - if (clearZBuffer) - DepthBuffer->clear(); - - if (clearBackBuffer) - RenderTargetSurface->fill( color ); - } - - return true; -} - - -//! sets a render target -void CBurningVideoDriver::setRenderTarget(video::CImage* image) -{ - if (RenderTargetSurface) - RenderTargetSurface->drop(); - - RenderTargetSurface = image; - RenderTargetSize.Width = 0; - RenderTargetSize.Height = 0; - - if (RenderTargetSurface) - { - RenderTargetSurface->grab(); - RenderTargetSize = RenderTargetSurface->getDimension(); - } - - setViewPort(core::rect(0,0,RenderTargetSize.Width,RenderTargetSize.Height)); - - if (DepthBuffer) - DepthBuffer->setSize(RenderTargetSize); - - if (StencilBuffer) - StencilBuffer->setSize(RenderTargetSize); -} - - - -//! sets a viewport -void CBurningVideoDriver::setViewPort(const core::rect& area) -{ - ViewPort = area; - - core::rect rendert(0,0,RenderTargetSize.Width,RenderTargetSize.Height); - ViewPort.clipAgainst(rendert); - - Transformation [ ETS_CLIPSCALE ].buildNDCToDCMatrix ( ViewPort, 1 ); - - if (CurrentShader) - CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); -} - -/* - generic plane clipping in homogenous coordinates - special case ndc frustum <-w,w>,<-w,w>,<-w,w> - can be rewritten with compares e.q near plane, a.z < -a.w and b.z < -b.w -*/ - -const sVec4 CBurningVideoDriver::NDCPlane[6] = -{ - sVec4( 0.f, 0.f, -1.f, -1.f ), // near - sVec4( 0.f, 0.f, 1.f, -1.f ), // far - sVec4( 1.f, 0.f, 0.f, -1.f ), // left - sVec4( -1.f, 0.f, 0.f, -1.f ), // right - sVec4( 0.f, 1.f, 0.f, -1.f ), // bottom - sVec4( 0.f, -1.f, 0.f, -1.f ) // top -}; - - - -/* - test a vertex if it's inside the standard frustum - - this is the generic one.. - - f32 dotPlane; - for ( u32 i = 0; i!= 6; ++i ) - { - dotPlane = v->Pos.dotProduct ( NDCPlane[i] ); - core::setbit_cond( flag, dotPlane <= 0.f, 1 << i ); - } - - // this is the base for ndc frustum <-w,w>,<-w,w>,<-w,w> - core::setbit_cond( flag, ( v->Pos.z - v->Pos.w ) <= 0.f, 1 ); - core::setbit_cond( flag, (-v->Pos.z - v->Pos.w ) <= 0.f, 2 ); - core::setbit_cond( flag, ( v->Pos.x - v->Pos.w ) <= 0.f, 4 ); - core::setbit_cond( flag, (-v->Pos.x - v->Pos.w ) <= 0.f, 8 ); - core::setbit_cond( flag, ( v->Pos.y - v->Pos.w ) <= 0.f, 16 ); - core::setbit_cond( flag, (-v->Pos.y - v->Pos.w ) <= 0.f, 32 ); - -*/ -#ifdef IRRLICHT_FAST_MATH - -REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const -{ - f32 test[6]; - u32 flag; - const f32 w = - v->Pos.w; - - // a conditional move is needed....FCOMI ( but we don't have it ) - // so let the fpu calculate and write it back. - // cpu makes the compare, interleaving - - test[0] = v->Pos.z + w; - test[1] = -v->Pos.z + w; - test[2] = v->Pos.x + w; - test[3] = -v->Pos.x + w; - test[4] = v->Pos.y + w; - test[5] = -v->Pos.y + w; - - flag = (IR ( test[0] ) ) >> 31; - flag |= (IR ( test[1] ) & 0x80000000 ) >> 30; - flag |= (IR ( test[2] ) & 0x80000000 ) >> 29; - flag |= (IR ( test[3] ) & 0x80000000 ) >> 28; - flag |= (IR ( test[4] ) & 0x80000000 ) >> 27; - flag |= (IR ( test[5] ) & 0x80000000 ) >> 26; - -/* - flag = F32_LOWER_EQUAL_0 ( test[0] ); - flag |= F32_LOWER_EQUAL_0 ( test[1] ) << 1; - flag |= F32_LOWER_EQUAL_0 ( test[2] ) << 2; - flag |= F32_LOWER_EQUAL_0 ( test[3] ) << 3; - flag |= F32_LOWER_EQUAL_0 ( test[4] ) << 4; - flag |= F32_LOWER_EQUAL_0 ( test[5] ) << 5; -*/ - return flag; -} - -#else - - -REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const -{ - u32 flag = 0; - - if ( v->Pos.z <= v->Pos.w ) flag |= 1; - if (-v->Pos.z <= v->Pos.w ) flag |= 2; - - if ( v->Pos.x <= v->Pos.w ) flag |= 4; - if (-v->Pos.x <= v->Pos.w ) flag |= 8; - - if ( v->Pos.y <= v->Pos.w ) flag |= 16; - if (-v->Pos.y <= v->Pos.w ) flag |= 32; - -/* - for ( u32 i = 0; i!= 6; ++i ) - { - core::setbit_cond( flag, v->Pos.dotProduct ( NDCPlane[i] ) <= 0.f, 1 << i ); - } -*/ - return flag; -} - -#endif // _MSC_VER - -u32 CBurningVideoDriver::clipToHyperPlane ( s4DVertex * dest, const s4DVertex * source, u32 inCount, const sVec4 &plane ) -{ - u32 outCount = 0; - s4DVertex * out = dest; - - const s4DVertex * a; - const s4DVertex * b = source; - - f32 bDotPlane; - - bDotPlane = b->Pos.dotProduct ( plane ); - - for( u32 i = 1; i < inCount + 1; ++i) - { - const s32 condition = i - inCount; - const s32 index = (( ( condition >> 31 ) & ( i ^ condition ) ) ^ condition ) << 1; - - a = &source[ index ]; - - // current point inside - if ( a->Pos.dotProduct ( plane ) <= 0.f ) - { - // last point outside - if ( F32_GREATER_0 ( bDotPlane ) ) - { - // intersect line segment with plane - out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); - out += 2; - outCount += 1; - } - - // copy current to out - //*out = *a; - irr::memcpy32_small ( out, a, SIZEOF_SVERTEX * 2 ); - b = out; - - out += 2; - outCount += 1; - } - else - { - // current point outside - - if ( F32_LOWER_EQUAL_0 ( bDotPlane ) ) - { - // previous was inside - // intersect line segment with plane - out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); - out += 2; - outCount += 1; - } - // pointer - b = a; - } - - bDotPlane = b->Pos.dotProduct ( plane ); - - } - - return outCount; -} - - -u32 CBurningVideoDriver::clipToFrustum ( s4DVertex *v0, s4DVertex * v1, const u32 vIn ) -{ - u32 vOut = vIn; - - vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[0] ); if ( vOut < vIn ) return vOut; - vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[1] ); if ( vOut < vIn ) return vOut; - vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[2] ); if ( vOut < vIn ) return vOut; - vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[3] ); if ( vOut < vIn ) return vOut; - vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[4] ); if ( vOut < vIn ) return vOut; - vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[5] ); - return vOut; -} - -/*! - Part I: - apply Clip Scale matrix - From Normalized Device Coordiante ( NDC ) Space to Device Coordinate Space ( DC ) - - Part II: - Project homogeneous vector - homogeneous to non-homogenous coordinates ( dividebyW ) - - Incoming: ( xw, yw, zw, w, u, v, 1, R, G, B, A ) - Outgoing: ( xw/w, yw/w, zw/w, w/w, u/w, v/w, 1/w, R/w, G/w, B/w, A/w ) - - - replace w/w by 1/w -*/ -inline void CBurningVideoDriver::ndc_2_dc_and_project ( s4DVertex *dest,s4DVertex *source, u32 vIn ) const -{ - u32 g; - - for ( g = 0; g != vIn; g += 2 ) - { - if ( (dest[g].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) - continue; - - dest[g].flag = source[g].flag | VERTEX4D_PROJECTED; - - const f32 w = source[g].Pos.w; - const f32 iw = core::reciprocal ( w ); - - // to device coordinates - dest[g].Pos.x = iw * ( source[g].Pos.x * Transformation [ ETS_CLIPSCALE ][ 0] + w * Transformation [ ETS_CLIPSCALE ][12] ); - dest[g].Pos.y = iw * ( source[g].Pos.y * Transformation [ ETS_CLIPSCALE ][ 5] + w * Transformation [ ETS_CLIPSCALE ][13] ); - -#ifndef SOFTWARE_DRIVER_2_USE_WBUFFER - dest[g].Pos.z = iw * source[g].Pos.z; -#endif - - #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR - #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT - dest[g].Color[0] = source[g].Color[0] * iw; - #else - dest[g].Color[0] = source[g].Color[0]; - #endif - - #endif - dest[g].LightTangent[0] = source[g].LightTangent[0] * iw; - dest[g].Pos.w = iw; - } -} - - -inline void CBurningVideoDriver::ndc_2_dc_and_project2 ( const s4DVertex **v, const u32 size ) const -{ - u32 g; - - for ( g = 0; g != size; g += 1 ) - { - s4DVertex * a = (s4DVertex*) v[g]; - - if ( (a[1].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) - continue; - - a[1].flag = a->flag | VERTEX4D_PROJECTED; - - // project homogenous vertex, store 1/w - const f32 w = a->Pos.w; - const f32 iw = core::reciprocal ( w ); - - // to device coordinates - const f32 * p = Transformation [ ETS_CLIPSCALE ].pointer(); - a[1].Pos.x = iw * ( a->Pos.x * p[ 0] + w * p[12] ); - a[1].Pos.y = iw * ( a->Pos.y * p[ 5] + w * p[13] ); - -#ifndef SOFTWARE_DRIVER_2_USE_WBUFFER - a[1].Pos.z = a->Pos.z * iw; -#endif - - #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR - #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT - a[1].Color[0] = a->Color[0] * iw; - #else - a[1].Color[0] = a->Color[0]; - #endif - #endif - - a[1].LightTangent[0] = a[0].LightTangent[0] * iw; - a[1].Pos.w = iw; - - } - -} - - -/*! - crossproduct in projected 2D -> screen area triangle -*/ -inline f32 CBurningVideoDriver::screenarea ( const s4DVertex *v ) const -{ - return ( ( v[3].Pos.x - v[1].Pos.x ) * ( v[5].Pos.y - v[1].Pos.y ) ) - - ( ( v[3].Pos.y - v[1].Pos.y ) * ( v[5].Pos.x - v[1].Pos.x ) ); -} - - -/*! -*/ -inline f32 CBurningVideoDriver::texelarea ( const s4DVertex *v, int tex ) const -{ - f32 z; - - z = ( (v[2].Tex[tex].x - v[0].Tex[tex].x ) * (v[4].Tex[tex].y - v[0].Tex[tex].y ) ) - - ( (v[4].Tex[tex].x - v[0].Tex[tex].x ) * (v[2].Tex[tex].y - v[0].Tex[tex].y ) ); - - return MAT_TEXTURE ( tex )->getLODFactor ( z ); -} - -/*! - crossproduct in projected 2D -*/ -inline f32 CBurningVideoDriver::screenarea2 ( const s4DVertex **v ) const -{ - return ( (( v[1] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) * ( (v[2] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) ) - - ( (( v[1] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) * ( (v[2] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) ); -} - -/*! -*/ -inline f32 CBurningVideoDriver::texelarea2 ( const s4DVertex **v, s32 tex ) const -{ - f32 z; - z = ( (v[1]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[2]->Tex[tex].y - v[0]->Tex[tex].y ) ) - - ( (v[2]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[1]->Tex[tex].y - v[0]->Tex[tex].y ) ); - - return MAT_TEXTURE ( tex )->getLODFactor ( z ); -} - - -/*! -*/ -inline void CBurningVideoDriver::select_polygon_mipmap ( s4DVertex *v, u32 vIn, u32 tex, const core::dimension2du& texSize ) const -{ - f32 f[2]; - - f[0] = (f32) texSize.Width - 0.25f; - f[1] = (f32) texSize.Height - 0.25f; - -#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT - for ( u32 g = 0; g != vIn; g += 2 ) - { - (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * ( v + g + 1 )->Pos.w * f[0]; - (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * ( v + g + 1 )->Pos.w * f[1]; - } -#else - for ( u32 g = 0; g != vIn; g += 2 ) - { - (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * f[0]; - (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * f[1]; - } -#endif -} - -inline void CBurningVideoDriver::select_polygon_mipmap2 ( s4DVertex **v, u32 tex, const core::dimension2du& texSize ) const -{ - f32 f[2]; - - f[0] = (f32) texSize.Width - 0.25f; - f[1] = (f32) texSize.Height - 0.25f; - -#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT - (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * ( v[0] + 1 )->Pos.w * f[0]; - (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * ( v[0] + 1 )->Pos.w * f[1]; - - (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * ( v[1] + 1 )->Pos.w * f[0]; - (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * ( v[1] + 1 )->Pos.w * f[1]; - - (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * ( v[2] + 1 )->Pos.w * f[0]; - (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * ( v[2] + 1 )->Pos.w * f[1]; - -#else - (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * f[0]; - (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * f[1]; - - (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * f[0]; - (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * f[1]; - - (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * f[0]; - (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * f[1]; -#endif -} - -// Vertex Cache -const SVSize CBurningVideoDriver::vSize[] = -{ - { VERTEX4D_FORMAT_TEXTURE_1 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 1 }, - { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex2TCoords),2 }, - { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1 | VERTEX4D_FORMAT_BUMP_DOT3, sizeof(S3DVertexTangents),2 }, - { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 2 }, // reflection map - { 0, sizeof(f32) * 3, 0 }, // core::vector3df* -}; - - - -/*! - fill a cache line with transformed, light and clipp test triangles -*/ -void CBurningVideoDriver::VertexCache_fill(const u32 sourceIndex, const u32 destIndex) -{ - u8 * source; - s4DVertex *dest; - - source = (u8*) VertexCache.vertices + ( sourceIndex * vSize[VertexCache.vType].Pitch ); - - // it's a look ahead so we never hit it.. - // but give priority... - //VertexCache.info[ destIndex ].hit = hitCount; - - // store info - VertexCache.info[ destIndex ].index = sourceIndex; - VertexCache.info[ destIndex ].hit = 0; - - // destination Vertex - dest = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( destIndex << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); - - // transform Model * World * Camera * Projection * NDCSpace matrix - const S3DVertex *base = ((S3DVertex*) source ); - Transformation [ ETS_CURRENT].transformVect ( &dest->Pos.x, base->Pos ); - - //mhm ;-) maybe no goto - if ( VertexCache.vType == 4 ) goto clipandproject; - - -#if defined (SOFTWARE_DRIVER_2_LIGHTING) || defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) - - // vertex normal in light space - if ( Material.org.Lighting || (LightSpace.Flags & VERTEXTRANSFORM) ) - { - if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) - { - LightSpace.normal.set ( base->Normal.X, base->Normal.Y, base->Normal.Z, 1.f ); - LightSpace.vertex.set ( base->Pos.X, base->Pos.Y, base->Pos.Z, 1.f ); - } - else - { - Transformation[ETS_WORLD].rotateVect ( &LightSpace.normal.x, base->Normal ); - - // vertex in light space - if ( LightSpace.Flags & ( POINTLIGHT | FOG | SPECULAR | VERTEXTRANSFORM) ) - Transformation[ETS_WORLD].transformVect ( &LightSpace.vertex.x, base->Pos ); - } - - if ( LightSpace.Flags & NORMALIZE ) - LightSpace.normal.normalize_xyz(); - - } - -#endif - -#if defined ( SOFTWARE_DRIVER_2_USE_VERTEX_COLOR ) - // apply lighting model - #if defined (SOFTWARE_DRIVER_2_LIGHTING) - if ( Material.org.Lighting ) - { - lightVertex ( dest, base->Color.color ); - } - else - { - dest->Color[0].setA8R8G8B8 ( base->Color.color ); - } - #else - dest->Color[0].setA8R8G8B8 ( base->Color.color ); - #endif -#endif - - // Texture Transform -#if !defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) - irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, - vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) - ); -#else - - if ( 0 == (LightSpace.Flags & VERTEXTRANSFORM) ) - { - irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, - vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) - ); - } - else - { - /* - Generate texture coordinates as linear functions so that: - u = Ux*x + Uy*y + Uz*z + Uw - v = Vx*x + Vy*y + Vz*z + Vw - The matrix M for this case is: - Ux Vx 0 0 - Uy Vy 0 0 - Uz Vz 0 0 - Uw Vw 0 0 - */ - - u32 t; - sVec4 n; - sVec2 srcT; - - for ( t = 0; t != vSize[VertexCache.vType].TexSize; ++t ) - { - const core::matrix4& M = Transformation [ ETS_TEXTURE_0 + t ]; - - // texgen - if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & (ETF_TEXGEN_CAMERA_NORMAL|ETF_TEXGEN_CAMERA_REFLECTION) ) - { - n.x = LightSpace.campos.x - LightSpace.vertex.x; - n.y = LightSpace.campos.x - LightSpace.vertex.y; - n.z = LightSpace.campos.x - LightSpace.vertex.z; - n.normalize_xyz(); - n.x += LightSpace.normal.x; - n.y += LightSpace.normal.y; - n.z += LightSpace.normal.z; - n.normalize_xyz(); - - const f32 *view = Transformation[ETS_VIEW].pointer(); - - if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & ETF_TEXGEN_CAMERA_REFLECTION ) - { - srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[4] + n.z * view[8] )); - srcT.y = 0.5f * ( 1.f + (n.x * view[1] + n.y * view[5] + n.z * view[9] )); - } - else - { - srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[1] + n.z * view[2] )); - srcT.y = 0.5f * ( 1.f + (n.x * view[4] + n.y * view[5] + n.z * view[6] )); - } - } - else - { - irr::memcpy32_small ( &srcT,(&base->TCoords) + t, - sizeof ( f32 ) * 2 ); - } - - switch ( Material.org.TextureLayer[t].TextureWrapU ) - { - case ETC_CLAMP: - case ETC_CLAMP_TO_EDGE: - case ETC_CLAMP_TO_BORDER: - dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); - break; - case ETC_MIRROR: - dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; - if (core::fract(dest->Tex[t].x)>0.5f) - dest->Tex[t].x=1.f-dest->Tex[t].x; - break; - case ETC_MIRROR_CLAMP: - case ETC_MIRROR_CLAMP_TO_EDGE: - case ETC_MIRROR_CLAMP_TO_BORDER: - dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); - if (core::fract(dest->Tex[t].x)>0.5f) - dest->Tex[t].x=1.f-dest->Tex[t].x; - break; - case ETC_REPEAT: - default: - dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; - break; - } - switch ( Material.org.TextureLayer[t].TextureWrapV ) - { - case ETC_CLAMP: - case ETC_CLAMP_TO_EDGE: - case ETC_CLAMP_TO_BORDER: - dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); - break; - case ETC_MIRROR: - dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; - if (core::fract(dest->Tex[t].y)>0.5f) - dest->Tex[t].y=1.f-dest->Tex[t].y; - break; - case ETC_MIRROR_CLAMP: - case ETC_MIRROR_CLAMP_TO_EDGE: - case ETC_MIRROR_CLAMP_TO_BORDER: - dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); - if (core::fract(dest->Tex[t].y)>0.5f) - dest->Tex[t].y=1.f-dest->Tex[t].y; - break; - case ETC_REPEAT: - default: - dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; - break; - } - } - } - -#if 0 - // tangent space light vector, emboss - if ( Lights.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) - { - const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); - const SBurningShaderLight &light = LightSpace.Light[0]; - - sVec4 vp; - - vp.x = light.pos.x - LightSpace.vertex.x; - vp.y = light.pos.y - LightSpace.vertex.y; - vp.z = light.pos.z - LightSpace.vertex.z; - - vp.normalize_xyz(); - - LightSpace.tangent.x = vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z; - LightSpace.tangent.y = vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z; - //LightSpace.tangent.z = vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z; - LightSpace.tangent.z = 0.f; - LightSpace.tangent.normalize_xyz(); - - f32 scale = 1.f / 128.f; - if ( Material.org.MaterialTypeParam > 0.f ) - scale = Material.org.MaterialTypeParam; - - // emboss, shift coordinates - dest->Tex[1].x = dest->Tex[0].x + LightSpace.tangent.x * scale; - dest->Tex[1].y = dest->Tex[0].y + LightSpace.tangent.y * scale; - //dest->Tex[1].z = LightSpace.tangent.z * scale; - } -#endif - - if ( LightSpace.Light.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) - { - const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); - - sVec4 vp; - - dest->LightTangent[0].x = 0.f; - dest->LightTangent[0].y = 0.f; - dest->LightTangent[0].z = 0.f; - for ( u32 i = 0; i < 2 && i < LightSpace.Light.size (); ++i ) - { - const SBurningShaderLight &light = LightSpace.Light[i]; - - if ( !light.LightIsOn ) - continue; - - vp.x = light.pos.x - LightSpace.vertex.x; - vp.y = light.pos.y - LightSpace.vertex.y; - vp.z = light.pos.z - LightSpace.vertex.z; - - /* - vp.x = light.pos_objectspace.x - base->Pos.X; - vp.y = light.pos_objectspace.y - base->Pos.Y; - vp.z = light.pos_objectspace.z - base->Pos.Z; - */ - - vp.normalize_xyz(); - - - // transform by tangent matrix - sVec3 l; - #if 1 - l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z ); - l.y = (vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z ); - l.z = (vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z ); - #else - l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Binormal.X + vp.z * tangent->Normal.X ); - l.y = (vp.x * tangent->Tangent.Y + vp.y * tangent->Binormal.Y + vp.z * tangent->Normal.Y ); - l.z = (vp.x * tangent->Tangent.Z + vp.y * tangent->Binormal.Z + vp.z * tangent->Normal.Z ); - #endif - - - /* - f32 scale = 1.f / 128.f; - scale /= dest->LightTangent[0].b; - - // emboss, shift coordinates - dest->Tex[1].x = dest->Tex[0].x + l.r * scale; - dest->Tex[1].y = dest->Tex[0].y + l.g * scale; - */ - dest->Tex[1].x = dest->Tex[0].x; - dest->Tex[1].y = dest->Tex[0].y; - - // scale bias - dest->LightTangent[0].x += l.x; - dest->LightTangent[0].y += l.y; - dest->LightTangent[0].z += l.z; - } - dest->LightTangent[0].setLength ( 0.5f ); - dest->LightTangent[0].x += 0.5f; - dest->LightTangent[0].y += 0.5f; - dest->LightTangent[0].z += 0.5f; - } - - -#endif - -clipandproject: - dest[0].flag = dest[1].flag = vSize[VertexCache.vType].Format; - - // test vertex - dest[0].flag |= clipToFrustumTest ( dest); - - // to DC Space, project homogenous vertex - if ( (dest[0].flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) - { - ndc_2_dc_and_project2 ( (const s4DVertex**) &dest, 1 ); - } - - //return dest; -} - -// - -REALINLINE s4DVertex * CBurningVideoDriver::VertexCache_getVertex ( const u32 sourceIndex ) -{ - for ( s32 i = 0; i < VERTEXCACHE_ELEMENT; ++i ) - { - if ( VertexCache.info[ i ].index == sourceIndex ) - { - return (s4DVertex *) ( (u8*) VertexCache.mem.data + ( i << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); - } - } - return 0; -} - - -/* - Cache based on linear walk indices - fill blockwise on the next 16(Cache_Size) unique vertices in indexlist - merge the next 16 vertices with the current -*/ -REALINLINE void CBurningVideoDriver::VertexCache_get(const s4DVertex ** face) -{ - SCacheInfo info[VERTEXCACHE_ELEMENT]; - - // next primitive must be complete in cache - if ( VertexCache.indicesIndex - VertexCache.indicesRun < 3 && - VertexCache.indicesIndex < VertexCache.indexCount - ) - { - // rewind to start of primitive - VertexCache.indicesIndex = VertexCache.indicesRun; - - irr::memset32 ( info, VERTEXCACHE_MISS, sizeof ( info ) ); - - // get the next unique vertices cache line - u32 fillIndex = 0; - u32 dIndex; - u32 i; - u32 sourceIndex; - - while ( VertexCache.indicesIndex < VertexCache.indexCount && - fillIndex < VERTEXCACHE_ELEMENT - ) - { - switch ( VertexCache.iType ) - { - case 1: - sourceIndex = ((u16*)VertexCache.indices) [ VertexCache.indicesIndex ]; - break; - case 2: - sourceIndex = ((u32*)VertexCache.indices) [ VertexCache.indicesIndex ]; - break; - case 4: - sourceIndex = VertexCache.indicesIndex; - break; - } - - VertexCache.indicesIndex += 1; - - // if not exist, push back - s32 exist = 0; - for ( dIndex = 0; dIndex < fillIndex; ++dIndex ) - { - if ( info[ dIndex ].index == sourceIndex ) - { - exist = 1; - break; - } - } - - if ( 0 == exist ) - { - info[fillIndex++].index = sourceIndex; - } - } - - // clear marks - for ( i = 0; i!= VERTEXCACHE_ELEMENT; ++i ) - { - VertexCache.info[i].hit = 0; - } - - // mark all existing - for ( i = 0; i!= fillIndex; ++i ) - { - for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) - { - if ( VertexCache.info[ dIndex ].index == info[i].index ) - { - info[i].hit = dIndex; - VertexCache.info[ dIndex ].hit = 1; - break; - } - } - } - - // fill new - for ( i = 0; i!= fillIndex; ++i ) - { - if ( info[i].hit != VERTEXCACHE_MISS ) - continue; - - for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) - { - if ( 0 == VertexCache.info[dIndex].hit ) - { - VertexCache_fill ( info[i].index, dIndex ); - VertexCache.info[dIndex].hit += 1; - info[i].hit = dIndex; - break; - } - } - } - } - - const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); - - switch ( VertexCache.iType ) - { - case 1: - { - const u16 *p = (const u16 *) VertexCache.indices; - face[0] = VertexCache_getVertex ( p[ i0 ] ); - face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); - face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); - } - break; - - case 2: - { - const u32 *p = (const u32 *) VertexCache.indices; - face[0] = VertexCache_getVertex ( p[ i0 ] ); - face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); - face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); - } - break; - - case 4: - face[0] = VertexCache_getVertex ( VertexCache.indicesRun + 0 ); - face[1] = VertexCache_getVertex ( VertexCache.indicesRun + 1 ); - face[2] = VertexCache_getVertex ( VertexCache.indicesRun + 2 ); - break; - default: - face[0] = face[1] = face[2] = VertexCache_getVertex(VertexCache.indicesRun + 0); - break; - } - - VertexCache.indicesRun += VertexCache.primitivePitch; -} - -/*! -*/ -REALINLINE void CBurningVideoDriver::VertexCache_getbypass ( s4DVertex ** face ) -{ - const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); - - if ( VertexCache.iType == 1 ) - { - const u16 *p = (const u16 *) VertexCache.indices; - VertexCache_fill ( p[ i0 ], 0 ); - VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); - VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); - } - else - { - const u32 *p = (const u32 *) VertexCache.indices; - VertexCache_fill ( p[ i0 ], 0 ); - VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); - VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); - } - - VertexCache.indicesRun += VertexCache.primitivePitch; - - face[0] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); - face[1] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); - face[2] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); - -} - -/*! -*/ -void CBurningVideoDriver::VertexCache_reset ( const void* vertices, u32 vertexCount, - const void* indices, u32 primitiveCount, - E_VERTEX_TYPE vType, - scene::E_PRIMITIVE_TYPE pType, - E_INDEX_TYPE iType) -{ - VertexCache.vertices = vertices; - VertexCache.vertexCount = vertexCount; - - VertexCache.indices = indices; - VertexCache.indicesIndex = 0; - VertexCache.indicesRun = 0; - - if ( Material.org.MaterialType == video::EMT_REFLECTION_2_LAYER ) - VertexCache.vType = 3; - else - VertexCache.vType = vType; - VertexCache.pType = pType; - - switch ( iType ) - { - case EIT_16BIT: VertexCache.iType = 1; break; - case EIT_32BIT: VertexCache.iType = 2; break; - default: - VertexCache.iType = iType; break; - } - - switch ( VertexCache.pType ) - { - // most types here will not work as expected, only triangles/triangle_fan - // is known to work. - case scene::EPT_POINTS: - VertexCache.indexCount = primitiveCount; - VertexCache.primitivePitch = 1; - break; - case scene::EPT_LINE_STRIP: - VertexCache.indexCount = primitiveCount+1; - VertexCache.primitivePitch = 1; - break; - case scene::EPT_LINE_LOOP: - VertexCache.indexCount = primitiveCount+1; - VertexCache.primitivePitch = 1; - break; - case scene::EPT_LINES: - VertexCache.indexCount = 2*primitiveCount; - VertexCache.primitivePitch = 2; - break; - case scene::EPT_TRIANGLE_STRIP: - VertexCache.indexCount = primitiveCount+2; - VertexCache.primitivePitch = 1; - break; - case scene::EPT_TRIANGLES: - VertexCache.indexCount = primitiveCount + primitiveCount + primitiveCount; - VertexCache.primitivePitch = 3; - break; - case scene::EPT_TRIANGLE_FAN: - VertexCache.indexCount = primitiveCount + 2; - VertexCache.primitivePitch = 1; - break; - case scene::EPT_QUAD_STRIP: - VertexCache.indexCount = 2*primitiveCount + 2; - VertexCache.primitivePitch = 2; - break; - case scene::EPT_QUADS: - VertexCache.indexCount = 4*primitiveCount; - VertexCache.primitivePitch = 4; - break; - case scene::EPT_POLYGON: - VertexCache.indexCount = primitiveCount+1; - VertexCache.primitivePitch = 1; - break; - case scene::EPT_POINT_SPRITES: - VertexCache.indexCount = primitiveCount; - VertexCache.primitivePitch = 1; - break; - } - - irr::memset32 ( VertexCache.info, VERTEXCACHE_MISS, sizeof ( VertexCache.info ) ); -} - - -void CBurningVideoDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, - const void* indexList, u32 primitiveCount, - E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) - -{ - if (!checkPrimitiveCount(primitiveCount)) - return; - - CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); - - // These calls would lead to crashes due to wrong index usage. - // The vertex cache needs to be rewritten for these primitives. - if (pType==scene::EPT_POINTS || pType==scene::EPT_LINE_STRIP || - pType==scene::EPT_LINE_LOOP || pType==scene::EPT_LINES || pType==scene::EPT_POLYGON || - pType==scene::EPT_POINT_SPRITES) - return; - - if ( 0 == CurrentShader ) - return; - - VertexCache_reset ( vertices, vertexCount, indexList, primitiveCount, vType, pType, iType ); - - const s4DVertex * face[3]; - - f32 dc_area; - s32 lodLevel; - u32 i; - u32 g; - u32 m; - video::CSoftwareTexture2* tex; - - for ( i = 0; i < (u32) primitiveCount; ++i ) - { - VertexCache_get(face); - - // if fully outside or outside on same side - if ( ( (face[0]->flag | face[1]->flag | face[2]->flag) & VERTEX4D_CLIPMASK ) - != VERTEX4D_INSIDE - ) - continue; - - // if fully inside - if ( ( face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) - { - dc_area = screenarea2 ( face ); - if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0( dc_area ) ) - continue; - else - if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) - continue; - - // select mipmap - dc_area = core::reciprocal ( dc_area ); - for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) - { - if ( 0 == (tex = MAT_TEXTURE ( m )) ) - { - CurrentShader->setTextureParam(m, 0, 0); - continue; - } - - lodLevel = s32_log2_f32 ( texelarea2 ( face, m ) * dc_area ); - CurrentShader->setTextureParam(m, tex, lodLevel ); - select_polygon_mipmap2 ( (s4DVertex**) face, m, tex->getSize() ); - } - - // rasterize - CurrentShader->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); - continue; - } - - // else if not complete inside clipping necessary - irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[0], SIZEOF_SVERTEX * 2 ); - irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[1], SIZEOF_SVERTEX * 2 ); - irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[2], SIZEOF_SVERTEX * 2 ); - - const u32 flag = CurrentOut.data->flag & VERTEX4D_FORMAT_MASK; - - for ( g = 0; g != CurrentOut.ElementSize; ++g ) - { - CurrentOut.data[g].flag = flag; - Temp.data[g].flag = flag; - } - - u32 vOut; - vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); - if ( vOut < 3 ) - continue; - - vOut <<= 1; - - // to DC Space, project homogenous vertex - ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); - -/* - // TODO: don't stick on 32 Bit Pointer - #define PointerAsValue(x) ( (u32) (u32*) (x) ) - - // if not complete inside clipping necessary - if ( ( test & VERTEX4D_INSIDE ) != VERTEX4D_INSIDE ) - { - u32 v[2] = { PointerAsValue ( Temp ) , PointerAsValue ( CurrentOut ) }; - for ( g = 0; g != 6; ++g ) - { - vOut = clipToHyperPlane ( (s4DVertex*) v[0], (s4DVertex*) v[1], vOut, NDCPlane[g] ); - if ( vOut < 3 ) - break; - - v[0] ^= v[1]; - v[1] ^= v[0]; - v[0] ^= v[1]; - } - - if ( vOut < 3 ) - continue; - - } -*/ - - // check 2d backface culling on first - dc_area = screenarea ( CurrentOut.data ); - if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0 ( dc_area ) ) - continue; - else if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) - continue; - - // select mipmap - dc_area = core::reciprocal ( dc_area ); - for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) - { - if ( 0 == (tex = MAT_TEXTURE ( m )) ) - { - CurrentShader->setTextureParam(m, 0, 0); - continue; - } - - lodLevel = s32_log2_f32 ( texelarea ( CurrentOut.data, m ) * dc_area ); - CurrentShader->setTextureParam(m, tex, lodLevel ); - select_polygon_mipmap ( CurrentOut.data, vOut, m, tex->getSize() ); - } - - - // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) - for ( g = 0; g <= vOut - 6; g += 2 ) - { - // rasterize - CurrentShader->drawTriangle ( CurrentOut.data + 0 + 1, - CurrentOut.data + g + 3, - CurrentOut.data + g + 5); - } - - } - - // dump statistics -/* - char buf [64]; - sprintf ( buf,"VCount:%d PCount:%d CacheMiss: %d", - vertexCount, primitiveCount, - VertexCache.CacheMiss - ); - os::Printer::log( buf ); -*/ - -} - - -//! Sets the dynamic ambient light color. The default color is -//! (0,0,0,0) which means it is dark. -//! \param color: New color of the ambient light. -void CBurningVideoDriver::setAmbientLight(const SColorf& color) -{ - LightSpace.Global_AmbientLight.setColorf ( color ); -} - - -//! adds a dynamic light -s32 CBurningVideoDriver::addDynamicLight(const SLight& dl) -{ - (void) CNullDriver::addDynamicLight( dl ); - - SBurningShaderLight l; -// l.org = dl; - l.Type = dl.Type; - l.LightIsOn = true; - - l.AmbientColor.setColorf ( dl.AmbientColor ); - l.DiffuseColor.setColorf ( dl.DiffuseColor ); - l.SpecularColor.setColorf ( dl.SpecularColor ); - - switch ( dl.Type ) - { - case video::ELT_DIRECTIONAL: - l.pos.x = -dl.Direction.X; - l.pos.y = -dl.Direction.Y; - l.pos.z = -dl.Direction.Z; - l.pos.w = 1.f; - break; - case ELT_POINT: - case ELT_SPOT: - LightSpace.Flags |= POINTLIGHT; - l.pos.x = dl.Position.X; - l.pos.y = dl.Position.Y; - l.pos.z = dl.Position.Z; - l.pos.w = 1.f; -/* - l.radius = (1.f / dl.Attenuation.Y) * (1.f / dl.Attenuation.Y); - l.constantAttenuation = dl.Attenuation.X; - l.linearAttenuation = dl.Attenuation.Y; - l.quadraticAttenuation = dl.Attenuation.Z; -*/ - l.radius = dl.Radius * dl.Radius; - l.constantAttenuation = dl.Attenuation.X; - l.linearAttenuation = 1.f / dl.Radius; - l.quadraticAttenuation = dl.Attenuation.Z; - - break; - default: - break; - } - - LightSpace.Light.push_back ( l ); - return LightSpace.Light.size() - 1; -} - -//! Turns a dynamic light on or off -void CBurningVideoDriver::turnLightOn(s32 lightIndex, bool turnOn) -{ - if(lightIndex > -1 && lightIndex < (s32)LightSpace.Light.size()) - { - LightSpace.Light[lightIndex].LightIsOn = turnOn; - } -} - -//! deletes all dynamic lights there are -void CBurningVideoDriver::deleteAllDynamicLights() -{ - LightSpace.reset (); - CNullDriver::deleteAllDynamicLights(); - -} - -//! returns the maximal amount of dynamic lights the device can handle -u32 CBurningVideoDriver::getMaximalDynamicLightAmount() const -{ - return 8; -} - - -//! sets a material -void CBurningVideoDriver::setMaterial(const SMaterial& material) -{ - Material.org = material; - -#ifdef SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM - for (u32 i = 0; i < 2; ++i) - { - setTransform((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i), - material.getTextureMatrix(i)); - } -#endif - -#ifdef SOFTWARE_DRIVER_2_LIGHTING - Material.AmbientColor.setR8G8B8 ( Material.org.AmbientColor.color ); - Material.DiffuseColor.setR8G8B8 ( Material.org.DiffuseColor.color ); - Material.EmissiveColor.setR8G8B8 ( Material.org.EmissiveColor.color ); - Material.SpecularColor.setR8G8B8 ( Material.org.SpecularColor.color ); - - core::setbit_cond ( LightSpace.Flags, Material.org.Shininess != 0.f, SPECULAR ); - core::setbit_cond ( LightSpace.Flags, Material.org.FogEnable, FOG ); - core::setbit_cond ( LightSpace.Flags, Material.org.NormalizeNormals, NORMALIZE ); -#endif - - setCurrentShader(); -} - - -/*! - Camera Position in World Space -*/ -void CBurningVideoDriver::getCameraPosWorldSpace () -{ - Transformation[ETS_VIEW_INVERSE] = Transformation[ ETS_VIEW ]; - Transformation[ETS_VIEW_INVERSE].makeInverse (); - TransformationFlag[ETS_VIEW_INVERSE] = 0; - - const f32 *M = Transformation[ETS_VIEW_INVERSE].pointer (); - - /* The viewpoint is at (0., 0., 0.) in eye space. - Turning this into a vector [0 0 0 1] and multiply it by - the inverse of the view matrix, the resulting vector is the - object space location of the camera. - */ - - LightSpace.campos.x = M[12]; - LightSpace.campos.y = M[13]; - LightSpace.campos.z = M[14]; - LightSpace.campos.w = 1.f; -} - -void CBurningVideoDriver::getLightPosObjectSpace () -{ - if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) - { - Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; - TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; - } - else - { - Transformation[ETS_WORLD].getInverse ( Transformation[ETS_WORLD_INVERSE] ); - TransformationFlag[ETS_WORLD_INVERSE] &= ~ETF_IDENTITY; - } - - for ( u32 i = 0; i < 1 && i < LightSpace.Light.size(); ++i ) - { - SBurningShaderLight &l = LightSpace.Light[i]; - - Transformation[ETS_WORLD_INVERSE].transformVec3 ( &l.pos_objectspace.x, &l.pos.x ); - } -} - - -#ifdef SOFTWARE_DRIVER_2_LIGHTING - -//! Sets the fog mode. -void CBurningVideoDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, - f32 end, f32 density, bool pixelFog, bool rangeFog) -{ - CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog); - LightSpace.FogColor.setA8R8G8B8 ( color.color ); -} - -/*! - applies lighting model -*/ -void CBurningVideoDriver::lightVertex ( s4DVertex *dest, u32 vertexargb ) -{ - sVec3 dColor; - - dColor = LightSpace.Global_AmbientLight; - dColor.add ( Material.EmissiveColor ); - - if ( Lights.size () == 0 ) - { - dColor.saturate( dest->Color[0], vertexargb); - return; - } - - sVec3 ambient; - sVec3 diffuse; - sVec3 specular; - - - // the universe started in darkness.. - ambient.set ( 0.f, 0.f, 0.f ); - diffuse.set ( 0.f, 0.f, 0.f ); - specular.set ( 0.f, 0.f, 0.f ); - - - u32 i; - f32 dot; - f32 len; - f32 attenuation; - sVec4 vp; // unit vector vertex to light - sVec4 lightHalf; // blinn-phong reflection - - for ( i = 0; i!= LightSpace.Light.size (); ++i ) - { - const SBurningShaderLight &light = LightSpace.Light[i]; - - if ( !light.LightIsOn ) - continue; - - // accumulate ambient - ambient.add ( light.AmbientColor ); - - switch ( light.Type ) - { - case video::ELT_SPOT: - case video::ELT_POINT: - // surface to light - vp.x = light.pos.x - LightSpace.vertex.x; - vp.y = light.pos.y - LightSpace.vertex.y; - vp.z = light.pos.z - LightSpace.vertex.z; - //vp.x = light.pos_objectspace.x - LightSpace.vertex.x; - //vp.y = light.pos_objectspace.y - LightSpace.vertex.x; - //vp.z = light.pos_objectspace.z - LightSpace.vertex.x; - - len = vp.get_length_xyz_square(); - if ( light.radius < len ) - continue; - - len = core::reciprocal_squareroot ( len ); - - // build diffuse reflection - - //angle between normal and light vector - vp.mul ( len ); - dot = LightSpace.normal.dot_xyz ( vp ); - if ( dot < 0.f ) - continue; - - attenuation = light.constantAttenuation + ( 1.f - ( len * light.linearAttenuation ) ); - - // diffuse component - diffuse.mulAdd ( light.DiffuseColor, 3.f * dot * attenuation ); - - if ( !(LightSpace.Flags & SPECULAR) ) - continue; - - // build specular - // surface to view - lightHalf.x = LightSpace.campos.x - LightSpace.vertex.x; - lightHalf.y = LightSpace.campos.y - LightSpace.vertex.y; - lightHalf.z = LightSpace.campos.z - LightSpace.vertex.z; - lightHalf.normalize_xyz(); - lightHalf += vp; - lightHalf.normalize_xyz(); - - // specular - dot = LightSpace.normal.dot_xyz ( lightHalf ); - if ( dot < 0.f ) - continue; - - //specular += light.SpecularColor * ( powf ( Material.org.Shininess ,dot ) * attenuation ); - specular.mulAdd ( light.SpecularColor, dot * attenuation ); - break; - - case video::ELT_DIRECTIONAL: - - //angle between normal and light vector - dot = LightSpace.normal.dot_xyz ( light.pos ); - if ( dot < 0.f ) - continue; - - // diffuse component - diffuse.mulAdd ( light.DiffuseColor, dot ); - break; - default: - break; - } - - } - - // sum up lights - dColor.mulAdd (ambient, Material.AmbientColor ); - dColor.mulAdd (diffuse, Material.DiffuseColor); - dColor.mulAdd (specular, Material.SpecularColor); - - dColor.saturate ( dest->Color[0], vertexargb ); -} - -#endif - - -//! 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. -void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::position2d& destPos, - const core::rect& sourceRect, - const core::rect* clipRect, SColor color, - bool useAlphaChannelOfTexture) -{ - if (texture) - { - if (texture->getDriverType() != EDT_BURNINGSVIDEO) - { - os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); - return; - } - -#if 0 - // 2d methods don't use viewPort - core::position2di dest = destPos; - core::recti clip=ViewPort; - if (ViewPort.getSize().Width != ScreenSize.Width) - { - dest.X=ViewPort.UpperLeftCorner.X+core::round32(destPos.X*ViewPort.getWidth()/(f32)ScreenSize.Width); - dest.Y=ViewPort.UpperLeftCorner.Y+core::round32(destPos.Y*ViewPort.getHeight()/(f32)ScreenSize.Height); - if (clipRect) - { - clip.constrainTo(*clipRect); - } - clipRect = &clip; - } -#endif - if (useAlphaChannelOfTexture) - ((CSoftwareTexture2*)texture)->getImage()->copyToWithAlpha( - RenderTargetSurface, destPos, sourceRect, color, clipRect); - else - ((CSoftwareTexture2*)texture)->getImage()->copyTo( - RenderTargetSurface, destPos, sourceRect, clipRect); - } -} - - -//! Draws a part of the texture into the rectangle. -void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, - const core::rect& sourceRect, const core::rect* clipRect, - const video::SColor* const colors, bool useAlphaChannelOfTexture) -{ - if (texture) - { - if (texture->getDriverType() != EDT_BURNINGSVIDEO) - { - os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); - return; - } - - if (useAlphaChannelOfTexture) - StretchBlit(BLITTER_TEXTURE_ALPHA_BLEND, RenderTargetSurface, &destRect, &sourceRect, - ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); - else - StretchBlit(BLITTER_TEXTURE, RenderTargetSurface, &destRect, &sourceRect, - ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); - } -} - -//! Draws a 2d line. -void CBurningVideoDriver::draw2DLine(const core::position2d& start, - const core::position2d& end, - SColor color) -{ - drawLine(BackBuffer, start, end, color ); -} - - -//! Draws a pixel -void CBurningVideoDriver::drawPixel(u32 x, u32 y, const SColor & color) -{ - BackBuffer->setPixel(x, y, color, true); -} - - -//! draw an 2d rectangle -void CBurningVideoDriver::draw2DRectangle(SColor color, const core::rect& pos, - const core::rect* clip) -{ - if (clip) - { - core::rect p(pos); - - p.clipAgainst(*clip); - - if(!p.isValid()) - return; - - drawRectangle(BackBuffer, p, color); - } - else - { - if(!pos.isValid()) - return; - - drawRectangle(BackBuffer, pos, color); - } -} - - -//! Only used by the internal engine. Used to notify the driver that -//! the window was resized. -void CBurningVideoDriver::OnResize(const core::dimension2d& size) -{ - // make sure width and height are multiples of 2 - core::dimension2d realSize(size); - - if (realSize.Width % 2) - realSize.Width += 1; - - if (realSize.Height % 2) - realSize.Height += 1; - - if (ScreenSize != realSize) - { - if (ViewPort.getWidth() == (s32)ScreenSize.Width && - ViewPort.getHeight() == (s32)ScreenSize.Height) - { - ViewPort.UpperLeftCorner.X = 0; - ViewPort.UpperLeftCorner.Y = 0; - ViewPort.LowerRightCorner.X = realSize.Width; - ViewPort.LowerRightCorner.X = realSize.Height; - } - - ScreenSize = realSize; - - bool resetRT = (RenderTargetSurface == BackBuffer); - - if (BackBuffer) - BackBuffer->drop(); - BackBuffer = new CImage(BURNINGSHADER_COLOR_FORMAT, realSize); - - if (resetRT) - setRenderTarget(BackBuffer); - } -} - - -//! returns the current render target size -const core::dimension2d& CBurningVideoDriver::getCurrentRenderTargetSize() const -{ - return RenderTargetSize; -} - - -//!Draws an 2d rectangle with a gradient. -void CBurningVideoDriver::draw2DRectangle(const core::rect& position, - SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, - const core::rect* clip) -{ -#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR - - core::rect pos = position; - - if (clip) - pos.clipAgainst(*clip); - - if (!pos.isValid()) - return; - - const core::dimension2d renderTargetSize ( ViewPort.getSize() ); - - const s32 xPlus = -(renderTargetSize.Width>>1); - const f32 xFact = 1.0f / (renderTargetSize.Width>>1); - - const s32 yPlus = renderTargetSize.Height-(renderTargetSize.Height>>1); - const f32 yFact = 1.0f / (renderTargetSize.Height>>1); - - // fill VertexCache direct - s4DVertex *v; - - VertexCache.vertexCount = 4; - - VertexCache.info[0].index = 0; - VertexCache.info[1].index = 1; - VertexCache.info[2].index = 2; - VertexCache.info[3].index = 3; - - v = &VertexCache.mem.data [ 0 ]; - - v[0].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); - v[0].Color[0].setA8R8G8B8 ( colorLeftUp.color ); - - v[2].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus- pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); - v[2].Color[0].setA8R8G8B8 ( colorRightUp.color ); - - v[4].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f ,1.f ); - v[4].Color[0].setA8R8G8B8 ( colorRightDown.color ); - - v[6].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f, 1.f ); - v[6].Color[0].setA8R8G8B8 ( colorLeftDown.color ); - - s32 i; - u32 g; - - for ( i = 0; i!= 8; i += 2 ) - { - v[i + 0].flag = clipToFrustumTest ( v + i ); - v[i + 1].flag = 0; - if ( (v[i].flag & VERTEX4D_INSIDE ) == VERTEX4D_INSIDE ) - { - ndc_2_dc_and_project ( v + i + 1, v + i, 2 ); - } - } - - - IBurningShader * render; - - render = BurningShader [ ETR_GOURAUD_ALPHA_NOZ ]; - render->setRenderTarget(RenderTargetSurface, ViewPort); - - static const s16 indexList[6] = {0,1,2,0,2,3}; - - s4DVertex * face[3]; - - for ( i = 0; i!= 6; i += 3 ) - { - face[0] = VertexCache_getVertex ( indexList [ i + 0 ] ); - face[1] = VertexCache_getVertex ( indexList [ i + 1 ] ); - face[2] = VertexCache_getVertex ( indexList [ i + 2 ] ); - - // test clipping - u32 test = face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_INSIDE; - - if ( test == VERTEX4D_INSIDE ) - { - render->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); - continue; - } - // Todo: all vertices are clipped in 2d.. - // is this true ? - u32 vOut = 6; - memcpy ( CurrentOut.data + 0, face[0], sizeof ( s4DVertex ) * 2 ); - memcpy ( CurrentOut.data + 2, face[1], sizeof ( s4DVertex ) * 2 ); - memcpy ( CurrentOut.data + 4, face[2], sizeof ( s4DVertex ) * 2 ); - - vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); - if ( vOut < 3 ) - continue; - - vOut <<= 1; - // to DC Space, project homogenous vertex - ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); - - // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) - for ( g = 0; g <= vOut - 6; g += 2 ) - { - // rasterize - render->drawTriangle ( CurrentOut.data + 1, &CurrentOut.data[g + 3], &CurrentOut.data[g + 5] ); - } - - } -#else - draw2DRectangle ( colorLeftUp, position, clip ); -#endif -} - - -//! Draws a 3d line. -void CBurningVideoDriver::draw3DLine(const core::vector3df& start, - const core::vector3df& end, SColor color) -{ - Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[0].Pos.x, start ); - Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[2].Pos.x, end ); - - u32 g; - u32 vOut; - - // no clipping flags - for ( g = 0; g != CurrentOut.ElementSize; ++g ) - { - CurrentOut.data[g].flag = 0; - Temp.data[g].flag = 0; - } - - // vertices count per line - vOut = clipToFrustum ( CurrentOut.data, Temp.data, 2 ); - if ( vOut < 2 ) - return; - - vOut <<= 1; - - IBurningShader * line; - line = BurningShader [ ETR_TEXTURE_GOURAUD_WIRE ]; - line->setRenderTarget(RenderTargetSurface, ViewPort); - - // to DC Space, project homogenous vertex - ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); - - // unproject vertex color -#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR - for ( g = 0; g != vOut; g+= 2 ) - { - CurrentOut.data[ g + 1].Color[0].setA8R8G8B8 ( color.color ); - } -#endif - - - for ( g = 0; g <= vOut - 4; g += 2 ) - { - // rasterize - line->drawLine ( CurrentOut.data + 1, CurrentOut.data + g + 3 ); - } -} - - -//! \return Returns the name of the video driver. Example: In case of the DirectX8 -//! driver, it would return "Direct3D8.1". -const wchar_t* CBurningVideoDriver::getName() const -{ -#ifdef BURNINGVIDEO_RENDERER_BEAUTIFUL - return L"Burning's Video 0.47 beautiful"; -#elif defined ( BURNINGVIDEO_RENDERER_ULTRA_FAST ) - return L"Burning's Video 0.47 ultra fast"; -#elif defined ( BURNINGVIDEO_RENDERER_FAST ) - return L"Burning's Video 0.47 fast"; -#else - return L"Burning's Video 0.47"; -#endif -} - -//! Returns the graphics card vendor name. -core::stringc CBurningVideoDriver::getVendorInfo() -{ - return "Burning's Video: Ing. Thomas Alten (c) 2006-2012"; -} - - -//! Returns type of video driver -E_DRIVER_TYPE CBurningVideoDriver::getDriverType() const -{ - return EDT_BURNINGSVIDEO; -} - - -//! returns color format -ECOLOR_FORMAT CBurningVideoDriver::getColorFormat() const -{ - return BURNINGSHADER_COLOR_FORMAT; -} - - -//! Returns the transformation set by setTransform -const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE state) const -{ - return Transformation[state]; -} - - -//! Creates a render target texture. -ITexture* CBurningVideoDriver::addRenderTargetTexture(const core::dimension2d& size, - const io::path& name, const ECOLOR_FORMAT format) -{ - IImage* img = createImage(BURNINGSHADER_COLOR_FORMAT, size); - ITexture* tex = new CSoftwareTexture2(img, name, CSoftwareTexture2::IS_RENDERTARGET ); - img->drop(); - addTexture(tex); - tex->drop(); - return tex; -} - - -//! Clears the DepthBuffer. -void CBurningVideoDriver::clearZBuffer() -{ - if (DepthBuffer) - DepthBuffer->clear(); -} - - -//! Returns an image created from the last rendered frame. -IImage* CBurningVideoDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) -{ - if (target != video::ERT_FRAME_BUFFER) - return 0; - - if (BackBuffer) - { - IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension()); - BackBuffer->copyTo(tmp); - return tmp; - } - else - return 0; -} - - -//! returns a device dependent texture from a software surface (IImage) -//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES -ITexture* CBurningVideoDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData) -{ - return new CSoftwareTexture2( - surface, name, - (getTextureCreationFlag(ETCF_CREATE_MIP_MAPS) ? CSoftwareTexture2::GEN_MIPMAP : 0 ) | - (getTextureCreationFlag(ETCF_ALLOW_NON_POWER_2) ? 0 : CSoftwareTexture2::NP2_SIZE ), mipmapData); - -} - - -//! Returns the maximum amount of primitives (mostly vertices) which -//! the device is able to render with one drawIndexedTriangleList -//! call. -u32 CBurningVideoDriver::getMaximalPrimitiveCount() const -{ - return 0xFFFFFFFF; -} - - -//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do -//! this: First, draw all geometry. Then use this method, to draw the shadow -//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. -void CBurningVideoDriver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) -{ - const u32 count = triangles.size(); - IBurningShader *shader = BurningShader [ ETR_STENCIL_SHADOW ]; - - CurrentShader = shader; - shader->setRenderTarget(RenderTargetSurface, ViewPort); - - Material.org.MaterialType = video::EMT_SOLID; - Material.org.Lighting = false; - Material.org.ZWriteEnable = false; - Material.org.ZBuffer = ECFN_LESSEQUAL; - LightSpace.Flags &= ~VERTEXTRANSFORM; - - //glStencilMask(~0); - //glStencilFunc(GL_ALWAYS, 0, ~0); - - if (true)// zpass does not work yet - { - Material.org.BackfaceCulling = true; - Material.org.FrontfaceCulling = false; - shader->setParam ( 0, 0 ); - shader->setParam ( 1, 1 ); - shader->setParam ( 2, 0 ); - drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); - //glStencilOp(GL_KEEP, incr, GL_KEEP); - //glDrawArrays(GL_TRIANGLES,0,count); - - Material.org.BackfaceCulling = false; - Material.org.FrontfaceCulling = true; - shader->setParam ( 0, 0 ); - shader->setParam ( 1, 2 ); - shader->setParam ( 2, 0 ); - drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); - //glStencilOp(GL_KEEP, decr, GL_KEEP); - //glDrawArrays(GL_TRIANGLES,0,count); - } - else // zpass - { - Material.org.BackfaceCulling = true; - Material.org.FrontfaceCulling = false; - shader->setParam ( 0, 0 ); - shader->setParam ( 1, 0 ); - shader->setParam ( 2, 1 ); - //glStencilOp(GL_KEEP, GL_KEEP, incr); - //glDrawArrays(GL_TRIANGLES,0,count); - - Material.org.BackfaceCulling = false; - Material.org.FrontfaceCulling = true; - shader->setParam ( 0, 0 ); - shader->setParam ( 1, 0 ); - shader->setParam ( 2, 2 ); - //glStencilOp(GL_KEEP, GL_KEEP, decr); - //glDrawArrays(GL_TRIANGLES,0,count); - } -} - -//! Fills the stencil shadow with color. After the shadow volume has been drawn -//! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this -//! to draw the color of the shadow. -void CBurningVideoDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, - video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) -{ - if (!StencilBuffer) - return; - // draw a shadow rectangle covering the entire screen using stencil buffer - const u32 h = RenderTargetSurface->getDimension().Height; - const u32 w = RenderTargetSurface->getDimension().Width; - tVideoSample *dst; - u32 *stencil; - u32* const stencilBase=(u32*) StencilBuffer->lock(); - - for ( u32 y = 0; y < h; ++y ) - { - dst = (tVideoSample*)RenderTargetSurface->lock() + ( y * w ); - stencil = stencilBase + ( y * w ); - - for ( u32 x = 0; x < w; ++x ) - { - if ( stencil[x] > 1 ) - { - dst[x] = PixelBlend32 ( dst[x], leftUpEdge.color ); - } - } - } - - StencilBuffer->clear(); -} - - -core::dimension2du CBurningVideoDriver::getMaxTextureSize() const -{ - return core::dimension2du(SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE, SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE); -} - - -} // end namespace video -} // end namespace irr - -#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ - -namespace irr -{ -namespace video -{ - -//! creates a video driver -IVideoDriver* createBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter) -{ - #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ - return new CBurningVideoDriver(params, io, presenter); - #else - return 0; - #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ -} - - - -} // end namespace video -} // end namespace irr - +// 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" +#include "CSoftwareDriver2.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +#include "SoftwareDriver2_helper.h" +#include "CSoftwareTexture2.h" +#include "CSoftware2MaterialRenderer.h" +#include "S3DVertex.h" +#include "S4DVertex.h" +#include "CBlit.h" + + +#define MAT_TEXTURE(tex) ( (video::CSoftwareTexture2*) Material.org.getTexture ( tex ) ) + + +namespace irr +{ +namespace video +{ + +namespace glsl +{ + +typedef sVec4 vec4; +typedef sVec3 vec3; +typedef sVec2 vec2; + +#define in +#define uniform +#define attribute +#define varying + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +struct mat4{ + float m[4][4]; + + vec4 operator* ( const vec4 &in ) const + { + vec4 out; + return out; + } + +}; + +struct mat3{ + float m[3][3]; + + vec3 operator* ( const vec3 &in ) const + { + vec3 out; + return out; + } +}; + +const int gl_MaxLights = 8; + + +inline float dot (float x, float y) { return x * y; } +inline float dot ( const vec2 &x, const vec2 &y) { return x.x * y.x + x.y * y.y; } +inline float dot ( const vec3 &x, const vec3 &y) { return x.x * y.x + x.y * y.y + x.z * y.z; } +inline float dot ( const vec4 &x, const vec4 &y) { return x.x * y.x + x.y * y.y + x.z * y.z + x.w * y.w; } + +inline float reflect (float I, float N) { return I - 2.0 * dot (N, I) * N; } +inline vec2 reflect (const vec2 &I, const vec2 &N) { return I - N * 2.0 * dot (N, I); } +inline vec3 reflect (const vec3 &I, const vec3 &N) { return I - N * 2.0 * dot (N, I); } +inline vec4 reflect (const vec4 &I, const vec4 &N) { return I - N * 2.0 * dot (N, I); } + + +inline float refract (float I, float N, float eta){ + const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); + if (k < 0.0) + return 0.0; + return eta * I - (eta * dot (N, I) + sqrt (k)) * N; +} + +inline vec2 refract (const vec2 &I, const vec2 &N, float eta){ + const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); + if (k < 0.0) + return vec2 (0.0); + return I * eta - N * (eta * dot (N, I) + sqrt (k)); +} + +inline vec3 refract (const vec3 &I, const vec3 &N, float eta) { + const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); + if (k < 0.0) + return vec3 (0.0); + return I * eta - N * (eta * dot (N, I) + sqrt (k)); +} + +inline vec4 refract (const vec4 &I, const vec4 &N, float eta) { + const float k = 1.0 - eta * eta * (1.0 - dot (N, I) * dot (N, I)); + if (k < 0.0) + return vec4 (0.0); + return I * eta - N * (eta * dot (N, I) + sqrt (k)); +} + + +inline float length ( const vec3 &v ) { return sqrtf ( v.x * v.x + v.y * v.y + v.z * v.z ); } +vec3 normalize ( const vec3 &v ) { float l = 1.f / length ( v ); return vec3 ( v.x * l, v.y * l, v.z * l ); } +float max ( float a, float b ) { return a > b ? a : b; } +float min ( float a, float b ) { return a < b ? a : b; } +vec4 clamp ( const vec4 &a, f32 low, f32 high ) { return vec4 ( min (max(a.x,low), high), min (max(a.y,low), high), min (max(a.z,low), high), min (max(a.w,low), high) ); } + + + +typedef int sampler2D; +sampler2D texUnit0; + +vec4 texture2D (sampler2D sampler, const vec2 &coord) { return vec4 (0.0); } + +struct gl_LightSourceParameters { + vec4 ambient; // Acli + vec4 diffuse; // Dcli + vec4 specular; // Scli + vec4 position; // Ppli + vec4 halfVector; // Derived: Hi + vec3 spotDirection; // Sdli + float spotExponent; // Srli + float spotCutoff; // Crli + // (range: [0.0,90.0], 180.0) + float spotCosCutoff; // Derived: cos(Crli) + // (range: [1.0,0.0],-1.0) + float constantAttenuation; // K0 + float linearAttenuation; // K1 + float quadraticAttenuation;// K2 +}; + +uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights]; + +struct gl_LightModelParameters { + vec4 ambient; +}; +uniform gl_LightModelParameters gl_LightModel; + +struct gl_LightModelProducts { + vec4 sceneColor; +}; + +uniform gl_LightModelProducts gl_FrontLightModelProduct; +uniform gl_LightModelProducts gl_BackLightModelProduct; + +struct gl_LightProducts { + vec4 ambient; + vec4 diffuse; + vec4 specular; +}; + +uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights]; +uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights]; + +struct gl_MaterialParameters +{ + vec4 emission; // Ecm + vec4 ambient; // Acm + vec4 diffuse; // Dcm + vec4 specular; // Scm + float shininess; // Srm +}; +uniform gl_MaterialParameters gl_FrontMaterial; +uniform gl_MaterialParameters gl_BackMaterial; + +// GLSL has some built-in attributes in a vertex shader: +attribute vec4 gl_Vertex; // 4D vector representing the vertex position +attribute vec3 gl_Normal; // 3D vector representing the vertex normal +attribute vec4 gl_Color; // 4D vector representing the vertex color +attribute vec4 gl_MultiTexCoord0; // 4D vector representing the texture coordinate of texture unit X +attribute vec4 gl_MultiTexCoord1; // 4D vector representing the texture coordinate of texture unit X + +uniform mat4 gl_ModelViewMatrix; //4x4 Matrix representing the model-view matrix. +uniform mat4 gl_ModelViewProjectionMatrix; //4x4 Matrix representing the model-view-projection matrix. +uniform mat3 gl_NormalMatrix; //3x3 Matrix representing the inverse transpose model-view matrix. This matrix is used for normal transformation. + + +varying vec4 gl_FrontColor; // 4D vector representing the primitives front color +varying vec4 gl_FrontSecondaryColor; // 4D vector representing the primitives second front color +varying vec4 gl_BackColor; // 4D vector representing the primitives back color +varying vec4 gl_TexCoord[4]; // 4D vector representing the Xth texture coordinate + +// shader output +varying vec4 gl_Position; // 4D vector representing the final processed vertex position. Only available in vertex shader. +varying vec4 gl_FragColor; // 4D vector representing the final color which is written in the frame buffer. Only available in fragment shader. +varying float gl_FragDepth; // float representing the depth which is written in the depth buffer. Only available in fragment shader. + +varying vec4 gl_SecondaryColor; +varying float gl_FogFragCoord; + + +vec4 ftransform(void) +{ + return gl_ModelViewProjectionMatrix * gl_Vertex; +} + +vec3 fnormal(void) +{ + //Compute the normal + vec3 normal = gl_NormalMatrix * gl_Normal; + normal = normalize(normal); + return normal; +} + + +struct program1 +{ + vec4 Ambient; + vec4 Diffuse; + vec4 Specular; + + void pointLight(in int i, in vec3 normal, in vec3 eye, in vec3 ecPosition3) + { + float nDotVP; // normal . light direction + float nDotHV; // normal . light half vector + float pf; // power factor + float attenuation; // computed attenuation factor + float d; // distance from surface to light source + vec3 VP; // direction from surface to light position + vec3 halfVector; // direction of maximum highlights + + // Compute vector from surface to light position + VP = vec3 (gl_LightSource[i].position) - ecPosition3; + + // Compute distance between surface and light position + d = length(VP); + + // Normalize the vector from surface to light position + VP = normalize(VP); + + // Compute attenuation + attenuation = 1.0 / (gl_LightSource[i].constantAttenuation + + gl_LightSource[i].linearAttenuation * d + + gl_LightSource[i].quadraticAttenuation * d * d); + + halfVector = normalize(VP + eye); + + nDotVP = max(0.0, dot(normal, VP)); + nDotHV = max(0.0, dot(normal, halfVector)); + + if (nDotVP == 0.0) + { + pf = 0.0; + } + else + { + pf = pow(nDotHV, gl_FrontMaterial.shininess); + + } + Ambient += gl_LightSource[i].ambient * attenuation; + Diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation; + Specular += gl_LightSource[i].specular * pf * attenuation; + } + + vec3 fnormal(void) + { + //Compute the normal + vec3 normal = gl_NormalMatrix * gl_Normal; + normal = normalize(normal); + return normal; + } + + void ftexgen(in vec3 normal, in vec4 ecPosition) + { + + gl_TexCoord[0] = gl_MultiTexCoord0; + } + + void flight(in vec3 normal, in vec4 ecPosition, float alphaFade) + { + vec4 color; + vec3 ecPosition3; + vec3 eye; + + ecPosition3 = (vec3 (ecPosition)) / ecPosition.w; + eye = vec3 (0.0, 0.0, 1.0); + + // Clear the light intensity accumulators + Ambient = vec4 (0.0); + Diffuse = vec4 (0.0); + Specular = vec4 (0.0); + + pointLight(0, normal, eye, ecPosition3); + + pointLight(1, normal, eye, ecPosition3); + + color = gl_FrontLightModelProduct.sceneColor + + Ambient * gl_FrontMaterial.ambient + + Diffuse * gl_FrontMaterial.diffuse; + gl_FrontSecondaryColor = Specular * gl_FrontMaterial.specular; + color = clamp( color, 0.0, 1.0 ); + gl_FrontColor = color; + + gl_FrontColor.a *= alphaFade; + } + + + void vertexshader_main (void) + { + vec3 transformedNormal; + float alphaFade = 1.0; + + // Eye-coordinate position of vertex, needed in various calculations + vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex; + + // Do fixed functionality vertex transform + gl_Position = ftransform(); + transformedNormal = fnormal(); + flight(transformedNormal, ecPosition, alphaFade); + ftexgen(transformedNormal, ecPosition); + } + + void fragmentshader_main (void) + { + vec4 color; + + color = gl_Color; + + color *= texture2D(texUnit0, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y) ); + + color += gl_SecondaryColor; + color = clamp(color, 0.0, 1.0); + + gl_FragColor = color; + } +}; + +} + +//! constructor +CBurningVideoDriver::CBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter) +: CNullDriver(io, params.WindowSize), BackBuffer(0), Presenter(presenter), + WindowId(0), SceneSourceRect(0), + RenderTargetTexture(0), RenderTargetSurface(0), CurrentShader(0), + DepthBuffer(0), StencilBuffer ( 0 ), + CurrentOut ( 12 * 2, 128 ), Temp ( 12 * 2, 128 ) +{ + #ifdef _DEBUG + setDebugName("CBurningVideoDriver"); + #endif + + // create backbuffer + BackBuffer = new CImage(BURNINGSHADER_COLOR_FORMAT, params.WindowSize); + if (BackBuffer) + { + BackBuffer->fill(SColor(0)); + + // create z buffer + if ( params.ZBufferBits ) + DepthBuffer = video::createDepthBuffer(BackBuffer->getDimension()); + + // create stencil buffer + if ( params.Stencilbuffer ) + StencilBuffer = video::createStencilBuffer(BackBuffer->getDimension()); + } + + DriverAttributes->setAttribute("MaxTextures", 2); + DriverAttributes->setAttribute("MaxIndices", 1<<16); + DriverAttributes->setAttribute("MaxTextureSize", 1024); + DriverAttributes->setAttribute("MaxLights", glsl::gl_MaxLights); + DriverAttributes->setAttribute("MaxTextureLODBias", 16.f); + DriverAttributes->setAttribute("Version", 47); + + // create triangle renderers + + irr::memset32 ( BurningShader, 0, sizeof ( BurningShader ) ); + //BurningShader[ETR_FLAT] = createTRFlat2(DepthBuffer); + //BurningShader[ETR_FLAT_WIRE] = createTRFlatWire2(DepthBuffer); + BurningShader[ETR_GOURAUD] = createTriangleRendererGouraud2(this); + BurningShader[ETR_GOURAUD_ALPHA] = createTriangleRendererGouraudAlpha2(this ); + BurningShader[ETR_GOURAUD_ALPHA_NOZ] = createTRGouraudAlphaNoZ2(this ); + //BurningShader[ETR_GOURAUD_WIRE] = createTriangleRendererGouraudWire2(DepthBuffer); + //BurningShader[ETR_TEXTURE_FLAT] = createTriangleRendererTextureFlat2(DepthBuffer); + //BurningShader[ETR_TEXTURE_FLAT_WIRE] = createTriangleRendererTextureFlatWire2(DepthBuffer); + BurningShader[ETR_TEXTURE_GOURAUD] = createTriangleRendererTextureGouraud2(this); + BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M1] = createTriangleRendererTextureLightMap2_M1(this); + BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M2] = createTriangleRendererTextureLightMap2_M2(this); + BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M4] = createTriangleRendererGTextureLightMap2_M4(this); + BurningShader[ETR_TEXTURE_LIGHTMAP_M4] = createTriangleRendererTextureLightMap2_M4(this); + BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD] = createTriangleRendererTextureLightMap2_Add(this); + BurningShader[ETR_TEXTURE_GOURAUD_DETAIL_MAP] = createTriangleRendererTextureDetailMap2(this); + + BurningShader[ETR_TEXTURE_GOURAUD_WIRE] = createTriangleRendererTextureGouraudWire2(this); + BurningShader[ETR_TEXTURE_GOURAUD_NOZ] = createTRTextureGouraudNoZ2(this); + BurningShader[ETR_TEXTURE_GOURAUD_ADD] = createTRTextureGouraudAdd2(this); + BurningShader[ETR_TEXTURE_GOURAUD_ADD_NO_Z] = createTRTextureGouraudAddNoZ2(this); + BurningShader[ETR_TEXTURE_GOURAUD_VERTEX_ALPHA] = createTriangleRendererTextureVertexAlpha2 ( this ); + + BurningShader[ETR_TEXTURE_GOURAUD_ALPHA] = createTRTextureGouraudAlpha(this ); + BurningShader[ETR_TEXTURE_GOURAUD_ALPHA_NOZ] = createTRTextureGouraudAlphaNoZ( this ); + + BurningShader[ETR_NORMAL_MAP_SOLID] = createTRNormalMap ( this ); + BurningShader[ETR_STENCIL_SHADOW] = createTRStencilShadow ( this ); + BurningShader[ETR_TEXTURE_BLEND] = createTRTextureBlend( this ); + + BurningShader[ETR_REFERENCE] = createTriangleRendererReference ( this ); + + + // add the same renderer for all solid types + CSoftware2MaterialRenderer_SOLID* smr = new CSoftware2MaterialRenderer_SOLID( this); + CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR* tmr = new CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR( this); + CSoftware2MaterialRenderer_UNSUPPORTED * umr = new CSoftware2MaterialRenderer_UNSUPPORTED ( this ); + + //!TODO: addMaterialRenderer depends on pushing order.... + addMaterialRenderer ( smr ); // EMT_SOLID + addMaterialRenderer ( smr ); // EMT_SOLID_2_LAYER, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP, + addMaterialRenderer ( tmr ); // EMT_LIGHTMAP_ADD, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_M2, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_M4, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING_M2, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING_M4, + addMaterialRenderer ( smr ); // EMT_DETAIL_MAP, + addMaterialRenderer ( umr ); // EMT_SPHERE_MAP, + addMaterialRenderer ( smr ); // EMT_REFLECTION_2_LAYER, + addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ADD_COLOR, + addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ALPHA_CHANNEL, + addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ALPHA_CHANNEL_REF, + addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_VERTEX_ALPHA, + addMaterialRenderer ( smr ); // EMT_TRANSPARENT_REFLECTION_2_LAYER, + addMaterialRenderer ( smr ); // EMT_NORMAL_MAP_SOLID, + addMaterialRenderer ( umr ); // EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR, + addMaterialRenderer ( tmr ); // EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA, + addMaterialRenderer ( smr ); // EMT_PARALLAX_MAP_SOLID, + addMaterialRenderer ( tmr ); // EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR, + addMaterialRenderer ( tmr ); // EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA, + addMaterialRenderer ( tmr ); // EMT_ONETEXTURE_BLEND + + smr->drop (); + tmr->drop (); + umr->drop (); + + // select render target + setRenderTarget(BackBuffer); + + //reset Lightspace + LightSpace.reset (); + + // select the right renderer + setCurrentShader(); +} + + +//! destructor +CBurningVideoDriver::~CBurningVideoDriver() +{ + // delete Backbuffer + if (BackBuffer) + BackBuffer->drop(); + + // delete triangle renderers + + for (s32 i=0; idrop(); + } + + // delete Additional buffer + if (StencilBuffer) + StencilBuffer->drop(); + + if (DepthBuffer) + DepthBuffer->drop(); + + if (RenderTargetTexture) + RenderTargetTexture->drop(); + + if (RenderTargetSurface) + RenderTargetSurface->drop(); +} + + +/*! + selects the right triangle renderer based on the render states. +*/ +void CBurningVideoDriver::setCurrentShader() +{ + ITexture *texture0 = Material.org.getTexture(0); + ITexture *texture1 = Material.org.getTexture(1); + + bool zMaterialTest = Material.org.ZBuffer != ECFN_NEVER && + Material.org.ZWriteEnable && + ( AllowZWriteOnTransparent || !Material.org.isTransparent() ); + + EBurningFFShader shader = zMaterialTest ? ETR_TEXTURE_GOURAUD : ETR_TEXTURE_GOURAUD_NOZ; + + TransformationFlag[ ETS_TEXTURE_0] &= ~(ETF_TEXGEN_CAMERA_NORMAL|ETF_TEXGEN_CAMERA_REFLECTION); + LightSpace.Flags &= ~VERTEXTRANSFORM; + + switch ( Material.org.MaterialType ) + { + case EMT_ONETEXTURE_BLEND: + shader = ETR_TEXTURE_BLEND; + break; + + case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: + Material.org.MaterialTypeParam = 0.5f; + // fall through + case EMT_TRANSPARENT_ALPHA_CHANNEL: + if ( texture0 && texture0->hasAlpha () ) + { + shader = zMaterialTest ? ETR_TEXTURE_GOURAUD_ALPHA : ETR_TEXTURE_GOURAUD_ALPHA_NOZ; + break; + } + // fall through + + case EMT_TRANSPARENT_ADD_COLOR: + shader = zMaterialTest ? ETR_TEXTURE_GOURAUD_ADD : ETR_TEXTURE_GOURAUD_ADD_NO_Z; + break; + + case EMT_TRANSPARENT_VERTEX_ALPHA: + shader = ETR_TEXTURE_GOURAUD_VERTEX_ALPHA; + break; + + case EMT_LIGHTMAP: + case EMT_LIGHTMAP_LIGHTING: + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1; + break; + + case EMT_LIGHTMAP_M2: + case EMT_LIGHTMAP_LIGHTING_M2: + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M2; + break; + + case EMT_LIGHTMAP_LIGHTING_M4: + if ( texture1 ) + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M4; + break; + case EMT_LIGHTMAP_M4: + if ( texture1 ) + shader = ETR_TEXTURE_LIGHTMAP_M4; + break; + + case EMT_LIGHTMAP_ADD: + if ( texture1 ) + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD; + break; + + case EMT_DETAIL_MAP: + shader = ETR_TEXTURE_GOURAUD_DETAIL_MAP; + break; + + case EMT_SPHERE_MAP: + TransformationFlag[ ETS_TEXTURE_0] |= ETF_TEXGEN_CAMERA_REFLECTION; // ETF_TEXGEN_CAMERA_NORMAL; + LightSpace.Flags |= VERTEXTRANSFORM; + break; + case EMT_REFLECTION_2_LAYER: + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1; + TransformationFlag[ ETS_TEXTURE_1] |= ETF_TEXGEN_CAMERA_REFLECTION; + LightSpace.Flags |= VERTEXTRANSFORM; + break; + + case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: + case EMT_NORMAL_MAP_SOLID: + case EMT_PARALLAX_MAP_SOLID: + case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: + shader = ETR_NORMAL_MAP_SOLID; + LightSpace.Flags |= VERTEXTRANSFORM; + break; + + default: + break; + + } + + if ( !texture0 ) + { + shader = ETR_GOURAUD; + } + + if ( Material.org.Wireframe ) + { + shader = ETR_TEXTURE_GOURAUD_WIRE; + } + + //shader = ETR_REFERENCE; + + // switchToTriangleRenderer + CurrentShader = BurningShader[shader]; + if ( CurrentShader ) + { + CurrentShader->setZCompareFunc ( Material.org.ZBuffer ); + CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); + CurrentShader->setMaterial ( Material ); + + switch ( shader ) + { + case ETR_TEXTURE_GOURAUD_ALPHA: + case ETR_TEXTURE_GOURAUD_ALPHA_NOZ: + case ETR_TEXTURE_BLEND: + CurrentShader->setParam ( 0, Material.org.MaterialTypeParam ); + break; + default: + break; + } + } + +} + + + +//! queries the features of the driver, returns true if feature is available +bool CBurningVideoDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const +{ + if (!FeatureEnabled[feature]) + return false; + + switch (feature) + { +#ifdef SOFTWARE_DRIVER_2_BILINEAR + case EVDF_BILINEAR_FILTER: + return true; +#endif +#ifdef SOFTWARE_DRIVER_2_MIPMAPPING + case EVDF_MIP_MAP: + return true; +#endif + case EVDF_STENCIL_BUFFER: + case EVDF_RENDER_TO_TARGET: + case EVDF_MULTITEXTURE: + case EVDF_HARDWARE_TL: + case EVDF_TEXTURE_NSQUARE: + return true; + + default: + return false; + } +} + + + +//! sets transformation +void CBurningVideoDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ + Transformation[state] = mat; + core::setbit_cond ( TransformationFlag[state], mat.isIdentity(), ETF_IDENTITY ); + + switch ( state ) + { + case ETS_VIEW: + Transformation[ETS_VIEW_PROJECTION].setbyproduct_nocheck ( + Transformation[ETS_PROJECTION], + Transformation[ETS_VIEW] + ); + getCameraPosWorldSpace (); + break; + + case ETS_WORLD: + if ( TransformationFlag[state] & ETF_IDENTITY ) + { + Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; + TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; + Transformation[ETS_CURRENT] = Transformation[ETS_VIEW_PROJECTION]; + } + else + { + //Transformation[ETS_WORLD].getInversePrimitive ( Transformation[ETS_WORLD_INVERSE] ); + Transformation[ETS_CURRENT].setbyproduct_nocheck ( + Transformation[ETS_VIEW_PROJECTION], + Transformation[ETS_WORLD] + ); + } + TransformationFlag[ETS_CURRENT] = 0; + //getLightPosObjectSpace (); + break; + case ETS_TEXTURE_0: + case ETS_TEXTURE_1: + case ETS_TEXTURE_2: + case ETS_TEXTURE_3: + if ( 0 == (TransformationFlag[state] & ETF_IDENTITY ) ) + LightSpace.Flags |= VERTEXTRANSFORM; + default: + break; + } +} + + +//! clears the zbuffer +bool CBurningVideoDriver::beginScene(bool backBuffer, bool zBuffer, + SColor color, const SExposedVideoData& videoData, + core::rect* sourceRect) +{ + CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect); + WindowId = videoData.D3D9.HWnd; + SceneSourceRect = sourceRect; + + if (backBuffer && BackBuffer) + BackBuffer->fill(color); + + if (zBuffer && DepthBuffer) + DepthBuffer->clear(); + + memset ( TransformationFlag, 0, sizeof ( TransformationFlag ) ); + return true; +} + + +//! presents the rendered scene on the screen, returns false if failed +bool CBurningVideoDriver::endScene() +{ + CNullDriver::endScene(); + + return Presenter->present(BackBuffer, WindowId, SceneSourceRect); +} + + +//! sets a render target +bool CBurningVideoDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, + bool clearZBuffer, SColor color) +{ + if (texture && texture->getDriverType() != EDT_BURNINGSVIDEO) + { + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + return false; + } + + if (RenderTargetTexture) + RenderTargetTexture->drop(); + + RenderTargetTexture = texture; + + if (RenderTargetTexture) + { + RenderTargetTexture->grab(); + setRenderTarget(((CSoftwareTexture2*)RenderTargetTexture)->getTexture()); + } + else + { + setRenderTarget(BackBuffer); + } + + if (RenderTargetSurface && (clearBackBuffer || clearZBuffer)) + { + if (clearZBuffer) + DepthBuffer->clear(); + + if (clearBackBuffer) + RenderTargetSurface->fill( color ); + } + + return true; +} + + +//! sets a render target +void CBurningVideoDriver::setRenderTarget(video::CImage* image) +{ + if (RenderTargetSurface) + RenderTargetSurface->drop(); + + RenderTargetSurface = image; + RenderTargetSize.Width = 0; + RenderTargetSize.Height = 0; + + if (RenderTargetSurface) + { + RenderTargetSurface->grab(); + RenderTargetSize = RenderTargetSurface->getDimension(); + } + + setViewPort(core::rect(0,0,RenderTargetSize.Width,RenderTargetSize.Height)); + + if (DepthBuffer) + DepthBuffer->setSize(RenderTargetSize); + + if (StencilBuffer) + StencilBuffer->setSize(RenderTargetSize); +} + + + +//! sets a viewport +void CBurningVideoDriver::setViewPort(const core::rect& area) +{ + ViewPort = area; + + core::rect rendert(0,0,RenderTargetSize.Width,RenderTargetSize.Height); + ViewPort.clipAgainst(rendert); + + Transformation [ ETS_CLIPSCALE ].buildNDCToDCMatrix ( ViewPort, 1 ); + + if (CurrentShader) + CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); +} + +/* + generic plane clipping in homogenous coordinates + special case ndc frustum <-w,w>,<-w,w>,<-w,w> + can be rewritten with compares e.q near plane, a.z < -a.w and b.z < -b.w +*/ + +const sVec4 CBurningVideoDriver::NDCPlane[6] = +{ + sVec4( 0.f, 0.f, -1.f, -1.f ), // near + sVec4( 0.f, 0.f, 1.f, -1.f ), // far + sVec4( 1.f, 0.f, 0.f, -1.f ), // left + sVec4( -1.f, 0.f, 0.f, -1.f ), // right + sVec4( 0.f, 1.f, 0.f, -1.f ), // bottom + sVec4( 0.f, -1.f, 0.f, -1.f ) // top +}; + + + +/* + test a vertex if it's inside the standard frustum + + this is the generic one.. + + f32 dotPlane; + for ( u32 i = 0; i!= 6; ++i ) + { + dotPlane = v->Pos.dotProduct ( NDCPlane[i] ); + core::setbit_cond( flag, dotPlane <= 0.f, 1 << i ); + } + + // this is the base for ndc frustum <-w,w>,<-w,w>,<-w,w> + core::setbit_cond( flag, ( v->Pos.z - v->Pos.w ) <= 0.f, 1 ); + core::setbit_cond( flag, (-v->Pos.z - v->Pos.w ) <= 0.f, 2 ); + core::setbit_cond( flag, ( v->Pos.x - v->Pos.w ) <= 0.f, 4 ); + core::setbit_cond( flag, (-v->Pos.x - v->Pos.w ) <= 0.f, 8 ); + core::setbit_cond( flag, ( v->Pos.y - v->Pos.w ) <= 0.f, 16 ); + core::setbit_cond( flag, (-v->Pos.y - v->Pos.w ) <= 0.f, 32 ); + +*/ +#ifdef IRRLICHT_FAST_MATH + +REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const +{ + f32 test[6]; + u32 flag; + const f32 w = - v->Pos.w; + + // a conditional move is needed....FCOMI ( but we don't have it ) + // so let the fpu calculate and write it back. + // cpu makes the compare, interleaving + + test[0] = v->Pos.z + w; + test[1] = -v->Pos.z + w; + test[2] = v->Pos.x + w; + test[3] = -v->Pos.x + w; + test[4] = v->Pos.y + w; + test[5] = -v->Pos.y + w; + + flag = (IR ( test[0] ) ) >> 31; + flag |= (IR ( test[1] ) & 0x80000000 ) >> 30; + flag |= (IR ( test[2] ) & 0x80000000 ) >> 29; + flag |= (IR ( test[3] ) & 0x80000000 ) >> 28; + flag |= (IR ( test[4] ) & 0x80000000 ) >> 27; + flag |= (IR ( test[5] ) & 0x80000000 ) >> 26; + +/* + flag = F32_LOWER_EQUAL_0 ( test[0] ); + flag |= F32_LOWER_EQUAL_0 ( test[1] ) << 1; + flag |= F32_LOWER_EQUAL_0 ( test[2] ) << 2; + flag |= F32_LOWER_EQUAL_0 ( test[3] ) << 3; + flag |= F32_LOWER_EQUAL_0 ( test[4] ) << 4; + flag |= F32_LOWER_EQUAL_0 ( test[5] ) << 5; +*/ + return flag; +} + +#else + + +REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const +{ + u32 flag = 0; + + if ( v->Pos.z <= v->Pos.w ) flag |= 1; + if (-v->Pos.z <= v->Pos.w ) flag |= 2; + + if ( v->Pos.x <= v->Pos.w ) flag |= 4; + if (-v->Pos.x <= v->Pos.w ) flag |= 8; + + if ( v->Pos.y <= v->Pos.w ) flag |= 16; + if (-v->Pos.y <= v->Pos.w ) flag |= 32; + +/* + for ( u32 i = 0; i!= 6; ++i ) + { + core::setbit_cond( flag, v->Pos.dotProduct ( NDCPlane[i] ) <= 0.f, 1 << i ); + } +*/ + return flag; +} + +#endif // _MSC_VER + +u32 CBurningVideoDriver::clipToHyperPlane ( s4DVertex * dest, const s4DVertex * source, u32 inCount, const sVec4 &plane ) +{ + u32 outCount = 0; + s4DVertex * out = dest; + + const s4DVertex * a; + const s4DVertex * b = source; + + f32 bDotPlane; + + bDotPlane = b->Pos.dotProduct ( plane ); + + for( u32 i = 1; i < inCount + 1; ++i) + { + const s32 condition = i - inCount; + const s32 index = (( ( condition >> 31 ) & ( i ^ condition ) ) ^ condition ) << 1; + + a = &source[ index ]; + + // current point inside + if ( a->Pos.dotProduct ( plane ) <= 0.f ) + { + // last point outside + if ( F32_GREATER_0 ( bDotPlane ) ) + { + // intersect line segment with plane + out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); + out += 2; + outCount += 1; + } + + // copy current to out + //*out = *a; + irr::memcpy32_small ( out, a, SIZEOF_SVERTEX * 2 ); + b = out; + + out += 2; + outCount += 1; + } + else + { + // current point outside + + if ( F32_LOWER_EQUAL_0 ( bDotPlane ) ) + { + // previous was inside + // intersect line segment with plane + out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); + out += 2; + outCount += 1; + } + // pointer + b = a; + } + + bDotPlane = b->Pos.dotProduct ( plane ); + + } + + return outCount; +} + + +u32 CBurningVideoDriver::clipToFrustum ( s4DVertex *v0, s4DVertex * v1, const u32 vIn ) +{ + u32 vOut = vIn; + + vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[0] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[1] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[2] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[3] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[4] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[5] ); + return vOut; +} + +/*! + Part I: + apply Clip Scale matrix + From Normalized Device Coordiante ( NDC ) Space to Device Coordinate Space ( DC ) + + Part II: + Project homogeneous vector + homogeneous to non-homogenous coordinates ( dividebyW ) + + Incoming: ( xw, yw, zw, w, u, v, 1, R, G, B, A ) + Outgoing: ( xw/w, yw/w, zw/w, w/w, u/w, v/w, 1/w, R/w, G/w, B/w, A/w ) + + + replace w/w by 1/w +*/ +inline void CBurningVideoDriver::ndc_2_dc_and_project ( s4DVertex *dest,s4DVertex *source, u32 vIn ) const +{ + u32 g; + + for ( g = 0; g != vIn; g += 2 ) + { + if ( (dest[g].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) + continue; + + dest[g].flag = source[g].flag | VERTEX4D_PROJECTED; + + const f32 w = source[g].Pos.w; + const f32 iw = core::reciprocal ( w ); + + // to device coordinates + dest[g].Pos.x = iw * ( source[g].Pos.x * Transformation [ ETS_CLIPSCALE ][ 0] + w * Transformation [ ETS_CLIPSCALE ][12] ); + dest[g].Pos.y = iw * ( source[g].Pos.y * Transformation [ ETS_CLIPSCALE ][ 5] + w * Transformation [ ETS_CLIPSCALE ][13] ); + +#ifndef SOFTWARE_DRIVER_2_USE_WBUFFER + dest[g].Pos.z = iw * source[g].Pos.z; +#endif + + #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + dest[g].Color[0] = source[g].Color[0] * iw; + #else + dest[g].Color[0] = source[g].Color[0]; + #endif + + #endif + dest[g].LightTangent[0] = source[g].LightTangent[0] * iw; + dest[g].Pos.w = iw; + } +} + + +inline void CBurningVideoDriver::ndc_2_dc_and_project2 ( const s4DVertex **v, const u32 size ) const +{ + u32 g; + + for ( g = 0; g != size; g += 1 ) + { + s4DVertex * a = (s4DVertex*) v[g]; + + if ( (a[1].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) + continue; + + a[1].flag = a->flag | VERTEX4D_PROJECTED; + + // project homogenous vertex, store 1/w + const f32 w = a->Pos.w; + const f32 iw = core::reciprocal ( w ); + + // to device coordinates + const f32 * p = Transformation [ ETS_CLIPSCALE ].pointer(); + a[1].Pos.x = iw * ( a->Pos.x * p[ 0] + w * p[12] ); + a[1].Pos.y = iw * ( a->Pos.y * p[ 5] + w * p[13] ); + +#ifndef SOFTWARE_DRIVER_2_USE_WBUFFER + a[1].Pos.z = a->Pos.z * iw; +#endif + + #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + a[1].Color[0] = a->Color[0] * iw; + #else + a[1].Color[0] = a->Color[0]; + #endif + #endif + + a[1].LightTangent[0] = a[0].LightTangent[0] * iw; + a[1].Pos.w = iw; + + } + +} + + +/*! + crossproduct in projected 2D -> screen area triangle +*/ +inline f32 CBurningVideoDriver::screenarea ( const s4DVertex *v ) const +{ + return ( ( v[3].Pos.x - v[1].Pos.x ) * ( v[5].Pos.y - v[1].Pos.y ) ) - + ( ( v[3].Pos.y - v[1].Pos.y ) * ( v[5].Pos.x - v[1].Pos.x ) ); +} + + +/*! +*/ +inline f32 CBurningVideoDriver::texelarea ( const s4DVertex *v, int tex ) const +{ + f32 z; + + z = ( (v[2].Tex[tex].x - v[0].Tex[tex].x ) * (v[4].Tex[tex].y - v[0].Tex[tex].y ) ) + - ( (v[4].Tex[tex].x - v[0].Tex[tex].x ) * (v[2].Tex[tex].y - v[0].Tex[tex].y ) ); + + return MAT_TEXTURE ( tex )->getLODFactor ( z ); +} + +/*! + crossproduct in projected 2D +*/ +inline f32 CBurningVideoDriver::screenarea2 ( const s4DVertex **v ) const +{ + return ( (( v[1] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) * ( (v[2] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) ) - + ( (( v[1] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) * ( (v[2] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) ); +} + +/*! +*/ +inline f32 CBurningVideoDriver::texelarea2 ( const s4DVertex **v, s32 tex ) const +{ + f32 z; + z = ( (v[1]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[2]->Tex[tex].y - v[0]->Tex[tex].y ) ) + - ( (v[2]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[1]->Tex[tex].y - v[0]->Tex[tex].y ) ); + + return MAT_TEXTURE ( tex )->getLODFactor ( z ); +} + + +/*! +*/ +inline void CBurningVideoDriver::select_polygon_mipmap ( s4DVertex *v, u32 vIn, u32 tex, const core::dimension2du& texSize ) const +{ + f32 f[2]; + + f[0] = (f32) texSize.Width - 0.25f; + f[1] = (f32) texSize.Height - 0.25f; + +#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + for ( u32 g = 0; g != vIn; g += 2 ) + { + (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * ( v + g + 1 )->Pos.w * f[0]; + (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * ( v + g + 1 )->Pos.w * f[1]; + } +#else + for ( u32 g = 0; g != vIn; g += 2 ) + { + (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * f[0]; + (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * f[1]; + } +#endif +} + +inline void CBurningVideoDriver::select_polygon_mipmap2 ( s4DVertex **v, u32 tex, const core::dimension2du& texSize ) const +{ + f32 f[2]; + + f[0] = (f32) texSize.Width - 0.25f; + f[1] = (f32) texSize.Height - 0.25f; + +#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * ( v[0] + 1 )->Pos.w * f[0]; + (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * ( v[0] + 1 )->Pos.w * f[1]; + + (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * ( v[1] + 1 )->Pos.w * f[0]; + (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * ( v[1] + 1 )->Pos.w * f[1]; + + (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * ( v[2] + 1 )->Pos.w * f[0]; + (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * ( v[2] + 1 )->Pos.w * f[1]; + +#else + (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * f[0]; + (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * f[1]; + + (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * f[0]; + (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * f[1]; + + (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * f[0]; + (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * f[1]; +#endif +} + +// Vertex Cache +const SVSize CBurningVideoDriver::vSize[] = +{ + { VERTEX4D_FORMAT_TEXTURE_1 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 1 }, + { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex2TCoords),2 }, + { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1 | VERTEX4D_FORMAT_BUMP_DOT3, sizeof(S3DVertexTangents),2 }, + { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 2 }, // reflection map + { 0, sizeof(f32) * 3, 0 }, // core::vector3df* +}; + + + +/*! + fill a cache line with transformed, light and clipp test triangles +*/ +void CBurningVideoDriver::VertexCache_fill(const u32 sourceIndex, const u32 destIndex) +{ + u8 * source; + s4DVertex *dest; + + source = (u8*) VertexCache.vertices + ( sourceIndex * vSize[VertexCache.vType].Pitch ); + + // it's a look ahead so we never hit it.. + // but give priority... + //VertexCache.info[ destIndex ].hit = hitCount; + + // store info + VertexCache.info[ destIndex ].index = sourceIndex; + VertexCache.info[ destIndex ].hit = 0; + + // destination Vertex + dest = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( destIndex << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + + // transform Model * World * Camera * Projection * NDCSpace matrix + const S3DVertex *base = ((S3DVertex*) source ); + Transformation [ ETS_CURRENT].transformVect ( &dest->Pos.x, base->Pos ); + + //mhm ;-) maybe no goto + if ( VertexCache.vType == 4 ) goto clipandproject; + + +#if defined (SOFTWARE_DRIVER_2_LIGHTING) || defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) + + // vertex normal in light space + if ( Material.org.Lighting || (LightSpace.Flags & VERTEXTRANSFORM) ) + { + if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) + { + LightSpace.normal.set ( base->Normal.X, base->Normal.Y, base->Normal.Z, 1.f ); + LightSpace.vertex.set ( base->Pos.X, base->Pos.Y, base->Pos.Z, 1.f ); + } + else + { + Transformation[ETS_WORLD].rotateVect ( &LightSpace.normal.x, base->Normal ); + + // vertex in light space + if ( LightSpace.Flags & ( POINTLIGHT | FOG | SPECULAR | VERTEXTRANSFORM) ) + Transformation[ETS_WORLD].transformVect ( &LightSpace.vertex.x, base->Pos ); + } + + if ( LightSpace.Flags & NORMALIZE ) + LightSpace.normal.normalize_xyz(); + + } + +#endif + +#if defined ( SOFTWARE_DRIVER_2_USE_VERTEX_COLOR ) + // apply lighting model + #if defined (SOFTWARE_DRIVER_2_LIGHTING) + if ( Material.org.Lighting ) + { + lightVertex ( dest, base->Color.color ); + } + else + { + dest->Color[0].setA8R8G8B8 ( base->Color.color ); + } + #else + dest->Color[0].setA8R8G8B8 ( base->Color.color ); + #endif +#endif + + // Texture Transform +#if !defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) + irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, + vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) + ); +#else + + if ( 0 == (LightSpace.Flags & VERTEXTRANSFORM) ) + { + irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, + vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) + ); + } + else + { + /* + Generate texture coordinates as linear functions so that: + u = Ux*x + Uy*y + Uz*z + Uw + v = Vx*x + Vy*y + Vz*z + Vw + The matrix M for this case is: + Ux Vx 0 0 + Uy Vy 0 0 + Uz Vz 0 0 + Uw Vw 0 0 + */ + + u32 t; + sVec4 n; + sVec2 srcT; + + for ( t = 0; t != vSize[VertexCache.vType].TexSize; ++t ) + { + const core::matrix4& M = Transformation [ ETS_TEXTURE_0 + t ]; + + // texgen + if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & (ETF_TEXGEN_CAMERA_NORMAL|ETF_TEXGEN_CAMERA_REFLECTION) ) + { + n.x = LightSpace.campos.x - LightSpace.vertex.x; + n.y = LightSpace.campos.x - LightSpace.vertex.y; + n.z = LightSpace.campos.x - LightSpace.vertex.z; + n.normalize_xyz(); + n.x += LightSpace.normal.x; + n.y += LightSpace.normal.y; + n.z += LightSpace.normal.z; + n.normalize_xyz(); + + const f32 *view = Transformation[ETS_VIEW].pointer(); + + if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & ETF_TEXGEN_CAMERA_REFLECTION ) + { + srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[4] + n.z * view[8] )); + srcT.y = 0.5f * ( 1.f + (n.x * view[1] + n.y * view[5] + n.z * view[9] )); + } + else + { + srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[1] + n.z * view[2] )); + srcT.y = 0.5f * ( 1.f + (n.x * view[4] + n.y * view[5] + n.z * view[6] )); + } + } + else + { + irr::memcpy32_small ( &srcT,(&base->TCoords) + t, + sizeof ( f32 ) * 2 ); + } + + switch ( Material.org.TextureLayer[t].TextureWrapU ) + { + case ETC_CLAMP: + case ETC_CLAMP_TO_EDGE: + case ETC_CLAMP_TO_BORDER: + dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); + break; + case ETC_MIRROR: + dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; + if (core::fract(dest->Tex[t].x)>0.5f) + dest->Tex[t].x=1.f-dest->Tex[t].x; + break; + case ETC_MIRROR_CLAMP: + case ETC_MIRROR_CLAMP_TO_EDGE: + case ETC_MIRROR_CLAMP_TO_BORDER: + dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); + if (core::fract(dest->Tex[t].x)>0.5f) + dest->Tex[t].x=1.f-dest->Tex[t].x; + break; + case ETC_REPEAT: + default: + dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; + break; + } + switch ( Material.org.TextureLayer[t].TextureWrapV ) + { + case ETC_CLAMP: + case ETC_CLAMP_TO_EDGE: + case ETC_CLAMP_TO_BORDER: + dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); + break; + case ETC_MIRROR: + dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; + if (core::fract(dest->Tex[t].y)>0.5f) + dest->Tex[t].y=1.f-dest->Tex[t].y; + break; + case ETC_MIRROR_CLAMP: + case ETC_MIRROR_CLAMP_TO_EDGE: + case ETC_MIRROR_CLAMP_TO_BORDER: + dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); + if (core::fract(dest->Tex[t].y)>0.5f) + dest->Tex[t].y=1.f-dest->Tex[t].y; + break; + case ETC_REPEAT: + default: + dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; + break; + } + } + } + +#if 0 + // tangent space light vector, emboss + if ( Lights.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) + { + const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); + const SBurningShaderLight &light = LightSpace.Light[0]; + + sVec4 vp; + + vp.x = light.pos.x - LightSpace.vertex.x; + vp.y = light.pos.y - LightSpace.vertex.y; + vp.z = light.pos.z - LightSpace.vertex.z; + + vp.normalize_xyz(); + + LightSpace.tangent.x = vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z; + LightSpace.tangent.y = vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z; + //LightSpace.tangent.z = vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z; + LightSpace.tangent.z = 0.f; + LightSpace.tangent.normalize_xyz(); + + f32 scale = 1.f / 128.f; + if ( Material.org.MaterialTypeParam > 0.f ) + scale = Material.org.MaterialTypeParam; + + // emboss, shift coordinates + dest->Tex[1].x = dest->Tex[0].x + LightSpace.tangent.x * scale; + dest->Tex[1].y = dest->Tex[0].y + LightSpace.tangent.y * scale; + //dest->Tex[1].z = LightSpace.tangent.z * scale; + } +#endif + + if ( LightSpace.Light.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) + { + const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); + + sVec4 vp; + + dest->LightTangent[0].x = 0.f; + dest->LightTangent[0].y = 0.f; + dest->LightTangent[0].z = 0.f; + for ( u32 i = 0; i < 2 && i < LightSpace.Light.size (); ++i ) + { + const SBurningShaderLight &light = LightSpace.Light[i]; + + if ( !light.LightIsOn ) + continue; + + vp.x = light.pos.x - LightSpace.vertex.x; + vp.y = light.pos.y - LightSpace.vertex.y; + vp.z = light.pos.z - LightSpace.vertex.z; + + /* + vp.x = light.pos_objectspace.x - base->Pos.X; + vp.y = light.pos_objectspace.y - base->Pos.Y; + vp.z = light.pos_objectspace.z - base->Pos.Z; + */ + + vp.normalize_xyz(); + + + // transform by tangent matrix + sVec3 l; + #if 1 + l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z ); + l.y = (vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z ); + l.z = (vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z ); + #else + l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Binormal.X + vp.z * tangent->Normal.X ); + l.y = (vp.x * tangent->Tangent.Y + vp.y * tangent->Binormal.Y + vp.z * tangent->Normal.Y ); + l.z = (vp.x * tangent->Tangent.Z + vp.y * tangent->Binormal.Z + vp.z * tangent->Normal.Z ); + #endif + + + /* + f32 scale = 1.f / 128.f; + scale /= dest->LightTangent[0].b; + + // emboss, shift coordinates + dest->Tex[1].x = dest->Tex[0].x + l.r * scale; + dest->Tex[1].y = dest->Tex[0].y + l.g * scale; + */ + dest->Tex[1].x = dest->Tex[0].x; + dest->Tex[1].y = dest->Tex[0].y; + + // scale bias + dest->LightTangent[0].x += l.x; + dest->LightTangent[0].y += l.y; + dest->LightTangent[0].z += l.z; + } + dest->LightTangent[0].setLength ( 0.5f ); + dest->LightTangent[0].x += 0.5f; + dest->LightTangent[0].y += 0.5f; + dest->LightTangent[0].z += 0.5f; + } + + +#endif + +clipandproject: + dest[0].flag = dest[1].flag = vSize[VertexCache.vType].Format; + + // test vertex + dest[0].flag |= clipToFrustumTest ( dest); + + // to DC Space, project homogenous vertex + if ( (dest[0].flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) + { + ndc_2_dc_and_project2 ( (const s4DVertex**) &dest, 1 ); + } + + //return dest; +} + +// + +REALINLINE s4DVertex * CBurningVideoDriver::VertexCache_getVertex ( const u32 sourceIndex ) +{ + for ( s32 i = 0; i < VERTEXCACHE_ELEMENT; ++i ) + { + if ( VertexCache.info[ i ].index == sourceIndex ) + { + return (s4DVertex *) ( (u8*) VertexCache.mem.data + ( i << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + } + } + return 0; +} + + +/* + Cache based on linear walk indices + fill blockwise on the next 16(Cache_Size) unique vertices in indexlist + merge the next 16 vertices with the current +*/ +REALINLINE void CBurningVideoDriver::VertexCache_get(const s4DVertex ** face) +{ + SCacheInfo info[VERTEXCACHE_ELEMENT]; + + // next primitive must be complete in cache + if ( VertexCache.indicesIndex - VertexCache.indicesRun < 3 && + VertexCache.indicesIndex < VertexCache.indexCount + ) + { + // rewind to start of primitive + VertexCache.indicesIndex = VertexCache.indicesRun; + + irr::memset32 ( info, VERTEXCACHE_MISS, sizeof ( info ) ); + + // get the next unique vertices cache line + u32 fillIndex = 0; + u32 dIndex; + u32 i; + u32 sourceIndex; + + while ( VertexCache.indicesIndex < VertexCache.indexCount && + fillIndex < VERTEXCACHE_ELEMENT + ) + { + switch ( VertexCache.iType ) + { + case 1: + sourceIndex = ((u16*)VertexCache.indices) [ VertexCache.indicesIndex ]; + break; + case 2: + sourceIndex = ((u32*)VertexCache.indices) [ VertexCache.indicesIndex ]; + break; + case 4: + sourceIndex = VertexCache.indicesIndex; + break; + } + + VertexCache.indicesIndex += 1; + + // if not exist, push back + s32 exist = 0; + for ( dIndex = 0; dIndex < fillIndex; ++dIndex ) + { + if ( info[ dIndex ].index == sourceIndex ) + { + exist = 1; + break; + } + } + + if ( 0 == exist ) + { + info[fillIndex++].index = sourceIndex; + } + } + + // clear marks + for ( i = 0; i!= VERTEXCACHE_ELEMENT; ++i ) + { + VertexCache.info[i].hit = 0; + } + + // mark all existing + for ( i = 0; i!= fillIndex; ++i ) + { + for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) + { + if ( VertexCache.info[ dIndex ].index == info[i].index ) + { + info[i].hit = dIndex; + VertexCache.info[ dIndex ].hit = 1; + break; + } + } + } + + // fill new + for ( i = 0; i!= fillIndex; ++i ) + { + if ( info[i].hit != VERTEXCACHE_MISS ) + continue; + + for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) + { + if ( 0 == VertexCache.info[dIndex].hit ) + { + VertexCache_fill ( info[i].index, dIndex ); + VertexCache.info[dIndex].hit += 1; + info[i].hit = dIndex; + break; + } + } + } + } + + const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); + + switch ( VertexCache.iType ) + { + case 1: + { + const u16 *p = (const u16 *) VertexCache.indices; + face[0] = VertexCache_getVertex ( p[ i0 ] ); + face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); + face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); + } + break; + + case 2: + { + const u32 *p = (const u32 *) VertexCache.indices; + face[0] = VertexCache_getVertex ( p[ i0 ] ); + face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); + face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); + } + break; + + case 4: + face[0] = VertexCache_getVertex ( VertexCache.indicesRun + 0 ); + face[1] = VertexCache_getVertex ( VertexCache.indicesRun + 1 ); + face[2] = VertexCache_getVertex ( VertexCache.indicesRun + 2 ); + break; + default: + face[0] = face[1] = face[2] = VertexCache_getVertex(VertexCache.indicesRun + 0); + break; + } + + VertexCache.indicesRun += VertexCache.primitivePitch; +} + +/*! +*/ +REALINLINE void CBurningVideoDriver::VertexCache_getbypass ( s4DVertex ** face ) +{ + const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); + + if ( VertexCache.iType == 1 ) + { + const u16 *p = (const u16 *) VertexCache.indices; + VertexCache_fill ( p[ i0 ], 0 ); + VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); + VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); + } + else + { + const u32 *p = (const u32 *) VertexCache.indices; + VertexCache_fill ( p[ i0 ], 0 ); + VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); + VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); + } + + VertexCache.indicesRun += VertexCache.primitivePitch; + + face[0] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + face[1] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + face[2] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + +} + +/*! +*/ +void CBurningVideoDriver::VertexCache_reset ( const void* vertices, u32 vertexCount, + const void* indices, u32 primitiveCount, + E_VERTEX_TYPE vType, + scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType) +{ + VertexCache.vertices = vertices; + VertexCache.vertexCount = vertexCount; + + VertexCache.indices = indices; + VertexCache.indicesIndex = 0; + VertexCache.indicesRun = 0; + + if ( Material.org.MaterialType == video::EMT_REFLECTION_2_LAYER ) + VertexCache.vType = 3; + else + VertexCache.vType = vType; + VertexCache.pType = pType; + + switch ( iType ) + { + case EIT_16BIT: VertexCache.iType = 1; break; + case EIT_32BIT: VertexCache.iType = 2; break; + default: + VertexCache.iType = iType; break; + } + + switch ( VertexCache.pType ) + { + // most types here will not work as expected, only triangles/triangle_fan + // is known to work. + case scene::EPT_POINTS: + VertexCache.indexCount = primitiveCount; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_LINE_STRIP: + VertexCache.indexCount = primitiveCount+1; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_LINE_LOOP: + VertexCache.indexCount = primitiveCount+1; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_LINES: + VertexCache.indexCount = 2*primitiveCount; + VertexCache.primitivePitch = 2; + break; + case scene::EPT_TRIANGLE_STRIP: + VertexCache.indexCount = primitiveCount+2; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_TRIANGLES: + VertexCache.indexCount = primitiveCount + primitiveCount + primitiveCount; + VertexCache.primitivePitch = 3; + break; + case scene::EPT_TRIANGLE_FAN: + VertexCache.indexCount = primitiveCount + 2; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_QUAD_STRIP: + VertexCache.indexCount = 2*primitiveCount + 2; + VertexCache.primitivePitch = 2; + break; + case scene::EPT_QUADS: + VertexCache.indexCount = 4*primitiveCount; + VertexCache.primitivePitch = 4; + break; + case scene::EPT_POLYGON: + VertexCache.indexCount = primitiveCount+1; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_POINT_SPRITES: + VertexCache.indexCount = primitiveCount; + VertexCache.primitivePitch = 1; + break; + } + + irr::memset32 ( VertexCache.info, VERTEXCACHE_MISS, sizeof ( VertexCache.info ) ); +} + + +void CBurningVideoDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) + +{ + if (!checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + // These calls would lead to crashes due to wrong index usage. + // The vertex cache needs to be rewritten for these primitives. + if (pType==scene::EPT_POINTS || pType==scene::EPT_LINE_STRIP || + pType==scene::EPT_LINE_LOOP || pType==scene::EPT_LINES || pType==scene::EPT_POLYGON || + pType==scene::EPT_POINT_SPRITES) + return; + + if ( 0 == CurrentShader ) + return; + + VertexCache_reset ( vertices, vertexCount, indexList, primitiveCount, vType, pType, iType ); + + const s4DVertex * face[3]; + + f32 dc_area; + s32 lodLevel; + u32 i; + u32 g; + u32 m; + video::CSoftwareTexture2* tex; + + for ( i = 0; i < (u32) primitiveCount; ++i ) + { + VertexCache_get(face); + + // if fully outside or outside on same side + if ( ( (face[0]->flag | face[1]->flag | face[2]->flag) & VERTEX4D_CLIPMASK ) + != VERTEX4D_INSIDE + ) + continue; + + // if fully inside + if ( ( face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) + { + dc_area = screenarea2 ( face ); + if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0( dc_area ) ) + continue; + else + if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) + continue; + + // select mipmap + dc_area = core::reciprocal ( dc_area ); + for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) + { + if ( 0 == (tex = MAT_TEXTURE ( m )) ) + { + CurrentShader->setTextureParam(m, 0, 0); + continue; + } + + lodLevel = s32_log2_f32 ( texelarea2 ( face, m ) * dc_area ); + CurrentShader->setTextureParam(m, tex, lodLevel ); + select_polygon_mipmap2 ( (s4DVertex**) face, m, tex->getSize() ); + } + + // rasterize + CurrentShader->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); + continue; + } + + // else if not complete inside clipping necessary + irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[0], SIZEOF_SVERTEX * 2 ); + irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[1], SIZEOF_SVERTEX * 2 ); + irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[2], SIZEOF_SVERTEX * 2 ); + + const u32 flag = CurrentOut.data->flag & VERTEX4D_FORMAT_MASK; + + for ( g = 0; g != CurrentOut.ElementSize; ++g ) + { + CurrentOut.data[g].flag = flag; + Temp.data[g].flag = flag; + } + + u32 vOut; + vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); + if ( vOut < 3 ) + continue; + + vOut <<= 1; + + // to DC Space, project homogenous vertex + ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); + +/* + // TODO: don't stick on 32 Bit Pointer + #define PointerAsValue(x) ( (u32) (u32*) (x) ) + + // if not complete inside clipping necessary + if ( ( test & VERTEX4D_INSIDE ) != VERTEX4D_INSIDE ) + { + u32 v[2] = { PointerAsValue ( Temp ) , PointerAsValue ( CurrentOut ) }; + for ( g = 0; g != 6; ++g ) + { + vOut = clipToHyperPlane ( (s4DVertex*) v[0], (s4DVertex*) v[1], vOut, NDCPlane[g] ); + if ( vOut < 3 ) + break; + + v[0] ^= v[1]; + v[1] ^= v[0]; + v[0] ^= v[1]; + } + + if ( vOut < 3 ) + continue; + + } +*/ + + // check 2d backface culling on first + dc_area = screenarea ( CurrentOut.data ); + if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0 ( dc_area ) ) + continue; + else if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) + continue; + + // select mipmap + dc_area = core::reciprocal ( dc_area ); + for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) + { + if ( 0 == (tex = MAT_TEXTURE ( m )) ) + { + CurrentShader->setTextureParam(m, 0, 0); + continue; + } + + lodLevel = s32_log2_f32 ( texelarea ( CurrentOut.data, m ) * dc_area ); + CurrentShader->setTextureParam(m, tex, lodLevel ); + select_polygon_mipmap ( CurrentOut.data, vOut, m, tex->getSize() ); + } + + + // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) + for ( g = 0; g <= vOut - 6; g += 2 ) + { + // rasterize + CurrentShader->drawTriangle ( CurrentOut.data + 0 + 1, + CurrentOut.data + g + 3, + CurrentOut.data + g + 5); + } + + } + + // dump statistics +/* + char buf [64]; + sprintf ( buf,"VCount:%d PCount:%d CacheMiss: %d", + vertexCount, primitiveCount, + VertexCache.CacheMiss + ); + os::Printer::log( buf ); +*/ + +} + + +//! Sets the dynamic ambient light color. The default color is +//! (0,0,0,0) which means it is dark. +//! \param color: New color of the ambient light. +void CBurningVideoDriver::setAmbientLight(const SColorf& color) +{ + LightSpace.Global_AmbientLight.setColorf ( color ); +} + + +//! adds a dynamic light +s32 CBurningVideoDriver::addDynamicLight(const SLight& dl) +{ + (void) CNullDriver::addDynamicLight( dl ); + + SBurningShaderLight l; +// l.org = dl; + l.Type = dl.Type; + l.LightIsOn = true; + + l.AmbientColor.setColorf ( dl.AmbientColor ); + l.DiffuseColor.setColorf ( dl.DiffuseColor ); + l.SpecularColor.setColorf ( dl.SpecularColor ); + + switch ( dl.Type ) + { + case video::ELT_DIRECTIONAL: + l.pos.x = -dl.Direction.X; + l.pos.y = -dl.Direction.Y; + l.pos.z = -dl.Direction.Z; + l.pos.w = 1.f; + break; + case ELT_POINT: + case ELT_SPOT: + LightSpace.Flags |= POINTLIGHT; + l.pos.x = dl.Position.X; + l.pos.y = dl.Position.Y; + l.pos.z = dl.Position.Z; + l.pos.w = 1.f; +/* + l.radius = (1.f / dl.Attenuation.Y) * (1.f / dl.Attenuation.Y); + l.constantAttenuation = dl.Attenuation.X; + l.linearAttenuation = dl.Attenuation.Y; + l.quadraticAttenuation = dl.Attenuation.Z; +*/ + l.radius = dl.Radius * dl.Radius; + l.constantAttenuation = dl.Attenuation.X; + l.linearAttenuation = 1.f / dl.Radius; + l.quadraticAttenuation = dl.Attenuation.Z; + + break; + default: + break; + } + + LightSpace.Light.push_back ( l ); + return LightSpace.Light.size() - 1; +} + +//! Turns a dynamic light on or off +void CBurningVideoDriver::turnLightOn(s32 lightIndex, bool turnOn) +{ + if(lightIndex > -1 && lightIndex < (s32)LightSpace.Light.size()) + { + LightSpace.Light[lightIndex].LightIsOn = turnOn; + } +} + +//! deletes all dynamic lights there are +void CBurningVideoDriver::deleteAllDynamicLights() +{ + LightSpace.reset (); + CNullDriver::deleteAllDynamicLights(); + +} + +//! returns the maximal amount of dynamic lights the device can handle +u32 CBurningVideoDriver::getMaximalDynamicLightAmount() const +{ + return 8; +} + + +//! sets a material +void CBurningVideoDriver::setMaterial(const SMaterial& material) +{ + Material.org = material; + +#ifdef SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM + for (u32 i = 0; i < 2; ++i) + { + setTransform((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i), + material.getTextureMatrix(i)); + } +#endif + +#ifdef SOFTWARE_DRIVER_2_LIGHTING + Material.AmbientColor.setR8G8B8 ( Material.org.AmbientColor.color ); + Material.DiffuseColor.setR8G8B8 ( Material.org.DiffuseColor.color ); + Material.EmissiveColor.setR8G8B8 ( Material.org.EmissiveColor.color ); + Material.SpecularColor.setR8G8B8 ( Material.org.SpecularColor.color ); + + core::setbit_cond ( LightSpace.Flags, Material.org.Shininess != 0.f, SPECULAR ); + core::setbit_cond ( LightSpace.Flags, Material.org.FogEnable, FOG ); + core::setbit_cond ( LightSpace.Flags, Material.org.NormalizeNormals, NORMALIZE ); +#endif + + setCurrentShader(); +} + + +/*! + Camera Position in World Space +*/ +void CBurningVideoDriver::getCameraPosWorldSpace () +{ + Transformation[ETS_VIEW_INVERSE] = Transformation[ ETS_VIEW ]; + Transformation[ETS_VIEW_INVERSE].makeInverse (); + TransformationFlag[ETS_VIEW_INVERSE] = 0; + + const f32 *M = Transformation[ETS_VIEW_INVERSE].pointer (); + + /* The viewpoint is at (0., 0., 0.) in eye space. + Turning this into a vector [0 0 0 1] and multiply it by + the inverse of the view matrix, the resulting vector is the + object space location of the camera. + */ + + LightSpace.campos.x = M[12]; + LightSpace.campos.y = M[13]; + LightSpace.campos.z = M[14]; + LightSpace.campos.w = 1.f; +} + +void CBurningVideoDriver::getLightPosObjectSpace () +{ + if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) + { + Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; + TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; + } + else + { + Transformation[ETS_WORLD].getInverse ( Transformation[ETS_WORLD_INVERSE] ); + TransformationFlag[ETS_WORLD_INVERSE] &= ~ETF_IDENTITY; + } + + for ( u32 i = 0; i < 1 && i < LightSpace.Light.size(); ++i ) + { + SBurningShaderLight &l = LightSpace.Light[i]; + + Transformation[ETS_WORLD_INVERSE].transformVec3 ( &l.pos_objectspace.x, &l.pos.x ); + } +} + + +#ifdef SOFTWARE_DRIVER_2_LIGHTING + +//! Sets the fog mode. +void CBurningVideoDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) +{ + CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog); + LightSpace.FogColor.setA8R8G8B8 ( color.color ); +} + +/*! + applies lighting model +*/ +void CBurningVideoDriver::lightVertex ( s4DVertex *dest, u32 vertexargb ) +{ + sVec3 dColor; + + dColor = LightSpace.Global_AmbientLight; + dColor.add ( Material.EmissiveColor ); + + if ( Lights.size () == 0 ) + { + dColor.saturate( dest->Color[0], vertexargb); + return; + } + + sVec3 ambient; + sVec3 diffuse; + sVec3 specular; + + + // the universe started in darkness.. + ambient.set ( 0.f, 0.f, 0.f ); + diffuse.set ( 0.f, 0.f, 0.f ); + specular.set ( 0.f, 0.f, 0.f ); + + + u32 i; + f32 dot; + f32 len; + f32 attenuation; + sVec4 vp; // unit vector vertex to light + sVec4 lightHalf; // blinn-phong reflection + + for ( i = 0; i!= LightSpace.Light.size (); ++i ) + { + const SBurningShaderLight &light = LightSpace.Light[i]; + + if ( !light.LightIsOn ) + continue; + + // accumulate ambient + ambient.add ( light.AmbientColor ); + + switch ( light.Type ) + { + case video::ELT_SPOT: + case video::ELT_POINT: + // surface to light + vp.x = light.pos.x - LightSpace.vertex.x; + vp.y = light.pos.y - LightSpace.vertex.y; + vp.z = light.pos.z - LightSpace.vertex.z; + //vp.x = light.pos_objectspace.x - LightSpace.vertex.x; + //vp.y = light.pos_objectspace.y - LightSpace.vertex.x; + //vp.z = light.pos_objectspace.z - LightSpace.vertex.x; + + len = vp.get_length_xyz_square(); + if ( light.radius < len ) + continue; + + len = core::reciprocal_squareroot ( len ); + + // build diffuse reflection + + //angle between normal and light vector + vp.mul ( len ); + dot = LightSpace.normal.dot_xyz ( vp ); + if ( dot < 0.f ) + continue; + + attenuation = light.constantAttenuation + ( 1.f - ( len * light.linearAttenuation ) ); + + // diffuse component + diffuse.mulAdd ( light.DiffuseColor, 3.f * dot * attenuation ); + + if ( !(LightSpace.Flags & SPECULAR) ) + continue; + + // build specular + // surface to view + lightHalf.x = LightSpace.campos.x - LightSpace.vertex.x; + lightHalf.y = LightSpace.campos.y - LightSpace.vertex.y; + lightHalf.z = LightSpace.campos.z - LightSpace.vertex.z; + lightHalf.normalize_xyz(); + lightHalf += vp; + lightHalf.normalize_xyz(); + + // specular + dot = LightSpace.normal.dot_xyz ( lightHalf ); + if ( dot < 0.f ) + continue; + + //specular += light.SpecularColor * ( powf ( Material.org.Shininess ,dot ) * attenuation ); + specular.mulAdd ( light.SpecularColor, dot * attenuation ); + break; + + case video::ELT_DIRECTIONAL: + + //angle between normal and light vector + dot = LightSpace.normal.dot_xyz ( light.pos ); + if ( dot < 0.f ) + continue; + + // diffuse component + diffuse.mulAdd ( light.DiffuseColor, dot ); + break; + default: + break; + } + + } + + // sum up lights + dColor.mulAdd (ambient, Material.AmbientColor ); + dColor.mulAdd (diffuse, Material.DiffuseColor); + dColor.mulAdd (specular, Material.SpecularColor); + + dColor.saturate ( dest->Color[0], vertexargb ); +} + +#endif + + +//! 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. +void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (texture) + { + if (texture->getDriverType() != EDT_BURNINGSVIDEO) + { + os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); + return; + } + +#if 0 + // 2d methods don't use viewPort + core::position2di dest = destPos; + core::recti clip=ViewPort; + if (ViewPort.getSize().Width != ScreenSize.Width) + { + dest.X=ViewPort.UpperLeftCorner.X+core::round32(destPos.X*ViewPort.getWidth()/(f32)ScreenSize.Width); + dest.Y=ViewPort.UpperLeftCorner.Y+core::round32(destPos.Y*ViewPort.getHeight()/(f32)ScreenSize.Height); + if (clipRect) + { + clip.constrainTo(*clipRect); + } + clipRect = &clip; + } +#endif + if (useAlphaChannelOfTexture) + ((CSoftwareTexture2*)texture)->getImage()->copyToWithAlpha( + RenderTargetSurface, destPos, sourceRect, color, clipRect); + else + ((CSoftwareTexture2*)texture)->getImage()->copyTo( + RenderTargetSurface, destPos, sourceRect, clipRect); + } +} + + +//! Draws a part of the texture into the rectangle. +void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) +{ + if (texture) + { + if (texture->getDriverType() != EDT_BURNINGSVIDEO) + { + os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); + return; + } + + if (useAlphaChannelOfTexture) + StretchBlit(BLITTER_TEXTURE_ALPHA_BLEND, RenderTargetSurface, &destRect, &sourceRect, + ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); + else + StretchBlit(BLITTER_TEXTURE, RenderTargetSurface, &destRect, &sourceRect, + ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); + } +} + +//! Draws a 2d line. +void CBurningVideoDriver::draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color) +{ + drawLine(BackBuffer, start, end, color ); +} + + +//! Draws a pixel +void CBurningVideoDriver::drawPixel(u32 x, u32 y, const SColor & color) +{ + BackBuffer->setPixel(x, y, color, true); +} + + +//! draw an 2d rectangle +void CBurningVideoDriver::draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip) +{ + if (clip) + { + core::rect p(pos); + + p.clipAgainst(*clip); + + if(!p.isValid()) + return; + + drawRectangle(BackBuffer, p, color); + } + else + { + if(!pos.isValid()) + return; + + drawRectangle(BackBuffer, pos, color); + } +} + + +//! Only used by the internal engine. Used to notify the driver that +//! the window was resized. +void CBurningVideoDriver::OnResize(const core::dimension2d& size) +{ + // make sure width and height are multiples of 2 + core::dimension2d realSize(size); + + if (realSize.Width % 2) + realSize.Width += 1; + + if (realSize.Height % 2) + realSize.Height += 1; + + if (ScreenSize != realSize) + { + if (ViewPort.getWidth() == (s32)ScreenSize.Width && + ViewPort.getHeight() == (s32)ScreenSize.Height) + { + ViewPort.UpperLeftCorner.X = 0; + ViewPort.UpperLeftCorner.Y = 0; + ViewPort.LowerRightCorner.X = realSize.Width; + ViewPort.LowerRightCorner.X = realSize.Height; + } + + ScreenSize = realSize; + + bool resetRT = (RenderTargetSurface == BackBuffer); + + if (BackBuffer) + BackBuffer->drop(); + BackBuffer = new CImage(BURNINGSHADER_COLOR_FORMAT, realSize); + + if (resetRT) + setRenderTarget(BackBuffer); + } +} + + +//! returns the current render target size +const core::dimension2d& CBurningVideoDriver::getCurrentRenderTargetSize() const +{ + return RenderTargetSize; +} + + +//!Draws an 2d rectangle with a gradient. +void CBurningVideoDriver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + const core::dimension2d renderTargetSize ( ViewPort.getSize() ); + + const s32 xPlus = -(renderTargetSize.Width>>1); + const f32 xFact = 1.0f / (renderTargetSize.Width>>1); + + const s32 yPlus = renderTargetSize.Height-(renderTargetSize.Height>>1); + const f32 yFact = 1.0f / (renderTargetSize.Height>>1); + + // fill VertexCache direct + s4DVertex *v; + + VertexCache.vertexCount = 4; + + VertexCache.info[0].index = 0; + VertexCache.info[1].index = 1; + VertexCache.info[2].index = 2; + VertexCache.info[3].index = 3; + + v = &VertexCache.mem.data [ 0 ]; + + v[0].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); + v[0].Color[0].setA8R8G8B8 ( colorLeftUp.color ); + + v[2].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus- pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); + v[2].Color[0].setA8R8G8B8 ( colorRightUp.color ); + + v[4].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f ,1.f ); + v[4].Color[0].setA8R8G8B8 ( colorRightDown.color ); + + v[6].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f, 1.f ); + v[6].Color[0].setA8R8G8B8 ( colorLeftDown.color ); + + s32 i; + u32 g; + + for ( i = 0; i!= 8; i += 2 ) + { + v[i + 0].flag = clipToFrustumTest ( v + i ); + v[i + 1].flag = 0; + if ( (v[i].flag & VERTEX4D_INSIDE ) == VERTEX4D_INSIDE ) + { + ndc_2_dc_and_project ( v + i + 1, v + i, 2 ); + } + } + + + IBurningShader * render; + + render = BurningShader [ ETR_GOURAUD_ALPHA_NOZ ]; + render->setRenderTarget(RenderTargetSurface, ViewPort); + + static const s16 indexList[6] = {0,1,2,0,2,3}; + + s4DVertex * face[3]; + + for ( i = 0; i!= 6; i += 3 ) + { + face[0] = VertexCache_getVertex ( indexList [ i + 0 ] ); + face[1] = VertexCache_getVertex ( indexList [ i + 1 ] ); + face[2] = VertexCache_getVertex ( indexList [ i + 2 ] ); + + // test clipping + u32 test = face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_INSIDE; + + if ( test == VERTEX4D_INSIDE ) + { + render->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); + continue; + } + // Todo: all vertices are clipped in 2d.. + // is this true ? + u32 vOut = 6; + memcpy ( CurrentOut.data + 0, face[0], sizeof ( s4DVertex ) * 2 ); + memcpy ( CurrentOut.data + 2, face[1], sizeof ( s4DVertex ) * 2 ); + memcpy ( CurrentOut.data + 4, face[2], sizeof ( s4DVertex ) * 2 ); + + vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); + if ( vOut < 3 ) + continue; + + vOut <<= 1; + // to DC Space, project homogenous vertex + ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); + + // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) + for ( g = 0; g <= vOut - 6; g += 2 ) + { + // rasterize + render->drawTriangle ( CurrentOut.data + 1, &CurrentOut.data[g + 3], &CurrentOut.data[g + 5] ); + } + + } +#else + draw2DRectangle ( colorLeftUp, position, clip ); +#endif +} + + +//! Draws a 3d line. +void CBurningVideoDriver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ + Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[0].Pos.x, start ); + Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[2].Pos.x, end ); + + u32 g; + u32 vOut; + + // no clipping flags + for ( g = 0; g != CurrentOut.ElementSize; ++g ) + { + CurrentOut.data[g].flag = 0; + Temp.data[g].flag = 0; + } + + // vertices count per line + vOut = clipToFrustum ( CurrentOut.data, Temp.data, 2 ); + if ( vOut < 2 ) + return; + + vOut <<= 1; + + IBurningShader * line; + line = BurningShader [ ETR_TEXTURE_GOURAUD_WIRE ]; + line->setRenderTarget(RenderTargetSurface, ViewPort); + + // to DC Space, project homogenous vertex + ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); + + // unproject vertex color +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( g = 0; g != vOut; g+= 2 ) + { + CurrentOut.data[ g + 1].Color[0].setA8R8G8B8 ( color.color ); + } +#endif + + + for ( g = 0; g <= vOut - 4; g += 2 ) + { + // rasterize + line->drawLine ( CurrentOut.data + 1, CurrentOut.data + g + 3 ); + } +} + + +//! \return Returns the name of the video driver. Example: In case of the DirectX8 +//! driver, it would return "Direct3D8.1". +const wchar_t* CBurningVideoDriver::getName() const +{ +#ifdef BURNINGVIDEO_RENDERER_BEAUTIFUL + return L"Burning's Video 0.47 beautiful"; +#elif defined ( BURNINGVIDEO_RENDERER_ULTRA_FAST ) + return L"Burning's Video 0.47 ultra fast"; +#elif defined ( BURNINGVIDEO_RENDERER_FAST ) + return L"Burning's Video 0.47 fast"; +#else + return L"Burning's Video 0.47"; +#endif +} + +//! Returns the graphics card vendor name. +core::stringc CBurningVideoDriver::getVendorInfo() +{ + return "Burning's Video: Ing. Thomas Alten (c) 2006-2012"; +} + + +//! Returns type of video driver +E_DRIVER_TYPE CBurningVideoDriver::getDriverType() const +{ + return EDT_BURNINGSVIDEO; +} + + +//! returns color format +ECOLOR_FORMAT CBurningVideoDriver::getColorFormat() const +{ + return BURNINGSHADER_COLOR_FORMAT; +} + + +//! Returns the transformation set by setTransform +const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return Transformation[state]; +} + + +//! Creates a render target texture. +ITexture* CBurningVideoDriver::addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format) +{ + IImage* img = createImage(BURNINGSHADER_COLOR_FORMAT, size); + ITexture* tex = new CSoftwareTexture2(img, name, CSoftwareTexture2::IS_RENDERTARGET ); + img->drop(); + addTexture(tex); + tex->drop(); + return tex; +} + + +//! Clears the DepthBuffer. +void CBurningVideoDriver::clearZBuffer() +{ + if (DepthBuffer) + DepthBuffer->clear(); +} + + +//! Returns an image created from the last rendered frame. +IImage* CBurningVideoDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) +{ + if (target != video::ERT_FRAME_BUFFER) + return 0; + + if (BackBuffer) + { + IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension()); + BackBuffer->copyTo(tmp); + return tmp; + } + else + return 0; +} + + +//! returns a device dependent texture from a software surface (IImage) +//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES +ITexture* CBurningVideoDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData) +{ + return new CSoftwareTexture2( + surface, name, + (getTextureCreationFlag(ETCF_CREATE_MIP_MAPS) ? CSoftwareTexture2::GEN_MIPMAP : 0 ) | + (getTextureCreationFlag(ETCF_ALLOW_NON_POWER_2) ? 0 : CSoftwareTexture2::NP2_SIZE ), mipmapData); + +} + + +//! Returns the maximum amount of primitives (mostly vertices) which +//! the device is able to render with one drawIndexedTriangleList +//! call. +u32 CBurningVideoDriver::getMaximalPrimitiveCount() const +{ + return 0xFFFFFFFF; +} + + +//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do +//! this: First, draw all geometry. Then use this method, to draw the shadow +//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. +void CBurningVideoDriver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) +{ + const u32 count = triangles.size(); + IBurningShader *shader = BurningShader [ ETR_STENCIL_SHADOW ]; + + CurrentShader = shader; + shader->setRenderTarget(RenderTargetSurface, ViewPort); + + Material.org.MaterialType = video::EMT_SOLID; + Material.org.Lighting = false; + Material.org.ZWriteEnable = false; + Material.org.ZBuffer = ECFN_LESSEQUAL; + LightSpace.Flags &= ~VERTEXTRANSFORM; + + //glStencilMask(~0); + //glStencilFunc(GL_ALWAYS, 0, ~0); + + if (true)// zpass does not work yet + { + Material.org.BackfaceCulling = true; + Material.org.FrontfaceCulling = false; + shader->setParam ( 0, 0 ); + shader->setParam ( 1, 1 ); + shader->setParam ( 2, 0 ); + drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); + //glStencilOp(GL_KEEP, incr, GL_KEEP); + //glDrawArrays(GL_TRIANGLES,0,count); + + Material.org.BackfaceCulling = false; + Material.org.FrontfaceCulling = true; + shader->setParam ( 0, 0 ); + shader->setParam ( 1, 2 ); + shader->setParam ( 2, 0 ); + drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); + //glStencilOp(GL_KEEP, decr, GL_KEEP); + //glDrawArrays(GL_TRIANGLES,0,count); + } + else // zpass + { + Material.org.BackfaceCulling = true; + Material.org.FrontfaceCulling = false; + shader->setParam ( 0, 0 ); + shader->setParam ( 1, 0 ); + shader->setParam ( 2, 1 ); + //glStencilOp(GL_KEEP, GL_KEEP, incr); + //glDrawArrays(GL_TRIANGLES,0,count); + + Material.org.BackfaceCulling = false; + Material.org.FrontfaceCulling = true; + shader->setParam ( 0, 0 ); + shader->setParam ( 1, 0 ); + shader->setParam ( 2, 2 ); + //glStencilOp(GL_KEEP, GL_KEEP, decr); + //glDrawArrays(GL_TRIANGLES,0,count); + } +} + +//! Fills the stencil shadow with color. After the shadow volume has been drawn +//! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this +//! to draw the color of the shadow. +void CBurningVideoDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, + video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) +{ + if (!StencilBuffer) + return; + // draw a shadow rectangle covering the entire screen using stencil buffer + const u32 h = RenderTargetSurface->getDimension().Height; + const u32 w = RenderTargetSurface->getDimension().Width; + tVideoSample *dst; + u32 *stencil; + u32* const stencilBase=(u32*) StencilBuffer->lock(); + + for ( u32 y = 0; y < h; ++y ) + { + dst = (tVideoSample*)RenderTargetSurface->lock() + ( y * w ); + stencil = stencilBase + ( y * w ); + + for ( u32 x = 0; x < w; ++x ) + { + if ( stencil[x] > 1 ) + { + dst[x] = PixelBlend32 ( dst[x], leftUpEdge.color ); + } + } + } + + StencilBuffer->clear(); +} + + +core::dimension2du CBurningVideoDriver::getMaxTextureSize() const +{ + return core::dimension2du(SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE, SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE); +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a video driver +IVideoDriver* createBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CBurningVideoDriver(params, io, presenter); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + + +} // end namespace video +} // end namespace irr + -- cgit v1.1