// 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 #ifndef __S_4D_VERTEX_H_INCLUDED__ #define __S_4D_VERTEX_H_INCLUDED__ #include "SoftwareDriver2_compile_config.h" #include "SoftwareDriver2_helper.h" #include "irrAllocator.h" namespace irr { namespace video { struct sVec2 { f32 x; f32 y; sVec2 () {} sVec2 ( f32 s) : x ( s ), y ( s ) {} sVec2 ( f32 _x, f32 _y ) : x ( _x ), y ( _y ) {} void set ( f32 _x, f32 _y ) { x = _x; y = _y; } // f = a * t + b * ( 1 - t ) void interpolate(const sVec2& a, const sVec2& b, const f32 t) { x = b.x + ( ( a.x - b.x ) * t ); y = b.y + ( ( a.y - b.y ) * t ); } sVec2 operator-(const sVec2& other) const { return sVec2(x - other.x, y - other.y); } sVec2 operator+(const sVec2& other) const { return sVec2(x + other.x, y + other.y); } void operator+=(const sVec2& other) { x += other.x; y += other.y; } sVec2 operator*(const f32 s) const { return sVec2(x * s , y * s); } void operator*=( const f32 s) { x *= s; y *= s; } void operator=(const sVec2& other) { x = other.x; y = other.y; } }; // A8R8G8B8 struct sVec4; struct sCompressedVec4 { u32 argb; void setA8R8G8B8 ( u32 value ) { argb = value; } void setColorf ( const video::SColorf & color ) { argb = core::floor32 ( color.a * 255.f ) << 24 | core::floor32 ( color.r * 255.f ) << 16 | core::floor32 ( color.g * 255.f ) << 8 | core::floor32 ( color.b * 255.f ); } void setVec4 ( const sVec4 & v ); // f = a * t + b * ( 1 - t ) void interpolate(const sCompressedVec4& a, const sCompressedVec4& b, const f32 t) { argb = PixelBlend32 ( b.argb, a.argb, core::floor32 ( t * 256.f ) ); } }; struct sVec4 { union { struct { f32 x, y, z, w; }; struct { f32 a, r, g, b; }; // struct { sVec2 xy, zw; }; // sorry, this does not compile with gcc }; sVec4 () {} sVec4 ( f32 s) : x ( s ), y ( s ), z ( s ), w ( s ) {} sVec4 ( f32 _x, f32 _y, f32 _z, f32 _w ) : x ( _x ), y ( _y ), z( _z ), w ( _w ){} void set ( f32 _x, f32 _y, f32 _z, f32 _w ) { x = _x; y = _y; z = _z; w = _w; } void setA8R8G8B8 ( u32 argb ) { x = ( ( argb & 0xFF000000 ) >> 24 ) * ( 1.f / 255.f ); y = ( ( argb & 0x00FF0000 ) >> 16 ) * ( 1.f / 255.f ); z = ( ( argb & 0x0000FF00 ) >> 8 ) * ( 1.f / 255.f ); w = ( ( argb & 0x000000FF ) ) * ( 1.f / 255.f ); } void setColorf ( const video::SColorf & color ) { x = color.a; y = color.r; z = color.g; w = color.b; } // f = a * t + b * ( 1 - t ) void interpolate(const sVec4& a, const sVec4& b, const f32 t) { x = b.x + ( ( a.x - b.x ) * t ); y = b.y + ( ( a.y - b.y ) * t ); z = b.z + ( ( a.z - b.z ) * t ); w = b.w + ( ( a.w - b.w ) * t ); } f32 dotProduct(const sVec4& other) const { return x*other.x + y*other.y + z*other.z + w*other.w; } f32 dot_xyz( const sVec4& other) const { return x*other.x + y*other.y + z*other.z; } f32 get_length_xyz_square () const { return x * x + y * y + z * z; } f32 get_length_xyz () const { return core::squareroot ( x * x + y * y + z * z ); } void normalize_xyz () { const f32 l = core::reciprocal_squareroot ( x * x + y * y + z * z ); x *= l; y *= l; z *= l; } void project_xyz () { w = core::reciprocal ( w ); x *= w; y *= w; z *= w; } sVec4 operator-(const sVec4& other) const { return sVec4(x - other.x, y - other.y, z - other.z,w - other.w); } sVec4 operator+(const sVec4& other) const { return sVec4(x + other.x, y + other.y, z + other.z,w + other.w); } void operator+=(const sVec4& other) { x += other.x; y += other.y; z += other.z; w += other.w; } sVec4 operator*(const f32 s) const { return sVec4(x * s , y * s, z * s,w * s); } sVec4 operator*(const sVec4 &other) const { return sVec4(x * other.x , y * other.y, z * other.z,w * other.w); } void mulReciprocal ( f32 s ) { const f32 i = core::reciprocal ( s ); x = (f32) ( x * i ); y = (f32) ( y * i ); z = (f32) ( z * i ); w = (f32) ( w * i ); } void mul ( const f32 s ) { x *= s; y *= s; z *= s; w *= s; } /* void operator*=(f32 s) { x *= s; y *= s; z *= s; w *= s; } */ void operator*=(const sVec4 &other) { x *= other.x; y *= other.y; z *= other.z; w *= other.w; } void operator=(const sVec4& other) { x = other.x; y = other.y; z = other.z; w = other.w; } }; struct sVec3 { union { struct { f32 r, g, b; }; struct { f32 x, y, z; }; }; sVec3 () {} sVec3 ( f32 _x, f32 _y, f32 _z ) : r ( _x ), g ( _y ), b( _z ) {} sVec3 ( const sVec4 &v ) : r ( v.x ), g ( v.y ), b( v.z ) {} void set ( f32 _r, f32 _g, f32 _b ) { r = _r; g = _g; b = _b; } void setR8G8B8 ( u32 argb ) { r = ( ( argb & 0x00FF0000 ) >> 16 ) * ( 1.f / 255.f ); g = ( ( argb & 0x0000FF00 ) >> 8 ) * ( 1.f / 255.f ); b = ( ( argb & 0x000000FF ) ) * ( 1.f / 255.f ); } void setColorf ( const video::SColorf & color ) { r = color.r; g = color.g; b = color.b; } void add (const sVec3& other) { r += other.r; g += other.g; b += other.b; } void mulAdd(const sVec3& other, const f32 v) { r += other.r * v; g += other.g * v; b += other.b * v; } void mulAdd(const sVec3& v0, const sVec3& v1) { r += v0.r * v1.r; g += v0.g * v1.g; b += v0.b * v1.b; } void saturate ( sVec4 &dest, u32 argb ) { dest.x = ( ( argb & 0xFF000000 ) >> 24 ) * ( 1.f / 255.f ); dest.y = core::min_ ( r, 1.f ); dest.z = core::min_ ( g, 1.f ); dest.w = core::min_ ( b, 1.f ); } // f = a * t + b * ( 1 - t ) void interpolate(const sVec3& v0, const sVec3& v1, const f32 t) { r = v1.r + ( ( v0.r - v1.r ) * t ); g = v1.g + ( ( v0.g - v1.g ) * t ); b = v1.b + ( ( v0.b - v1.b ) * t ); } sVec3 operator-(const sVec3& other) const { return sVec3(r - other.r, b - other.b, g - other.g); } sVec3 operator+(const sVec3& other) const { return sVec3(r + other.r, g + other.g, b + other.b); } sVec3 operator*(const f32 s) const { return sVec3(r * s , g * s, b * s); } sVec3 operator/(const f32 s) const { f32 inv = 1.f / s; return sVec3(r * inv , g * inv, b * inv); } sVec3 operator*(const sVec3 &other) const { return sVec3(r * other.r , b * other.b, g * other.g); } void operator+=(const sVec3& other) { r += other.r; g += other.g; b += other.b; } void setLength ( f32 len ) { const f32 l = len * core::reciprocal_squareroot ( r * r + g * g + b * b ); r *= l; g *= l; b *= l; } }; inline void sCompressedVec4::setVec4 ( const sVec4 & v ) { argb = core::floor32 ( v.x * 255.f ) << 24 | core::floor32 ( v.y * 255.f ) << 16 | core::floor32 ( v.z * 255.f ) << 8 | core::floor32 ( v.w * 255.f ); } enum e4DVertexFlag { VERTEX4D_INSIDE = 0x0000003F, VERTEX4D_CLIPMASK = 0x0000003F, VERTEX4D_PROJECTED = 0x00000100, VERTEX4D_FORMAT_MASK = 0xFFFF0000, VERTEX4D_FORMAT_MASK_TEXTURE = 0x000F0000, VERTEX4D_FORMAT_TEXTURE_1 = 0x00010000, VERTEX4D_FORMAT_TEXTURE_2 = 0x00020000, VERTEX4D_FORMAT_TEXTURE_3 = 0x00030000, VERTEX4D_FORMAT_TEXTURE_4 = 0x00040000, VERTEX4D_FORMAT_MASK_COLOR = 0x00F00000, VERTEX4D_FORMAT_COLOR_1 = 0x00100000, VERTEX4D_FORMAT_COLOR_2 = 0x00200000, VERTEX4D_FORMAT_MASK_BUMP = 0x0F000000, VERTEX4D_FORMAT_BUMP_DOT3 = 0x01000000, }; const u32 MATERIAL_MAX_COLORS = 1; const u32 BURNING_MATERIAL_MAX_TEXTURES = 2; const u32 BURNING_MATERIAL_MAX_TANGENT = 1; // dummy Vertex. used for calculation vertex memory size struct s4DVertex_proxy { u32 flag; sVec4 Pos; sVec2 Tex[BURNING_MATERIAL_MAX_TEXTURES]; #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR sVec4 Color[MATERIAL_MAX_COLORS]; #endif sVec3 LightTangent[BURNING_MATERIAL_MAX_TANGENT]; }; #define SIZEOF_SVERTEX 64 #define SIZEOF_SVERTEX_LOG2 6 /*! Internal BurningVideo Vertex */ struct s4DVertex { u32 flag; sVec4 Pos; sVec2 Tex[ BURNING_MATERIAL_MAX_TEXTURES ]; #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR sVec4 Color[ MATERIAL_MAX_COLORS ]; #endif sVec3 LightTangent[BURNING_MATERIAL_MAX_TANGENT]; //u8 fill [ SIZEOF_SVERTEX - sizeof (s4DVertex_proxy) ]; // f = a * t + b * ( 1 - t ) void interpolate(const s4DVertex& b, const s4DVertex& a, const f32 t) { u32 i; u32 size; Pos.interpolate ( a.Pos, b.Pos, t ); #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR size = (flag & VERTEX4D_FORMAT_MASK_COLOR) >> 20; for ( i = 0; i!= size; ++i ) { Color[i].interpolate ( a.Color[i], b.Color[i], t ); } #endif size = (flag & VERTEX4D_FORMAT_MASK_TEXTURE) >> 16; for ( i = 0; i!= size; ++i ) { Tex[i].interpolate ( a.Tex[i], b.Tex[i], t ); } size = (flag & VERTEX4D_FORMAT_MASK_BUMP) >> 24; for ( i = 0; i!= size; ++i ) { LightTangent[i].interpolate ( a.LightTangent[i], b.LightTangent[i], t ); } } }; // ----------------- Vertex Cache --------------------------- struct SAlignedVertex { SAlignedVertex ( u32 element, u32 aligned ) : ElementSize ( element ) { u32 byteSize = (ElementSize << SIZEOF_SVERTEX_LOG2 ) + aligned; mem = new u8 [ byteSize ]; data = (s4DVertex*) mem; } virtual ~SAlignedVertex () { delete [] mem; } s4DVertex *data; u8 *mem; u32 ElementSize; }; // hold info for different Vertex Types struct SVSize { u32 Format; u32 Pitch; u32 TexSize; }; // a cache info struct SCacheInfo { u32 index; u32 hit; }; #define VERTEXCACHE_ELEMENT 16 #define VERTEXCACHE_MISS 0xFFFFFFFF struct SVertexCache { SVertexCache (): mem ( VERTEXCACHE_ELEMENT * 2, 128 ) {} SCacheInfo info[VERTEXCACHE_ELEMENT]; // Transformed and lite, clipping state // + Clipped, Projected SAlignedVertex mem; // source const void* vertices; u32 vertexCount; const void* indices; u32 indexCount; u32 indicesIndex; u32 indicesRun; // primitives consist of x vertices u32 primitivePitch; u32 vType; //E_VERTEX_TYPE u32 pType; //scene::E_PRIMITIVE_TYPE u32 iType; //E_INDEX_TYPE iType }; // swap 2 pointer REALINLINE void swapVertexPointer(const s4DVertex** v1, const s4DVertex** v2) { const s4DVertex* b = *v1; *v1 = *v2; *v2 = b; } // ------------------------ Internal Scanline Rasterizer ----------------------------- // internal scan convert struct sScanConvertData { u8 left; // major edge left/right u8 right; // !left f32 invDeltaY[3]; // inverse edge delta y f32 x[2]; // x coordinate f32 slopeX[2]; // x slope along edges #if defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) || defined ( SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT ) f32 w[2]; // w coordinate fp24 slopeW[2]; // w slope along edges #else f32 z[2]; // z coordinate f32 slopeZ[2]; // z slope along edges #endif sVec4 c[MATERIAL_MAX_COLORS][2]; // color sVec4 slopeC[MATERIAL_MAX_COLORS][2]; // color slope along edges sVec2 t[BURNING_MATERIAL_MAX_TEXTURES][2]; // texture sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES][2]; // texture slope along edges sVec3 l[BURNING_MATERIAL_MAX_TANGENT][2]; // Light Tangent sVec3 slopeL[BURNING_MATERIAL_MAX_TEXTURES][2]; // tanget slope along edges }; // passed to scan Line struct sScanLineData { s32 y; // y position of scanline f32 x[2]; // x start, x end of scanline #if defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) || defined ( SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT ) f32 w[2]; // w start, w end of scanline #else f32 z[2]; // z start, z end of scanline #endif #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR sVec4 c[MATERIAL_MAX_COLORS][2]; // color start, color end of scanline #endif sVec2 t[BURNING_MATERIAL_MAX_TEXTURES][2]; // texture start, texture end of scanline sVec3 l[BURNING_MATERIAL_MAX_TANGENT][2]; // Light Tangent start, end }; // passed to pixel Shader struct sPixelShaderData { tVideoSample *dst; fp24 *z; s32 xStart; s32 xEnd; s32 dx; s32 i; }; /* load a color value */ inline void getTexel_plain2 ( tFixPoint &r, tFixPoint &g, tFixPoint &b, const sVec4 &v ) { r = tofix ( v.y ); g = tofix ( v.z ); b = tofix ( v.w ); } /* load a color value */ inline void getSample_color ( tFixPoint &a, tFixPoint &r, tFixPoint &g, tFixPoint &b, const sVec4 &v ) { a = tofix ( v.x ); r = tofix ( v.y, COLOR_MAX * FIX_POINT_F32_MUL); g = tofix ( v.z, COLOR_MAX * FIX_POINT_F32_MUL); b = tofix ( v.w, COLOR_MAX * FIX_POINT_F32_MUL); } /* load a color value */ inline void getSample_color ( tFixPoint &r, tFixPoint &g, tFixPoint &b,const sVec4 &v ) { r = tofix ( v.y, COLOR_MAX * FIX_POINT_F32_MUL); g = tofix ( v.z, COLOR_MAX * FIX_POINT_F32_MUL); b = tofix ( v.w, COLOR_MAX * FIX_POINT_F32_MUL); } /* load a color value */ inline void getSample_color ( tFixPoint &r, tFixPoint &g, tFixPoint &b, const sVec4 &v, const f32 mulby ) { r = tofix ( v.y, mulby); g = tofix ( v.z, mulby); b = tofix ( v.w, mulby); } } } #endif