3D C/C++ tutorials -> Software rendering -> Software shadow mapping
Use for personal or educational purposes only. Commercial and other profit uses strictly prohibited. Exploitation of content on a website or in a publication prohibited.
software_shadow_mapping.h
// ----------------------------------------------------------------------------------------------------------------------------
#include <windows.h>
#ifndef WM_MOUSWHEEL
#define WM_MOUSWHEEL 0x020A
#endif
#include "string.h"
#include "glmath.h"
#include <FreeImage.h> // http://freeimage.sourceforge.net/
#pragma comment(lib, "FreeImage.lib")
#pragma comment(lib, "winmm.lib")
#pragma warning(disable : 4996)
// ----------------------------------------------------------------------------------------------------------------------------
class CTexture
{
private:
void *Bits;
private:
int Width, Height, Format, Pitch;
public:
CTexture();
~CTexture();
private:
void SetDefaults();
public:
void* GetBits();
int GetWidth();
int GetHeight();
int GetFormat();
public:
void Create(int Width, int Height, int Format);
bool LoadTexture(char *TextureFileName);
void GetColorNearest(float s, float t, vec3 &Color);
void GetColorBilinear(float s, float t, vec3 &Color);
float GetShadowNearest(vec4 &TexCoord);
float GetShadowBilinear(vec4 &TexCoord);
void Destroy();
};
// ----------------------------------------------------------------------------------------------------------------------------
class CFrameBuffer
{
private:
CTexture *ColorTexture;
CTexture *DepthTexture;
public:
CFrameBuffer();
~CFrameBuffer();
public:
CTexture* GetColorTexture();
void SetColorTexture(CTexture *ColorTexture);
CTexture* GetDepthTexture();
void SetDepthTexture(CTexture *DepthTexture);
};
// ----------------------------------------------------------------------------------------------------------------------------
class CCamera
{
public:
vec3 X, Y, Z, Position, Reference;
public:
mat4x4 ViewMatrix, ProjectionMatrix, ViewProjectionMatrix;
public:
CCamera();
~CCamera();
public:
void Look(const vec3 &Position, const vec3 &Reference, bool RotateAroundReference = false);
void Move(const vec3 &Movement);
vec3 OnKeys(BYTE Keys, float FrameTime);
void OnMouseMove(int dx, int dy);
void OnMouseWheel(float zDelta);
void SetPerspective(float fovy, float aspect, float n, float f);
private:
void CalculateViewMatrix();
};
// ----------------------------------------------------------------------------------------------------------------------------
class CVertex
{
public:
vec3 Position;
vec3 Color;
vec2 TexCoord;
vec3 Normal;
};
// ----------------------------------------------------------------------------------------------------------------------------
class CObject
{
public:
CTexture Texture;
public:
CVertex *Vertices;
int VerticesCount;
public:
vec3 Min, Max;
public:
CObject();
~CObject();
private:
void SetDefaults();
public:
bool Load(char *Directory, char *ObjFileName);
void Translate(const vec3 &Translation);
void Scale(float ScaleFactor);
void Rotate(float Angle, const vec3 &Axis);
void Destroy();
private:
bool ReadSource(char *Directory, char *FileName, char **Source, long &Length);
bool ParseMtl(char *Directory, char *MtlFileName);
void GetMinMax();
};
// ----------------------------------------------------------------------------------------------------------------------------
class CLight
{
public:
vec3 Position;
vec3 Ambient;
vec3 Diffuse;
float ConstantAttenuation;
float LinearAttenuation;
float QuadraticAttenuation;
};
// ----------------------------------------------------------------------------------------------------------------------------
class CFragment
{
public:
vec4 Position;
vec3 Color;
vec2 TexCoord;
vec3 Normal;
vec3 LightDirection;
vec4 ShadowMapTexCoord;
};
// ----------------------------------------------------------------------------------------------------------------------------
class CEdge
{
public:
CFragment *Fragment1, *Fragment2;
public:
vec4 PositionDiff;
vec3 ColorDiff;
vec2 TexCoordDiff;
vec3 NormalDiff;
vec3 LightDirectionDiff;
vec4 ShadowMapTexCoordDiff;
public:
void Set(CFragment *Fragment1, CFragment *Fragment2);
};
// ----------------------------------------------------------------------------------------------------------------------------
class CSpan
{
public:
CFragment *Fragment1, *Fragment2;
public:
vec4 PositionDiff;
vec3 ColorDiff;
vec2 TexCoordDiff;
vec3 NormalDiff;
vec3 LightDirectionDiff;
vec4 ShadowMapTexCoordDiff;
public:
void Set(CFragment *Fragment1, CFragment *Fragment2);
};
// ----------------------------------------------------------------------------------------------------------------------------
#define NONE 0x00
#define ANTI_ALIASING_2X2 0x01
#define ANTI_ALIASING_3X3 0x02
#define ANTI_ALIASING_4X4 0x03
#define CULL_FACE_FRONT 0x04
#define CULL_FACE_BACK 0x05
#define TEXTURE_FORMAT_BGR24 0x06
#define TEXTURE_FORMAT_DEPTH16 0x07
// ----------------------------------------------------------------------------------------------------------------------------
#define THREAD_SLEEP_TIME 0
// ----------------------------------------------------------------------------------------------------------------------------
class CThreadData
{
public:
HANDLE Thread;
DWORD Id;
void *SoftwareGL;
int ThreadId, Function;
bool ThreadIsRunning;
};
// ----------------------------------------------------------------------------------------------------------------------------
class CSoftwareGL
{
private:
int Width, Height;
private:
int ViewportX, ViewportY, ViewportWidth, ViewportHeight;
private:
BYTE *AntiAliasingColorBuffer;
int AntiAliasingColorBufferWidth, AntiAliasingColorBufferHeight;
private:
BYTE *StandardColorBuffer;
int StandardColorBufferWidth, StandardColorBufferHeight;
private:
BITMAPINFO BitmapInfo;
private:
USHORT *StandardDepthBuffer;
int StandardDepthBufferWidth, StandardDepthBufferHeight;
private:
BYTE *ColorBuffer;
int ColorBufferWidth, ColorBufferHeight;
private:
USHORT *DepthBuffer;
int DepthBufferWidth, DepthBufferHeight;
private:
int BufferWidthM1, BufferHeightM1;
private:
CFrameBuffer *FrameBuffer;
private:
int AntiAliasing;
mat4x4 ModelViewProjectionMatrix, ShadowMapMatrix;
CLight *Light;
int CullFace;
bool BilinearTextureFiltering, DepthTest;
CTexture *Texture, *ShadowMap;
private:
CThreadData *ThreadsData;
int ThreadsCount;
private:
bool ColorBuffering, DepthTesting, NotDepthTesting, Texturing, Lighting, ShadowMapping;
private:
CVertex *Vertices;
int FirstIndex, LastIndex;
public:
CSoftwareGL();
~CSoftwareGL();
public:
int GetAntiAliasing();
void SetAntiAliasing(int AntiAliasing);
int GetCullFace();
void SetCullFace(int CullFace);
bool GetBilinearTextureFiltering();
void SetBilinearTextureFiltering(bool BilinearTextureFiltering);
bool GetDepthTest();
void SetDepthTest(bool DepthTest);
public:
int GetThreadsCount();
public:
void BindFrameBuffer(CFrameBuffer *FrameBuffer);
void Viewport(int X, int Y, int Width, int Height);
void Clear(bool ClearColorBuffer = true, bool ClearDepthBuffer = true);
void LoadModelViewProjectionMatrix(const mat4x4 &ModelViewProjectionMatrix);
void LoadShadowMapMatrix(const mat4x4 &ShadowMapMatrix);
void BindLight(CLight *Light);
void BindTexture(CTexture *Texture);
void BindShadowMap(CTexture *ShadowMap);
void DrawTriangles(CVertex *Vertices, int FirstIndex, int Count);
private:
void RunFunctionMultiThreadedAndWaitForCompletion(int Function);
bool ThreadsAreRunning();
static DWORD WINAPI ThreadProc(LPVOID lpParam);
void DrawTriangles(int ThreadId);
void ClipTriangle(CFragment *Fragments, int ThreadId, int ClipPlane = 1);
void RasterizeTriangle(CFragment *Fragments, int ThreadId);
void DrawSpansBetweenEdges(CEdge *Edge1, CEdge *Edge2, int ThreadId);
void DrawSpan(CSpan *Span, int y);
void BlitAntiAliasingColorBuffer2x2(int Line);
void BlitAntiAliasingColorBuffer3x3(int Line);
void BlitAntiAliasingColorBuffer4x4(int Line);
public:
void ResizeBuffers(int Width, int Height);
void SwapBuffers(HDC hDC);
};
// ----------------------------------------------------------------------------------------------------------------------------
class CSoftwareGLRenderer : public CSoftwareGL
{
private:
int Width, Height;
private:
int LastX, LastY, LastClickedX, LastClickedY;
private:
CCamera Camera;
private:
CTexture Texture;
private:
CObject Object;
private:
CVertex *Vertices;
private:
CLight Light;
mat4x4 LightViewMatrix, LightProjectionMatrix, LightViewProjectionMatrix;
private:
CTexture ShadowMap;
CFrameBuffer FrameBuffer;
mat4x4 OrthogonalProjectionMatrix;
private:
bool RenderObject, Texturing, Lighting, ShadowMapping, DisplayShadowMap, RotateLight;
public:
CSoftwareGLRenderer();
~CSoftwareGLRenderer();
public:
bool Init();
void Animate(float FrameTime);
void Render();
void Resize(int Width, int Height);
void Destroy();
private:
void RenderShadowMap();
public:
void CheckCameraKeys(float FrameTime);
public:
void OnKeyDown(UINT Key);
void OnLButtonDown(int X, int Y);
void OnLButtonUp(int X, int Y);
void OnMouseMove(int X, int Y);
void OnMouseWheel(short zDelta);
void OnRButtonDown(int X, int Y);
void OnRButtonUp(int X, int Y);
};
// ----------------------------------------------------------------------------------------------------------------------------
class CSoftwareGLView
{
private:
char *Title;
int Width, Height;
HWND hWnd;
HDC hDC;
private:
CSoftwareGLRenderer SoftwareGLRenderer;
public:
CSoftwareGLView();
~CSoftwareGLView();
public:
bool Create(HINSTANCE hInstance, char *Title, int Width, int Height);
void Show(bool Maximized = false);
void MsgLoop();
void Destroy();
public:
void OnKeyDown(UINT Key);
void OnLButtonDown(int X, int Y);
void OnLButtonUp(int X, int Y);
void OnMouseMove(int X, int Y);
void OnMouseWheel(short zDelta);
void OnPaint();
void OnRButtonDown(int X, int Y);
void OnRButtonUp(int X, int Y);
void OnSize(int Width, int Height);
};
// ----------------------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR sCmdLine, int iShow);
// ----------------------------------------------------------------------------------------------------------------------------
software_shadow_mapping.cpp
// ----------------------------------------------------------------------------------------------------------------------------
#include "software_shadow_mapping.h"
// ----------------------------------------------------------------------------------------------------------------------------
CString ErrorLog, ModuleDirectory;
// ----------------------------------------------------------------------------------------------------------------------------
CTexture::CTexture()
{
SetDefaults();
}
CTexture::~CTexture()
{
}
void CTexture::SetDefaults()
{
Bits = NULL;
Width = 0;
Height = 0;
Format = NONE;
Pitch = 0;
}
void* CTexture::GetBits()
{
return Bits;
}
int CTexture::GetWidth()
{
return Width;
}
int CTexture::GetHeight()
{
return Height;
}
int CTexture::GetFormat()
{
return Format;
}
void CTexture::Create(int Width, int Height, int Format)
{
Destroy();
if(Width > 0 && Height > 0 && (Format == TEXTURE_FORMAT_BGR24 || Format == TEXTURE_FORMAT_DEPTH16))
{
switch(Format)
{
case TEXTURE_FORMAT_BGR24: Bits = new BYTE[Width * Height * 3]; Pitch = Width * 3; break;
case TEXTURE_FORMAT_DEPTH16: Bits = new USHORT[Width * Height]; break;
}
this->Width = Width;
this->Height = Height;
this->Format = Format;
}
}
bool CTexture::LoadTexture(char *TextureFileName)
{
CString FileName = ModuleDirectory + TextureFileName;
CString ErrorText = "Error loading file " + FileName + " -> ";
FREE_IMAGE_FORMAT FIF = FreeImage_GetFileType(FileName);
if(FIF == FIF_UNKNOWN)
{
FIF = FreeImage_GetFIFFromFilename(FileName);
}
if(FIF == FIF_UNKNOWN)
{
ErrorLog.Append(ErrorText + "FIF is FIF_UNKNOWN!" + "\r\n");
return false;
}
FIBITMAP *DIB = NULL;
if(FreeImage_FIFSupportsReading(FIF))
{
DIB = FreeImage_Load(FIF, FileName);
}
if(DIB == NULL)
{
ErrorLog.Append(ErrorText + "DIB is NULL!" + "\r\n");
return false;
}
int Width = FreeImage_GetWidth(DIB);
int Height = FreeImage_GetHeight(DIB);
int Pitch = FreeImage_GetPitch(DIB);
int BPP = FreeImage_GetBPP(DIB);
if(Width == 0 || Height == 0)
{
ErrorLog.Append(ErrorText + "Width or Height is 0!" + "\r\n");
FreeImage_Unload(DIB);
return false;
}
if(BPP != 24 && BPP != 32)
{
ErrorLog.Append(ErrorText + "BPP is not 24 nor 32!" + "\r\n");
FreeImage_Unload(DIB);
return false;
}
BPP /= 8;
BYTE *Bits = FreeImage_GetBits(DIB);
if(Bits == NULL)
{
ErrorLog.Append(ErrorText + "Bits is NULL!" + "\r\n");
FreeImage_Unload(DIB);
return false;
}
Create(Width, Height, TEXTURE_FORMAT_BGR24);
BYTE *Colors = (BYTE*)this->Bits;
for(int y = 0; y < Height; y++)
{
for(int x = 0; x < Height; x++)
{
for(int i = 0; i < 3; i++)
{
Colors[(Width * y + x) * 3 + i] = Bits[Pitch * y + BPP * x + i];
}
}
}
FreeImage_Unload(DIB);
return true;
}
float OD255 = 1.0f / 255.0f, OD65535 = 1.0f / 65535.0f;
void CTexture::GetColorNearest(float s, float t, vec3 &Color)
{
if(Bits != NULL)
{
s -= (int)s;
t -= (int)t;
if(s < 0.0f) s += 1.0f;
if(t < 0.0f) t += 1.0f;
int x = (int)(s * Width), y = (int)(t * Height);
if(Format == TEXTURE_FORMAT_BGR24)
{
BYTE *A = (BYTE*)Bits + Pitch * y + x * 3;
Color.b = *A * OD255;
A++;
Color.g = *A * OD255;
A++;
Color.r = *A * OD255;
}
else if(Format == TEXTURE_FORMAT_DEPTH16)
{
USHORT *A = (USHORT*)Bits + Width * y + x;
Color.b = Color.g = Color.r = *A * OD65535;
}
}
else
{
Color.b = Color.g = Color.r = 1.0f;
}
}
void CTexture::GetColorBilinear(float s, float t, vec3 &Color)
{
if(Bits != NULL)
{
s -= (int)s;
t -= (int)t;
if(s < 0.0f) s += 1.0f;
if(t < 0.0f) t += 1.0f;
float fx = s * Width - 0.5f, fy = t * Height - 0.5f;
if(fx < 0.0f) fx += Width;
if(fy < 0.0f) fy += Height;
int x0 = (int)fx, y0 = (int)fy, x1 = (x0 + 1) % Width, y1 = (y0 + 1) % Height;
if(Format == TEXTURE_FORMAT_BGR24)
{
BYTE *LineAB = (BYTE*)Bits + Pitch * y0;
BYTE *LineCD = (BYTE*)Bits + Pitch * y1;
int x0M3 = x0 * 3, x1M3 = x1 * 3;
BYTE *A = LineAB + x0M3;
BYTE *B = LineAB + x1M3;
BYTE *C = LineCD + x1M3;
BYTE *D = LineCD + x0M3;
float u1 = fx - x0, v1 = fy - y0, u0 = 1.0f - u1, v0 = 1.0f - v1;
u0 *= OD255;
u1 *= OD255;
float u0v0 = u0 * v0, u1v0 = u1 * v0, u1v1 = u1 * v1, u0v1 = u0 * v1;
Color.b = *A * u0v0 + *B * u1v0 + *C * u1v1 + *D * u0v1;
A++; B++; C++; D++;
Color.g = *A * u0v0 + *B * u1v0 + *C * u1v1 + *D * u0v1;
A++; B++; C++; D++;
Color.r = *A * u0v0 + *B * u1v0 + *C * u1v1 + *D * u0v1;
}
else if(Format == TEXTURE_FORMAT_DEPTH16)
{
USHORT *LineAB = (USHORT*)Bits + Width * y0;
USHORT *LineCD = (USHORT*)Bits + Width * y1;
USHORT *A = LineAB + x0;
USHORT *B = LineAB + x1;
USHORT *C = LineCD + x1;
USHORT *D = LineCD + x0;
float u1 = fx - x0, v1 = fy - y0, u0 = 1.0f - u1, v0 = 1.0f - v1;
u0 *= OD65535;
u1 *= OD65535;
float u0v0 = u0 * v0, u1v0 = u1 * v0, u1v1 = u1 * v1, u0v1 = u0 * v1;
Color.b = Color.g = Color.r = *A * u0v0 + *B * u1v0 + *C * u1v1 + *D * u0v1;
}
}
else
{
Color.b = Color.g = Color.r = 1.0f;
}
}
float CTexture::GetShadowNearest(vec4 &TexCoord)
{
if(Bits != NULL && Format == TEXTURE_FORMAT_DEPTH16 && TexCoord.q > 0.0f)
{
TexCoord.q = 1.0f / TexCoord.q;
TexCoord.s *= TexCoord.q;
TexCoord.t *= TexCoord.q;
TexCoord.p *= TexCoord.q;
if(TexCoord.s >= 0.0f && TexCoord.s < 1.0f && TexCoord.t >= 0.0f && TexCoord.t < 1.0f && TexCoord.p >= 0.0f && TexCoord.p <= 1.0f)
{
TexCoord.p *= 65535.0f;
int x = (int)(TexCoord.s * Width), y = (int)(TexCoord.t * Height);
USHORT *A = (USHORT*)Bits + Width * y + x;
if(TexCoord.p > *A)
{
return 0.0f;
}
}
}
return 1.0f;
}
float CTexture::GetShadowBilinear(vec4 &TexCoord)
{
if(Bits != NULL && Format == TEXTURE_FORMAT_DEPTH16 && TexCoord.q > 0.0f)
{
TexCoord.q = 1.0f / TexCoord.q;
TexCoord.s *= TexCoord.q;
TexCoord.t *= TexCoord.q;
TexCoord.p *= TexCoord.q;
if(TexCoord.s >= 0.0f && TexCoord.s < 1.0f && TexCoord.t >= 0.0f && TexCoord.t < 1.0f && TexCoord.p >= 0.0f && TexCoord.p <= 1.0f)
{
TexCoord.p *= 65535.0f;
float fx = TexCoord.s * Width - 0.5f, fy = TexCoord.t * Height - 0.5f;
if(fx < 0.0f) fx = 0.0f;
if(fy < 0.0f) fy = 0.0f;
int x0 = (int)fx, y0 = (int)fy, x1 = x0 + 1, y1 = y0 + 1;
if(x1 == Width) x1--;
if(y1 == Height) y1--;
USHORT *LineAB = (USHORT*)Bits + Width * y0;
USHORT *LineCD = (USHORT*)Bits + Width * y1;
float A = TexCoord.p > *(LineAB + x0) ? 0.0f : 1.0f;
float B = TexCoord.p > *(LineAB + x1) ? 0.0f : 1.0f;
float C = TexCoord.p > *(LineCD + x1) ? 0.0f : 1.0f;
float D = TexCoord.p > *(LineCD + x0) ? 0.0f : 1.0f;
float u1 = fx - x0, v1 = fy - y0, u0 = 1.0f - u1, v0 = 1.0f - v1;
float u0v0 = u0 * v0, u1v0 = u1 * v0, u1v1 = u1 * v1, u0v1 = u0 * v1;
return A * u0v0 + B * u1v0 + C * u1v1 + D * u0v1;
}
}
return 1.0f;
}
void CTexture::Destroy()
{
if(Bits != NULL)
{
switch(Format)
{
case TEXTURE_FORMAT_BGR24: delete [] (BYTE*)Bits; break;
case TEXTURE_FORMAT_DEPTH16: delete [] (USHORT*)Bits; break;
}
}
SetDefaults();
}
// ----------------------------------------------------------------------------------------------------------------------------
CFrameBuffer::CFrameBuffer()
{
ColorTexture = NULL;
DepthTexture = NULL;
}
CFrameBuffer::~CFrameBuffer()
{
}
CTexture* CFrameBuffer::GetColorTexture()
{
return ColorTexture;
}
void CFrameBuffer::SetColorTexture(CTexture *ColorTexture)
{
this->ColorTexture = NULL;
if(ColorTexture != NULL && ColorTexture->GetBits() != NULL && ColorTexture->GetFormat() == TEXTURE_FORMAT_BGR24)
{
if(DepthTexture == NULL || (ColorTexture->GetWidth() == DepthTexture->GetWidth() && ColorTexture->GetHeight() == DepthTexture->GetHeight()))
{
this->ColorTexture = ColorTexture;
}
}
}
CTexture* CFrameBuffer::GetDepthTexture()
{
return DepthTexture;
}
void CFrameBuffer::SetDepthTexture(CTexture *DepthTexture)
{
this->DepthTexture = NULL;
if(DepthTexture != NULL && DepthTexture->GetBits() != NULL && DepthTexture->GetFormat() == TEXTURE_FORMAT_DEPTH16)
{
if(ColorTexture == NULL || (DepthTexture->GetWidth() == ColorTexture->GetWidth() && DepthTexture->GetHeight() == ColorTexture->GetHeight()))
{
this->DepthTexture = DepthTexture;
}
}
}
// ----------------------------------------------------------------------------------------------------------------------------
CCamera::CCamera()
{
X = vec3(1.0f, 0.0f, 0.0f);
Y = vec3(0.0f, 1.0f, 0.0f);
Z = vec3(0.0f, 0.0f, 1.0f);
Position = vec3(0.0f, 0.0f, 5.0f);
Reference = vec3(0.0f, 0.0f, 0.0f);
CalculateViewMatrix();
}
CCamera::~CCamera()
{
}
void CCamera::Look(const vec3 &Position, const vec3 &Reference, bool RotateAroundReference)
{
this->Position = Position;
this->Reference = Reference;
Z = normalize(Position - Reference);
GetXY(Z, X, Y);
if(!RotateAroundReference)
{
this->Reference = this->Position - Z * 0.05f;
}
CalculateViewMatrix();
}
void CCamera::Move(const vec3 &Movement)
{
Position += Movement;
Reference += Movement;
CalculateViewMatrix();
}
vec3 CCamera::OnKeys(BYTE Keys, float FrameTime)
{
float Speed = 5.0f;
if(Keys & 0x40) Speed *= 2.0f;
if(Keys & 0x80) Speed *= 0.5f;
float Distance = Speed * FrameTime;
vec3 Up(0.0f, 1.0f, 0.0f);
vec3 Right = X;
vec3 Forward = cross(Up, Right);
Up *= Distance;
Right *= Distance;
Forward *= Distance;
vec3 Movement = vec3(0.0f);
if(Keys & 0x01) Movement += Forward;
if(Keys & 0x02) Movement -= Forward;
if(Keys & 0x04) Movement -= Right;
if(Keys & 0x08) Movement += Right;
if(Keys & 0x10) Movement += Up;
if(Keys & 0x20) Movement -= Up;
return Movement;
}
void CCamera::OnMouseMove(int dx, int dy)
{
float Sensitivity = 0.25f;
Position -= Reference;
if(dx != 0)
{
float DeltaX = (float)dx * Sensitivity;
X = rotate(X, DeltaX, vec3(0.0f, 1.0f, 0.0f));
Y = rotate(Y, DeltaX, vec3(0.0f, 1.0f, 0.0f));
Z = rotate(Z, DeltaX, vec3(0.0f, 1.0f, 0.0f));
}
if(dy != 0)
{
float DeltaY = (float)dy * Sensitivity;
Y = rotate(Y, DeltaY, X);
Z = rotate(Z, DeltaY, X);
if(Y.y < 0.0f)
{
Z = vec3(0.0f, Z.y > 0.0f ? 1.0f : -1.0f, 0.0f);
Y = cross(Z, X);
}
}
Position = Reference + Z * length(Position);
CalculateViewMatrix();
}
void CCamera::OnMouseWheel(float zDelta)
{
Position -= Reference;
if(zDelta < 0 && length(Position) < 500.0f)
{
Position += Position * 0.1f;
}
if(zDelta > 0 && length(Position) > 0.05f)
{
Position -= Position * 0.1f;
}
Position += Reference;
CalculateViewMatrix();
}
void CCamera::SetPerspective(float fovy, float aspect, float n, float f)
{
ProjectionMatrix = perspective(fovy, aspect, n, f);
ViewProjectionMatrix = ProjectionMatrix * ViewMatrix;
}
void CCamera::CalculateViewMatrix()
{
ViewMatrix = mat4x4(X.x, Y.x, Z.x, 0.0f, X.y, Y.y, Z.y, 0.0f, X.z, Y.z, Z.z, 0.0f, -dot(X, Position), -dot(Y, Position), -dot(Z, Position), 1.0f);
ViewProjectionMatrix = ProjectionMatrix * ViewMatrix;
}
// ----------------------------------------------------------------------------------------------------------------------------
CObject::CObject()
{
SetDefaults();
}
CObject::~CObject()
{
}
void CObject::SetDefaults()
{
Vertices = NULL;
VerticesCount = 0;
}
bool CObject::Load(char *Directory, char *ObjFileName)
{
char *ObjSource;
long ObjLength;
Destroy();
if(!ReadSource(Directory, ObjFileName, &ObjSource, ObjLength)) return false;
char *Line, *End = ObjSource + ObjLength;
float x, y, z;
int PositionsCount = 0, TexCoordsCount = 0, NormalsCount = 0, TrianglesCount = 0;
int i1, i2, i3, i4, i5, i6, i7, i8, i9;
int p = 0, tc = 0, n = 0, v = 0;
Line = ObjSource;
while(Line < End)
{
while(Line < End && (*Line == ' ' || *Line == '\t')) Line++;
if(Line[0] == 'm' && Line[1] == 't' && Line[2] == 'l' && Line[3] == 'l' && Line[4] == 'i' && Line[5] == 'b' && (Line[6] == ' ' || Line[6] == '\t'))
{
char *MtlFileName = Line + 6;
while(MtlFileName < End && (*MtlFileName == ' ' || *MtlFileName == '\t')) MtlFileName++;
if(!ParseMtl(Directory, MtlFileName))
{
delete [] ObjSource;
return false;
}
}
else if(sscanf(Line, "v %f %f %f", &x, &y, &z) == 3)
{
PositionsCount++;
}
else if(sscanf(Line, "vt %f %f", &x, &y) == 2)
{
TexCoordsCount++;
}
else if(sscanf(Line, "vn %f %f %f", &x, &y, &z) == 3)
{
NormalsCount++;
}
else if(sscanf(Line, "f %d/%d/%d %d/%d/%d %d/%d/%d", &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9) == 9)
{
TrianglesCount++;
}
else if(sscanf(Line, "f %d//%d %d//%d %d//%d", &i1, &i2, &i3, &i4, &i5, &i6) == 6)
{
TrianglesCount++;
}
else if(sscanf(Line, "f %d/%d %d/%d %d/%d", &i1, &i2, &i3, &i4, &i5, &i6) == 6)
{
TrianglesCount++;
}
else if(sscanf(Line, "f %d %d %d", &i1, &i2, &i3) == 3)
{
TrianglesCount++;
}
while(Line < End && *Line != 0) Line++;
while(Line < End && *Line == 0) Line++;
}
if(TrianglesCount == 0)
{
ErrorLog.Append("Error loading file %s!\r\n", ObjFileName);
delete [] ObjSource;
Destroy();
return false;
}
vec3 *Positions = NULL;
vec2 *TexCoords = NULL;
vec3 *Normals = NULL;
if(PositionsCount > 0) Positions = new vec3[PositionsCount];
if(TexCoordsCount > 0) TexCoords = new vec2[TexCoordsCount];
if(NormalsCount > 0) Normals = new vec3[NormalsCount];
VerticesCount = TrianglesCount * 3;
Vertices = new CVertex[VerticesCount];
Line = ObjSource;
while(Line < End)
{
while(Line < End && (*Line == ' ' || *Line == '\t')) Line++;
if(sscanf(Line, "v %f %f %f", &x, &y, &z) == 3)
{
Positions[p++] = vec3(x, y, z);
}
else if(sscanf(Line, "vt %f %f", &x, &y) == 2)
{
TexCoords[tc++] = vec2(x, y);
}
else if(sscanf(Line, "vn %f %f %f", &x, &y, &z) == 3)
{
Normals[n++] = normalize(vec3(x, y, z));
}
else if(sscanf(Line, "f %d/%d/%d %d/%d/%d %d/%d/%d", &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9) == 9)
{
Vertices[v].Position = Positions[i1 - 1];
Vertices[v].TexCoord = TexCoords[i2 - 1];
Vertices[v].Normal = Normals[i3 - 1];
v++;
Vertices[v].Position = Positions[i4 - 1];
Vertices[v].TexCoord = TexCoords[i5 - 1];
Vertices[v].Normal = Normals[i6 - 1];
v++;
Vertices[v].Position = Positions[i7 - 1];
Vertices[v].TexCoord = TexCoords[i8 - 1];
Vertices[v].Normal = Normals[i9 - 1];
v++;
}
else if(sscanf(Line, "f %d//%d %d//%d %d//%d", &i1, &i2, &i3, &i4, &i5, &i6) == 6)
{
Vertices[v].Position = Positions[i1 - 1];
Vertices[v].Normal = Normals[i2 - 1];
v++;
Vertices[v].Position = Positions[i3 - 1];
Vertices[v].Normal = Normals[i4 - 1];
v++;
Vertices[v].Position = Positions[i5 - 1];
Vertices[v].Normal = Normals[i6 - 1];
v++;
}
else if(sscanf(Line, "f %d/%d %d/%d %d/%d", &i1, &i2, &i3, &i4, &i5, &i6) == 6)
{
Vertices[v].Position = Positions[i1 - 1];
if(TexCoords != NULL && i1 - 1 < TexCoordsCount) Vertices[v].TexCoord = TexCoords[i1 - 1];
if(TexCoords != NULL && i2 - 1 < TexCoordsCount) Vertices[v].TexCoord = TexCoords[i2 - 1];
if(Normals != NULL && i1 - 1 < NormalsCount) Vertices[v].Normal = Normals[i1 - 1];
if(Normals != NULL && i2 - 1 < NormalsCount) Vertices[v].Normal = Normals[i2 - 1];
v++;
Vertices[v].Position = Positions[i3 - 1];
if(TexCoords != NULL && i3 - 1 < TexCoordsCount) Vertices[v].TexCoord = TexCoords[i3 - 1];
if(TexCoords != NULL && i4 - 1 < TexCoordsCount) Vertices[v].TexCoord = TexCoords[i4 - 1];
if(Normals != NULL && i3 - 1 < NormalsCount) Vertices[v].Normal = Normals[i3 - 1];
if(Normals != NULL && i4 - 1 < NormalsCount) Vertices[v].Normal = Normals[i4 - 1];
v++;
Vertices[v].Position = Positions[i5 - 1];
if(TexCoords != NULL && i5 - 1 < TexCoordsCount) Vertices[v].TexCoord = TexCoords[i5 - 1];
if(TexCoords != NULL && i6 - 1 < TexCoordsCount) Vertices[v].TexCoord = TexCoords[i6 - 1];
if(Normals != NULL && i5 - 1 < NormalsCount) Vertices[v].Normal = Normals[i5 - 1];
if(Normals != NULL && i6 - 1 < NormalsCount) Vertices[v].Normal = Normals[i6 - 1];
v++;
}
else if(sscanf(Line, "f %d %d %d", &i1, &i2, &i3) == 3)
{
Vertices[v].Position = Positions[i1 - 1];
if(TexCoords != NULL && i1 - 1 < TexCoordsCount) Vertices[v].TexCoord = TexCoords[i1 - 1];
if(Normals != NULL && i1 - 1 < NormalsCount) Vertices[v].Normal = Normals[i1 - 1];
v++;
Vertices[v].Position = Positions[i2 - 1];
if(TexCoords != NULL && i2 - 1 < TexCoordsCount) Vertices[v].TexCoord = TexCoords[i2 - 1];
if(Normals != NULL && i2 - 1 < NormalsCount) Vertices[v].Normal = Normals[i2 - 1];
v++;
Vertices[v].Position = Positions[i3 - 1];
if(TexCoords != NULL && i3 - 1 < TexCoordsCount) Vertices[v].TexCoord = TexCoords[i3 - 1];
if(Normals != NULL && i3 - 1 < NormalsCount) Vertices[v].Normal = Normals[i3 - 1];
v++;
}
while(Line < End && *Line != 0) Line++;
while(Line < End && *Line == 0) Line++;
}
delete [] Positions;
delete [] TexCoords;
delete [] Normals;
delete [] ObjSource;
for(int i = 0; i < VerticesCount; i++)
{
Vertices[i].Color = vec3(1.0f);
}
if(NormalsCount == 0)
{
vec3 A, B, Normal;
for(int i = 0; i < VerticesCount; i += 3)
{
int i0 = i, i1 = i + 1, i2 = i + 2;
A = Vertices[i1].Position - Vertices[i0].Position;
B = Vertices[i2].Position - Vertices[i0].Position;
Normal = normalize(cross(A, B));
Vertices[i0].Normal = Normal;
Vertices[i1].Normal = Normal;
Vertices[i2].Normal = Normal;
}
}
GetMinMax();
return true;
}
void CObject::Translate(const vec3 &Translation)
{
for(int i = 0; i < VerticesCount; i++)
{
Vertices[i].Position += Translation;
}
Min += Translation;
Max += Translation;
}
void CObject::Scale(float ScaleFactor)
{
for(int i = 0; i < VerticesCount; i++)
{
Vertices[i].Position *= ScaleFactor;
}
Min *= ScaleFactor;
Max *= ScaleFactor;
}
void CObject::Rotate(float Angle, const vec3 &Axis)
{
mat3x3 RotationMatrix = mat3x3(rotate(Angle, Axis));
for(int i = 0; i < VerticesCount; i++)
{
Vertices[i].Position = RotationMatrix * Vertices[i].Position;
Vertices[i].Normal = RotationMatrix * Vertices[i].Normal;
}
GetMinMax();
}
void CObject::Destroy()
{
Texture.Destroy();
if(Vertices != NULL)
{
delete [] Vertices;
}
SetDefaults();
}
bool CObject::ReadSource(char *Directory, char *FileName, char **Source, long &Length)
{
CString PathFileName = ModuleDirectory + Directory + FileName;
FILE *File;
if((File = fopen(PathFileName, "rb")) == NULL)
{
ErrorLog.Append("Error opening file " + PathFileName + "!\r\n");
return false;
}
fseek(File, 0, SEEK_END);
Length = ftell(File);
fseek(File, 0, SEEK_SET);
*Source = new char[Length + 1];
fread(*Source, 1, Length, File);
(*Source)[Length] = 0;
fclose(File);
for(long i = 0; i < Length; i++)
{
if((*Source)[i] == '\r' || (*Source)[i] == '\n') (*Source)[i] = 0;
}
return true;
}
bool CObject::ParseMtl(char *Directory, char *MtlFileName)
{
char *MtlSource;
long MtlLength;
if(!ReadSource(Directory, MtlFileName, &MtlSource, MtlLength)) return false;
char *Line = MtlSource, *End = MtlSource + MtlLength;
bool Error = false;
while(Line < End)
{
while(Line < End && (*Line == ' ' || *Line == '\t')) Line++;
if(Line[0] == 'm' && Line[1] == 'a' && Line[2] == 'p' && Line[3] == '_' && Line[4] == 'K' && Line[5] == 'a' && (Line[6] == ' ' || Line[6] == '\t'))
{
char *TextureFileName = Line + 6;
while(TextureFileName < End && (*TextureFileName == ' ' || *TextureFileName == '\t')) TextureFileName++;
Error |= !Texture.LoadTexture(CString(Directory) + TextureFileName);
}
while(Line < End && *Line != 0) Line++;
while(Line < End && *Line == 0) Line++;
}
delete [] MtlSource;
return !Error;
}
void CObject::GetMinMax()
{
Min = Max = Vertices[0].Position;
for(int i = 1; i < VerticesCount; i++)
{
if(Min.x > Vertices[i].Position.x) Min.x = Vertices[i].Position.x;
if(Min.y > Vertices[i].Position.y) Min.y = Vertices[i].Position.y;
if(Min.z > Vertices[i].Position.z) Min.z = Vertices[i].Position.z;
if(Max.x < Vertices[i].Position.x) Max.x = Vertices[i].Position.x;
if(Max.y < Vertices[i].Position.y) Max.y = Vertices[i].Position.y;
if(Max.z < Vertices[i].Position.z) Max.z = Vertices[i].Position.z;
}
}
// ----------------------------------------------------------------------------------------------------------------------------
void CEdge::Set(CFragment *Fragment1, CFragment *Fragment2)
{
if(Fragment1->Position.y <= Fragment2->Position.y)
{
this->Fragment1 = Fragment1;
this->Fragment2 = Fragment2;
}
else
{
this->Fragment1 = Fragment2;
this->Fragment2 = Fragment1;
}
}
// ----------------------------------------------------------------------------------------------------------------------------
void CSpan::Set(CFragment *Fragment1, CFragment *Fragment2)
{
if(Fragment1->Position.x <= Fragment2->Position.x)
{
this->Fragment1 = Fragment1;
this->Fragment2 = Fragment2;
}
else
{
this->Fragment1 = Fragment2;
this->Fragment2 = Fragment1;
}
}
// ----------------------------------------------------------------------------------------------------------------------------
CSoftwareGL::CSoftwareGL()
{
Width = 0;
Height = 0;
ViewportX = 0;
ViewportY = 0;
ViewportWidth = 0;
ViewportHeight = 0;
AntiAliasingColorBuffer = NULL;
AntiAliasingColorBufferWidth = 0;
AntiAliasingColorBufferHeight = 0;
StandardColorBuffer = NULL;
StandardColorBufferWidth = 0;
StandardColorBufferHeight = 0;
StandardDepthBuffer = NULL;
StandardDepthBufferWidth = 0;
StandardDepthBufferHeight = 0;
ColorBuffer = NULL;
ColorBufferWidth = 0;
ColorBufferHeight = 0;
DepthBuffer = NULL;
DepthBufferWidth = 0;
DepthBufferHeight = 0;
FrameBuffer = NULL;
AntiAliasing = ANTI_ALIASING_2X2;
ModelViewProjectionMatrix = mat4x4(1.0f);
ShadowMapMatrix = mat4x4(1.0f);
Light = NULL;
CullFace = CULL_FACE_BACK;
BilinearTextureFiltering = true;
DepthTest = true;
Texture = NULL;
ShadowMap = NULL;
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
ThreadsCount = SystemInfo.dwNumberOfProcessors;
if(ThreadsCount > 1)
{
ThreadsData = new CThreadData[ThreadsCount];
for(int i = 0; i < ThreadsCount; i++)
{
ThreadsData[i].SoftwareGL = this;
ThreadsData[i].ThreadId = i;
ThreadsData[i].ThreadIsRunning = false;
ThreadsData[i].Thread = CreateThread(NULL, 0, ThreadProc, &ThreadsData[i], 0, &ThreadsData[i].Id);
SetThreadAffinityMask(ThreadsData[i].Thread, 1 << i);
}
if(THREAD_SLEEP_TIME > 0)
{
timeBeginPeriod(THREAD_SLEEP_TIME);
}
}
}
CSoftwareGL::~CSoftwareGL()
{
if(AntiAliasingColorBuffer != NULL)
{
delete [] AntiAliasingColorBuffer;
}
if(StandardColorBuffer != NULL)
{
delete [] StandardColorBuffer;
}
if(StandardDepthBuffer != NULL)
{
delete [] StandardDepthBuffer;
}
if(ThreadsCount > 1)
{
for(int i = 0; i < ThreadsCount; i++)
{
TerminateThread(ThreadsData[i].Thread, 0);
CloseHandle(ThreadsData[i].Thread);
}
delete [] ThreadsData;
if(THREAD_SLEEP_TIME > 0)
{
timeEndPeriod(THREAD_SLEEP_TIME);
}
}
}
int CSoftwareGL::GetAntiAliasing()
{
return AntiAliasing;
}
void CSoftwareGL::SetAntiAliasing(int AntiAliasing)
{
if(AntiAliasing == NONE || AntiAliasing == ANTI_ALIASING_2X2 || AntiAliasing == ANTI_ALIASING_3X3 || AntiAliasing == ANTI_ALIASING_4X4)
{
if(this->AntiAliasing != AntiAliasing)
{
this->AntiAliasing = AntiAliasing;
ResizeBuffers(Width, Height);
}
}
}
int CSoftwareGL::GetCullFace()
{
return CullFace;
}
void CSoftwareGL::SetCullFace(int CullFace)
{
if(CullFace == NONE || CullFace == CULL_FACE_FRONT || CullFace == CULL_FACE_BACK)
{
this->CullFace = CullFace;
}
}
bool CSoftwareGL::GetBilinearTextureFiltering()
{
return BilinearTextureFiltering;
}
void CSoftwareGL::SetBilinearTextureFiltering(bool BilinearTextureFiltering)
{
this->BilinearTextureFiltering = BilinearTextureFiltering;
}
bool CSoftwareGL::GetDepthTest()
{
return DepthTest;
}
void CSoftwareGL::SetDepthTest(bool DepthTest)
{
this->DepthTest = DepthTest;
}
int CSoftwareGL::GetThreadsCount()
{
return ThreadsCount;
}
void CSoftwareGL::BindFrameBuffer(CFrameBuffer *FrameBuffer)
{
if(FrameBuffer != NULL)
{
if(FrameBuffer->GetColorTexture() != NULL)
{
ColorBuffer = (BYTE*)FrameBuffer->GetColorTexture()->GetBits();
ColorBufferWidth = FrameBuffer->GetColorTexture()->GetWidth();
ColorBufferHeight = FrameBuffer->GetColorTexture()->GetHeight();
BufferWidthM1 = ColorBufferWidth - 1;
BufferHeightM1 = ColorBufferHeight - 1;
}
else
{
ColorBuffer = NULL;
ColorBufferWidth = 0;
ColorBufferHeight = 0;
}
if(FrameBuffer->GetDepthTexture() != NULL)
{
DepthBuffer = (USHORT*)FrameBuffer->GetDepthTexture()->GetBits();
DepthBufferWidth = FrameBuffer->GetDepthTexture()->GetWidth();
DepthBufferHeight = FrameBuffer->GetDepthTexture()->GetHeight();
BufferWidthM1 = DepthBufferWidth - 1;
BufferHeightM1 = DepthBufferHeight - 1;
}
else
{
DepthBuffer = NULL;
DepthBufferWidth = 0;
DepthBufferHeight = 0;
}
if(FrameBuffer->GetColorTexture() == NULL && FrameBuffer->GetDepthTexture() == NULL)
{
BufferWidthM1 = 0;
BufferHeightM1 = 0;
}
this->FrameBuffer = FrameBuffer;
}
else
{
if(AntiAliasing)
{
ColorBuffer = AntiAliasingColorBuffer;
ColorBufferWidth = AntiAliasingColorBufferWidth;
ColorBufferHeight = AntiAliasingColorBufferHeight;
}
else
{
ColorBuffer = StandardColorBuffer;
ColorBufferWidth = StandardColorBufferWidth;
ColorBufferHeight = StandardColorBufferHeight;
}
DepthBuffer = StandardDepthBuffer;
DepthBufferWidth = StandardDepthBufferWidth;
DepthBufferHeight = StandardDepthBufferHeight;
BufferWidthM1 = DepthBufferWidth - 1;
BufferHeightM1 = DepthBufferHeight - 1;
}
this->FrameBuffer = FrameBuffer;
}
void CSoftwareGL::Viewport(int X, int Y, int Width, int Height)
{
ViewportX = X;
ViewportY = Y;
ViewportWidth = Width;
ViewportHeight = Height;
}
void CSoftwareGL::Clear(bool ClearColorBuffer, bool ClearDepthBuffer)
{
if(ClearColorBuffer && ColorBuffer != NULL)
{
memset(ColorBuffer, 0, ColorBufferWidth * ColorBufferHeight * 3);
}
if(ClearDepthBuffer && DepthBuffer != NULL)
{
memset(DepthBuffer, 255, DepthBufferWidth * DepthBufferHeight * 2);
}
}
void CSoftwareGL::LoadModelViewProjectionMatrix(const mat4x4 &ModelViewProjectionMatrix)
{
this->ModelViewProjectionMatrix = ModelViewProjectionMatrix;
}
void CSoftwareGL::LoadShadowMapMatrix(const mat4x4 &ShadowMapMatrix)
{
this->ShadowMapMatrix = ShadowMapMatrix;
}
void CSoftwareGL::BindLight(CLight *Light)
{
this->Light = Light;
}
void CSoftwareGL::BindTexture(CTexture *Texture)
{
this->Texture = Texture;
}
void CSoftwareGL::BindShadowMap(CTexture *ShadowMap)
{
this->ShadowMap = ShadowMap;
}
void CSoftwareGL::DrawTriangles(CVertex *Vertices, int FirstIndex, int Count)
{
if((ColorBuffer == NULL && DepthBuffer == NULL) || ViewportWidth <= 0 || ViewportHeight <= 0 || Vertices == NULL || FirstIndex < 0 || Count < 3) return;
ColorBuffering = ColorBuffer != NULL;
DepthTesting = DepthBuffer != NULL && DepthTest;
NotDepthTesting = !DepthTesting;
Texturing = Texture != NULL;
Lighting = Light != NULL;
ShadowMapping = ShadowMap != NULL;
this->Vertices = Vertices;
this->FirstIndex = FirstIndex;
this->LastIndex = FirstIndex + Count / 3 * 3;
int Factor = 1;
if(FrameBuffer == NULL && AntiAliasing)
{
switch(AntiAliasing)
{
case ANTI_ALIASING_2X2: Factor = 2; break;
case ANTI_ALIASING_3X3: Factor = 3; break;
case ANTI_ALIASING_4X4: Factor = 4; break;
}
}
if(Factor > 1)
{
ViewportX *= Factor;
ViewportY *= Factor;
ViewportWidth *= Factor;
ViewportHeight *= Factor;
}
RunFunctionMultiThreadedAndWaitForCompletion(1);
if(Factor > 1)
{
ViewportX /= Factor;
ViewportY /= Factor;
ViewportWidth /= Factor;
ViewportHeight /= Factor;
}
}
void CSoftwareGL::RunFunctionMultiThreadedAndWaitForCompletion(int Function)
{
if(ThreadsCount > 1)
{
for(int i = 0; i < ThreadsCount; i++)
{
ThreadsData[i].Function = Function;
ThreadsData[i].ThreadIsRunning = true;
}
while(ThreadsAreRunning())
{
if(Width > 0 && Height > 0)
{
Sleep(THREAD_SLEEP_TIME);
}
else
{
Sleep(250);
}
}
}
else
{
switch(Function)
{
case 1: DrawTriangles(0); break;
case 2: BlitAntiAliasingColorBuffer2x2(0); break;
case 3: BlitAntiAliasingColorBuffer3x3(0); break;
case 4: BlitAntiAliasingColorBuffer4x4(0); break;
}
}
}
bool CSoftwareGL::ThreadsAreRunning()
{
bool ThreadsAreRunning = false;
for(int i = 0; i < ThreadsCount; i++)
{
ThreadsAreRunning |= ThreadsData[i].ThreadIsRunning;
}
return ThreadsAreRunning;
}
DWORD WINAPI CSoftwareGL::ThreadProc(LPVOID lpParam)
{
CThreadData *ThreadData = (CThreadData*)lpParam;
CSoftwareGL *SoftwareGL = (CSoftwareGL*)ThreadData->SoftwareGL;
while(1)
{
while(!ThreadData->ThreadIsRunning)
{
if(SoftwareGL->Width > 0 && SoftwareGL->Height > 0)
{
Sleep(THREAD_SLEEP_TIME);
}
else
{
Sleep(250);
}
}
switch(ThreadData->Function)
{
case 1: SoftwareGL->DrawTriangles(ThreadData->ThreadId); break;
case 2: SoftwareGL->BlitAntiAliasingColorBuffer2x2(ThreadData->ThreadId); break;
case 3: SoftwareGL->BlitAntiAliasingColorBuffer3x3(ThreadData->ThreadId); break;
case 4: SoftwareGL->BlitAntiAliasingColorBuffer4x4(ThreadData->ThreadId); break;
}
ThreadData->ThreadIsRunning = false;
}
return 0;
}
void CSoftwareGL::DrawTriangles(int ThreadId)
{
float *ModelViewProjectionMatrix = &this->ModelViewProjectionMatrix;
float *ShadowMapMatrix = &this->ShadowMapMatrix;
// primitive assembly
CFragment Fragments[3];
for(int i = FirstIndex; i < LastIndex; i += 3)
{
CVertex *Vertex = Vertices + i;
CFragment *Fragment = Fragments;
for(int j = 0; j < 3; j++)
{
// vertex shader
Fragment->Position.x = ModelViewProjectionMatrix[0] * Vertex->Position.x + ModelViewProjectionMatrix[4] * Vertex->Position.y + ModelViewProjectionMatrix[8] * Vertex->Position.z + ModelViewProjectionMatrix[12];
Fragment->Position.y = ModelViewProjectionMatrix[1] * Vertex->Position.x + ModelViewProjectionMatrix[5] * Vertex->Position.y + ModelViewProjectionMatrix[9] * Vertex->Position.z + ModelViewProjectionMatrix[13];
Fragment->Position.z = ModelViewProjectionMatrix[2] * Vertex->Position.x + ModelViewProjectionMatrix[6] * Vertex->Position.y + ModelViewProjectionMatrix[10] * Vertex->Position.z + ModelViewProjectionMatrix[14];
Fragment->Position.w = ModelViewProjectionMatrix[3] * Vertex->Position.x + ModelViewProjectionMatrix[7] * Vertex->Position.y + ModelViewProjectionMatrix[11] * Vertex->Position.z + ModelViewProjectionMatrix[15];
if(ColorBuffering)
{
Fragment->Color.r = Vertex->Color.r;
Fragment->Color.g = Vertex->Color.g;
Fragment->Color.b = Vertex->Color.b;
if(Texturing)
{
Fragment->TexCoord.s = Vertex->TexCoord.s;
Fragment->TexCoord.t = Vertex->TexCoord.t;
}
if(Lighting)
{
Fragment->Normal.x = Vertex->Normal.x;
Fragment->Normal.y = Vertex->Normal.y;
Fragment->Normal.z = Vertex->Normal.z;
Fragment->LightDirection.x = Light->Position.x - Vertex->Position.x;
Fragment->LightDirection.y = Light->Position.y - Vertex->Position.y;
Fragment->LightDirection.z = Light->Position.z - Vertex->Position.z;
if(ShadowMapping)
{
Fragment->ShadowMapTexCoord.s = ShadowMapMatrix[0] * Vertex->Position.x + ShadowMapMatrix[4] * Vertex->Position.y + ShadowMapMatrix[8] * Vertex->Position.z + ShadowMapMatrix[12];
Fragment->ShadowMapTexCoord.t = ShadowMapMatrix[1] * Vertex->Position.x + ShadowMapMatrix[5] * Vertex->Position.y + ShadowMapMatrix[9] * Vertex->Position.z + ShadowMapMatrix[13];
Fragment->ShadowMapTexCoord.p = ShadowMapMatrix[2] * Vertex->Position.x + ShadowMapMatrix[6] * Vertex->Position.y + ShadowMapMatrix[10] * Vertex->Position.z + ShadowMapMatrix[14];
Fragment->ShadowMapTexCoord.q = ShadowMapMatrix[3] * Vertex->Position.x + ShadowMapMatrix[7] * Vertex->Position.y + ShadowMapMatrix[11] * Vertex->Position.z + ShadowMapMatrix[15];
}
}
}
Vertex++;
Fragment++;
}
// clipping
ClipTriangle(Fragments, ThreadId);
}
}
// ----------------------------------------------------------------------------------------------------------------------------
//
// clipping using homogeneous coordinates
//
// ----------------------------------------------------------------------------------------------------------------------------
//
// c equals the x or y or z coordinate of a fragment
//
// ----------------------------------------------------------------------------------------------------------------------------
//
// a fragment of an edge is in front of or lies on a negative clip plane: - w <= c
//
// a fragment of an edge is behind a negative clip plane: - w > c
//
// to find the intersection of an edge with a negative clip plane we need to find t for which: - w = c
//
// ----------------------------------------------------------------------------------------------------------------------------
//
// w = w1 + (w2 - w1) * t
// c = c1 + (c2 - c1) * t
//
// - w = c
//
// - (w1 + (w2 - w1) * t) = c1 + (c2 - c1) * t
// - w1 - (w2 - w1) * t = c1 + (c2 - c1) * t
// - (w2 - w1) * t = c1 + w1 + (c2 - c1) * t
// - (c2 - c1) * t - (w2 - w1) * t = c1 + w1
// (c2 - c1) * t + (w2 - w1) * t = - c1 - w1
// (c2 - c1 + w2 - w1) * t = - c1 - w1
// t = (- c1 - w1) / (c2 - c1 + w2 - w1)
// t = (c1 + w1) / (- c2 + c1 - w2 + w1)
// t = (c1 + w1) / (c1 - c2 + w1 - w2)
//
// ----------------------------------------------------------------------------------------------------------------------------
//
// a fragment of an edge is in front of or lies on a positive clip plane: c <= w
//
// a fragment of an edge is behind a positive clip plane: c > w
//
// to find the intersection of an edge with a positive clip plane we need to find t for which: c = w
//
// ----------------------------------------------------------------------------------------------------------------------------
//
// c = c1 + (c2 - c1) * t
// w = w1 + (w2 - w1) * t
//
// c = w
//
// c1 + (c2 - c1) * t = w1 + (w2 - w1) * t
// (c2 - c1) * t = w1 - c1 + (w2 - w1) * t
// (c2 - c1) * t - (w2 - w1) * t = w1 - c1
// ((c2 - c1) - (w2 - w1)) * t = w1 - c1
// (c2 - c1 - w2 + w1) * t = w1 - c1
// t = (w1 - c1) / (c2 - c1 - w2 + w1)
// t = (- w1 + c1) / (- c2 + c1 + w2 - w1)
// t = (c1 - w1) / (c1 - c2 - w1 + w2)
//
// ----------------------------------------------------------------------------------------------------------------------------
void CSoftwareGL::ClipTriangle(CFragment *Fragments, int ThreadId, int ClipPlane)
{
if(ClipPlane >= 1 && ClipPlane <= 6)
{
int fifocp, fbcp, fbcpc = 0; // fragment in front of clip plane, fragment behind clip plane, fragments behind clip plane count
// visibility testing
CFragment *Fragment = Fragments;
for(int i = 0; i < 3; i++)
{
bool Visible;
switch(ClipPlane)
{
case 1: Visible = -Fragment->Position.w <= Fragment->Position.x; break;
case 2: Visible = Fragment->Position.x <= Fragment->Position.w; break;
case 3: Visible = -Fragment->Position.w <= Fragment->Position.y; break;
case 4: Visible = Fragment->Position.y <= Fragment->Position.w; break;
case 5: Visible = -Fragment->Position.w <= Fragment->Position.z; break;
case 6: Visible = Fragment->Position.z <= Fragment->Position.w; break;
}
if(Visible)
{
fifocp = i;
}
else
{
fbcp = i;
fbcpc++;
}
Fragment++;
}
// clipping
if(fbcpc == 3)
{
return;
}
else if(fbcpc == 2)
{
CFragment *Fragment1 = Fragments + (fifocp + 1) % 3;
CFragment *Fragment2 = Fragments + (fifocp + 2) % 3;
CFragment *Fragment3 = Fragments + fifocp;
float t1, t2;
switch(ClipPlane)
{
case 1:
t1 = (Fragment1->Position.x + Fragment1->Position.w) / (Fragment1->Position.x - Fragment3->Position.x + Fragment1->Position.w - Fragment3->Position.w);
t2 = (Fragment2->Position.x + Fragment2->Position.w) / (Fragment2->Position.x - Fragment3->Position.x + Fragment2->Position.w - Fragment3->Position.w);
break;
case 2:
t1 = (Fragment1->Position.x - Fragment1->Position.w) / (Fragment1->Position.x - Fragment3->Position.x - Fragment1->Position.w + Fragment3->Position.w);
t2 = (Fragment2->Position.x - Fragment2->Position.w) / (Fragment2->Position.x - Fragment3->Position.x - Fragment2->Position.w + Fragment3->Position.w);
break;
case 3:
t1 = (Fragment1->Position.y + Fragment1->Position.w) / (Fragment1->Position.y - Fragment3->Position.y + Fragment1->Position.w - Fragment3->Position.w);
t2 = (Fragment2->Position.y + Fragment2->Position.w) / (Fragment2->Position.y - Fragment3->Position.y + Fragment2->Position.w - Fragment3->Position.w);
break;
case 4:
t1 = (Fragment1->Position.y - Fragment1->Position.w) / (Fragment1->Position.y - Fragment3->Position.y - Fragment1->Position.w + Fragment3->Position.w);
t2 = (Fragment2->Position.y - Fragment2->Position.w) / (Fragment2->Position.y - Fragment3->Position.y - Fragment2->Position.w + Fragment3->Position.w);
break;
case 5:
t1 = (Fragment1->Position.z + Fragment1->Position.w) / (Fragment1->Position.z - Fragment3->Position.z + Fragment1->Position.w - Fragment3->Position.w);
t2 = (Fragment2->Position.z + Fragment2->Position.w) / (Fragment2->Position.z - Fragment3->Position.z + Fragment2->Position.w - Fragment3->Position.w);
break;
case 6:
t1 = (Fragment1->Position.z - Fragment1->Position.w) / (Fragment1->Position.z - Fragment3->Position.z - Fragment1->Position.w + Fragment3->Position.w);
t2 = (Fragment2->Position.z - Fragment2->Position.w) / (Fragment2->Position.z - Fragment3->Position.z - Fragment2->Position.w + Fragment3->Position.w);
break;
}
Fragment1->Position.x += (Fragment3->Position.x - Fragment1->Position.x) * t1;
Fragment1->Position.y += (Fragment3->Position.y - Fragment1->Position.y) * t1;
Fragment1->Position.z += (Fragment3->Position.z - Fragment1->Position.z) * t1;
Fragment1->Position.w += (Fragment3->Position.w - Fragment1->Position.w) * t1;
Fragment2->Position.x += (Fragment3->Position.x - Fragment2->Position.x) * t2;
Fragment2->Position.y += (Fragment3->Position.y - Fragment2->Position.y) * t2;
Fragment2->Position.z += (Fragment3->Position.z - Fragment2->Position.z) * t2;
Fragment2->Position.w += (Fragment3->Position.w - Fragment2->Position.w) * t2;
if(ColorBuffering)
{
Fragment1->Color.r += (Fragment3->Color.r - Fragment1->Color.r) * t1;
Fragment1->Color.g += (Fragment3->Color.g - Fragment1->Color.g) * t1;
Fragment1->Color.b += (Fragment3->Color.b - Fragment1->Color.b) * t1;
Fragment2->Color.r += (Fragment3->Color.r - Fragment2->Color.r) * t2;
Fragment2->Color.g += (Fragment3->Color.g - Fragment2->Color.g) * t2;
Fragment2->Color.b += (Fragment3->Color.b - Fragment2->Color.b) * t2;
if(Texturing)
{
Fragment1->TexCoord.s += (Fragment3->TexCoord.s - Fragment1->TexCoord.s) * t1;
Fragment1->TexCoord.t += (Fragment3->TexCoord.t - Fragment1->TexCoord.t) * t1;
Fragment2->TexCoord.s += (Fragment3->TexCoord.s - Fragment2->TexCoord.s) * t2;
Fragment2->TexCoord.t += (Fragment3->TexCoord.t - Fragment2->TexCoord.t) * t2;
}
if(Lighting)
{
Fragment1->Normal.x += (Fragment3->Normal.x - Fragment1->Normal.x) * t1;
Fragment1->Normal.y += (Fragment3->Normal.y - Fragment1->Normal.y) * t1;
Fragment1->Normal.z += (Fragment3->Normal.z - Fragment1->Normal.z) * t1;
Fragment2->Normal.x += (Fragment3->Normal.x - Fragment2->Normal.x) * t2;
Fragment2->Normal.y += (Fragment3->Normal.y - Fragment2->Normal.y) * t2;
Fragment2->Normal.z += (Fragment3->Normal.z - Fragment2->Normal.z) * t2;
Fragment1->LightDirection.x += (Fragment3->LightDirection.x - Fragment1->LightDirection.x) * t1;
Fragment1->LightDirection.y += (Fragment3->LightDirection.y - Fragment1->LightDirection.y) * t1;
Fragment1->LightDirection.z += (Fragment3->LightDirection.z - Fragment1->LightDirection.z) * t1;
Fragment2->LightDirection.x += (Fragment3->LightDirection.x - Fragment2->LightDirection.x) * t2;
Fragment2->LightDirection.y += (Fragment3->LightDirection.y - Fragment2->LightDirection.y) * t2;
Fragment2->LightDirection.z += (Fragment3->LightDirection.z - Fragment2->LightDirection.z) * t2;
if(ShadowMapping)
{
Fragment1->ShadowMapTexCoord.s += (Fragment3->ShadowMapTexCoord.s - Fragment1->ShadowMapTexCoord.s) * t1;
Fragment1->ShadowMapTexCoord.t += (Fragment3->ShadowMapTexCoord.t - Fragment1->ShadowMapTexCoord.t) * t1;
Fragment1->ShadowMapTexCoord.p += (Fragment3->ShadowMapTexCoord.p - Fragment1->ShadowMapTexCoord.p) * t1;
Fragment1->ShadowMapTexCoord.q += (Fragment3->ShadowMapTexCoord.q - Fragment1->ShadowMapTexCoord.q) * t1;
Fragment2->ShadowMapTexCoord.s += (Fragment3->ShadowMapTexCoord.s - Fragment2->ShadowMapTexCoord.s) * t2;
Fragment2->ShadowMapTexCoord.t += (Fragment3->ShadowMapTexCoord.t - Fragment2->ShadowMapTexCoord.t) * t2;
Fragment2->ShadowMapTexCoord.p += (Fragment3->ShadowMapTexCoord.p - Fragment2->ShadowMapTexCoord.p) * t2;
Fragment2->ShadowMapTexCoord.q += (Fragment3->ShadowMapTexCoord.q - Fragment2->ShadowMapTexCoord.q) * t2;
}
}
}
ClipTriangle(Fragments, ThreadId, ClipPlane + 1);
}
else if(fbcpc == 1)
{
int if1 = (fbcp + 1) % 3, if2 = (fbcp + 2) % 3;
CFragment *Fragment1 = Fragments + if1;
CFragment *Fragment2 = Fragments + if2;
CFragment *Fragment3 = Fragments + fbcp;
CFragment NewFragments[3];
CFragment *NewFragment1 = NewFragments + if1;
CFragment *NewFragment2 = NewFragments + if2;
CFragment *NewFragment3 = NewFragments + fbcp;
float t1, t2;
switch(ClipPlane)
{
case 1:
t1 = (Fragment3->Position.x + Fragment3->Position.w) / (Fragment3->Position.x - Fragment1->Position.x + Fragment3->Position.w - Fragment1->Position.w);
t2 = (Fragment3->Position.x + Fragment3->Position.w) / (Fragment3->Position.x - Fragment2->Position.x + Fragment3->Position.w - Fragment2->Position.w);
break;
case 2:
t1 = (Fragment3->Position.x - Fragment3->Position.w) / (Fragment3->Position.x - Fragment1->Position.x - Fragment3->Position.w + Fragment1->Position.w);
t2 = (Fragment3->Position.x - Fragment3->Position.w) / (Fragment3->Position.x - Fragment2->Position.x - Fragment3->Position.w + Fragment2->Position.w);
break;
case 3:
t1 = (Fragment3->Position.y + Fragment3->Position.w) / (Fragment3->Position.y - Fragment1->Position.y + Fragment3->Position.w - Fragment1->Position.w);
t2 = (Fragment3->Position.y + Fragment3->Position.w) / (Fragment3->Position.y - Fragment2->Position.y + Fragment3->Position.w - Fragment2->Position.w);
break;
case 4:
t1 = (Fragment3->Position.y - Fragment3->Position.w) / (Fragment3->Position.y - Fragment1->Position.y - Fragment3->Position.w + Fragment1->Position.w);
t2 = (Fragment3->Position.y - Fragment3->Position.w) / (Fragment3->Position.y - Fragment2->Position.y - Fragment3->Position.w + Fragment2->Position.w);
break;
case 5:
t1 = (Fragment3->Position.z + Fragment3->Position.w) / (Fragment3->Position.z - Fragment1->Position.z + Fragment3->Position.w - Fragment1->Position.w);
t2 = (Fragment3->Position.z + Fragment3->Position.w) / (Fragment3->Position.z - Fragment2->Position.z + Fragment3->Position.w - Fragment2->Position.w);
break;
case 6:
t1 = (Fragment3->Position.z - Fragment3->Position.w) / (Fragment3->Position.z - Fragment1->Position.z - Fragment3->Position.w + Fragment1->Position.w);
t2 = (Fragment3->Position.z - Fragment3->Position.w) / (Fragment3->Position.z - Fragment2->Position.z - Fragment3->Position.w + Fragment2->Position.w);
break;
}
NewFragment3->Position.x = Fragment3->Position.x;
NewFragment3->Position.y = Fragment3->Position.y;
NewFragment3->Position.z = Fragment3->Position.z;
NewFragment3->Position.w = Fragment3->Position.w;
NewFragment2->Position.x = Fragment2->Position.x;
NewFragment2->Position.y = Fragment2->Position.y;
NewFragment2->Position.z = Fragment2->Position.z;
NewFragment2->Position.w = Fragment2->Position.w;
Fragment3->Position.x += (Fragment1->Position.x - Fragment3->Position.x) * t1;
Fragment3->Position.y += (Fragment1->Position.y - Fragment3->Position.y) * t1;
Fragment3->Position.z += (Fragment1->Position.z - Fragment3->Position.z) * t1;
Fragment3->Position.w += (Fragment1->Position.w - Fragment3->Position.w) * t1;
NewFragment1->Position.x = Fragment3->Position.x;
NewFragment1->Position.y = Fragment3->Position.y;
NewFragment1->Position.z = Fragment3->Position.z;
NewFragment1->Position.w = Fragment3->Position.w;
NewFragment3->Position.x += (NewFragment2->Position.x - NewFragment3->Position.x) * t2;
NewFragment3->Position.y += (NewFragment2->Position.y - NewFragment3->Position.y) * t2;
NewFragment3->Position.z += (NewFragment2->Position.z - NewFragment3->Position.z) * t2;
NewFragment3->Position.w += (NewFragment2->Position.w - NewFragment3->Position.w) * t2;
if(ColorBuffering)
{
NewFragment3->Color.r = Fragment3->Color.r;
NewFragment3->Color.g = Fragment3->Color.g;
NewFragment3->Color.b = Fragment3->Color.b;
NewFragment2->Color.r = Fragment2->Color.r;
NewFragment2->Color.g = Fragment2->Color.g;
NewFragment2->Color.b = Fragment2->Color.b;
Fragment3->Color.r += (Fragment1->Color.r - Fragment3->Color.r) * t1;
Fragment3->Color.g += (Fragment1->Color.g - Fragment3->Color.g) * t1;
Fragment3->Color.b += (Fragment1->Color.b - Fragment3->Color.b) * t1;
NewFragment1->Color.r = Fragment3->Color.r;
NewFragment1->Color.g = Fragment3->Color.g;
NewFragment1->Color.b = Fragment3->Color.b;
NewFragment3->Color.r += (NewFragment2->Color.r - NewFragment3->Color.r) * t2;
NewFragment3->Color.g += (NewFragment2->Color.g - NewFragment3->Color.g) * t2;
NewFragment3->Color.b += (NewFragment2->Color.b - NewFragment3->Color.b) * t2;
if(Texturing)
{
NewFragment3->TexCoord.s = Fragment3->TexCoord.s;
NewFragment3->TexCoord.t = Fragment3->TexCoord.t;
NewFragment2->TexCoord.s = Fragment2->TexCoord.s;
NewFragment2->TexCoord.t = Fragment2->TexCoord.t;
Fragment3->TexCoord.s += (Fragment1->TexCoord.s - Fragment3->TexCoord.s) * t1;
Fragment3->TexCoord.t += (Fragment1->TexCoord.t - Fragment3->TexCoord.t) * t1;
NewFragment1->TexCoord.s = Fragment3->TexCoord.s;
NewFragment1->TexCoord.t = Fragment3->TexCoord.t;
NewFragment3->TexCoord.s += (NewFragment2->TexCoord.s - NewFragment3->TexCoord.s) * t2;
NewFragment3->TexCoord.t += (NewFragment2->TexCoord.t - NewFragment3->TexCoord.t) * t2;
}
if(Lighting)
{
NewFragment3->Normal.x = Fragment3->Normal.x;
NewFragment3->Normal.y = Fragment3->Normal.y;
NewFragment3->Normal.z = Fragment3->Normal.z;
NewFragment2->Normal.x = Fragment2->Normal.x;
NewFragment2->Normal.y = Fragment2->Normal.y;
NewFragment2->Normal.z = Fragment2->Normal.z;
Fragment3->Normal.x += (Fragment1->Normal.x - Fragment3->Normal.x) * t1;
Fragment3->Normal.y += (Fragment1->Normal.y - Fragment3->Normal.y) * t1;
Fragment3->Normal.z += (Fragment1->Normal.z - Fragment3->Normal.z) * t1;
NewFragment1->Normal.x = Fragment3->Normal.x;
NewFragment1->Normal.y = Fragment3->Normal.y;
NewFragment1->Normal.z = Fragment3->Normal.z;
NewFragment3->Normal.x += (NewFragment2->Normal.x - NewFragment3->Normal.x) * t2;
NewFragment3->Normal.y += (NewFragment2->Normal.y - NewFragment3->Normal.y) * t2;
NewFragment3->Normal.z += (NewFragment2->Normal.z - NewFragment3->Normal.z) * t2;
NewFragment3->LightDirection.x = Fragment3->LightDirection.x;
NewFragment3->LightDirection.y = Fragment3->LightDirection.y;
NewFragment3->LightDirection.z = Fragment3->LightDirection.z;
NewFragment2->LightDirection.x = Fragment2->LightDirection.x;
NewFragment2->LightDirection.y = Fragment2->LightDirection.y;
NewFragment2->LightDirection.z = Fragment2->LightDirection.z;
Fragment3->LightDirection.x += (Fragment1->LightDirection.x - Fragment3->LightDirection.x) * t1;
Fragment3->LightDirection.y += (Fragment1->LightDirection.y - Fragment3->LightDirection.y) * t1;
Fragment3->LightDirection.z += (Fragment1->LightDirection.z - Fragment3->LightDirection.z) * t1;
NewFragment1->LightDirection.x = Fragment3->LightDirection.x;
NewFragment1->LightDirection.y = Fragment3->LightDirection.y;
NewFragment1->LightDirection.z = Fragment3->LightDirection.z;
NewFragment3->LightDirection.x += (NewFragment2->LightDirection.x - NewFragment3->LightDirection.x) * t2;
NewFragment3->LightDirection.y += (NewFragment2->LightDirection.y - NewFragment3->LightDirection.y) * t2;
NewFragment3->LightDirection.z += (NewFragment2->LightDirection.z - NewFragment3->LightDirection.z) * t2;
if(ShadowMapping)
{
NewFragment3->ShadowMapTexCoord.s = Fragment3->ShadowMapTexCoord.s;
NewFragment3->ShadowMapTexCoord.t = Fragment3->ShadowMapTexCoord.t;
NewFragment3->ShadowMapTexCoord.p = Fragment3->ShadowMapTexCoord.p;
NewFragment3->ShadowMapTexCoord.q = Fragment3->ShadowMapTexCoord.q;
NewFragment2->ShadowMapTexCoord.s = Fragment2->ShadowMapTexCoord.s;
NewFragment2->ShadowMapTexCoord.t = Fragment2->ShadowMapTexCoord.t;
NewFragment2->ShadowMapTexCoord.p = Fragment2->ShadowMapTexCoord.p;
NewFragment2->ShadowMapTexCoord.q = Fragment2->ShadowMapTexCoord.q;
Fragment3->ShadowMapTexCoord.s += (Fragment1->ShadowMapTexCoord.s - Fragment3->ShadowMapTexCoord.s) * t1;
Fragment3->ShadowMapTexCoord.t += (Fragment1->ShadowMapTexCoord.t - Fragment3->ShadowMapTexCoord.t) * t1;
Fragment3->ShadowMapTexCoord.p += (Fragment1->ShadowMapTexCoord.p - Fragment3->ShadowMapTexCoord.p) * t1;
Fragment3->ShadowMapTexCoord.q += (Fragment1->ShadowMapTexCoord.q - Fragment3->ShadowMapTexCoord.q) * t1;
NewFragment1->ShadowMapTexCoord.s = Fragment3->ShadowMapTexCoord.s;
NewFragment1->ShadowMapTexCoord.t = Fragment3->ShadowMapTexCoord.t;
NewFragment1->ShadowMapTexCoord.p = Fragment3->ShadowMapTexCoord.p;
NewFragment1->ShadowMapTexCoord.q = Fragment3->ShadowMapTexCoord.q;
NewFragment3->ShadowMapTexCoord.s += (NewFragment2->ShadowMapTexCoord.s - NewFragment3->ShadowMapTexCoord.s) * t2;
NewFragment3->ShadowMapTexCoord.t += (NewFragment2->ShadowMapTexCoord.t - NewFragment3->ShadowMapTexCoord.t) * t2;
NewFragment3->ShadowMapTexCoord.p += (NewFragment2->ShadowMapTexCoord.p - NewFragment3->ShadowMapTexCoord.p) * t2;
NewFragment3->ShadowMapTexCoord.q += (NewFragment2->ShadowMapTexCoord.q - NewFragment3->ShadowMapTexCoord.q) * t2;
}
}
}
ClipTriangle(Fragments, ThreadId, ClipPlane + 1);
ClipTriangle(NewFragments, ThreadId, ClipPlane + 1);
}
else if(fbcpc == 0)
{
ClipTriangle(Fragments, ThreadId, ClipPlane + 1);
}
}
else if(ClipPlane == 7)
{
RasterizeTriangle(Fragments, ThreadId);
}
}
void CSoftwareGL::RasterizeTriangle(CFragment *Fragments, int ThreadId)
{
CFragment *Fragment1 = Fragments, *Fragment2 = Fragment1 + 1, *Fragment3 = Fragment2 + 1;
// projection
Fragment1->Position.w = 1.0f / Fragment1->Position.w;
Fragment1->Position.x *= Fragment1->Position.w;
Fragment1->Position.y *= Fragment1->Position.w;
Fragment2->Position.w = 1.0f / Fragment2->Position.w;
Fragment2->Position.x *= Fragment2->Position.w;
Fragment2->Position.y *= Fragment2->Position.w;
Fragment3->Position.w = 1.0f / Fragment3->Position.w;
Fragment3->Position.x *= Fragment3->Position.w;
Fragment3->Position.y *= Fragment3->Position.w;
// culling
if(CullFace)
{
float a = 0.0f;
a += Fragment1->Position.x * Fragment2->Position.y - Fragment2->Position.x * Fragment1->Position.y;
a += Fragment2->Position.x * Fragment3->Position.y - Fragment3->Position.x * Fragment2->Position.y;
a += Fragment3->Position.x * Fragment1->Position.y - Fragment1->Position.x * Fragment3->Position.y;
switch(CullFace)
{
case CULL_FACE_FRONT:
if(a >= 0.0f) return;
break;
case CULL_FACE_BACK:
if(a <= 0.0f) return;
break;
}
}
// perspective correct z and attribute values interpolation
// http://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf
Fragment1->Position.x = (Fragment1->Position.x * 0.5f + 0.5f) * ViewportWidth + ViewportX;
Fragment1->Position.y = (Fragment1->Position.y * 0.5f + 0.5f) * ViewportHeight + ViewportY;
Fragment1->Position.z = Fragment1->Position.z * Fragment1->Position.w * 0.5f + 0.5f;
Fragment2->Position.x = (Fragment2->Position.x * 0.5f + 0.5f) * ViewportWidth + ViewportX;
Fragment2->Position.y = (Fragment2->Position.y * 0.5f + 0.5f) * ViewportHeight + ViewportY;
Fragment2->Position.z = Fragment2->Position.z * Fragment2->Position.w * 0.5f + 0.5f;
Fragment3->Position.x = (Fragment3->Position.x * 0.5f + 0.5f) * ViewportWidth + ViewportX;
Fragment3->Position.y = (Fragment3->Position.y * 0.5f + 0.5f) * ViewportHeight + ViewportY;
Fragment3->Position.z = Fragment3->Position.z * Fragment3->Position.w * 0.5f + 0.5f;
if(ColorBuffering)
{
Fragment1->Color.r *= Fragment1->Position.w;
Fragment1->Color.g *= Fragment1->Position.w;
Fragment1->Color.b *= Fragment1->Position.w;
Fragment2->Color.r *= Fragment2->Position.w;
Fragment2->Color.g *= Fragment2->Position.w;
Fragment2->Color.b *= Fragment2->Position.w;
Fragment3->Color.r *= Fragment3->Position.w;
Fragment3->Color.g *= Fragment3->Position.w;
Fragment3->Color.b *= Fragment3->Position.w;
if(Texturing)
{
Fragment1->TexCoord.s *= Fragment1->Position.w;
Fragment1->TexCoord.t *= Fragment1->Position.w;
Fragment2->TexCoord.s *= Fragment2->Position.w;
Fragment2->TexCoord.t *= Fragment2->Position.w;
Fragment3->TexCoord.s *= Fragment3->Position.w;
Fragment3->TexCoord.t *= Fragment3->Position.w;
}
if(Lighting)
{
Fragment1->Normal.x *= Fragment1->Position.w;
Fragment1->Normal.y *= Fragment1->Position.w;
Fragment1->Normal.z *= Fragment1->Position.w;
Fragment2->Normal.x *= Fragment2->Position.w;
Fragment2->Normal.y *= Fragment2->Position.w;
Fragment2->Normal.z *= Fragment2->Position.w;
Fragment3->Normal.x *= Fragment3->Position.w;
Fragment3->Normal.y *= Fragment3->Position.w;
Fragment3->Normal.z *= Fragment3->Position.w;
Fragment1->LightDirection.x *= Fragment1->Position.w;
Fragment1->LightDirection.y *= Fragment1->Position.w;
Fragment1->LightDirection.z *= Fragment1->Position.w;
Fragment2->LightDirection.x *= Fragment2->Position.w;
Fragment2->LightDirection.y *= Fragment2->Position.w;
Fragment2->LightDirection.z *= Fragment2->Position.w;
Fragment3->LightDirection.x *= Fragment3->Position.w;
Fragment3->LightDirection.y *= Fragment3->Position.w;
Fragment3->LightDirection.z *= Fragment3->Position.w;
if(ShadowMapping)
{
Fragment1->ShadowMapTexCoord.s *= Fragment1->Position.w;
Fragment1->ShadowMapTexCoord.t *= Fragment1->Position.w;
Fragment1->ShadowMapTexCoord.p *= Fragment1->Position.w;
Fragment1->ShadowMapTexCoord.q *= Fragment1->Position.w;
Fragment2->ShadowMapTexCoord.s *= Fragment2->Position.w;
Fragment2->ShadowMapTexCoord.t *= Fragment2->Position.w;
Fragment2->ShadowMapTexCoord.p *= Fragment2->Position.w;
Fragment2->ShadowMapTexCoord.q *= Fragment2->Position.w;
Fragment3->ShadowMapTexCoord.s *= Fragment3->Position.w;
Fragment3->ShadowMapTexCoord.t *= Fragment3->Position.w;
Fragment3->ShadowMapTexCoord.p *= Fragment3->Position.w;
Fragment3->ShadowMapTexCoord.q *= Fragment3->Position.w;
}
}
}
// triangle rasterization
// http://joshbeam.com/articles/triangle_rasterization/
CEdge Edges[3], *Edge1 = Edges, *Edge2 = Edge1 + 1, *Edge3 = Edge2 + 1;
Edge1->Set(Fragment1, Fragment2);
Edge2->Set(Fragment2, Fragment3);
Edge3->Set(Fragment3, Fragment1);
Edge1->PositionDiff.x = Edge1->Fragment2->Position.x - Edge1->Fragment1->Position.x;
Edge1->PositionDiff.y = Edge1->Fragment2->Position.y - Edge1->Fragment1->Position.y;
Edge1->PositionDiff.z = Edge1->Fragment2->Position.z - Edge1->Fragment1->Position.z;
Edge1->PositionDiff.w = Edge1->Fragment2->Position.w - Edge1->Fragment1->Position.w;
Edge2->PositionDiff.x = Edge2->Fragment2->Position.x - Edge2->Fragment1->Position.x;
Edge2->PositionDiff.y = Edge2->Fragment2->Position.y - Edge2->Fragment1->Position.y;
Edge2->PositionDiff.z = Edge2->Fragment2->Position.z - Edge2->Fragment1->Position.z;
Edge2->PositionDiff.w = Edge2->Fragment2->Position.w - Edge2->Fragment1->Position.w;
Edge3->PositionDiff.x = Edge3->Fragment2->Position.x - Edge3->Fragment1->Position.x;
Edge3->PositionDiff.y = Edge3->Fragment2->Position.y - Edge3->Fragment1->Position.y;
Edge3->PositionDiff.z = Edge3->Fragment2->Position.z - Edge3->Fragment1->Position.z;
Edge3->PositionDiff.w = Edge3->Fragment2->Position.w - Edge3->Fragment1->Position.w;
if(ColorBuffering)
{
Edge1->ColorDiff.r = Edge1->Fragment2->Color.r - Edge1->Fragment1->Color.r;
Edge1->ColorDiff.g = Edge1->Fragment2->Color.g - Edge1->Fragment1->Color.g;
Edge1->ColorDiff.b = Edge1->Fragment2->Color.b - Edge1->Fragment1->Color.b;
Edge2->ColorDiff.r = Edge2->Fragment2->Color.r - Edge2->Fragment1->Color.r;
Edge2->ColorDiff.g = Edge2->Fragment2->Color.g - Edge2->Fragment1->Color.g;
Edge2->ColorDiff.b = Edge2->Fragment2->Color.b - Edge2->Fragment1->Color.b;
Edge3->ColorDiff.r = Edge3->Fragment2->Color.r - Edge3->Fragment1->Color.r;
Edge3->ColorDiff.g = Edge3->Fragment2->Color.g - Edge3->Fragment1->Color.g;
Edge3->ColorDiff.b = Edge3->Fragment2->Color.b - Edge3->Fragment1->Color.b;
if(Texturing)
{
Edge1->TexCoordDiff.s = Edge1->Fragment2->TexCoord.s - Edge1->Fragment1->TexCoord.s;
Edge1->TexCoordDiff.t = Edge1->Fragment2->TexCoord.t - Edge1->Fragment1->TexCoord.t;
Edge2->TexCoordDiff.s = Edge2->Fragment2->TexCoord.s - Edge2->Fragment1->TexCoord.s;
Edge2->TexCoordDiff.t = Edge2->Fragment2->TexCoord.t - Edge2->Fragment1->TexCoord.t;
Edge3->TexCoordDiff.s = Edge3->Fragment2->TexCoord.s - Edge3->Fragment1->TexCoord.s;
Edge3->TexCoordDiff.t = Edge3->Fragment2->TexCoord.t - Edge3->Fragment1->TexCoord.t;
}
if(Lighting)
{
Edge1->NormalDiff.x = Edge1->Fragment2->Normal.x - Edge1->Fragment1->Normal.x;
Edge1->NormalDiff.y = Edge1->Fragment2->Normal.y - Edge1->Fragment1->Normal.y;
Edge1->NormalDiff.z = Edge1->Fragment2->Normal.z - Edge1->Fragment1->Normal.z;
Edge2->NormalDiff.x = Edge2->Fragment2->Normal.x - Edge2->Fragment1->Normal.x;
Edge2->NormalDiff.y = Edge2->Fragment2->Normal.y - Edge2->Fragment1->Normal.y;
Edge2->NormalDiff.z = Edge2->Fragment2->Normal.z - Edge2->Fragment1->Normal.z;
Edge3->NormalDiff.x = Edge3->Fragment2->Normal.x - Edge3->Fragment1->Normal.x;
Edge3->NormalDiff.y = Edge3->Fragment2->Normal.y - Edge3->Fragment1->Normal.y;
Edge3->NormalDiff.z = Edge3->Fragment2->Normal.z - Edge3->Fragment1->Normal.z;
Edge1->LightDirectionDiff.x = Edge1->Fragment2->LightDirection.x - Edge1->Fragment1->LightDirection.x;
Edge1->LightDirectionDiff.y = Edge1->Fragment2->LightDirection.y - Edge1->Fragment1->LightDirection.y;
Edge1->LightDirectionDiff.z = Edge1->Fragment2->LightDirection.z - Edge1->Fragment1->LightDirection.z;
Edge2->LightDirectionDiff.x = Edge2->Fragment2->LightDirection.x - Edge2->Fragment1->LightDirection.x;
Edge2->LightDirectionDiff.y = Edge2->Fragment2->LightDirection.y - Edge2->Fragment1->LightDirection.y;
Edge2->LightDirectionDiff.z = Edge2->Fragment2->LightDirection.z - Edge2->Fragment1->LightDirection.z;
Edge3->LightDirectionDiff.x = Edge3->Fragment2->LightDirection.x - Edge3->Fragment1->LightDirection.x;
Edge3->LightDirectionDiff.y = Edge3->Fragment2->LightDirection.y - Edge3->Fragment1->LightDirection.y;
Edge3->LightDirectionDiff.z = Edge3->Fragment2->LightDirection.z - Edge3->Fragment1->LightDirection.z;
if(ShadowMapping)
{
Edge1->ShadowMapTexCoordDiff.s = Edge1->Fragment2->ShadowMapTexCoord.s - Edge1->Fragment1->ShadowMapTexCoord.s;
Edge1->ShadowMapTexCoordDiff.t = Edge1->Fragment2->ShadowMapTexCoord.t - Edge1->Fragment1->ShadowMapTexCoord.t;
Edge1->ShadowMapTexCoordDiff.p = Edge1->Fragment2->ShadowMapTexCoord.p - Edge1->Fragment1->ShadowMapTexCoord.p;
Edge1->ShadowMapTexCoordDiff.q = Edge1->Fragment2->ShadowMapTexCoord.q - Edge1->Fragment1->ShadowMapTexCoord.q;
Edge2->ShadowMapTexCoordDiff.s = Edge2->Fragment2->ShadowMapTexCoord.s - Edge2->Fragment1->ShadowMapTexCoord.s;
Edge2->ShadowMapTexCoordDiff.t = Edge2->Fragment2->ShadowMapTexCoord.t - Edge2->Fragment1->ShadowMapTexCoord.t;
Edge2->ShadowMapTexCoordDiff.p = Edge2->Fragment2->ShadowMapTexCoord.p - Edge2->Fragment1->ShadowMapTexCoord.p;
Edge2->ShadowMapTexCoordDiff.q = Edge2->Fragment2->ShadowMapTexCoord.q - Edge2->Fragment1->ShadowMapTexCoord.q;
Edge3->ShadowMapTexCoordDiff.s = Edge3->Fragment2->ShadowMapTexCoord.s - Edge3->Fragment1->ShadowMapTexCoord.s;
Edge3->ShadowMapTexCoordDiff.t = Edge3->Fragment2->ShadowMapTexCoord.t - Edge3->Fragment1->ShadowMapTexCoord.t;
Edge3->ShadowMapTexCoordDiff.p = Edge3->Fragment2->ShadowMapTexCoord.p - Edge3->Fragment1->ShadowMapTexCoord.p;
Edge3->ShadowMapTexCoordDiff.q = Edge3->Fragment2->ShadowMapTexCoord.q - Edge3->Fragment1->ShadowMapTexCoord.q;
}
}
}
CEdge *LongEdge = Edge1, *ShortEdge1 = Edge2, *ShortEdge2 = Edge3;
if(Edge2->PositionDiff.y > LongEdge->PositionDiff.y)
{
LongEdge = Edge2;
ShortEdge1 = Edge3;
ShortEdge2 = Edge1;
}
if(Edge3->PositionDiff.y > LongEdge->PositionDiff.y)
{
LongEdge = Edge3;
ShortEdge1 = Edge1;
ShortEdge2 = Edge2;
}
DrawSpansBetweenEdges(LongEdge, ShortEdge1, ThreadId);
DrawSpansBetweenEdges(LongEdge, ShortEdge2, ThreadId);
}
void CSoftwareGL::DrawSpansBetweenEdges(CEdge *Edge1, CEdge *Edge2, int ThreadId)
{
if(Edge1->PositionDiff.y == 0.0f || Edge2->PositionDiff.y == 0.0f) return;
int iy1 = (int)Edge2->Fragment1->Position.y, iy2 = (int)Edge2->Fragment2->Position.y;
if(iy1 < 0) iy1 = 0;
while(iy1 % ThreadsCount != ThreadId) iy1++;
if(iy2 > BufferHeightM1) iy2 = BufferHeightM1;
float fy, factor1, factor2, ode1pdy = 1.0f / Edge1->PositionDiff.y, ode2pdy = 1.0f / Edge2->PositionDiff.y;
CFragment Fragment1, Fragment2;
CSpan Span;
for(int y = iy1; y <= iy2; y += ThreadsCount)
{
fy = y + 0.5f;
factor1 = (fy - Edge1->Fragment1->Position.y) * ode1pdy;
if(factor1 < 0.0f || factor1 > 1.0f) continue;
factor2 = (fy - Edge2->Fragment1->Position.y) * ode2pdy;
if(factor2 < 0.0f || factor2 > 1.0f) continue;
Fragment1.Position.x = Edge1->Fragment1->Position.x + Edge1->PositionDiff.x * factor1;
Fragment1.Position.y = Edge1->Fragment1->Position.y + Edge1->PositionDiff.y * factor1;
Fragment1.Position.z = Edge1->Fragment1->Position.z + Edge1->PositionDiff.z * factor1;
Fragment1.Position.w = Edge1->Fragment1->Position.w + Edge1->PositionDiff.w * factor1;
Fragment2.Position.x = Edge2->Fragment1->Position.x + Edge2->PositionDiff.x * factor2;
Fragment2.Position.y = Edge2->Fragment1->Position.y + Edge2->PositionDiff.y * factor2;
Fragment2.Position.z = Edge2->Fragment1->Position.z + Edge2->PositionDiff.z * factor2;
Fragment2.Position.w = Edge2->Fragment1->Position.w + Edge2->PositionDiff.w * factor2;
if(ColorBuffering)
{
Fragment1.Color.r = Edge1->Fragment1->Color.r + Edge1->ColorDiff.r * factor1;
Fragment1.Color.g = Edge1->Fragment1->Color.g + Edge1->ColorDiff.g * factor1;
Fragment1.Color.b = Edge1->Fragment1->Color.b + Edge1->ColorDiff.b * factor1;
Fragment2.Color.r = Edge2->Fragment1->Color.r + Edge2->ColorDiff.r * factor2;
Fragment2.Color.g = Edge2->Fragment1->Color.g + Edge2->ColorDiff.g * factor2;
Fragment2.Color.b = Edge2->Fragment1->Color.b + Edge2->ColorDiff.b * factor2;
if(Texturing)
{
Fragment1.TexCoord.s = Edge1->Fragment1->TexCoord.s + Edge1->TexCoordDiff.s * factor1;
Fragment1.TexCoord.t = Edge1->Fragment1->TexCoord.t + Edge1->TexCoordDiff.t * factor1;
Fragment2.TexCoord.s = Edge2->Fragment1->TexCoord.s + Edge2->TexCoordDiff.s * factor2;
Fragment2.TexCoord.t = Edge2->Fragment1->TexCoord.t + Edge2->TexCoordDiff.t * factor2;
}
if(Lighting)
{
Fragment1.Normal.x = Edge1->Fragment1->Normal.x + Edge1->NormalDiff.x * factor1;
Fragment1.Normal.y = Edge1->Fragment1->Normal.y + Edge1->NormalDiff.y * factor1;
Fragment1.Normal.z = Edge1->Fragment1->Normal.z + Edge1->NormalDiff.z * factor1;
Fragment2.Normal.x = Edge2->Fragment1->Normal.x + Edge2->NormalDiff.x * factor2;
Fragment2.Normal.y = Edge2->Fragment1->Normal.y + Edge2->NormalDiff.y * factor2;
Fragment2.Normal.z = Edge2->Fragment1->Normal.z + Edge2->NormalDiff.z * factor2;
Fragment1.LightDirection.x = Edge1->Fragment1->LightDirection.x + Edge1->LightDirectionDiff.x * factor1;
Fragment1.LightDirection.y = Edge1->Fragment1->LightDirection.y + Edge1->LightDirectionDiff.y * factor1;
Fragment1.LightDirection.z = Edge1->Fragment1->LightDirection.z + Edge1->LightDirectionDiff.z * factor1;
Fragment2.LightDirection.x = Edge2->Fragment1->LightDirection.x + Edge2->LightDirectionDiff.x * factor2;
Fragment2.LightDirection.y = Edge2->Fragment1->LightDirection.y + Edge2->LightDirectionDiff.y * factor2;
Fragment2.LightDirection.z = Edge2->Fragment1->LightDirection.z + Edge2->LightDirectionDiff.z * factor2;
if(ShadowMapping)
{
Fragment1.ShadowMapTexCoord.s = Edge1->Fragment1->ShadowMapTexCoord.s + Edge1->ShadowMapTexCoordDiff.s * factor1;
Fragment1.ShadowMapTexCoord.t = Edge1->Fragment1->ShadowMapTexCoord.t + Edge1->ShadowMapTexCoordDiff.t * factor1;
Fragment1.ShadowMapTexCoord.p = Edge1->Fragment1->ShadowMapTexCoord.p + Edge1->ShadowMapTexCoordDiff.p * factor1;
Fragment1.ShadowMapTexCoord.q = Edge1->Fragment1->ShadowMapTexCoord.q + Edge1->ShadowMapTexCoordDiff.q * factor1;
Fragment2.ShadowMapTexCoord.s = Edge2->Fragment1->ShadowMapTexCoord.s + Edge2->ShadowMapTexCoordDiff.s * factor2;
Fragment2.ShadowMapTexCoord.t = Edge2->Fragment1->ShadowMapTexCoord.t + Edge2->ShadowMapTexCoordDiff.t * factor2;
Fragment2.ShadowMapTexCoord.p = Edge2->Fragment1->ShadowMapTexCoord.p + Edge2->ShadowMapTexCoordDiff.p * factor2;
Fragment2.ShadowMapTexCoord.q = Edge2->Fragment1->ShadowMapTexCoord.q + Edge2->ShadowMapTexCoordDiff.q * factor2;
}
}
}
Span.Set(&Fragment1, &Fragment2);
Span.PositionDiff.x = Span.Fragment2->Position.x - Span.Fragment1->Position.x;
Span.PositionDiff.y = Span.Fragment2->Position.y - Span.Fragment1->Position.y;
Span.PositionDiff.z = Span.Fragment2->Position.z - Span.Fragment1->Position.z;
Span.PositionDiff.w = Span.Fragment2->Position.w - Span.Fragment1->Position.w;
if(ColorBuffering)
{
Span.ColorDiff.r = Span.Fragment2->Color.r - Span.Fragment1->Color.r;
Span.ColorDiff.g = Span.Fragment2->Color.g - Span.Fragment1->Color.g;
Span.ColorDiff.b = Span.Fragment2->Color.b - Span.Fragment1->Color.b;
if(Texturing)
{
Span.TexCoordDiff.s = Span.Fragment2->TexCoord.s - Span.Fragment1->TexCoord.s;
Span.TexCoordDiff.t = Span.Fragment2->TexCoord.t - Span.Fragment1->TexCoord.t;
}
if(Lighting)
{
Span.NormalDiff.x = Span.Fragment2->Normal.x - Span.Fragment1->Normal.x;
Span.NormalDiff.y = Span.Fragment2->Normal.y - Span.Fragment1->Normal.y;
Span.NormalDiff.z = Span.Fragment2->Normal.z - Span.Fragment1->Normal.z;
Span.LightDirectionDiff.x = Span.Fragment2->LightDirection.x - Span.Fragment1->LightDirection.x;
Span.LightDirectionDiff.y = Span.Fragment2->LightDirection.y - Span.Fragment1->LightDirection.y;
Span.LightDirectionDiff.z = Span.Fragment2->LightDirection.z - Span.Fragment1->LightDirection.z;
if(ShadowMapping)
{
Span.ShadowMapTexCoordDiff.s = Span.Fragment2->ShadowMapTexCoord.s - Span.Fragment1->ShadowMapTexCoord.s;
Span.ShadowMapTexCoordDiff.t = Span.Fragment2->ShadowMapTexCoord.t - Span.Fragment1->ShadowMapTexCoord.t;
Span.ShadowMapTexCoordDiff.p = Span.Fragment2->ShadowMapTexCoord.p - Span.Fragment1->ShadowMapTexCoord.p;
Span.ShadowMapTexCoordDiff.q = Span.Fragment2->ShadowMapTexCoord.q - Span.Fragment1->ShadowMapTexCoord.q;
}
}
}
DrawSpan(&Span, y);
}
}
void CSoftwareGL::DrawSpan(CSpan *Span, int y)
{
if(Span->PositionDiff.x == 0.0f) return;
int ix1 = (int)Span->Fragment1->Position.x, ix2 = (int)Span->Fragment2->Position.x;
if(ix1 < 0) ix1 = 0;
if(ix2 > BufferWidthM1) ix2 = BufferWidthM1;
float factor, odspdx = 1.0f / Span->PositionDiff.x, z, w;
USHORT Depth;
vec3 Color;
vec2 TexCoord;
vec3 Normal;
vec3 LightDirection;
vec4 ShadowMapTexCoord;
vec3 TextureColor;
float NdotLD, Shadow, NormalLength, LightDistance2, LightDistance, LightAttenuation;
BYTE *ColorBuffer = this->ColorBuffer + (ColorBufferWidth * y + ix1) * 3;
USHORT *DepthBuffer = this->DepthBuffer + DepthBufferWidth * y + ix1;
for(int x = ix1; x <= ix2; x++)
{
factor = (x + 0.5f - Span->Fragment1->Position.x) * odspdx;
if(factor >= 0.0f && factor <= 1.0f)
{
z = Span->Fragment1->Position.z + Span->PositionDiff.z * factor;
Depth = (USHORT)(z * 65535.0f);
// depth test
if(NotDepthTesting || Depth <= *DepthBuffer)
{
w = 1.0f / (Span->Fragment1->Position.w + Span->PositionDiff.w * factor);
if(ColorBuffering)
{
Color.r = (Span->Fragment1->Color.r + Span->ColorDiff.r * factor) * w;
Color.g = (Span->Fragment1->Color.g + Span->ColorDiff.g * factor) * w;
Color.b = (Span->Fragment1->Color.b + Span->ColorDiff.b * factor) * w;
if(Texturing)
{
TexCoord.s = (Span->Fragment1->TexCoord.s + Span->TexCoordDiff.s * factor) * w;
TexCoord.t = (Span->Fragment1->TexCoord.t + Span->TexCoordDiff.t * factor) * w;
}
if(Lighting)
{
Normal.x = (Span->Fragment1->Normal.x + Span->NormalDiff.x * factor) * w;
Normal.y = (Span->Fragment1->Normal.y + Span->NormalDiff.y * factor) * w;
Normal.z = (Span->Fragment1->Normal.z + Span->NormalDiff.z * factor) * w;
LightDirection.x = (Span->Fragment1->LightDirection.x + Span->LightDirectionDiff.x * factor) * w;
LightDirection.y = (Span->Fragment1->LightDirection.y + Span->LightDirectionDiff.y * factor) * w;
LightDirection.z = (Span->Fragment1->LightDirection.z + Span->LightDirectionDiff.z * factor) * w;
if(ShadowMapping)
{
ShadowMapTexCoord.s = (Span->Fragment1->ShadowMapTexCoord.s + Span->ShadowMapTexCoordDiff.s * factor) * w;
ShadowMapTexCoord.t = (Span->Fragment1->ShadowMapTexCoord.t + Span->ShadowMapTexCoordDiff.t * factor) * w;
ShadowMapTexCoord.p = (Span->Fragment1->ShadowMapTexCoord.p + Span->ShadowMapTexCoordDiff.p * factor) * w;
ShadowMapTexCoord.q = (Span->Fragment1->ShadowMapTexCoord.q + Span->ShadowMapTexCoordDiff.q * factor) * w;
}
}
// fragment shader
if(Texturing)
{
if(BilinearTextureFiltering)
{
Texture->GetColorBilinear(TexCoord.s, TexCoord.t, TextureColor);
}
else
{
Texture->GetColorNearest(TexCoord.s, TexCoord.t, TextureColor);
}
Color.r *= TextureColor.r;
Color.g *= TextureColor.g;
Color.b *= TextureColor.b;
}
if(Lighting)
{
LightDistance2 = LightDirection.x * LightDirection.x + LightDirection.y * LightDirection.y + LightDirection.z * LightDirection.z;
LightDistance = sqrt(LightDistance2);
NdotLD = Normal.x * LightDirection.x + Normal.y * LightDirection.y + Normal.z * LightDirection.z;
if(NdotLD < 0.0f)
{
NdotLD = 0.0f;
}
else
{
if(ShadowMapping)
{
if(BilinearTextureFiltering)
{
NdotLD *= ShadowMap->GetShadowBilinear(ShadowMapTexCoord);
}
else
{
NdotLD *= ShadowMap->GetShadowNearest(ShadowMapTexCoord);
}
}
if(NdotLD > 0.0f)
{
NormalLength = sqrt(Normal.x * Normal.x + Normal.y * Normal.y + Normal.z * Normal.z);
NdotLD /= NormalLength * LightDistance;
}
}
LightAttenuation = 1.0f / (Light->ConstantAttenuation + Light->LinearAttenuation * LightDistance + Light->QuadraticAttenuation * LightDistance2);
Color.r *= (Light->Ambient.r + Light->Diffuse.r * NdotLD) * LightAttenuation;
Color.g *= (Light->Ambient.g + Light->Diffuse.g * NdotLD) * LightAttenuation;
Color.b *= (Light->Ambient.b + Light->Diffuse.b * NdotLD) * LightAttenuation;
}
// writing to color buffer
*ColorBuffer = /*Color.b <= 0.0f ? 0 : Color.b >= 1.0f ? 255 :*/ (BYTE)(Color.b * 255.0f); ColorBuffer++;
*ColorBuffer = /*Color.g <= 0.0f ? 0 : Color.g >= 1.0f ? 255 :*/ (BYTE)(Color.g * 255.0f); ColorBuffer++;
*ColorBuffer = /*Color.r <= 0.0f ? 0 : Color.r >= 1.0f ? 255 :*/ (BYTE)(Color.r * 255.0f); ColorBuffer++;
}
else
{
ColorBuffer += 3;
}
// writing to depth buffer
if(DepthTesting)
{
*DepthBuffer = Depth; DepthBuffer++;
}
}
else
{
ColorBuffer += 3;
DepthBuffer++;
}
}
else
{
ColorBuffer += 3;
DepthBuffer++;
}
}
}
void CSoftwareGL::BlitAntiAliasingColorBuffer2x2(int ThreadId)
{
int TCM2 = ThreadsCount * 2, AACBWM3 = AntiAliasingColorBufferWidth * 3;
int LineAACB0, LineAACB1, LineSCB;
int xm3;
int LineAACB0Px0, LineAACB0Px1;
int LineAACB1Px0, LineAACB1Px1;
int LineSCBPxD2M3;
float r, g, b;
for(int y = ThreadId * 2; y < AntiAliasingColorBufferHeight; y += TCM2)
{
LineAACB0 = AACBWM3 * y;
LineAACB1 = LineAACB0 + AACBWM3;
LineSCB = StandardColorBufferWidth * y / 2 * 3;
for(int x = 0; x < AntiAliasingColorBufferWidth; x += 2)
{
xm3 = x * 3;
LineAACB0Px0 = LineAACB0 + xm3;
LineAACB0Px1 = LineAACB0Px0 + 3;
LineAACB1Px0 = LineAACB1 + xm3;
LineAACB1Px1 = LineAACB1Px0 + 3;
LineSCBPxD2M3 = LineSCB + x / 2 * 3;
b = AntiAliasingColorBuffer[LineAACB0Px0++];
g = AntiAliasingColorBuffer[LineAACB0Px0++];
r = AntiAliasingColorBuffer[LineAACB0Px0];
b += AntiAliasingColorBuffer[LineAACB0Px1++];
g += AntiAliasingColorBuffer[LineAACB0Px1++];
r += AntiAliasingColorBuffer[LineAACB0Px1];
b += AntiAliasingColorBuffer[LineAACB1Px0++];
g += AntiAliasingColorBuffer[LineAACB1Px0++];
r += AntiAliasingColorBuffer[LineAACB1Px0];
b += AntiAliasingColorBuffer[LineAACB1Px1++];
g += AntiAliasingColorBuffer[LineAACB1Px1++];
r += AntiAliasingColorBuffer[LineAACB1Px1];
StandardColorBuffer[LineSCBPxD2M3++] = (BYTE)(b / 4.0f);
StandardColorBuffer[LineSCBPxD2M3++] = (BYTE)(g / 4.0f);
StandardColorBuffer[LineSCBPxD2M3] = (BYTE)(r / 4.0f);
}
}
}
void CSoftwareGL::BlitAntiAliasingColorBuffer3x3(int ThreadId)
{
int TCM3 = ThreadsCount * 3, AACBWM3 = AntiAliasingColorBufferWidth * 3;
int LineAACB0, LineAACB1, LineAACB2, LineSCB;
int xm3;
int LineAACB0Px0, LineAACB0Px1, LineAACB0Px2;
int LineAACB1Px0, LineAACB1Px1, LineAACB1Px2;
int LineAACB2Px0, LineAACB2Px1, LineAACB2Px2;
int LineSCBPxD3M3;
float r, g, b;
for(int y = ThreadId * 3; y < AntiAliasingColorBufferHeight; y += TCM3)
{
LineAACB0 = AACBWM3 * y;
LineAACB1 = LineAACB0 + AACBWM3;
LineAACB2 = LineAACB1 + AACBWM3;
LineSCB = StandardColorBufferWidth * y;
for(int x = 0; x < AntiAliasingColorBufferWidth; x += 3)
{
xm3 = x * 3;
LineAACB0Px0 = LineAACB0 + xm3;
LineAACB0Px1 = LineAACB0Px0 + 3;
LineAACB0Px2 = LineAACB0Px1 + 3;
LineAACB1Px0 = LineAACB1 + xm3;
LineAACB1Px1 = LineAACB1Px0 + 3;
LineAACB1Px2 = LineAACB1Px1 + 3;
LineAACB2Px0 = LineAACB2 + xm3;
LineAACB2Px1 = LineAACB2Px0 + 3;
LineAACB2Px2 = LineAACB2Px1 + 3;
LineSCBPxD3M3 = LineSCB + x;
b = AntiAliasingColorBuffer[LineAACB0Px0++];
g = AntiAliasingColorBuffer[LineAACB0Px0++];
r = AntiAliasingColorBuffer[LineAACB0Px0];
b += AntiAliasingColorBuffer[LineAACB0Px1++];
g += AntiAliasingColorBuffer[LineAACB0Px1++];
r += AntiAliasingColorBuffer[LineAACB0Px1];
b += AntiAliasingColorBuffer[LineAACB0Px2++];
g += AntiAliasingColorBuffer[LineAACB0Px2++];
r += AntiAliasingColorBuffer[LineAACB0Px2];
b += AntiAliasingColorBuffer[LineAACB1Px0++];
g += AntiAliasingColorBuffer[LineAACB1Px0++];
r += AntiAliasingColorBuffer[LineAACB1Px0];
b += AntiAliasingColorBuffer[LineAACB1Px1++];
g += AntiAliasingColorBuffer[LineAACB1Px1++];
r += AntiAliasingColorBuffer[LineAACB1Px1];
b += AntiAliasingColorBuffer[LineAACB1Px2++];
g += AntiAliasingColorBuffer[LineAACB1Px2++];
r += AntiAliasingColorBuffer[LineAACB1Px2];
b += AntiAliasingColorBuffer[LineAACB2Px0++];
g += AntiAliasingColorBuffer[LineAACB2Px0++];
r += AntiAliasingColorBuffer[LineAACB2Px0];
b += AntiAliasingColorBuffer[LineAACB2Px1++];
g += AntiAliasingColorBuffer[LineAACB2Px1++];
r += AntiAliasingColorBuffer[LineAACB2Px1];
b += AntiAliasingColorBuffer[LineAACB2Px2++];
g += AntiAliasingColorBuffer[LineAACB2Px2++];
r += AntiAliasingColorBuffer[LineAACB2Px2];
StandardColorBuffer[LineSCBPxD3M3++] = (BYTE)(b / 9.0f);
StandardColorBuffer[LineSCBPxD3M3++] = (BYTE)(g / 9.0f);
StandardColorBuffer[LineSCBPxD3M3] = (BYTE)(r / 9.0f);
}
}
}
void CSoftwareGL::BlitAntiAliasingColorBuffer4x4(int ThreadId)
{
int TCM4 = ThreadsCount * 4, AACBWM3 = AntiAliasingColorBufferWidth * 3;
int LineAACB0, LineAACB1, LineAACB2, LineAACB3, LineSCB;
int xm3;
int LineAACB0Px0, LineAACB0Px1, LineAACB0Px2, LineAACB0Px3;
int LineAACB1Px0, LineAACB1Px1, LineAACB1Px2, LineAACB1Px3;
int LineAACB2Px0, LineAACB2Px1, LineAACB2Px2, LineAACB2Px3;
int LineAACB3Px0, LineAACB3Px1, LineAACB3Px2, LineAACB3Px3;
int LineSCBPxD4M3;
float r, g, b;
for(int y = ThreadId * 4; y < AntiAliasingColorBufferHeight; y += TCM4)
{
LineAACB0 = AACBWM3 * y;
LineAACB1 = LineAACB0 + AACBWM3;
LineAACB2 = LineAACB1 + AACBWM3;
LineAACB3 = LineAACB2 + AACBWM3;
LineSCB = StandardColorBufferWidth * y / 4 * 3;
for(int x = 0; x < AntiAliasingColorBufferWidth; x += 4)
{
xm3 = x * 3;
LineAACB0Px0 = LineAACB0 + xm3;
LineAACB0Px1 = LineAACB0Px0 + 3;
LineAACB0Px2 = LineAACB0Px1 + 3;
LineAACB0Px3 = LineAACB0Px2 + 3;
LineAACB1Px0 = LineAACB1 + xm3;
LineAACB1Px1 = LineAACB1Px0 + 3;
LineAACB1Px2 = LineAACB1Px1 + 3;
LineAACB1Px3 = LineAACB1Px2 + 3;
LineAACB2Px0 = LineAACB2 + xm3;
LineAACB2Px1 = LineAACB2Px0 + 3;
LineAACB2Px2 = LineAACB2Px1 + 3;
LineAACB2Px3 = LineAACB2Px2 + 3;
LineAACB3Px0 = LineAACB3 + xm3;
LineAACB3Px1 = LineAACB3Px0 + 3;
LineAACB3Px2 = LineAACB3Px1 + 3;
LineAACB3Px3 = LineAACB3Px2 + 3;
LineSCBPxD4M3 = LineSCB + x / 4 * 3;
b = AntiAliasingColorBuffer[LineAACB0Px0++];
g = AntiAliasingColorBuffer[LineAACB0Px0++];
r = AntiAliasingColorBuffer[LineAACB0Px0];
b += AntiAliasingColorBuffer[LineAACB0Px1++];
g += AntiAliasingColorBuffer[LineAACB0Px1++];
r += AntiAliasingColorBuffer[LineAACB0Px1];
b += AntiAliasingColorBuffer[LineAACB0Px2++];
g += AntiAliasingColorBuffer[LineAACB0Px2++];
r += AntiAliasingColorBuffer[LineAACB0Px2];
b += AntiAliasingColorBuffer[LineAACB0Px3++];
g += AntiAliasingColorBuffer[LineAACB0Px3++];
r += AntiAliasingColorBuffer[LineAACB0Px3];
b += AntiAliasingColorBuffer[LineAACB1Px0++];
g += AntiAliasingColorBuffer[LineAACB1Px0++];
r += AntiAliasingColorBuffer[LineAACB1Px0];
b += AntiAliasingColorBuffer[LineAACB1Px1++];
g += AntiAliasingColorBuffer[LineAACB1Px1++];
r += AntiAliasingColorBuffer[LineAACB1Px1];
b += AntiAliasingColorBuffer[LineAACB1Px2++];
g += AntiAliasingColorBuffer[LineAACB1Px2++];
r += AntiAliasingColorBuffer[LineAACB1Px2];
b += AntiAliasingColorBuffer[LineAACB1Px3++];
g += AntiAliasingColorBuffer[LineAACB1Px3++];
r += AntiAliasingColorBuffer[LineAACB1Px3];
b += AntiAliasingColorBuffer[LineAACB2Px0++];
g += AntiAliasingColorBuffer[LineAACB2Px0++];
r += AntiAliasingColorBuffer[LineAACB2Px0];
b += AntiAliasingColorBuffer[LineAACB2Px1++];
g += AntiAliasingColorBuffer[LineAACB2Px1++];
r += AntiAliasingColorBuffer[LineAACB2Px1];
b += AntiAliasingColorBuffer[LineAACB2Px2++];
g += AntiAliasingColorBuffer[LineAACB2Px2++];
r += AntiAliasingColorBuffer[LineAACB2Px2];
b += AntiAliasingColorBuffer[LineAACB2Px3++];
g += AntiAliasingColorBuffer[LineAACB2Px3++];
r += AntiAliasingColorBuffer[LineAACB2Px3];
b += AntiAliasingColorBuffer[LineAACB3Px0++];
g += AntiAliasingColorBuffer[LineAACB3Px0++];
r += AntiAliasingColorBuffer[LineAACB3Px0];
b += AntiAliasingColorBuffer[LineAACB3Px1++];
g += AntiAliasingColorBuffer[LineAACB3Px1++];
r += AntiAliasingColorBuffer[LineAACB3Px1];
b += AntiAliasingColorBuffer[LineAACB3Px2++];
g += AntiAliasingColorBuffer[LineAACB3Px2++];
r += AntiAliasingColorBuffer[LineAACB3Px2];
b += AntiAliasingColorBuffer[LineAACB3Px3++];
g += AntiAliasingColorBuffer[LineAACB3Px3++];
r += AntiAliasingColorBuffer[LineAACB3Px3];
StandardColorBuffer[LineSCBPxD4M3++] = (BYTE)(b / 16.0f);
StandardColorBuffer[LineSCBPxD4M3++] = (BYTE)(g / 16.0f);
StandardColorBuffer[LineSCBPxD4M3] = (BYTE)(r / 16.0f);
}
}
}
void CSoftwareGL::ResizeBuffers(int Width, int Height)
{
this->Width = Width;
this->Height = Height;
if(AntiAliasingColorBuffer != NULL)
{
delete [] AntiAliasingColorBuffer;
AntiAliasingColorBuffer = NULL;
AntiAliasingColorBufferWidth = 0;
AntiAliasingColorBufferHeight = 0;
}
if(StandardColorBuffer != NULL)
{
delete [] StandardColorBuffer;
StandardColorBuffer = NULL;
StandardColorBufferWidth = 0;
StandardColorBufferHeight = 0;
}
if(StandardDepthBuffer != NULL)
{
delete [] StandardDepthBuffer;
StandardDepthBuffer = NULL;
StandardDepthBufferWidth = 0;
StandardDepthBufferHeight = 0;
}
if(FrameBuffer == NULL)
{
BufferWidthM1 = 0;
BufferHeightM1 = 0;
}
if(Width > 0 && Height > 0)
{
int Factor = 1;
if(AntiAliasing)
{
switch(AntiAliasing)
{
case ANTI_ALIASING_2X2: Factor = 2; break;
case ANTI_ALIASING_3X3: Factor = 3; break;
case ANTI_ALIASING_4X4: Factor = 4; break;
}
AntiAliasingColorBufferWidth = Width * Factor;
AntiAliasingColorBufferHeight = Height * Factor;
AntiAliasingColorBuffer = new BYTE[AntiAliasingColorBufferWidth * AntiAliasingColorBufferHeight * 3];
}
StandardColorBufferWidth = Width;
StandardColorBufferHeight = Height;
int WidthMod4 = Width % 4;
if(WidthMod4 > 0)
{
StandardColorBufferWidth += 4 - WidthMod4;
}
StandardColorBuffer = new BYTE[StandardColorBufferWidth * StandardColorBufferHeight * 3];
memset(&BitmapInfo, 0, sizeof(BITMAPINFO));
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 24;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
BitmapInfo.bmiHeader.biWidth = StandardColorBufferWidth;
BitmapInfo.bmiHeader.biHeight = StandardColorBufferHeight;
StandardDepthBufferWidth = Width * Factor;
StandardDepthBufferHeight = Height * Factor;
StandardDepthBuffer = new USHORT[StandardDepthBufferWidth * StandardDepthBufferHeight];
}
if(FrameBuffer == NULL)
{
if(AntiAliasing)
{
ColorBuffer = AntiAliasingColorBuffer;
ColorBufferWidth = AntiAliasingColorBufferWidth;
ColorBufferHeight = AntiAliasingColorBufferHeight;
}
else
{
ColorBuffer = StandardColorBuffer;
ColorBufferWidth = StandardColorBufferWidth;
ColorBufferHeight = StandardColorBufferHeight;
}
DepthBuffer = StandardDepthBuffer;
DepthBufferWidth = StandardDepthBufferWidth;
DepthBufferHeight = StandardDepthBufferHeight;
BufferWidthM1 = DepthBufferWidth - 1;
BufferHeightM1 = DepthBufferHeight - 1;
}
}
void CSoftwareGL::SwapBuffers(HDC hDC)
{
if(StandardColorBuffer != NULL)
{
if(AntiAliasing)
{
if(AntiAliasingColorBuffer != NULL)
{
switch(AntiAliasing)
{
case ANTI_ALIASING_2X2: RunFunctionMultiThreadedAndWaitForCompletion(2); break;
case ANTI_ALIASING_3X3: RunFunctionMultiThreadedAndWaitForCompletion(3); break;
case ANTI_ALIASING_4X4: RunFunctionMultiThreadedAndWaitForCompletion(4); break;
}
}
}
StretchDIBits(hDC, 0, 0, Width, Height, 0, 0, Width, Height, StandardColorBuffer, &BitmapInfo, DIB_RGB_COLORS, SRCCOPY);
}
}
// ----------------------------------------------------------------------------------------------------------------------------
CSoftwareGLRenderer::CSoftwareGLRenderer()
{
RenderObject = true;
Texturing = true;
Lighting = true;
ShadowMapping = true;
DisplayShadowMap = true;
RotateLight = true;
}
CSoftwareGLRenderer::~CSoftwareGLRenderer()
{
}
bool CSoftwareGLRenderer::Init()
{
bool Error = false;
Error |= !Texture.LoadTexture("texture.jpg");
Error |= !Object.Load("Models\\Thor\\", "thor.obj");
if(Error)
{
return false;
}
Object.Rotate(-90.0f, vec3(0.0f, 1.0f, 0.0f));
Object.Scale(1.75f / (Object.Max.y - Object.Min.y));
Object.Translate(vec3(-(Object.Min.x + Object.Max.x) / 2.0f, -0.5f, -(Object.Min.z + Object.Max.z) / 2.0f));
Vertices = new CVertex[84];
int v = 0;
vec3 Offset = vec3(1.0, 0.0, 0.0);
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f,-0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f, 0.5f) + Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3(-1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 1.0f, 0.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f,-1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f,-0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f,-1.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 0.5f,-0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 0.5f, 0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(0.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3(-0.5f, 0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f, 0.5f) - Offset; Vertices[v].Color = vec3(1.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2(0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3(-5.0f,-0.5f, 5.0f); Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(-5.0f,-5.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 5.0f,-0.5f, 5.0f); Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2( 5.0f,-5.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 5.0f,-0.5f,-5.0f); Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 5.0f, 5.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 5.0f,-0.5f,-5.0f); Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 5.0f, 5.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-5.0f,-0.5f,-5.0f); Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(-5.0f, 5.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-5.0f,-0.5f, 5.0f); Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(-5.0f,-5.0f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.0f, 0.0f, 0.0f); Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 1.0f, 0.0f, 0.0f); Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 1.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 1.0f, 1.0f, 0.0f); Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 1.0f, 1.0f, 0.0f); Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 1.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 0.0f, 1.0f, 0.0f); Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 0.0f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3( 0.0f, 0.0f, 0.0f); Vertices[v].Color = vec3(1.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 0.0f, 0.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
for(int i = 0; i < 78; i++)
{
Vertices[i].Color = vec3(1.0f);
}
Light.Position = vec3(0.0f, 3.0f, 4.0f) * 0.875f;
Light.Ambient = vec3(0.25f, 0.25f, 0.25f);
Light.Diffuse = vec3(0.75f, 0.75f, 0.75f);
Light.ConstantAttenuation = 1.0f;
Light.LinearAttenuation = 0.0f;
Light.QuadraticAttenuation = 0.0f;
LightProjectionMatrix = perspective(45.0f, 1.0f, 2.85f, 8.5f);
ShadowMap.Create(512, 512, TEXTURE_FORMAT_DEPTH16);
FrameBuffer.SetDepthTexture(&ShadowMap);
RenderShadowMap();
OrthogonalProjectionMatrix = ortho(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
return true;
}
void CSoftwareGLRenderer::Animate(float FrameTime)
{
if(RotateLight)
{
Light.Position = rotate(Light.Position, 11.25f * FrameTime, vec3(0.0f, 1.0f, 0.0f));
RenderShadowMap();
}
}
void CSoftwareGLRenderer::Render()
{
Clear();
LoadModelViewProjectionMatrix(Camera.ViewProjectionMatrix);
if(Lighting)
{
BindLight(&Light);
if(ShadowMapping)
{
LoadShadowMapMatrix(BiasMatrix * LightViewProjectionMatrix);
BindShadowMap(&ShadowMap);
}
}
if(Texturing)
{
BindTexture(&Texture);
}
DrawTriangles(Vertices, 0, 78);
if(RenderObject)
{
if(Texturing)
{
BindTexture(&Object.Texture);
}
DrawTriangles(Object.Vertices, 0, Object.VerticesCount);
}
if(Texturing)
{
BindTexture(NULL);
}
if(Lighting)
{
if(ShadowMapping)
{
BindShadowMap(NULL);
}
BindLight(NULL);
}
if(DisplayShadowMap)
{
LoadModelViewProjectionMatrix(OrthogonalProjectionMatrix);
Viewport(16, 16, 256, 256);
BindTexture(&ShadowMap);
SetDepthTest(false);
DrawTriangles(Vertices, 78, 6);
SetDepthTest(true);
BindTexture(NULL);
Viewport(0, 0, Width, Height);
}
}
void CSoftwareGLRenderer::Resize(int Width, int Height)
{
this->Width = Width;
this->Height = Height;
Viewport(0, 0, Width, Height);
Camera.SetPerspective(45.0f, (float)Width / (float)Height, 0.125f, 512.0f);
}
void CSoftwareGLRenderer::Destroy()
{
Texture.Destroy();
Object.Destroy();
delete [] Vertices;
ShadowMap.Destroy();
}
void CSoftwareGLRenderer::RenderShadowMap()
{
if((Lighting && ShadowMapping) || DisplayShadowMap)
{
LightViewMatrix = look(Light.Position, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f));
LightViewProjectionMatrix = LightProjectionMatrix * LightViewMatrix;
BindFrameBuffer(&FrameBuffer);
Viewport(0, 0, ShadowMap.GetWidth(), ShadowMap.GetHeight());
Clear();
LoadModelViewProjectionMatrix(LightViewProjectionMatrix);
SetCullFace(CULL_FACE_FRONT);
DrawTriangles(Vertices, 0, 78);
if(RenderObject)
{
DrawTriangles(Object.Vertices, 0, Object.VerticesCount);
}
SetCullFace(CULL_FACE_BACK);
Viewport(0, 0, Width, Height);
BindFrameBuffer(NULL);
}
}
void CSoftwareGLRenderer::CheckCameraKeys(float FrameTime)
{
BYTE Keys = 0x00;
if(GetKeyState('W') & 0x80) Keys |= 0x01;
if(GetKeyState('S') & 0x80) Keys |= 0x02;
if(GetKeyState('A') & 0x80) Keys |= 0x04;
if(GetKeyState('D') & 0x80) Keys |= 0x08;
if(GetKeyState('R') & 0x80) Keys |= 0x10;
if(GetKeyState('F') & 0x80) Keys |= 0x20;
if(GetKeyState(VK_SHIFT) & 0x80) Keys |= 0x40;
if(GetKeyState(VK_CONTROL) & 0x80) Keys |= 0x80;
if(Keys & 0x3F)
{
Camera.Move(Camera.OnKeys(Keys, FrameTime));
}
}
void CSoftwareGLRenderer::OnKeyDown(UINT Key)
{
switch(Key)
{
case VK_F2:
SetBilinearTextureFiltering(!GetBilinearTextureFiltering());
break;
case '1':
SetAntiAliasing(NONE);
break;
case '2':
SetAntiAliasing(ANTI_ALIASING_2X2);
break;
case '3':
SetAntiAliasing(ANTI_ALIASING_3X3);
break;
case '4':
SetAntiAliasing(ANTI_ALIASING_4X4);
break;
case 'O':
RenderObject = !RenderObject;
if(!RotateLight) RenderShadowMap();
break;
case 'T':
Texturing = !Texturing;
break;
case 'L':
Lighting = !Lighting;
if(!RotateLight) RenderShadowMap();
break;
case 'P':
ShadowMapping = !ShadowMapping;
if(!RotateLight) RenderShadowMap();
break;
case 'M':
DisplayShadowMap = !DisplayShadowMap;
if(!RotateLight) RenderShadowMap();
break;
case VK_SPACE:
RotateLight = !RotateLight;
break;
}
}
void CSoftwareGLRenderer::OnLButtonDown(int X, int Y)
{
LastClickedX = X;
LastClickedY = Y;
}
void CSoftwareGLRenderer::OnLButtonUp(int X, int Y)
{
if(X == LastClickedX && Y == LastClickedY)
{
}
}
void CSoftwareGLRenderer::OnMouseMove(int X, int Y)
{
if(GetKeyState(VK_RBUTTON) & 0x80)
{
Camera.OnMouseMove(LastX - X, LastY - Y);
}
LastX = X;
LastY = Y;
}
void CSoftwareGLRenderer::OnMouseWheel(short zDelta)
{
Camera.OnMouseWheel(zDelta);
}
void CSoftwareGLRenderer::OnRButtonDown(int X, int Y)
{
LastClickedX = X;
LastClickedY = Y;
}
void CSoftwareGLRenderer::OnRButtonUp(int X, int Y)
{
if(X == LastClickedX && Y == LastClickedY)
{
}
}
// ----------------------------------------------------------------------------------------------------------------------------
CSoftwareGLView::CSoftwareGLView()
{
char *moduledirectory = new char[256];
GetModuleFileName(GetModuleHandle(NULL), moduledirectory, 256);
*(strrchr(moduledirectory, '\\') + 1) = 0;
ModuleDirectory = moduledirectory;
delete [] moduledirectory;
}
CSoftwareGLView::~CSoftwareGLView()
{
}
bool CSoftwareGLView::Create(HINSTANCE hInstance, char *Title, int Width, int Height)
{
WNDCLASSEX WndClassEx;
memset(&WndClassEx, 0, sizeof(WNDCLASSEX));
WndClassEx.cbSize = sizeof(WNDCLASSEX);
WndClassEx.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
WndClassEx.lpfnWndProc = WndProc;
WndClassEx.hInstance = hInstance;
WndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClassEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
WndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClassEx.lpszClassName = "Win32OpenGLWindow";
if(RegisterClassEx(&WndClassEx) == 0)
{
ErrorLog.Set("RegisterClassEx failed!");
return false;
}
this->Title = Title;
this->Width = Width;
this->Height = Height;
DWORD Style = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
if((hWnd = CreateWindowEx(WS_EX_APPWINDOW, WndClassEx.lpszClassName, Title, Style, 0, 0, Width, Height, NULL, NULL, hInstance, NULL)) == NULL)
{
ErrorLog.Set("CreateWindowEx failed!");
return false;
}
if((hDC = GetDC(hWnd)) == NULL)
{
ErrorLog.Set("GetDC failed!");
return false;
}
return SoftwareGLRenderer.Init();
}
void CSoftwareGLView::Show(bool Maximized)
{
RECT dRect, wRect, cRect;
GetWindowRect(GetDesktopWindow(), &dRect);
GetWindowRect(hWnd, &wRect);
GetClientRect(hWnd, &cRect);
wRect.right += Width - cRect.right;
wRect.bottom += Height - cRect.bottom;
wRect.right -= wRect.left;
wRect.bottom -= wRect.top;
wRect.left = dRect.right / 2 - wRect.right / 2;
wRect.top = dRect.bottom / 2 - wRect.bottom / 2;
MoveWindow(hWnd, wRect.left, wRect.top, wRect.right, wRect.bottom, FALSE);
ShowWindow(hWnd, Maximized ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL);
}
void CSoftwareGLView::MsgLoop()
{
MSG Msg;
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
void CSoftwareGLView::Destroy()
{
SoftwareGLRenderer.Destroy();
DestroyWindow(hWnd);
}
void CSoftwareGLView::OnKeyDown(UINT Key)
{
switch(Key)
{
case '5':
ShowWindow(hWnd, SW_HIDE);
Width = 400;
Height = 300;
Show();
break;
case '6':
ShowWindow(hWnd, SW_HIDE);
Width = 512;
Height = 384;
Show();
break;
case '7':
ShowWindow(hWnd, SW_HIDE);
Width = 640;
Height = 480;
Show();
break;
case '8':
ShowWindow(hWnd, SW_HIDE);
Width = 800;
Height = 600;
Show();
break;
case '9':
ShowWindow(hWnd, SW_HIDE);
Width = 1024;
Height = 768;
Show();
break;
case '0':
ShowWindow(hWnd, SW_HIDE);
Width = 1280;
Height = 800;
Show();
break;
}
SoftwareGLRenderer.OnKeyDown(Key);
}
void CSoftwareGLView::OnLButtonDown(int X, int Y)
{
SoftwareGLRenderer.OnLButtonDown(X, Y);
}
void CSoftwareGLView::OnLButtonUp(int X, int Y)
{
SoftwareGLRenderer.OnLButtonUp(X, Y);
}
void CSoftwareGLView::OnMouseMove(int X, int Y)
{
SoftwareGLRenderer.OnMouseMove(X, Y);
}
void CSoftwareGLView::OnMouseWheel(short zDelta)
{
SoftwareGLRenderer.OnMouseWheel(zDelta);
}
void CSoftwareGLView::OnPaint()
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
static DWORD LastFPSTime = GetTickCount(), LastFrameTime = LastFPSTime;
static int FPS = 0;
DWORD Time = GetTickCount();
float FrameTime = (Time - LastFrameTime) * 0.001f;
LastFrameTime = Time;
if(Time - LastFPSTime > 1000)
{
CString Text = Title;
Text.Append(" - %dx%d", Width, Height);
Text.Append(", BTF: "); if(SoftwareGLRenderer.GetBilinearTextureFiltering()) Text.Append("ON"); else Text.Append("OFF");
if(SoftwareGLRenderer.GetAntiAliasing() == NONE) Text.Append(", AA: OFF");
else if(SoftwareGLRenderer.GetAntiAliasing() == ANTI_ALIASING_2X2) Text.Append(", AA: 4x");
else if(SoftwareGLRenderer.GetAntiAliasing() == ANTI_ALIASING_3X3) Text.Append(", AA: 9x");
else if(SoftwareGLRenderer.GetAntiAliasing() == ANTI_ALIASING_4X4) Text.Append(", AA: 16x");
Text.Append(", Threads: %d", SoftwareGLRenderer.GetThreadsCount());
Text.Append(", FPS: %d", FPS);
SetWindowText(hWnd, Text);
LastFPSTime = Time;
FPS = 0;
}
else
{
FPS++;
}
SoftwareGLRenderer.CheckCameraKeys(FrameTime);
SoftwareGLRenderer.Animate(FrameTime);
SoftwareGLRenderer.Render();
SoftwareGLRenderer.SwapBuffers(hDC);
EndPaint(hWnd, &ps);
InvalidateRect(hWnd, NULL, FALSE);
}
void CSoftwareGLView::OnRButtonDown(int X, int Y)
{
SoftwareGLRenderer.OnRButtonDown(X, Y);
}
void CSoftwareGLView::OnRButtonUp(int X, int Y)
{
SoftwareGLRenderer.OnRButtonUp(X, Y);
}
void CSoftwareGLView::OnSize(int Width, int Height)
{
this->Width = Width;
this->Height = Height;
SoftwareGLRenderer.ResizeBuffers(Width, Height);
SoftwareGLRenderer.Resize(Width, Height);
}
// ----------------------------------------------------------------------------------------------------------------------------
CSoftwareGLView SoftwareGLView;
// ----------------------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch(uiMsg)
{
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
SoftwareGLView.OnKeyDown((UINT)wParam);
break;
case WM_LBUTTONDOWN:
SoftwareGLView.OnLButtonDown(LOWORD(lParam), HIWORD(lParam));
break;
case WM_LBUTTONUP:
SoftwareGLView.OnLButtonUp(LOWORD(lParam), HIWORD(lParam));
break;
case WM_MOUSEMOVE:
SoftwareGLView.OnMouseMove(LOWORD(lParam), HIWORD(lParam));
break;
case WM_MOUSWHEEL:
SoftwareGLView.OnMouseWheel(HIWORD(wParam));
break;
case WM_PAINT:
SoftwareGLView.OnPaint();
break;
case WM_RBUTTONDOWN:
SoftwareGLView.OnRButtonDown(LOWORD(lParam), HIWORD(lParam));
break;
case WM_RBUTTONUP:
SoftwareGLView.OnRButtonUp(LOWORD(lParam), HIWORD(lParam));
break;
case WM_SIZE:
SoftwareGLView.OnSize(LOWORD(lParam), HIWORD(lParam));
break;
default:
return DefWindowProc(hWnd, uiMsg, wParam, lParam);
}
return 0;
}
// ----------------------------------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR sCmdLine, int iShow)
{
if(SoftwareGLView.Create(hInstance, "Software shadow mapping", 800, 600))
{
SoftwareGLView.Show();
SoftwareGLView.MsgLoop();
}
else
{
MessageBox(NULL, ErrorLog, "Error", MB_OK | MB_ICONERROR);
}
SoftwareGLView.Destroy();
return 0;
}
// ----------------------------------------------------------------------------------------------------------------------------
Download
|