Mass refactoring part 1/2: establishing multiple subprojects, moving source files to their new location, adding resources/templates to version control

This commit is contained in:
parax0
2015-12-14 18:33:16 -07:00
parent b4b134d55b
commit 8805baaee1
1116 changed files with 129200 additions and 546 deletions

10
src/Common/AnimUtil.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include "CTimer.h"
#include <cmath>
namespace AnimUtil
{
float SecondsMod900()
{
return fmod((float) CTimer::GlobalTime(), 900.f);
}
}

9
src/Common/AnimUtil.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef ANIMUTIL_H
#define ANIMUTIL_H
namespace AnimUtil
{
float SecondsMod900();
}
#endif // ANIMUTIL_H

211
src/Common/CColor.cpp Normal file
View File

@@ -0,0 +1,211 @@
#include "CColor.h"
CColor::CColor()
{
r = g = b = a = 0;
}
CColor::CColor(CInputStream& src)
{
src.ReadBytes(&r, 4);
}
CColor::CColor(u32 rgba)
{
r = (rgba >> 24) & 0xFF;
g = (rgba >> 16) & 0xFF;
b = (rgba >> 8) & 0xFF;
a = rgba & 0xFF;
}
CColor::CColor(u8 rgba)
{
r = g = b = a = rgba;
}
CColor::CColor(u8 _r, u8 _g, u8 _b, u8 _a)
{
r = _r;
g = _g;
b = _b;
a = _a;
}
CColor::CColor(float rgba)
{
r = g = b = a = u8(rgba * 255.f);
}
CColor::CColor(float _r, float _g, float _b, float _a)
{
r = u8(_r * 255.f);
g = u8(_g * 255.f);
b = u8(_b * 255.f);
a = u8(_a * 255.f);
}
void CColor::Write(COutputStream &Output)
{
Output.WriteBytes(&r, 4);
}
long CColor::AsLongRGBA() const
{
return (r << 24) | (g << 16) | (b << 8) | a;
}
long CColor::ToLongARGB() const
{
return (a << 24) | (r << 16) | (g << 8) | b;
}
CVector4f CColor::ToVector4f() const
{
return CVector4f(float(r) / 255.f,
float(g) / 255.f,
float(b) / 255.f,
float(a) / 255.f);
}
bool CColor::operator==(const CColor& other) const
{
return ((r == other.r) &&
(g == other.g) &&
(b == other.b) &&
(a == other.a));
}
bool CColor::operator!=(const CColor& other) const
{
return (!(*this == other));
}
CColor CColor::operator+(const CColor& other) const
{
u16 NewR = r + other.r;
if (NewR > 255) NewR = 255;
u16 NewG = g + other.g;
if (NewG > 255) NewG = 255;
u16 NewB = b + other.b;
if (NewB > 255) NewB = 255;
u16 NewA = a + other.a;
if (NewA > 255) NewA = 255;
return CColor((u8) NewR, (u8) NewG, (u8) NewB, (u8) NewA);
}
void CColor::operator+=(const CColor& other)
{
*this = (*this + other);
}
CColor CColor::operator-(const CColor& other) const
{
s16 NewR = r - other.r;
if (NewR < 0) NewR = 0;
s16 NewG = g - other.g;
if (NewG < 0) NewG = 0;
s16 NewB = b - other.b;
if (NewB < 0) NewB = 0;
s16 NewA = a - other.a;
if (NewA < 0) NewA = 0;
return CColor((u8) NewR, (u8) NewG, (u8) NewB, (u8) NewA);
}
void CColor::operator-=(const CColor& other)
{
*this = (*this - other);
}
CColor CColor::operator*(const CColor& other) const
{
CVector4f A = ToVector4f();
CVector4f B = other.ToVector4f();
float NewR = A.x * B.x;
float NewG = A.y * B.y;
float NewB = A.z * B.z;
float NewA = A.w * B.w;
return CColor(NewR, NewG, NewB, NewA);
}
void CColor::operator*=(const CColor& other)
{
*this = (*this * other);
}
CColor CColor::operator*(const float other) const
{
CVector4f Vec4f = ToVector4f() * other;
return CColor(Vec4f.x, Vec4f.y, Vec4f.z, Vec4f.w);
}
void CColor::operator*=(const float other)
{
*this = (*this * other);
}
CColor CColor::operator/(const CColor& other) const
{
u16 NewR = (other.r == 0) ? 0 : r / other.r;
u16 NewG = (other.g == 0) ? 0 : g / other.g;
u16 NewB = (other.b == 0) ? 0 : b / other.b;
u16 NewA = (other.a == 0) ? 0 : a / other.a;
return CColor((u8) NewR, (u8) NewG, (u8) NewB, (u8) NewA);
}
void CColor::operator/=(const CColor& other)
{
*this = (*this / other);
}
// ************ STATIC ************
CColor CColor::RandomColor(bool transparent)
{
CColor out;
out.r = rand() % 255;
out.g = rand() % 255;
out.b = rand() % 255;
out.a = (transparent ? rand() % 255 : 0);
return out;
}
CColor CColor::RandomLightColor(bool transparent)
{
CColor out;
out.r = 127 + (rand() % 128);
out.g = 127 + (rand() % 128);
out.b = 127 + (rand() % 128);
out.a = (transparent ? 127 + (rand() % 128) : 0);
return out;
}
CColor CColor::RandomDarkColor(bool transparent)
{
CColor out;
out.r = rand() % 128;
out.g = rand() % 128;
out.b = rand() % 128;
out.a = (transparent ? rand() % 128 : 0);
return out;
}
// defining predefined colors
const CColor CColor::skRed (u32(0xFF0000FF));
const CColor CColor::skGreen (u32(0x00FF00FF));
const CColor CColor::skBlue (u32(0x0000FFFF));
const CColor CColor::skYellow(u32(0xFFFF00FF));
const CColor CColor::skPurple(u32(0xFF00FFFF));
const CColor CColor::skCyan (u32(0x00FFFFFF));
const CColor CColor::skWhite (u32(0xFFFFFFFF));
const CColor CColor::skBlack (u32(0x000000FF));
const CColor CColor::skGray (u32(0x808080FF));
const CColor CColor::skTransparentRed (u32(0xFF000000));
const CColor CColor::skTransparentGreen (u32(0x00FF0000));
const CColor CColor::skTransparentBlue (u32(0x0000FF00));
const CColor CColor::skTransparentYellow(u32(0xFFFF0000));
const CColor CColor::skTransparentPurple(u32(0xFF00FF00));
const CColor CColor::skTransparentCyan (u32(0x00FFFF00));
const CColor CColor::skTransparentWhite (u32(0xFFFFFF00));
const CColor CColor::skTransparentBlack (u32(0x00000000));
const CColor CColor::skTransparentGray (u32(0x80808000));

65
src/Common/CColor.h Normal file
View File

@@ -0,0 +1,65 @@
#ifndef CCOLOR_H
#define CCOLOR_H
#include <FileIO/CInputStream.h>
#include <FileIO/COutputStream.h>
#include "CVector4f.h"
#include "types.h"
class CColor
{
public:
u8 r, g, b, a;
CColor();
CColor(CInputStream& src);
CColor(u32 rgba);
CColor(u8 rgba);
CColor(u8 _r, u8 _g, u8 _b, u8 _a);
CColor(float rgba);
CColor(float _r, float _g, float _b, float _a);
void Write(COutputStream& Output);
long AsLongRGBA() const;
long ToLongARGB() const;
CVector4f ToVector4f() const;
bool operator==(const CColor& other) const;
bool operator!=(const CColor& other) const;
CColor operator+(const CColor& other) const;
void operator+=(const CColor& other);
CColor operator-(const CColor& other) const;
void operator-=(const CColor& other);
CColor operator*(const CColor& other) const;
void operator*=(const CColor& other);
CColor operator*(const float other) const;
void operator*=(const float other);
CColor operator/(const CColor& other) const;
void operator/=(const CColor& other);
// Static
static CColor RandomColor(bool transparent);
static CColor RandomLightColor(bool transparent);
static CColor RandomDarkColor(bool transparent);
// some predefined colors below for ease of use
static const CColor skRed;
static const CColor skGreen;
static const CColor skBlue;
static const CColor skYellow;
static const CColor skPurple;
static const CColor skCyan;
static const CColor skWhite;
static const CColor skBlack;
static const CColor skGray;
static const CColor skTransparentRed;
static const CColor skTransparentGreen;
static const CColor skTransparentBlue;
static const CColor skTransparentYellow;
static const CColor skTransparentPurple;
static const CColor skTransparentCyan;
static const CColor skTransparentWhite;
static const CColor skTransparentBlack;
static const CColor skTransparentGray;
};
#endif // CCOLOR_H

120
src/Common/CFourCC.cpp Normal file
View File

@@ -0,0 +1,120 @@
#include "CFourCC.h"
// ************ CONSTRUCTORS ************
CFourCC::CFourCC()
{
memset(mFourCC, 0, 4);
}
CFourCC::CFourCC(const char *src)
{
*this = src;
}
CFourCC::CFourCC(const TString& src)
{
*this = src;
}
CFourCC::CFourCC(u32 src)
{
*this = src;
}
CFourCC::CFourCC(CInputStream& src)
{
src.ReadBytes(&mFourCC[0], 4);
}
// ************ FUNCTIONALITY ************
void CFourCC::Write(COutputStream &Output)
{
Output.WriteBytes(mFourCC, 4);
}
u32 CFourCC::ToLong() const
{
return mFourCC[0] << 24 | mFourCC[1] << 16 | mFourCC[2] << 8 | mFourCC[3];
}
TString CFourCC::ToString() const
{
return TString(mFourCC, 4);
}
CFourCC CFourCC::ToUpper() const
{
CFourCC Out;
for (int c = 0; c < 4; c++)
{
if ((mFourCC[c] >= 0x61) && (mFourCC[c] <= 0x7A))
Out.mFourCC[c] = mFourCC[c] - 0x20;
else
Out.mFourCC[c] = mFourCC[c];
}
return Out;
}
// ************ OPERATORS ************
CFourCC& CFourCC::operator=(const char *src)
{
memcpy(&mFourCC[0], src, 4);
return *this;
}
CFourCC& CFourCC::operator=(const TString& src)
{
memcpy(&mFourCC[0], src.CString(), 4);
return *this;
}
CFourCC& CFourCC::operator=(u32 src)
{
mFourCC[0] = (src >> 24) & 0xFF;
mFourCC[1] = (src >> 16) & 0xFF;
mFourCC[2] = (src >> 8) & 0xFF;
mFourCC[3] = (src >> 0) & 0xFF;
return *this;
}
bool CFourCC::operator==(const CFourCC& other) const
{
return ((mFourCC[0] == other.mFourCC[0]) && (mFourCC[1] == other.mFourCC[1]) && (mFourCC[2] == other.mFourCC[2]) && (mFourCC[3] == other.mFourCC[3]));
}
bool CFourCC::operator!=(const CFourCC& other) const
{
return (!(*this == other));
}
bool CFourCC::operator>(const CFourCC& other) const
{
return (ToLong() > other.ToLong());
}
bool CFourCC::operator>=(const CFourCC& other) const
{
return (ToLong() >= other.ToLong());
}
bool CFourCC::operator<(const CFourCC& other) const
{
return (ToLong() < other.ToLong());
}
bool CFourCC::operator<=(const CFourCC& other) const
{
return (ToLong() <= other.ToLong());
}
char CFourCC::operator[](int index)
{
return mFourCC[index];
}
const char CFourCC::operator[](int index) const
{
return mFourCC[index];
}

40
src/Common/CFourCC.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef CFOURCC_H
#define CFOURCC_H
#include "types.h"
#include "TString.h"
#include <FileIO/CInputStream.h>
#include <FileIO/COutputStream.h>
class CFourCC
{
char mFourCC[4];
public:
// Constructors
CFourCC();
CFourCC(const char *src);
CFourCC(const TString& src);
CFourCC(u32 src);
CFourCC(CInputStream& src);
// Functionality
void Write(COutputStream& Output);
u32 ToLong() const;
TString ToString() const;
CFourCC ToUpper() const;
// Operators
CFourCC& operator=(const char *src);
CFourCC& operator=(const TString& src);
CFourCC& operator=(u32 src);
bool operator==(const CFourCC& other) const;
bool operator!=(const CFourCC& other) const;
bool operator>(const CFourCC& other) const;
bool operator>=(const CFourCC& other) const;
bool operator<(const CFourCC& other) const;
bool operator<=(const CFourCC& other) const;
char operator[](int index);
const char operator[](int index) const;
};
#endif // CFOURCC_H

72
src/Common/CHashFNV1A.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "CHashFNV1A.h"
const u64 CHashFNV1A::skFNVOffsetBasis32 = 0x811C9DC5;
const u64 CHashFNV1A::skFNVOffsetBasis64 = 0xCBF29CE484222325;
const u64 CHashFNV1A::skFNVPrime32 = 0x1000193;
const u64 CHashFNV1A::skFNVPrime64 = 0x100000001B3;
CHashFNV1A::CHashFNV1A()
{
Init32();
}
void CHashFNV1A::Init32()
{
mHashLength = e32Bit;
mHash = skFNVOffsetBasis32;
}
void CHashFNV1A::Init64()
{
mHashLength = e64Bit;
mHash = skFNVOffsetBasis64;
}
void CHashFNV1A::HashData(const void *pData, u32 Size)
{
const char *pCharData = (const char*) pData;
u64 FNVPrime = (mHashLength == e32Bit) ? skFNVPrime32 : skFNVPrime64;
for (u32 i = 0; i < Size; i++)
{
mHash ^= *pCharData;
mHash *= FNVPrime;
pCharData++;
}
}
u32 CHashFNV1A::GetHash32()
{
return (u32) mHash;
}
u64 CHashFNV1A::GetHash64()
{
return mHash;
}
// ************ CONVENIENCE FUNCTIONS ************
void CHashFNV1A::HashByte(const u8& v)
{
HashData(&v, 1);
}
void CHashFNV1A::HashShort(const u16& v)
{
HashData(&v, 2);
}
void CHashFNV1A::HashLong(const u32& v)
{
HashData(&v, 4);
}
void CHashFNV1A::HashFloat(const float& v)
{
HashData(&v, 4);
}
void CHashFNV1A::HashString(const TString& v)
{
HashData(v.Data(), v.Size());
}

36
src/Common/CHashFNV1A.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef CHASHFNV1A_H
#define CHASHFNV1A_H
#include "types.h"
#include "TString.h"
class CHashFNV1A
{
u64 mHash;
enum EHashLength {
e32Bit, e64Bit
} mHashLength;
static const u64 skFNVOffsetBasis32;
static const u64 skFNVOffsetBasis64;
static const u64 skFNVPrime32;
static const u64 skFNVPrime64;
public:
CHashFNV1A();
void Init32();
void Init64();
void HashData(const void *pData, u32 Size);
u32 GetHash32();
u64 GetHash64();
// Convenience functions
void HashByte(const u8& v);
void HashShort(const u16& v);
void HashLong(const u32& v);
void HashFloat(const float& v);
void HashString(const TString& v);
};
#endif // CHASHFNV1A_H

89
src/Common/CTimer.cpp Normal file
View File

@@ -0,0 +1,89 @@
#include "CTimer.h"
#include <ctime>
CTimer::CTimer()
{
mStartTime = 0;
mStopTime = 0;
mStarted = false;
mPaused = false;
}
void CTimer::Start()
{
if (!mStarted)
{
mStartTime = GlobalTime();
mStarted = true;
mPaused = false;
mPauseStartTime = 0;
mTotalPauseTime = 0;
mStopTime = 0;
}
}
void CTimer::Start(double StartTime)
{
if (!mStarted)
{
mStartTime = GlobalTime() - StartTime;
mStarted = true;
mPaused = false;
mPauseStartTime = 0;
mTotalPauseTime = 0;
mStopTime = 0;
}
}
void CTimer::Restart()
{
mStarted = false;
Start();
}
double CTimer::Stop()
{
mStopTime = Time();
mStarted = false;
mPaused = false;
return mStopTime;
}
double CTimer::Pause()
{
mPauseStartTime = GlobalTime();
mPaused = true;
return Time();
}
bool CTimer::IsPaused()
{
return mPaused;
}
void CTimer::Resume()
{
if (mPaused)
{
mTotalPauseTime += GlobalTime() - mPauseStartTime;
mPaused = false;
}
}
double CTimer::Time()
{
if (mStarted)
{
double CurrentPauseTime = 0;
if (mPaused) CurrentPauseTime = GlobalTime() - mPauseStartTime;
return GlobalTime() - mStartTime - mTotalPauseTime - CurrentPauseTime;
}
else
return mStopTime;
}
double CTimer::GlobalTime()
{
return (double) clock() / CLOCKS_PER_SEC;
}

28
src/Common/CTimer.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef CTIMER_H
#define CTIMER_H
class CTimer
{
double mStartTime;
double mPauseStartTime;
double mTotalPauseTime;
double mStopTime;
bool mStarted;
bool mPaused;
public:
CTimer();
void Start();
void Start(double StartTime);
void Restart();
double Stop();
double Pause();
bool IsPaused();
void Resume();
double Time();
// Static
static double GlobalTime();
};
#endif // CTIMER_H

300
src/Common/CUniqueID.cpp Normal file
View File

@@ -0,0 +1,300 @@
#include "CUniqueID.h"
#include <Common/TString.h>
#include <iomanip>
#include <random>
#include <sstream>
// this class probably isn't optimized! this may not be the best way to do things
using IOUtil::SystemEndianness;
using IOUtil::LittleEndian;
using IOUtil::BigEndian;
CUniqueID::CUniqueID()
{
memset(mID, 0xFF, 16);
mLength = eInvalidUIDLength;
}
CUniqueID::CUniqueID(u64 ID)
{
// This constructor is intended to be used with both 32-bit and 64-bit input values
memset(mID, 0xFF, 16);
// 64-bit - check for valid content in upper 32 bits (at least one bit set + one bit unset)
if ((ID & 0xFFFFFFFF00000000) && (~ID & 0xFFFFFFFF00000000))
{
memcpy(&mID, &ID, 8);
mLength = e64Bit;
}
// 32-bit
else
{
memcpy(mID, &ID, 4);
mLength = e32Bit;
}
// Reverse for Big Endian
if (SystemEndianness == BigEndian)
Reverse();
}
CUniqueID::CUniqueID(u64 Part1, u64 Part2)
{
// Constructor for 128-bit IDs
memcpy(&mID[0], &Part1, 8);
memcpy(&mID[8], &Part2, 8);
mLength = e128Bit;
}
CUniqueID::CUniqueID(const char* ID)
{
*this = CUniqueID::FromString(ID);
}
CUniqueID::CUniqueID(CInputStream& Input, EUIDLength Length)
{
memset(mID, 0, 16);
Input.ReadBytes(&mID[16 - Length], Length);
if (Length != e128Bit)
if (SystemEndianness == LittleEndian)
Reverse();
mLength = Length;
}
u32 CUniqueID::ToLong() const
{
if (SystemEndianness == LittleEndian)
return *((u32*) mID);
else
return *((u32*) &mID[12]);
}
u64 CUniqueID::ToLongLong() const
{
if (SystemEndianness == LittleEndian)
return *((u64*) mID);
else
return *((u64*) &mID[8]);
}
TString CUniqueID::ToString() const
{
switch (mLength)
{
case e32Bit:
return TString::FromInt32(ToLong(), 8);
case e64Bit:
return TString::FromInt64(ToLongLong(), 16);
case e128Bit:
// todo: TString should have a "FromInt128" function
std::stringstream Ret;
Ret << std::hex << std::setfill('0');
for (u32 i = 0; i < 16; i++)
Ret << std::setw(2) << (u32) mID[i];
return Ret.str();
}
return "INVALID ID LENGTH";
}
void CUniqueID::Reverse()
{
std::reverse(mID, &mID[16]);
}
EUIDLength CUniqueID::Length() const
{
return mLength;
}
void CUniqueID::SetLength(EUIDLength Length)
{
mLength = Length;
}
bool CUniqueID::IsValid() const
{
if (mLength == e32Bit)
return (*this != skInvalidID32);
else if (mLength == e64Bit)
return (*this != skInvalidID64);
else if (mLength == e128Bit)
return (*this != skInvalidID128);
else return false;
}
// ************ OPERATORS ************
void CUniqueID::operator=(const u64& Input)
{
*this = CUniqueID(Input);
}
void CUniqueID::operator=(const char* Input)
{
*this = CUniqueID(Input);
}
bool CUniqueID::operator==(const CUniqueID& Other) const
{
return ((mLength == Other.mLength) &&
(memcmp(mID, Other.mID, 16) == 0));
}
bool CUniqueID::operator!=(const CUniqueID& Other) const
{
return (!(*this == Other));
}
bool CUniqueID::operator>(const CUniqueID& Other) const
{
if (mLength != Other.mLength)
return mLength > Other.mLength;
switch (mLength)
{
case e32Bit:
return (ToLong() > Other.ToLong());
case e64Bit:
return (ToLongLong() > Other.ToLongLong());
case e128Bit:
for (u32 i = 0; i < 16; i++)
if (mID[i] != Other.mID[i])
return (mID[i] > Other.mID[i]);
return false;
default:
return false;
}
}
bool CUniqueID::operator>=(const CUniqueID& Other) const
{
return ((*this == Other) || (*this > Other));
}
bool CUniqueID::operator<(const CUniqueID& Other) const
{
if (mLength != Other.mLength)
return mLength < Other.mLength;
switch (mLength)
{
case e32Bit:
return (ToLong() < Other.ToLong());
case e64Bit:
return (ToLongLong() < Other.ToLongLong());
case e128Bit:
for (u32 i = 0; i < 16; i++)
if (mID[i] != Other.mID[i])
return (mID[i] < Other.mID[i]);
return false;
default:
return false;
}
}
bool CUniqueID::operator<=(const CUniqueID& Other) const
{
return ((*this == Other) || (*this < Other));
}
bool CUniqueID::operator==(u64 Other) const
{
return (*this == CUniqueID(Other));
}
bool CUniqueID::operator!=(u64 Other) const
{
return (!(*this == Other));
}
// ************ STATIC ************
CUniqueID CUniqueID::FromString(const TString& String)
{
// If the input is a hex ID in string form, then preserve it... otherwise, generate an ID by hashing the string
TString Name = String.GetFileName(false);
u32 NameLength = Name.Length();
if (Name.IsHexString())
{
if (NameLength == 8)
{
CUniqueID ID;
ID.mLength = e32Bit;
u32 LongID = Name.ToInt32();
if (SystemEndianness == LittleEndian)
memcpy(ID.mID, &LongID, 4);
else
memcpy(&ID.mID[12], &LongID, 4);
return ID;
}
else if (NameLength == 16)
{
CUniqueID ID;
ID.mLength = e64Bit;
u64 LongID = Name.ToInt64();
if (SystemEndianness == LittleEndian)
memcpy(ID.mID, &LongID, 8);
else
memcpy(&ID.mID[8], &LongID, 8);
return ID;
}
else if (NameLength == 32)
{
CUniqueID ID;
ID.mLength = e128Bit;
Name.ToInt128((char*) ID.mID);
return ID;
}
}
return CUniqueID(String.Hash64());
}
CUniqueID CUniqueID::FromData(void *pData, EUIDLength Length)
{
CUniqueID ID;
ID.mLength = Length;
memcpy(ID.mID, pData, Length);
return ID;
}
CUniqueID CUniqueID::RandomID()
{
CUniqueID ID;
ID.mLength = e128Bit;
for (u32 i = 0; i < 16; i++)
ID.mID[i] = rand() & 0xFF;
return ID;
}
// ************ STATIC MEMBER INITIALIZATION ************
CUniqueID CUniqueID::skInvalidID32 = CUniqueID((u32) -1);
CUniqueID CUniqueID::skInvalidID64 = CUniqueID((u64) -1);
CUniqueID CUniqueID::skInvalidID128 = CUniqueID((u64) -1, (u64) -1);

57
src/Common/CUniqueID.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef CUNIQUEID_H
#define CUNIQUEID_H
#include "types.h"
#include "TString.h"
#include <FileIO/FileIO.h>
enum EUIDLength
{
e32Bit = 4,
e64Bit = 8,
e128Bit = 16,
eInvalidUIDLength = 0
};
class CUniqueID
{
EUIDLength mLength;
u8 mID[16];
public:
CUniqueID();
CUniqueID(u64 ID);
CUniqueID(u64 Part1, u64 Part2);
CUniqueID(const char* ID);
CUniqueID(CInputStream& Input, EUIDLength Length);
u32 ToLong() const;
u64 ToLongLong() const;
TString ToString() const;
void Reverse();
EUIDLength Length() const;
void SetLength(EUIDLength Length);
bool IsValid() const;
// Operators
void operator=(const u64& Input);
void operator=(const char *Input);
bool operator==(const CUniqueID& Other) const;
bool operator!=(const CUniqueID& Other) const;
bool operator>(const CUniqueID& Other) const;
bool operator>=(const CUniqueID& Other) const;
bool operator<(const CUniqueID& Other) const;
bool operator<=(const CUniqueID& Other) const;
bool operator==(u64 Other) const;
bool operator!=(u64 Other) const;
// Static
static CUniqueID FromString(const TString& String);
static CUniqueID FromData(void *pData, EUIDLength Length);
static CUniqueID RandomID();
static CUniqueID skInvalidID32;
static CUniqueID skInvalidID64;
static CUniqueID skInvalidID128;
};
#endif // CUNIQUEID_H

95
src/Common/Common.pro Normal file
View File

@@ -0,0 +1,95 @@
#-------------------------------------------------
#
# Project created by QtCreator 2015-12-13T15:27:18
#
#-------------------------------------------------
QT -= core gui
CONFIG += staticlib
TEMPLATE = lib
DESTDIR = $$PWD/../../build/Common
unix {
target.path = /usr/lib
INSTALLS += target
}
CONFIG (debug, debug|release) {
# Debug Config
OBJECTS_DIR = $$PWD/../../build/Common/debug
TARGET = Commond
# Debug Libs
LIBS += -L$$PWD/../../externals/FileIO/lib/ -lFileIOd
}
CONFIG (release, debug|release) {
# Release Config
OBJECTS_DIR = $$PWD/../../build/Common/release
TARGET = Common
# Release Libs
LIBS += -L$$PWD/../../externals/FileIO/lib/ -lFileIO
}
# Debug/Release Libs
LIBS += -L$$PWD/../../externals/lzo-2.08/lib -llzo-2.08 \
-L$$PWD/../../externals/zlib/lib -lzdll \
# Include Paths
INCLUDEPATH += $$PWD/.. \
$$PWD/../../externals/FileIO/include \
$$PWD/../../externals/glm/glm \
$$PWD/../../externals/lzo-2.08/include \
$$PWD/../../externals/zlib/include
# Source Files
HEADERS += \
AnimUtil.h \
CColor.h \
CFourCC.h \
CHashFNV1A.h \
CompressionUtil.h \
CTimer.h \
CUniqueID.h \
EKeyInputs.h \
EMouseInputs.h \
EnumUtil.h \
ETransformSpace.h \
TString.h \
types.h \
Math/CAABox.h \
Math/CFrustumPlanes.h \
Math/CMatrix4f.h \
Math/CPlane.h \
Math/CQuaternion.h \
Math/CRay.h \
Math/CTransform4f.h \
Math/CVector2f.h \
Math/CVector2i.h \
Math/CVector3f.h \
Math/CVector4f.h \
Math/Math.h
SOURCES += \
AnimUtil.cpp \
CColor.cpp \
CFourCC.cpp \
CHashFNV1A.cpp \
CompressionUtil.cpp \
CTimer.cpp \
CUniqueID.cpp \
TString.cpp \
Math/CAABox.cpp \
Math/CFrustumPlanes.cpp \
Math/CMatrix4f.cpp \
Math/CPlane.cpp \
Math/CQuaternion.cpp \
Math/CRay.cpp \
Math/CTransform4f.cpp \
Math/CVector2f.cpp \
Math/CVector2i.cpp \
Math/CVector3f.cpp \
Math/CVector4f.cpp \
Math/Math.cpp

View File

@@ -0,0 +1,39 @@
#include "types.h"
#include <lzo/lzo1x.h>
#include <cstring>
namespace CompressionUtil
{
bool DecompressAreaLZO(u8 *src, u32 src_len, u8 *dst, u32 dst_len)
{
u8 *src_end = src + src_len;
u8 *dst_end = dst + dst_len;
lzo_init();
lzo_uint decmp;
while ((src < src_end) && (dst < dst_end))
{
u8 a = *src++;
u8 b = *src++;
u16 size = (a << 8) | b;
if (size >= 0xC000)
{
size = 0x10000 - size;
memcpy(dst, src, size);
dst += size;
src += size;
}
else
{
lzo1x_decompress(src, size, dst, &decmp, LZO1X_MEM_DECOMPRESS);
src += size;
dst += decmp;
}
}
return ((src == src_end) && (dst == dst_end));
}
}

View File

@@ -0,0 +1,11 @@
#ifndef COMPRESSIONUTIL_H
#define COMPRESSIONUTIL_H
#include "types.h"
namespace CompressionUtil
{
bool DecompressAreaLZO(u8 *src, u32 src_len, u8 *dst, u32 dst_len);
}
#endif // COMPRESSIONUTIL_H

21
src/Common/EKeyInputs.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef EKEYINPUTS
#define EKEYINPUTS
#include "EnumUtil.h"
enum EKeyInputs
{
eNoKeys = 0,
eCtrlKey = 0x1,
eAltKey = 0x2,
eQKey = 0x4,
eWKey = 0x8,
eEKey = 0x10,
eAKey = 0x20,
eSKey = 0x40,
eDKey = 0x80
};
DEFINE_ENUM_FLAGS(EKeyInputs)
#endif // EKEYINPUTS

15
src/Common/EMouseInputs.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef EMOUSEINPUTS
#define EMOUSEINPUTS
#include "EnumUtil.h"
enum EMouseInputs
{
eLeftButton = 0x1,
eMiddleButton = 0x2,
eRightButton = 0x4
};
DEFINE_ENUM_FLAGS(EMouseInputs)
#endif // EMOUSEINPUTS

43
src/Common/EnumUtil.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef ENUMUTIL
#define ENUMUTIL
#define DEFINE_ENUM_FLAGS(X) \
inline X operator|(const X& A, const X& B) { \
return (X) ((int) A | (int) B); \
} \
inline void operator|= (X& A, X& B) { \
A = A | B; \
} \
inline X operator|(const X& A, const int B) { \
return (X) ((int) A | B); \
} \
inline void operator|= (X& A, int B) { \
A = A | B; \
} \
inline X operator|(const X& A, const unsigned int B) { \
return (X) ((int) A | B); \
} \
inline void operator|= (X& A, unsigned int B) { \
A = A | B; \
} \
inline X operator&(const X& A, const X& B) { \
return (X) ((int) A & (int) B); \
} \
inline void operator&= (X& A, X& B) { \
A = A & B; \
} \
inline X operator&(const X& A, const int B) { \
return (X) ((int) A & B); \
} \
inline void operator&= (X& A, int B) { \
A = A & B; \
} \
inline X operator&(const X& A, const unsigned int B) { \
return (X) ((int) A & B); \
} \
inline void operator&= (X& A, unsigned int B) { \
A = A & B; \
}
#endif // ENUMUTIL

186
src/Common/Math/CAABox.cpp Normal file
View File

@@ -0,0 +1,186 @@
#include "CAABox.h"
#include <Common/CTransform4f.h>
#include <Common/Math.h>
#include "CRay.h"
#include "SRayIntersection.h"
#include <float.h>
CAABox::CAABox()
{
mMin = CVector3f::skInfinite;
mMax = -CVector3f::skInfinite;
}
CAABox::CAABox(const CVector3f& Min, const CVector3f& Max)
{
mMin = Min;
mMax = Max;
}
CAABox::CAABox(CInputStream& input)
{
mMin = CVector3f(input);
mMax = CVector3f(input);
}
void CAABox::Write(COutputStream& Output)
{
mMin.Write(Output);
mMax.Write(Output);
}
CVector3f CAABox::Center() const
{
return (mMax - ((mMax - mMin) * 0.5f));
}
CVector3f CAABox::Size() const
{
return (mMax - mMin);
}
CVector3f CAABox::Min() const
{
return mMin;
}
CVector3f CAABox::Max() const
{
return mMax;
}
void CAABox::SetMin(const CVector3f& min)
{
mMin = min;
}
void CAABox::SetMax(const CVector3f& max)
{
mMax = max;
}
bool CAABox::IsNull() const
{
return (Size() == CVector3f::skZero);
}
bool CAABox::IsInfinite() const
{
return (Size() == CVector3f::skInfinite);
}
void CAABox::ExpandBounds(const CVector3f& vtx)
{
// take an input vertex coordinate and expand the bounding box to fit it, if necessary
if (vtx.x < mMin.x) mMin.x = vtx.x;
if (vtx.x > mMax.x) mMax.x = vtx.x;
if (vtx.y < mMin.y) mMin.y = vtx.y;
if (vtx.y > mMax.y) mMax.y = vtx.y;
if (vtx.z < mMin.z) mMin.z = vtx.z;
if (vtx.z > mMax.z) mMax.z = vtx.z;
}
void CAABox::ExpandBounds(const CAABox& AABox)
{
ExpandBounds(AABox.mMin);
ExpandBounds(AABox.mMax);
}
void CAABox::ExpandBy(const CVector3f& amount)
{
CVector3f halfAmount = amount / 2.f;
mMin -= halfAmount;
mMax += halfAmount;
}
CAABox CAABox::Transformed(const CTransform4f& transform) const
{
CAABox AABox;
AABox.ExpandBounds(transform * CVector3f(mMin.x, mMin.y, mMin.z));
AABox.ExpandBounds(transform * CVector3f(mMin.x, mMin.y, mMax.z));
AABox.ExpandBounds(transform * CVector3f(mMin.x, mMax.y, mMax.z));
AABox.ExpandBounds(transform * CVector3f(mMin.x, mMax.y, mMin.z));
AABox.ExpandBounds(transform * CVector3f(mMax.x, mMin.y, mMin.z));
AABox.ExpandBounds(transform * CVector3f(mMax.x, mMin.y, mMax.z));
AABox.ExpandBounds(transform * CVector3f(mMax.x, mMax.y, mMax.z));
AABox.ExpandBounds(transform * CVector3f(mMax.x, mMax.y, mMin.z));
return AABox;
}
bool CAABox::IsPointInBox(const CVector3f& Point) const
{
return ( ((Point.x >= mMin.x) && (Point.x <= mMax.x)) &&
((Point.y >= mMin.y) && (Point.y <= mMax.y)) &&
((Point.z >= mMin.z) && (Point.z <= mMax.z)) );
}
CVector3f CAABox::ClosestPointAlongVector(const CVector3f& dir) const
{
CVector3f out;
out.x = (dir.x >= 0.f) ? mMin.x : mMax.x;
out.y = (dir.y >= 0.f) ? mMin.y : mMax.y;
out.z = (dir.z >= 0.f) ? mMin.z : mMax.z;
return out;
}
CVector3f CAABox::FurthestPointAlongVector(const CVector3f& dir) const
{
CVector3f out;
out.x = (dir.x >= 0.f) ? mMax.x : mMin.x;
out.y = (dir.y >= 0.f) ? mMax.y : mMin.y;
out.z = (dir.z >= 0.f) ? mMax.z : mMin.z;
return out;
}
// ************ INTERSECTION TESTS ************
// These tests are kinda bad and probably inaccurate, they need rewrites
bool CAABox::IntersectsAABox(const CAABox& AABox)
{
return ((mMax > AABox.mMin) && (mMin < AABox.mMax));
}
bool CAABox::IntersectsSphere(const CVector3f& SphereCenter, const float SphereRadius)
{
// Placeholder for proper sphere intersection test
// Generate an AABox for the sphere and do an AABox/AABox intersection test instead
return IntersectsAABox(CAABox(SphereCenter - SphereRadius, SphereCenter + SphereRadius));
}
std::pair<bool,float> CAABox::IntersectsRay(const CRay &Ray) const
{
return Math::RayBoxIntersection(Ray, *this);
}
// ************ OPERATORS ************
CAABox CAABox::operator+(const CVector3f& translate) const
{
return CAABox(mMin + translate, mMax + translate);
}
CAABox CAABox::operator*(float scalar) const
{
return CAABox(mMin * scalar, mMax * scalar);
}
bool CAABox::operator==(const CAABox& Other) const
{
return ((mMin == Other.mMin) && (mMax == Other.mMax));
}
bool CAABox::operator!=(const CAABox& Other) const
{
return (!(*this == Other));
}
// ************ CONSTANTS ************
// min set to float maximum, max set to float minimum; ideal for creating an AABox from scratch
const CAABox CAABox::skInfinite = CAABox(CVector3f(FLT_MAX), CVector3f(-FLT_MAX));
// a 1x1x1 bounding box
const CAABox CAABox::skOne = CAABox( CVector3f(-0.5f, -0.5f, -0.5f), CVector3f(0.5f, 0.5f, 0.5f) );
// a 0x0x0 bounding box
const CAABox CAABox::skZero = CAABox(CVector3f(0), CVector3f(0));

56
src/Common/Math/CAABox.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef CAABOX_H
#define CAABOX_H
#include <FileIO/CInputStream.h>
#include <FileIO/COutputStream.h>
#include "CVector3f.h"
#include <utility>
class CRay;
class CRayIntersection;
class CAABox
{
CVector3f mMin, mMax;
public:
CAABox();
CAABox(const CVector3f& Min, const CVector3f& Max);
CAABox(CInputStream& input);
void Write(COutputStream& Output);
CVector3f Center() const;
CVector3f Size() const;
CVector3f Min() const;
CVector3f Max() const;
void SetMin(const CVector3f& min);
void SetMax(const CVector3f& max);
bool IsNull() const;
bool IsInfinite() const;
void ExpandBounds(const CVector3f& vtx);
void ExpandBounds(const CAABox& AABox);
void ExpandBy(const CVector3f& amount);
CAABox Transformed(const CTransform4f& transform) const;
bool IsPointInBox(const CVector3f& Point) const;
CVector3f ClosestPointAlongVector(const CVector3f& dir) const;
CVector3f FurthestPointAlongVector(const CVector3f& dir) const;
// Intersection Tests
bool IntersectsAABox(const CAABox& AABox);
bool IntersectsSphere(const CVector3f& SphereCenter, const float SphereRadius);
std::pair<bool,float> IntersectsRay(const CRay& Ray) const;
// Operators
CAABox operator+(const CVector3f& translate) const;
CAABox operator*(float scalar) const;
bool operator==(const CAABox& Other) const;
bool operator!=(const CAABox& Other) const;
// Constants
static const CAABox skInfinite;
static const CAABox skOne;
static const CAABox skZero;
};
#endif // CAABOX_H

View File

@@ -0,0 +1,98 @@
#include "CFrustumPlanes.h"
#include <Common/Math.h>
#include <Common/types.h>
CFrustumPlanes::CFrustumPlanes()
{
}
CFrustumPlanes::~CFrustumPlanes()
{
}
const CPlane& CFrustumPlanes::GetPlane(EFrustumSide side) const
{
return mPlanes[side];
}
void CFrustumPlanes::SetPlanes(const CVector3f& position, const CVector3f& direction, float fieldOfView, float aspectRatio, float near, float far)
{
// Calculate up/right vectors
CVector3f right = direction.Cross(CVector3f::skUp).Normalized();
CVector3f up = right.Cross(direction).Normalized();
// Calculate dimensions of near plane
float nearHeight = 2 * tanf(Math::DegreesToRadians(fieldOfView) / 2.f) * near;
float nearWidth = nearHeight * aspectRatio;
// Define the planes
CVector3f nearCenter = position + (direction * near);
mPlanes[eNearPlane].Redefine(direction, nearCenter);
CVector3f farCenter = position + (direction * far);
mPlanes[eFarPlane].Redefine(-direction, farCenter);
CVector3f midRight = nearCenter + (right * (nearWidth / 2.f));
CVector3f rightNormal = up.Cross((midRight - position).Normalized());
mPlanes[eRightPlane].Redefine(rightNormal, position);
CVector3f midLeft = nearCenter - (right * (nearWidth / 2.f));
CVector3f leftNormal = (midLeft - position).Normalized().Cross(up);
mPlanes[eLeftPlane].Redefine(leftNormal, position);
CVector3f midTop = nearCenter + (up * (nearHeight / 2.f));
CVector3f topNormal = (midTop - position).Normalized().Cross(right);
mPlanes[eTopPlane].Redefine(topNormal, position);
CVector3f midBottom = nearCenter - (up * (nearHeight / 2.f));
CVector3f bottomNormal = right.Cross((midBottom - position).Normalized());
mPlanes[eBottomPlane].Redefine(bottomNormal, position);
}
bool CFrustumPlanes::PointInFrustum(const CVector3f& point) const
{
for (u32 iPlane = 0; iPlane < 6; iPlane++)
{
const CPlane& plane = mPlanes[iPlane];
if (plane.Normal().Dot(point) + plane.Dist() < 0.f)
return false;
}
return true;
}
bool CFrustumPlanes::BoxInFrustum(const CAABox& box) const
{
CVector3f min = box.Min();
CVector3f max = box.Max();
CVector3f points[8];
points[0] = min;
points[1] = max;
points[2] = CVector3f(min.x, min.y, max.z);
points[3] = CVector3f(min.x, max.y, min.z);
points[4] = CVector3f(min.x, max.y, max.z);
points[5] = CVector3f(max.x, min.y, max.z);
points[6] = CVector3f(max.x, max.y, min.z);
points[7] = CVector3f(max.x, min.y, min.z);
for (u32 iPlane = 0; iPlane < 6; iPlane++)
{
const CPlane& plane = mPlanes[iPlane];
int numPoints = 0;
for (u32 iPoint = 0; iPoint < 8; iPoint++)
{
if (plane.Normal().Dot(points[iPoint]) + plane.Dist() < 0.f)
numPoints++;
else
break;
}
if (numPoints == 8) return false;
}
return true;
}

View File

@@ -0,0 +1,30 @@
#ifndef CFRUSTUMPLANES_H
#define CFRUSTUMPLANES_H
#include <Common/CAABox.h>
#include <Common/CPlane.h>
#include <Common/CVector3f.h>
class CFrustumPlanes
{
public:
enum EFrustumSide
{
eNearPlane = 0, eFarPlane = 1,
eTopPlane = 2, eBottomPlane = 3,
eLeftPlane = 4, eRightPlane = 5
};
private:
CPlane mPlanes[6];
public:
CFrustumPlanes();
~CFrustumPlanes();
const CPlane& GetPlane(EFrustumSide side) const;
void SetPlanes(const CVector3f& position, const CVector3f& direction, float fieldOfView, float aspectRatio, float near, float far);
bool PointInFrustum(const CVector3f& point) const;
bool BoxInFrustum(const CAABox& box) const;
};
#endif // CFRUSTUMPLANES_H

View File

@@ -0,0 +1,241 @@
#include "CMatrix4f.h"
#include "CVector3f.h"
#include "CVector4f.h"
#include "CTransform4f.h"
CMatrix4f::CMatrix4f()
{
}
CMatrix4f::CMatrix4f(float v)
{
*this = skZero;
m[0][0] = v;
m[1][1] = v;
m[2][2] = v;
m[3][3] = v;
}
CMatrix4f::CMatrix4f(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33)
{
m[0][0] = m00;
m[0][1] = m01;
m[0][2] = m02;
m[0][3] = m03;
m[1][0] = m10;
m[1][1] = m11;
m[1][2] = m12;
m[1][3] = m13;
m[2][0] = m20;
m[2][1] = m21;
m[2][2] = m22;
m[2][3] = m23;
m[3][0] = m30;
m[3][1] = m31;
m[3][2] = m32;
m[3][3] = m33;
}
// ************ MATH ************
CMatrix4f CMatrix4f::Transpose() const
{
return CMatrix4f(m[0][0], m[1][0], m[2][0], m[3][0],
m[0][1], m[1][1], m[2][1], m[3][1],
m[0][2], m[1][2], m[2][2], m[3][2],
m[0][3], m[1][3], m[2][3], m[3][3]);
}
CMatrix4f CMatrix4f::Inverse() const
{
// Copied from Ogre.
// todo after developing a better understanding of the math - rewrite
float m00 = m[0][0], m01 = m[0][1], m02 = m[0][2], m03 = m[0][3];
float m10 = m[1][0], m11 = m[1][1], m12 = m[1][2], m13 = m[1][3];
float m20 = m[2][0], m21 = m[2][1], m22 = m[2][2], m23 = m[2][3];
float m30 = m[3][0], m31 = m[3][1], m32 = m[3][2], m33 = m[3][3];
float v0 = m20 * m31 - m21 * m30;
float v1 = m20 * m32 - m22 * m30;
float v2 = m20 * m33 - m23 * m30;
float v3 = m21 * m32 - m22 * m31;
float v4 = m21 * m33 - m23 * m31;
float v5 = m22 * m33 - m23 * m32;
float t00 = + (v5 * m11 - v4 * m12 + v3 * m13);
float t10 = - (v5 * m10 - v2 * m12 + v1 * m13);
float t20 = + (v4 * m10 - v2 * m11 + v0 * m13);
float t30 = - (v3 * m10 - v1 * m11 + v0 * m12);
float invDet = 1 / (t00 * m00 + t10 * m01 + t20 * m02 + t30 * m03);
float d00 = t00 * invDet;
float d10 = t10 * invDet;
float d20 = t20 * invDet;
float d30 = t30 * invDet;
float d01 = - (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
float d11 = + (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
float d21 = - (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
float d31 = + (v3 * m00 - v1 * m01 + v0 * m02) * invDet;
v0 = m10 * m31 - m11 * m30;
v1 = m10 * m32 - m12 * m30;
v2 = m10 * m33 - m13 * m30;
v3 = m11 * m32 - m12 * m31;
v4 = m11 * m33 - m13 * m31;
v5 = m12 * m33 - m13 * m32;
float d02 = + (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
float d12 = - (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
float d22 = + (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
float d32 = - (v3 * m00 - v1 * m01 + v0 * m02) * invDet;
v0 = m21 * m10 - m20 * m11;
v1 = m22 * m10 - m20 * m12;
v2 = m23 * m10 - m20 * m13;
v3 = m22 * m11 - m21 * m12;
v4 = m23 * m11 - m21 * m13;
v5 = m23 * m12 - m22 * m13;
float d03 = - (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
float d13 = + (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
float d23 = - (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
float d33 = + (v3 * m00 - v1 * m01 + v0 * m02) * invDet;
return CMatrix4f(
d00, d01, d02, d03,
d10, d11, d12, d13,
d20, d21, d22, d23,
d30, d31, d32, d33);
}
float CMatrix4f::Determinant() const
{
float AA = m[1][1] * ((m[2][2] * m[3][3]) - (m[2][3] * m[3][2]));
float AB = m[1][2] * ((m[2][1] * m[3][3]) - (m[2][3] * m[3][1]));
float AC = m[1][3] * ((m[2][1] * m[3][2]) - (m[2][2] * m[3][1]));
float A = m[0][0] * (AA - AB + AC);
float BA = m[1][0] * ((m[2][2] * m[3][3]) - (m[2][3] * m[3][2]));
float BB = m[1][2] * ((m[2][0] * m[3][3]) - (m[2][3] * m[3][0]));
float BC = m[1][3] * ((m[2][0] * m[3][2]) - (m[2][2] * m[3][0]));
float B = m[0][1] * (BA - BB + BC);
float CA = m[1][0] * ((m[2][1] * m[3][3]) - (m[2][3] * m[3][1]));
float CB = m[1][1] * ((m[2][0] * m[3][3]) - (m[2][3] * m[3][0]));
float CC = m[1][3] * ((m[2][0] * m[3][1]) - (m[2][1] * m[3][0]));
float C = m[0][2] * (CA - CB + CC);
float DA = m[1][0] * ((m[2][1] * m[3][2]) - (m[2][2] * m[3][1]));
float DB = m[1][1] * ((m[2][0] * m[3][2]) - (m[2][2] * m[3][0]));
float DC = m[1][2] * ((m[2][0] * m[3][1]) - (m[2][1] * m[3][0]));
float D = m[0][3] * (DA - DB + DC);
return (A - B + C - D);
}
glm::mat4 CMatrix4f::ToGlmMat4() const
{
glm::mat4 out = glm::mat4(1);
memcpy(&out[0][0], &m[0][0], sizeof(glm::mat4));
return out;
}
// ************ STATIC ************
CMatrix4f CMatrix4f::FromGlmMat4(glm::mat4 src)
{
CMatrix4f out;
memcpy(&out[0][0], &src[0][0], sizeof(CMatrix4f));
return out;
}
// ************ OPERATORS ************
inline float* CMatrix4f::operator[](long index)
{
return m[index];
}
inline const float* CMatrix4f::operator[](long index) const
{
return m[index];
}
CVector3f CMatrix4f::operator*(const CVector3f& vec) const
{
// For vec3 multiplication, the vector w component is considered to be 1.0
CVector3f out;
float w = (m[3][0] * vec.x) + (m[3][1] * vec.y) + (m[3][2] * vec.z) + m[3][3];
out.x = ((m[0][0] * vec.x) + (m[0][1] * vec.y) + (m[0][2] * vec.z) + m[0][3]) / w;
out.y = ((m[1][0] * vec.x) + (m[1][1] * vec.y) + (m[1][2] * vec.z) + m[1][3]) / w;
out.z = ((m[2][0] * vec.x) + (m[2][1] * vec.y) + (m[2][2] * vec.z) + m[1][3]) / w;
return out;
}
CVector4f CMatrix4f::operator*(const CVector4f& vec) const
{
CVector4f out;
out.x = (m[0][0] * vec.x) + (m[0][1] * vec.y) + (m[0][2] * vec.z) + (m[0][3] * vec.w);
out.y = (m[1][0] * vec.x) + (m[1][1] * vec.y) + (m[1][2] * vec.z) + (m[1][3] * vec.w);
out.z = (m[2][0] * vec.x) + (m[2][1] * vec.y) + (m[2][2] * vec.z) + (m[2][3] * vec.w);
out.w = (m[3][0] * vec.x) + (m[3][1] * vec.y) + (m[3][2] * vec.z) + (m[3][3] * vec.w);
return out;
}
CMatrix4f CMatrix4f::operator*(const CTransform4f& mtx) const
{
// CTransform4f is a 3x4 matrix with an implicit fourth row of {0, 0, 0, 1}
CMatrix4f out;
out[0][0] = (m[0][0] * mtx[0][0]) + (m[0][1] * mtx[1][0]) + (m[0][2] * mtx[2][0]);
out[0][1] = (m[0][0] * mtx[0][1]) + (m[0][1] * mtx[1][1]) + (m[0][2] * mtx[2][1]);
out[0][2] = (m[0][0] * mtx[0][2]) + (m[0][1] * mtx[1][2]) + (m[0][2] * mtx[2][2]);
out[0][3] = (m[0][0] * mtx[0][3]) + (m[0][1] * mtx[1][3]) + (m[0][2] * mtx[2][3]) + m[0][3];
out[1][0] = (m[1][0] * mtx[0][0]) + (m[1][1] * mtx[1][0]) + (m[1][2] * mtx[2][0]);
out[1][1] = (m[1][0] * mtx[0][1]) + (m[1][1] * mtx[1][1]) + (m[1][2] * mtx[2][1]);
out[1][2] = (m[1][0] * mtx[0][2]) + (m[1][1] * mtx[1][2]) + (m[1][2] * mtx[2][2]);
out[1][3] = (m[1][0] * mtx[0][3]) + (m[1][1] * mtx[1][3]) + (m[1][2] * mtx[2][3]) + m[1][3];
out[2][0] = (m[2][0] * mtx[0][0]) + (m[2][1] * mtx[1][0]) + (m[2][2] * mtx[2][0]);
out[2][1] = (m[2][0] * mtx[0][1]) + (m[2][1] * mtx[1][1]) + (m[2][2] * mtx[2][1]);
out[2][2] = (m[2][0] * mtx[0][2]) + (m[2][1] * mtx[1][2]) + (m[2][2] * mtx[2][2]);
out[2][3] = (m[2][0] * mtx[0][3]) + (m[2][1] * mtx[1][3]) + (m[2][2] * mtx[2][3]) + m[2][3];
out[3][0] = (m[3][0] * mtx[0][0]) + (m[3][1] * mtx[1][0]) + (m[3][2] * mtx[2][0]);
out[3][1] = (m[3][0] * mtx[0][1]) + (m[3][1] * mtx[1][1]) + (m[3][2] * mtx[2][1]);
out[3][2] = (m[3][0] * mtx[0][2]) + (m[3][1] * mtx[1][2]) + (m[3][2] * mtx[2][2]);
out[3][3] = (m[3][0] * mtx[0][3]) + (m[3][1] * mtx[1][3]) + (m[3][2] * mtx[2][3]) + m[3][3];
return out;
}
CMatrix4f CMatrix4f::operator*(const CMatrix4f& mtx) const
{
CMatrix4f out;
out[0][0] = (m[0][0] * mtx[0][0]) + (m[0][1] * mtx[1][0]) + (m[0][2] * mtx[2][0]) + (m[0][3] * mtx[3][0]);
out[0][1] = (m[0][0] * mtx[0][1]) + (m[0][1] * mtx[1][1]) + (m[0][2] * mtx[2][1]) + (m[0][3] * mtx[3][1]);
out[0][2] = (m[0][0] * mtx[0][2]) + (m[0][1] * mtx[1][2]) + (m[0][2] * mtx[2][2]) + (m[0][3] * mtx[3][2]);
out[0][3] = (m[0][0] * mtx[0][3]) + (m[0][1] * mtx[1][3]) + (m[0][2] * mtx[2][3]) + (m[0][3] * mtx[3][3]);
out[1][0] = (m[1][0] * mtx[0][0]) + (m[1][1] * mtx[1][0]) + (m[1][2] * mtx[2][0]) + (m[1][3] * mtx[3][0]);
out[1][1] = (m[1][0] * mtx[0][1]) + (m[1][1] * mtx[1][1]) + (m[1][2] * mtx[2][1]) + (m[1][3] * mtx[3][1]);
out[1][2] = (m[1][0] * mtx[0][2]) + (m[1][1] * mtx[1][2]) + (m[1][2] * mtx[2][2]) + (m[1][3] * mtx[3][2]);
out[1][3] = (m[1][0] * mtx[0][3]) + (m[1][1] * mtx[1][3]) + (m[1][2] * mtx[2][3]) + (m[1][3] * mtx[3][3]);
out[2][0] = (m[2][0] * mtx[0][0]) + (m[2][1] * mtx[1][0]) + (m[2][2] * mtx[2][0]) + (m[2][3] * mtx[3][0]);
out[2][1] = (m[2][0] * mtx[0][1]) + (m[2][1] * mtx[1][1]) + (m[2][2] * mtx[2][1]) + (m[2][3] * mtx[3][1]);
out[2][2] = (m[2][0] * mtx[0][2]) + (m[2][1] * mtx[1][2]) + (m[2][2] * mtx[2][2]) + (m[2][3] * mtx[3][2]);
out[2][3] = (m[2][0] * mtx[0][3]) + (m[2][1] * mtx[1][3]) + (m[2][2] * mtx[2][3]) + (m[2][3] * mtx[3][3]);
out[3][0] = (m[3][0] * mtx[0][0]) + (m[3][1] * mtx[1][0]) + (m[3][2] * mtx[2][0]) + (m[3][3] * mtx[3][0]);
out[3][1] = (m[3][0] * mtx[0][1]) + (m[3][1] * mtx[1][1]) + (m[3][2] * mtx[2][1]) + (m[3][3] * mtx[3][1]);
out[3][2] = (m[3][0] * mtx[0][2]) + (m[3][1] * mtx[1][2]) + (m[3][2] * mtx[2][2]) + (m[3][3] * mtx[3][2]);
out[3][3] = (m[3][0] * mtx[0][3]) + (m[3][1] * mtx[1][3]) + (m[3][2] * mtx[2][3]) + (m[3][3] * mtx[3][3]);
return out;
}
// ************ CONSTANT ************
const CMatrix4f CMatrix4f::skZero(0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f);
const CMatrix4f CMatrix4f::skIdentity(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);

View File

@@ -0,0 +1,50 @@
#ifndef CMATRIX4_H
#define CMATRIX4_H
#include <glm.hpp>
class CVector3f;
class CVector4f;
class CTransform4f;
class CMatrix4f
{
union
{
float m[4][4];
float _m[16];
};
public:
CMatrix4f();
CMatrix4f(float v);
CMatrix4f(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33);
// Math
CMatrix4f Transpose() const;
CMatrix4f Inverse() const;
float Determinant() const;
// Conversion
glm::mat4 ToGlmMat4() const;
// Static
static CMatrix4f FromGlmMat4(glm::mat4 src);
// Operators
inline float* operator[](long index);
inline const float* operator[](long index) const;
CVector3f operator*(const CVector3f& vec) const;
CVector4f operator*(const CVector4f& vec) const;
CMatrix4f operator*(const CTransform4f& mtx) const;
CMatrix4f operator*(const CMatrix4f& mtx) const;
// Constants
static const CMatrix4f skZero;
static const CMatrix4f skIdentity;
};
#endif // CMATRIX4_H

View File

@@ -0,0 +1,44 @@
#include "CPlane.h"
CPlane::CPlane()
{
mNormal = CVector3f::skUp;
mDist = 0.f;
}
CPlane::CPlane(const CVector3f& normal, float dist)
{
mNormal = normal;
mDist = dist;
}
CPlane::CPlane(const CVector3f& normal, const CVector3f& origin)
{
Redefine(normal, origin);
}
void CPlane::Redefine(const CVector3f& normal, const CVector3f& origin)
{
mNormal = normal;
mDist = -normal.Dot(origin);
}
CVector3f CPlane::Normal() const
{
return mNormal;
}
float CPlane::Dist() const
{
return mDist;
}
void CPlane::SetNormal(const CVector3f& normal)
{
mNormal = normal;
}
void CPlane::SetDist(float dist)
{
mDist = dist;
}

23
src/Common/Math/CPlane.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef CPLANE_H
#define CPLANE_H
#include "CVector3f.h"
class CPlane
{
CVector3f mNormal;
float mDist;
public:
CPlane();
CPlane(const CVector3f& normal, float dist);
CPlane(const CVector3f& normal, const CVector3f& origin);
void Redefine(const CVector3f& normal, const CVector3f& origin);
CVector3f Normal() const;
float Dist() const;
void SetNormal(const CVector3f& normal);
void SetDist(float dist);
};
#endif // CPLANE_H

View File

@@ -0,0 +1,195 @@
#include "CQuaternion.h"
#include <cmath>
#include <math.h>
#include "Math.h"
#include "CMatrix4f.h"
CQuaternion::CQuaternion()
{
w = 0.f;
x = 0.f;
y = 0.f;
z = 0.f;
}
CQuaternion::CQuaternion(float _w, float _x, float _y, float _z)
{
w = _w;
x = _x;
y = _y;
z = _z;
}
CVector3f CQuaternion::XAxis()
{
return (*this * CVector3f::skUnitX);
}
CVector3f CQuaternion::YAxis()
{
return (*this * CVector3f::skUnitY);
}
CVector3f CQuaternion::ZAxis()
{
return (*this * CVector3f::skUnitZ);
}
CQuaternion CQuaternion::Inverse()
{
float fNorm = (w * w) + (x * x) + (y * y) + (z * z);
if (fNorm > 0.f)
{
float fInvNorm = 1.f / fNorm;
return CQuaternion( w * fInvNorm, -x * fInvNorm, -y * fInvNorm, -z * fInvNorm);
}
else
return CQuaternion::skZero;
}
CVector3f CQuaternion::ToEuler()
{
// There is more than one way to do this conversion, based on rotation order.
// But since we only care about the rotation order used in Retro games, which is consistent,
// we can just have a single conversion function. Handy!
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
float ex = atan2f(2 * (w*x + y*z), 1 - (2 * (Math::Pow(x,2) + Math::Pow(y,2))));
float ey = asinf(2 * (w*y - z*x));
float ez = atan2f(2 * (w*z + x*y), 1 - (2 * (Math::Pow(y,2) + Math::Pow(z,2))));
return CVector3f(Math::RadiansToDegrees(ex), Math::RadiansToDegrees(ey), Math::RadiansToDegrees(ez));
}
// ************ OPERATORS ************
CVector3f CQuaternion::operator*(const CVector3f& vec) const
{
CVector3f uv, uuv;
CVector3f qvec(x, y, z);
uv = qvec.Cross(vec);
uuv = qvec.Cross(uv);
uv *= (2.0f * w);
uuv *= 2.0f;
return vec + uv + uuv;
}
CQuaternion CQuaternion::operator*(const CQuaternion& other) const
{
CQuaternion out;
out.w = (-x * other.x) - (y * other.y) - (z * other.z) + (w * other.w);
out.x = ( x * other.w) + (y * other.z) - (z * other.y) + (w * other.x);
out.y = (-x * other.z) + (y * other.w) + (z * other.x) + (w * other.y);
out.z = ( x * other.y) - (y * other.x) + (z * other.w) + (w * other.z);
return out;
}
void CQuaternion::operator *= (const CQuaternion& other)
{
*this = *this * other;
}
// ************ STATIC ************
CQuaternion CQuaternion::FromEuler(CVector3f euler)
{
/**
* The commented-out code below might be faster but the conversion isn't completely correct
* So in lieu of fixing it I'm using axis angles to convert from Eulers instead
* I'm not sure what the difference is performance-wise but the result is 100% accurate
*/
/*CQuaternion quat;
// Convert from degrees to radians
float pi = 3.14159265358979323846f;
euler = euler * pi / 180;
// Convert to quaternion
float c1 = cos(euler.x / 2);
float c2 = cos(euler.y / 2);
float c3 = cos(euler.z / 2);
float s1 = sin(euler.x / 2);
float s2 = sin(euler.y / 2);
float s3 = sin(euler.z / 2);
quat.w = (c1 * c2 * c3) - (s1 * s2 * s3);
quat.x = -((s1 * c2 * c3) + (c1 * s2 * s3));
quat.y = ((c1 * s2 * c3) - (s1 * c2 * s3));
quat.z = ((s1 * s2 * c3) + (c1 * c2 * s3));*/
CQuaternion x = CQuaternion::FromAxisAngle(Math::DegreesToRadians(euler.x), CVector3f(1,0,0));
CQuaternion y = CQuaternion::FromAxisAngle(Math::DegreesToRadians(euler.y), CVector3f(0,1,0));
CQuaternion z = CQuaternion::FromAxisAngle(Math::DegreesToRadians(euler.z), CVector3f(0,0,1));
CQuaternion quat = z * y * x;
return quat;
}
CQuaternion CQuaternion::FromAxisAngle(float angle, CVector3f axis)
{
CQuaternion quat;
axis = axis.Normalized();
float sa = sinf(angle / 2);
quat.w = cosf(angle / 2);
quat.x = axis.x * sa;
quat.y = axis.y * sa;
quat.z = axis.z * sa;
return quat;
}
CQuaternion CQuaternion::FromRotationMatrix(const CMatrix4f& RotMtx)
{
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
CQuaternion out;
float trace = RotMtx[0][0] + RotMtx[1][1] + RotMtx[2][2];
if (trace > 0.f)
{
float s = Math::Sqrt(trace + 1.f) * 2; // s = 4*w
out.w = 0.25f * s;
out.x = (RotMtx[2][1] - RotMtx[1][2]) / s;
out.y = (RotMtx[0][2] - RotMtx[2][0]) / s;
out.z = (RotMtx[1][0] - RotMtx[0][1]) / s;
}
else if ((RotMtx[0][0] > RotMtx[1][1]) && (RotMtx[0][0] > RotMtx[2][2]))
{
float s = Math::Sqrt(1.f + RotMtx[0][0] - RotMtx[1][1] - RotMtx[2][2]) * 2; // s = 4*x
out.w = (RotMtx[2][1] - RotMtx[1][2]) / s;
out.x = 0.25f * s;
out.y = (RotMtx[0][1] + RotMtx[1][0]) / s;
out.z = (RotMtx[0][2] + RotMtx[2][0]) / s;
}
else if (RotMtx[1][1] > RotMtx[2][2]) {
float s = Math::Sqrt(1.f + RotMtx[1][1] - RotMtx[0][0] - RotMtx[2][2]) * 2; // s = 4*y
out.w = (RotMtx[0][2] - RotMtx[2][0]) / s;
out.x = (RotMtx[0][1] + RotMtx[1][0]) / s;
out.y = 0.25f * s;
out.z = (RotMtx[1][2] + RotMtx[2][1]) / s;
}
else {
float s = Math::Sqrt(1.f + RotMtx[2][2] - RotMtx[0][0] - RotMtx[1][1]) * 2; // S=4*qz
out.w = (RotMtx[1][0] - RotMtx[0][1]) / s;
out.x = (RotMtx[0][2] + RotMtx[2][0]) / s;
out.y = (RotMtx[1][2] + RotMtx[2][1]) / s;
out.z = 0.25f * s;
}
return out;
}
CQuaternion CQuaternion::FromAxes(const CVector3f& X, const CVector3f& Y, const CVector3f& Z)
{
CMatrix4f RotMtx(X.x, Y.x, Z.x, 0.f,
X.y, Y.y, Z.y, 0.f,
X.z, Y.z, Z.z, 0.f,
0.f, 0.f, 0.f, 1.f);
return CQuaternion::FromRotationMatrix(RotMtx);
}
CQuaternion CQuaternion::skIdentity = CQuaternion(1.f, 0.f, 0.f, 0.f);
CQuaternion CQuaternion::skZero = CQuaternion(0.f, 0.f, 0.f, 0.f);

View File

@@ -0,0 +1,35 @@
#ifndef CQUATERNION_H
#define CQUATERNION_H
#include "CVector3f.h"
class CQuaternion
{
public:
float w, x, y, z;
CQuaternion();
CQuaternion(float _w, float _x, float _y, float _z);
CVector3f XAxis();
CVector3f YAxis();
CVector3f ZAxis();
CQuaternion Inverse();
CVector3f ToEuler();
// Operators
CVector3f operator*(const CVector3f& vec) const;
CQuaternion operator*(const CQuaternion& other) const;
void operator *= (const CQuaternion& other);
// Static
static CQuaternion FromEuler(CVector3f euler);
static CQuaternion FromAxisAngle(float angle, CVector3f axis);
static CQuaternion FromRotationMatrix(const CMatrix4f& RotMtx);
static CQuaternion FromAxes(const CVector3f& X, const CVector3f& Y, const CVector3f& Z);
static CQuaternion skIdentity;
static CQuaternion skZero;
};
#endif // CQUATERNION_H

43
src/Common/Math/CRay.cpp Normal file
View File

@@ -0,0 +1,43 @@
#include "CRay.h"
#include <Common/CVector4f.h>
#include <Common/CTransform4f.h>
#include <iostream>
CRay::CRay()
{
}
CRay::CRay(const CVector3f& Origin, const CVector3f& Direction)
: mOrigin(Origin), mDirection(Direction)
{
}
CRay::~CRay()
{
}
void CRay::SetOrigin(const CVector3f& Origin)
{
mOrigin = Origin;
}
void CRay::SetDirection(const CVector3f& Direction)
{
mDirection = Direction;
}
CRay CRay::Transformed(const CTransform4f &Matrix) const
{
CRay out;
out.mOrigin = Matrix * mOrigin;
CVector3f Point = Matrix * (mOrigin + mDirection);
out.mDirection = (Point - out.mOrigin).Normalized();
return out;
}
CVector3f CRay::PointOnRay(float Distance) const
{
return mOrigin + (mDirection * Distance);
}

35
src/Common/Math/CRay.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef CRAY_H
#define CRAY_H
#include "CVector3f.h"
class CRay
{
CVector3f mOrigin;
CVector3f mDirection;
public:
CRay();
CRay(const CVector3f& Origin, const CVector3f& Direction);
~CRay();
const CVector3f& Origin() const;
const CVector3f& Direction() const;
void SetOrigin(const CVector3f& Origin);
void SetDirection(const CVector3f& Direction);
CRay Transformed(const CTransform4f& Matrix) const;
CVector3f PointOnRay(float Distance) const;
};
// ************ INLINE FUNCTIONS ************
inline const CVector3f& CRay::Origin() const
{
return mOrigin;
}
inline const CVector3f& CRay::Direction() const
{
return mDirection;
}
#endif // CRAY_H

View File

@@ -0,0 +1,309 @@
#include "CTransform4f.h"
#include "CVector3f.h"
#include "CVector4f.h"
#include "CQuaternion.h"
#include "CMatrix4f.h"
// ************ CONSTRUCTRS ************
CTransform4f::CTransform4f()
{
*this = skIdentity;
}
CTransform4f::CTransform4f(CInputStream& input)
{
for (int v = 0; v < 12; v++)
_m[v] = input.ReadFloat();
}
CTransform4f::CTransform4f(float v)
{
*this = skZero;
m[0][0] = v;
m[1][1] = v;
m[2][2] = v;
}
CTransform4f::CTransform4f(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23)
{
m[0][0] = m00;
m[0][1] = m01;
m[0][2] = m02;
m[0][3] = m03;
m[1][0] = m10;
m[1][1] = m11;
m[1][2] = m12;
m[1][3] = m13;
m[2][0] = m20;
m[2][1] = m21;
m[2][2] = m22;
m[2][3] = m23;
}
CTransform4f::CTransform4f(CVector3f Position, CQuaternion Rotation, CVector3f Scale)
{
*this = skIdentity;
Translate(Position);
Rotate(Rotation);
this->Scale(Scale);
}
CTransform4f::CTransform4f(CVector3f, CVector3f, CVector3f)
{
}
// ************ MATH ************
void CTransform4f::Translate(CVector3f Translation)
{
CTransform4f TranslateMtx = CTransform4f::TranslationMatrix(Translation);
*this = TranslateMtx * *this;
}
void CTransform4f::Translate(float XTrans, float YTrans, float ZTrans)
{
Translate(CVector3f(XTrans, YTrans, ZTrans));
}
void CTransform4f::Rotate(CQuaternion Rotation)
{
CTransform4f RotateMtx = CTransform4f::RotationMatrix(Rotation);
*this = RotateMtx * *this;
}
void CTransform4f::Rotate(CVector3f Rotation)
{
CQuaternion quat = CQuaternion::FromEuler(Rotation);
Rotate(quat);
}
void CTransform4f::Rotate(float XRot, float YRot, float ZRot)
{
Rotate(CVector3f(XRot, YRot, ZRot));
}
void CTransform4f::Scale(CVector3f Scale)
{
CTransform4f ScaleMtx = CTransform4f::ScaleMatrix(Scale);
*this = ScaleMtx * *this;
}
void CTransform4f::Scale(float XScale, float YScale, float ZScale)
{
Scale(CVector3f(XScale, YScale, ZScale));
}
CTransform4f CTransform4f::MultiplyIgnoreTranslation(const CTransform4f& mtx) const
{
CTransform4f out;
out[0][0] = (m[0][0] * mtx[0][0]) + (m[0][1] * mtx[1][0]) + (m[0][2] * mtx[2][0]);
out[0][1] = (m[0][0] * mtx[0][1]) + (m[0][1] * mtx[1][1]) + (m[0][2] * mtx[2][1]);
out[0][2] = (m[0][0] * mtx[0][2]) + (m[0][1] * mtx[1][2]) + (m[0][2] * mtx[2][2]);
out[1][0] = (m[1][0] * mtx[0][0]) + (m[1][1] * mtx[1][0]) + (m[1][2] * mtx[2][0]);
out[1][1] = (m[1][0] * mtx[0][1]) + (m[1][1] * mtx[1][1]) + (m[1][2] * mtx[2][1]);
out[1][2] = (m[1][0] * mtx[0][2]) + (m[1][1] * mtx[1][2]) + (m[1][2] * mtx[2][2]);
out[2][0] = (m[2][0] * mtx[0][0]) + (m[2][1] * mtx[1][0]) + (m[2][2] * mtx[2][0]);
out[2][1] = (m[2][0] * mtx[0][1]) + (m[2][1] * mtx[1][1]) + (m[2][2] * mtx[2][1]);
out[2][2] = (m[2][0] * mtx[0][2]) + (m[2][1] * mtx[1][2]) + (m[2][2] * mtx[2][2]);
out[0][3] = 0.f;
out[1][3] = 0.f;
out[2][3] = 0.f;
return out;
}
CTransform4f CTransform4f::Inverse() const
{
// This uses CMatrix4f because I suck at math
// todo - rewrite this without using CMatrix4f
CMatrix4f Mat4 = ToMatrix4f().Inverse();
CTransform4f Out;
memcpy(&Out[0][0], &Mat4[0][0], sizeof(CTransform4f));
return Out;
}
CTransform4f CTransform4f::QuickInverse() const
{
CTransform4f out;
out[0][0] = m[0][0];
out[0][1] = m[1][0];
out[0][2] = m[2][0];
out[0][3] = -((m[0][0] * m[0][3]) + (m[1][0] * m[1][3]) + (m[2][0] * m[2][3]));
out[1][0] = m[0][1];
out[1][1] = m[1][1];
out[1][2] = m[2][1];
out[1][3] = -((m[0][1] * m[0][3]) + (m[1][1] * m[1][3]) + (m[2][1] * m[2][3]));
out[2][0] = m[0][2];
out[2][1] = m[1][2];
out[2][2] = m[2][2];
out[2][3] = -((m[0][2] * m[0][3]) + (m[1][2] * m[1][3]) + (m[2][2] * m[2][3]));
return out;
}
CTransform4f CTransform4f::NoTranslation() const
{
return CTransform4f(m[0][0], m[0][1], m[0][2], 0.f,
m[1][0], m[1][1], m[1][2], 0.f,
m[2][0], m[2][1], m[2][2], 0.f);
}
CTransform4f CTransform4f::RotationOnly() const
{
return CTransform4f::FromMatrix4f(Inverse().ToMatrix4f().Transpose());
}
// ************ OPERATORS ************
float* CTransform4f::operator[](long index)
{
return m[index];
}
const float* CTransform4f::operator[](long index) const
{
return m[index];
}
CVector3f CTransform4f::operator*(const CVector3f& vec) const
{
CVector3f out;
out.x = (m[0][0] * vec.x) + (m[0][1] * vec.y) + (m[0][2] * vec.z) + (m[0][3]);
out.y = (m[1][0] * vec.x) + (m[1][1] * vec.y) + (m[1][2] * vec.z) + (m[1][3]);
out.z = (m[2][0] * vec.x) + (m[2][1] * vec.y) + (m[2][2] * vec.z) + (m[2][3]);
return out;
}
CVector4f CTransform4f::operator*(const CVector4f& vec) const
{
CVector4f out;
out.x = (m[0][0] * vec.x) + (m[0][1] * vec.y) + (m[0][2] * vec.z) + (m[0][3] * vec.w);
out.y = (m[1][0] * vec.x) + (m[1][1] * vec.y) + (m[1][2] * vec.z) + (m[1][3] * vec.w);
out.z = (m[2][0] * vec.x) + (m[2][1] * vec.y) + (m[2][2] * vec.z) + (m[2][3] * vec.w);
out.w = vec.w;
return out;
}
CTransform4f CTransform4f::operator*(const CTransform4f& mtx) const
{
CTransform4f out;
out[0][0] = (m[0][0] * mtx[0][0]) + (m[0][1] * mtx[1][0]) + (m[0][2] * mtx[2][0]);
out[0][1] = (m[0][0] * mtx[0][1]) + (m[0][1] * mtx[1][1]) + (m[0][2] * mtx[2][1]);
out[0][2] = (m[0][0] * mtx[0][2]) + (m[0][1] * mtx[1][2]) + (m[0][2] * mtx[2][2]);
out[0][3] = (m[0][0] * mtx[0][3]) + (m[0][1] * mtx[1][3]) + (m[0][2] * mtx[2][3]) + m[0][3];
out[1][0] = (m[1][0] * mtx[0][0]) + (m[1][1] * mtx[1][0]) + (m[1][2] * mtx[2][0]);
out[1][1] = (m[1][0] * mtx[0][1]) + (m[1][1] * mtx[1][1]) + (m[1][2] * mtx[2][1]);
out[1][2] = (m[1][0] * mtx[0][2]) + (m[1][1] * mtx[1][2]) + (m[1][2] * mtx[2][2]);
out[1][3] = (m[1][0] * mtx[0][3]) + (m[1][1] * mtx[1][3]) + (m[1][2] * mtx[2][3]) + m[1][3];
out[2][0] = (m[2][0] * mtx[0][0]) + (m[2][1] * mtx[1][0]) + (m[2][2] * mtx[2][0]);
out[2][1] = (m[2][0] * mtx[0][1]) + (m[2][1] * mtx[1][1]) + (m[2][2] * mtx[2][1]);
out[2][2] = (m[2][0] * mtx[0][2]) + (m[2][1] * mtx[1][2]) + (m[2][2] * mtx[2][2]);
out[2][3] = (m[2][0] * mtx[0][3]) + (m[2][1] * mtx[1][3]) + (m[2][2] * mtx[2][3]) + m[2][3];
return out;
}
void CTransform4f::operator*=(const CTransform4f& mtx)
{
*this = *this * mtx;
}
bool CTransform4f::operator==(const CTransform4f& mtx) const
{
return ((m[0][0] == mtx[0][0]) &&
(m[0][1] == mtx[0][1]) &&
(m[0][2] == mtx[0][2]) &&
(m[0][3] == mtx[0][3]) &&
(m[1][0] == mtx[1][0]) &&
(m[1][1] == mtx[1][1]) &&
(m[1][2] == mtx[1][2]) &&
(m[1][3] == mtx[1][3]) &&
(m[2][0] == mtx[2][0]) &&
(m[2][1] == mtx[2][1]) &&
(m[2][2] == mtx[2][2]) &&
(m[2][3] == mtx[2][3]));
}
bool CTransform4f::operator!=(const CTransform4f& mtx) const
{
return (!(*this == mtx));
}
// ************ CONVERSION ************
CMatrix4f CTransform4f::ToMatrix4f() const
{
return CMatrix4f(m[0][0], m[0][1], m[0][2], m[0][3],
m[1][0], m[1][1], m[1][2], m[1][3],
m[2][0], m[2][1], m[2][2], m[2][3],
0.f, 0.f, 0.f, 1.f);
}
// ************ STATIC ************
CTransform4f CTransform4f::TranslationMatrix(CVector3f Translation)
{
CTransform4f out = skIdentity;
out[0][3] = Translation.x;
out[1][3] = Translation.y;
out[2][3] = Translation.z;
return out;
}
CTransform4f CTransform4f::RotationMatrix(CQuaternion Rotation)
{
CTransform4f out = skIdentity;
float x = Rotation.x;
float y = Rotation.y;
float z = Rotation.z;
float w = Rotation.w;
float x2 = x * x;
float y2 = y * y;
float z2 = z * z;
out[0][0] = 1.0f - (2 * y2) - (2 * z2);
out[0][1] = (2 * x * y) - (2 * z * w);
out[0][2] = (2 * x * z) + (2 * y * w);
out[1][0] = (2 * x * y) + (2 * z * w);
out[1][1] = 1.0f - (2 * x2) - (2 * z2);
out[1][2] = (2 * y * z) - (2 * x * w);
out[2][0] = (2 * x * z) - (2 * y * w);
out[2][1] = (2 * y * z) + (2 * x * w);
out[2][2] = 1.0f - (2 * x2) - (2 * y2);
return out;
}
CTransform4f CTransform4f::ScaleMatrix(CVector3f Scale)
{
CTransform4f out = skIdentity;
out[0][0] = Scale.x;
out[1][1] = Scale.y;
out[2][2] = Scale.z;
return out;
}
CTransform4f CTransform4f::FromMatrix4f(const CMatrix4f& mtx)
{
CTransform4f out;
for (int r = 0; r < 3; r++)
for (int c = 0; c < 4; c++)
out[r][c] = mtx[r][c];
return out;
}
CTransform4f CTransform4f::FromGlmMat4(const glm::mat4& mtx)
{
CTransform4f out;
for (int r = 0; r < 3; r++)
for (int c = 0; c < 4; c++)
out[r][c] = mtx[r][c];
return out;
}
static CTransform4f FromGlmMat4(const glm::mat4&)
{
}
// ************ CONSTANTS ************
const CTransform4f CTransform4f::skIdentity(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f);
const CTransform4f CTransform4f::skZero(0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f);

View File

@@ -0,0 +1,70 @@
#ifndef CTRANSFORM4F_H
#define CTRANSFORM4F_H
#include <FileIO/FileIO.h>
#include "CMatrix4f.h"
#include <glm.hpp>
class CVector3f;
class CVector4f;
class CQuaternion;
class CMatrix4f;
class CTransform4f
{
union
{
float m[3][4];
float _m[12];
};
public:
CTransform4f();
CTransform4f(CInputStream& input);
CTransform4f(float v);
CTransform4f(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23);
CTransform4f(CVector3f Position, CQuaternion Rotation, CVector3f Scale);
CTransform4f(CVector3f Position, CVector3f Rotation, CVector3f Scale);
// Math
void Translate(CVector3f Translation);
void Translate(float XTrans, float YTrans, float ZTrans);
void Rotate(CQuaternion Rotation);
void Rotate(CVector3f Rotation);
void Rotate(float XRot, float YRot, float ZRot);
void Scale(CVector3f Scale);
void Scale(float XScale, float YScale, float ZScale);
CTransform4f MultiplyIgnoreTranslation(const CTransform4f& mtx) const;
CTransform4f Inverse() const;
CTransform4f QuickInverse() const;
CTransform4f NoTranslation() const;
CTransform4f RotationOnly() const;
// Conversion
CMatrix4f ToMatrix4f() const;
// Static
static CTransform4f TranslationMatrix(CVector3f Translation);
static CTransform4f RotationMatrix(CQuaternion Rotation);
static CTransform4f ScaleMatrix(CVector3f Scale);
static CTransform4f FromMatrix4f(const CMatrix4f& mtx);
static CTransform4f FromGlmMat4(const glm::mat4& mtx);
// Operators
float* operator[](long index);
const float* operator[](long index) const;
CVector3f operator*(const CVector3f& vec) const;
CVector4f operator*(const CVector4f& vec) const;
CTransform4f operator*(const CTransform4f& mtx) const;
void operator*=(const CTransform4f& mtx);
bool operator==(const CTransform4f& mtx) const;
bool operator!=(const CTransform4f& mtx) const;
// Constant
static const CTransform4f skIdentity;
static const CTransform4f skZero;
};
#endif // CTRANSFORM4F_H

View File

@@ -0,0 +1,186 @@
#include "CVector2f.h"
CVector2f::CVector2f()
{
x = y = 0.f;
}
CVector2f::CVector2f(float xy)
{
x = y = xy;
}
CVector2f::CVector2f(float _x, float _y)
{
x = _x;
y = _y;
}
CVector2f::CVector2f(CInputStream& Input)
{
x = Input.ReadFloat();
y = Input.ReadFloat();
}
void CVector2f::Write(COutputStream &Output)
{
Output.WriteFloat(x);
Output.WriteFloat(y);
}
float CVector2f::Magnitude() const
{
return sqrtf(SquaredMagnitude());
}
float CVector2f::SquaredMagnitude() const
{
return Dot(*this);
}
CVector2f CVector2f::Normalized() const
{
return *this / Magnitude();
}
float CVector2f::Dot(const CVector2f& other) const
{
return ((x * other.x) + (y * other.y));
}
CVector2f CVector2f::operator+(const CVector2f& src) const
{
CVector2f out;
out.x = this->x + src.x;
out.y = this->y + src.y;
return out;
}
CVector2f CVector2f::operator-(const CVector2f& src) const
{
CVector2f out;
out.x = this->x - src.x;
out.y = this->y - src.y;
return out;
}
CVector2f CVector2f::operator*(const CVector2f& src) const
{
CVector2f out;
out.x = this->x * src.x;
out.y = this->y * src.y;
return out;
}
CVector2f CVector2f::operator/(const CVector2f& src) const
{
CVector2f out;
out.x = this->x / src.x;
out.y = this->y / src.y;
return out;
}
void CVector2f::operator+=(const CVector2f& other)
{
*this = *this + other;
}
void CVector2f::operator-=(const CVector2f& other)
{
*this = *this - other;
}
void CVector2f::operator*=(const CVector2f& other)
{
*this = *this * other;
}
void CVector2f::operator/=(const CVector2f& other)
{
*this = *this / other;
}
CVector2f CVector2f::operator+(const float src) const
{
CVector2f out;
out.x = this->x + src;
out.y = this->y + src;
return out;
}
CVector2f CVector2f::operator-(const float src) const
{
CVector2f out;
out.x = this->x - src;
out.y = this->y - src;
return out;
}
CVector2f CVector2f::operator*(const float src) const
{
CVector2f out;
out.x = this->x * src;
out.y = this->y * src;
return out;
}
CVector2f CVector2f::operator/(const float src) const
{
CVector2f out;
out.x = this->x / src;
out.y = this->y / src;
return out;
}
void CVector2f::operator+=(const float other)
{
*this = *this + other;
}
void CVector2f::operator-=(const float other)
{
*this = *this - other;
}
void CVector2f::operator*=(const float other)
{
*this = *this * other;
}
void CVector2f::operator/=(const float other)
{
*this = *this / other;
}
bool CVector2f::operator==(const CVector2f& other) const
{
return ((x == other.x) && (y == other.y));
}
bool CVector2f::operator!=(const CVector2f& other) const
{
return (!(*this == other));
}
CVector2f CVector2f::operator-() const
{
return CVector2f(-x, -y);
}
float& CVector2f::operator[](long index)
{
return (&x)[index];
}
const float& CVector2f::operator[](long index) const
{
return (&x)[index];
}
// ************ STATIC MEMBER INITIALIZATION ************
const CVector2f CVector2f::skZero = CVector2f(0, 0);
const CVector2f CVector2f::skOne = CVector2f(1, 1);
const CVector2f CVector2f::skUp = CVector2f(0, 1);
const CVector2f CVector2f::skRight = CVector2f(1, 0);
const CVector2f CVector2f::skDown = CVector2f(0,-1);
const CVector2f CVector2f::skLeft = CVector2f(-1,0);

View File

@@ -0,0 +1,53 @@
#ifndef CVECTOR2F
#define CVECTOR2F
#include <FileIO/CInputStream.h>
#include <FileIO/COutputStream.h>
class CVector2f
{
public:
float x, y;
CVector2f();
CVector2f(float xy);
CVector2f(float _x, float _y);
CVector2f(CInputStream& Input);
void Write(COutputStream& Output);
float Magnitude() const;
float SquaredMagnitude() const;
CVector2f Normalized() const;
float Dot(const CVector2f& other) const;
CVector2f operator+(const CVector2f& other) const;
CVector2f operator-(const CVector2f& other) const;
CVector2f operator*(const CVector2f& other) const;
CVector2f operator/(const CVector2f& other) const;
void operator+=(const CVector2f& other);
void operator-=(const CVector2f& other);
void operator*=(const CVector2f& other);
void operator/=(const CVector2f& other);
CVector2f operator+(const float other) const;
CVector2f operator-(const float other) const;
CVector2f operator*(const float other) const;
CVector2f operator/(const float other) const;
void operator+=(const float other);
void operator-=(const float other);
void operator*=(const float other);
void operator/=(const float other);
bool operator==(const CVector2f& other) const;
bool operator!=(const CVector2f& other) const;
CVector2f operator-() const;
float& operator[](long index);
const float& operator[](long index) const;
// Static Members
static const CVector2f skZero;
static const CVector2f skOne;
static const CVector2f skUp;
static const CVector2f skRight;
static const CVector2f skDown;
static const CVector2f skLeft;
};
#endif // CVECTOR2F

View File

@@ -0,0 +1,139 @@
#include "CVector2i.h"
CVector2i::CVector2i()
{
x = y = 0;
}
CVector2i::CVector2i(int xy)
{
x = y = xy;
}
CVector2i::CVector2i(int _x, int _y)
{
x = _x;
y = _y;
}
CVector2i CVector2i::operator+(const CVector2i& other) const
{
CVector2i out;
out.x = this->x + other.x;
out.y = this->y + other.y;
return out;
}
CVector2i CVector2i::operator-(const CVector2i& other) const
{
CVector2i out;
out.x = this->x - other.x;
out.y = this->y - other.y;
return out;
}
CVector2i CVector2i::operator*(const CVector2i& other) const
{
CVector2i out;
out.x = this->x * other.x;
out.y = this->y * other.y;
return out;
}
CVector2i CVector2i::operator/(const CVector2i& other) const
{
CVector2i out;
out.x = this->x / other.x;
out.y = this->y / other.y;
return out;
}
void CVector2i::operator+=(const CVector2i& other)
{
*this = *this + other;
}
void CVector2i::operator-=(const CVector2i& other)
{
*this = *this - other;
}
void CVector2i::operator*=(const CVector2i& other)
{
*this = *this * other;
}
void CVector2i::operator/=(const CVector2i& other)
{
*this = *this / other;
}
CVector2i CVector2i::operator+(const int other) const
{
CVector2i out;
out.x = this->x + other;
out.y = this->y + other;
return out;
}
CVector2i CVector2i::operator-(const int other) const
{
CVector2i out;
out.x = this->x - other;
out.y = this->y - other;
return out;
}
CVector2i CVector2i::operator*(const int other) const
{
CVector2i out;
out.x = this->x * other;
out.y = this->y * other;
return out;
}
CVector2i CVector2i::operator/(const int other) const
{
CVector2i out;
out.x = this->x / other;
out.y = this->y / other;
return out;
}
void CVector2i::operator+=(const int other)
{
*this = *this + other;
}
void CVector2i::operator-=(const int other)
{
*this = *this - other;
}
void CVector2i::operator*=(const int other)
{
*this = *this * other;
}
void CVector2i::operator/=(const int other)
{
*this = *this / other;
}
bool CVector2i::operator==(const CVector2i& other) const
{
return ((this->x == other.x) && (this->y == other.y));
}
bool CVector2i::operator!=(const CVector2i& other) const
{
return (!(*this == other));
}
int& CVector2i::operator[](int index)
{
return (&x)[index];
}
// ************ STATIC MEMBER INTIALIZATION ************
const CVector2i CVector2i::skZero = CVector2i(0,0);

View File

@@ -0,0 +1,39 @@
#ifndef CVECTOR2I_H
#define CVECTOR2I_H
#include <FileIO/CInputStream.h>
#include <FileIO/COutputStream.h>
class CVector2i
{
public:
int x, y;
CVector2i();
CVector2i(int xy);
CVector2i(int _x, int _y);
CVector2i operator+(const CVector2i& other) const;
CVector2i operator-(const CVector2i& other) const;
CVector2i operator*(const CVector2i& other) const;
CVector2i operator/(const CVector2i& other) const;
void operator+=(const CVector2i& other);
void operator-=(const CVector2i& other);
void operator*=(const CVector2i& other);
void operator/=(const CVector2i& other);
CVector2i operator+(const int other) const;
CVector2i operator-(const int other) const;
CVector2i operator*(const int other) const;
CVector2i operator/(const int other) const;
void operator+=(const int other);
void operator-=(const int other);
void operator*=(const int other);
void operator/=(const int other);
bool operator==(const CVector2i& other) const;
bool operator!=(const CVector2i& other) const;
int& operator[](int index);
// Static Members
static const CVector2i skZero;
};
#endif // CVECTOR2I_H

View File

@@ -0,0 +1,309 @@
#include "CVector3f.h"
#include "CVector2f.h"
#include "CVector4f.h"
#include "CTransform4f.h"
#include <iomanip>
#include <float.h>
CVector3f::CVector3f()
{
x = y = z = 0.f;
}
CVector3f::CVector3f(float xyz)
{
x = y = z = xyz;
}
CVector3f::CVector3f(float _x, float _y, float _z)
{
x = _x;
y = _y;
z = _z;
}
CVector3f::CVector3f(CInputStream& Input)
{
x = Input.ReadFloat();
y = Input.ReadFloat();
z = Input.ReadFloat();
}
void CVector3f::Write(COutputStream &Output)
{
Output.WriteFloat(x);
Output.WriteFloat(y);
Output.WriteFloat(z);
}
// ************ SWIZZLE ************
CVector2f CVector3f::xy()
{
return CVector2f(x, y);
}
CVector2f CVector3f::xz()
{
return CVector2f(x, z);
}
CVector2f CVector3f::yz()
{
return CVector2f(y, z);
}
// ************ MATH ************
float CVector3f::Magnitude() const
{
return sqrtf(SquaredMagnitude());
}
float CVector3f::SquaredMagnitude() const
{
return Dot(*this);
}
CVector3f CVector3f::Normalized() const
{
return *this / Magnitude();
}
float CVector3f::Dot(const CVector3f& other) const
{
return (x * other.x) + (y * other.y) + (z * other.z);
}
CVector3f CVector3f::Cross(const CVector3f& other) const
{
return CVector3f((y * other.z) - (z * other.y), (z * other.x) - (x * other.z), (x * other.y) - (y * other.x));
}
float CVector3f::Distance(const CVector3f& point) const
{
return (*this - point).Magnitude();
}
float CVector3f::SquaredDistance(const CVector3f& point) const
{
return (*this - point).SquaredMagnitude();
}
// ************ OPERATORS ************
// VECTOR/VECTOR
CVector3f CVector3f::operator+(const CVector3f& src) const
{
CVector3f out;
out.x = this->x + src.x;
out.y = this->y + src.y;
out.z = this->z + src.z;
return out;
}
CVector3f CVector3f::operator-(const CVector3f& src) const
{
CVector3f out;
out.x = this->x - src.x;
out.y = this->y - src.y;
out.z = this->z - src.z;
return out;
}
CVector3f CVector3f::operator*(const CVector3f& src) const
{
CVector3f out;
out.x = this->x * src.x;
out.y = this->y * src.y;
out.z = this->z * src.z;
return out;
}
CVector3f CVector3f::operator/(const CVector3f& src) const
{
CVector3f out;
out.x = this->x / src.x;
out.y = this->y / src.y;
out.z = this->z / src.z;
return out;
}
void CVector3f::operator+=(const CVector3f& other)
{
*this = *this + other;
}
void CVector3f::operator-=(const CVector3f& other)
{
*this = *this - other;
}
void CVector3f::operator*=(const CVector3f& other)
{
*this = *this * other;
}
void CVector3f::operator/=(const CVector3f& other)
{
*this = *this / other;
}
bool CVector3f::operator> (const CVector3f& other) const
{
return ((x > other.x) && (y > other.y) && (z > other.z));
}
bool CVector3f::operator>=(const CVector3f& other) const
{
return ((x >= other.x) && (y >= other.y) && (z >= other.z));
}
bool CVector3f::operator< (const CVector3f& other) const
{
return ((x < other.x) && (y < other.y) && (z < other.z));
}
bool CVector3f::operator<=(const CVector3f& other) const
{
return ((x <= other.x) && (y <= other.y) && (z <= other.z));
}
bool CVector3f::operator==(const CVector3f& other) const
{
return ((x == other.x) && (y == other.y) && (z == other.z));
}
bool CVector3f::operator!=(const CVector3f& other) const
{
return (!(*this == other));
}
// VECTOR/FLOAT
CVector3f CVector3f::operator+(const float src) const
{
CVector3f out;
out.x = this->x + src;
out.y = this->y + src;
out.z = this->z + src;
return out;
}
CVector3f CVector3f::operator-(const float src) const
{
CVector3f out;
out.x = this->x - src;
out.y = this->y - src;
out.z = this->z - src;
return out;
}
CVector3f CVector3f::operator*(const float src) const
{
CVector3f out;
out.x = this->x * src;
out.y = this->y * src;
out.z = this->z * src;
return out;
}
CVector3f CVector3f::operator/(const float src) const
{
CVector3f out;
out.x = this->x / src;
out.y = this->y / src;
out.z = this->z / src;
return out;
}
void CVector3f::operator+=(const float other)
{
*this = *this + other;
}
void CVector3f::operator-=(const float other)
{
*this = *this - other;
}
void CVector3f::operator*=(const float other)
{
*this = *this * other;
}
void CVector3f::operator/=(const float other)
{
*this = *this / other;
}
// VECTOR/MATRIX
CVector3f CVector3f::operator*(const CTransform4f& mtx) const
{
CVector3f out;
out.x = (x * mtx[0][0]) + (y * mtx[1][0]) + (z * mtx[2][0]);
out.y = (x * mtx[0][1]) + (y * mtx[1][1]) + (z * mtx[2][1]);
out.z = (x * mtx[0][2]) + (y * mtx[1][2]) + (z * mtx[2][2]);
return out;
}
void CVector3f::operator*=(const CTransform4f& mtx)
{
*this = *this * mtx;
}
CVector3f CVector3f::operator*(const CMatrix4f& mtx) const
{
// To multiply by a Matrix4f, we consider the vector w component to be 1
CVector3f out;
float w = (x * mtx[0][3]) + (y * mtx[1][3]) + (z * mtx[2][3]) + mtx[3][3];
out.x = ((x * mtx[0][0]) + (y * mtx[1][0]) + (z * mtx[2][0]) + mtx[3][0]) / w;
out.y = ((x * mtx[0][1]) + (y * mtx[1][1]) + (z * mtx[2][1]) + mtx[3][1]) / w;
out.z = ((x * mtx[0][2]) + (y * mtx[1][2]) + (z * mtx[2][2]) + mtx[3][2]) / w;
return out;
}
// UNARY
CVector3f CVector3f::operator-() const
{
return CVector3f(-x, -y, -z);
}
float& CVector3f::operator[](long index)
{
return (&x)[index];
}
const float& CVector3f::operator[](long index) const
{
return (&x)[index];
}
// ************ CONSTANTS ************
const CVector3f CVector3f::skZero = CVector3f(0.f);
const CVector3f CVector3f::skOne = CVector3f(1.f);
const CVector3f CVector3f::skInfinite = CVector3f(FLT_MAX);
const CVector3f CVector3f::skUnitX = CVector3f(1.f, 0.f, 0.f);
const CVector3f CVector3f::skUnitY = CVector3f(0.f, 1.f, 0.f);
const CVector3f CVector3f::skUnitZ = CVector3f(0.f, 0.f, 1.f);
const CVector3f CVector3f::skRight = CVector3f::skUnitX;
const CVector3f CVector3f::skLeft = -CVector3f::skUnitX;
const CVector3f CVector3f::skForward = CVector3f::skUnitY;
const CVector3f CVector3f::skBack = -CVector3f::skUnitY;
const CVector3f CVector3f::skUp = CVector3f::skUnitZ;
const CVector3f CVector3f::skDown = -CVector3f::skUnitZ;
// ************ OTHER ************
std::ostream& operator<<(std::ostream& o, const CVector3f& Vector)
{
o << std::setprecision(6)
<< std::fixed
<< "["
<< ((Vector.x >= 0) ? " " : "")
<< Vector.x
<< ", "
<< ((Vector.y >= 0) ? " " : "")
<< Vector.y
<< ", "
<< ((Vector.z >= 0) ? " " : "")
<< Vector.z
<< "]";
return o;
}

View File

@@ -0,0 +1,92 @@
#ifndef CVECTOR3F
#define CVECTOR3F
#include <FileIO/CInputStream.h>
#include <FileIO/COutputStream.h>
#include <ostream>
class CMatrix4f;
class CVector2f;
class CVector4f;
class CTransform4f;
class CVector3f
{
public:
float x, y, z;
CVector3f();
CVector3f(float xyz);
CVector3f(float _x, float _y, float _z);
CVector3f(CInputStream& Input);
void Write(COutputStream& Output);
// Swizzle
CVector2f xy();
CVector2f xz();
CVector2f yz();
// Math
float Magnitude() const;
float SquaredMagnitude() const;
CVector3f Normalized() const;
float Dot(const CVector3f& other) const;
CVector3f Cross(const CVector3f& other) const;
float Distance(const CVector3f& point) const;
float SquaredDistance(const CVector3f& point) const;
// Vector/Vector
CVector3f operator+(const CVector3f& other) const;
CVector3f operator-(const CVector3f& other) const;
CVector3f operator*(const CVector3f& other) const;
CVector3f operator/(const CVector3f& other) const;
void operator+=(const CVector3f& other);
void operator-=(const CVector3f& other);
void operator*=(const CVector3f& other);
void operator/=(const CVector3f& other);
bool operator> (const CVector3f& other) const;
bool operator>=(const CVector3f& other) const;
bool operator< (const CVector3f& other) const;
bool operator<=(const CVector3f& other) const;
bool operator==(const CVector3f& other) const;
bool operator!=(const CVector3f& other) const;
// Vector/Float
CVector3f operator+(const float other) const;
CVector3f operator-(const float other) const;
CVector3f operator*(const float other) const;
CVector3f operator/(const float other) const;
void operator+=(const float other);
void operator-=(const float other);
void operator*=(const float other);
void operator/=(const float other);
// Vector/Matrix
CVector3f operator*(const CTransform4f& mtx) const;
void operator*=(const CTransform4f& mtx);
CVector3f operator*(const CMatrix4f& mtx) const;
// Unary
CVector3f operator-() const;
float& operator[](long index);
const float& operator[](long index) const;
// Constants
static const CVector3f skZero;
static const CVector3f skOne;
static const CVector3f skInfinite;
static const CVector3f skUnitX;
static const CVector3f skUnitY;
static const CVector3f skUnitZ;
static const CVector3f skRight;
static const CVector3f skLeft;
static const CVector3f skForward;
static const CVector3f skBack;
static const CVector3f skUp;
static const CVector3f skDown;
// Other
friend std::ostream& operator<<(std::ostream& o, const CVector3f& Vector);
};
#endif // CVECTOR3F

View File

@@ -0,0 +1,273 @@
#include "CVector4f.h"
#include "CVector2f.h"
#include "CVector3f.h"
#include "CTransform4f.h"
CVector4f::CVector4f()
{
x = y = z = w = 0.f;
}
CVector4f::CVector4f(float xyzw)
{
x = y = z = w = xyzw;
}
CVector4f::CVector4f(float _x, float _y, float _z, float _w)
{
x = _x;
y = _y;
z = _z;
w = _w;
}
CVector4f::CVector4f(const CVector2f& xy, float _z, float _w)
{
x = xy.x;
y = xy.y;
z = _z;
w = _w;
}
CVector4f::CVector4f(const CVector3f& xyz)
{
x = xyz.x;
y = xyz.y;
z = xyz.z;
w = 1.f;
}
CVector4f::CVector4f(const CVector3f& xyz, float _w)
{
x = xyz.x;
y = xyz.y;
z = xyz.z;
w = _w;
}
CVector4f::CVector4f(CInputStream& Input)
{
x = Input.ReadFloat();
y = Input.ReadFloat();
z = Input.ReadFloat();
w = Input.ReadFloat();
}
void CVector4f::Write(COutputStream &Output)
{
Output.WriteFloat(x);
Output.WriteFloat(y);
Output.WriteFloat(z);
Output.WriteFloat(w);
}
// ************ SWIZZLE ************
CVector3f CVector4f::xyz()
{
return CVector3f(x, y, z);
}
CVector3f CVector4f::xzw()
{
return CVector3f(x, z, w);
}
CVector3f CVector4f::yzw()
{
return CVector3f(y, z, w);
}
CVector2f CVector4f::xy()
{
return CVector2f(x, y);
}
CVector2f CVector4f::xz()
{
return CVector2f(x, z);
}
CVector2f CVector4f::xw()
{
return CVector2f(x, w);
}
CVector2f CVector4f::yz()
{
return CVector2f(y, z);
}
CVector2f CVector4f::yw()
{
return CVector2f(y, w);
}
CVector2f CVector4f::zw()
{
return CVector2f(z, w);
}
// ************ MATH ************
// ************ VECTOR/VECTOR ************
CVector4f CVector4f::operator+(const CVector4f& src) const
{
CVector4f out;
out.x = this->x + src.x;
out.y = this->y + src.y;
out.z = this->z + src.z;
out.w = this->w + src.w;
return out;
}
CVector4f CVector4f::operator-(const CVector4f& src) const
{
CVector4f out;
out.x = this->x - src.x;
out.y = this->y - src.y;
out.z = this->z - src.z;
out.w = this->w - src.w;
return out;
}
CVector4f CVector4f::operator*(const CVector4f& src) const
{
CVector4f out;
out.x = this->x * src.x;
out.y = this->y * src.y;
out.z = this->z * src.z;
out.w = this->w * src.w;
return out;
}
CVector4f CVector4f::operator/(const CVector4f& src) const
{
CVector4f out;
out.x = this->x / src.x;
out.y = this->y / src.y;
out.z = this->z / src.z;
out.w = this->w / src.w;
return out;
}
void CVector4f::operator+=(const CVector4f& other)
{
*this = *this + other;
}
void CVector4f::operator-=(const CVector4f& other)
{
*this = *this - other;
}
void CVector4f::operator*=(const CVector4f& other)
{
*this = *this * other;
}
void CVector4f::operator/=(const CVector4f& other)
{
*this = *this / other;
}
bool CVector4f::operator==(const CVector4f& other) const
{
return ((x == other.x) && (y == other.y) && (z == other.z) && (w == other.w));
}
// ************ VECTOR/FLOAT ************
CVector4f CVector4f::operator+(const float src) const
{
CVector4f out;
out.x = this->x + src;
out.y = this->y + src;
out.z = this->z + src;
out.w = this->w + src;
return out;
}
CVector4f CVector4f::operator-(const float src) const
{
CVector4f out;
out.x = this->x - src;
out.y = this->y - src;
out.z = this->z - src;
out.w = this->w - src;
return out;
}
CVector4f CVector4f::operator*(const float src) const
{
CVector4f out;
out.x = this->x * src;
out.y = this->y * src;
out.z = this->z * src;
out.w = this->w * src;
return out;
}
CVector4f CVector4f::operator/(const float src) const
{
CVector4f out;
out.x = this->x / src;
out.y = this->y / src;
out.z = this->z / src;
out.w = this->w / src;
return out;
}
void CVector4f::operator+=(const float other)
{
*this = *this + other;
}
void CVector4f::operator-=(const float other)
{
*this = *this - other;
}
void CVector4f::operator*=(const float other)
{
*this = *this * other;
}
void CVector4f::operator/=(const float other)
{
*this = *this / other;
}
// ************ VECTOR/MATRIX ************
CVector4f CVector4f::operator*(const CTransform4f& mtx) const
{
CVector4f out;
out.x = (x * mtx[0][0]) + (y * mtx[1][0]) + (z * mtx[2][0]);
out.y = (x * mtx[0][1]) + (y * mtx[1][1]) + (z * mtx[2][1]);
out.z = (x * mtx[0][2]) + (y * mtx[1][2]) + (z * mtx[2][2]);
out.w = (x * mtx[0][3]) + (y * mtx[1][3]) + (z * mtx[2][3]) + w;
return out;
}
void CVector4f::operator*=(const CTransform4f& mtx)
{
*this = *this * mtx;
}
CVector4f CVector4f::operator*(const CMatrix4f& mtx) const
{
CVector4f out;
out.x = (x * mtx[0][0]) + (y * mtx[1][0]) + (z * mtx[2][0]) + (w * mtx[3][0]);
out.y = (x * mtx[0][1]) + (y * mtx[1][1]) + (z * mtx[2][1]) + (w * mtx[3][1]);
out.z = (x * mtx[0][2]) + (y * mtx[1][2]) + (z * mtx[2][2]) + (w * mtx[3][2]);
out.w = (x * mtx[0][3]) + (y * mtx[1][3]) + (z * mtx[2][3]) + (w * mtx[3][3]);
return out;
}
void CVector4f::operator*=(const CMatrix4f& mtx)
{
*this = *this * mtx;
}
// ************ UNARY ************
float& CVector4f::operator[](long index)
{
return (&x)[index];
}

View File

@@ -0,0 +1,68 @@
#ifndef CVECTOR4F
#define CVECTOR4F
#include <FileIO/CInputStream.h>
#include <FileIO/COutputStream.h>
class CMatrix4f;
class CTransform4f;
class CVector2f;
class CVector3f;
class CVector4f
{
public:
float x, y, z, w;
CVector4f();
CVector4f(float xyzw);
CVector4f(float _x, float _y, float _z, float _w);
CVector4f(const CVector2f& xy, float _z, float _w);
CVector4f(const CVector3f& xyz);
CVector4f(const CVector3f& xyz, float _w);
CVector4f(CInputStream& Input);
void Write(COutputStream& Output);
// Swizzle
CVector3f xyz();
CVector3f xzw();
CVector3f yzw();
CVector2f xy();
CVector2f xz();
CVector2f xw();
CVector2f yz();
CVector2f yw();
CVector2f zw();
// Vector/Vector
CVector4f operator+(const CVector4f& other) const;
CVector4f operator-(const CVector4f& other) const;
CVector4f operator*(const CVector4f& other) const;
CVector4f operator/(const CVector4f& other) const;
void operator+=(const CVector4f& other);
void operator-=(const CVector4f& other);
void operator*=(const CVector4f& other);
void operator/=(const CVector4f& other);
bool operator==(const CVector4f& other) const;
// Vector/Float
CVector4f operator+(const float other) const;
CVector4f operator-(const float other) const;
CVector4f operator*(const float other) const;
CVector4f operator/(const float other) const;
void operator+=(const float other);
void operator-=(const float other);
void operator*=(const float other);
void operator/=(const float other);
// Vector/Matrix
CVector4f operator*(const CTransform4f& mtx) const;
void operator*=(const CTransform4f& mtx);
CVector4f operator*(const CMatrix4f& mtx) const;
void operator*=(const CMatrix4f& mtx);
// Unary
float& operator[](long index);
};
#endif // CVECTOR4F

View File

@@ -0,0 +1,11 @@
#ifndef ETRANSFORMSPACE
#define ETRANSFORMSPACE
enum ETransformSpace
{
eWorldTransform,
eLocalTransform
};
#endif // ETRANSFORMSPACE

352
src/Common/Math/Math.cpp Normal file
View File

@@ -0,0 +1,352 @@
#include "Math.h"
#include <Common/CMatrix4f.h>
#include <gtc/matrix_transform.hpp>
namespace Math
{
float Abs(float v)
{
return fabs(v);
}
float Pow(float Base, float Exponent)
{
return pow(Base, Exponent);
}
float Sqrt(float v)
{
return sqrtf(v);
}
float Distance(const CVector3f& A, const CVector3f& B)
{
return sqrtf( Pow(B.x - A.x, 2.f) +
Pow(B.y - A.y, 2.f) +
Pow(B.z - A.z, 2.f) );
}
float DegreesToRadians(float deg)
{
return deg * skPi / 180.f;
}
float RadiansToDegrees(float rad)
{
return rad * 180.f / skPi;
}
std::pair<bool,float> RayPlaneIntersecton(const CRay& ray, const CPlane& plane)
{
// Code based on ray/plane intersect code from Ogre
// https://bitbucket.org/sinbad/ogre/src/197116fd2ac62c57cdeed1666f9866c3dddd4289/OgreMain/src/OgreMath.cpp?at=default#OgreMath.cpp-350
// Are ray and plane parallel?
float denom = plane.Normal().Dot(ray.Direction());
if (Abs(denom) < FLT_EPSILON)
return std::pair<bool,float>(false, 0.f);
// Not parallel
float nom = plane.Normal().Dot(ray.Origin()) + plane.Dist();
float t = -(nom / denom);
return std::pair<bool,float>(t >= 0.f, t);
}
std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box)
{
// Code slightly modified from Ogre
// https://github.com/ehsan/ogre/blob/master/OgreMain/src/OgreMath.cpp
if (Box.IsNull()) return std::pair<bool,float>(false, 0.f);
if (Box.IsInfinite()) return std::pair<bool,float>(true, 0.f);
float lowt = 0.0f;
float t;
bool Hit = false;
CVector3f HitPoint;
const CVector3f& RayOrig = Ray.Origin();
const CVector3f& RayDir = Ray.Direction();
const CVector3f Min = Box.Min();
const CVector3f Max = Box.Max();
// Check origin inside first
if ( RayOrig > Min && RayOrig < Max )
{
return std::pair<bool, float>(true, 0.f);
}
// Check each face in turn, only check closest 3
// Min x
if (RayOrig.x <= Min.x && RayDir.x > 0)
{
t = (Min.x - RayOrig.x) / RayDir.x;
if (t >= 0)
{
// Substitute t back into ray and check bounds and dist
HitPoint = RayOrig + RayDir * t;
if (HitPoint.y >= Min.y && HitPoint.y <= Max.y &&
HitPoint.z >= Min.z && HitPoint.z <= Max.z &&
(!Hit || t < lowt))
{
Hit = true;
lowt = t;
}
}
}
// Max x
if (RayOrig.x >= Max.x && RayDir.x < 0)
{
t = (Max.x - RayOrig.x) / RayDir.x;
if (t >= 0)
{
// Substitute t back into ray and check bounds and dist
HitPoint = RayOrig + RayDir * t;
if (HitPoint.y >= Min.y && HitPoint.y <= Max.y &&
HitPoint.z >= Min.z && HitPoint.z <= Max.z &&
(!Hit || t < lowt))
{
Hit = true;
lowt = t;
}
}
}
// Min y
if (RayOrig.y <= Min.y && RayDir.y > 0)
{
t = (Min.y - RayOrig.y) / RayDir.y;
if (t >= 0)
{
// Substitute t back into ray and check bounds and dist
HitPoint = RayOrig + RayDir * t;
if (HitPoint.x >= Min.x && HitPoint.x <= Max.x &&
HitPoint.z >= Min.z && HitPoint.z <= Max.z &&
(!Hit || t < lowt))
{
Hit = true;
lowt = t;
}
}
}
// Max y
if (RayOrig.y >= Max.y && RayDir.y < 0)
{
t = (Max.y - RayOrig.y) / RayDir.y;
if (t >= 0)
{
// Substitute t back into ray and check bounds and dist
HitPoint = RayOrig + RayDir * t;
if (HitPoint.x >= Min.x && HitPoint.x <= Max.x &&
HitPoint.z >= Min.z && HitPoint.z <= Max.z &&
(!Hit || t < lowt))
{
Hit = true;
lowt = t;
}
}
}
// Min z
if (RayOrig.z <= Min.z && RayDir.z > 0)
{
t = (Min.z - RayOrig.z) / RayDir.z;
if (t >= 0)
{
// Substitute t back into ray and check bounds and dist
HitPoint = RayOrig + RayDir * t;
if (HitPoint.x >= Min.x && HitPoint.x <= Max.x &&
HitPoint.y >= Min.y && HitPoint.y <= Max.y &&
(!Hit || t < lowt))
{
Hit = true;
lowt = t;
}
}
}
// Max z
if (RayOrig.z >= Max.z && RayDir.z < 0)
{
t = (Max.z - RayOrig.z) / RayDir.z;
if (t >= 0)
{
// Substitute t back into ray and check bounds and dist
HitPoint = RayOrig + RayDir * t;
if (HitPoint.x >= Min.x && HitPoint.x <= Max.x &&
HitPoint.y >= Min.y && HitPoint.y <= Max.y &&
(!Hit || t < lowt))
{
Hit = true;
lowt = t;
}
}
}
return std::pair<bool,float>(Hit, lowt);
}
std::pair<bool,float> RayLineIntersection(const CRay& ray, const CVector3f& pointA,
const CVector3f& pointB, float threshold)
{
// http://geomalgorithms.com/a07-_distance.html
// http://www.gamedev.net/topic/589705-rayline-intersection-in-3d/
CVector3f u = ray.Direction();
CVector3f v = pointB - pointA;
CVector3f w = ray.Origin() - pointA;
float a = u.Dot(u);
float b = u.Dot(v);
float c = v.Dot(v);
float d = u.Dot(w);
float e = v.Dot(w);
float D = a * c - b * b;
float sc, sN, sD = D;
float tc, tN, tD = D;
if (D < FLT_EPSILON) {
sN = 0.f;
sD = 1.f;
tN = e;
tD = c;
}
else {
sN = b * e - c * d;
tN = a * e - b * d;
if (sN < 0.f) {
sN = 0.f;
tN = e;
tD = c;
}
}
if (tN < 0.f) {
tN = 0.f;
if (-d < 0.f)
sN = 0.f;
else {
sN = -d;
sD = a;
}
}
else if (tN > tD) {
tN = tD;
if (-d + b < 0.f)
sN = 0.f;
else {
sN = -d + b;
sD = a;
}
}
sc = (fabs(sN) < FLT_EPSILON ? 0.f : sN / sD);
tc = (fabs(tN) < FLT_EPSILON ? 0.f : tN / tD);
CVector3f dP = w + (u * sc) - (v * tc);
bool hit = (dP.Magnitude() <= threshold);
return std::pair<bool,float>(hit, sc);
}
std::pair<bool,float> RayTriangleIntersection(const CRay& Ray,
const CVector3f& vtxA, const CVector3f& vtxB,
const CVector3f& vtxC, bool AllowBackfaces)
{
// Ogre code cuz I'm lazy and bad at math
// https://github.com/ehsan/ogre/blob/master/OgreMain/src/OgreMath.cpp#L709
CVector3f FaceNormal = (vtxB - vtxA).Cross(vtxC - vtxA);
//
// Calculate intersection with plane.
//
float t;
{
float denom = FaceNormal.Dot(Ray.Direction());
// Check intersect side
if (denom > + std::numeric_limits<float>::epsilon())
{
if (!AllowBackfaces)
return std::pair<bool,float>(false, 0.f);
}
else if (denom >= - std::numeric_limits<float>::epsilon())
{
// Parallel or triangle area is close to zero when
// the plane normal not normalised.
return std::pair<bool,float>(false, 0.f);
}
t = FaceNormal.Dot(vtxA - Ray.Origin()) / denom;
if (t < 0)
{
// Intersection is behind origin
return std::pair<bool,float>(false, 0.f);
}
}
//
// Calculate the largest area projection plane in X, Y or Z.
//
size_t i0, i1;
{
float n0 = fabs(FaceNormal[0]);
float n1 = fabs(FaceNormal[1]);
float n2 = fabs(FaceNormal[2]);
i0 = 1; i1 = 2;
if (n1 > n2)
{
if (n1 > n0) i0 = 0;
}
else
{
if (n2 > n0) i1 = 0;
}
}
//
// Check the intersection point is inside the triangle.
//
{
float u1 = vtxB[i0] - vtxA[i0];
float v1 = vtxB[i1] - vtxA[i1];
float u2 = vtxC[i0] - vtxA[i0];
float v2 = vtxC[i1] - vtxA[i1];
float u0 = t * Ray.Direction()[i0] + Ray.Origin()[i0] - vtxA[i0];
float v0 = t * Ray.Direction()[i1] + Ray.Origin()[i1] - vtxA[i1];
float alpha = u0 * v2 - u2 * v0;
float beta = u1 * v0 - u0 * v1;
float area = u1 * v2 - u2 * v1;
// epsilon to avoid float precision error
const float EPSILON = 1e-6f;
float tolerance = - EPSILON * area;
if (area > 0)
{
if (alpha < tolerance || beta < tolerance || alpha+beta > area-tolerance)
return std::pair<bool,float>(false, 0.f);
}
else
{
if (alpha > tolerance || beta > tolerance || alpha+beta < area-tolerance)
return std::pair<bool,float>(false, 0.f);
}
}
return std::pair<bool,float>(true, t);
}
CMatrix4f PerspectiveMatrix(float fov, float aspect, float near, float far)
{
// todo: don't use glm
return CMatrix4f::FromGlmMat4(glm::perspective(fov, aspect, near, far)).Transpose();
}
CMatrix4f OrthographicMatrix(float left, float right, float bottom, float top, float near, float far)
{
return CMatrix4f::FromGlmMat4(glm::ortho(left, right, bottom, top, near, far)).Transpose();
}
} // End namespace

47
src/Common/Math/Math.h Normal file
View File

@@ -0,0 +1,47 @@
#ifndef MATH
#define MATH
#include "CAABox.h"
#include "CRay.h"
#include "CPlane.h"
#include "CVector3f.h"
#include "SRayIntersection.h"
#include <utility>
namespace Math
{
float Abs(float v);
float Pow(float Base, float Exponent);
float Sqrt(float v);
float Distance(const CVector3f& A, const CVector3f& B);
float DegreesToRadians(float deg);
float RadiansToDegrees(float rad);
std::pair<bool,float> RayPlaneIntersecton(const CRay& ray, const CPlane& plane);
std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box);
std::pair<bool,float> RayLineIntersection(const CRay& ray, const CVector3f& pointA,
const CVector3f& pointB, float threshold = 0.02f);
std::pair<bool,float> RayTriangleIntersection(const CRay& Ray, const CVector3f& PointA,
const CVector3f& PointB, const CVector3f& PointC,
bool AllowBackfaces = false);
CMatrix4f PerspectiveMatrix(float fov, float aspect, float near, float far);
CMatrix4f OrthographicMatrix(float left, float right, float bottom, float top, float near, float far);
// Constants
static const float skPi = 3.14159265358979323846f;
static const float skHalfPi = skPi / 2.f;
}
#endif // MATH

115
src/Common/TString.cpp Normal file
View File

@@ -0,0 +1,115 @@
#include "TString.h"
#include <FileIO/IOUtil.h>
// ************ TString ************
TString::TString(const wchar_t* pkText)
{
*this = TWideString(pkText).ToUTF8();
}
TString::TString(const std::wstring& rkText)
{
*this = TWideString(rkText).ToUTF8();
}
TString::TString(const TWideString& rkText)
{
*this = rkText.ToUTF8();
}
TWideString TString::ToUTF16() const
{
TWideString out;
const char *pkCStr = CString();
while (pkCStr[0])
{
// Step 1: decode UTF-8 code point
wchar_t CodePoint;
// One byte
if ((pkCStr[0] & 0x80) == 0)
{
CodePoint = pkCStr[0] & 0x7FFFFFFF;
pkCStr++;
}
// Two bytes
else if ((pkCStr[0] & 0xE0) == 0xC0)
{
CodePoint = (((pkCStr[0] & 0x1F) << 6) |
(pkCStr[1] & 0x3F));
pkCStr += 2;
}
// Three bytes
else if ((pkCStr[0] & 0xF0) == 0xE0)
{
CodePoint = (((pkCStr[0] & 0xF) << 12) |
((pkCStr[1] & 0x3F) << 6) |
(pkCStr[2] & 0x3F));
pkCStr += 3;
}
// Four bytes
else if ((pkCStr[0] & 0xF8) == 0xF0)
{
CodePoint = (((pkCStr[0] & 0x7) << 18) |
((pkCStr[1] & 0x3F) << 12) |
((pkCStr[2] & 0x3F) << 6) |
(pkCStr[3] & 0x3F));
pkCStr += 4;
}
// Five bytes
else if ((pkCStr[0] & 0xFC) == 0xF8)
{
CodePoint = (((pkCStr[0] & 0x3) << 24) |
((pkCStr[1] & 0x3F) << 18) |
((pkCStr[2] & 0x3F) << 12) |
((pkCStr[3] & 0x3F) << 6) |
(pkCStr[4] & 0x3F));
pkCStr += 5;
}
// Six bytes
else if ((pkCStr[0] & 0xFE) == 0xFC)
{
CodePoint = (((pkCStr[0] & 0x1) << 30) |
((pkCStr[1] & 0x3F) << 24) |
((pkCStr[2] & 0x3F) << 18) |
((pkCStr[3] & 0x3F) << 12) |
((pkCStr[4] & 0x3F) << 6) |
(pkCStr[5] & 0x3F));
pkCStr += 6;
}
// Step 2: Append to output string
if ( ((CodePoint >= 0) && (CodePoint <= 0xD7FF)) ||
((CodePoint >= 0xE000) && (CodePoint <= 0xFFFF)) )
out.Append((wchar_t) (CodePoint & 0xFFFF));
}
return out;
}
// ************ TWideString ************
TWideString::TWideString(const char* pkText)
{
*this = TString(pkText).ToUTF16();
}
TWideString::TWideString(const std::string& rkText)
{
*this = TString(rkText).ToUTF16();
}
TWideString::TWideString(const TString& rkText)
{
*this = rkText.ToUTF16();
}
TString TWideString::ToUTF8() const
{
return "UTF16 to UTF8 currently unsupported";
}

821
src/Common/TString.h Normal file
View File

@@ -0,0 +1,821 @@
#ifndef TSTRING_H
#define TSTRING_H
#include "types.h"
#include <FileIO/IOUtil.h>
#include <string>
#include <list>
#include <vector>
#include <sstream>
#include <iomanip>
/* This is a string class which is essentially a wrapper around std::basic_string.
* The reason for this is because there are a lot of string functions I use very
* frequently that std::string is missing and this is more convenient than creating
* all these functions externally. I've chosen to remove access to the default
* std::basic_string functions and replace them with a custom API for consistency.
*
* Most of the file contains an implementation for a template base class, TBasicString.
* Afterwards we define the following subclasses/typedefs:
*
* - TBasicString<char> - TString
* - TBasicString<wchar_t> - TWideString
* - std::list<TString> - TStringList
* - std::list<TWideString> - TWideStringList
*
* TString and TWideString have functions for converting between each other. For these
* functions, TString is expected to be encoded in UTF-8 and TWideString is expected to
* be encoded in UTF-16.
*/
// ************ TBasicString ************
template<class CharType>
class TBasicString
{
typedef TBasicString<CharType> _TString;
typedef std::basic_string<CharType> _TStdString;
typedef std::list<_TString> _TStringList;
protected:
_TStdString mInternalString;
public:
// Constructors
TBasicString()
: mInternalString()
{
}
TBasicString(u32 size)
: mInternalString(size, 0)
{
}
TBasicString(u32 size, CharType fill)
: mInternalString(size, fill)
{
}
TBasicString(const CharType* pkText)
: mInternalString(pkText)
{
}
TBasicString(const CharType* pkText, u32 length)
: mInternalString(pkText, length)
{
}
TBasicString(const _TStdString& rkText)
: mInternalString(rkText)
{
}
// Data Accessors
inline const CharType* CString() const
{
return mInternalString.c_str();
}
inline const CharType* Data() const
{
return mInternalString.data();
}
inline CharType At(u32 pos) const
{
#if _DEBUG
if (Size() <= pos)
throw std::out_of_range("Invalid position passed to TBasicString::At()");
#endif
return mInternalString.at(pos);
}
inline CharType Front() const
{
return (Size() > 0 ? mInternalString[0] : 0);
}
inline CharType Back() const
{
return (Size() > 0 ? mInternalString[Size() - 1] : 0);
}
inline u32 Size() const
{
return mInternalString.size();
}
inline u32 Length() const
{
return Size();
}
inline u32 IndexOf(const CharType* pkCharacters) const
{
size_t pos = mInternalString.find_first_of(pkCharacters);
if (pos == _TStdString::npos)
return -1;
else
return (u32) pos;
}
inline u32 LastIndexOf(const CharType* pkCharacters) const
{
size_t pos = mInternalString.find_last_of(pkCharacters);
if (pos == _TStdString::npos)
return -1;
else
return (u32) pos;
}
// Modify String
inline _TString SubString(int startPos, int length) const
{
return mInternalString.substr(startPos, length);
}
inline void Insert(u32 pos, CharType c)
{
#ifdef _DEBUG
if (Size() < pos)
throw std::out_of_range("Invalid pos passed to TBasicString::Insert(CharType)");
#endif
mInternalString.insert(pos, 1, c);
}
inline void Insert(u32 pos, const CharType* pkStr)
{
#ifdef _DEBUG
if (Size() < pos)
throw std::out_of_range("Invalid pos passed to TBasicString::Insert(const CharType*)");
#endif
mInternalString.insert(pos, pkStr);
}
inline void Insert(u32 pos, const _TString& rkStr)
{
Insert(pos, rkStr.CString());
}
inline void Append(CharType c)
{
mInternalString.append(1, c);
}
inline void Append(const CharType* pkText)
{
mInternalString.append(pkText);
}
inline void Append(const _TString& rkStr)
{
mInternalString.append(rkStr.CString());
}
inline void Prepend(CharType c)
{
Insert(0, c);
}
inline void Prepend(const CharType* pkText)
{
Insert(0, pkText);
}
inline void Prepend(const _TString& rkStr)
{
Insert(0, rkStr);
}
_TString ToUpper() const
{
// todo: doesn't handle accented characters
_TString out(Size());
for (u32 iChar = 0; iChar < Size(); iChar++)
{
CharType c = At(iChar);
if (c >= 'a' && c <= 'z')
out[iChar] = c - 0x20;
else
out[iChar] = c;
}
return out;
}
_TString ToLower() const
{
// todo: doesn't handle accented characters
_TString out(Size());
for (u32 iChar = 0; iChar < Size(); iChar++)
{
CharType c = At(iChar);
if (c >= 'A' && c <= 'Z')
out[iChar] = c + 0x20;
else
out[iChar] = c;
}
return out;
}
_TString Trimmed() const
{
int start, end;
for (u32 iChar = 0; iChar < Size(); iChar++)
{
if (!IsWhitespace(mInternalString[iChar]))
{
start = iChar;
break;
}
}
for (int iChar = Size() - 1; iChar >= 0; iChar--)
{
if (!IsWhitespace(mInternalString[iChar]))
{
end = iChar + 1;
break;
}
}
return SubString(start, end - start);
}
inline _TString Truncate(u32 amount) const
{
return SubString(0, amount);
}
inline _TString ChopFront(u32 amount) const
{
return SubString(amount, Size() - amount);
}
inline _TString ChopBack(u32 amount) const
{
return SubString(0, Size() - amount);
}
u32 Hash32() const
{
u32 hash = 0;
for (u32 iChar = 0; iChar < Size(); iChar++)
{
hash += At(iChar);
hash *= 101;
}
return hash;
}
u64 Hash64() const
{
u64 hash = 0;
for (u32 iChar = 0; iChar < Size(); iChar++)
{
hash += At(iChar);
hash *= 101;
}
return hash;
}
inline u32 ToInt32(int base = 16) const
{
return std::stoul(mInternalString, nullptr, base);
}
inline u64 ToInt64(int base = 16) const
{
return std::stoull(mInternalString, nullptr, base);
}
void ToInt128(CharType* pOut, int base = 16) const
{
// TODO: only works in base 16
u64 part1 = std::stoull(mInternalString.substr(0, 16), nullptr, base);
u64 part2 = std::stoull(mInternalString.substr(16, 16), nullptr, base);
if (IOUtil::SystemEndianness == IOUtil::LittleEndian)
{
IOUtil::SwapBytes(part1);
IOUtil::SwapBytes(part2);
}
memcpy(pOut, &part1, 8);
memcpy(pOut + 8, &part2, 8);
}
inline _TStdString ToStdString() const
{
return mInternalString;
}
_TStringList Split(const CharType* pkTokens) const
{
_TStringList out;
u32 lastSplit = 0;
// Iterate over all characters in the input string
for (u32 iChr = 0; iChr < Length(); iChr++)
{
// Check whether this character is one of the user-provided tokens
for (u32 iTok = 0; true; iTok++)
{
if (!pkTokens[iTok]) break;
if (mInternalString[iChr] == pkTokens[iTok])
{
// Token found - split string
if (iChr > lastSplit)
out.push_back(SubString(lastSplit, iChr - lastSplit));
lastSplit = iChr + 1;
break;
}
}
}
// Add final string
if (lastSplit != Length())
out.push_back(SubString(lastSplit, Length() - lastSplit));
return out;
}
void EnsureEndsWith(CharType chr)
{
if (Back() != chr)
Append(chr);
}
void EnsureEndsWith(const CharType* pkText)
{
if (!EndsWith(pkText))
Append(pkText);
}
// Check String
bool IsEmpty() const
{
return (Size() == 0);
}
bool StartsWith(const _TString& str) const
{
if (Size() < str.Size())
return false;
return (SubString(0, str.Size()) == str);
}
bool EndsWith(const _TString& str) const
{
if (Size() < str.Size())
return false;
return (SubString(Size() - str.Size(), str.Size()) == str);
}
bool Contains(_TString str, bool caseSensitive = true) const
{
if (Size() < str.Size()) return false;
_TString checkStr(caseSensitive ? *this : ToUpper());
if (!caseSensitive) str = str.ToUpper();
int latestPossibleStart = Size() - str.Size();
int match = 0;
for (int iChr = 0; iChr < latestPossibleStart; iChr++)
{
// If the current character matches, increment match
if (checkStr.At(iChr) == str.At(match))
match++;
// Otherwise...
else
{
// We need to also compare this character to the first
// character of the string (unless we just did that)
if (match > 0)
iChr--;
match = 0;
}
// If we've matched the entire string, then we can return true
if (match == str.Size()) return true;
}
return false;
}
bool IsHexString(bool requirePrefix = false, u32 width = -1) const
{
_TString str(*this);
bool hasPrefix = str.StartsWith("0x");
// If we're required to match the prefix and prefix is missing, return false
if (requirePrefix && !hasPrefix)
return false;
if (width == -1)
{
// If the string has the 0x prefix, remove it
if (hasPrefix)
str = str.ChopFront(2);
// If we have a variable width then assign the width value to the string size
width = str.Size();
}
// If the string starts with the prefix and the length matches the string, remove the prefix
else if ((str.Size() == width + 2) && (hasPrefix))
str = str.ChopFront(2);
// By this point, the string size and the width should match. If they don't, return false.
if (str.Size() != width) return false;
// Now we can finally check the actual string and make sure all the characters are valid hex characters.
for (u32 c = 0; c < width; c++)
{
char chr = str[c];
if (!((chr >= '0') && (chr <= '9')) &&
!((chr >= 'a') && (chr <= 'f')) &&
!((chr >= 'A') && (chr <= 'F')))
return false;
}
return true;
}
inline bool CaseInsensitiveCompare(const _TString& rkOther) const
{
return (ToUpper() == rkOther.ToUpper());
}
// Get Filename Components
_TString GetFileDirectory() const
{
size_t endPath = mInternalString.find_last_of("\\/");
return SubString(0, endPath + 1);
}
_TString GetFileName(bool withExtension = true) const
{
size_t endPath = mInternalString.find_last_of("\\/") + 1;
if (withExtension)
{
return SubString(endPath, Size() - endPath);
}
else
{
size_t endName = mInternalString.find_last_of(".");
return SubString(endPath, endName - endPath);
}
}
_TString GetFileExtension() const
{
size_t endName = mInternalString.find_last_of(".");
return SubString(endName + 1, Size() - endName);
}
_TString GetFilePathWithoutExtension() const
{
size_t endName = mInternalString.find_last_of(".");
return SubString(0, endName);
}
// Operators
inline _TString& operator=(const CharType* pkText)
{
mInternalString = pkText;
return *this;
}
inline _TString& operator=(const _TString& rkText)
{
mInternalString = rkText.mInternalString;
return *this;
}
inline CharType& operator[](int pos)
{
return mInternalString[pos];
}
inline const CharType& operator[](int pos) const
{
return mInternalString[pos];
}
inline const CharType* operator*() const
{
return CString();
}
_TString operator+(const CharType* pkOther) const
{
u32 len = CStringLength(pkOther);
_TString out(len + Size());
memcpy(&out[0], mInternalString.data(), Size() * sizeof(CharType));
memcpy(&out[Size()], pkOther, len * sizeof(CharType));
return out;
}
inline _TString operator+(const _TString& other) const
{
return (*this + other.CString());
}
inline void operator+=(const CharType* pkOther)
{
*this = *this + pkOther;
}
inline void operator+=(const _TString& rkOther)
{
*this = *this + rkOther;
}
inline friend _TString operator+(const CharType* pkLeft, const _TString& rkRight)
{
u32 len = CStringLength(pkLeft);
_TString out(len + rkRight.Size());
memcpy(&out[0], pkLeft, len * sizeof(CharType));
memcpy(&out[len], rkRight.CString(), rkRight.Size() * sizeof(CharType));
return out;
}
inline friend _TString operator+(const _TStdString& rkLeft, const _TString& rkRight)
{
_TString out(rkLeft.size() + rkRight.Size());
memcpy(&out[0], rkLeft.data(), rkLeft.size() * sizeof(CharType));
memcpy(&out[rkLeft.size()], rkRight.Data(), rkRight.Size() * sizeof(CharType));
return out;
}
inline bool operator==(const CharType *pkText) const
{
return CompareCStrings(pkText, CString());
}
inline bool operator==(const _TString& rkOther) const
{
return (mInternalString == rkOther.mInternalString);
}
inline friend bool operator==(const CharType *pkText, const _TString& rkString)
{
return (rkString == pkText);
}
inline friend bool operator==(const _TStdString& rkStringA, const _TString& rkStringB)
{
return (rkStringB == rkStringA);
}
inline bool operator!=(const CharType *pkText) const
{
return (!(*this == pkText));
}
inline bool operator!=(const _TString& rkOther) const
{
return (!(*this == rkOther));
}
inline friend bool operator!=(const CharType *pkText, const _TString& rkString)
{
return (rkString != pkText);
}
inline friend bool operator!=(const _TStdString& rkStringA, const _TString& rkStringB)
{
return (rkStringB != rkStringA);
}
inline bool operator<(const CharType* pkText) const
{
return (mInternalString < pkText);
}
inline bool operator<(const _TString& rkOther) const
{
return (mInternalString < rkOther.mInternalString);
}
inline friend bool operator<(const CharType* pkText, const _TString& rkString)
{
return (rkString > pkText);
}
inline friend bool operator<(const _TStdString& rkStringA, const _TString& rkStringB)
{
return (rkStringB > rkStringA);
}
inline bool operator<=(const CharType* pkText) const
{
return (mInternalString <= pkText);
}
inline bool operator<=(const _TString& rkOther) const
{
return (mInternalString <= rkOther.mInternalString);
}
inline friend bool operator<=(const CharType* pkText, const _TString& rkString)
{
return (rkString >= pkText);
}
inline friend bool operator<=(const _TStdString& rkStringA, const _TString& rkStringB)
{
return (rkStringB >= rkStringA);
}
inline bool operator>(const CharType* pkText) const
{
return (mInternalString > pkText);
}
inline bool operator>(const _TString& rkOther) const
{
return (mInternalString > rkOther.mInternalString);
}
inline friend bool operator>(const CharType* pkText, const _TString& rkString)
{
return (rkString < pkText);
}
inline friend bool operator>(const _TStdString& rkStringA, const _TString& rkStringB)
{
return (rkStringB < rkStringA);
}
inline bool operator>=(const CharType* pkText) const
{
return (mInternalString >= pkText);
}
inline bool operator>=(const _TString& rkOther) const
{
return (mInternalString >= rkOther.mInternalString);
}
inline friend bool operator>=(const CharType* pkText, const _TString& rkString)
{
return (rkString <= pkText);
}
inline friend bool operator>=(const _TStdString& rkStringA, const _TString& rkStringB)
{
return (rkStringB <= rkStringA);
}
inline friend std::ostream& operator<<(std::ostream& rStream, const _TString& rkString)
{
rStream << rkString.mInternalString;
return rStream;
}
inline friend std::istream& operator>>(std::istream& rStream, const _TString& rkString)
{
rStream >> rkString.mInternalString;
return rStream;
}
// Static
static TBasicString<CharType> FromInt32(u32 value, int width = 0, int base = 16)
{
std::basic_stringstream<CharType> sstream;
sstream << std::setbase(base) << std::setw(width) << std::setfill('0') << value;
return sstream.str();
}
static TBasicString<CharType> FromInt64(u64 value, int width = 0, int base = 16)
{
std::basic_stringstream<CharType> sstream;
sstream << std::setbase(base) << std::setw(width) << std::setfill('0') << value;
return sstream.str();
}
static TBasicString<CharType> HexString(unsigned char num, bool addPrefix = true, bool uppercase = false, int width = 0)
{
return HexString((unsigned long) num, addPrefix, uppercase, width);
}
static TBasicString<CharType> HexString(unsigned short num, bool addPrefix = true, bool uppercase = false, int width = 0)
{
return HexString((unsigned long) num, addPrefix, uppercase, width);
}
static TBasicString<CharType> HexString(unsigned long num, bool addPrefix = true, bool uppercase = false, int width = 0)
{
std::basic_stringstream<CharType> sstream;
sstream << std::hex << std::setw(width) << std::setfill('0') << num;
_TString str = sstream.str();
if (uppercase) str = str.ToUpper();
if (addPrefix) str.Prepend("0x");
return str;
}
static bool CompareCStrings(const CharType* pkA, const CharType* pkB)
{
// Replacement for strcmp so we can compare any CharType
while (true)
{
if (*pkA != *pkB) return false;
if ((*pkA == 0) || (*pkB == 0)) return true;
pkA++;
pkB++;
}
}
static u32 CStringLength(const CharType* pkStr)
{
// Replacement for strlen so we can measure any CharType
u32 out = 0;
while (true)
{
if (*pkStr == 0) return out;
out++;
pkStr++;
}
}
static bool IsWhitespace(CharType c)
{
return ( (c == '\t') ||
(c == '\n') ||
(c == '\v') ||
(c == '\f') ||
(c == '\r') ||
(c == ' ') );
}
};
// ************ TString ************
class TString : public TBasicString<char>
{
public:
TString() : TBasicString<char>() {}
TString(size_t size) : TBasicString<char>(size) {}
TString(size_t size, char fill) : TBasicString<char>(size, fill) {}
TString(const char* pkText) : TBasicString<char>(pkText) {}
TString(const char* pkText, u32 length) : TBasicString<char>(pkText, length) {}
TString(const std::string& rkText) : TBasicString<char>(rkText) {}
TString(const TBasicString<char>& rkStr) : TBasicString<char>(rkStr) {}
TString(const wchar_t* pkText);
TString(const std::wstring& rkText);
TString(const class TWideString& rkText);
class TWideString ToUTF16() const;
};
// ************ TWideString ************
class TWideString : public TBasicString<wchar_t>
{
public:
TWideString() : TBasicString<wchar_t>() {}
TWideString(u32 size) : TBasicString<wchar_t>(size) {}
TWideString(u32 size, wchar_t fill) : TBasicString<wchar_t>(size, fill) {}
TWideString(const wchar_t* pkText) : TBasicString<wchar_t>(pkText) {}
TWideString(const wchar_t* pkText, u32 length) : TBasicString<wchar_t>(pkText, length) {}
TWideString(const std::wstring& rkText) : TBasicString<wchar_t>(rkText) {}
TWideString(const TBasicString<wchar_t>& rkStr) : TBasicString<wchar_t>(rkStr) {}
TWideString(const char* pkText);
TWideString(const std::string& rkText);
TWideString(const TString& rkText);
class TString ToUTF8() const;
};
// ************ Typedefs ************
typedef std::list<TBasicString<char>> TStringList;
typedef std::list<TBasicString<wchar_t>> TWideStringList;
#endif // TSTRING_H

15
src/Common/types.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef TYPES_H
#define TYPES_H
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef unsigned long long u64;
typedef signed char s8;
typedef signed short s16;
typedef signed long s32;
typedef signed long long s64;
#endif // TYPES_H

View File

@@ -0,0 +1,54 @@
#include "CAreaAttributes.h"
#include <Resource/script/CMasterTemplate.h>
#include <Resource/script/CScriptLayer.h>
CAreaAttributes::CAreaAttributes(CScriptObject *pObj)
{
SetObject(pObj);
}
CAreaAttributes::~CAreaAttributes()
{
}
void CAreaAttributes::SetObject(CScriptObject *pObj)
{
mpObj = pObj;
mGame = pObj->Template()->MasterTemplate()->GetGame();
}
bool CAreaAttributes::IsLayerEnabled()
{
return mpObj->Layer()->IsActive();
}
bool CAreaAttributes::IsSkyEnabled()
{
CPropertyStruct *pBaseStruct = mpObj->Properties();
switch (mGame)
{
case ePrime:
case eEchoes:
case eCorruption:
return static_cast<CBoolProperty*>(pBaseStruct->PropertyByIndex(1))->Get();
default:
return false;
}
}
CModel* CAreaAttributes::SkyModel()
{
CPropertyStruct *pBaseStruct = mpObj->Properties();
switch (mGame)
{
case ePrime:
case eEchoes:
return (CModel*) static_cast<CFileProperty*>(pBaseStruct->PropertyByIndex(7))->Get().RawPointer();
case eCorruption:
return (CModel*) static_cast<CFileProperty*>(pBaseStruct->PropertyByIndex(8))->Get().RawPointer();
default:
return nullptr;
}
}

View File

@@ -0,0 +1,20 @@
#ifndef CAREAATTRIBUTES_H
#define CAREAATTRIBUTES_H
#include <Resource/script/CScriptObject.h>
class CAreaAttributes
{
EGame mGame;
CScriptObject *mpObj;
public:
CAreaAttributes(CScriptObject *pObj);
~CAreaAttributes();
void SetObject(CScriptObject *pObj);
bool IsLayerEnabled();
bool IsSkyEnabled();
CModel* SkyModel();
};
#endif // CAREAATTRIBUTES_H

View File

@@ -0,0 +1,25 @@
#include "CLightParameters.h"
CLightParameters::CLightParameters(CPropertyStruct *pStruct, EGame game)
: mpStruct(pStruct), mGame(game)
{
}
CLightParameters::~CLightParameters()
{
}
int CLightParameters::LightLayerIndex()
{
if (!mpStruct) return 0;
CLongProperty *pParam;
if (mGame <= ePrime)
pParam = (CLongProperty*) mpStruct->PropertyByIndex(0xD);
else
pParam = (CLongProperty*) mpStruct->PropertyByID(0x1F715FD3);
if (!pParam) return 0;
else return pParam->Get();
}

View File

@@ -0,0 +1,18 @@
#ifndef CLIGHTPARAMETERS_H
#define CLIGHTPARAMETERS_H
#include <Resource/CGameArea.h>
#include <Resource/script/CProperty.h>
class CLightParameters
{
CPropertyStruct *mpStruct;
EGame mGame;
public:
CLightParameters(CPropertyStruct *pStruct, EGame game);
~CLightParameters();
int LightLayerIndex();
};
#endif // CLIGHTPARAMETERS_H

View File

@@ -0,0 +1,68 @@
#include "CRayCollisionTester.h"
#include <Scene/CSceneNode.h>
CRayCollisionTester::CRayCollisionTester(const CRay& Ray)
: mRay(Ray)
{
}
CRayCollisionTester::~CRayCollisionTester()
{
}
void CRayCollisionTester::AddNode(CSceneNode *pNode, u32 ComponentIndex, float Distance)
{
mBoxIntersectList.emplace_back(SRayIntersection());
SRayIntersection& Intersection = mBoxIntersectList.back();
Intersection.pNode = pNode;
Intersection.ComponentIndex = ComponentIndex;
Intersection.Distance = Distance;
}
void CRayCollisionTester::AddNodeModel(CSceneNode *pNode, CBasicModel *pModel)
{
// Check each of the model's surfaces and queue them for further testing if they hit
for (u32 iSurf = 0; iSurf < pModel->GetSurfaceCount(); iSurf++)
{
std::pair<bool,float> SurfResult = pModel->GetSurfaceAABox(iSurf).Transformed(pNode->Transform()).IntersectsRay(mRay);
if (SurfResult.first)
AddNode(pNode, iSurf, SurfResult.second);
}
}
SRayIntersection CRayCollisionTester::TestNodes(const SViewInfo& ViewInfo)
{
// Sort nodes by distance from ray
mBoxIntersectList.sort(
[](const SRayIntersection& A, SRayIntersection& B) -> bool
{
return (A.Distance < B.Distance);
});
// Now do more precise intersection tests on geometry
SRayIntersection Result;
Result.Hit = false;
for (auto iNode = mBoxIntersectList.begin(); iNode != mBoxIntersectList.end(); iNode++)
{
SRayIntersection& Intersection = *iNode;
// If we have a result, and the distance for the bounding box hit is further than the current result distance
// then we know that every remaining node is further away and there is no chance of finding a closer hit.
if ((Result.Hit) && (Result.Distance < Intersection.Distance))
break;
// Otherwise, more intersection tests...
CSceneNode *pNode = Intersection.pNode;
SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, Intersection.ComponentIndex, ViewInfo);
if (MidResult.Hit)
{
if ((!Result.Hit) || (MidResult.Distance < Result.Distance))
Result = MidResult;
}
}
return Result;
}

View File

@@ -0,0 +1,35 @@
#ifndef CRAYCOLLISIONHELPER_H
#define CRAYCOLLISIONHELPER_H
#include "CAABox.h"
#include "CRay.h"
#include "CVector3f.h"
#include "SRayIntersection.h"
#include "types.h"
#include <Core/SViewInfo.h>
#include <Resource/model/CBasicModel.h>
#include <list>
class CSceneNode;
class CRayCollisionTester
{
CRay mRay;
std::list<SRayIntersection> mBoxIntersectList;
public:
CRayCollisionTester(const CRay& Ray);
~CRayCollisionTester();
const CRay& Ray() const;
void AddNode(CSceneNode *pNode, u32 AssetIndex, float Distance);
void AddNodeModel(CSceneNode *pNode, CBasicModel *pModel);
SRayIntersection TestNodes(const SViewInfo& ViewInfo);
};
inline const CRay& CRayCollisionTester::Ray() const
{
return mRay;
}
#endif // CRAYCOLLISIONHELPER_H

245
src/Core/Core.pro Normal file
View File

@@ -0,0 +1,245 @@
#-------------------------------------------------
#
# Project created by QtCreator 2015-12-13T15:31:43
#
#-------------------------------------------------
QT -= core gui
CONFIG += staticlib
TEMPLATE = lib
DESTDIR = $$PWD/../../build/Core
DEFINES += GLEW_STATIC
unix {
target.path = /usr/lib
INSTALLS += target
}
CONFIG (debug, debug|release) {
# Debug Config
OBJECTS_DIR = $$PWD/../../build/Core/debug
TARGET = Cored
# Debug Libs
LIBS += -L$$PWD/../../build/Common/ -lCommond \
-L$$PWD/../../externals/assimp/lib/ -lassimp-vc120-mtd \
-L$$PWD/../../externals/boost_1_56_0/lib32-msvc-12.0 -llibboost_filesystem-vc120-mt-gd-1_56 \
-L$$PWD/../../externals/FileIO/lib/ -lFileIOd \
-L$$PWD/../../externals/tinyxml2/lib/ -ltinyxml2d
}
CONFIG (release, debug|release) {
# Release Config
OBJECTS_DIR = $$PWD/../../build/Core/release
TARGET = Core
# Release Libs
LIBS += -L$$PWD/../../build/Common/ -lCommon \
-L$$PWD/../../externals/assimp/lib/ -lassimp-vc120-mt \
-L$$PWD/../../externals/boost_1_56_0/lib32-msvc-12.0 -llibboost_filesystem-vc120-mt-1_56 \
-L$$PWD/../../externals/FileIO/lib/ -lFileIO \
-L$$PWD/../../externals/tinyxml2/lib/ -ltinyxml2
}
# Debug/Release Libs
LIBS += -L$$PWD/../../externals/glew-1.9.0/lib/ -lglew32s \
-L$$PWD/../../externals/lzo-2.08/lib -llzo-2.08 \
-L$$PWD/../../externals/zlib/lib -lzdll
# Include Paths
INCLUDEPATH += $$PWD/../ \
$$PWD/../../externals/assimp/include \
$$PWD/../../externals/boost_1_56_0 \
$$PWD/../../externals/FileIO/include \
$$PWD/../../externals/glew-1.9.0/include \
$$PWD/../../externals/glm/glm \
$$PWD/../../externals/lzo-2.08/include \
$$PWD/../../externals/tinyxml2/include \
$$PWD/../../externals/zlib/include
# Source Files
HEADERS += \
Render/CCamera.h \
Render/CDrawUtil.h \
Render/CGraphics.h \
Render/CRenderBucket.h \
Render/CRenderer.h \
Render/ERenderCommand.h \
Render/ERenderOptions.h \
Render/IRenderable.h \
Render/SRenderablePtr.h \
Render/SViewInfo.h \
Resource/Cooker/CMaterialCooker.h \
Resource/Cooker/CModelCooker.h \
Resource/Cooker/CSectionMgrOut.h \
Resource/Cooker/CTemplateWriter.h \
Resource/Cooker/CTextureEncoder.h \
Resource/Cooker/CWorldCooker.h \
Resource/Factory/CAnimSetLoader.h \
Resource/Factory/CAreaLoader.h \
Resource/Factory/CBlockMgrIn.h \
Resource/Factory/CCollisionLoader.h \
Resource/Factory/CFontLoader.h \
Resource/Factory/CMaterialLoader.h \
Resource/Factory/CModelLoader.h \
Resource/Factory/CScanLoader.h \
Resource/Factory/CScriptLoader.h \
Resource/Factory/CStringLoader.h \
Resource/Factory/CTemplateLoader.h \
Resource/Factory/CTextureDecoder.h \
Resource/Factory/CWorldLoader.h \
Resource/Model/CBasicModel.h \
Resource/Model/CModel.h \
Resource/Model/CStaticModel.h \
Resource/Model/CVertex.h \
Resource/Model/EVertexDescription.h \
Resource/Model/SSurface.h \
Resource/Script/CMasterTemplate.h \
Resource/Script/CProperty.h \
Resource/Script/CPropertyTemplate.h \
Resource/Script/CScriptLayer.h \
Resource/Script/CScriptObject.h \
Resource/Script/CScriptTemplate.h \
Resource/Script/EObjectType.h \
Resource/Script/EPropertyType.h \
Resource/Script/EVolumeShape.h \
Resource/Script/SConnection.h \
Resource/CAnimationParameters.h \
Resource/CAnimSet.h \
Resource/CCollisionMesh.h \
Resource/CCollisionMeshGroup.h \
Resource/CFont.h \
Resource/CGameArea.h \
Resource/CLight.h \
Resource/CMaterial.h \
Resource/CMaterialPass.h \
Resource/CMaterialSet.h \
Resource/CPakFile.h \
Resource/CResCache.h \
Resource/CResource.h \
Resource/CScan.h \
Resource/CStringTable.h \
Resource/CTexture.h \
Resource/CWorld.h \
Resource/EFormatVersion.h \
Resource/EResType.h \
Resource/ETevEnums.h \
Resource/ETexelFormat.h \
Resource/SDependency.h \
Resource/SNamedResource.h \
Resource/SResInfo.h \
Resource/TResPtr.h \
Scene/CCollisionNode.h \
Scene/CLightNode.h \
Scene/CModelNode.h \
Scene/CRootNode.h \
Scene/CSceneManager.h \
Scene/CSceneNode.h \
Scene/CScriptNode.h \
Scene/CStaticNode.h \
Scene/ENodeType.h \
ScriptExtra/CDamageableTriggerExtra.h \
ScriptExtra/CDoorExtra.h \
ScriptExtra/CPointOfInterestExtra.h \
ScriptExtra/CScriptExtra.h \
ScriptExtra/CSpacePirateExtra.h \
ScriptExtra/CWaypointExtra.h \
CAreaAttributes.h \
CLightParameters.h \
CRayCollisionTester.h \
Log.h \
SRayIntersection.h \
OpenGL/CDynamicVertexBuffer.h \
OpenGL/CFramebuffer.h \
OpenGL/CGL.h \
OpenGL/CIndexBuffer.h \
OpenGL/CRenderbuffer.h \
OpenGL/CShader.h \
OpenGL/CShaderGenerator.h \
OpenGL/CUniformBuffer.h \
OpenGL/CVertexArrayManager.h \
OpenGL/CVertexBuffer.h \
OpenGL/GLCommon.h
SOURCES += \
Render/CCamera.cpp \
Render/CDrawUtil.cpp \
Render/CGraphics.cpp \
Render/CRenderBucket.cpp \
Render/CRenderer.cpp \
Resource/Cooker/CMaterialCooker.cpp \
Resource/Cooker/CModelCooker.cpp \
Resource/Cooker/CSectionMgrOut.cpp \
Resource/Cooker/CTemplateWriter.cpp \
Resource/Cooker/CTextureEncoder.cpp \
Resource/Cooker/CWorldCooker.cpp \
Resource/Factory/CAnimSetLoader.cpp \
Resource/Factory/CAreaLoader.cpp \
Resource/Factory/CBlockMgr.cpp \
Resource/Factory/CCollisionLoader.cpp \
Resource/Factory/CFontLoader.cpp \
Resource/Factory/CMaterialLoader.cpp \
Resource/Factory/CModelLoader.cpp \
Resource/Factory/CScanLoader.cpp \
Resource/Factory/CScriptLoader.cpp \
Resource/Factory/CStringLoader.cpp \
Resource/Factory/CTemplateLoader.cpp \
Resource/Factory/CTextureDecoder.cpp \
Resource/Factory/CWorldLoader.cpp \
Resource/Model/CBasicModel.cpp \
Resource/Model/CModel.cpp \
Resource/Model/CStaticModel.cpp \
Resource/Model/SSurface.cpp \
Resource/Script/CMasterTemplate.cpp \
Resource/Script/CProperty.cpp \
Resource/Script/CPropertyTemplate.cpp \
Resource/Script/CScriptLayer.cpp \
Resource/Script/CScriptObject.cpp \
Resource/Script/CScriptTemplate.cpp \
Resource/CAnimationParameters.cpp \
Resource/CAnimSet.cpp \
Resource/CCollisionMesh.cpp \
Resource/CCollisionMeshGroup.cpp \
Resource/CFont.cpp \
Resource/CGameArea.cpp \
Resource/CLight.cpp \
Resource/CMaterial.cpp \
Resource/CMaterialPass.cpp \
Resource/CMaterialSet.cpp \
Resource/CPakFile.cpp \
Resource/CResCache.cpp \
Resource/CResource.cpp \
Resource/CScan.cpp \
Resource/CStringTable.cpp \
Resource/CTexture.cpp \
Resource/CWorld.cpp \
Scene/CCollisionNode.cpp \
Scene/CLightNode.cpp \
Scene/CModelNode.cpp \
Scene/CSceneManager.cpp \
Scene/CSceneNode.cpp \
Scene/CScriptNode.cpp \
Scene/CStaticNode.cpp \
ScriptExtra/CDamageableTriggerExtra.cpp \
ScriptExtra/CDoorExtra.cpp \
ScriptExtra/CPointOfInterestExtra.cpp \
ScriptExtra/CScriptExtra.cpp \
ScriptExtra/CSpacePirateExtra.cpp \
ScriptExtra/CWaypointExtra.cpp \
CAreaAttributes.cpp \
CLightParameters.cpp \
CRayCollisionTester.cpp \
Log.cpp \
OpenGL/CDynamicVertexBuffer.cpp \
OpenGL/CFramebuffer.cpp \
OpenGL/CGL.cpp \
OpenGL/CIndexBuffer.cpp \
OpenGL/CRenderbuffer.cpp \
OpenGL/CShader.cpp \
OpenGL/CShaderGenerator.cpp \
OpenGL/CUniformBuffer.cpp \
OpenGL/CVertexArrayManager.cpp \
OpenGL/CVertexBuffer.cpp \
OpenGL/GLCommon.cpp

76
src/Core/Log.cpp Normal file
View File

@@ -0,0 +1,76 @@
#include <ctime>
#include <iostream>
#include <Common/TString.h>
#include <QMessageBox>
namespace Log
{
static const TString gskLogFilename = "primeworldeditor.log";
#pragma warning(push)
#pragma warning(disable: 4996) // Can't use fopen_s here without creating a separate init function for the log
FILE *gpLogFile = fopen(*gskLogFilename, "w");
#pragma warning(pop)
void Write(const TString& message)
{
if (gpLogFile)
{
time_t RawTime;
time(&RawTime);
tm pTimeInfo;
localtime_s(&pTimeInfo, &RawTime);
char Buffer[80];
strftime(Buffer, 80, "[%H:%M:%S]", &pTimeInfo);
fprintf(gpLogFile, "%s %s\n", Buffer, *message);
fflush(gpLogFile);
}
}
void Error(const TString& message)
{
Write("ERROR: " + message);
std::cout << "ERROR: " << message << "\n";
}
void Warning(const TString& message)
{
Write("Warning: " + message);
std::cout << "Warning: " << message << "\n";
}
void FileWrite(const TString& filename, const TString& message)
{
Write(filename + " : " + message);
}
void FileWrite(const TString& filename, unsigned long offset, const TString& message)
{
Write(filename + " : " + TString::HexString(offset) + " - " + message);
}
void FileError(const TString& filename, const TString& message)
{
Error(filename + " : " + message);
}
void FileError(const TString& filename, unsigned long offset, const TString& message)
{
Error(filename + " : " + TString::HexString(offset) + " - " + message);
}
void FileWarning(const TString& filename, const TString& message)
{
Warning(filename + " : " + message);
}
void FileWarning(const TString& filename, unsigned long offset, const TString& message)
{
Warning(filename + " : " + TString::HexString(offset) + " - " + message);
}
}

22
src/Core/Log.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef INFO
#define INFO
#include <Common/TString.h>
namespace Log
{
void Write(const TString& message);
void Error(const TString& message);
void Warning(const TString& message);
void FileWrite(const TString& filename, const TString& message);
void FileWrite(const TString& filename, unsigned long offset, const TString& message);
void FileError(const TString& filename, const TString& message);
void FileError(const TString& filename, unsigned long offset, const TString& message);
void FileWarning(const TString& filename, const TString& message);
void FileWarning(const TString& filename, unsigned long offset, const TString& message);
}
#endif // INFO

View File

@@ -0,0 +1,136 @@
#include "CDynamicVertexBuffer.h"
#include "CVertexArrayManager.h"
static const u32 gskAttribSize[] = {
0xC, 0xC, 0x4, 0x4, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8
};
CDynamicVertexBuffer::CDynamicVertexBuffer()
{
mAttribFlags = eNoAttributes;
mBufferedFlags = eNoAttributes;
mNumVertices = 0;
}
CDynamicVertexBuffer::~CDynamicVertexBuffer()
{
CVertexArrayManager::DeleteAllArraysForVBO(this);
ClearBuffers();
}
void CDynamicVertexBuffer::SetVertexCount(u32 NumVerts)
{
ClearBuffers();
mNumVertices = NumVerts;
InitBuffers();
}
void CDynamicVertexBuffer::Bind()
{
CVertexArrayManager::Current()->BindVAO(this);
}
void CDynamicVertexBuffer::Unbind()
{
glBindVertexArray(0);
}
void CDynamicVertexBuffer::SetActiveAttribs(u32 AttribFlags)
{
ClearBuffers();
mAttribFlags = (EVertexDescription) AttribFlags;
InitBuffers();
}
void CDynamicVertexBuffer::BufferAttrib(EVertexDescription Attrib, const void *pData)
{
u32 Index;
switch (Attrib)
{
case ePosition: Index = 0; break;
case eNormal: Index = 1; break;
case eColor0: Index = 2; break;
case eColor1: Index = 3; break;
case eTex0: Index = 4; break;
case eTex1: Index = 5; break;
case eTex2: Index = 6; break;
case eTex3: Index = 7; break;
case eTex4: Index = 8; break;
case eTex5: Index = 9; break;
case eTex6: Index = 10; break;
case eTex7: Index = 11; break;
default: return;
}
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[Index]);
glBufferSubData(GL_ARRAY_BUFFER, 0, gskAttribSize[Index] * mNumVertices, pData);
}
void CDynamicVertexBuffer::ClearBuffers()
{
for (u32 iAttrib = 0; iAttrib < 12; iAttrib++)
{
int bit = 1 << iAttrib;
if (mBufferedFlags & bit)
glDeleteBuffers(1, &mAttribBuffers[iAttrib]);
}
mBufferedFlags = eNoAttributes;
}
GLuint CDynamicVertexBuffer::CreateVAO()
{
GLuint VertexArray;
glGenVertexArrays(1, &VertexArray);
glBindVertexArray(VertexArray);
for (u32 iAttrib = 0; iAttrib < 12; iAttrib++)
{
bool HasAttrib = ((3 << (iAttrib * 2)) != 0);
if (HasAttrib)
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
GLuint NumComponents;
GLenum DataType;
if ((iAttrib == 2) || (iAttrib == 3))
{
NumComponents = 4;
DataType = GL_UNSIGNED_BYTE;
}
else
{
NumComponents = gskAttribSize[iAttrib] / 4;
DataType = GL_FLOAT;
}
glVertexAttribPointer(iAttrib, NumComponents, DataType, GL_FALSE, 0, (void*) 0);
glEnableVertexAttribArray(iAttrib);
}
}
glBindVertexArray(0);
return VertexArray;
}
// ************ PRIVATE ************
void CDynamicVertexBuffer::InitBuffers()
{
if (mBufferedFlags) ClearBuffers();
for (u32 iAttrib = 0; iAttrib < 12; iAttrib++)
{
bool HasAttrib = ((3 << (iAttrib * 2)) != 0);
if (HasAttrib)
{
glGenBuffers(1, &mAttribBuffers[iAttrib]);
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, gskAttribSize[iAttrib] * mNumVertices, NULL, GL_DYNAMIC_DRAW);
}
}
mBufferedFlags = mAttribFlags;
}

View File

@@ -0,0 +1,32 @@
#ifndef CDYNAMICVERTEXBUFFER_H
#define CDYNAMICVERTEXBUFFER_H
#include <GL/glew.h>
#include <Common/types.h>
#include <Common/CVector2f.h>
#include <Common/CVector3f.h>
#include <Resource/model/EVertexDescription.h>
#include <vector>
class CDynamicVertexBuffer
{
EVertexDescription mAttribFlags;
EVertexDescription mBufferedFlags;
u32 mNumVertices;
GLuint mAttribBuffers[12];
public:
CDynamicVertexBuffer();
~CDynamicVertexBuffer();
void SetVertexCount(u32 NumVerts);
void Bind();
void Unbind();
void SetActiveAttribs(u32 AttribFlags);
void BufferAttrib(EVertexDescription Attrib, const void *pData);
void ClearBuffers();
GLuint CreateVAO();
private:
void InitBuffers();
};
#endif // CDYNAMICVERTEXBUFFER_H

View File

@@ -0,0 +1,111 @@
#include "CFramebuffer.h"
#include <iostream>
CFramebuffer::CFramebuffer()
{
mInitialized = false;
mWidth = 0;
mHeight = 0;
mpRenderbuffer = nullptr;
mpTexture = nullptr;
}
CFramebuffer::CFramebuffer(u32 Width, u32 Height)
{
mInitialized = false;
mWidth = 0;
mHeight = 0;
mpRenderbuffer = nullptr;
mpTexture = nullptr;
Resize(Width, Height);
}
CFramebuffer::~CFramebuffer()
{
if (mInitialized)
{
glDeleteFramebuffers(1, &mFramebuffer);
delete mpRenderbuffer;
delete mpTexture;
}
}
void CFramebuffer::Init()
{
if (!smStaticsInitialized)
{
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &smDefaultFramebuffer);
smStaticsInitialized = true;
}
if (!mInitialized)
{
glGenFramebuffers(1, &mFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
mpRenderbuffer = new CRenderbuffer(mWidth, mHeight);
mpRenderbuffer->Bind();
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mpRenderbuffer->BufferID()
);
mpTexture = new CTexture(mWidth, mHeight);
mpTexture->Bind(0);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mpTexture->TextureID(), 0
);
mStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (mStatus != GL_FRAMEBUFFER_COMPLETE)
std::cout << "\rError: Framebuffer not complete\n";
mInitialized = true;
}
}
void CFramebuffer::Bind()
{
if (!mInitialized) Init();
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
}
void CFramebuffer::Resize(u32 Width, u32 Height)
{
if ((mWidth != Width) || (mHeight != Height))
{
mWidth = Width;
mHeight = Height;
if (mInitialized)
{
mpRenderbuffer->Resize(Width, Height);
mpTexture->Resize(Width, Height);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
mpRenderbuffer->Bind();
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mpRenderbuffer->BufferID()
);
mpTexture->Bind(0);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mpTexture->TextureID(), 0
);
}
}
}
CTexture* CFramebuffer::Texture()
{
return mpTexture;
}
// ************ STATIC ************
void CFramebuffer::BindDefaultFramebuffer()
{
glBindFramebuffer(GL_FRAMEBUFFER, smDefaultFramebuffer);
}
GLint CFramebuffer::smDefaultFramebuffer;
bool CFramebuffer::smStaticsInitialized;

View File

@@ -0,0 +1,32 @@
#ifndef CFRAMEBUFFER_H
#define CFRAMEBUFFER_H
#include "CRenderbuffer.h"
#include <Resource/CTexture.h>
#include <gl/glew.h>
class CFramebuffer
{
GLuint mFramebuffer;
CRenderbuffer *mpRenderbuffer;
CTexture *mpTexture;
u32 mWidth, mHeight;
bool mInitialized;
GLenum mStatus;
static GLint smDefaultFramebuffer;
static bool smStaticsInitialized;
public:
CFramebuffer();
CFramebuffer(u32 Width, u32 Height);
~CFramebuffer();
void Init();
void Bind();
void Resize(u32 Width, u32 Height);
CTexture* Texture();
static void BindDefaultFramebuffer();
};
#endif // CFRAMEBUFFER_H

41
src/Core/OpenGL/CGL.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "CGL.h"
// ************ PUBLIC ************
void CGL::SetBlendMode(EBlendFactor Source, EBlendFactor Dest)
{
glBlendFuncSeparate(Source, Dest, eBlendZero, eBlendZero);
mBlendSrcFac = Source;
mBlendDstFac = Dest;
}
void CGL::SetOpaqueBlend()
{
SetBlendMode(eBlendOne, eBlendZero);
}
void CGL::SetAlphaBlend()
{
SetBlendMode(eBlendSrcAlpha, eBlendInvSrcAlpha);
}
void CGL::SetAdditiveBlend()
{
SetBlendMode(eBlendOne, eBlendOne);
}
// ************ PRIVATE ************
void CGL::Init()
{
if (!mInitialized)
{
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ZERO);
mBlendSrcFac = eBlendOne;
mBlendDstFac = eBlendZero;
mInitialized = true;
}
}
// ************ STATIC MEMBER INITIALIZATION ************
bool CGL::mInitialized;
EBlendFactor CGL::mBlendSrcFac;
EBlendFactor CGL::mBlendDstFac;

26
src/Core/OpenGL/CGL.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef CGL_H
#define CGL_H
#include "GLCommon.h"
#include <Common/types.h>
#include <GL/glew.h>
class CGL
{
public:
void SetBlendMode(EBlendFactor Source, EBlendFactor Dest);
void SetOpaqueBlend();
void SetAlphaBlend();
void SetAdditiveBlend();
private:
static void Init();
static bool mInitialized;
static EBlendFactor mBlendSrcFac, mBlendDstFac;
static u8 mColorMask;
static bool mDepthMask;
static bool mStencilMask;
};
#endif // CGL_H

View File

@@ -0,0 +1,156 @@
#include "CIndexBuffer.h"
CIndexBuffer::CIndexBuffer()
{
mBuffered = false;
}
CIndexBuffer::CIndexBuffer(GLenum type)
{
mPrimitiveType = type;
mBuffered = false;
}
CIndexBuffer::~CIndexBuffer()
{
if (mBuffered)
glDeleteBuffers(1, &mIndexBuffer);
}
void CIndexBuffer::AddIndex(u16 idx)
{
mIndices.push_back(idx);
}
void CIndexBuffer::AddIndices(u16 *indicesPtr, u32 count)
{
Reserve(count);
for (u32 i = 0; i < count; i++)
mIndices.push_back(*indicesPtr++);
}
void CIndexBuffer::Reserve(u32 size)
{
mIndices.reserve(mIndices.size() + size);
}
void CIndexBuffer::Clear()
{
if (mBuffered)
glDeleteBuffers(1, &mIndexBuffer);
mBuffered = false;
mIndices.clear();
}
void CIndexBuffer::Buffer()
{
if (mBuffered)
glDeleteBuffers(1, &mIndexBuffer);
glGenBuffers(1, &mIndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndices.size() * sizeof(u16), mIndices.data(), GL_STATIC_DRAW);
mBuffered = true;
}
void CIndexBuffer::Bind()
{
if (!mBuffered) Buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
}
void CIndexBuffer::Unbind()
{
}
void CIndexBuffer::DrawElements()
{
Bind();
glDrawElements(mPrimitiveType, mIndices.size(), GL_UNSIGNED_SHORT, (void*) 0);
Unbind();
}
void CIndexBuffer::DrawElements(u32 Offset, u32 Size)
{
Bind();
glDrawElements(mPrimitiveType, Size, GL_UNSIGNED_SHORT, (void*) (Offset * 2));
Unbind();
}
bool CIndexBuffer::IsBuffered()
{
return mBuffered;
}
u32 CIndexBuffer::GetSize()
{
return mIndices.size();
}
GLenum CIndexBuffer::GetPrimitiveType()
{
return mPrimitiveType;
}
void CIndexBuffer::SetPrimitiveType(GLenum type)
{
mPrimitiveType = type;
}
void CIndexBuffer::TrianglesToStrips(u16 *indicesPtr, u32 count)
{
Reserve(count + (count / 3));
for (u32 i = 0; i < count; i += 3)
{
mIndices.push_back(*indicesPtr++);
mIndices.push_back(*indicesPtr++);
mIndices.push_back(*indicesPtr++);
mIndices.push_back(0xFFFF);
}
}
void CIndexBuffer::FansToStrips(u16 *indicesPtr, u32 count)
{
Reserve(count);
u16 FirstIndex = *indicesPtr;
for (u32 i = 2; i < count; i += 3)
{
mIndices.push_back(indicesPtr[i - 1]);
mIndices.push_back(indicesPtr[i]);
mIndices.push_back(FirstIndex);
if (i + 1 < count)
mIndices.push_back(indicesPtr[i + 1]);
if (i + 2 < count)
mIndices.push_back(indicesPtr[i + 2]);
mIndices.push_back(0xFFFF);
}
}
void CIndexBuffer::QuadsToStrips(u16 *indicesPtr, u32 count)
{
Reserve((u32) (count * 1.25));
u32 i = 3;
for (; i < count; i += 4)
{
mIndices.push_back(indicesPtr[i - 2]);
mIndices.push_back(indicesPtr[i - 1]);
mIndices.push_back(indicesPtr[i - 3]);
mIndices.push_back(indicesPtr[i]);
mIndices.push_back(0xFFFF);
}
// if there's three indices present that indicates a single triangle
if (i == count)
{
mIndices.push_back(indicesPtr[i - 3]);
mIndices.push_back(indicesPtr[i - 2]);
mIndices.push_back(indicesPtr[i - 1]);
mIndices.push_back(0xFFFF);
}
}

View File

@@ -0,0 +1,39 @@
#ifndef CINDEXBUFFER_H
#define CINDEXBUFFER_H
#include <Common/types.h>
#include <Common/CVector3f.h>
#include <gl/glew.h>
class CIndexBuffer
{
GLuint mIndexBuffer;
std::vector<u16> mIndices;
GLenum mPrimitiveType;
bool mBuffered;
public:
CIndexBuffer();
CIndexBuffer(GLenum type);
~CIndexBuffer();
void AddIndex(u16 idx);
void AddIndices(u16 *indicesPtr, u32 count);
void Reserve(u32 size);
void Clear();
void Buffer();
void Bind();
void Unbind();
void DrawElements();
void DrawElements(u32 Offset, u32 Size);
bool IsBuffered();
u32 GetSize();
GLenum GetPrimitiveType();
void SetPrimitiveType(GLenum type);
void TrianglesToStrips(u16 *indicesPtr, u32 count);
void FansToStrips(u16 *indicesPtr, u32 count);
void QuadsToStrips(u16 *indicesPtr, u32 count);
};
#endif // CINDEXBUFFER_H

View File

@@ -0,0 +1,52 @@
#include "CRenderbuffer.h"
CRenderbuffer::CRenderbuffer()
{
mInitialized = false;
mWidth = 0;
mHeight = 0;
}
CRenderbuffer::CRenderbuffer(u32 Width, u32 Height)
{
mInitialized = false;
mWidth = Width;
mHeight = Height;
}
CRenderbuffer::~CRenderbuffer()
{
if (mInitialized)
glDeleteRenderbuffers(1, &mRenderbuffer);
}
void CRenderbuffer::Init()
{
glGenRenderbuffers(1, &mRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mWidth, mHeight);
mInitialized = true;
}
void CRenderbuffer::Resize(u32 Width, u32 Height)
{
mWidth = Width;
mHeight = Height;
if (mInitialized)
{
Bind();
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mWidth, mHeight);
}
}
void CRenderbuffer::Bind()
{
if (!mInitialized) Init();
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
}
void CRenderbuffer::Unbind()
{
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}

View File

@@ -0,0 +1,31 @@
#ifndef CRENDERBUFFER_H
#define CRENDERBUFFER_H
#include <GL/glew.h>
#include <Common/types.h>
class CRenderbuffer
{
GLuint mRenderbuffer;
u32 mWidth, mHeight;
bool mInitialized;
public:
CRenderbuffer();
CRenderbuffer(u32 Width, u32 Height);
~CRenderbuffer();
void Init();
void Resize(u32 Width, u32 Height);
void Bind();
void Unbind();
// Getters
GLuint BufferID();
};
inline GLuint CRenderbuffer::BufferID()
{
return mRenderbuffer;
}
#endif // CRENDERBUFFER_H

263
src/Core/OpenGL/CShader.cpp Normal file
View File

@@ -0,0 +1,263 @@
#include "CShader.h"
#include <Common/types.h>
#include <Core/CGraphics.h>
#include <FileIO/CTextInStream.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
bool gDebugDumpShaders = false;
u64 gFailedCompileCount = 0;
u64 gSuccessfulCompileCount = 0;
CShader* CShader::spCurrentShader = nullptr;
CShader::CShader()
{
mVertexShaderExists = false;
mPixelShaderExists = false;
mProgramExists = false;
}
CShader::CShader(const char *kpVertexSource, const char *kpPixelSource)
{
mVertexShaderExists = false;
mPixelShaderExists = false;
mProgramExists = false;
CompileVertexSource(kpVertexSource);
CompilePixelSource(kpPixelSource);
LinkShaders();
}
CShader::~CShader()
{
if (mVertexShaderExists) glDeleteShader(mVertexShader);
if (mPixelShaderExists) glDeleteShader(mPixelShader);
if (mProgramExists) glDeleteProgram(mProgram);
if (spCurrentShader == this) spCurrentShader = 0;
}
bool CShader::CompileVertexSource(const char* kpSource)
{
mVertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(mVertexShader, 1, (const GLchar**) &kpSource, NULL);
glCompileShader(mVertexShader);
// Shader should be compiled - check for errors
GLint CompileStatus;
glGetShaderiv(mVertexShader, GL_COMPILE_STATUS, &CompileStatus);
if (CompileStatus == GL_FALSE)
{
TString Out = "dump/BadVS_" + std::to_string(gFailedCompileCount) + ".txt";
std::cout << "ERROR: Unable to compile vertex shader; dumped to " << Out << "\n";
DumpShaderSource(mVertexShader, Out);
gFailedCompileCount++;
glDeleteShader(mVertexShader);
return false;
}
// Debug dump
else if (gDebugDumpShaders == true)
{
TString Out = "dump/VS_" + TString::FromInt64(gSuccessfulCompileCount, 8, 10) + ".txt";
std::cout << "Debug shader dumping enabled; dumped to " << Out << "\n";
DumpShaderSource(mVertexShader, Out);
gSuccessfulCompileCount++;
}
mVertexShaderExists = true;
return true;
}
bool CShader::CompilePixelSource(const char* kpSource)
{
mPixelShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(mPixelShader, 1, (const GLchar**) &kpSource, NULL);
glCompileShader(mPixelShader);
// Shader should be compiled - check for errors
GLint CompileStatus;
glGetShaderiv(mPixelShader, GL_COMPILE_STATUS, &CompileStatus);
if (CompileStatus == GL_FALSE)
{
TString Out = "dump/BadPS_" + TString::FromInt64(gFailedCompileCount, 8, 10) + ".txt";
std::cout << "ERROR: Unable to compile pixel shader; dumped to " << Out << "\n";
DumpShaderSource(mPixelShader, Out);
gFailedCompileCount++;
glDeleteShader(mPixelShader);
return false;
}
// Debug dump
else if (gDebugDumpShaders == true)
{
TString Out = "dump/PS_" + TString::FromInt64(gSuccessfulCompileCount, 8, 10) + ".txt";
std::cout << "Debug shader dumping enabled; dumped to " << Out << "\n";
DumpShaderSource(mPixelShader, Out);
gSuccessfulCompileCount++;
}
mPixelShaderExists = true;
return true;
}
bool CShader::LinkShaders()
{
if ((!mVertexShaderExists) || (!mPixelShaderExists)) return false;
mProgram = glCreateProgram();
glAttachShader(mProgram, mVertexShader);
glAttachShader(mProgram, mPixelShader);
glLinkProgram(mProgram);
glDeleteShader(mVertexShader);
glDeleteShader(mPixelShader);
mVertexShaderExists = false;
mPixelShaderExists = false;
// Shader should be linked - check for errors
GLint LinkStatus;
glGetProgramiv(mProgram, GL_LINK_STATUS, &LinkStatus);
if (LinkStatus == GL_FALSE)
{
TString Out = "dump/BadLink_" + TString::FromInt64(gFailedCompileCount, 8, 10) + ".txt";
std::cout << "ERROR: Unable to link shaders. Dumped error log to " << Out << "\n";
GLint LogLen;
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &LogLen);
GLchar *InfoLog = new GLchar[LogLen];
glGetProgramInfoLog(mProgram, LogLen, NULL, InfoLog);
std::ofstream LinkOut;
LinkOut.open(*Out);
if (LogLen > 0)
LinkOut << InfoLog;
LinkOut.close();
delete[] InfoLog;
gFailedCompileCount++;
glDeleteProgram(mProgram);
return false;
}
mMVPBlockIndex = GetUniformBlockIndex("MVPBlock");
mVertexBlockIndex = GetUniformBlockIndex("VertexBlock");
mPixelBlockIndex = GetUniformBlockIndex("PixelBlock");
mLightBlockIndex = GetUniformBlockIndex("LightBlock");
mProgramExists = true;
return true;
}
bool CShader::IsValidProgram()
{
return mProgramExists;
}
GLuint CShader::GetProgramID()
{
return mProgram;
}
GLuint CShader::GetUniformLocation(const char* Uniform)
{
return glGetUniformLocation(mProgram, Uniform);
}
GLuint CShader::GetUniformBlockIndex(const char* UniformBlock)
{
return glGetUniformBlockIndex(mProgram, UniformBlock);
}
void CShader::SetCurrent()
{
if (spCurrentShader != this)
{
glUseProgram(mProgram);
spCurrentShader = this;
glUniformBlockBinding(mProgram, mMVPBlockIndex, CGraphics::MVPBlockBindingPoint());
glUniformBlockBinding(mProgram, mVertexBlockIndex, CGraphics::VertexBlockBindingPoint());
glUniformBlockBinding(mProgram, mPixelBlockIndex, CGraphics::PixelBlockBindingPoint());
glUniformBlockBinding(mProgram, mLightBlockIndex, CGraphics::LightBlockBindingPoint());
}
}
// ************ STATIC ************
CShader* CShader::FromResourceFile(const TString& ShaderName)
{
TString VertexShaderFilename = "../resources/shaders/" + ShaderName + ".vs";
TString PixelShaderFilename = "../resources/shaders/" + ShaderName + ".ps";
CTextInStream VertexShaderFile(VertexShaderFilename.ToStdString());
CTextInStream PixelShaderFile(PixelShaderFilename.ToStdString());
if (!VertexShaderFile.IsValid())
std::cout << "Error: Couldn't load vertex shader file for " << ShaderName << "\n";
if (!PixelShaderFile.IsValid())
std::cout << "Error: Couldn't load pixel shader file for " << ShaderName << "\n";
if ((!VertexShaderFile.IsValid()) || (!PixelShaderFile.IsValid())) return nullptr;
std::stringstream VertexShader;
while (!VertexShaderFile.EoF())
VertexShader << VertexShaderFile.GetString();
std::stringstream PixelShader;
while (!PixelShaderFile.EoF())
PixelShader << PixelShaderFile.GetString();
CShader *pShader = new CShader();
pShader->CompileVertexSource(VertexShader.str().c_str());
pShader->CompilePixelSource(PixelShader.str().c_str());
pShader->LinkShaders();
return pShader;
}
CShader* CShader::CurrentShader()
{
return spCurrentShader;
}
void CShader::KillCachedShader()
{
spCurrentShader = 0;
}
// ************ PRIVATE ************
void CShader::DumpShaderSource(GLuint Shader, const TString& Out)
{
GLint SourceLen;
glGetShaderiv(Shader, GL_SHADER_SOURCE_LENGTH, &SourceLen);
GLchar *Source = new GLchar[SourceLen];
glGetShaderSource(Shader, SourceLen, NULL, Source);
GLint LogLen;
glGetShaderiv(Shader, GL_INFO_LOG_LENGTH, &LogLen);
GLchar *InfoLog = new GLchar[LogLen];
glGetShaderInfoLog(Shader, LogLen, NULL, InfoLog);
std::ofstream ShaderOut;
ShaderOut.open(*Out);
if (SourceLen > 0)
ShaderOut << Source;
if (LogLen > 0)
ShaderOut << InfoLog;
ShaderOut.close();
delete[] Source;
delete[] InfoLog;
}

45
src/Core/OpenGL/CShader.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef CSHADER_H
#define CSHADER_H
#include <gl/glew.h>
#include <Common/TString.h>
class CShader
{
bool mVertexShaderExists;
bool mPixelShaderExists;
bool mProgramExists;
GLuint mVertexShader;
GLuint mPixelShader;
GLuint mProgram;
GLuint mMVPBlockIndex;
GLuint mVertexBlockIndex;
GLuint mPixelBlockIndex;
GLuint mLightBlockIndex;
static CShader* spCurrentShader;
public:
CShader();
CShader(const char* kpVertexSource, const char* kpPixelSource);
~CShader();
bool CompileVertexSource(const char* kpSource);
bool CompilePixelSource(const char* kpSource);
bool LinkShaders();
bool IsValidProgram();
GLuint GetProgramID();
GLuint GetUniformLocation(const char* kpUniform);
GLuint GetUniformBlockIndex(const char* kpUniformBlock);
void SetCurrent();
// Static
static CShader* FromResourceFile(const TString& ShaderName);
static CShader* CurrentShader();
static void KillCachedShader();
private:
void DumpShaderSource(GLuint Shader, const TString& Out);
};
#endif // CSHADER_H

View File

@@ -0,0 +1,443 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <gl/glew.h>
#include "CShaderGenerator.h"
const TString gkCoordSrc[] = {
"RawPosition.xyz",
"RawNormal.xyz",
"0.0, 0.0, 0.0",
"0.0, 0.0, 0.0",
"RawTex0.xy, 1.0",
"RawTex1.xy, 1.0",
"RawTex2.xy, 1.0",
"RawTex3.xy, 1.0",
"RawTex4.xy, 1.0",
"RawTex5.xy, 1.0",
"RawTex6.xy, 1.0",
"RawTex7.xy, 1.0"
};
const TString gkRasSel[] = {
"vec4(COLOR0A0.rgb, 1.0)",
"vec4(COLOR1A1.rgb, 1.0)",
"vec4(0.0, 0.0, 0.0, COLOR0A0.a)",
"vec4(0.0, 0.0, 0.0, COLOR1A1.a)",
"COLOR0A0",
"COLOR1A1",
"vec4(0.0, 0.0, 0.0, 0.0)"
};
const TString gkKonstColor[] = {
"1.0, 1.0, 1.0",
"0.875, 0.875, 0.875",
"0.75, 0.75, 0.75",
"0.625, 0.625, 0.625",
"0.5, 0.5, 0.5",
"0.375, 0.375, 0.375",
"0.25, 0.25, 0.25",
"0.125, 0.125, 0.125",
"",
"",
"",
"",
"KonstColors[0].rgb",
"KonstColors[1].rgb",
"KonstColors[2].rgb",
"KonstColors[3].rgb",
"KonstColors[0].rrr",
"KonstColors[1].rrr",
"KonstColors[2].rrr",
"KonstColors[3].rrr",
"KonstColors[0].ggg",
"KonstColors[1].ggg",
"KonstColors[2].ggg",
"KonstColors[3].ggg",
"KonstColors[0].bbb",
"KonstColors[1].bbb",
"KonstColors[2].bbb",
"KonstColors[3].bbb",
"KonstColors[0].aaa",
"KonstColors[1].aaa",
"KonstColors[2].aaa",
"KonstColors[3].aaa"
};
const TString gkKonstAlpha[] = {
"1.0",
"0.875",
"0.75",
"0.625",
"0.5",
"0.375",
"0.25",
"0.125",
"",
"",
"",
"",
"",
"",
"",
"",
"KonstColors[0].r",
"KonstColors[1].r",
"KonstColors[2].r",
"KonstColors[3].r",
"KonstColors[0].g",
"KonstColors[1].g",
"KonstColors[2].g",
"KonstColors[3].g",
"KonstColors[0].b",
"KonstColors[1].b",
"KonstColors[2].b",
"KonstColors[3].b",
"KonstColors[0].a",
"KonstColors[1].a",
"KonstColors[2].a",
"KonstColors[3].a"
};
const TString gkTevColor[] = {
"Prev.rgb",
"Prev.aaa",
"C0.rgb",
"C0.aaa",
"C1.rgb",
"C1.aaa",
"C2.rgb",
"C2.aaa",
"Tex.rgb",
"Tex.aaa",
"Ras.rgb",
"Ras.aaa",
"1.0, 1.0, 1.0",
"0.5, 0.5, 0.5",
"Konst.rgb",
"0.0, 0.0, 0.0"
};
const TString gkTevAlpha[] = {
"Prev.a",
"C0.a",
"C1.a",
"C2.a",
"Tex.a",
"Ras.a",
"Konst.a",
"0.0"
};
const TString gkTevRigid[] = {
"Prev",
"C0",
"C1",
"C2"
};
CShaderGenerator::CShaderGenerator()
{
}
CShaderGenerator::~CShaderGenerator()
{
}
bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
{
std::stringstream ShaderCode;
ShaderCode << "#version 330 core\n"
<< "\n";
// Input
ShaderCode << "// Input\n";
EVertexDescription VtxDesc = Mat.VtxDesc();
if (VtxDesc & ePosition) ShaderCode << "layout(location = 0) in vec3 RawPosition;\n";
if (VtxDesc & eNormal) ShaderCode << "layout(location = 1) in vec3 RawNormal;\n";
if (VtxDesc & eColor0) ShaderCode << "layout(location = 2) in vec4 RawColor0;\n";
if (VtxDesc & eColor1) ShaderCode << "layout(location = 3) in vec4 RawColor1;\n";
if (VtxDesc & eTex0) ShaderCode << "layout(location = 4) in vec2 RawTex0;\n";
if (VtxDesc & eTex1) ShaderCode << "layout(location = 5) in vec2 RawTex1;\n";
if (VtxDesc & eTex2) ShaderCode << "layout(location = 6) in vec2 RawTex2;\n";
if (VtxDesc & eTex3) ShaderCode << "layout(location = 7) in vec2 RawTex3;\n";
if (VtxDesc & eTex4) ShaderCode << "layout(location = 8) in vec2 RawTex4;\n";
if (VtxDesc & eTex5) ShaderCode << "layout(location = 9) in vec2 RawTex5;\n";
if (VtxDesc & eTex6) ShaderCode << "layout(location = 10) in vec2 RawTex6;\n";
ShaderCode << "\n";
// Output
ShaderCode << "// Output\n";
if (VtxDesc & eNormal) ShaderCode << "out vec3 Normal;\n";
if (VtxDesc & eColor0) ShaderCode << "out vec4 Color0;\n";
if (VtxDesc & eColor1) ShaderCode << "out vec4 Color1;\n";
for (u32 iPass = 0; iPass < Mat.PassCount(); iPass++)
if (Mat.Pass(iPass)->TexCoordSource() != 0xFF)
ShaderCode << "out vec3 Tex" << iPass << ";\n";
ShaderCode << "out vec4 COLOR0A0;\n"
<< "out vec4 COLOR1A1;\n";
ShaderCode << "\n";
// Uniforms
ShaderCode << "// Uniforms\n"
<< "layout(std140) uniform MVPBlock\n"
<< "{\n"
<< " mat4 ModelMtx;\n"
<< " mat4 ViewMtx;\n"
<< " mat4 ProjMtx;\n"
<< "};\n"
<< "\n"
<< "layout(std140) uniform VertexBlock\n"
<< "{\n"
<< " mat4 TexMtx[10];\n"
<< " mat4 PostMtx[20];\n"
<< " vec4 COLOR0_Amb;\n"
<< " vec4 COLOR0_Mat;\n"
<< " vec4 COLOR1_Amb;\n"
<< " vec4 COLOR1_Mat;\n"
<< "};\n"
<< "\n"
<< "struct GXLight\n"
<< "{\n"
<< " vec4 Position;\n"
<< " vec4 Direction;\n"
<< " vec4 Color;\n"
<< " vec4 DistAtten;\n"
<< " vec4 AngleAtten;\n"
<< "};\n"
<< "layout(std140) uniform LightBlock {\n"
<< " GXLight Lights[8];\n"
<< "};\n"
<< "uniform int NumLights;\n"
<< "\n";
// Main
ShaderCode << "// Main\n"
<< "void main()\n"
<< "{\n"
<< " mat4 MV = ModelMtx * ViewMtx;\n"
<< " mat4 MVP = MV * ProjMtx;\n";
if (VtxDesc & ePosition) ShaderCode << " gl_Position = vec4(RawPosition, 1) * MVP;\n";
if (VtxDesc & eNormal) ShaderCode << " Normal = normalize(RawNormal.xyz * inverse(transpose(mat3(MV))));\n";
if (VtxDesc & eColor0) ShaderCode << " Color0 = RawColor0;\n";
if (VtxDesc & eColor1) ShaderCode << " Color1 = RawColor1;\n";
// Per-vertex lighting
ShaderCode << "\n"
<< " // Dynamic Lighting\n";
// This bit could do with some cleaning up
// It took a lot of experimentation to get dynamic lights working and I never went back and cleaned it up after
if (Mat.IsLightingEnabled())
{
ShaderCode << " vec4 Illum = vec4(0.0);\n"
<< " vec3 PositionMV = vec3(vec4(RawPosition, 1.0) * MV);\n"
<< " \n"
<< " for (int iLight = 0; iLight < NumLights; iLight++)\n"
<< " {\n"
<< " vec3 LightPosMV = vec3(Lights[iLight].Position * ViewMtx);\n"
<< " vec3 LightDirMV = normalize(Lights[iLight].Direction.xyz * inverse(transpose(mat3(ViewMtx))));\n"
<< " vec3 LightDist = LightPosMV.xyz - PositionMV.xyz;\n"
<< " float DistSquared = dot(LightDist, LightDist);\n"
<< " float Dist = sqrt(DistSquared);\n"
<< " LightDist /= Dist;\n"
<< " vec3 AngleAtten = Lights[iLight].AngleAtten.xyz;\n"
<< " AngleAtten = vec3(AngleAtten.x, AngleAtten.y, AngleAtten.z);\n"
<< " float Atten = max(0, dot(LightDist, LightDirMV.xyz));\n"
<< " Atten = max(0, dot(AngleAtten, vec3(1.0, Atten, Atten * Atten))) / dot(Lights[iLight].DistAtten.xyz, vec3(1.0, Dist, DistSquared));\n"
<< " float DiffuseAtten = max(0, dot(Normal, LightDist));\n"
<< " Illum += (Atten * DiffuseAtten * Lights[iLight].Color);\n"
<< " }\n"
<< " COLOR0A0 = COLOR0_Mat * (Illum + COLOR0_Amb);\n"
<< " COLOR1A1 = COLOR1_Mat * (Illum + COLOR1_Amb);\n"
<< " \n";
}
else
{
ShaderCode << " COLOR0A0 = COLOR0_Mat;\n"
<< " COLOR1A1 = COLOR1_Mat;\n"
<< "\n";
}
// Texture coordinate generation
ShaderCode << " \n"
<< " // TexGen\n";
u32 PassCount = Mat.PassCount();
for (u32 iPass = 0; iPass < PassCount; iPass++)
{
CMaterialPass *pPass = Mat.Pass(iPass);
if (pPass->TexCoordSource() == 0xFF) continue;
EUVAnimMode AnimMode = pPass->AnimMode();
if (AnimMode == eNoUVAnim) // No animation
ShaderCode << " Tex" << iPass << " = vec3(" << gkCoordSrc[pPass->TexCoordSource()] << ");\n";
else // Animation used - texture matrix at least, possibly normalize/post-transform
{
// Texture Matrix
ShaderCode << " Tex" << iPass << " = vec3(vec4(" << gkCoordSrc[pPass->TexCoordSource()] << ", 1.0) * TexMtx[" << iPass << "]).xyz;\n";
if ((AnimMode < 2) || (AnimMode > 5))
{
// Normalization + Post-Transform
ShaderCode << " Tex" << iPass << " = normalize(Tex" << iPass << ");\n";
ShaderCode << " Tex" << iPass << " = vec3(vec4(Tex" << iPass << ", 1.0) * PostMtx[" << iPass << "]).xyz;\n";
}
}
ShaderCode << "\n";
}
ShaderCode << "}\n\n";
// Done!
return mShader->CompileVertexSource(ShaderCode.str().c_str());
}
bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat)
{
std::stringstream ShaderCode;
ShaderCode << "#version 330 core\n"
<< "\n";
EVertexDescription VtxDesc = Mat.VtxDesc();
if (VtxDesc & ePosition) ShaderCode << "in vec3 Position;\n";
if (VtxDesc & eNormal) ShaderCode << "in vec3 Normal;\n";
if (VtxDesc & eColor0) ShaderCode << "in vec4 Color0;\n";
if (VtxDesc & eColor1) ShaderCode << "in vec4 Color1;\n";
u32 PassCount = Mat.PassCount();
for (u32 iPass = 0; iPass < PassCount; iPass++)
if (Mat.Pass(iPass)->TexCoordSource() != 0xFF)
ShaderCode << "in vec3 Tex" << iPass << ";\n";
ShaderCode << "in vec4 COLOR0A0;\n"
<< "in vec4 COLOR1A1;\n"
<< "\n"
<< "out vec4 PixelColor;\n"
<< "\n"
<< "layout(std140) uniform PixelBlock {\n"
<< " vec4 KonstColors[4];\n"
<< " vec4 TevColor;\n"
<< " vec4 TintColor;\n"
<< "};\n\n";
for (u32 iPass = 0; iPass < PassCount; iPass++)
if (Mat.Pass(iPass)->Texture() != nullptr)
ShaderCode << "uniform sampler2D Texture" << iPass << ";\n";
ShaderCode <<"\n";
ShaderCode << "void main()\n"
<< "{\n"
<< " vec4 TevInA = vec4(0, 0, 0, 0), TevInB = vec4(0, 0, 0, 0), TevInC = vec4(0, 0, 0, 0), TevInD = vec4(0, 0, 0, 0);\n"
<< " vec4 Prev = vec4(0, 0, 0, 0), C0 = TevColor, C1 = C0, C2 = C0;\n"
<< " vec4 Ras = vec4(0, 0, 0, 1), Tex = vec4(0, 0, 0, 0);\n"
<< " vec4 Konst = vec4(1, 1, 1, 1);\n";
ShaderCode << " vec2 TevCoord = vec2(0, 0);\n"
<< " \n";
bool Lightmap = false;
for (u32 iPass = 0; iPass < PassCount; iPass++)
{
const CMaterialPass *pPass = Mat.Pass(iPass);
CFourCC PassType = pPass->Type();
ShaderCode << " // TEV Stage " << iPass << " - " << PassType.ToString() << "\n";
if (pPass->Type() == "DIFF") Lightmap = true;
if (!pPass->IsEnabled())
{
ShaderCode << " // Pass is disabled\n\n";
continue;
}
if (pPass->TexCoordSource() != 0xFF)
ShaderCode << " TevCoord = (Tex" << iPass << ".z == 0.0 ? Tex" << iPass << ".xy : Tex" << iPass << ".xy / Tex" << iPass << ".z);\n";
if (pPass->Texture() != nullptr)
ShaderCode << " Tex = texture(Texture" << iPass << ", TevCoord)";
// A couple pass types require special swizzles to access different texture color channels as alpha
if ((PassType == "TRAN") || (PassType == "INCA") || (PassType == "BLOI"))
ShaderCode << ".rgbr";
else if (PassType == "BLOL")
ShaderCode << ".rgbg";
ShaderCode << ";\n";
ShaderCode << " Konst = vec4(" << gkKonstColor[pPass->KColorSel()] << ", " << gkKonstAlpha[pPass->KAlphaSel()] << ");\n";
if (pPass->RasSel() != eRasColorNull)
ShaderCode << " Ras = " << gkRasSel[pPass->RasSel()] << ";\n";
for (u8 iInput = 0; iInput < 4; iInput++)
{
char TevChar = iInput + 0x41; // the current stage number represented as an ASCII letter; eg 0 is 'A'
ShaderCode << " TevIn" << TevChar << " = vec4("
<< gkTevColor[pPass->ColorInput(iInput) & 0xF]
<< ", "
<< gkTevAlpha[pPass->AlphaInput(iInput) & 0x7]
<< ");\n";
}
ShaderCode << " // RGB Combine\n"
<< " "
<< gkTevRigid[pPass->ColorOutput()]
<< ".rgb = ";
ShaderCode << "clamp(vec3(TevInD.rgb + ((1.0 - TevInC.rgb) * TevInA.rgb + TevInC.rgb * TevInB.rgb))";
if ((PassType == "CLR ") && (Lightmap)) ShaderCode << "* 2.0"; // Apply tevscale 2.0 on the color pass if lightmap is present
ShaderCode << ", vec3(0, 0, 0), vec3(1.0, 1.0, 1.0));\n";
ShaderCode << " // Alpha Combine\n"
<< " "
<< gkTevRigid[pPass->AlphaOutput()]
<< ".a = ";
ShaderCode << "clamp(TevInD.a + ((1.0 - TevInC.a) * TevInA.a + TevInC.a * TevInB.a), 0.0, 1.0);\n\n";
}
if (Mat.Options() & CMaterial::ePunchthrough)
{
if (Mat.Version() < eCorruptionProto)
{
ShaderCode << " if (Prev.a <= 0.25) discard;\n"
<< " else Prev.a = 1.0;\n\n";
}
else
{
ShaderCode << " if (Prev.a <= 0.75) discard;\n"
" else Prev.a = 0.0;\n\n";
}
}
ShaderCode << " PixelColor = Prev.rgba * TintColor;\n"
<< "}\n\n";
// Done!
return mShader->CompilePixelSource(ShaderCode.str().c_str());
}
CShader* CShaderGenerator::GenerateShader(const CMaterial& Mat)
{
CShaderGenerator Generator;
Generator.mShader = new CShader();
bool Success = Generator.CreateVertexShader(Mat);
if (Success) Success = Generator.CreatePixelShader(Mat);
Generator.mShader->LinkShaders();
return Generator.mShader;
}

View File

@@ -0,0 +1,22 @@
#ifndef SHADERGEN_H
#define SHADERGEN_H
#include <gl/glew.h>
#include "CShader.h"
#include <Resource/CMaterial.h>
class CShaderGenerator
{
CShader *mShader;
CShaderGenerator();
~CShaderGenerator();
bool CreateVertexShader(const CMaterial& Mat);
bool CreatePixelShader(const CMaterial& Mat);
public:
static CShader* GenerateShader(const CMaterial& Mat);
};
#endif // SHADERGEN_H

View File

@@ -0,0 +1,60 @@
#include "CUniformBuffer.h"
CUniformBuffer::CUniformBuffer()
{
glGenBuffers(1, &mUniformBuffer);
SetBufferSize(0);
}
CUniformBuffer::CUniformBuffer(u32 Size)
{
glGenBuffers(1, &mUniformBuffer);
SetBufferSize(Size);
}
CUniformBuffer::~CUniformBuffer()
{
glDeleteBuffers(1, &mUniformBuffer);
}
void CUniformBuffer::InitializeBuffer()
{
Bind();
glBufferData(GL_UNIFORM_BUFFER, mBufferSize, 0, GL_DYNAMIC_DRAW);
Unbind();
}
void CUniformBuffer::Bind()
{
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
}
void CUniformBuffer::Unbind()
{
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
void CUniformBuffer::BindBase(GLuint index)
{
Bind();
glBindBufferBase(GL_UNIFORM_BUFFER, index, mUniformBuffer);
Unbind();
}
void CUniformBuffer::Buffer(void *pData)
{
Bind();
glBufferSubData(GL_UNIFORM_BUFFER, 0, mBufferSize, pData);
Unbind();
}
void CUniformBuffer::SetBufferSize(u32 Size)
{
mBufferSize = Size;
InitializeBuffer();
}
u32 CUniformBuffer::GetBufferSize()
{
return mBufferSize;
}

View File

@@ -0,0 +1,28 @@
#ifndef CUNIFORMBUFFER_H
#define CUNIFORMBUFFER_H
#include <gl/glew.h>
#include <Common/types.h>
class CUniformBuffer
{
GLuint mUniformBuffer;
u32 mBufferSize;
public:
CUniformBuffer();
CUniformBuffer(u32 Size);
~CUniformBuffer();
void Bind();
void Unbind();
void BindBase(GLuint index);
void Buffer(void *pData);
void SetBufferSize(u32 Size);
u32 GetBufferSize();
private:
void InitializeBuffer();
};
#endif // CUNIFORMBUFFER_H

View File

@@ -0,0 +1,105 @@
#include "CVertexArrayManager.h"
// ************ STATIC MEMBER INITIALIZATION ************
std::vector<CVertexArrayManager*> CVertexArrayManager::sVAManagers;
CVertexArrayManager *CVertexArrayManager::spCurrentManager;
// ************ CONSTRUCTORS/DESTRUCTORS ************
CVertexArrayManager::CVertexArrayManager()
{
mVectorIndex = sVAManagers.size();
sVAManagers.push_back(this);
}
CVertexArrayManager::~CVertexArrayManager()
{
for (auto it = mVBOMap.begin(); it != mVBOMap.end(); it = mVBOMap.begin())
DeleteVAO(it->first);
for (auto it = mDynamicVBOMap.begin(); it != mDynamicVBOMap.end(); it = mDynamicVBOMap.begin())
DeleteVAO(it->first);
sVAManagers.erase(sVAManagers.begin() + mVectorIndex);
if (sVAManagers.size() > mVectorIndex)
for (auto it = sVAManagers.begin() + mVectorIndex; it != sVAManagers.end(); it++)
(*it)->mVectorIndex--;
}
// ************ PUBLIC ************
void CVertexArrayManager::SetCurrent()
{
spCurrentManager = this;
}
void CVertexArrayManager::BindVAO(CVertexBuffer *pVBO)
{
auto it = mVBOMap.find(pVBO);
if (it != mVBOMap.end())
glBindVertexArray(it->second);
else
{
GLuint VAO = pVBO->CreateVAO();
mVBOMap[pVBO] = VAO;
glBindVertexArray(VAO);
}
}
void CVertexArrayManager::BindVAO(CDynamicVertexBuffer *pVBO)
{
// Overload for CDynamicVertexBuffer
auto it = mDynamicVBOMap.find(pVBO);
if (it != mDynamicVBOMap.end())
glBindVertexArray(it->second);
else
{
GLuint VAO = pVBO->CreateVAO();
mDynamicVBOMap[pVBO] = VAO;
glBindVertexArray(VAO);
}
}
void CVertexArrayManager::DeleteVAO(CVertexBuffer *pVBO)
{
auto it = mVBOMap.find(pVBO);
if (it != mVBOMap.end())
{
glDeleteVertexArrays(1, &it->second);
mVBOMap.erase(it);
}
}
void CVertexArrayManager::DeleteVAO(CDynamicVertexBuffer *pVBO)
{
// Overload for CDynamicVertexBuffer
auto it = mDynamicVBOMap.find(pVBO);
if (it != mDynamicVBOMap.end())
{
glDeleteVertexArrays(1, &it->second);
mDynamicVBOMap.erase(it);
}
}
// ************ STATIC ************
CVertexArrayManager* CVertexArrayManager::Current()
{
return spCurrentManager;
}
void CVertexArrayManager::DeleteAllArraysForVBO(CVertexBuffer *pVBO)
{
for (u32 iVAM = 0; iVAM < sVAManagers.size(); iVAM++)
sVAManagers[iVAM]->DeleteVAO(pVBO);
}
void CVertexArrayManager::DeleteAllArraysForVBO(CDynamicVertexBuffer *pVBO)
{
for (u32 iVAM = 0; iVAM < sVAManagers.size(); iVAM++)
sVAManagers[iVAM]->DeleteVAO(pVBO);
}

View File

@@ -0,0 +1,34 @@
#ifndef CVERTEXARRAYMANAGER_H
#define CVERTEXARRAYMANAGER_H
#include "CDynamicVertexBuffer.h"
#include "CVertexBuffer.h"
#include <unordered_map>
#include <vector>
#include <GL/glew.h>
class CVertexArrayManager
{
std::unordered_map<CVertexBuffer*, GLuint> mVBOMap;
std::unordered_map<CDynamicVertexBuffer*, GLuint> mDynamicVBOMap;
u32 mVectorIndex;
static std::vector<CVertexArrayManager*> sVAManagers;
static CVertexArrayManager *spCurrentManager;
public:
CVertexArrayManager();
~CVertexArrayManager();
void SetCurrent();
void BindVAO(CVertexBuffer *pVBO);
void BindVAO(CDynamicVertexBuffer *pVBO);
void DeleteVAO(CVertexBuffer *pVBO);
void DeleteVAO(CDynamicVertexBuffer *pVBO);
static CVertexArrayManager* Current();
static void DeleteAllArraysForVBO(CVertexBuffer *pVBO);
static void DeleteAllArraysForVBO(CDynamicVertexBuffer *pVBO);
};
#endif // CVERTEXARRAYMANAGER_H

View File

@@ -0,0 +1,230 @@
#include "CVertexBuffer.h"
#include "CVertexArrayManager.h"
#include <Core/CGraphics.h>
CVertexBuffer::CVertexBuffer()
{
mBuffered = false;
SetVertexDesc(ePosition | eNormal | eTex0 | eTex1 | eTex2 | eTex3 | eTex4 | eTex5 | eTex6 | eTex7);
}
CVertexBuffer::CVertexBuffer(EVertexDescription Desc)
{
mBuffered = false;
SetVertexDesc(Desc);
}
CVertexBuffer::~CVertexBuffer()
{
CVertexArrayManager::DeleteAllArraysForVBO(this);
if (mBuffered)
glDeleteBuffers(12, mAttribBuffers);
}
u16 CVertexBuffer::AddVertex(const CVertex& Vert)
{
if (mPositions.size() == 0xFFFF) throw std::overflow_error("VBO contains too many vertices");
if (mVtxDesc & ePosition) mPositions.push_back(Vert.Position);
if (mVtxDesc & eNormal) mNormals.push_back(Vert.Normal);
if (mVtxDesc & eColor0) mColors[0].push_back(Vert.Color[0]);
if (mVtxDesc & eColor1) mColors[1].push_back(Vert.Color[1]);
for (u32 iTex = 0; iTex < 8; iTex++)
if (mVtxDesc & (eTex0 << (iTex * 2))) mTexCoords[iTex].push_back(Vert.Tex[iTex]);
for (u32 iMtx = 0; iMtx < 8; iMtx++)
if (mVtxDesc & (ePosMtx << iMtx)) mTexCoords[iMtx].push_back(Vert.MatrixIndices[iMtx]);
return (mPositions.size() - 1);
}
u16 CVertexBuffer::AddIfUnique(const CVertex& Vert, u16 Start)
{
if (Start < mPositions.size())
{
for (u16 iVert = Start; iVert < mPositions.size(); iVert++)
{
// I use a bool because "continue" doesn't work properly within the iTex loop
bool Unique = false;
if (mVtxDesc & ePosition)
if (Vert.Position != mPositions[iVert]) Unique = true;
if ((!Unique) && (mVtxDesc & eNormal))
if (Vert.Normal != mNormals[iVert]) Unique = true;
if ((!Unique) && (mVtxDesc & eColor0))
if (Vert.Color[0] != mColors[0][iVert]) Unique = true;
if ((!Unique) && (mVtxDesc & eColor1))
if (Vert.Color[1] != mColors[1][iVert]) Unique = true;
if (!Unique)
for (u32 iTex = 0; iTex < 8; iTex++)
if ((mVtxDesc & (eTex0 << (iTex * 2))))
if (Vert.Tex[iTex] != mTexCoords[iTex][iVert])
{
Unique = true;
break;
}
if (!Unique) return iVert;
}
}
return AddVertex(Vert);
}
void CVertexBuffer::Reserve(u16 size)
{
u32 ReserveSize = mPositions.size() + size;
if (mVtxDesc & ePosition)
mPositions.reserve(ReserveSize);
if (mVtxDesc & eNormal)
mNormals.reserve(ReserveSize);
if (mVtxDesc & eColor0)
mColors[0].reserve(ReserveSize);
if (mVtxDesc & eColor1)
mColors[1].reserve(ReserveSize);
for (u32 iTex = 0; iTex < 8; iTex++)
if (mVtxDesc & (eTex0 << (iTex * 2)))
mTexCoords[iTex].reserve(ReserveSize);
}
void CVertexBuffer::Clear()
{
if (mBuffered)
glDeleteBuffers(12, mAttribBuffers);
mBuffered = false;
mPositions.clear();
mNormals.clear();
mColors[0].clear();
mColors[1].clear();
for (u32 iTex = 0; iTex < 8; iTex++)
mTexCoords[iTex].clear();
}
void CVertexBuffer::Buffer()
{
// Make sure we don't end up with two buffers for the same data...
if (mBuffered)
{
glDeleteBuffers(12, mAttribBuffers);
mBuffered = false;
}
// Generate buffers
glGenBuffers(12, mAttribBuffers);
for (u32 iAttrib = 0; iAttrib < 12; iAttrib++)
{
int Attrib = (ePosition << (iAttrib * 2));
bool HasAttrib = ((mVtxDesc & Attrib) != 0);
if (!HasAttrib) continue;
if (iAttrib < 2)
{
std::vector<CVector3f> *pBuffer = (iAttrib == 0) ? &mPositions : &mNormals;
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, pBuffer->size() * sizeof(CVector3f), pBuffer->data(), GL_STATIC_DRAW);
}
else if (iAttrib < 4)
{
u8 idx = (u8) (iAttrib - 2);
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mColors[idx].size() * sizeof(CColor), mColors[idx].data(), GL_STATIC_DRAW);
}
else
{
u8 idx = (u8) (iAttrib - 4);
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mTexCoords[idx].size() * sizeof(CVector2f), mTexCoords[idx].data(), GL_STATIC_DRAW);
}
}
mBuffered = true;
}
void CVertexBuffer::Bind()
{
if (!mBuffered) Buffer();
CVertexArrayManager::Current()->BindVAO(this);
}
void CVertexBuffer::Unbind()
{
glBindVertexArray(0);
}
bool CVertexBuffer::IsBuffered()
{
return mBuffered;
}
EVertexDescription CVertexBuffer::VertexDesc()
{
return mVtxDesc;
}
void CVertexBuffer::SetVertexDesc(EVertexDescription Desc)
{
Clear();
mVtxDesc = Desc;
}
u32 CVertexBuffer::Size()
{
return mPositions.size();
}
GLuint CVertexBuffer::CreateVAO()
{
GLuint VertexArray;
glGenVertexArrays(1, &VertexArray);
glBindVertexArray(VertexArray);
for (u32 iAttrib = 0; iAttrib < 12; iAttrib++)
{
int Attrib = (ePosition << (iAttrib * 2));
bool HasAttrib = ((mVtxDesc & Attrib) != 0);
if (!HasAttrib) continue;
if (iAttrib < 2)
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribPointer(iAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(CVector3f), (void*) 0);
glEnableVertexAttribArray(iAttrib);
}
else if (iAttrib < 4)
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribPointer(iAttrib, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(CColor), (void*) 0);
glEnableVertexAttribArray(iAttrib);
}
else
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribPointer(iAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(CVector2f), (void*) 0);
glEnableVertexAttribArray(iAttrib);
}
}
glBindVertexArray(0);
return VertexArray;
}

View File

@@ -0,0 +1,37 @@
#ifndef CVERTEXBUFFER_H
#define CVERTEXBUFFER_H
#include <GL/glew.h>
#include <Resource/model/CVertex.h>
#include <Resource/model/EVertexDescription.h>
#include <vector>
class CVertexBuffer
{
EVertexDescription mVtxDesc; // Flags that indicate what vertex attributes are enabled on this vertex buffer
GLuint mAttribBuffers[12]; // Separate GL buffer for each attribute to allow not tracking unused attribs. No support for matrix indices currently.
std::vector<CVector3f> mPositions; // Vector of vertex positions
std::vector<CVector3f> mNormals; // Vector of vertex normals
std::vector<CColor> mColors[2]; // Vectors of vertex colors
std::vector<CVector2f> mTexCoords[8]; // Vectors of texture coordinates
bool mBuffered; // Bool value that indicates whether the attributes have been buffered.
public:
CVertexBuffer();
CVertexBuffer(EVertexDescription Desc);
~CVertexBuffer();
u16 AddVertex(const CVertex& vtx);
u16 AddIfUnique(const CVertex& vtx, u16 start);
void Reserve(u16 size);
void Clear();
void Buffer();
void Bind();
void Unbind();
bool IsBuffered();
EVertexDescription VertexDesc();
void SetVertexDesc(EVertexDescription Desc);
u32 Size();
GLuint CreateVAO();
};
#endif // CVERTEXBUFFER_H

View File

@@ -0,0 +1,37 @@
#include "GLCommon.h"
#include <stdexcept>
GLenum glBlendFactor[] = {
GL_ZERO, // GX_BL_ZERO
GL_ONE, // GX_BL_ONE
GL_SRC_COLOR, // GX_BL_SRCCLR / GX_BL_DSTCLR
GL_ONE_MINUS_SRC_COLOR, // GX_BL_INVSRCCLR / GX_BL_INVDSTCLR
GL_SRC_ALPHA, // GX_BL_SRCALPHA
GL_ONE_MINUS_SRC_ALPHA, // GX_BL_INVSRCALPHA
GL_DST_ALPHA, // GX_BL_DSTALPHA
GL_ONE_MINUS_DST_ALPHA // GX_BL_INVDSTALPHA
};
GLenum glZMode[] = {
GL_NEVER, // GX_NEVER
GL_LESS, // GX_LESS
GL_EQUAL, // GX_EQUAL
GL_LEQUAL, // GX_LEQUAL
GL_GREATER, // GX_GREATER
GL_NOTEQUAL, // GX_NEQUAL
GL_ALWAYS // GX_ALWAYS
};
GLenum GXPrimToGLPrim(EGXPrimitiveType t) {
switch (t) {
case eGX_Quads: return GL_TRIANGLE_STRIP; // Quads are converted to strips
case eGX_Triangles: return GL_TRIANGLE_STRIP; // Triangles are converted to strips
case eGX_TriangleStrip: return GL_TRIANGLE_STRIP;
case eGX_TriangleFan: return GL_TRIANGLE_STRIP; // Fans are converted to strips
case eGX_Lines: return GL_LINES;
case eGX_LineStrip: return GL_LINE_STRIP;
case eGX_Points: return GL_POINTS;
default: throw std::invalid_argument("Invalid GX primitive type");
}
}

View File

@@ -0,0 +1,34 @@
#ifndef GLCOMMON_H
#define GLCOMMON_H
#include <GL/glew.h>
#include <Common/types.h>
enum EBlendFactor
{
eBlendZero = GL_ZERO,
eBlendOne = GL_ONE,
eBlendSrcColor = GL_SRC_COLOR,
eBlendInvSrcColor = GL_ONE_MINUS_SRC_COLOR,
eBlendSrcAlpha = GL_SRC_ALPHA,
eBlendInvSrcAlpha = GL_ONE_MINUS_SRC_ALPHA,
eBlendDstAlpha = GL_DST_ALPHA,
eBlendInvDstAlpha = GL_ONE_MINUS_DST_ALPHA
};
enum EGXPrimitiveType
{
eGX_Quads = 0x80,
eGX_Triangles = 0x90,
eGX_TriangleStrip = 0x98,
eGX_TriangleFan = 0xA0,
eGX_Lines = 0xA8,
eGX_LineStrip = 0xB0,
eGX_Points = 0xB8
};
extern GLenum glBlendFactor[];
extern GLenum glZMode[];
GLenum GXPrimToGLPrim(EGXPrimitiveType t);
#endif // GLCOMMON_H

370
src/Core/Render/CCamera.cpp Normal file
View File

@@ -0,0 +1,370 @@
#include "CCamera.h"
#include "CGraphics.h"
#include <Common/CQuaternion.h>
#include <Common/Math.h>
#include <gtc/matrix_transform.hpp>
CCamera::CCamera()
{
mMode = eFreeCamera;
mPosition = CVector3f(0);
mAspectRatio = 1.7777777f;
mYaw = -Math::skHalfPi;
mPitch = 0.0f;
SetOrbit(CVector3f(0), 5.f);
mMoveSpeed = 1.f;
mLookSpeed = 1.f;
mTransformDirty = true;
mViewDirty = true;
mProjectionDirty = true;
mFrustumPlanesDirty = true;
}
CCamera::CCamera(CVector3f Position, CVector3f /*Target*/)
{
// todo: make it actually look at the target!
// don't actually use this constructor, it's unfinished and won't work properly
mMode = eFreeCamera;
mMoveSpeed = 1.f;
mLookSpeed = 1.f;
mPosition = Position;
mYaw = -Math::skHalfPi;
mPitch = 0.0f;
}
void CCamera::Pan(float XAmount, float YAmount)
{
if (mMode == eFreeCamera)
{
mPosition += mRightVector * (XAmount * mMoveSpeed);
mPosition += mUpVector * (YAmount * mMoveSpeed);
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
else
Rotate(-XAmount * 0.3f, YAmount * 0.3f);
}
void CCamera::Rotate(float XAmount, float YAmount)
{
mYaw -= (XAmount * mLookSpeed * 0.3f);
mPitch -= (YAmount * mLookSpeed * 0.3f);
ValidatePitch();
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
void CCamera::Zoom(float Amount)
{
if (mMode == eFreeCamera)
mPosition += mDirection * (Amount * mMoveSpeed);
else
{
mOrbitDistance -= Amount * mMoveSpeed;
mTransformDirty = true;
}
mViewDirty = true;
mFrustumPlanesDirty = true;
}
void CCamera::Snap(CVector3f Position)
{
mPosition = Position;
mYaw = -Math::skHalfPi;
mPitch = 0.0f;
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
void CCamera::ProcessKeyInput(EKeyInputs KeyFlags, double DeltaTime)
{
float FDeltaTime = (float) DeltaTime;
if (KeyFlags & eWKey) Zoom(FDeltaTime * 25.f);
if (KeyFlags & eSKey) Zoom(-FDeltaTime * 25.f);
if (KeyFlags & eQKey) Pan(0, -FDeltaTime * 25.f);
if (KeyFlags & eEKey) Pan(0, FDeltaTime * 25.f);
if (KeyFlags & eAKey) Pan(-FDeltaTime * 25.f, 0);
if (KeyFlags & eDKey) Pan(FDeltaTime * 25.f, 0);
}
void CCamera::ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement)
{
// Free Camera
if (mMode == eFreeCamera)
{
if (MouseFlags & eMiddleButton)
{
if (KeyFlags & eCtrlKey) Zoom(-YMovement * 0.2f);
else Pan(-XMovement, YMovement);
}
else if (MouseFlags & eRightButton) Rotate(XMovement, YMovement);
}
// Orbit Camera
else if (mMode == eOrbitCamera)
{
if ((MouseFlags & eMiddleButton) || (MouseFlags & eRightButton))
Pan(-XMovement, YMovement);
}
}
CRay CCamera::CastRay(CVector2f DeviceCoords) const
{
CMatrix4f InverseVP = (ViewMatrix().Transpose() * ProjectionMatrix().Transpose()).Inverse();
CVector3f RayOrigin = CVector3f(DeviceCoords.x, DeviceCoords.y, -1.f) * InverseVP;
CVector3f RayTarget = CVector3f(DeviceCoords.x, DeviceCoords.y, 0.f) * InverseVP;
CVector3f RayDir = (RayTarget - RayOrigin).Normalized();
CRay Ray;
Ray.SetOrigin(RayOrigin);
Ray.SetDirection(RayDir);
return Ray;
}
void CCamera::SetMoveMode(ECameraMoveMode Mode)
{
mMode = Mode;
mViewDirty = true;
mFrustumPlanesDirty = true;
if (mMode == eOrbitCamera)
mTransformDirty = true;
}
void CCamera::SetOrbit(const CVector3f& OrbitTarget, float Distance)
{
mOrbitTarget = OrbitTarget;
mOrbitDistance = Distance;
if (mMode == eOrbitCamera)
{
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
}
void CCamera::SetOrbit(const CAABox& OrbitTarget, float DistScale /*= 4.f*/)
{
CVector3f Min = OrbitTarget.Min();
CVector3f Max = OrbitTarget.Max();
mOrbitTarget = OrbitTarget.Center();
// Find largest extent
CVector3f Extent = (Max - Min) / 2.f;
float Dist = 0.f;
if (Extent.x >= Extent.y && Extent.x >= Extent.z) Dist = Extent.x;
else if (Extent.y >= Extent.x && Extent.y >= Extent.z) Dist = Extent.y;
else Dist = Extent.z;
mOrbitDistance = Dist * DistScale;
if (mMode == eOrbitCamera)
{
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
}
void CCamera::SetOrbitDistance(float Distance)
{
mOrbitDistance = Distance;
if (mMode == eOrbitCamera)
{
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
}
void CCamera::LoadMatrices() const
{
CGraphics::sMVPBlock.ViewMatrix = ViewMatrix();
CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix();
CGraphics::UpdateMVPBlock();
}
// ************ GETTERS ************
CVector3f CCamera::Position() const
{
UpdateTransform();
return mPosition;
}
CVector3f CCamera::Direction() const
{
UpdateTransform();
return mDirection;
}
CVector3f CCamera::UpVector() const
{
UpdateTransform();
return mUpVector;
}
CVector3f CCamera::RightVector() const
{
UpdateTransform();
return mRightVector;
}
float CCamera::Yaw() const
{
return mYaw;
}
float CCamera::Pitch() const
{
return mPitch;
}
float CCamera::FieldOfView() const
{
return 55.f;
}
ECameraMoveMode CCamera::MoveMode() const
{
return mMode;
}
const CMatrix4f& CCamera::ViewMatrix() const
{
UpdateView();
return mViewMatrix;
}
const CMatrix4f& CCamera::ProjectionMatrix() const
{
UpdateProjection();
return mProjectionMatrix;
}
const CFrustumPlanes& CCamera::FrustumPlanes() const
{
UpdateFrustum();
return mFrustumPlanes;
}
// ************ SETTERS ************
void CCamera::SetYaw(float Yaw)
{
mYaw = Yaw;
mTransformDirty = true;
}
void CCamera::SetPitch(float Pitch)
{
mPitch = Pitch;
ValidatePitch();
mTransformDirty = true;
}
void CCamera::SetMoveSpeed(float MoveSpeed)
{
mMoveSpeed = MoveSpeed;
}
void CCamera::SetLookSpeed(float LookSpeed)
{
mLookSpeed = LookSpeed;
}
void CCamera::SetAspectRatio(float AspectRatio)
{
mAspectRatio = AspectRatio;
mProjectionDirty = true;
mFrustumPlanesDirty = true;
}
// ************ PRIVATE ************
void CCamera::ValidatePitch()
{
// This function mainly just exists to ensure the camera doesn't flip upside down
if (mPitch > Math::skHalfPi) mPitch = Math::skHalfPi;
if (mPitch < -Math::skHalfPi) mPitch = -Math::skHalfPi;
}
void CCamera::UpdateTransform() const
{
// Transform should be marked dirty when pitch, yaw, or orbit target/distance are changed
if (mTransformDirty)
{
mDirection = CVector3f(
cos(mPitch) * cos(mYaw),
cos(mPitch) * sin(mYaw),
sin(mPitch)
);
mRightVector = CVector3f(
cos(mYaw - Math::skHalfPi),
sin(mYaw - Math::skHalfPi),
0
);
mUpVector = mRightVector.Cross(mDirection);
// Update position
if (mMode == eOrbitCamera)
{
if (mOrbitDistance < 1.f) mOrbitDistance = 1.f;
mPosition = mOrbitTarget + (mDirection * -mOrbitDistance);
}
mViewDirty = true;
mFrustumPlanesDirty = true;
mTransformDirty = false;
}
}
void CCamera::UpdateView() const
{
// todo: don't use glm
UpdateTransform();
if (mViewDirty)
{
glm::vec3 glmpos(mPosition.x, mPosition.y, mPosition.z);
glm::vec3 glmdir(mDirection.x, mDirection.y, mDirection.z);
glm::vec3 glmup(mUpVector.x, mUpVector.y, mUpVector.z);
mViewMatrix = CMatrix4f::FromGlmMat4(glm::lookAt(glmpos, glmpos + glmdir, glmup)).Transpose();
mViewDirty = false;
}
}
void CCamera::UpdateProjection() const
{
if (mProjectionDirty)
{
mProjectionMatrix = Math::PerspectiveMatrix(55.f, mAspectRatio, 0.1f, 4096.f);
mProjectionDirty = false;
}
}
void CCamera::UpdateFrustum() const
{
UpdateTransform();
if (mFrustumPlanesDirty)
{
mFrustumPlanes.SetPlanes(mPosition, mDirection, 55.f, mAspectRatio, 0.1f, 4096.f);
mFrustumPlanesDirty = false;
}
}

99
src/Core/Render/CCamera.h Normal file
View File

@@ -0,0 +1,99 @@
#ifndef CCAMERA_H
#define CCAMERA_H
#include "CFrustumPlanes.h"
#include <Common/CAABox.h>
#include <Common/CMatrix4f.h>
#include <Common/CRay.h>
#include <Common/CVector2i.h>
#include <Common/CVector3f.h>
#include <Common/types.h>
#include <Common/EKeyInputs.h>
#include <Common/EMouseInputs.h>
enum ECameraMoveMode
{
eFreeCamera, eOrbitCamera
};
/* This class uses a lot of mutable members as an optimization so that they can
* be updated as infrequently as possible (eg only when the values are requested
* the next time after changes are made) while still always returning the correct
* value via the const get functions. They are not modified in const functions
* beyond ensuring that all data is valid and synced with everything else (eg
* mPosition is only modified to ensure it's correct in orbit mode given the
* target/distance/pitch/yaw; it won't be modified as a camera snap in a const
* function). */
class CCamera
{
ECameraMoveMode mMode;
mutable CVector3f mPosition;
mutable CVector3f mDirection;
mutable CVector3f mRightVector;
mutable CVector3f mUpVector;
float mAspectRatio;
float mYaw;
float mPitch;
CVector3f mOrbitTarget;
mutable float mOrbitDistance;
float mMoveSpeed;
float mLookSpeed;
mutable CMatrix4f mViewMatrix;
mutable CMatrix4f mProjectionMatrix;
mutable CFrustumPlanes mFrustumPlanes;
mutable bool mTransformDirty;
mutable bool mViewDirty;
mutable bool mProjectionDirty;
mutable bool mFrustumPlanesDirty;
public:
CCamera();
CCamera(CVector3f Position, CVector3f Target);
void Pan(float XAmount, float YAmount);
void Rotate(float XAmount, float YAmount);
void Zoom(float Amount);
void Snap(CVector3f Position);
void ProcessKeyInput(EKeyInputs KeyFlags, double DeltaTime);
void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement);
CRay CastRay(CVector2f DeviceCoords) const;
void LoadMatrices() const;
void SetMoveMode(ECameraMoveMode Mode);
void SetOrbit(const CVector3f& OrbitTarget, float Distance);
void SetOrbit(const CAABox& OrbitTarget, float DistScale = 4.f);
void SetOrbitDistance(float Distance);
// Getters
CVector3f Position() const;
CVector3f Direction() const;
CVector3f UpVector() const;
CVector3f RightVector() const;
float Yaw() const;
float Pitch() const;
float FieldOfView() const;
ECameraMoveMode MoveMode() const;
const CMatrix4f& ViewMatrix() const;
const CMatrix4f& ProjectionMatrix() const;
const CFrustumPlanes& FrustumPlanes() const;
// Setters
void SetYaw(float Yaw);
void SetPitch(float Pitch);
void SetMoveSpeed(float MoveSpeed);
void SetLookSpeed(float LookSpeed);
void SetAspectRatio(float AspectRatio);
// Private
private:
void ValidatePitch();
void UpdateTransform() const;
void UpdateView() const;
void UpdateProjection() const;
void UpdateFrustum() const;
};
#endif // CCAMERA_H

View File

@@ -0,0 +1,578 @@
#include "CDrawUtil.h"
#include "CGraphics.h"
#include "CResCache.h"
#include <Common/CTransform4f.h>
#include <iostream>
#include "Log.h"
// ************ MEMBER INITIALIZATION ************
CVertexBuffer CDrawUtil::mGridVertices;
CIndexBuffer CDrawUtil::mGridIndices;
CDynamicVertexBuffer CDrawUtil::mSquareVertices;
CIndexBuffer CDrawUtil::mSquareIndices;
CDynamicVertexBuffer CDrawUtil::mLineVertices;
CIndexBuffer CDrawUtil::mLineIndices;
TResPtr<CModel> CDrawUtil::mpCubeModel;
CVertexBuffer CDrawUtil::mWireCubeVertices;
CIndexBuffer CDrawUtil::mWireCubeIndices;
TResPtr<CModel> CDrawUtil::mpSphereModel;
TResPtr<CModel> CDrawUtil::mpDoubleSidedSphereModel;
TResPtr<CModel> CDrawUtil::mpWireSphereModel;
CShader *CDrawUtil::mpColorShader;
CShader *CDrawUtil::mpColorShaderLighting;
CShader *CDrawUtil::mpBillboardShader;
CShader *CDrawUtil::mpLightBillboardShader;
CShader *CDrawUtil::mpTextureShader;
CShader *CDrawUtil::mpCollisionShader;
CShader *CDrawUtil::mpTextShader;
TResPtr<CTexture> CDrawUtil::mpCheckerTexture;
TResPtr<CTexture> CDrawUtil::mpLightTextures[4];
TResPtr<CTexture> CDrawUtil::mpLightMasks[4];
bool CDrawUtil::mDrawUtilInitialized = false;
// ************ PUBLIC ************
void CDrawUtil::DrawGrid()
{
Init();
mGridVertices.Bind();
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
CGraphics::UpdateMVPBlock();
glBlendFunc(GL_ONE, GL_ZERO);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glLineWidth(1.0f);
UseColorShader(CColor(0.6f, 0.6f, 0.6f, 0.f));
mGridIndices.DrawElements(0, mGridIndices.GetSize() - 4);
glLineWidth(1.5f);
UseColorShader(CColor::skTransparentBlack);
mGridIndices.DrawElements(mGridIndices.GetSize() - 4, 4);
}
void CDrawUtil::DrawSquare()
{
// Overload with default tex coords
CVector2f TexCoords[4] = { CVector2f(0.f, 1.f), CVector2f(1.f, 1.f), CVector2f(1.f, 0.f), CVector2f(0.f, 0.f) };
DrawSquare(&TexCoords[0].x);
}
void CDrawUtil::DrawSquare(const CVector2f& TexUL, const CVector2f& TexUR, const CVector2f& TexBR, const CVector2f& TexBL)
{
// Overload with tex coords specified via parameters
// I don't think that parameters are guaranteed to be contiguous in memory, so:
CVector2f TexCoords[4] = { TexUL, TexUR, TexBR, TexBL };
DrawSquare(&TexCoords[0].x);
}
void CDrawUtil::DrawSquare(const float *pTexCoords)
{
Init();
// Set tex coords
for (u32 iTex = 0; iTex < 8; iTex++)
{
EVertexDescription TexAttrib = (EVertexDescription) (eTex0 << (iTex *2));
mSquareVertices.BufferAttrib(TexAttrib, pTexCoords);
}
// Draw
mSquareVertices.Bind();
mSquareIndices.DrawElements();
mSquareVertices.Unbind();
}
void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB)
{
DrawLine(PointA, PointB, CColor::skWhite);
}
void CDrawUtil::DrawLine(const CVector2f& PointA, const CVector2f& PointB)
{
// Overload for 2D lines
DrawLine(CVector3f(PointA.x, PointA.y, 0.f), CVector3f(PointB.x, PointB.y, 0.f), CColor::skWhite);
}
void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB, const CColor& LineColor)
{
Init();
// Copy vec3s into an array to ensure they are adjacent in memory
CVector3f Points[2] = { PointA, PointB };
mLineVertices.BufferAttrib(ePosition, Points);
// Draw
UseColorShader(LineColor);
mLineVertices.Bind();
mLineIndices.DrawElements();
mLineVertices.Unbind();
}
void CDrawUtil::DrawLine(const CVector2f& PointA, const CVector2f& PointB, const CColor& LineColor)
{
// Overload for 2D lines
DrawLine(CVector3f(PointA.x, PointA.y, 0.f), CVector3f(PointB.x, PointB.y, 0.f), LineColor);
}
void CDrawUtil::DrawCube()
{
Init();
mpCubeModel->Draw(eNoMaterialSetup, 0);
}
void CDrawUtil::DrawCube(const CColor& Color)
{
Init();
UseColorShader(Color);
DrawCube();
}
void CDrawUtil::DrawCube(const CVector3f& Position, const CColor& Color)
{
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Position).ToMatrix4f();
CGraphics::UpdateMVPBlock();
UseColorShader(Color);
DrawCube();
}
void CDrawUtil::DrawShadedCube(const CColor& Color)
{
Init();
UseColorShaderLighting(Color);
DrawCube();
}
void CDrawUtil::DrawWireCube()
{
Init();
glLineWidth(1.f);
mWireCubeVertices.Bind();
mWireCubeIndices.DrawElements();
mWireCubeVertices.Unbind();
}
void CDrawUtil::DrawWireCube(const CAABox& kAABox, const CColor& kColor)
{
Init();
// Calculate model matrix
CTransform4f Transform;
Transform.Scale(kAABox.Size());
Transform.Translate(kAABox.Center());
CGraphics::sMVPBlock.ModelMatrix = Transform.ToMatrix4f();
CGraphics::UpdateMVPBlock();
UseColorShader(kColor);
DrawWireCube();
}
void CDrawUtil::DrawSphere(bool DoubleSided)
{
Init();
if (!DoubleSided)
mpSphereModel->Draw(eNoMaterialSetup, 0);
else
mpDoubleSidedSphereModel->Draw(eNoMaterialSetup, 0);
}
void CDrawUtil::DrawSphere(const CColor &kColor)
{
Init();
UseColorShader(kColor);
DrawSphere(false);
}
void CDrawUtil::DrawWireSphere(const CVector3f& Position, float Radius, const CColor& Color /*= CColor::skWhite*/)
{
Init();
// Create model matrix
CTransform4f Transform;
Transform.Scale(Radius);
Transform.Translate(Position);
CGraphics::sMVPBlock.ModelMatrix = Transform.ToMatrix4f();
CGraphics::UpdateMVPBlock();
// Set other render params
UseColorShader(Color);
CMaterial::KillCachedMaterial();
glBlendFunc(GL_ONE, GL_ZERO);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
// Draw
mpWireSphereModel->Draw(eNoMaterialSetup, 0);
}
void CDrawUtil::DrawBillboard(CTexture* pTexture, const CVector3f& Position, const CVector2f& Scale /*= CVector2f::skOne*/, const CColor& Tint /*= CColor::skWhite*/)
{
Init();
// Create translation-only model matrix
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Position).ToMatrix4f();
CGraphics::UpdateMVPBlock();
// Set uniforms
mpBillboardShader->SetCurrent();
GLuint ScaleLoc = mpBillboardShader->GetUniformLocation("BillboardScale");
glUniform2f(ScaleLoc, Scale.x, Scale.y);
GLuint TintLoc = mpBillboardShader->GetUniformLocation("TintColor");
CVector4f Tint4f = Tint.ToVector4f();
glUniform4f(TintLoc, Tint4f.x, Tint4f.y, Tint4f.z, Tint4f.w);
pTexture->Bind(0);
// Set other properties
CMaterial::KillCachedMaterial();
glBlendFunc(GL_ONE, GL_ZERO);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
// Draw
DrawSquare();
}
void CDrawUtil::DrawLightBillboard(ELightType Type, const CColor& LightColor, const CVector3f& Position, const CVector2f& Scale /*= CVector2f::skOne*/, const CColor& Tint /*= CColor::skWhite*/)
{
Init();
// Create translation-only model matrix
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Position).ToMatrix4f();
CGraphics::UpdateMVPBlock();
// Set uniforms
mpLightBillboardShader->SetCurrent();
GLuint ScaleLoc = mpLightBillboardShader->GetUniformLocation("BillboardScale");
glUniform2f(ScaleLoc, Scale.x, Scale.y);
GLuint ColorLoc = mpLightBillboardShader->GetUniformLocation("LightColor");
CVector4f Color4f = LightColor.ToVector4f();
glUniform4f(ColorLoc, Color4f.x, Color4f.y, Color4f.z, Color4f.w);
GLuint TintLoc = mpLightBillboardShader->GetUniformLocation("TintColor");
CVector4f Tint4f = Tint.ToVector4f();
glUniform4f(TintLoc, Tint4f.x, Tint4f.y, Tint4f.z, Tint4f.w);
CTexture *pTexA = GetLightTexture(Type);
CTexture *pTexB = GetLightMask(Type);
pTexA->Bind(0);
pTexB->Bind(1);
GLuint TextureLoc = mpLightBillboardShader->GetUniformLocation("Texture");
GLuint MaskLoc = mpLightBillboardShader->GetUniformLocation("LightMask");
glUniform1i(TextureLoc, 0);
glUniform1i(MaskLoc, 1);
// Set other properties
CMaterial::KillCachedMaterial();
glBlendFunc(GL_ONE, GL_ZERO);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
// Draw
DrawSquare();
}
void CDrawUtil::UseColorShader(const CColor& kColor)
{
Init();
mpColorShader->SetCurrent();
GLuint ColorLoc = mpColorShader->GetUniformLocation("ColorIn");
CVector4f ColorVec4 = kColor.ToVector4f();
glUniform4f(ColorLoc, ColorVec4.x, ColorVec4.y, ColorVec4.z, ColorVec4.w);
CMaterial::KillCachedMaterial();
}
void CDrawUtil::UseColorShaderLighting(const CColor& kColor)
{
Init();
mpColorShaderLighting->SetCurrent();
GLuint NumLightsLoc = mpColorShaderLighting->GetUniformLocation("NumLights");
glUniform1i(NumLightsLoc, CGraphics::sNumLights);
GLuint ColorLoc = mpColorShaderLighting->GetUniformLocation("ColorIn");
CVector4f ColorVec4 = kColor.ToVector4f();
glUniform4f(ColorLoc, ColorVec4.x, ColorVec4.y, ColorVec4.z, ColorVec4.w);
CMaterial::KillCachedMaterial();
}
void CDrawUtil::UseTextureShader()
{
UseTextureShader(CColor::skWhite);
}
void CDrawUtil::UseTextureShader(const CColor& TintColor)
{
Init();
mpTextureShader->SetCurrent();
GLuint TintColorLoc = mpTextureShader->GetUniformLocation("TintColor");
CVector4f TintVec4 = TintColor.ToVector4f();
glUniform4f(TintColorLoc, TintVec4.x, TintVec4.y, TintVec4.z, TintVec4.w);
CMaterial::KillCachedMaterial();
}
void CDrawUtil::UseCollisionShader(const CColor& TintColor /*= CColor::skWhite*/)
{
Init();
mpCollisionShader->SetCurrent();
LoadCheckerboardTexture(0);
GLuint TintColorLoc = mpCollisionShader->GetUniformLocation("TintColor");
CVector4f Tint4f = TintColor.ToVector4f();
glUniform4f(TintColorLoc, Tint4f.x, Tint4f.y, Tint4f.z, Tint4f.w);
CMaterial::KillCachedMaterial();
}
CShader* CDrawUtil::GetTextShader()
{
Init();
return mpTextShader;
}
void CDrawUtil::LoadCheckerboardTexture(u32 GLTextureUnit)
{
Init();
mpCheckerTexture->Bind(GLTextureUnit);
}
CTexture* CDrawUtil::GetLightTexture(ELightType Type)
{
Init();
return mpLightTextures[Type];
}
CTexture* CDrawUtil::GetLightMask(ELightType Type)
{
Init();
return mpLightMasks[Type];
}
CModel* CDrawUtil::GetCubeModel()
{
Init();
return mpCubeModel;
}
// ************ PRIVATE ************
CDrawUtil::CDrawUtil()
{
}
void CDrawUtil::Init()
{
if (!mDrawUtilInitialized)
{
Log::Write("Initializing CDrawUtil");
InitGrid();
InitSquare();
InitLine();
InitCube();
InitWireCube();
InitSphere();
InitWireSphere();
InitShaders();
InitTextures();
mDrawUtilInitialized = true;
}
}
void CDrawUtil::InitGrid()
{
Log::Write("Creating grid");
mGridVertices.SetVertexDesc(ePosition);
mGridVertices.Reserve(64);
for (s32 i = -7; i < 8; i++)
{
if (i == 0) continue;
mGridVertices.AddVertex(CVector3f(-7.0f, float(i), 0.0f));
mGridVertices.AddVertex(CVector3f( 7.0f, float(i), 0.0f));
mGridVertices.AddVertex(CVector3f(float(i), -7.0f, 0.0f));
mGridVertices.AddVertex(CVector3f(float(i), 7.0f, 0.0f));
}
mGridVertices.AddVertex(CVector3f(-7.0f, 0, 0.0f));
mGridVertices.AddVertex(CVector3f( 7.0f, 0, 0.0f));
mGridVertices.AddVertex(CVector3f(0, -7.0f, 0.0f));
mGridVertices.AddVertex(CVector3f(0, 7.0f, 0.0f));
mGridIndices.Reserve(60);
for (u16 i = 0; i < 60; i++) mGridIndices.AddIndex(i);
mGridIndices.SetPrimitiveType(GL_LINES);
}
void CDrawUtil::InitSquare()
{
Log::Write("Creating square");
mSquareVertices.SetActiveAttribs(ePosition | eNormal |
eTex0 | eTex1 | eTex2 | eTex3 |
eTex4 | eTex5 | eTex6 | eTex7);
mSquareVertices.SetVertexCount(4);
CVector3f SquareVertices[] = {
CVector3f(-1.f, 1.f, 0.f),
CVector3f( 1.f, 1.f, 0.f),
CVector3f( 1.f, -1.f, 0.f),
CVector3f(-1.f, -1.f, 0.f)
};
CVector3f SquareNormals[] = {
CVector3f(0.f, 0.f, 1.f),
CVector3f(0.f, 0.f, 1.f),
CVector3f(0.f, 0.f, 1.f),
CVector3f(0.f, 0.f, 1.f)
};
CVector2f SquareTexCoords[] = {
CVector2f(0.f, 1.f),
CVector2f(1.f, 1.f),
CVector2f(1.f, 0.f),
CVector2f(0.f, 0.f)
};
mSquareVertices.BufferAttrib(ePosition, SquareVertices);
mSquareVertices.BufferAttrib(eNormal, SquareNormals);
for (u32 iTex = 0; iTex < 8; iTex++)
{
EVertexDescription Attrib = (EVertexDescription) (eTex0 << (iTex *2));
mSquareVertices.BufferAttrib(Attrib, SquareTexCoords);
}
mSquareIndices.Reserve(4);
mSquareIndices.SetPrimitiveType(GL_TRIANGLE_STRIP);
mSquareIndices.AddIndex(3);
mSquareIndices.AddIndex(2);
mSquareIndices.AddIndex(0);
mSquareIndices.AddIndex(1);
}
void CDrawUtil::InitLine()
{
Log::Write("Creating line");
mLineVertices.SetActiveAttribs(ePosition);
mLineVertices.SetVertexCount(2);
mLineIndices.Reserve(2);
mLineIndices.SetPrimitiveType(GL_LINES);
mLineIndices.AddIndex(0);
mLineIndices.AddIndex(1);
}
void CDrawUtil::InitCube()
{
Log::Write("Creating cube");
mpCubeModel = gResCache.GetResource("../resources/Cube.cmdl");
}
void CDrawUtil::InitWireCube()
{
Log::Write("Creating wire cube");
mWireCubeVertices.SetVertexDesc(ePosition);
mWireCubeVertices.Reserve(8);
mWireCubeVertices.AddVertex(CVector3f(-0.5f, -0.5f, -0.5f));
mWireCubeVertices.AddVertex(CVector3f(-0.5f, 0.5f, -0.5f));
mWireCubeVertices.AddVertex(CVector3f( 0.5f, 0.5f, -0.5f));
mWireCubeVertices.AddVertex(CVector3f( 0.5f, -0.5f, -0.5f));
mWireCubeVertices.AddVertex(CVector3f(-0.5f, -0.5f, 0.5f));
mWireCubeVertices.AddVertex(CVector3f( 0.5f, -0.5f, 0.5f));
mWireCubeVertices.AddVertex(CVector3f( 0.5f, 0.5f, 0.5f));
mWireCubeVertices.AddVertex(CVector3f(-0.5f, 0.5f, 0.5f));
u16 Indices[] = {
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 7,
2, 6,
3, 5
};
mWireCubeIndices.AddIndices(Indices, sizeof(Indices) / sizeof(u16));
mWireCubeIndices.SetPrimitiveType(GL_LINES);
}
void CDrawUtil::InitSphere()
{
Log::Write("Creating sphere");
mpSphereModel = gResCache.GetResource("../resources/Sphere.cmdl");
mpDoubleSidedSphereModel = gResCache.GetResource("../resources/SphereDoubleSided.cmdl");
}
void CDrawUtil::InitWireSphere()
{
Log::Write("Creating wire sphere");
mpWireSphereModel = gResCache.GetResource("../resources/WireSphere.cmdl");
}
void CDrawUtil::InitShaders()
{
Log::Write("Creating shaders");
mpColorShader = CShader::FromResourceFile("ColorShader");
mpColorShaderLighting = CShader::FromResourceFile("ColorShaderLighting");
mpBillboardShader = CShader::FromResourceFile("BillboardShader");
mpLightBillboardShader = CShader::FromResourceFile("LightBillboardShader");
mpTextureShader = CShader::FromResourceFile("TextureShader");
mpCollisionShader = CShader::FromResourceFile("CollisionShader");
mpTextShader = CShader::FromResourceFile("TextShader");
}
void CDrawUtil::InitTextures()
{
Log::Write("Loading textures");
mpCheckerTexture = gResCache.GetResource("../resources/Checkerboard.txtr");
mpLightTextures[0] = gResCache.GetResource("../resources/LightAmbient.txtr");
mpLightTextures[1] = gResCache.GetResource("../resources/LightDirectional.txtr");
mpLightTextures[2] = gResCache.GetResource("../resources/LightCustom.txtr");
mpLightTextures[3] = gResCache.GetResource("../resources/LightSpot.txtr");
mpLightMasks[0] = gResCache.GetResource("../resources/LightAmbientMask.txtr");
mpLightMasks[1] = gResCache.GetResource("../resources/LightDirectionalMask.txtr");
mpLightMasks[2] = gResCache.GetResource("../resources/LightCustomMask.txtr");
mpLightMasks[3] = gResCache.GetResource("../resources/LightSpotMask.txtr");
}
void CDrawUtil::Shutdown()
{
if (mDrawUtilInitialized)
{
Log::Write("Shutting down");
delete mpColorShader;
delete mpColorShaderLighting;
delete mpTextureShader;
delete mpCollisionShader;
delete mpTextShader;
mDrawUtilInitialized = false;
}
}

118
src/Core/Render/CDrawUtil.h Normal file
View File

@@ -0,0 +1,118 @@
#ifndef CDRAWUTIL
#define CDRAWUTIL
#include <OpenGL/CVertexBuffer.h>
#include <OpenGL/CDynamicVertexBuffer.h>
#include <OpenGL/CIndexBuffer.h>
#include <Resource/model/CModel.h>
#include <Resource/CLight.h>
// todo: CDrawUtil should work with CRenderer to queue primitives for rendering
// rather than trying to draw them straight away, so that CDrawUtil functions can
// be called from anywhere in the codebase and still function correctly
class CDrawUtil
{
// 7x7 Grid
static CVertexBuffer mGridVertices;
static CIndexBuffer mGridIndices;
// Square
static CDynamicVertexBuffer mSquareVertices;
static CIndexBuffer mSquareIndices;
// Line
static CDynamicVertexBuffer mLineVertices;
static CIndexBuffer mLineIndices;
// Cube
static TResPtr<CModel> mpCubeModel;
// Wire Cube
static CVertexBuffer mWireCubeVertices;
static CIndexBuffer mWireCubeIndices;
// Sphere
static TResPtr<CModel> mpSphereModel;
static TResPtr<CModel> mpDoubleSidedSphereModel;
// Wire Sphere
static TResPtr<CModel> mpWireSphereModel;
// Shaders
static CShader *mpColorShader;
static CShader *mpColorShaderLighting;
static CShader *mpBillboardShader;
static CShader *mpLightBillboardShader;
static CShader *mpTextureShader;
static CShader *mpCollisionShader;
static CShader *mpTextShader;
// Textures
static TResPtr<CTexture> mpCheckerTexture;
static TResPtr<CTexture> mpLightTextures[4];
static TResPtr<CTexture> mpLightMasks[4];
// Have all the above members been initialized?
static bool mDrawUtilInitialized;
public:
static void DrawGrid();
static void DrawSquare();
static void DrawSquare(const CVector2f& TexUL, const CVector2f& TexUR, const CVector2f& TexBR, const CVector2f& TexBL);
static void DrawSquare(const float *pTexCoords);
static void DrawLine(const CVector3f& PointA, const CVector3f& PointB);
static void DrawLine(const CVector2f& PointA, const CVector2f& PointB);
static void DrawLine(const CVector3f& PointA, const CVector3f& PointB, const CColor& LineColor);
static void DrawLine(const CVector2f& PointA, const CVector2f& PointB, const CColor& LineColor);
static void DrawCube();
static void DrawCube(const CColor& Color);
static void DrawCube(const CVector3f& Position, const CColor& Color);
static void DrawShadedCube(const CColor& Color);
static void DrawWireCube();
static void DrawWireCube(const CAABox& AABox, const CColor& Color);
static void DrawSphere(bool DoubleSided = false);
static void DrawSphere(const CColor& Color);
static void DrawWireSphere(const CVector3f& Position, float Radius, const CColor& Color = CColor::skWhite);
static void DrawBillboard(CTexture* pTexture, const CVector3f& Position, const CVector2f& Scale = CVector2f::skOne, const CColor& Tint = CColor::skWhite);
static void DrawLightBillboard(ELightType Type, const CColor& LightColor, const CVector3f& Position, const CVector2f& Scale = CVector2f::skOne, const CColor& Tint = CColor::skWhite);
static void UseColorShader(const CColor& Color);
static void UseColorShaderLighting(const CColor& Color);
static void UseTextureShader();
static void UseTextureShader(const CColor& TintColor);
static void UseCollisionShader(const CColor& TintColor = CColor::skWhite);
static CShader* GetTextShader();
static void LoadCheckerboardTexture(u32 GLTextureUnit);
static CTexture* GetLightTexture(ELightType Type);
static CTexture* GetLightMask(ELightType Type);
static CModel* GetCubeModel();
private:
CDrawUtil(); // Private constructor to prevent class from being instantiated
static void Init();
static void InitGrid();
static void InitSquare();
static void InitLine();
static void InitCube();
static void InitWireCube();
static void InitSphere();
static void InitWireSphere();
static void InitShaders();
static void InitTextures();
public:
static void Shutdown();
};
#endif // CDRAWUTIL

View File

@@ -0,0 +1,178 @@
#include "CGraphics.h"
#include <OpenGL/CShader.h>
#include <Resource/CMaterial.h>
#include "Log.h"
// ************ MEMBER INITIALIZATION ************
CUniformBuffer* CGraphics::mpMVPBlockBuffer;
CUniformBuffer* CGraphics::mpVertexBlockBuffer;
CUniformBuffer* CGraphics::mpPixelBlockBuffer;
CUniformBuffer* CGraphics::mpLightBlockBuffer;
u32 CGraphics::mContextIndices = 0;
u32 CGraphics::mActiveContext = -1;
bool CGraphics::mInitialized = false;
std::vector<CVertexArrayManager*> CGraphics::mVAMs;
CGraphics::SMVPBlock CGraphics::sMVPBlock;
CGraphics::SVertexBlock CGraphics::sVertexBlock;
CGraphics::SPixelBlock CGraphics::sPixelBlock;
CGraphics::SLightBlock CGraphics::sLightBlock;
CGraphics::ELightingMode CGraphics::sLightMode;
u32 CGraphics::sNumLights;
const CColor CGraphics::skDefaultAmbientColor = CColor(0.5f, 0.5f, 0.5f, 1.f);
CColor CGraphics::sAreaAmbientColor = CColor::skBlack;
float CGraphics::sWorldLightMultiplier;
CLight CGraphics::sDefaultDirectionalLights[3] = {
*CLight::BuildDirectional(CVector3f(0), CVector3f (0.f, -0.866025f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 1.f)),
*CLight::BuildDirectional(CVector3f(0), CVector3f(-0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 1.f)),
*CLight::BuildDirectional(CVector3f(0), CVector3f( 0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 1.f))
};
// ************ FUNCTIONS ************
void CGraphics::Initialize()
{
if (!mInitialized)
{
Log::Write("Initializing GLEW");
glewExperimental = true;
glewInit();
glGetError(); // This is to work around a glew bug - error is always set after initializing
Log::Write("Creating uniform buffers");
mpMVPBlockBuffer = new CUniformBuffer(sizeof(sMVPBlock));
mpVertexBlockBuffer = new CUniformBuffer(sizeof(sVertexBlock));
mpPixelBlockBuffer = new CUniformBuffer(sizeof(sPixelBlock));
mpLightBlockBuffer = new CUniformBuffer(sizeof(sLightBlock));
sLightMode = eWorldLighting;
sNumLights = 0;
sWorldLightMultiplier = 1.f;
mInitialized = true;
}
mpMVPBlockBuffer->BindBase(0);
mpVertexBlockBuffer->BindBase(1);
mpPixelBlockBuffer->BindBase(2);
mpLightBlockBuffer->BindBase(3);
}
void CGraphics::Shutdown()
{
if (mInitialized)
{
Log::Write("Shutting down CGraphics");
delete mpMVPBlockBuffer;
delete mpVertexBlockBuffer;
delete mpPixelBlockBuffer;
delete mpLightBlockBuffer;
mInitialized = false;
}
}
void CGraphics::UpdateMVPBlock()
{
mpMVPBlockBuffer->Buffer(&sMVPBlock);
}
void CGraphics::UpdateVertexBlock()
{
mpVertexBlockBuffer->Buffer(&sVertexBlock);
}
void CGraphics::UpdatePixelBlock()
{
mpPixelBlockBuffer->Buffer(&sPixelBlock);
}
void CGraphics::UpdateLightBlock()
{
mpLightBlockBuffer->Buffer(&sLightBlock);
}
GLuint CGraphics::MVPBlockBindingPoint()
{
return 0;
}
GLuint CGraphics::VertexBlockBindingPoint()
{
return 1;
}
GLuint CGraphics::PixelBlockBindingPoint()
{
return 2;
}
GLuint CGraphics::LightBlockBindingPoint()
{
return 3;
}
u32 CGraphics::GetContextIndex()
{
for (u32 iCon = 0; iCon < 32; iCon++)
{
u32 Mask = (1 << iCon);
if ((mContextIndices & Mask) == 0)
{
mContextIndices |= Mask;
CVertexArrayManager *pVAM = new CVertexArrayManager;
if (mVAMs.size() >= iCon) mVAMs.resize(iCon + 1);
mVAMs[iCon] = pVAM;
return iCon;
}
}
return -1;
}
u32 CGraphics::GetActiveContext()
{
return mActiveContext;
}
void CGraphics::ReleaseContext(u32 Index)
{
if (Index < 32) mContextIndices &= ~(1 << Index);
if (mActiveContext == Index) mActiveContext = -1;
delete mVAMs[Index];
}
void CGraphics::SetActiveContext(u32 Index)
{
mActiveContext = Index;
mVAMs[Index]->SetCurrent();
CMaterial::KillCachedMaterial();
CShader::KillCachedShader();
}
void CGraphics::SetDefaultLighting()
{
sNumLights = 0; // CLight load function increments the light count by 1, which is why I set it to 0
sDefaultDirectionalLights[0].Load();
sDefaultDirectionalLights[1].Load();
sDefaultDirectionalLights[2].Load();
UpdateLightBlock();
sVertexBlock.COLOR0_Amb = CColor::skGray.ToVector4f();
UpdateVertexBlock();
}
void CGraphics::SetupAmbientColor()
{
if (sLightMode == eWorldLighting)
sVertexBlock.COLOR0_Amb = sAreaAmbientColor.ToVector4f() * sWorldLightMultiplier;
else
sVertexBlock.COLOR0_Amb = skDefaultAmbientColor.ToVector4f();
}
void CGraphics::SetIdentityMVP()
{
sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
sMVPBlock.ViewMatrix = CMatrix4f::skIdentity;
sMVPBlock.ProjectionMatrix = CMatrix4f::skIdentity;
}

View File

@@ -0,0 +1,99 @@
#ifndef CGRAPHICS_H
#define CGRAPHICS_H
#include <Common/CColor.h>
#include <Common/CMatrix4f.h>
#include <Common/CVector3f.h>
#include <Common/CVector4f.h>
#include <GL/glew.h>
#include <OpenGL/CUniformBuffer.h>
#include <OpenGL/CVertexArrayManager.h>
#include <Resource/CLight.h>
class CGraphics
{
static CUniformBuffer *mpMVPBlockBuffer;
static CUniformBuffer *mpVertexBlockBuffer;
static CUniformBuffer *mpPixelBlockBuffer;
static CUniformBuffer *mpLightBlockBuffer;
static u32 mContextIndices;
static u32 mActiveContext;
static bool mInitialized;
static std::vector<CVertexArrayManager*> mVAMs;
public:
// SMVPBlock
struct SMVPBlock
{
CMatrix4f ModelMatrix;
CMatrix4f ViewMatrix;
CMatrix4f ProjectionMatrix;
};
static SMVPBlock sMVPBlock;
// SVertexBlock
struct SVertexBlock
{
CMatrix4f TexMatrices[10];
CMatrix4f PostMatrices[20];
CVector4f COLOR0_Amb;
CVector4f COLOR0_Mat;
CVector4f COLOR1_Amb;
CVector4f COLOR1_Mat;
};
static SVertexBlock sVertexBlock;
// SPixelBlock
struct SPixelBlock
{
CVector4f Konst[4];
CVector4f TevColor;
CVector4f TintColor;
};
static SPixelBlock sPixelBlock;
// SLightBlock
struct SLightBlock
{
struct SGXLight
{
CVector4f Position;
CVector4f Direction;
CVector4f Color;
CVector4f DistAtten;
CVector4f AngleAtten;
};
SGXLight Lights[8];
};
static SLightBlock sLightBlock;
// Lighting-related
enum ELightingMode { eNoLighting, eBasicLighting, eWorldLighting };
static ELightingMode sLightMode;
static u32 sNumLights;
static const CColor skDefaultAmbientColor;
static CColor sAreaAmbientColor;
static float sWorldLightMultiplier;
static CLight sDefaultDirectionalLights[3];
// Functions
static void Initialize();
static void Shutdown();
static void UpdateMVPBlock();
static void UpdateVertexBlock();
static void UpdatePixelBlock();
static void UpdateLightBlock();
static GLuint MVPBlockBindingPoint();
static GLuint VertexBlockBindingPoint();
static GLuint PixelBlockBindingPoint();
static GLuint LightBlockBindingPoint();
static u32 GetContextIndex();
static u32 GetActiveContext();
static void ReleaseContext(u32 Index);
static void SetActiveContext(u32 Index);
static void SetDefaultLighting();
static void SetupAmbientColor();
static void SetIdentityMVP();
};
#endif // CGRAPHICS_H

View File

@@ -0,0 +1,89 @@
#include "CRenderBucket.h"
#include <algorithm>
#include "CDrawUtil.h"
#include "CGraphics.h"
#include "CRenderer.h"
CRenderBucket::CRenderBucket()
{
mEstSize = 0;
mSize = 0;
}
void CRenderBucket::SetSortType(ESortType Type)
{
mSortType = Type;
}
void CRenderBucket::Add(const SRenderablePtr& ptr)
{
if (mSize >= mEstSize)
mRenderables.push_back(ptr);
else
mRenderables[mSize] = ptr;
mSize++;
}
void CRenderBucket::Sort(CCamera* pCamera)
{
struct {
CCamera *pCamera;
bool operator()(SRenderablePtr left, SRenderablePtr right) {
CVector3f cPos = pCamera->Position();
CVector3f cDir = pCamera->Direction();
CVector3f distL = left.AABox.ClosestPointAlongVector(cDir) - cPos;
float dotL = distL.Dot(cDir);
CVector3f distR = right.AABox.ClosestPointAlongVector(cDir) - cPos;
float dotR = distR.Dot(cDir);
return (dotL > dotR);
}
} backToFront;
backToFront.pCamera = pCamera;
if (mSortType == BackToFront)
std::stable_sort(mRenderables.begin(), mRenderables.begin() + mSize, backToFront);
// Test: draw node bounding boxes + vertices used for sorting
/*for (u32 iNode = 0; iNode < mNodes.size(); iNode++)
{
SMeshPointer *pNode = &mNodes[iNode];
CVector3f Vert = pNode->AABox.ClosestPointAlongVector(Camera.GetDirection());
CDrawUtil::DrawWireCube(pNode->AABox, CColor::skWhite);
CVector3f Dist = Vert - Camera.GetPosition();
float Dot = Dist.Dot(Camera.GetDirection());
if (Dot < 0.f) Dot = -Dot;
if (Dot > 50.f) Dot = 50.f;
float Intensity = 1.f - (Dot / 50.f);
CColor CubeColor(Intensity, Intensity, Intensity, 1.f);
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Vert).ToMatrix4f();
CGraphics::UpdateMVPBlock();
CDrawUtil::DrawCube(CubeColor);
}*/
}
void CRenderBucket::Clear()
{
mEstSize = mSize;
if (mRenderables.size() > mSize) mRenderables.resize(mSize);
mSize = 0;
}
void CRenderBucket::Draw(const SViewInfo& ViewInfo)
{
ERenderOptions Options = ViewInfo.pRenderer->RenderOptions();
for (u32 n = 0; n < mSize; n++)
{
if (mRenderables[n].Command == eDrawMesh)
mRenderables[n].pRenderable->Draw(Options, mRenderables[n].ComponentIndex, ViewInfo);
else if (mRenderables[n].Command == eDrawSelection)
mRenderables[n].pRenderable->DrawSelection();
// todo: implementation for eDrawExtras
}
}

View File

@@ -0,0 +1,33 @@
#ifndef CRENDERBUCKET_H
#define CRENDERBUCKET_H
#include "CCamera.h"
#include "ERenderOptions.h"
#include "SRenderablePtr.h"
#include <Common/types.h>
#include <vector>
class CRenderBucket
{
public:
enum ESortType
{
BackToFront,
FrontToBack
};
private:
ESortType mSortType;
std::vector<SRenderablePtr> mRenderables;
u32 mEstSize;
u32 mSize;
public:
CRenderBucket();
void SetSortType(ESortType Type);
void Add(const SRenderablePtr& ptr);
void Sort(CCamera* pCamera);
void Clear();
void Draw(const SViewInfo& ViewInfo);
};
#endif // CRENDERBUCKET_H

View File

@@ -0,0 +1,388 @@
#include "CRenderer.h"
#include "CDrawUtil.h"
#include "CGraphics.h"
#include "CResCache.h"
#include <Common/AnimUtil.h>
#include <Common/CTransform4f.h>
#include <Resource/factory/CTextureDecoder.h>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <gtx/transform.hpp>
// ************ STATIC MEMBER INITIALIZATION ************
u32 CRenderer::sNumRenderers = 0;
// ************ INITIALIZATION ************
CRenderer::CRenderer()
{
mOptions = eDrawWorld | eDrawObjects | eDrawLights | eDrawSky |
eEnableUVScroll | eEnableBackfaceCull;
mBloomMode = eNoBloom;
mDrawGrid = true;
mInitialized = false;
mContextIndex = -1;
mOpaqueBucket.SetSortType(CRenderBucket::FrontToBack);
mTransparentBucket.SetSortType(CRenderBucket::BackToFront);
sNumRenderers++;
}
CRenderer::~CRenderer()
{
sNumRenderers--;
if (sNumRenderers == 0)
{
CGraphics::Shutdown();
CDrawUtil::Shutdown();
}
}
void CRenderer::Init()
{
if (!mInitialized)
{
CVector4f ClearVec = mClearColor.ToVector4f();
glClearColor(ClearVec.x, ClearVec.y, ClearVec.z, ClearVec.w);
mContextIndex = CGraphics::GetContextIndex();
mInitialized = true;
}
}
// ************ GETTERS/SETTERS ************
ERenderOptions CRenderer::RenderOptions() const
{
return mOptions;
}
void CRenderer::ToggleWorld(bool b)
{
if (b) mOptions |= eDrawWorld;
else mOptions &= ~eDrawWorld;
}
void CRenderer::ToggleWorldCollision(bool b)
{
if (b) mOptions |= eDrawWorldCollision;
else mOptions &= ~eDrawWorldCollision;
}
void CRenderer::ToggleObjects(bool b)
{
if (b) mOptions |= eDrawObjects;
else mOptions &= ~eDrawObjects;
}
void CRenderer::ToggleObjectCollision(bool b)
{
if (b) mOptions |= eDrawObjectCollision;
else mOptions &= ~eDrawObjectCollision;
}
void CRenderer::ToggleLights(bool b)
{
if (b) mOptions |= eDrawLights;
else mOptions &= ~eDrawLights;
}
void CRenderer::ToggleSky(bool b)
{
if (b) mOptions |= eDrawSky;
else mOptions &= ~eDrawSky;
}
void CRenderer::ToggleBackfaceCull(bool b)
{
if (b) mOptions |= eEnableBackfaceCull;
else mOptions &= ~eEnableBackfaceCull;
}
void CRenderer::ToggleUVAnimation(bool b)
{
if (b) mOptions |= eEnableUVScroll;
else mOptions &= ~eEnableUVScroll;
}
void CRenderer::ToggleGrid(bool b)
{
mDrawGrid = b;
}
void CRenderer::ToggleOccluders(bool b)
{
if (b) mOptions |= eEnableOccluders;
else mOptions &= ~eEnableOccluders;
}
void CRenderer::ToggleAlphaDisabled(bool b)
{
if (b) mOptions |= eNoAlpha;
else mOptions &= ~eNoAlpha;
}
void CRenderer::SetBloom(EBloomMode BloomMode)
{
mBloomMode = BloomMode;
if (BloomMode != eNoBloom)
mOptions |= eEnableBloom;
else
mOptions &= ~eEnableBloom;
}
void CRenderer::SetFont(CFont* /*pFont*/)
{
}
void CRenderer::SetClearColor(CColor Clear)
{
mClearColor = Clear;
CVector4f ClearVec = Clear.ToVector4f();
ClearVec.w = 0.f;
glClearColor(ClearVec.x, ClearVec.y, ClearVec.z, ClearVec.w);
}
void CRenderer::SetViewportSize(u32 Width, u32 Height)
{
mViewportWidth = Width;
mViewportHeight = Height;
mBloomHScale = ((float) Width / 640);
mBloomVScale = ((float) Height / 528);
mBloomWidth = (u32) (320 * mBloomHScale);
mBloomHeight = (u32) (224 * mBloomVScale);
mBloomHScale = 1.f / mBloomHScale;
mBloomVScale = 1.f / mBloomVScale;
}
// ************ RENDER ************
void CRenderer::RenderBuckets(const SViewInfo& ViewInfo)
{
if (!mInitialized) Init();
mSceneFramebuffer.Bind();
// Set backface culling
if (mOptions & eEnableBackfaceCull) glEnable(GL_CULL_FACE);
else glDisable(GL_CULL_FACE);
// Render scene to texture
glDepthRange(0.f, 1.f);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
mOpaqueBucket.Draw(ViewInfo);
mOpaqueBucket.Clear();
mTransparentBucket.Sort(ViewInfo.pCamera);
mTransparentBucket.Draw(ViewInfo);
mTransparentBucket.Clear();
}
void CRenderer::RenderBloom()
{
// Check to ensure bloom is enabled
if (mBloomMode == eNoBloom) return;
// Setup
static const float skHOffset[6] = { -0.008595f, -0.005470f, -0.002345f,
0.002345f, 0.005470f, 0.008595f };
static const float skVOffset[6] = { -0.012275f, -0.007815f, -0.003350f,
0.003350f, 0.007815f, 0.012275f };
static const CColor skTintColors[6] = { CColor((u8) 17, 17, 17, 255),
CColor((u8) 53, 53, 53, 255),
CColor((u8) 89, 89, 89, 255),
CColor((u8) 89, 89, 89, 255),
CColor((u8) 53, 53, 53, 255),
CColor((u8) 17, 17, 17, 255) };
u32 BloomWidth = (mBloomMode == eBloom ? mBloomWidth : mViewportWidth);
u32 BloomHeight = (mBloomMode == eBloom ? mBloomHeight : mViewportHeight);
float BloomHScale = (mBloomMode == eBloom ? mBloomHScale : 0);
float BloomVScale = (mBloomMode == eBloom ? mBloomVScale : 0);
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, BloomWidth, BloomHeight);
glClearColor(0.f, 0.f, 0.f, 0.f);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_FALSE);
CGraphics::SetIdentityMVP();
CGraphics::UpdateMVPBlock();
// Pass 1: Alpha-blend the scene texture on a black background
mBloomFramebuffers[0].Resize(BloomWidth, BloomHeight);
mBloomFramebuffers[0].Bind();
glClear(GL_COLOR_BUFFER_BIT);
CDrawUtil::UseTextureShader();
glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
mSceneFramebuffer.Texture()->Bind(0);
CDrawUtil::DrawSquare();
// Pass 2: Horizontal blur
mBloomFramebuffers[1].Resize(BloomWidth, BloomHeight);
mBloomFramebuffers[1].Bind();
CDrawUtil::UseTextureShader(CColor::skGray);
glBlendFunc(GL_ONE, GL_ZERO);
mBloomFramebuffers[0].Texture()->Bind(0);
CDrawUtil::DrawSquare();
for (u32 iPass = 0; iPass < 6; iPass++)
{
CDrawUtil::UseTextureShader(skTintColors[iPass]);
CVector3f Translate(skHOffset[iPass] * BloomHScale, 0.f, 0.f);
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate).ToMatrix4f();
CGraphics::UpdateMVPBlock();
glBlendFunc(GL_ONE, GL_ONE);
CDrawUtil::DrawSquare();
}
// Pass 3: Vertical blur
mBloomFramebuffers[2].Resize(BloomWidth, BloomHeight);
mBloomFramebuffers[2].Bind();
glClear(GL_COLOR_BUFFER_BIT);
CDrawUtil::UseTextureShader(CColor::skGray);
glBlendFunc(GL_ONE, GL_ZERO);
mBloomFramebuffers[1].Texture()->Bind(0);
CDrawUtil::DrawSquare();
for (u32 iPass = 0; iPass < 6; iPass++)
{
CDrawUtil::UseTextureShader(skTintColors[iPass]);
CVector3f Translate(0.f, skVOffset[iPass] * BloomVScale, 0.f);
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate).ToMatrix4f();
CGraphics::UpdateMVPBlock();
glBlendFunc(GL_ONE, GL_ONE);
CDrawUtil::DrawSquare();
}
// Render result onto main scene framebuffer
mSceneFramebuffer.Bind();
glViewport(0, 0, mViewportWidth, mViewportHeight);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
CGraphics::SetIdentityMVP();
CGraphics::UpdateMVPBlock();
CDrawUtil::UseTextureShader();
glBlendFunc(GL_ONE, GL_ONE);
mBloomFramebuffers[2].Texture()->Bind(0);
CDrawUtil::DrawSquare();
if (mBloomMode == eBloomMaps)
{
// Bloom maps are in the framebuffer alpha channel.
// White * dst alpha = bloom map colors
CDrawUtil::UseColorShader(CColor::skWhite);
glBlendFunc(GL_DST_ALPHA, GL_ZERO);
CDrawUtil::DrawSquare();
}
// Clean up
glEnable(GL_DEPTH_TEST);
}
void CRenderer::RenderSky(CModel *pSkyboxModel, const SViewInfo& ViewInfo)
{
if (!mInitialized) Init();
if (!pSkyboxModel) return;
glEnable(GL_CULL_FACE);
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
CGraphics::sVertexBlock.COLOR0_Amb = CVector4f(1.f, 1.f, 1.f, 1.f);
CGraphics::sPixelBlock.TevColor = CVector4f(1.f, 1.f, 1.f, 1.f);
CGraphics::sPixelBlock.TintColor = CColor::skWhite.ToVector4f();
CGraphics::sNumLights = 0;
CGraphics::UpdateVertexBlock();
CGraphics::UpdatePixelBlock();
CGraphics::UpdateLightBlock();
// Load rotation-only view matrix
CGraphics::sMVPBlock.ViewMatrix = ViewInfo.RotationOnlyViewMatrix;
CGraphics::UpdateMVPBlock();
glDepthRange(1.f, 1.f);
pSkyboxModel->Draw(mOptions, 0);
}
void CRenderer::AddOpaqueMesh(IRenderable *pRenderable, int AssetID, CAABox& AABox, ERenderCommand Command)
{
SRenderablePtr ptr;
ptr.pRenderable = pRenderable;
ptr.ComponentIndex = AssetID;
ptr.AABox = AABox;
ptr.Command = Command;
mOpaqueBucket.Add(ptr);
}
void CRenderer::AddTransparentMesh(IRenderable *pRenderable, int AssetID, CAABox& AABox, ERenderCommand Command)
{
SRenderablePtr ptr;
ptr.pRenderable = pRenderable;
ptr.ComponentIndex = AssetID;
ptr.AABox = AABox;
ptr.Command = Command;
mTransparentBucket.Add(ptr);
}
void CRenderer::BeginFrame()
{
if (!mInitialized) Init();
CGraphics::SetActiveContext(mContextIndex);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mDefaultFramebuffer);
mSceneFramebuffer.Resize(mViewportWidth, mViewportHeight);
mSceneFramebuffer.Bind();
glViewport(0, 0, mViewportWidth, mViewportHeight);
InitFramebuffer();
}
void CRenderer::EndFrame()
{
// Render result to screen
glBindFramebuffer(GL_FRAMEBUFFER, mDefaultFramebuffer);
InitFramebuffer();
glViewport(0, 0, mViewportWidth, mViewportHeight);
CGraphics::SetIdentityMVP();
CGraphics::UpdateMVPBlock();
glDisable(GL_DEPTH_TEST);
CDrawUtil::UseTextureShader();
glBlendFunc(GL_ONE, GL_ZERO);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
mSceneFramebuffer.Texture()->Bind(0);
CDrawUtil::DrawSquare();
glEnable(GL_DEPTH_TEST);
gDrawCount = 0;
}
void CRenderer::ClearDepthBuffer()
{
glDepthMask(GL_TRUE);
glClear(GL_DEPTH_BUFFER_BIT);
}
// ************ PRIVATE ************
void CRenderer::InitFramebuffer()
{
CVector4f Clear = mClearColor.ToVector4f();
Clear.w = 0.f;
glClearColor(Clear.x, Clear.y, Clear.z, Clear.w);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
u32 gDrawCount;

View File

@@ -0,0 +1,91 @@
#ifndef CRENDERER_H
#define CRENDERER_H
#include <gl/glew.h>
#include "CCamera.h"
#include "CGraphics.h"
#include "CRenderBucket.h"
#include "ERenderOptions.h"
#include "ERenderCommand.h"
#include "SRenderablePtr.h"
#include "SViewInfo.h"
#include <Common/CAABox.h>
#include <Common/CColor.h>
#include <Common/CMatrix4f.h>
#include <Common/types.h>
#include <OpenGL/CFramebuffer.h>
#include <Resource/CFont.h>
#include <Resource/CLight.h>
#include <Resource/CTexture.h>
#include <Scene/CSceneNode.h>
class CRenderer
{
public:
enum EBloomMode {
eNoBloom, eBloom, eBloomMaps, eFakeBloom
};
private:
ERenderOptions mOptions;
EBloomMode mBloomMode;
bool mDrawGrid;
CColor mClearColor;
u32 mContextIndex;
CRenderBucket mOpaqueBucket;
CRenderBucket mTransparentBucket;
bool mInitialized;
u32 mViewportWidth, mViewportHeight;
u32 mBloomWidth, mBloomHeight;
float mBloomHScale, mBloomVScale;
CFramebuffer mSceneFramebuffer;
CFramebuffer mBloomFramebuffers[3];
GLint mDefaultFramebuffer;
// Static Members
static u32 sNumRenderers;
public:
// Initialization
CRenderer();
~CRenderer();
void Init();
// Getters/Setters
ERenderOptions RenderOptions() const;
void ToggleWorld(bool b);
void ToggleWorldCollision(bool b);
void ToggleObjects(bool b);
void ToggleObjectCollision(bool b);
void ToggleLights(bool b);
void ToggleSky(bool b);
void ToggleBackfaceCull(bool b);
void ToggleUVAnimation(bool b);
void ToggleGrid(bool b);
void ToggleOccluders(bool b);
void ToggleAlphaDisabled(bool b);
void SetBloom(EBloomMode BloomMode);
void SetFont(CFont *pFont);
void SetClearColor(CColor Clear);
void SetViewportSize(u32 Width, u32 Height);
// Render
void RenderBuckets(const SViewInfo& ViewInfo);
void RenderBloom();
void RenderSky(CModel *pSkyboxModel, const SViewInfo& ViewInfo);
void AddOpaqueMesh(IRenderable *pRenderable, int AssetID, CAABox& AABox, ERenderCommand Command);
void AddTransparentMesh(IRenderable *pRenderable, int AssetID, CAABox& AABox, ERenderCommand Command);
void BeginFrame();
void EndFrame();
void ClearDepthBuffer();
// Private
private:
void InitFramebuffer();
};
extern u32 gDrawCount;
#endif // RENDERMANAGER_H

View File

@@ -0,0 +1,11 @@
#ifndef ERENDERCOMMAND
#define ERENDERCOMMAND
enum ERenderCommand
{
eDrawMesh,
eDrawSelection
};
#endif // ERENDERCOMMAND

View File

@@ -0,0 +1,25 @@
#ifndef ERENDEROPTIONS
#define ERENDEROPTIONS
#include <Common/EnumUtil.h>
enum ERenderOptions
{
eNoRenderOptions = 0x0,
eDrawWorld = 0x1,
eDrawWorldCollision = 0x2,
eDrawObjects = 0x4,
eDrawObjectCollision = 0x8,
eDrawLights = 0x10,
eDrawSky = 0x20,
eEnableUVScroll = 0x40,
eEnableBackfaceCull = 0x80,
eEnableOccluders = 0x100,
eNoMaterialSetup = 0x200,
eEnableBloom = 0x400,
eNoAlpha = 0x800
};
DEFINE_ENUM_FLAGS(ERenderOptions)
#endif // ERENDEROPTIONS

View File

@@ -0,0 +1,20 @@
#ifndef IRENDERABLE_H
#define IRENDERABLE_H
#include "ERenderOptions.h"
#include "SViewInfo.h"
#include <Common/types.h>
class CRenderer;
class IRenderable
{
public:
IRenderable() {}
virtual ~IRenderable() {}
virtual void AddToRenderer(CRenderer* pRenderer, const SViewInfo& ViewInfo) = 0;
virtual void Draw(ERenderOptions /*Options*/, int /*ComponentIndex*/, const SViewInfo& /*ViewInfo*/) {}
virtual void DrawSelection() {}
};
#endif // IRENDERABLE_H

View File

@@ -0,0 +1,18 @@
#ifndef SRENDERABLEPTR_H
#define SRENDERABLEPTR_H
#include <Common/CAABox.h>
#include <Common/types.h>
#include <Core/ERenderCommand.h>
#include <Scene/CSceneNode.h>
#include <Resource/CMaterial.h>
struct SRenderablePtr
{
IRenderable *pRenderable;
u32 ComponentIndex;
CAABox AABox;
ERenderCommand Command;
};
#endif // SRENDERABLEPTR_H

View File

@@ -0,0 +1,20 @@
#ifndef SVIEWINFO
#define SVIEWINFO
#include "CFrustumPlanes.h"
#include <Common/CMatrix4f.h>
#include <Common/CRay.h>
struct SViewInfo
{
class CSceneManager *pScene;
class CRenderer *pRenderer;
class CCamera *pCamera;
bool GameMode;
CFrustumPlanes ViewFrustum;
CMatrix4f RotationOnlyViewMatrix;
};
#endif // SVIEWINFO

View File

@@ -0,0 +1,31 @@
#include "CAnimSet.h"
#include <Core/CResCache.h>
CAnimSet::CAnimSet() : CResource()
{
}
CAnimSet::~CAnimSet()
{
}
u32 CAnimSet::getNodeCount()
{
return nodes.size();
}
TString CAnimSet::getNodeName(u32 node)
{
if (node >= nodes.size())
return nodes[0].name;
else
return nodes[node].name;
}
CModel* CAnimSet::getNodeModel(u32 node)
{
if (node >= nodes.size())
return nodes[0].model;
else
return nodes[node].model;
}

View File

@@ -0,0 +1,36 @@
#ifndef CANIMSET_H
#define CANIMSET_H
#include <Common/types.h>
#include <Core/TResPtr.h>
#include <vector>
#include "model/CModel.h"
#include "CResource.h"
// will expand later! this is where animation support will come in
class CAnimSet : public CResource
{
DECLARE_RESOURCE_TYPE(eAnimSet)
friend class CAnimSetLoader;
struct SNode
{
TString name;
TResPtr<CModel> model;
u32 skinID;
u32 skelID;
SNode() { model = nullptr; }
};
std::vector<SNode> nodes;
public:
CAnimSet();
~CAnimSet();
u32 getNodeCount();
TString getNodeName(u32 node);
CModel* getNodeModel(u32 node);
};
#endif // CCHARACTERSET_H

View File

@@ -0,0 +1,138 @@
#include "CAnimationParameters.h"
#include "CAnimSet.h"
#include <Core/CResCache.h>
#include <Core/Log.h>
#include <iostream>
CAnimationParameters::CAnimationParameters()
{
mGame = ePrime;
mpCharSet = nullptr;
mNodeIndex = 0;
mUnknown1 = 0;
mUnknown2 = 0;
mUnknown3 = 0;
mUnknown4 = 0;
}
CAnimationParameters::CAnimationParameters(CInputStream& SCLY, EGame game)
{
mGame = game;
mpCharSet = nullptr;
mNodeIndex = 0;
mUnknown1 = 0;
mUnknown2 = 0;
mUnknown3 = 0;
mUnknown4 = 0;
if (game <= eEchoes)
{
u32 animSetID = SCLY.ReadLong();
mNodeIndex = SCLY.ReadLong();
mUnknown1 = SCLY.ReadLong();
mpCharSet = gResCache.GetResource(animSetID, "ANCS");
}
else if (game <= eCorruption)
{
u64 charID = SCLY.ReadLongLong();
mUnknown1 = SCLY.ReadLong();
mpCharSet = gResCache.GetResource(charID, "CHAR");
}
else if (game == eReturns)
{
SCLY.Seek(-6, SEEK_CUR);
u32 offset = SCLY.Tell();
u32 propID = SCLY.ReadLong();
SCLY.Seek(2, SEEK_CUR);
mUnknown1 = (u32) SCLY.ReadByte();
mUnknown1 &= 0xFF;
if (mUnknown1 == 0x60)
{
u64 charID = SCLY.ReadLongLong();
mUnknown2 = SCLY.ReadLong();
mUnknown3 = SCLY.ReadLong();
mUnknown4 = SCLY.ReadLong();
mpCharSet = gResCache.GetResource(charID, "CHAR");
}
else if (mUnknown1 != 0x80)
{
Log::FileError(SCLY.GetSourceString(), offset,
"Unexpected AnimationParameters byte: " + TString::HexString(mUnknown1, true, true, 2) + " (property " + TString::HexString(propID, true, true, 8) + ")");
}
}
}
CModel* CAnimationParameters::GetCurrentModel(s32 nodeIndex)
{
if (!mpCharSet) return nullptr;
if (mpCharSet->Type() != eAnimSet) return nullptr;
if (nodeIndex == -1) nodeIndex = mNodeIndex;
CAnimSet *pSet = static_cast<CAnimSet*>(mpCharSet.RawPointer());
if (pSet->getNodeCount() <= (u32) nodeIndex) return nullptr;
return pSet->getNodeModel(nodeIndex);
}
// ************ GETTERS ************
EGame CAnimationParameters::Version()
{
return mGame;
}
CResource* CAnimationParameters::Resource()
{
return mpCharSet;
}
u32 CAnimationParameters::CharacterIndex()
{
return mNodeIndex;
}
u32 CAnimationParameters::Unknown(u32 index)
{
switch (index)
{
case 0: return mUnknown1;
case 1: return mUnknown2;
case 2: return mUnknown3;
case 3: return mUnknown4;
default: return 0;
}
}
// ************ SETTERS ************
void CAnimationParameters::SetResource(CResource *pRes)
{
if ((pRes->Type() == eAnimSet) || (pRes->Type() == eCharacter))
{
mpCharSet = pRes;
mNodeIndex = 0;
}
else
Log::Error("Resource with invalid type passed to CAnimationParameters: " + pRes->Source());
}
void CAnimationParameters::SetNodeIndex(u32 index)
{
mNodeIndex = index;
}
void CAnimationParameters::SetUnknown(u32 index, u32 value)
{
switch (index)
{
case 0: mUnknown1 = value;
case 1: mUnknown2 = value;
case 2: mUnknown3 = value;
case 3: mUnknown4 = value;
}
}

View File

@@ -0,0 +1,37 @@
#ifndef CANIMATIONPARAMETERS_H
#define CANIMATIONPARAMETERS_H
#include "CResource.h"
#include "model/CModel.h"
#include <Core/TResPtr.h>
#include "EFormatVersion.h"
class CAnimationParameters
{
EGame mGame;
TResPtr<CResource> mpCharSet;
u32 mNodeIndex;
u32 mUnknown1;
u32 mUnknown2;
u32 mUnknown3;
u32 mUnknown4;
public:
CAnimationParameters();
CAnimationParameters(CInputStream& SCLY, EGame game);
CModel* GetCurrentModel(s32 nodeIndex = -1);
// Getters
EGame Version();
CResource* Resource();
u32 CharacterIndex();
u32 Unknown(u32 index);
// Setters
void SetResource(CResource *pRes);
void SetNodeIndex(u32 index);
void SetUnknown(u32 index, u32 value);
};
#endif // CANIMATIONPARAMETERS_H

View File

@@ -0,0 +1,114 @@
#include "CCollisionMesh.h"
#include <Core/CRenderer.h>
CCollisionMesh::CCollisionMesh()
{
mVBO.SetVertexDesc(ePosition);
mVertexCount = 0;
mLineCount = 0;
mFaceCount = 0;
mBuffered = false;
mIBO.SetPrimitiveType(GL_TRIANGLES);
}
CCollisionMesh::~CCollisionMesh()
{
if (mBuffered)
{
mIBO.Clear();
mVBO.Clear();
mBuffered = false;
}
}
void CCollisionMesh::BufferGL()
{
if (mBuffered)
{
mIBO.Clear();
mVBO.Clear();
mBuffered = false;
}
// Add all the verts to our VBO, first...
mVBO.Reserve(mCollisionVertices.size());
for (u16 v = 0; v < mCollisionVertices.size(); v++)
mVBO.AddVertex(CVertex(mCollisionVertices[v].Pos));
// Then add all the relevant indices to the IBO
mIBO.Reserve(mCollisionFaces.size() * 3);
for (u32 v = 0; v < mCollisionFaces.size(); v++)
{
u16 Verts[3];
CCollisionFace *Face = &mCollisionFaces[v];
CCollisionLine *LineA = GetLine(Face->Lines[0]);
CCollisionLine *LineB = GetLine(Face->Lines[1]);
Verts[0] = LineA->Vertices[0];
Verts[1] = LineA->Vertices[1];
// We have two vertex indices; the last one is one of the ones on line B, but we're not sure which one
if ((LineB->Vertices[0] != Verts[0]) &&
(LineB->Vertices[0] != Verts[1]))
Verts[2] = LineB->Vertices[0];
else
Verts[2] = LineB->Vertices[1];
// Some faces have a property that indicates they need to be inverted
if (!Face->Properties.Invert)
mIBO.AddIndices(&Verts[0], 3);
else {
mIBO.AddIndex(Verts[2]);
mIBO.AddIndex(Verts[1]);
mIBO.AddIndex(Verts[0]);
}
}
// Buffer, and done
mVBO.Buffer();
mIBO.Buffer();
mBuffered = true;
}
void CCollisionMesh::Draw()
{
if (!mBuffered) BufferGL();
mVBO.Bind();
mIBO.Bind();
glDrawElements(GL_TRIANGLES, mIBO.GetSize(), GL_UNSIGNED_SHORT, (void*) 0);
gDrawCount++;
mIBO.Unbind();
mVBO.Unbind();
}
void CCollisionMesh::DrawWireframe()
{
if (!mBuffered) BufferGL();
mVBO.Bind();
mIBO.Bind();
for (u32 f = 0; f < mFaceCount; f++)
{
glDrawElements(GL_LINE_LOOP, 3, GL_UNSIGNED_SHORT, (void*) (f * 6));
gDrawCount++;
}
mIBO.Unbind();
mVBO.Unbind();
}
CCollisionMesh::CCollisionVertex* CCollisionMesh::GetVertex(u16 index)
{
return &mCollisionVertices[index];
}
CCollisionMesh::CCollisionLine* CCollisionMesh::GetLine(u16 index)
{
return &mCollisionLines[index];
}
CCollisionMesh::CCollisionFace* CCollisionMesh::GetFace(u16 index)
{
return &mCollisionFaces[index];
}

View File

@@ -0,0 +1,88 @@
#ifndef CCOLLISIONMESH_H
#define CCOLLISIONMESH_H
#include <Common/CAABox.h>
#include <OpenGL/CVertexBuffer.h>
#include <OpenGL/CIndexBuffer.h>
#include "CResource.h"
class CCollisionMesh
{
friend class CCollisionLoader;
class CCollisionOctree
{
friend class CCollisionLoader;
struct SOctreeNode {};
struct SLeaf : public SOctreeNode
{
CAABox AABox;
std::vector<u16> FaceIndices;
};
struct SBranch : public SOctreeNode
{
u16 Flags;
SOctreeNode *pChildren[8];
};
SOctreeNode* Root;
};
struct SCollisionProperties
{
// todo: figure out what the other properties are
bool Invert;
};
class CCollisionVertex
{
public:
SCollisionProperties Properties;
CVector3f Pos;
};
class CCollisionLine
{
public:
SCollisionProperties Properties;
u16 Vertices[2];
};
class CCollisionFace
{
public:
SCollisionProperties Properties;
u16 Lines[3];
};
CVertexBuffer mVBO;
CIndexBuffer mIBO;
u32 mVertexCount;
u32 mLineCount;
u32 mFaceCount;
bool mBuffered;
CAABox mAABox;
CCollisionOctree *mOctree;
std::vector<u32> mFlags;
std::vector<CCollisionVertex> mCollisionVertices;
std::vector<CCollisionLine> mCollisionLines;
std::vector<CCollisionFace> mCollisionFaces;
bool mOctreeLoaded;
CCollisionVertex *GetVertex(u16 index);
CCollisionLine *GetLine(u16 index);
CCollisionFace *GetFace(u16 index);
public:
CCollisionMesh();
~CCollisionMesh();
void BufferGL();
void Draw();
void DrawWireframe();
};
#endif // CCOLLISIONMESH_H

View File

@@ -0,0 +1,38 @@
#include "CCollisionMeshGroup.h"
CCollisionMeshGroup::CCollisionMeshGroup()
{
}
CCollisionMeshGroup::~CCollisionMeshGroup()
{
for (auto it = mMeshes.begin(); it != mMeshes.end(); it++)
delete *it;
}
u32 CCollisionMeshGroup::NumMeshes()
{
return mMeshes.size();
}
CCollisionMesh* CCollisionMeshGroup::MeshByIndex(u32 index)
{
return mMeshes[index];
}
void CCollisionMeshGroup::AddMesh(CCollisionMesh *pMesh)
{
mMeshes.push_back(pMesh);
}
void CCollisionMeshGroup::Draw()
{
for (auto it = mMeshes.begin(); it != mMeshes.end(); it++)
(*it)->Draw();
}
void CCollisionMeshGroup::DrawWireframe()
{
for (auto it = mMeshes.begin(); it != mMeshes.end(); it++)
(*it)->DrawWireframe();
}

View File

@@ -0,0 +1,25 @@
#ifndef CCOLLISIONMESHGROUP_H
#define CCOLLISIONMESHGROUP_H
#include "CResource.h"
#include "CCollisionMesh.h"
#include <Core/TResPtr.h>
#include <vector>
class CCollisionMeshGroup : public CResource
{
DECLARE_RESOURCE_TYPE(eCollisionMeshGroup)
std::vector<CCollisionMesh*> mMeshes;
public:
CCollisionMeshGroup();
~CCollisionMeshGroup();
u32 NumMeshes();
CCollisionMesh* MeshByIndex(u32 index);
void AddMesh(CCollisionMesh *pMesh);
void Draw();
void DrawWireframe();
};
#endif // CCOLLISIONMESHGROUP_H

Some files were not shown because too many files have changed in this diff Show More