Initial commit of current work on Prime World Editor

This commit is contained in:
parax0
2015-07-26 17:39:49 -04:00
commit 66e8c2ebcb
305 changed files with 33469 additions and 0 deletions

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++)
{
u8 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

111
OpenGL/CFramebuffer.cpp Normal file
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;

32
OpenGL/CFramebuffer.h Normal file
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
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
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

156
OpenGL/CIndexBuffer.cpp Normal file
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);
}
}

39
OpenGL/CIndexBuffer.h Normal file
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

52
OpenGL/CRenderbuffer.cpp Normal file
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);
}

31
OpenGL/CRenderbuffer.h Normal file
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
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)
{
std::string 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)
{
std::string Out = "dump/VS_" + std::to_string(gSuccessfulCompileCount) + ".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)
{
std::string Out = "dump/BadPS_" + std::to_string(gFailedCompileCount) + ".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)
{
std::string Out = "dump/PS_" + std::to_string(gSuccessfulCompileCount) + ".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)
{
std::string Out = "dump/BadLink_" + std::to_string(gFailedCompileCount) + ".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.c_str());
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(std::string ShaderName)
{
std::string VertexShaderFilename = "../resources/shaders/" + ShaderName + ".vs";
std::string PixelShaderFilename = "../resources/shaders/" + ShaderName + ".ps";
CTextInStream VertexShaderFile(VertexShaderFilename);
CTextInStream PixelShaderFile(PixelShaderFilename);
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, std::string 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.c_str());
if (SourceLen > 0)
ShaderOut << Source;
if (LogLen > 0)
ShaderOut << InfoLog;
ShaderOut.close();
delete[] Source;
delete[] InfoLog;
}

45
OpenGL/CShader.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef CSHADER_H
#define CSHADER_H
#include <gl/glew.h>
#include <string>
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* Uniform);
GLuint GetUniformBlockIndex(const char* UniformBlock);
void SetCurrent();
// Static
static CShader* FromResourceFile(std::string ShaderName);
static CShader* CurrentShader();
static void KillCachedShader();
private:
void DumpShaderSource(GLuint Shader, std::string Out);
};
#endif // CSHADER_H

445
OpenGL/CShaderGenerator.cpp Normal file
View File

@@ -0,0 +1,445 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <gl/glew.h>
#include "CShaderGenerator.h"
const std::string 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 std::string 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 std::string 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 std::string 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 std::string 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 std::string gkTevAlpha[] = {
"Prev.a",
"C0.a",
"C1.a",
"C2.a",
"Tex.a",
"Ras.a",
"Konst.a",
"0.0"
};
const std::string 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 MVP = ModelMtx * ViewMtx * ProjMtx;\n"
<< " mat4 MV = ModelMtx * ViewMtx;\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"
<< "#extension GL_ARB_shading_language_420pack : enable\n" // Needed to set texture binding layouts
<< "\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 << "layout(binding = " << iPass << ") 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;\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,445 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <gl/glew.h>
#include "CShaderGenerator.h"
const std::string 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 std::string 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 std::string 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 std::string 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"
};
const std::string gkTevAlpha[] = {
"Prev.a",
"C0.a",
"C1.a",
"C2.a",
"Tex.a",
"Ras.a",
"Konst.a",
"0"
};
const std::string 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.GetVtxDesc();
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.mPasses.size(); iPass++)
if (Mat.mPasses[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 MVP = ModelMtx * ViewMtx * ProjMtx;\n"
<< " mat4 MV = ModelMtx * ViewMtx;\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 << " Color1 = RawColor0;\n";
if (VtxDesc & eColor1) ShaderCode << " Color2 = RawColor1;\n";
// Per-vertex lighting
ShaderCode << "\n"
<< " // Dynamic Lighting\n";
// The 0x1 bit on the flag determines whether lighting is enabled for COLOR0
if (Mat.mChanCtrlFlags & 0x1)
{
u8 DiffuseFunction = (Mat.mChanCtrlFlags >> 11) & 0x3;
if (Mat.mChanCount > 0)
{
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";
if (DiffuseFunction == 2) ShaderCode << " float DiffuseAtten = max(0, dot(Normal, LightDist));\n";
else if (DiffuseFunction == 1) ShaderCode << " float DiffuseAtten = dot(Normal, LightDist);\n";
else ShaderCode << " float DiffuseAtten = 1.0;\n";
ShaderCode << " 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";
}
}
else
{
ShaderCode << " COLOR0A0 = COLOR0_Mat;\n"
<< " COLOR1A1 = COLOR1_Mat;\n"
<< "\n";
}
// Texture coordinate generation
ShaderCode << " \n"
<< " // TexGen\n";
for (u32 iCoord = 0; iCoord < Mat.mPasses.size(); iCoord++)
{
if (Mat.mPasses[iCoord].TexCoordSource == 0xFF) continue;
s32 AnimType = Mat.mPasses[iCoord].AnimMode;
// Texture Matrix
if (AnimType == -1) // No animation
ShaderCode << " Tex" << iCoord << " = vec3(" << gkCoordSrc[Mat.mPasses[iCoord].TexCoordSource] << ");\n";
else // Animation used - texture matrix at least, possibly normalization/post-transform
{
// Texture Matrix
ShaderCode << " Tex" << iCoord << " = vec3(vec4(" << gkCoordSrc[Mat.mPasses[iCoord].TexCoordSource] << ", 1.0) * TexMtx[" << iCoord << "]).xyz;\n";
if ((AnimType < 2) || (AnimType > 5))
{
// Normalization + Post-Transform
ShaderCode << " Tex" << iCoord << " = normalize(Tex" << iCoord << ");\n";
ShaderCode << " Tex" << iCoord << " = vec3(vec4(Tex" << iCoord << ", 1.0) * PostMtx[" << iCoord << "]).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"
<< "#extension GL_ARB_shading_language_420pack : enable\n" // Needed to set texture binding layouts
<< "\n";
EVertexDescription VtxDesc = Mat.GetVtxDesc();
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";
for (u32 iPass = 0; iPass < Mat.mPasses.size(); iPass++)
if (Mat.mPasses[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 iTex = 0; iTex < Mat.mPasses.size(); iTex++)
if (Mat.mPasses[iTex].pTexture != nullptr)
ShaderCode << "layout(binding = " << iTex << ") uniform sampler2D Texture" << iTex << ";\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";
for (u32 iPass = 0; iPass < Mat.mPasses.size(); iPass++)
{
ShaderCode << " // TEV Stage " << iPass << "\n";
const CMaterial::SPass *pPass = &Mat.mPasses[iPass];
if (pPass->Hidden)
{
ShaderCode << " // Pass is hidden\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->pTexture != nullptr)
ShaderCode << " Tex = texture(Texture" << iPass << ", TevCoord);\n";
ShaderCode << " Konst = vec4(" << gkKonstColor[pPass->KonstColorSel] << ", " << gkKonstAlpha[pPass->KonstAlphaSel] << ");\n";
if (pPass->RasSel != 0xFF)
{
if (pPass->RasSel == 0x0) ShaderCode << " Ras = vec4(COLOR0A0.xyz, 1.0);\n";
else if (pPass->RasSel == 0x1) ShaderCode << " Ras = vec4(COLOR1A1.xyz, 1.0);\n";
else if (pPass->RasSel == 0x2) ShaderCode << " Ras = vec4(0.0, 0.0, 0.0, COLOR0A0.w);\n";
else if (pPass->RasSel == 0x3) ShaderCode << " Ras = vec4(0.0, 0.0, 0.0, COLOR1A1.w);\n";
else if (pPass->RasSel == 0x4) ShaderCode << " Ras = COLOR0A0;\n";
else if (pPass->RasSel == 0x5) ShaderCode << " Ras = COLOR1A1;\n";
else if (pPass->RasSel == 0x6) ShaderCode << " Ras = vec4(0.0, 0.0, 0.0, 0.0);\n";
}
for (u8 iInput = 0; iInput < 4; iInput++)
{
u8 TevCharacter = iInput + 0x41; // the current stage number represented as an ASCII letter; eg 0 is 'A'
ShaderCode << " TevIn" << TevCharacter << " = vec4("
<< gkTevColor[Mat.GetTevColorIn(iPass, iInput) & 0xF]
<< ", "
<< gkTevAlpha[Mat.GetTevAlphaIn(iPass, iInput) & 0x7]
<< ");\n";
}
// Applying TRAN and BLOL (opacity and bloom maps) in Corruption require accessing specific color channels
// This feels hacky and might not be the best way to implement this
if (pPass->Type == "TRAN")
{
ShaderCode << " // TRAN Combine\n"
<< " Prev.a = 1.0 - Tex.r;\n\n";
}
/*else if (pPass->Type == "BLOL")
{
ShaderCode << " // BLOL Combine\n"
<< " C0.rgb += vec3(Tex.g, Tex.g, Tex.g);\n\n";
}*/
else
{
ShaderCode << " // RGB Combine\n"
<< " "
<< gkTevRigid[pPass->ColorOutputRegister]
<< ".rgb = ";
ShaderCode << "clamp(vec3(TevInD.rgb + ((1.0 - TevInC.rgb) * TevInA.rgb + TevInC.rgb * TevInB.rgb)), vec3(0, 0, 0), vec3(1.0, 1.0, 1.0));\n";
ShaderCode << " // Alpha Combine\n"
<< " "
<< gkTevRigid[pPass->AlphaOutputRegister]
<< ".a = ";
ShaderCode << "clamp(TevInD.a + ((1.0 - TevInC.a) * TevInA.a + TevInC.a * TevInB.a), 0.0, 1.0);\n\n";
}
}
if (Mat.GetOptions() & ePunchthrough) {
ShaderCode << " if (Prev.a <= 0.25) discard;\n"
<< " else Prev.a = 1.0;\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;
}

22
OpenGL/CShaderGenerator.h Normal file
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

60
OpenGL/CUniformBuffer.cpp Normal file
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;
}

28
OpenGL/CUniformBuffer.h Normal file
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

230
OpenGL/CVertexBuffer.cpp Normal file
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;
}

37
OpenGL/CVertexBuffer.h Normal file
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

37
OpenGL/GLCommon.cpp Normal file
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");
}
}

34
OpenGL/GLCommon.h Normal file
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

18
OpenGL/SMeshPointer.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef SMESHPOINTER_H
#define SMESHPOINTER_H
#include <Common/CAABox.h>
#include <Common/types.h>
#include <Core/ERenderCommand.h>
#include <Scene/CSceneNode.h>
#include <Resource/CMaterial.h>
struct SMeshPointer
{
CSceneNode *pNode;
u32 Asset;
CAABox AABox;
ERenderCommand Command;
};
#endif // SMESHPOINTER_H