3D C/C++ tutorials -> Software rendering -> Simple software renderer
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.
simple_software_renderer_multithreading_v1.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:
FIBITMAP *DIB;
BYTE *Bits;
private:
int Width, Height, Pitch, BPP;
public:
CTexture();
~CTexture();
private:
void SetDefaults();
public:
bool LoadTexture(char *TextureFileName);
void GetColorNearest(float s, float t, float *r, float *g, float *b);
void GetColorBilinear(float s, float t, float *r, float *g, float *b);
void Destroy();
};
// ----------------------------------------------------------------------------------------------------------------------------
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:
float x, y, z, w, r, g, b, s, t;
};
// ----------------------------------------------------------------------------------------------------------------------------
class CEdge
{
public:
CFragment *Fragment1, *Fragment2;
public:
float dx, dy, dz, dw, dr, dg, db, ds, dt;
public:
void Set(CFragment *Fragment1, CFragment *Fragment2);
private:
void CalculateDiffs();
};
// ----------------------------------------------------------------------------------------------------------------------------
class CSpan
{
public:
CFragment *Fragment1, *Fragment2;
public:
float dx, dy, dz, dw, dr, dg, db, ds, dt;
public:
void Set(CFragment *Fragment1, CFragment *Fragment2);
private:
void CalculateDiffs();
};
// ----------------------------------------------------------------------------------------------------------------------------
#define NONE 0x00
#define CULL_FACE_FRONT 0x01
#define CULL_FACE_BACK 0x02
#define ANTI_ALIASING_2X2 0x03
#define ANTI_ALIASING_3X3 0x04
#define ANTI_ALIASING_4X4 0x05
// ----------------------------------------------------------------------------------------------------------------------------
#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:
BYTE *AntiAliasingColorBuffer;
int AntiAliasingColorBufferWidth, AntiAliasingColorBufferHeight;
private:
BYTE *StandardColorBuffer;
int StandardColorBufferWidth, StandardColorBufferHeight;
BITMAPINFO StandardColorBufferInfo;
private:
BYTE *ColorBuffer;
int ColorBufferWidth, ColorBufferHeight;
private:
USHORT *DepthBuffer;
int DepthBufferWidth, DepthBufferHeight;
private:
int AntiAliasing;
mat4x4 ModelViewProjectionMatrix;
CLight *Light;
int CullFace;
bool BilinearTextureFiltering;
CTexture *Texture;
private:
CVertex *Vertices;
int FirstIndex, LastIndex;
private:
CThreadData *ThreadsData;
int ThreadsCount;
public:
CSoftwareGL();
~CSoftwareGL();
public:
int GetAntiAliasing();
void SetAntiAliasing(int AntiAliasing);
int GetCullFace();
void SetCullFace(int CullFace);
bool GetBilinearTextureFiltering();
void SetBilinearTextureFiltering(bool BilinearTextureFiltering);
public:
int GetThreadsCount();
public:
void Clear();
void LoadModelViewProjectionMatrix(const mat4x4 &ModelViewProjectionMatrix);
void BindLight(CLight *Light);
void BindTexture(CTexture *Texture);
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 Viewport(int Width, int Height);
void SwapBuffers(HDC hDC);
};
// ----------------------------------------------------------------------------------------------------------------------------
class CSoftwareGLRenderer : public CSoftwareGL
{
private:
int LastX, LastY, LastClickedX, LastClickedY;
private:
CCamera Camera;
private:
CTexture Texture;
private:
CVertex *Vertices;
private:
CObject Object[3];
private:
int RenderObject;
private:
bool Lighting, Texturing;
private:
CLight Light;
public:
CSoftwareGLRenderer();
~CSoftwareGLRenderer();
public:
bool Init();
void Render(float FrameTime);
void Resize(int Width, int Height);
void Destroy();
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);
// ----------------------------------------------------------------------------------------------------------------------------
simple_software_renderer_multithreading_v1.cpp
// ----------------------------------------------------------------------------------------------------------------------------
#include "simple_software_renderer_multithreading_v1.h"
// ----------------------------------------------------------------------------------------------------------------------------
CString ErrorLog, ModuleDirectory;
// ----------------------------------------------------------------------------------------------------------------------------
CTexture::CTexture()
{
SetDefaults();
}
CTexture::~CTexture()
{
}
void CTexture::SetDefaults()
{
DIB = NULL;
Bits = NULL;
Width = 0;
Height = 0;
Pitch = 0;
BPP = 0;
}
bool CTexture::LoadTexture(char *TextureFileName)
{
CString FileName = ModuleDirectory + TextureFileName;
CString ErrorText = "Error loading file " + FileName + " -> ";
Destroy();
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;
}
if(FreeImage_FIFSupportsReading(FIF))
{
DIB = FreeImage_Load(FIF, FileName);
}
if(DIB == NULL)
{
ErrorLog.Append(ErrorText + "DIB is NULL!" + "\r\n");
return false;
}
Width = FreeImage_GetWidth(DIB);
Height = FreeImage_GetHeight(DIB);
Pitch = FreeImage_GetPitch(DIB);
BPP = FreeImage_GetBPP(DIB);
if(Width == 0 || Height == 0)
{
ErrorLog.Append(ErrorText + "Width or Height is 0!" + "\r\n");
Destroy();
return false;
}
if(BPP != 24 && BPP != 32)
{
ErrorLog.Append(ErrorText + "BPP is not 24 nor 32!" + "\r\n");
Destroy();
return false;
}
BPP /= 8;
Bits = FreeImage_GetBits(DIB);
if(Bits == NULL)
{
ErrorLog.Append(ErrorText + "Bits is NULL!" + "\r\n");
Destroy();
return false;
}
return true;
}
float OD255 = 1.0f / 255.0f;
void CTexture::GetColorNearest(float s, float t, float *r, float *g, float *b)
{
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);
BYTE *A = Bits + Pitch * y + BPP * x;
*b = *A * OD255;
A++;
*g = *A * OD255;
A++;
*r = *A * OD255;
}
else
{
*r = *g = *b = 1.0f;
}
}
void CTexture::GetColorBilinear(float s, float t, float *r, float *g, float *b)
{
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;
BYTE *LineAB = Bits + Pitch * y0;
BYTE *LineCD = Bits + Pitch * y1;
int BPPMx0 = BPP * x0, BPPMx1 = BPP * x1;
BYTE *A = LineAB + BPPMx0;
BYTE *B = LineAB + BPPMx1;
BYTE *C = LineCD + BPPMx1;
BYTE *D = LineCD + BPPMx0;
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;
*b = *A * u0v0 + *B * u1v0 + *C * u1v1 + *D * u0v1;
A++; B++; C++; D++;
*g = *A * u0v0 + *B * u1v0 + *C * u1v1 + *D * u0v1;
A++; B++; C++; D++;
*r = *A * u0v0 + *B * u1v0 + *C * u1v1 + *D * u0v1;
}
else
{
*r = *g = *b = 1.0f;
}
}
void CTexture::Destroy()
{
if(DIB != NULL)
{
FreeImage_Unload(DIB);
}
SetDefaults();
}
// ----------------------------------------------------------------------------------------------------------------------------
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->y <= Fragment2->y)
{
this->Fragment1 = Fragment1;
this->Fragment2 = Fragment2;
}
else
{
this->Fragment1 = Fragment2;
this->Fragment2 = Fragment1;
}
CalculateDiffs();
}
void CEdge::CalculateDiffs()
{
dx = Fragment2->x - Fragment1->x;
dy = Fragment2->y - Fragment1->y;
dz = Fragment2->z - Fragment1->z;
dw = Fragment2->w - Fragment1->w;
dr = Fragment2->r - Fragment1->r;
dg = Fragment2->g - Fragment1->g;
db = Fragment2->b - Fragment1->b;
ds = Fragment2->s - Fragment1->s;
dt = Fragment2->t - Fragment1->t;
}
// ----------------------------------------------------------------------------------------------------------------------------
void CSpan::Set(CFragment *Fragment1, CFragment *Fragment2)
{
if(Fragment1->x <= Fragment2->x)
{
this->Fragment1 = Fragment1;
this->Fragment2 = Fragment2;
}
else
{
this->Fragment1 = Fragment2;
this->Fragment2 = Fragment1;
}
CalculateDiffs();
}
void CSpan::CalculateDiffs()
{
dx = Fragment2->x - Fragment1->x;
dy = Fragment2->y - Fragment1->y;
dz = Fragment2->z - Fragment1->z;
dw = Fragment2->w - Fragment1->w;
dr = Fragment2->r - Fragment1->r;
dg = Fragment2->g - Fragment1->g;
db = Fragment2->b - Fragment1->b;
ds = Fragment2->s - Fragment1->s;
dt = Fragment2->t - Fragment1->t;
}
// ----------------------------------------------------------------------------------------------------------------------------
CSoftwareGL::CSoftwareGL()
{
Width = 0;
Height = 0;
AntiAliasingColorBuffer = NULL;
AntiAliasingColorBufferWidth = 0;
AntiAliasingColorBufferHeight = 0;
StandardColorBuffer = NULL;
StandardColorBufferWidth = 0;
StandardColorBufferHeight = 0;
ColorBuffer = NULL;
ColorBufferWidth = 0;
ColorBufferHeight = 0;
DepthBuffer = NULL;
DepthBufferWidth = 0;
DepthBufferHeight = 0;
AntiAliasing = ANTI_ALIASING_2X2;
ModelViewProjectionMatrix = mat4x4(1.0f);
CullFace = CULL_FACE_BACK;
BilinearTextureFiltering = true;
Light = NULL;
Texture = NULL;
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
ThreadsCount = SystemInfo.dwNumberOfProcessors;
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(DepthBuffer != NULL)
{
delete [] DepthBuffer;
}
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;
Viewport(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;
}
int CSoftwareGL::GetThreadsCount()
{
return ThreadsCount;
}
void CSoftwareGL::Clear()
{
if(ColorBuffer != NULL)
{
memset(ColorBuffer, 0, ColorBufferWidth * ColorBufferHeight * 3);
}
if(DepthBuffer != NULL)
{
memset(DepthBuffer, 255, DepthBufferWidth * DepthBufferHeight * 2);
}
}
void CSoftwareGL::LoadModelViewProjectionMatrix(const mat4x4 &ModelViewProjectionMatrix)
{
this->ModelViewProjectionMatrix = ModelViewProjectionMatrix;
}
void CSoftwareGL::BindLight(CLight *Light)
{
this->Light = Light;
}
void CSoftwareGL::BindTexture(CTexture *Texture)
{
this->Texture = Texture;
}
void CSoftwareGL::DrawTriangles(CVertex *Vertices, int FirstIndex, int Count)
{
if(ColorBuffer == NULL || DepthBuffer == NULL || Vertices == NULL || FirstIndex < 0 || Count < 3) return;
this->Vertices = Vertices;
this->FirstIndex = FirstIndex;
this->LastIndex = FirstIndex + Count / 3 * 3;
RunFunctionMultiThreadedAndWaitForCompletion(1);
}
void CSoftwareGL::RunFunctionMultiThreadedAndWaitForCompletion(int Function)
{
for(int i = 0; i < ThreadsCount; i++)
{
ThreadsData[i].Function = Function;
ThreadsData[i].ThreadIsRunning = true;
}
while(ThreadsAreRunning())
{
Sleep(THREAD_SLEEP_TIME);
}
}
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)
{
Sleep(THREAD_SLEEP_TIME);
}
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;
// 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->x = ModelViewProjectionMatrix[0] * Vertex->Position.x + ModelViewProjectionMatrix[4] * Vertex->Position.y + ModelViewProjectionMatrix[8] * Vertex->Position.z + ModelViewProjectionMatrix[12];
Fragment->y = ModelViewProjectionMatrix[1] * Vertex->Position.x + ModelViewProjectionMatrix[5] * Vertex->Position.y + ModelViewProjectionMatrix[9] * Vertex->Position.z + ModelViewProjectionMatrix[13];
Fragment->z = ModelViewProjectionMatrix[2] * Vertex->Position.x + ModelViewProjectionMatrix[6] * Vertex->Position.y + ModelViewProjectionMatrix[10] * Vertex->Position.z + ModelViewProjectionMatrix[14];
Fragment->w = ModelViewProjectionMatrix[3] * Vertex->Position.x + ModelViewProjectionMatrix[7] * Vertex->Position.y + ModelViewProjectionMatrix[11] * Vertex->Position.z + ModelViewProjectionMatrix[15];
Fragment->r = Vertex->Color.r;
Fragment->g = Vertex->Color.g;
Fragment->b = Vertex->Color.b;
Fragment->s = Vertex->TexCoord.s;
Fragment->t = Vertex->TexCoord.t;
if(Light != NULL)
{
vec3 LightDirection;
LightDirection.x = Light->Position.x - Vertex->Position.x;
LightDirection.y = Light->Position.y - Vertex->Position.y;
LightDirection.z = Light->Position.z - Vertex->Position.z;
float LightDistance2 = LightDirection.x * LightDirection.x + LightDirection.y * LightDirection.y + LightDirection.z * LightDirection.z;
float LightDistance = sqrt(LightDistance2);
float NdotLD = (LightDirection.x * Vertex->Normal.x + LightDirection.y * Vertex->Normal.y + LightDirection.z * Vertex->Normal.z) / LightDistance;
if(NdotLD < 0.0f) NdotLD = 0.0f;
float LightAttenuation = 1.0f / (Light->ConstantAttenuation + Light->LinearAttenuation * LightDistance + Light->QuadraticAttenuation * LightDistance2);
Fragment->r *= (Light->Ambient.r + Light->Diffuse.r * NdotLD) * LightAttenuation;
Fragment->g *= (Light->Ambient.g + Light->Diffuse.g * NdotLD) * LightAttenuation;
Fragment->b *= (Light->Ambient.b + Light->Diffuse.b * NdotLD) * LightAttenuation;
}
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->w <= Fragment->x; break;
case 2: Visible = Fragment->x <= Fragment->w; break;
case 3: Visible = -Fragment->w <= Fragment->y; break;
case 4: Visible = Fragment->y <= Fragment->w; break;
case 5: Visible = -Fragment->w <= Fragment->z; break;
case 6: Visible = Fragment->z <= Fragment->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->x + Fragment1->w) / (Fragment1->x - Fragment3->x + Fragment1->w - Fragment3->w);
t2 = (Fragment2->x + Fragment2->w) / (Fragment2->x - Fragment3->x + Fragment2->w - Fragment3->w);
break;
case 2:
t1 = (Fragment1->x - Fragment1->w) / (Fragment1->x - Fragment3->x - Fragment1->w + Fragment3->w);
t2 = (Fragment2->x - Fragment2->w) / (Fragment2->x - Fragment3->x - Fragment2->w + Fragment3->w);
break;
case 3:
t1 = (Fragment1->y + Fragment1->w) / (Fragment1->y - Fragment3->y + Fragment1->w - Fragment3->w);
t2 = (Fragment2->y + Fragment2->w) / (Fragment2->y - Fragment3->y + Fragment2->w - Fragment3->w);
break;
case 4:
t1 = (Fragment1->y - Fragment1->w) / (Fragment1->y - Fragment3->y - Fragment1->w + Fragment3->w);
t2 = (Fragment2->y - Fragment2->w) / (Fragment2->y - Fragment3->y - Fragment2->w + Fragment3->w);
break;
case 5:
t1 = (Fragment1->z + Fragment1->w) / (Fragment1->z - Fragment3->z + Fragment1->w - Fragment3->w);
t2 = (Fragment2->z + Fragment2->w) / (Fragment2->z - Fragment3->z + Fragment2->w - Fragment3->w);
break;
case 6:
t1 = (Fragment1->z - Fragment1->w) / (Fragment1->z - Fragment3->z - Fragment1->w + Fragment3->w);
t2 = (Fragment2->z - Fragment2->w) / (Fragment2->z - Fragment3->z - Fragment2->w + Fragment3->w);
break;
}
Fragment1->x += (Fragment3->x - Fragment1->x) * t1;
Fragment1->y += (Fragment3->y - Fragment1->y) * t1;
Fragment1->z += (Fragment3->z - Fragment1->z) * t1;
Fragment1->w += (Fragment3->w - Fragment1->w) * t1;
Fragment1->r += (Fragment3->r - Fragment1->r) * t1;
Fragment1->g += (Fragment3->g - Fragment1->g) * t1;
Fragment1->b += (Fragment3->b - Fragment1->b) * t1;
Fragment1->s += (Fragment3->s - Fragment1->s) * t1;
Fragment1->t += (Fragment3->t - Fragment1->t) * t1;
Fragment2->x += (Fragment3->x - Fragment2->x) * t2;
Fragment2->y += (Fragment3->y - Fragment2->y) * t2;
Fragment2->z += (Fragment3->z - Fragment2->z) * t2;
Fragment2->w += (Fragment3->w - Fragment2->w) * t2;
Fragment2->r += (Fragment3->r - Fragment2->r) * t2;
Fragment2->g += (Fragment3->g - Fragment2->g) * t2;
Fragment2->b += (Fragment3->b - Fragment2->b) * t2;
Fragment2->s += (Fragment3->s - Fragment2->s) * t2;
Fragment2->t += (Fragment3->t - Fragment2->t) * 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->x + Fragment3->w) / (Fragment3->x - Fragment1->x + Fragment3->w - Fragment1->w);
t2 = (Fragment3->x + Fragment3->w) / (Fragment3->x - Fragment2->x + Fragment3->w - Fragment2->w);
break;
case 2:
t1 = (Fragment3->x - Fragment3->w) / (Fragment3->x - Fragment1->x - Fragment3->w + Fragment1->w);
t2 = (Fragment3->x - Fragment3->w) / (Fragment3->x - Fragment2->x - Fragment3->w + Fragment2->w);
break;
case 3:
t1 = (Fragment3->y + Fragment3->w) / (Fragment3->y - Fragment1->y + Fragment3->w - Fragment1->w);
t2 = (Fragment3->y + Fragment3->w) / (Fragment3->y - Fragment2->y + Fragment3->w - Fragment2->w);
break;
case 4:
t1 = (Fragment3->y - Fragment3->w) / (Fragment3->y - Fragment1->y - Fragment3->w + Fragment1->w);
t2 = (Fragment3->y - Fragment3->w) / (Fragment3->y - Fragment2->y - Fragment3->w + Fragment2->w);
break;
case 5:
t1 = (Fragment3->z + Fragment3->w) / (Fragment3->z - Fragment1->z + Fragment3->w - Fragment1->w);
t2 = (Fragment3->z + Fragment3->w) / (Fragment3->z - Fragment2->z + Fragment3->w - Fragment2->w);
break;
case 6:
t1 = (Fragment3->z - Fragment3->w) / (Fragment3->z - Fragment1->z - Fragment3->w + Fragment1->w);
t2 = (Fragment3->z - Fragment3->w) / (Fragment3->z - Fragment2->z - Fragment3->w + Fragment2->w);
break;
}
NewFragment3->x = Fragment3->x;
NewFragment3->y = Fragment3->y;
NewFragment3->z = Fragment3->z;
NewFragment3->w = Fragment3->w;
NewFragment3->r = Fragment3->r;
NewFragment3->g = Fragment3->g;
NewFragment3->b = Fragment3->b;
NewFragment3->s = Fragment3->s;
NewFragment3->t = Fragment3->t;
NewFragment2->x = Fragment2->x;
NewFragment2->y = Fragment2->y;
NewFragment2->z = Fragment2->z;
NewFragment2->w = Fragment2->w;
NewFragment2->r = Fragment2->r;
NewFragment2->g = Fragment2->g;
NewFragment2->b = Fragment2->b;
NewFragment2->s = Fragment2->s;
NewFragment2->t = Fragment2->t;
Fragment3->x += (Fragment1->x - Fragment3->x) * t1;
Fragment3->y += (Fragment1->y - Fragment3->y) * t1;
Fragment3->z += (Fragment1->z - Fragment3->z) * t1;
Fragment3->w += (Fragment1->w - Fragment3->w) * t1;
Fragment3->r += (Fragment1->r - Fragment3->r) * t1;
Fragment3->g += (Fragment1->g - Fragment3->g) * t1;
Fragment3->b += (Fragment1->b - Fragment3->b) * t1;
Fragment3->s += (Fragment1->s - Fragment3->s) * t1;
Fragment3->t += (Fragment1->t - Fragment3->t) * t1;
NewFragment1->x = Fragment3->x;
NewFragment1->y = Fragment3->y;
NewFragment1->z = Fragment3->z;
NewFragment1->w = Fragment3->w;
NewFragment1->r = Fragment3->r;
NewFragment1->g = Fragment3->g;
NewFragment1->b = Fragment3->b;
NewFragment1->s = Fragment3->s;
NewFragment1->t = Fragment3->t;
NewFragment3->x += (NewFragment2->x - NewFragment3->x) * t2;
NewFragment3->y += (NewFragment2->y - NewFragment3->y) * t2;
NewFragment3->z += (NewFragment2->z - NewFragment3->z) * t2;
NewFragment3->w += (NewFragment2->w - NewFragment3->w) * t2;
NewFragment3->r += (NewFragment2->r - NewFragment3->r) * t2;
NewFragment3->g += (NewFragment2->g - NewFragment3->g) * t2;
NewFragment3->b += (NewFragment2->b - NewFragment3->b) * t2;
NewFragment3->s += (NewFragment2->s - NewFragment3->s) * t2;
NewFragment3->t += (NewFragment2->t - NewFragment3->t) * 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->w = 1.0f / Fragment1->w;
Fragment1->x *= Fragment1->w;
Fragment1->y *= Fragment1->w;
Fragment2->w = 1.0f / Fragment2->w;
Fragment2->x *= Fragment2->w;
Fragment2->y *= Fragment2->w;
Fragment3->w = 1.0f / Fragment3->w;
Fragment3->x *= Fragment3->w;
Fragment3->y *= Fragment3->w;
// culling
if(CullFace)
{
float a = 0.0f;
a += Fragment1->x * Fragment2->y - Fragment2->x * Fragment1->y;
a += Fragment2->x * Fragment3->y - Fragment3->x * Fragment2->y;
a += Fragment3->x * Fragment1->y - Fragment1->x * Fragment3->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->x = (Fragment1->x * 0.5f + 0.5f) * DepthBufferWidth;
Fragment1->y = (Fragment1->y * 0.5f + 0.5f) * DepthBufferHeight;
Fragment1->z = Fragment1->z * Fragment1->w * 0.5f + 0.5f;
Fragment1->r *= Fragment1->w;
Fragment1->g *= Fragment1->w;
Fragment1->b *= Fragment1->w;
Fragment1->s *= Fragment1->w;
Fragment1->t *= Fragment1->w;
Fragment2->x = (Fragment2->x * 0.5f + 0.5f) * DepthBufferWidth;
Fragment2->y = (Fragment2->y * 0.5f + 0.5f) * DepthBufferHeight;
Fragment2->z = Fragment2->z * Fragment2->w * 0.5f + 0.5f;
Fragment2->r *= Fragment2->w;
Fragment2->g *= Fragment2->w;
Fragment2->b *= Fragment2->w;
Fragment2->s *= Fragment2->w;
Fragment2->t *= Fragment2->w;
Fragment3->x = (Fragment3->x * 0.5f + 0.5f) * DepthBufferWidth;
Fragment3->y = (Fragment3->y * 0.5f + 0.5f) * DepthBufferHeight;
Fragment3->z = Fragment3->z * Fragment3->w * 0.5f + 0.5f;
Fragment3->r *= Fragment3->w;
Fragment3->g *= Fragment3->w;
Fragment3->b *= Fragment3->w;
Fragment3->s *= Fragment3->w;
Fragment3->t *= Fragment3->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);
CEdge *LongEdge = Edge1, *ShortEdge1 = Edge2, *ShortEdge2 = Edge3;
if(Edge2->dy > LongEdge->dy)
{
LongEdge = Edge2;
ShortEdge1 = Edge3;
ShortEdge2 = Edge1;
}
if(Edge3->dy > LongEdge->dy)
{
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->dy == 0.0f || Edge2->dy == 0.0f) return;
int iy1 = (int)Edge2->Fragment1->y, iy2 = (int)Edge2->Fragment2->y;
while(iy1 % ThreadsCount != ThreadId) iy1++;
if(iy2 == DepthBufferHeight) iy2--;
float fy, factor1, factor2, ode1dy = 1.0f / Edge1->dy, ode2dy = 1.0f / Edge2->dy;
CFragment Fragment1, Fragment2;
CSpan Span;
for(int y = iy1; y <= iy2; y += ThreadsCount)
{
fy = y + 0.5f;
factor1 = (fy - Edge1->Fragment1->y) * ode1dy;
if(factor1 < 0.0f || factor1 > 1.0f) continue;
factor2 = (fy - Edge2->Fragment1->y) * ode2dy;
if(factor2 < 0.0f || factor2 > 1.0f) continue;
Fragment1.x = Edge1->Fragment1->x + Edge1->dx * factor1;
Fragment1.y = Edge1->Fragment1->y + Edge1->dy * factor1;
Fragment1.z = Edge1->Fragment1->z + Edge1->dz * factor1;
Fragment1.w = Edge1->Fragment1->w + Edge1->dw * factor1;
Fragment1.r = Edge1->Fragment1->r + Edge1->dr * factor1;
Fragment1.g = Edge1->Fragment1->g + Edge1->dg * factor1;
Fragment1.b = Edge1->Fragment1->b + Edge1->db * factor1;
Fragment1.s = Edge1->Fragment1->s + Edge1->ds * factor1;
Fragment1.t = Edge1->Fragment1->t + Edge1->dt * factor1;
Fragment2.x = Edge2->Fragment1->x + Edge2->dx * factor2;
Fragment2.y = Edge2->Fragment1->y + Edge2->dy * factor2;
Fragment2.z = Edge2->Fragment1->z + Edge2->dz * factor2;
Fragment2.w = Edge2->Fragment1->w + Edge2->dw * factor2;
Fragment2.r = Edge2->Fragment1->r + Edge2->dr * factor2;
Fragment2.g = Edge2->Fragment1->g + Edge2->dg * factor2;
Fragment2.b = Edge2->Fragment1->b + Edge2->db * factor2;
Fragment2.s = Edge2->Fragment1->s + Edge2->ds * factor2;
Fragment2.t = Edge2->Fragment1->t + Edge2->dt * factor2;
Span.Set(&Fragment1, &Fragment2);
DrawSpan(&Span, y);
}
}
void CSoftwareGL::DrawSpan(CSpan *Span, int y)
{
if(Span->dx == 0.0f) return;
int ix1 = (int)Span->Fragment1->x, ix2 = (int)Span->Fragment2->x;
if(ix2 == DepthBufferWidth) ix2--;
float factor, odsdx = 1.0f / Span->dx, z, w, r, g, b, s, t, tr, tg, tb;
USHORT Depth;
int ColorBufferIndex = (ColorBufferWidth * y + ix1) * 3;
int DepthBufferIndex = DepthBufferWidth * y + ix1;
for(int x = ix1; x <= ix2; x++)
{
factor = (x + 0.5f - Span->Fragment1->x) * odsdx;
if(factor >= 0.0f && factor <= 1.0f)
{
z = Span->Fragment1->z + Span->dz * factor;
Depth = (USHORT)(z * 65535.0f);
// depth test
if(Depth <= DepthBuffer[DepthBufferIndex])
{
w = 1.0f / (Span->Fragment1->w + Span->dw * factor);
r = (Span->Fragment1->r + Span->dr * factor) * w;
g = (Span->Fragment1->g + Span->dg * factor) * w;
b = (Span->Fragment1->b + Span->db * factor) * w;
s = (Span->Fragment1->s + Span->ds * factor) * w;
t = (Span->Fragment1->t + Span->dt * factor) * w;
// fragment shader
if(Texture != NULL)
{
if(BilinearTextureFiltering)
{
Texture->GetColorBilinear(s, t, &tr, &tg, &tb);
}
else
{
Texture->GetColorNearest(s, t, &tr, &tg, &tb);
}
r *= tr;
g *= tg;
b *= tb;
}
// writing to buffers
ColorBuffer[ColorBufferIndex++] = /*b <= 0.0f ? 0 : b >= 1.0f ? 255 :*/ (BYTE)(b * 255.0f);
ColorBuffer[ColorBufferIndex++] = /*g <= 0.0f ? 0 : g >= 1.0f ? 255 :*/ (BYTE)(g * 255.0f);
ColorBuffer[ColorBufferIndex++] = /*r <= 0.0f ? 0 : r >= 1.0f ? 255 :*/ (BYTE)(r * 255.0f);
DepthBuffer[DepthBufferIndex++] = Depth;
}
else
{
ColorBufferIndex += 3;
DepthBufferIndex++;
}
}
else
{
ColorBufferIndex += 3;
DepthBufferIndex++;
}
}
}
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::Viewport(int Width, int Height)
{
this->Width = Width;
this->Height = Height;
if(AntiAliasingColorBuffer != NULL)
{
delete [] AntiAliasingColorBuffer;
AntiAliasingColorBuffer = NULL;
}
if(StandardColorBuffer != NULL)
{
delete [] StandardColorBuffer;
StandardColorBuffer = NULL;
}
if(DepthBuffer != NULL)
{
delete [] DepthBuffer;
DepthBuffer = NULL;
}
if(Width > 0 && Height > 0)
{
if(AntiAliasing)
{
switch(AntiAliasing)
{
case ANTI_ALIASING_2X2:
AntiAliasingColorBufferWidth = Width * 2;
AntiAliasingColorBufferHeight = Height * 2;
break;
case ANTI_ALIASING_3X3:
AntiAliasingColorBufferWidth = Width * 3;
AntiAliasingColorBufferHeight = Height * 3;
break;
case ANTI_ALIASING_4X4:
AntiAliasingColorBufferWidth = Width * 4;
AntiAliasingColorBufferHeight = Height * 4;
break;
}
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(&StandardColorBufferInfo, 0, sizeof(BITMAPINFO));
StandardColorBufferInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
StandardColorBufferInfo.bmiHeader.biPlanes = 1;
StandardColorBufferInfo.bmiHeader.biBitCount = 24;
StandardColorBufferInfo.bmiHeader.biCompression = BI_RGB;
StandardColorBufferInfo.bmiHeader.biWidth = StandardColorBufferWidth;
StandardColorBufferInfo.bmiHeader.biHeight = StandardColorBufferHeight;
switch(AntiAliasing)
{
case NONE:
DepthBufferWidth = Width;
DepthBufferHeight = Height;
break;
case ANTI_ALIASING_2X2:
DepthBufferWidth = Width * 2;
DepthBufferHeight = Height * 2;
break;
case ANTI_ALIASING_3X3:
DepthBufferWidth = Width * 3;
DepthBufferHeight = Height * 3;
break;
case ANTI_ALIASING_4X4:
DepthBufferWidth = Width * 4;
DepthBufferHeight = Height * 4;
break;
}
DepthBuffer = new USHORT[DepthBufferWidth * DepthBufferHeight];
}
if(AntiAliasing)
{
ColorBuffer = AntiAliasingColorBuffer;
ColorBufferWidth = AntiAliasingColorBufferWidth;
ColorBufferHeight = AntiAliasingColorBufferHeight;
}
else
{
ColorBuffer = StandardColorBuffer;
ColorBufferWidth = StandardColorBufferWidth;
ColorBufferHeight = StandardColorBufferHeight;
}
}
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, &StandardColorBufferInfo, DIB_RGB_COLORS, SRCCOPY);
}
}
// ----------------------------------------------------------------------------------------------------------------------------
CSoftwareGLRenderer::CSoftwareGLRenderer()
{
RenderObject = 3;
Lighting = true;
Texturing = true;
}
CSoftwareGLRenderer::~CSoftwareGLRenderer()
{
}
bool CSoftwareGLRenderer::Init()
{
bool Error = false;
Error |= !Texture.LoadTexture("texture.jpg");
Error |= !Object[0].Load("Models\\Thor\\", "thor.obj");
Error |= !Object[1].Load("Models\\", "Bunny_Medium.obj");
Error |= !Object[2].Load("Models\\", "Dragon_Medium.obj");
if(Error)
{
return false;
}
Object[0].Rotate(-90.0f, vec3(0.0f, 1.0f, 0.0f));
Object[0].Scale(1.75f / (Object[0].Max.y - Object[0].Min.y));
Object[0].Translate(vec3(-(Object[0].Min.x + Object[0].Max.x) / 2.0f, -(Object[0].Min.y + Object[0].Max.y) / 2.0f, -(Object[0].Min.z + Object[0].Max.z) / 2.0f));
Object[1].Rotate(90.0f, vec3(0.0f, 1.0f, 0.0f));
Object[1].Scale(1.75f / (Object[1].Max.y - Object[1].Min.y));
Object[1].Translate(vec3(-(Object[1].Min.x + Object[1].Max.x) / 2.0f, -(Object[1].Min.y + Object[1].Max.y) / 2.0f, -(Object[1].Min.z + Object[1].Max.z) / 2.0f));
Object[2].Rotate(90.0f, vec3(0.0f, 1.0f, 0.0f));
Object[2].Scale(1.75f / (Object[2].Max.y - Object[2].Min.y));
Object[2].Translate(vec3(-(Object[2].Min.x + Object[2].Max.x) / 2.0f, -(Object[2].Min.y + Object[2].Max.y) / 2.0f, -(Object[2].Min.z + Object[2].Max.z) / 2.0f));
Vertices = new CVertex[45];
int v = 0;
Vertices[v].Position = vec3(-0.5f,-0.5f, 0.0f); Vertices[v].Color = vec3(1.0f, 0.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.0f); 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.0f, 0.5f, 0.0f); Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(0.5f, 1.0f); Vertices[v].Normal = vec3( 0.0f, 0.0f, 1.0f); v++;
Vertices[v].Position = vec3(-0.5f,-0.5f,-0.5f); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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.75f, 0.0f, 0.75f); Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(-0.75f,-0.75f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.75f, 0.0f, 0.75f); Vertices[v].Color = vec3(0.0f, 1.0f, 0.0f); Vertices[v].TexCoord = vec2( 0.75f,-0.75f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.75f, 0.0f,-0.75f); Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 0.75f, 0.75f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3( 0.75f, 0.0f,-0.75f); Vertices[v].Color = vec3(0.0f, 1.0f, 1.0f); Vertices[v].TexCoord = vec2( 0.75f, 0.75f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.75f, 0.0f,-0.75f); Vertices[v].Color = vec3(1.0f, 0.0f, 0.0f); Vertices[v].TexCoord = vec2(-0.75f, 0.75f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Vertices[v].Position = vec3(-0.75f, 0.0f, 0.75f); Vertices[v].Color = vec3(0.0f, 0.0f, 1.0f); Vertices[v].TexCoord = vec2(-0.75f,-0.75f); Vertices[v].Normal = vec3( 0.0f, 1.0f, 0.0f); v++;
Light.Position = Camera.Position;
Light.Ambient = vec3(0.5f);
Light.Diffuse = vec3(0.5f);
Light.ConstantAttenuation = 1.0f;
Light.LinearAttenuation = 0.0f;
Light.QuadraticAttenuation = 0.0f;
return true;
}
void CSoftwareGLRenderer::Render(float FrameTime)
{
Clear();
LoadModelViewProjectionMatrix(Camera.ViewProjectionMatrix);
if(Lighting)
{
Light.Position = Camera.Position;
BindLight(&Light);
}
if(Texturing)
{
switch(RenderObject)
{
case 1: BindTexture(&Texture); break;
case 2: BindTexture(&Texture); break;
case 3: BindTexture(&Object[0].Texture); break;
case 4: BindTexture(&Object[1].Texture); break;
case 5: BindTexture(&Object[2].Texture); break;
}
}
switch(RenderObject)
{
case 1: DrawTriangles(Vertices, 0, 3); break;
case 2: DrawTriangles(Vertices, 3, 42); break;
case 3: DrawTriangles(Object[0].Vertices, 0, Object[0].VerticesCount); break;
case 4: DrawTriangles(Object[1].Vertices, 0, Object[1].VerticesCount); break;
case 5: DrawTriangles(Object[2].Vertices, 0, Object[2].VerticesCount); break;
}
if(Texturing)
{
BindTexture(NULL);
}
if(Lighting)
{
BindLight(NULL);
}
}
void CSoftwareGLRenderer::Resize(int Width, int Height)
{
Viewport(Width, Height);
Camera.SetPerspective(45.0f, (float)Width / (float)Height, 0.125f, 512.0f);
}
void CSoftwareGLRenderer::Destroy()
{
Texture.Destroy();
for(int i = 0; i < 3; i++)
{
Object[i].Destroy();
}
delete [] Vertices;
}
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_F1:
if(GetCullFace() == CULL_FACE_FRONT) SetCullFace(CULL_FACE_BACK);
else if(GetCullFace() == CULL_FACE_BACK) SetCullFace(CULL_FACE_FRONT);
break;
case VK_F2:
SetBilinearTextureFiltering(!GetBilinearTextureFiltering());
break;
case VK_F5:
RenderObject = 1;
break;
case VK_F6:
RenderObject = 2;
break;
case VK_F7:
RenderObject = 3;
break;
case VK_F8:
RenderObject = 4;
break;
case VK_F9:
RenderObject = 5;
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 'T':
Texturing = !Texturing;
break;
case 'L':
Lighting = !Lighting;
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.Render(FrameTime);
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.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, "Simple software renderer - Multithreading", 800, 600))
{
SoftwareGLView.Show();
SoftwareGLView.MsgLoop();
}
else
{
MessageBox(NULL, ErrorLog, "Error", MB_OK | MB_ICONERROR);
}
SoftwareGLView.Destroy();
return 0;
}
// ----------------------------------------------------------------------------------------------------------------------------
Download
|