Initial Commit
This commit is contained in:
120
src/render/debugrender.cpp
Normal file
120
src/render/debugrender.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include "debugrender.h"
|
||||
#include "render_shared.h"
|
||||
#include "render.h"
|
||||
#include "renderdevice.h"
|
||||
#include "gpu_buffer.h"
|
||||
#include "shadersystem.h"
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
||||
struct DebugVertex
|
||||
{
|
||||
glm::vec3 position;
|
||||
glm::vec3 color;
|
||||
};
|
||||
|
||||
static InputLayoutDesc_t g_debugRenderLayout[] =
|
||||
{
|
||||
{ VERTEXATTR_VEC3, SHADERSEMANTIC_POSITION },
|
||||
{ VERTEXATTR_VEC3, SHADERSEMANTIC_COLOR }
|
||||
};
|
||||
|
||||
bool g_drawDebug = true;
|
||||
|
||||
DebugRender* g_pDebugRender;
|
||||
|
||||
DebugRender::DebugRender()
|
||||
{
|
||||
m_verticesBuffer = nullptr;
|
||||
m_shader = nullptr;
|
||||
}
|
||||
|
||||
DebugRender::~DebugRender()
|
||||
{
|
||||
m_verticesBuffer = nullptr;
|
||||
m_shader = nullptr;
|
||||
}
|
||||
|
||||
void DebugRender::Initialize()
|
||||
{
|
||||
//float points[12];
|
||||
//m_verticesBuffer = g_pRenderDevice->CreateVertexBuffer(points, sizeof(points), true);
|
||||
|
||||
m_verticesBuffer = g_pRenderDevice->CreateVertexBuffer(NULL, kMaxDebugVBSize, true);
|
||||
|
||||
m_shader = g_pShaderSystem->CreateShader("debug_draw",
|
||||
"data/shaders/debug_draw.vs",
|
||||
"data/shaders/debug_draw.ps",
|
||||
g_debugRenderLayout,
|
||||
sizeof(g_debugRenderLayout) / sizeof(g_debugRenderLayout[0]));
|
||||
}
|
||||
|
||||
void DebugRender::Shutdown()
|
||||
{
|
||||
if (m_verticesBuffer) {
|
||||
delete m_verticesBuffer;
|
||||
m_verticesBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DebugRender::DrawLine(const glm::vec3& from, const glm::vec3& to, const glm::vec3& color)
|
||||
{
|
||||
if (!g_drawDebug)
|
||||
return;
|
||||
|
||||
Line line;
|
||||
line.from = from;
|
||||
line.color0 = color;
|
||||
line.to = to;
|
||||
line.color1 = color;
|
||||
m_lines.push_back(line);
|
||||
}
|
||||
|
||||
void DebugRender::RenderFrame()
|
||||
{
|
||||
if (!g_drawDebug)
|
||||
return;
|
||||
|
||||
// draw lines
|
||||
DrawLinesInternal();
|
||||
|
||||
// and clear them
|
||||
m_lines.clear();
|
||||
}
|
||||
|
||||
void DebugRender::DrawAxis(const glm::vec3& vec)
|
||||
{
|
||||
const float length = 0.2f;
|
||||
DrawLine(vec, glm::vec3(vec.x + length, vec.y, vec.z), glm::vec3(1.0f, 0.0, 0.0f));
|
||||
DrawLine(vec, glm::vec3(vec.x, vec.y + length, vec.z), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
DrawLine(vec, glm::vec3(vec.x, vec.y, vec.z + length), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
void DebugRender::DrawLinesInternal()
|
||||
{
|
||||
if (m_lines.empty())
|
||||
return;
|
||||
|
||||
g_pRenderDevice->SetDepthTest(true);
|
||||
g_pRenderDevice->SetDepthWrite(true);
|
||||
|
||||
g_pRenderDevice->SetVerticesBuffer(m_verticesBuffer);
|
||||
|
||||
m_verticesBuffer->UpdateBuffer(m_lines.data(), m_lines.size() * sizeof(Line));
|
||||
|
||||
// Bind our shader
|
||||
g_pShaderSystem->SetShader(m_shader);
|
||||
|
||||
// #TODO: Fix stupid bug, when we get very far from wireframe and lines can start cliping
|
||||
glm::mat4 proj = g_pRender->GetProjectionMatrix();
|
||||
glm::mat4 view = g_pRender->GetViewMatrix();
|
||||
proj[2][3] -= 0.0001f;
|
||||
|
||||
glm::mat4 mv = glm::mat4(1.0f);
|
||||
mv = proj * view;
|
||||
|
||||
g_pShaderSystem->SetUniformMatrix(m_shader, UNIFORM_MVP_MATRIX, &mv[0]);
|
||||
|
||||
// draw stuff
|
||||
g_pRenderDevice->DrawArrays(PT_LINES, 0, m_lines.size() * 2);
|
||||
}
|
||||
52
src/render/debugrender.h
Normal file
52
src/render/debugrender.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef DEBUGRENDER_H
|
||||
#define DEBUGRENDER_H
|
||||
|
||||
#include <vector>
|
||||
#include "render_shared.h"
|
||||
|
||||
const int kMaxDebugVBSize = 1024 * 1024 * 2;
|
||||
|
||||
class GPUBuffer;
|
||||
class Shader;
|
||||
|
||||
class DebugRender
|
||||
{
|
||||
public:
|
||||
DebugRender();
|
||||
~DebugRender();
|
||||
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
void DrawAxis(const glm::vec3& vec);
|
||||
void DrawLine(const glm::vec3& from, const glm::vec3& to, const glm::vec3& color);
|
||||
|
||||
void RenderFrame();
|
||||
|
||||
private:
|
||||
|
||||
void DrawLinesInternal();
|
||||
|
||||
private:
|
||||
// Primitives
|
||||
struct Line
|
||||
{
|
||||
glm::vec3 from;
|
||||
glm::vec3 color0;
|
||||
|
||||
glm::vec3 to;
|
||||
glm::vec3 color1;
|
||||
};
|
||||
|
||||
std::vector<Line> m_lines;
|
||||
|
||||
private:
|
||||
GPUBuffer* m_verticesBuffer;
|
||||
Shader* m_shader;
|
||||
};
|
||||
|
||||
extern DebugRender* g_pDebugRender;
|
||||
|
||||
extern bool g_drawDebug;
|
||||
|
||||
#endif // !DEBUGRENDER_H
|
||||
215
src/render/gl_shared.cpp
Normal file
215
src/render/gl_shared.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
#include "gl_shared.h"
|
||||
#include "log.h"
|
||||
|
||||
const char *GL_ErrorString( int err )
|
||||
{
|
||||
switch( err )
|
||||
{
|
||||
#ifdef GL_STACK_OVERFLOW
|
||||
case GL_STACK_OVERFLOW:
|
||||
return "GL_STACK_OVERFLOW";
|
||||
#endif // GL_STACK_OVERFLOW
|
||||
#ifdef GL_STACK_UNDERFLOW
|
||||
case GL_STACK_UNDERFLOW:
|
||||
return "GL_STACK_UNDERFLOW";
|
||||
#endif // GL_STACK_UNDERFLOW
|
||||
case GL_INVALID_ENUM:
|
||||
return "GL_INVALID_ENUM";
|
||||
case GL_INVALID_VALUE:
|
||||
return "GL_INVALID_VALUE";
|
||||
case GL_INVALID_OPERATION:
|
||||
return "GL_INVALID_OPERATION";
|
||||
case GL_OUT_OF_MEMORY:
|
||||
return "GL_OUT_OF_MEMORY";
|
||||
default:
|
||||
return "UNKNOWN ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
void GL_CheckError()
|
||||
{
|
||||
GLenum err;
|
||||
if ( (err = glGetError()) != GL_NO_ERROR )
|
||||
Msg( "OpenGL Error: %s", GL_ErrorString( err ) );// Msg("OpenGL Error: %s [%s]\n", GL_ErrorString(err), GL_TargetToString(tex->target));
|
||||
}
|
||||
|
||||
void GL_CheckErrorEx( const char* filename, int line )
|
||||
{
|
||||
GLenum err;
|
||||
if ( (err = glGetError()) != GL_NO_ERROR )
|
||||
Msg( "OpenGL Error: %s at %s:%i", GL_ErrorString( err ), filename, line );// Msg("OpenGL Error: %s [%s]\n", GL_ErrorString(err), GL_TargetToString(tex->target));
|
||||
}
|
||||
|
||||
void GL_CheckErrorFunction(const char* expression, const char* filename, int line)
|
||||
{
|
||||
GLenum err;
|
||||
if ( (err = glGetError()) != GL_NO_ERROR )
|
||||
Msg( "OpenGL Error: %s (%s) at %s:%i", expression, GL_ErrorString( err ), filename, line );// Msg("OpenGL Error: %s [%s]\n", GL_ErrorString(err), GL_TargetToString(tex->target));
|
||||
}
|
||||
|
||||
// Conversion functions
|
||||
|
||||
#include "render_shared.h"
|
||||
|
||||
uint32_t GetGLInternalPF(PixelFormat pf)
|
||||
{
|
||||
switch (pf)
|
||||
{
|
||||
case PF_UNKNOWN:
|
||||
return 0;
|
||||
|
||||
case PF_R8G8B8:
|
||||
case PF_R8G8B8F:
|
||||
return GL_RGB;
|
||||
|
||||
case PF_R8G8B8A8:
|
||||
case PF_R8G8B8A8F:
|
||||
return GL_RGBA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t GetGLTypePF(PixelFormat pf)
|
||||
{
|
||||
switch (pf)
|
||||
{
|
||||
case PF_UNKNOWN:
|
||||
return 0;
|
||||
|
||||
case PF_R8G8B8:
|
||||
case PF_R8G8B8A8:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
|
||||
case PF_R8G8B8F:
|
||||
case PF_R8G8B8A8F:
|
||||
return GL_FLOAT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t GetGLBlendFactor(BlendFactor factor)
|
||||
{
|
||||
switch (factor)
|
||||
{
|
||||
case BF_ZERO:
|
||||
return GL_ZERO;
|
||||
case BF_ONE:
|
||||
return GL_ONE;
|
||||
case BF_SRC_COLOR:
|
||||
return GL_SRC_COLOR;
|
||||
case BF_ONE_MINUS_SRC_COLOR:
|
||||
return GL_ONE_MINUS_SRC_COLOR;
|
||||
case BF_DST_COLOR:
|
||||
return GL_DST_COLOR;
|
||||
case BF_ONE_MINUS_DST_COLOR:
|
||||
return GL_ONE_MINUS_DST_COLOR;
|
||||
case BF_SRC_ALPHA:
|
||||
return GL_SRC_ALPHA;
|
||||
case BF_ONE_MINUS_SRC_ALPHA:
|
||||
return GL_ONE_MINUS_SRC_ALPHA;
|
||||
case BF_DST_ALPHA:
|
||||
return GL_DST_ALPHA;
|
||||
case BF_ONE_MINUS_DST_ALPHA:
|
||||
return GL_ONE_MINUS_DST_ALPHA;
|
||||
case BF_CONSTANT_COLOR:
|
||||
return GL_CONSTANT_COLOR;
|
||||
case BF_ONE_MINUS_CONSTANT_COLOR:
|
||||
return GL_ONE_MINUS_CONSTANT_COLOR;
|
||||
case BF_CONSTANT_ALPHA:
|
||||
return GL_CONSTANT_ALPHA;
|
||||
case BF_ONE_MINUS_CONSTANT_ALPHA:
|
||||
return GL_ONE_MINUS_CONSTANT_ALPHA;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t GetGLEquation(BlendEquation equation)
|
||||
{
|
||||
switch (equation)
|
||||
{
|
||||
case BE_FUNC_ADD:
|
||||
return GL_FUNC_ADD;
|
||||
case BE_FUNC_SUBTRACT:
|
||||
return GL_FUNC_SUBTRACT;
|
||||
case BE_FUNC_REVERSE_SUBTRACT:
|
||||
return GL_FUNC_REVERSE_SUBTRACT;
|
||||
case BE_MIN:
|
||||
return GL_MIN;
|
||||
case BE_MAX:
|
||||
return GL_MAX;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t GetGLDepthFunc(DepthFunc func)
|
||||
{
|
||||
switch (func)
|
||||
{
|
||||
case DF_NEVER:
|
||||
return GL_NEVER;
|
||||
case DF_LESS:
|
||||
return GL_LESS;
|
||||
case DF_EQUAL:
|
||||
return GL_EQUAL;
|
||||
case DF_LEQUAL:
|
||||
return GL_LEQUAL;
|
||||
case DF_GREATER:
|
||||
return GL_GREATER;
|
||||
case DF_NOTEQUAL:
|
||||
return GL_NOTEQUAL;
|
||||
case DF_GEQUAL:
|
||||
return GL_GEQUAL;
|
||||
case DF_ALWAYS:
|
||||
return GL_ALWAYS;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_assert(0 && "Should be never here");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getGlWrap(TextureWrap wrap)
|
||||
{
|
||||
int param = 0;
|
||||
|
||||
if (wrap == TextureWrap_Repeat)
|
||||
param = GL_REPEAT;
|
||||
else if (wrap == TextureWrap_MirroredRepeat)
|
||||
param = GL_MIRRORED_REPEAT;
|
||||
else if (wrap == TextureWrap_ClampToEdge)
|
||||
param = GL_CLAMP_TO_EDGE;
|
||||
else if (wrap == TextureWrap_ClampToBorder)
|
||||
param = GL_CLAMP_TO_BORDER;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
int getGlTexFilter(TextureFilter filter)
|
||||
{
|
||||
int param = 0;
|
||||
|
||||
if (filter == TextureFilter_Linear)
|
||||
param = GL_LINEAR;
|
||||
else if (filter == TextureFilter_Nearest)
|
||||
param = GL_NEAREST;
|
||||
else if (filter == TextureFilter_LinearMipmapLinear)
|
||||
param = GL_LINEAR_MIPMAP_LINEAR;
|
||||
else if (filter == TextureFilter_LinearMipmapNearest)
|
||||
param = GL_LINEAR_MIPMAP_NEAREST;
|
||||
else if (filter == TextureFilter_NearestMipmapLinear)
|
||||
param = GL_NEAREST_MIPMAP_LINEAR;
|
||||
else if (filter == TextureFilter_NearestMipmapNearest)
|
||||
param = GL_NEAREST_MIPMAP_NEAREST;
|
||||
|
||||
return param;
|
||||
}
|
||||
18
src/render/gl_shared.h
Normal file
18
src/render/gl_shared.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef GL_SHARED_H
|
||||
#define GL_SHARED_H
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
void GL_CheckError();
|
||||
void GL_CheckErrorEx(const char* filename, int line);
|
||||
void GL_CheckErrorFunction(const char* expression, const char* filename, int line);
|
||||
|
||||
#define GL_CHECK_ERROR() \
|
||||
GL_CheckErrorEx(__FILE__, __LINE__)
|
||||
|
||||
#define GL_CHECK_FUNC_ERROR(expr) \
|
||||
expr; \
|
||||
GL_CheckErrorFunction(#expr, __FILE__, __LINE__)
|
||||
|
||||
#endif // !GL_SHARED_H
|
||||
103
src/render/gpu_buffer.cpp
Normal file
103
src/render/gpu_buffer.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "log.h"
|
||||
#include "gl_shared.h"
|
||||
#include "render_shared.h"
|
||||
#include "gpu_buffer.h"
|
||||
|
||||
GLenum BufferTypeToTarget(BufferType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BT_VERTEX:
|
||||
return GL_ARRAY_BUFFER;
|
||||
|
||||
case BT_INDEX:
|
||||
return GL_ELEMENT_ARRAY_BUFFER;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
SDL_assert(0 && "Unknowed buffer type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
GPUBuffer::GPUBuffer(BufferType type, void* data, size_t size, bool isStream /*= false*/)
|
||||
{
|
||||
m_type = type;
|
||||
m_target = BufferTypeToTarget(m_type);
|
||||
m_isStream = isStream;
|
||||
m_size = size;
|
||||
|
||||
glGenBuffers(1, &m_buffer);
|
||||
glBindBuffer(m_target, m_buffer);
|
||||
glBufferData(m_target, size, data, isStream ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||
GL_CHECK_ERROR();
|
||||
glBindBuffer(m_target, 0);
|
||||
}
|
||||
|
||||
GPUBuffer::~GPUBuffer()
|
||||
{
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
}
|
||||
|
||||
void GPUBuffer::Bind()
|
||||
{
|
||||
glBindBuffer(m_target, m_buffer);
|
||||
}
|
||||
|
||||
void* GPUBuffer::MapBuffer(BufferAccess access)
|
||||
{
|
||||
GLenum accessGl = 0;
|
||||
|
||||
switch (access)
|
||||
{
|
||||
case BA_READ_ONLY:
|
||||
accessGl = GL_READ_ONLY;
|
||||
break;
|
||||
case BA_WRITE_ONLY:
|
||||
accessGl = GL_WRITE_ONLY;
|
||||
break;
|
||||
case BA_READ_WRITE:
|
||||
accessGl = GL_READ_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
Bind();
|
||||
|
||||
void* ptr = glMapBuffer(m_target, accessGl);
|
||||
|
||||
GL_CHECK_ERROR();
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void GPUBuffer::UnmapBuffer()
|
||||
{
|
||||
Bind();
|
||||
|
||||
glUnmapBuffer(m_target);
|
||||
}
|
||||
|
||||
void GPUBuffer::UpdateBuffer(void* data, size_t size)
|
||||
{
|
||||
SDL_assert(m_isStream && "Trying to update static buffer.");
|
||||
|
||||
// Clear GL errors
|
||||
glGetError();
|
||||
|
||||
// Bind buffer
|
||||
Bind();
|
||||
|
||||
glBufferData(m_target, size, data, GL_DYNAMIC_DRAW);
|
||||
|
||||
GL_CHECK_ERROR();
|
||||
|
||||
GLenum error = glGetError();
|
||||
if (error == GL_OUT_OF_MEMORY)
|
||||
{
|
||||
Msg("GPUBuffer::UpdateData: Out of memory. Couldn't allocate buffer with %u size", (unsigned)size);
|
||||
return;
|
||||
}
|
||||
|
||||
m_size = size;
|
||||
}
|
||||
32
src/render/gpu_buffer.h
Normal file
32
src/render/gpu_buffer.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef GPU_BUFFER_H
|
||||
#define GPU_BUFFER_H
|
||||
|
||||
#include "render_shared.h"
|
||||
|
||||
class RenderDevice;
|
||||
|
||||
class GPUBuffer
|
||||
{
|
||||
friend class RenderDevice;
|
||||
public:
|
||||
~GPUBuffer();
|
||||
|
||||
void Bind();
|
||||
|
||||
void* MapBuffer(BufferAccess access);
|
||||
void UnmapBuffer();
|
||||
|
||||
void UpdateBuffer(void* data, size_t size);
|
||||
|
||||
private:
|
||||
GPUBuffer(BufferType type, void* data, size_t size, bool isStream = false);
|
||||
|
||||
BufferType m_type;
|
||||
uint32_t m_target;
|
||||
uint32_t m_buffer;
|
||||
size_t m_size;
|
||||
|
||||
bool m_isStream;
|
||||
};
|
||||
|
||||
#endif // !GPU_BUFFER_H
|
||||
404
src/render/modelsystem.cpp
Normal file
404
src/render/modelsystem.cpp
Normal file
@@ -0,0 +1,404 @@
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "ifilesystem.h"
|
||||
#include "log.h"
|
||||
#include "render.h"
|
||||
#include "gpu_buffer.h"
|
||||
#include "shader.h"
|
||||
#include "shadersystem.h"
|
||||
#include "renderdevice.h"
|
||||
#include "modelsystem.h"
|
||||
#include "texturesmanager.h"
|
||||
|
||||
ModelSystem* g_pModelSystem = nullptr;
|
||||
|
||||
static InputLayoutDesc_t g_staticVertexLayout[] = {
|
||||
{ VERTEXATTR_VEC3, SHADERSEMANTIC_POSITION },
|
||||
{ VERTEXATTR_VEC3, SHADERSEMANTIC_NORMAL },
|
||||
{ VERTEXATTR_VEC2, SHADERSEMANTIC_TEXCOORD },
|
||||
};
|
||||
|
||||
static InputLayoutDesc_t g_skinnedVertexLayout[] = {
|
||||
{ VERTEXATTR_VEC3, SHADERSEMANTIC_POSITION },
|
||||
{ VERTEXATTR_VEC3, SHADERSEMANTIC_NORMAL },
|
||||
{ VERTEXATTR_VEC2, SHADERSEMANTIC_TEXCOORD }
|
||||
};
|
||||
|
||||
Shader* g_litShader = nullptr;
|
||||
|
||||
std::string getFileNameWithoutExtension(const std::string& filename)
|
||||
{
|
||||
size_t lastindex = filename.find_last_of(".");
|
||||
if (lastindex != std::string::npos) {
|
||||
return filename.substr(0, lastindex);
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
ModelSystem::ModelSystem()
|
||||
{
|
||||
}
|
||||
|
||||
ModelSystem::~ModelSystem()
|
||||
{
|
||||
}
|
||||
|
||||
void ModelSystem::Shutdown()
|
||||
{
|
||||
for (int i = 0; i < m_models.size(); i++)
|
||||
{
|
||||
if (m_models[i].model)
|
||||
{
|
||||
delete m_models[i].model;
|
||||
m_models[i].model = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
m_models.clear();
|
||||
}
|
||||
|
||||
Model* ModelSystem::LoadModel(const char* filename)
|
||||
{
|
||||
auto it = std::find_if(m_models.begin(), m_models.end(), [=](const ModelEntry& entry) { return strcmp(entry.filename, filename) == 0; });
|
||||
if (it != m_models.end())
|
||||
{
|
||||
return it->model;
|
||||
}
|
||||
|
||||
if (!GetFileSystem()->IsExist(filename))
|
||||
{
|
||||
Msg("ModelSystem::LoadModel: File '%s' not exist.", filename);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Model* model = new Model();
|
||||
|
||||
if (strstr(filename, ".obj"))
|
||||
{
|
||||
model->LoadObj(filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find file extension
|
||||
size_t stringLength = strlen(filename);
|
||||
|
||||
for (int i = stringLength; i > 0; --i)
|
||||
{
|
||||
if (filename[i] == '.')
|
||||
{
|
||||
stringLength = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char* fileExtension = &filename[stringLength];
|
||||
|
||||
Msg("ModelSystem::LoadModel: Unknowed file format '%s'", filename, fileExtension);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ModelEntry entry = {};
|
||||
strcpy(entry.filename, filename);
|
||||
entry.model = model;
|
||||
|
||||
m_models.push_back(entry);
|
||||
|
||||
Msg("Loaded Model '%s'", filename);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
Model::Model()
|
||||
{
|
||||
m_data.vb = nullptr;
|
||||
m_data.ib = nullptr;
|
||||
m_AlbedoTexture = nullptr;
|
||||
|
||||
//m_boundingBox.min = glm::vec3(0.0f);
|
||||
//m_boundingBox.max = glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
m_AlbedoTexture = nullptr;
|
||||
|
||||
if (m_data.vb)
|
||||
{
|
||||
delete m_data.vb;
|
||||
m_data.vb = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Model::LoadObj(const char* filename)
|
||||
{
|
||||
Msg("Loading OBJ file %s...", filename);
|
||||
|
||||
std::vector<unsigned int> vertexIndices, uvIndices, normalIndices;
|
||||
std::vector<glm::vec3> temp_vertices;
|
||||
std::vector<glm::vec2> temp_uvs;
|
||||
std::vector<glm::vec3> temp_normals;
|
||||
|
||||
std::vector<glm::vec3> out_vertices;
|
||||
std::vector<glm::vec2> out_uvs;
|
||||
std::vector<glm::vec3> out_normals;
|
||||
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
Msg("Model::LoadObj: Impossible to open the file !");
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
char lineHeader[128];
|
||||
// read the first word of the line
|
||||
int res = fscanf(file, "%s", lineHeader);
|
||||
if (res == EOF)
|
||||
break; // EOF = End Of File. Quit the loop.
|
||||
|
||||
// else : parse lineHeader
|
||||
|
||||
if (strcmp(lineHeader, "v") == 0) {
|
||||
glm::vec3 vertex;
|
||||
fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
|
||||
temp_vertices.push_back(vertex);
|
||||
}
|
||||
else if (strcmp(lineHeader, "vt") == 0) {
|
||||
glm::vec2 uv;
|
||||
fscanf(file, "%f %f\n", &uv.x, &uv.y);
|
||||
uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders.
|
||||
temp_uvs.push_back(uv);
|
||||
}
|
||||
else if (strcmp(lineHeader, "vn") == 0) {
|
||||
glm::vec3 normal;
|
||||
fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
|
||||
temp_normals.push_back(normal);
|
||||
}
|
||||
else if (strcmp(lineHeader, "f") == 0) {
|
||||
std::string vertex1, vertex2, vertex3;
|
||||
unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
|
||||
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2]);
|
||||
if (matches != 9) {
|
||||
Msg("Model::LoadObj: File can't be read by our simple parser :-( Try exporting with other options");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
vertexIndices.push_back(vertexIndex[0]);
|
||||
vertexIndices.push_back(vertexIndex[1]);
|
||||
vertexIndices.push_back(vertexIndex[2]);
|
||||
uvIndices.push_back(uvIndex[0]);
|
||||
uvIndices.push_back(uvIndex[1]);
|
||||
uvIndices.push_back(uvIndex[2]);
|
||||
normalIndices.push_back(normalIndex[0]);
|
||||
normalIndices.push_back(normalIndex[1]);
|
||||
normalIndices.push_back(normalIndex[2]);
|
||||
}
|
||||
else {
|
||||
// Probably a comment, eat up the rest of the line
|
||||
char stupidBuffer[1000];
|
||||
fgets(stupidBuffer, 1000, file);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// For each vertex of each triangle
|
||||
for (unsigned int i = 0; i < vertexIndices.size(); i++) {
|
||||
|
||||
// Get the indices of its attributes
|
||||
unsigned int vertexIndex = vertexIndices[i];
|
||||
unsigned int uvIndex = uvIndices[i];
|
||||
unsigned int normalIndex = normalIndices[i];
|
||||
|
||||
// Get the attributes thanks to the index
|
||||
glm::vec3 vertex = temp_vertices[vertexIndex - 1];
|
||||
glm::vec2 uv = temp_uvs[uvIndex - 1];
|
||||
glm::vec3 normal = temp_normals[normalIndex - 1];
|
||||
|
||||
// Put the attributes in buffers
|
||||
out_vertices.push_back(vertex);
|
||||
out_uvs.push_back(uv);
|
||||
out_normals.push_back(normal);
|
||||
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
// Combine in to the one array
|
||||
std::vector<StaticMeshVertex> vertices;
|
||||
for (unsigned int i = 0; i < vertexIndices.size(); i++)
|
||||
{
|
||||
// Get the indices of its attributes
|
||||
unsigned int vertexIndex = vertexIndices[i];
|
||||
unsigned int uvIndex = uvIndices[i];
|
||||
unsigned int normalIndex = normalIndices[i];
|
||||
|
||||
// Get the attributes thanks to the index
|
||||
glm::vec3 vertex = temp_vertices[vertexIndex - 1];
|
||||
glm::vec2 uv = temp_uvs[uvIndex - 1];
|
||||
glm::vec3 normal = temp_normals[normalIndex - 1];
|
||||
|
||||
StaticMeshVertex vtx = {};
|
||||
vtx.position = vertex;
|
||||
vtx.normal = normal;
|
||||
vtx.texcoord = uv;
|
||||
vertices.push_back(vtx);
|
||||
|
||||
//m_boundingBox.min = glm::min(m_boundingBox.min, vertex);
|
||||
//m_boundingBox.max = glm::max(m_boundingBox.max, vertex);
|
||||
}
|
||||
|
||||
m_Vertices = vertices;
|
||||
|
||||
m_data.vb = g_pRenderDevice->CreateVertexBuffer(vertices.data(), (int)sizeof(StaticMeshVertex) * (int)vertices.size());
|
||||
m_data.vbcount = vertices.size();
|
||||
|
||||
std::string mtlfilename = getFileNameWithoutExtension(filename);
|
||||
mtlfilename += ".mtl";
|
||||
LoadMtl(mtlfilename.c_str());
|
||||
}
|
||||
|
||||
void Model::LoadMtl(const char* filename)
|
||||
{
|
||||
Msg("Loading MTL file %s...", filename);
|
||||
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
Msg("Model::LoadObj: Impossible to open the file !");
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
char lineHeader[128];
|
||||
// read the first word of the line
|
||||
int res = fscanf(file, "%s", lineHeader);
|
||||
if (res == EOF)
|
||||
break; // EOF = End Of File. Quit the loop.
|
||||
|
||||
if (strcmp(lineHeader, "map_Kd") == 0) {
|
||||
char stupidBuffer[1000];
|
||||
fgets(stupidBuffer, 1000, file);
|
||||
|
||||
const char* textureFilename = stupidBuffer + 1;
|
||||
m_AlbedoTexture = g_pTexturesManager->LoadTexture2D(textureFilename, true);
|
||||
}
|
||||
|
||||
//if (strcmp(lineHeader, "v") == 0) {
|
||||
// glm::vec3 vertex;
|
||||
// fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
|
||||
// temp_vertices.push_back(vertex);
|
||||
//}
|
||||
//else {
|
||||
// // Probably a comment, eat up the rest of the line
|
||||
// char stupidBuffer[1000];
|
||||
// fgets(stupidBuffer, 1000, file);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void Model::Draw(const glm::mat4& model, bool isTransparent /*= false*/)
|
||||
{
|
||||
if (!g_litShader)
|
||||
{
|
||||
g_litShader = g_pShaderSystem->CreateShader("lit_generic", "data/shaders/lit_generic.vs", "data/shaders/lit_generic.ps",
|
||||
g_staticVertexLayout, sizeof(g_staticVertexLayout) / sizeof(g_staticVertexLayout[0]));
|
||||
}
|
||||
|
||||
glFrontFace(GL_CCW);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
g_pRenderDevice->SetCullFace(true);
|
||||
g_pRenderDevice->SetDepthTest(true);
|
||||
g_pRenderDevice->SetDepthWrite(true);
|
||||
|
||||
if (isTransparent)
|
||||
{
|
||||
// Enable blending
|
||||
g_pRenderDevice->SetBlending(true);
|
||||
g_pRenderDevice->SetBlendingFunction(BF_SRC_ALPHA, BF_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glm::vec4 color = glm::vec4(1.f, 1.f, 1.f, .5f);
|
||||
g_pShaderSystem->SetUniformFloat4(g_litShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr(color));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pRenderDevice->SetBlending(false);
|
||||
|
||||
//glm::vec4 color = glm::vec4(1.f, 1.f, 1.f, 1.f);
|
||||
//g_pShaderSystem->SetUniformFloat4(g_litShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr(color));
|
||||
}
|
||||
|
||||
g_pRenderDevice->SetVerticesBuffer(m_data.vb);
|
||||
|
||||
g_pShaderSystem->SetShader(g_litShader);
|
||||
g_pShaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MODEL_MATRIX, &model[0]);
|
||||
|
||||
//static float test = 0.0f;
|
||||
//test += g_systemTimer->GetDelta() * 6.0f;
|
||||
|
||||
//glm::mat4 model = glm::mat4(1.0f);
|
||||
|
||||
//int32_t x = 0, y = 0;
|
||||
//g_inputSystem->GetMousePosition(&x, &y);
|
||||
//
|
||||
//glm::mat4 model = glm::mat4(1.0f);
|
||||
//model = glm::rotate(model, test, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
//
|
||||
//float realY = (float)g_renderView.height - (float)y - 1;
|
||||
//
|
||||
//glm::vec4 viewport = glm::vec4(0.0f, 0.0f, (float)g_renderView.width, (float)g_renderView.height);
|
||||
//glm::vec3 pos = glm::unProject(
|
||||
// glm::vec3((float)x, realY, 0.0f),
|
||||
// model,
|
||||
// g_renderView.proj,
|
||||
// viewport);
|
||||
//
|
||||
//pos *= 50.0f;
|
||||
//
|
||||
//model = glm::translate(model, pos);
|
||||
|
||||
glm::mat4 mvp = glm::identity<glm::mat4>();
|
||||
mvp = g_pRender->GetProjectionMatrix() * g_pRender->GetViewMatrix() * model;
|
||||
g_pShaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MVP_MATRIX, &mvp[0]);
|
||||
|
||||
g_pTexturesManager->SetTexture(0, m_AlbedoTexture);
|
||||
g_pShaderSystem->SetUniformSampler(g_litShader, SAMPLER_ALBEDO, 0);
|
||||
|
||||
g_pRenderDevice->DrawArrays(PT_TRIANGLES, 0, m_data.vbcount);
|
||||
|
||||
#if 0
|
||||
glm::mat4 mvp = glm::identity<glm::mat4>();
|
||||
mvp = g_renderView.proj * g_renderView.view * model;
|
||||
g_shaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MVP_MATRIX, &mvp[0]);
|
||||
|
||||
g_pTexturesManager->SetTexture(0, m_AlbedoTexture);
|
||||
g_shaderSystem->SetUniformSampler(g_litShader, SAMPLER_ALBEDO, 0);
|
||||
|
||||
g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_data.vbcount);
|
||||
|
||||
BoundingBox bbox = m_boundingBox;
|
||||
TransformBoundingBox(bbox, model);
|
||||
g_pDebugRender->DrawBoundingBox(bbox, glm::vec3(1.0f));
|
||||
#endif
|
||||
}
|
||||
|
||||
void ReleaseModelData(ModelData_t& data)
|
||||
{
|
||||
if (data.ib)
|
||||
{
|
||||
delete data.ib;
|
||||
data.ib = nullptr;
|
||||
}
|
||||
|
||||
if (data.vb)
|
||||
{
|
||||
delete data.vb;
|
||||
data.vb = nullptr;
|
||||
}
|
||||
}
|
||||
70
src/render/modelsystem.h
Normal file
70
src/render/modelsystem.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef MODELMANAGER_H
|
||||
#define MODELMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "render_shared.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
class GPUBuffer;
|
||||
class Texture2D;
|
||||
|
||||
struct ModelData_t
|
||||
{
|
||||
GPUBuffer* vb;
|
||||
GPUBuffer* ib;
|
||||
uint32_t vbcount;
|
||||
uint32_t ibcount;
|
||||
};
|
||||
|
||||
void ReleaseModelData(ModelData_t& data);
|
||||
|
||||
class Render;
|
||||
|
||||
class Model
|
||||
{
|
||||
friend class Render;
|
||||
public:
|
||||
Model();
|
||||
~Model();
|
||||
|
||||
void LoadObj(const char* filename);
|
||||
void LoadMtl(const char* filename);
|
||||
|
||||
void Draw(const glm::mat4& model, bool isTransparent = false);
|
||||
|
||||
//BoundingBox GetBoundingBox() { return m_boundingBox; }
|
||||
|
||||
private:
|
||||
std::vector<StaticMeshVertex> m_Vertices;
|
||||
ModelData_t m_data;
|
||||
//BoundingBox m_boundingBox;
|
||||
Texture2D* m_AlbedoTexture;
|
||||
};
|
||||
|
||||
class ModelSystem
|
||||
{
|
||||
public:
|
||||
ModelSystem();
|
||||
~ModelSystem();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
Model* LoadModel(const char* filename);
|
||||
|
||||
private:
|
||||
struct ModelEntry
|
||||
{
|
||||
char filename[260];
|
||||
Model* model;
|
||||
};
|
||||
|
||||
std::vector< ModelEntry > m_models;
|
||||
|
||||
};
|
||||
|
||||
extern ModelSystem* g_pModelSystem;
|
||||
|
||||
#endif // !MODELMANAGER_H
|
||||
266
src/render/render.cpp
Normal file
266
src/render/render.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
#include "core.h"
|
||||
#include "log.h"
|
||||
#include "render.h"
|
||||
#include "renderdevice.h"
|
||||
#include "texturesmanager.h"
|
||||
#include "shadersystem.h"
|
||||
#include "modelsystem.h"
|
||||
#include "debugrender.h"
|
||||
#include "ifilesystem.h"
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
static GLuint g_VAO = 0;
|
||||
|
||||
// TEMP
|
||||
glm::vec3 g_viewOrigin;
|
||||
glm::vec3 g_viewOrient;
|
||||
|
||||
#ifdef GL_DEBUG_OUTPUT
|
||||
#define GL_DEBUG_OUTPUT 0x92E0
|
||||
#endif // GL_DEBUG_OUTPUT
|
||||
|
||||
#ifndef GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB
|
||||
#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
|
||||
#endif // !GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB
|
||||
|
||||
#ifndef GL_DEBUG_TYPE_ERROR_ARB
|
||||
#define GL_DEBUG_TYPE_ERROR_ARB 0x824C
|
||||
#endif // !GL_DEBUG_TYPE_ERROR_ARB
|
||||
|
||||
#ifndef GL_ARB_debug_output
|
||||
#define GL_ARB_debug_output 1
|
||||
typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled);
|
||||
PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
|
||||
typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf);
|
||||
PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
|
||||
typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC)(GLDEBUGPROCARB callback, const void* userParam);
|
||||
PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
|
||||
typedef GLuint(APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC)(GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog);
|
||||
PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB;
|
||||
#endif
|
||||
|
||||
void APIENTRY GL_DebugOutput(GLenum source,
|
||||
GLenum type,
|
||||
unsigned int id,
|
||||
GLenum severity,
|
||||
GLsizei length,
|
||||
const char* message,
|
||||
const void* userParam)
|
||||
{
|
||||
// Nvidia spam too much about filenameBuffer mapping
|
||||
if (type == 0x8251)
|
||||
return;
|
||||
|
||||
Msg("OpenGL: %stype = 0x%x, severity = 0x%x, message = %s\n",
|
||||
(type == GL_DEBUG_TYPE_ERROR_ARB ? "** GL ERROR ** " : ""),
|
||||
type, severity, message);
|
||||
|
||||
if (type == GL_DEBUG_TYPE_ERROR_ARB)
|
||||
{
|
||||
bool debug = true;
|
||||
}
|
||||
}
|
||||
|
||||
Render* g_pRender = nullptr;
|
||||
|
||||
Render::Render() :
|
||||
m_pWindow(nullptr),
|
||||
m_pGLContext(nullptr),
|
||||
m_pStretchedPicVBuf(nullptr),
|
||||
m_sceneModel(nullptr),
|
||||
m_bUsingVAO(false)
|
||||
{
|
||||
m_ViewMatrix = glm::identity<glm::mat4>();
|
||||
m_ProjectionMatrix = glm::identity<glm::mat4>();
|
||||
}
|
||||
|
||||
Render::~Render()
|
||||
{
|
||||
}
|
||||
|
||||
void Render::Init(SDL_Window* pWindow)
|
||||
{
|
||||
m_pWindow = pWindow;
|
||||
SDL_assert(m_pWindow);
|
||||
|
||||
// Create OpenGL context
|
||||
m_pGLContext = SDL_GL_CreateContext(m_pWindow);
|
||||
SDL_GL_MakeCurrent(m_pWindow, m_pGLContext);
|
||||
|
||||
gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress);
|
||||
|
||||
if (GLVersion.major == 0 || GLVersion.minor == 0)
|
||||
{
|
||||
Core::Error("Failed to load OpenGL");
|
||||
}
|
||||
|
||||
// Core profile probably, should use VAO
|
||||
if (GLVersion.major >= 3 && GLVersion.minor >= 1)
|
||||
m_bUsingVAO = true;
|
||||
|
||||
Msg("%s", (const char*)glGetString(GL_VENDOR));
|
||||
Msg("%s", (const char*)glGetString(GL_RENDERER));
|
||||
Msg("OpenGL ver. %s", (const char*)glGetString(GL_VERSION));
|
||||
Msg("Context created with OpenGL version %d.%d", GLVersion.major, GLVersion.minor);
|
||||
|
||||
// Reset OpenGL error stack
|
||||
glGetError();
|
||||
|
||||
// Load extension
|
||||
glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
|
||||
|
||||
// Enable debug output
|
||||
if (glDebugMessageCallbackARB)
|
||||
{
|
||||
Msg("...found GL_ARB_debug_output");
|
||||
|
||||
//glEnable(GL_DEBUG_OUTPUT);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
||||
glDebugMessageCallbackARB(GL_DebugOutput, NULL);
|
||||
}
|
||||
|
||||
|
||||
// Create render device
|
||||
g_pRenderDevice = new RenderDevice();
|
||||
|
||||
// Create texture manager
|
||||
g_pTexturesManager = new TexturesManager();
|
||||
g_pTexturesManager->Init();
|
||||
|
||||
// Create shader system
|
||||
g_pShaderSystem = new ShaderSystem();
|
||||
g_pShaderSystem->Init();
|
||||
|
||||
// Create model system
|
||||
g_pModelSystem = new ModelSystem();
|
||||
|
||||
// Create debug render
|
||||
g_pDebugRender = new DebugRender();
|
||||
g_pDebugRender->Initialize();
|
||||
|
||||
// Create stretched picture filenameBuffer
|
||||
m_pStretchedPicVBuf = g_pRenderDevice->CreateVertexBuffer(nullptr, MAX_STRETCH_VX, true);
|
||||
|
||||
// Core profile require Vertex Array Object to render
|
||||
if (m_bUsingVAO)
|
||||
{
|
||||
// Create global vertex array
|
||||
glGenVertexArrays(1, &g_VAO);
|
||||
glBindVertexArray(g_VAO);
|
||||
}
|
||||
}
|
||||
|
||||
void Render::Shutdown()
|
||||
{
|
||||
if (m_bUsingVAO)
|
||||
{
|
||||
glBindVertexArray(0);
|
||||
glDeleteVertexArrays(1, &g_VAO);
|
||||
}
|
||||
|
||||
delete m_pStretchedPicVBuf;
|
||||
m_pStretchedPicVBuf = nullptr;
|
||||
|
||||
g_pDebugRender->Shutdown();
|
||||
delete g_pDebugRender;
|
||||
g_pDebugRender = nullptr;
|
||||
|
||||
g_pModelSystem->Shutdown();
|
||||
delete g_pModelSystem;
|
||||
g_pModelSystem = nullptr;
|
||||
|
||||
g_pShaderSystem->Shutdown();
|
||||
delete g_pShaderSystem;
|
||||
g_pShaderSystem = nullptr;
|
||||
|
||||
g_pTexturesManager->Shutdown();
|
||||
delete g_pTexturesManager;
|
||||
g_pTexturesManager = nullptr;
|
||||
|
||||
delete g_pRenderDevice;
|
||||
g_pRenderDevice = nullptr;
|
||||
|
||||
// Destroy OpenGL context
|
||||
SDL_GL_MakeCurrent(nullptr, nullptr);
|
||||
SDL_GL_DestroyContext(m_pGLContext);
|
||||
m_pGLContext = nullptr;
|
||||
}
|
||||
|
||||
void Render::RenderScene()
|
||||
{
|
||||
if (m_sceneModel) {
|
||||
static glm::mat4 s_identity = glm::mat4(1.0f);
|
||||
m_sceneModel->Draw(s_identity);
|
||||
}
|
||||
|
||||
g_pDebugRender->RenderFrame();
|
||||
}
|
||||
|
||||
void Render::Present(bool vsync)
|
||||
{
|
||||
SDL_GL_SwapWindow(m_pWindow);
|
||||
}
|
||||
|
||||
void Render::ResetStates()
|
||||
{
|
||||
g_pRenderDevice->SetDepthTest(true);
|
||||
g_pRenderDevice->SetDepthWrite(true);
|
||||
g_pRenderDevice->SetStencilTest(false);
|
||||
g_pRenderDevice->SetScissorTest(false);
|
||||
g_pRenderDevice->SetCullFace(false);
|
||||
g_pRenderDevice->SetBlending(false);
|
||||
}
|
||||
|
||||
void Render::SetViewMatrix(const glm::mat4& matView)
|
||||
{
|
||||
m_ViewMatrix = matView;
|
||||
}
|
||||
|
||||
void Render::SetProjectionMatrix(const glm::mat4& matProjection)
|
||||
{
|
||||
m_ProjectionMatrix = matProjection;
|
||||
}
|
||||
|
||||
void Render::LoadSceneXML(const char* filename)
|
||||
{
|
||||
char filenameBuffer[kMaxPathLength];
|
||||
snprintf(filenameBuffer, kMaxPathLength, "data/levels/%s/%s.xml", filename, filename);
|
||||
|
||||
FileHandle_t file = GetFileSystem()->OpenFile(filenameBuffer, "rb");
|
||||
SDL_assert_always(file != kInvalidFileHandleValue);
|
||||
|
||||
size_t length = GetFileSystem()->GetFileLength(file);
|
||||
|
||||
char* filedata = new char[length + 1];
|
||||
GetFileSystem()->ReadFile(file, filedata, length);
|
||||
filedata[length] = '\0';
|
||||
|
||||
GetFileSystem()->CloseFile(file);
|
||||
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_buffer(filedata, length);
|
||||
delete[] filedata;
|
||||
if (!result) {
|
||||
Core::Error("Render::LoadSceneXML: Error while reading level description file '%s'\nError: %s:%i",
|
||||
filenameBuffer, result.description(), result.offset);
|
||||
}
|
||||
|
||||
pugi::xml_node root = doc.document_element();
|
||||
const char* scenefilename = root.child("SceneFile").attribute("filename").value();
|
||||
|
||||
sprintf(filenameBuffer, "data/levels/%s/%s", filename, scenefilename);
|
||||
|
||||
if (!GetFileSystem()->IsExist(filenameBuffer)) {
|
||||
Core::Error("SceneManager::LoadScene: scene file '%s' doesnt exist", scenefilename);
|
||||
}
|
||||
|
||||
m_sceneFilename = filenameBuffer;
|
||||
|
||||
m_sceneModel = g_pModelSystem->LoadModel(m_sceneFilename.c_str());
|
||||
}
|
||||
|
||||
//IRender* GetRender()
|
||||
//{
|
||||
// return g_pRender;
|
||||
//}
|
||||
58
src/render/render.h
Normal file
58
src/render/render.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef RENDER_H
|
||||
#define RENDER_H
|
||||
|
||||
#include "gl_shared.h"
|
||||
#include "render_shared.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class GPUBuffer;
|
||||
class Model;
|
||||
|
||||
class Render
|
||||
{
|
||||
public:
|
||||
Render();
|
||||
~Render();
|
||||
|
||||
void Init(SDL_Window* pWindow);
|
||||
void Shutdown();
|
||||
|
||||
void RenderScene();
|
||||
|
||||
void Present(bool vsync = false);
|
||||
|
||||
void ResetStates();
|
||||
|
||||
void SetViewMatrix(const glm::mat4& matView);
|
||||
void SetProjectionMatrix(const glm::mat4& matProjection);
|
||||
|
||||
inline const glm::mat4& GetViewMatrix() { return m_ViewMatrix; }
|
||||
inline const glm::mat4& GetProjectionMatrix() { return m_ProjectionMatrix; }
|
||||
|
||||
void LoadSceneXML(const char* filename);
|
||||
|
||||
private:
|
||||
glm::mat4 m_ViewMatrix;
|
||||
glm::mat4 m_ProjectionMatrix;
|
||||
|
||||
SDL_Window* m_pWindow;
|
||||
SDL_GLContext m_pGLContext;
|
||||
|
||||
GPUBuffer* m_pStretchedPicVBuf;
|
||||
|
||||
std::string m_sceneFilename;
|
||||
std::string m_sceneName;
|
||||
|
||||
Model* m_sceneModel;
|
||||
|
||||
bool m_bUsingVAO;
|
||||
};
|
||||
|
||||
extern Render* g_pRender;
|
||||
|
||||
// TEMP
|
||||
extern glm::vec3 g_viewOrigin;
|
||||
extern glm::vec3 g_viewOrient;
|
||||
|
||||
#endif // !RENDER_H
|
||||
240
src/render/render_shared.h
Normal file
240
src/render/render_shared.h
Normal file
@@ -0,0 +1,240 @@
|
||||
// Shared header for render subsystem
|
||||
#ifndef RENDER_SHARED_H
|
||||
#define RENDER_SHARED_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
typedef uint32_t index_t;
|
||||
|
||||
enum BufferType
|
||||
{
|
||||
BT_VERTEX,
|
||||
BT_INDEX,
|
||||
|
||||
BT_MAX
|
||||
};
|
||||
|
||||
enum BufferAccess
|
||||
{
|
||||
BA_READ_ONLY,
|
||||
BA_WRITE_ONLY,
|
||||
BA_READ_WRITE,
|
||||
|
||||
BA_MAX
|
||||
};
|
||||
|
||||
// texture format
|
||||
enum PixelFormat
|
||||
{
|
||||
PF_UNKNOWN,
|
||||
PF_R8G8B8,
|
||||
PF_R8G8B8A8,
|
||||
PF_R8G8B8F,
|
||||
PF_R8G8B8A8F,
|
||||
|
||||
// Depth formats
|
||||
PF_DEPTH32F
|
||||
};
|
||||
|
||||
// Blending functions
|
||||
enum BlendFactor
|
||||
{
|
||||
BF_ZERO,
|
||||
BF_ONE,
|
||||
BF_SRC_COLOR,
|
||||
BF_ONE_MINUS_SRC_COLOR,
|
||||
BF_DST_COLOR,
|
||||
BF_ONE_MINUS_DST_COLOR,
|
||||
BF_SRC_ALPHA,
|
||||
BF_ONE_MINUS_SRC_ALPHA,
|
||||
BF_DST_ALPHA,
|
||||
BF_ONE_MINUS_DST_ALPHA,
|
||||
BF_CONSTANT_COLOR,
|
||||
BF_ONE_MINUS_CONSTANT_COLOR,
|
||||
BF_CONSTANT_ALPHA,
|
||||
BF_ONE_MINUS_CONSTANT_ALPHA
|
||||
};
|
||||
|
||||
enum BlendEquation
|
||||
{
|
||||
BE_FUNC_ADD,
|
||||
BE_FUNC_SUBTRACT,
|
||||
BE_FUNC_REVERSE_SUBTRACT,
|
||||
BE_MIN,
|
||||
BE_MAX
|
||||
};
|
||||
|
||||
enum DepthFunc
|
||||
{
|
||||
DF_NEVER, // Never passes.
|
||||
DF_LESS, // Passes if the incoming depth value is less than the stored depth value.
|
||||
DF_EQUAL, // Passes if the incoming depth value is equal to the stored depth value.
|
||||
DF_LEQUAL, // Passes if the incoming depth value is less than or equal to the stored depth value.
|
||||
DF_GREATER, // Passes if the incoming depth value is greater than the stored depth value.
|
||||
DF_NOTEQUAL, // Passes if the incoming depth value is not equal to the stored depth value.
|
||||
DF_GEQUAL, // Passes if the incoming depth value is greater than or equal to the stored depth value.
|
||||
DF_ALWAYS, // Always passes.
|
||||
DF_MAX
|
||||
};
|
||||
|
||||
enum TextureWrap
|
||||
{
|
||||
TextureWrap_Repeat,
|
||||
TextureWrap_MirroredRepeat,
|
||||
TextureWrap_ClampToEdge,
|
||||
TextureWrap_ClampToBorder
|
||||
};
|
||||
|
||||
enum TextureFilter
|
||||
{
|
||||
TextureFilter_Nearest,
|
||||
TextureFilter_Linear,
|
||||
TextureFilter_NearestMipmapNearest,
|
||||
TextureFilter_LinearMipmapNearest,
|
||||
TextureFilter_NearestMipmapLinear,
|
||||
TextureFilter_LinearMipmapLinear
|
||||
};
|
||||
|
||||
enum TextureSurfaceType
|
||||
{
|
||||
TST_COLOR = 1 << 0,
|
||||
TST_DEPTH = 1 << 1,
|
||||
TST_STENCIL = 1 << 2,
|
||||
};
|
||||
|
||||
enum PrimitiveType
|
||||
{
|
||||
PT_POINTS,
|
||||
PT_LINES,
|
||||
PT_TRIANGLES
|
||||
};
|
||||
|
||||
// pixel format convertion
|
||||
uint32_t GetGLPF(PixelFormat pf);
|
||||
uint32_t GetGLInternalPF(PixelFormat pf);
|
||||
uint32_t GetGLTypePF(PixelFormat pf);
|
||||
|
||||
// Wrapping and Filter convertion
|
||||
int getGlWrap(TextureWrap wrap);
|
||||
int getGlTexFilter(TextureFilter filter);
|
||||
|
||||
uint32_t GetGLDepthFunc(DepthFunc func);
|
||||
|
||||
// Blending factor convertion
|
||||
uint32_t GetGLBlendFactor(BlendFactor factor);
|
||||
|
||||
// Blending equation convertion
|
||||
uint32_t GetGLEquation(BlendEquation equation);
|
||||
|
||||
struct Viewport
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
// Base structure for render view (view and projection matrices, viewport settings)
|
||||
struct View
|
||||
{
|
||||
//glm::mat4 view;
|
||||
//glm::mat4 proj;
|
||||
|
||||
int x, y;
|
||||
int width, height;
|
||||
|
||||
float fov;
|
||||
bool ortho;
|
||||
};
|
||||
|
||||
// Stretched picture vertex
|
||||
struct StretchedVertex
|
||||
{
|
||||
glm::vec3 position;
|
||||
glm::vec2 texcoord;
|
||||
glm::vec4 color;
|
||||
};
|
||||
|
||||
#define MAX_STRETCH_VX 12 * sizeof(StretchedVertex)
|
||||
|
||||
const int SHADERUNIFORM_MAX_COUNT = 16;
|
||||
const int INPUT_LAYOUT_MAX_COUNT = 8;
|
||||
|
||||
enum VertexAttribute_t {
|
||||
VERTEXATTR_VEC2,
|
||||
VERTEXATTR_VEC3,
|
||||
VERTEXATTR_VEC4,
|
||||
VERTEXATTR_UINT,
|
||||
|
||||
VERTEXATTR_MAX
|
||||
};
|
||||
|
||||
enum ShaderSemantic_t {
|
||||
SHADERSEMANTIC_POSITION,
|
||||
SHADERSEMANTIC_COLOR,
|
||||
SHADERSEMANTIC_TEXCOORD,
|
||||
SHADERSEMANTIC_TEXCOORD0,
|
||||
SHADERSEMANTIC_TEXCOORD1,
|
||||
SHADERSEMANTIC_NORMAL,
|
||||
SHADERSEMANTIC_TANGENT,
|
||||
SHADERSEMANTIC_BITANGENT,
|
||||
SHADERSEMANTIC_BONEIDS,
|
||||
SHADERSEMANTIC_WEIGHTS,
|
||||
|
||||
SHADERSEMANTIC_MAX
|
||||
};
|
||||
|
||||
enum ShaderUniformType_t {
|
||||
SHADERUNIFORM_FLOAT,
|
||||
SHADERUNIFORM_VEC2,
|
||||
SHADERUNIFORM_VEC3,
|
||||
SHADERUNIFORM_VEC4,
|
||||
SHADERUNIFORM_MAT4,
|
||||
|
||||
SHADERUNIFORM_MAX
|
||||
};
|
||||
|
||||
enum ShaderUniform_t
|
||||
{
|
||||
UNIFORM_MODEL_MATRIX,
|
||||
UNIFORM_VIEW_MATRIX,
|
||||
UNIFORM_PROJ_MATRIX,
|
||||
UNIFORM_MVP_MATRIX,
|
||||
UNIFORM_CUSTOM_COLOR,
|
||||
UNIFORM_SUN_DIRECTION,
|
||||
UNIFORM_SUN_COLOR,
|
||||
UNIFORM_SUN_AMBIENT,
|
||||
|
||||
UNIFORM_MAX,
|
||||
};
|
||||
|
||||
enum ShaderSamplers_t
|
||||
{
|
||||
SAMPLER_ALBEDO,
|
||||
SAMPLER_NORMAL,
|
||||
SAMPLER_LIGHTMAP,
|
||||
|
||||
SAMPLER_MAX
|
||||
};
|
||||
|
||||
struct InputLayoutDesc_t {
|
||||
VertexAttribute_t attribute;
|
||||
ShaderSemantic_t semantic;
|
||||
};
|
||||
|
||||
struct ShaderUniformDesc_t {
|
||||
ShaderUniformType_t type;
|
||||
const char* name;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct StaticMeshVertex
|
||||
{
|
||||
glm::vec3 position;
|
||||
glm::vec3 normal;
|
||||
glm::vec2 texcoord;
|
||||
};
|
||||
|
||||
#endif
|
||||
162
src/render/renderdevice.cpp
Normal file
162
src/render/renderdevice.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// OpenGL
|
||||
#include "gl_shared.h"
|
||||
|
||||
#include "gpu_buffer.h"
|
||||
#include "renderdevice.h"
|
||||
|
||||
static GLenum g_glPrimitiveMode[PT_TRIANGLES + 1] = {
|
||||
GL_POINTS,
|
||||
GL_LINES,
|
||||
GL_TRIANGLES
|
||||
};
|
||||
|
||||
// The render device instance.
|
||||
RenderDevice* g_pRenderDevice = nullptr;
|
||||
|
||||
RenderDevice::RenderDevice()
|
||||
{
|
||||
m_activeVB = nullptr;
|
||||
m_activeIB = nullptr;
|
||||
m_blending = false;
|
||||
m_activeReadRT = nullptr;
|
||||
m_activeWriteRT = nullptr;
|
||||
}
|
||||
|
||||
RenderDevice::~RenderDevice()
|
||||
{
|
||||
}
|
||||
|
||||
GPUBuffer* RenderDevice::CreateVertexBuffer(void* data, size_t size, bool isStream)
|
||||
{
|
||||
return new GPUBuffer(BT_VERTEX, data, size, isStream);
|
||||
}
|
||||
|
||||
GPUBuffer* RenderDevice::CreateIndexBuffer(void* data, size_t size, bool isStream)
|
||||
{
|
||||
return new GPUBuffer(BT_INDEX, data, size, isStream);
|
||||
}
|
||||
|
||||
void RenderDevice::SetVerticesBuffer(GPUBuffer* buffer)
|
||||
{
|
||||
if (buffer) {
|
||||
if (m_activeVB != buffer) {
|
||||
m_activeVB = buffer;
|
||||
m_activeVB->Bind();
|
||||
}
|
||||
} else { // unbind buffer
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderDevice::SetIndicesBuffer(GPUBuffer* buffer)
|
||||
{
|
||||
if (buffer) {
|
||||
if (m_activeIB != buffer) {
|
||||
m_activeIB = buffer;
|
||||
m_activeIB->Bind();
|
||||
}
|
||||
} else { // unbind buffer
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderDevice::SetDepthTest(bool enable)
|
||||
{
|
||||
enable ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void RenderDevice::SetDepthWrite(bool enable)
|
||||
{
|
||||
glDepthMask(enable ? GL_TRUE : GL_FALSE);
|
||||
}
|
||||
|
||||
void RenderDevice::SetStencilTest(bool enable)
|
||||
{
|
||||
enable ? glEnable(GL_STENCIL_TEST) : glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
void RenderDevice::SetScissorTest(bool enable)
|
||||
{
|
||||
enable ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void RenderDevice::SetCullFace(bool enable)
|
||||
{
|
||||
enable ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
void RenderDevice::SetBlending(bool value)
|
||||
{
|
||||
if (m_blending != value) {
|
||||
m_blending = value;
|
||||
|
||||
value ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderDevice::SetBlendingFunction(BlendFactor srcFactor, BlendFactor destFactor)
|
||||
{
|
||||
// Switch state if one of two blending factors was changed
|
||||
if (srcFactor != m_srcBlendFactor || destFactor != m_destBlendFactor)
|
||||
{
|
||||
m_srcBlendFactor = srcFactor;
|
||||
m_destBlendFactor = destFactor;
|
||||
|
||||
// push to gl state
|
||||
glBlendFunc(GetGLBlendFactor(srcFactor), GetGLBlendFactor(destFactor));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderDevice::SetBlendFuncSeparate(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha)
|
||||
{
|
||||
glBlendFuncSeparate(GetGLBlendFactor(srcRGB), GetGLBlendFactor(dstRGB),
|
||||
GetGLBlendFactor(srcAlpha), GetGLBlendFactor(dstAlpha));
|
||||
}
|
||||
|
||||
void RenderDevice::SetBlendEquation(BlendEquation equation)
|
||||
{
|
||||
glBlendEquation(GetGLEquation(equation));
|
||||
}
|
||||
|
||||
void RenderDevice::SetViewport(int x, int y, int w, int h)
|
||||
{
|
||||
glViewport(x, y, w, h);
|
||||
}
|
||||
|
||||
void RenderDevice::Clear(uint32_t surfaces, float r, float g, float b, float a, float z, uint32_t stencil)
|
||||
{
|
||||
GLenum flags = 0;
|
||||
|
||||
if (surfaces & TST_COLOR)
|
||||
{
|
||||
flags |= GL_COLOR_BUFFER_BIT;
|
||||
glClearColor(r, g, b, a);
|
||||
}
|
||||
|
||||
if (surfaces & TST_DEPTH)
|
||||
{
|
||||
flags |= GL_DEPTH_BUFFER_BIT;
|
||||
glClearDepth(z);
|
||||
}
|
||||
|
||||
if (surfaces & TST_STENCIL)
|
||||
{
|
||||
flags |= GL_STENCIL_BUFFER_BIT;
|
||||
glClearStencil((GLint)stencil);
|
||||
}
|
||||
|
||||
glClear(flags);
|
||||
}
|
||||
|
||||
void RenderDevice::DrawArrays(PrimitiveType primType, uint32_t startOf, size_t verticesCount)
|
||||
{
|
||||
glDrawArrays(g_glPrimitiveMode[primType], startOf, GLsizei(verticesCount));
|
||||
}
|
||||
|
||||
void RenderDevice::DrawElements(PrimitiveType primType, size_t elementsCount, bool is16bitIndices)
|
||||
{
|
||||
glDrawElements(g_glPrimitiveMode[primType], GLsizei(elementsCount), is16bitIndices ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, NULL);
|
||||
}
|
||||
59
src/render/renderdevice.h
Normal file
59
src/render/renderdevice.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef RENDERDEVICE_H
|
||||
#define RENDERDEVICE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "render_shared.h"
|
||||
|
||||
class GPUBuffer;
|
||||
class VertexFormat;
|
||||
class RenderTarget;
|
||||
|
||||
class RenderDevice
|
||||
{
|
||||
public:
|
||||
RenderDevice();
|
||||
~RenderDevice();
|
||||
|
||||
GPUBuffer* CreateVertexBuffer(void* data, size_t size, bool isStream = false);
|
||||
GPUBuffer* CreateIndexBuffer(void* data, size_t size, bool isStream = false);
|
||||
|
||||
void SetVerticesBuffer(GPUBuffer* buffer);
|
||||
void SetIndicesBuffer(GPUBuffer* buffer);
|
||||
|
||||
void SetDepthTest(bool enable);
|
||||
void SetDepthWrite(bool enable);
|
||||
|
||||
void SetStencilTest(bool enable);
|
||||
|
||||
void SetScissorTest(bool enable);
|
||||
|
||||
void SetCullFace(bool enable);
|
||||
|
||||
void SetBlending(bool value);
|
||||
void SetBlendingFunction(BlendFactor srcFactor, BlendFactor destFactor);
|
||||
void SetBlendFuncSeparate(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha);
|
||||
void SetBlendEquation(BlendEquation equation);
|
||||
|
||||
void SetViewport(int x, int y, int w, int h);
|
||||
|
||||
void Clear(uint32_t surfaces, float r, float g, float b, float a, float z, uint32_t stencil);
|
||||
|
||||
// drawing
|
||||
void DrawArrays(PrimitiveType primType, uint32_t startOf, size_t verticesCount);
|
||||
void DrawElements(PrimitiveType primType, size_t elementsCount, bool is16bitIndices);
|
||||
|
||||
private:
|
||||
GPUBuffer* m_activeVB;
|
||||
GPUBuffer* m_activeIB;
|
||||
|
||||
RenderTarget* m_activeReadRT;
|
||||
RenderTarget* m_activeWriteRT;
|
||||
|
||||
bool m_blending;
|
||||
BlendFactor m_srcBlendFactor;
|
||||
BlendFactor m_destBlendFactor;
|
||||
};
|
||||
|
||||
extern RenderDevice* g_pRenderDevice;
|
||||
|
||||
#endif // !RENDERDEVICE_H
|
||||
89
src/render/shader.cpp
Normal file
89
src/render/shader.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "shader.h"
|
||||
#include "ifilesystem.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
GLuint CreateShader(GLenum shaderType, const char* filename)
|
||||
{
|
||||
FileHandle_t file = GetFileSystem()->OpenFile(filename, "rb");
|
||||
if (file == kInvalidFileHandleValue)
|
||||
{
|
||||
Msg("CreateShader: failed to open file %s", filename);
|
||||
}
|
||||
|
||||
size_t length = GetFileSystem()->GetFileLength(file);
|
||||
|
||||
std::string content;
|
||||
content.resize(length + 1);
|
||||
GetFileSystem()->ReadFile(file, (void*)content.data(), length);
|
||||
|
||||
content[length] = '\0';
|
||||
|
||||
GetFileSystem()->CloseFile(file);
|
||||
|
||||
const char* contentCStr = content.c_str();
|
||||
|
||||
GLuint shader = glCreateShader(shaderType);
|
||||
glShaderSource(shader, 1, &contentCStr, NULL);
|
||||
glCompileShader(shader);
|
||||
|
||||
int success;
|
||||
char infoLog[512];
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
glGetShaderInfoLog(shader, 512, NULL, infoLog);
|
||||
Msg("Failed to compile shader %s\n%s", filename, infoLog);
|
||||
}
|
||||
|
||||
Msg("created shader from file %s", filename);
|
||||
return shader;
|
||||
}
|
||||
|
||||
Shader::Shader() :
|
||||
m_stride(0),
|
||||
m_layoutCount(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Shader::Create(const char* name, const char* vsfilepath, const char* psfilepath)
|
||||
{
|
||||
m_name = name;
|
||||
|
||||
GLuint vertexShader = CreateShader(GL_VERTEX_SHADER, vsfilepath);
|
||||
GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER, psfilepath);
|
||||
|
||||
m_program = glCreateProgram();
|
||||
glAttachShader(m_program, vertexShader);
|
||||
glAttachShader(m_program, fragmentShader);
|
||||
AllocateAttributes();
|
||||
glLinkProgram(m_program);
|
||||
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
|
||||
int success;
|
||||
char infoLog[512];
|
||||
glGetProgramiv(m_program, GL_LINK_STATUS, &success);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
glGetProgramInfoLog(m_program, 512, NULL, infoLog);
|
||||
Msg("Failed to link program %s", infoLog);
|
||||
}
|
||||
|
||||
AllocateUniforms();
|
||||
}
|
||||
|
||||
void Shader::Destroy()
|
||||
{
|
||||
glDeleteProgram(m_program);
|
||||
}
|
||||
65
src/render/shader.h
Normal file
65
src/render/shader.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef SHADER_H
|
||||
#define SHADER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "render_shared.h"
|
||||
#include "gl_shared.h"
|
||||
|
||||
class ShaderSystem;
|
||||
|
||||
class Shader
|
||||
{
|
||||
friend class ShaderSystem;
|
||||
public:
|
||||
Shader();
|
||||
~Shader();
|
||||
|
||||
void Create(const char* name, const char* vsfilepath, const char* psfilepath);
|
||||
void Destroy();
|
||||
|
||||
void AllocateAttributes();
|
||||
void AllocateUniforms();
|
||||
|
||||
bool HasUniform(ShaderUniform_t uniform) { return m_glUniformLocation[uniform] != -1; }
|
||||
|
||||
const std::string& GetName() const { return m_name; }
|
||||
|
||||
private:
|
||||
// TEMP SOLUTION
|
||||
ShaderUniformDesc_t m_uniformDesc[SHADERUNIFORM_MAX_COUNT];
|
||||
size_t m_uniformCount;
|
||||
|
||||
InputLayoutDesc_t m_layouts[INPUT_LAYOUT_MAX_COUNT];
|
||||
size_t m_layoutCount;
|
||||
|
||||
GLint m_glUniformLocation[SHADERSEMANTIC_MAX];
|
||||
GLint m_glSamplerLocation[SAMPLER_MAX];
|
||||
|
||||
GLuint m_glLayouts[INPUT_LAYOUT_MAX_COUNT];
|
||||
|
||||
std::string m_name;
|
||||
|
||||
int m_stride;
|
||||
|
||||
GLuint m_program;
|
||||
};
|
||||
|
||||
inline int GetVertexAttributeSize( VertexAttribute_t attrib )
|
||||
{
|
||||
switch ( attrib )
|
||||
{
|
||||
case VERTEXATTR_VEC2:
|
||||
return 2;
|
||||
case VERTEXATTR_VEC3:
|
||||
return 3;
|
||||
case VERTEXATTR_VEC4:
|
||||
return 4;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // !SHADER_H
|
||||
188
src/render/shadersystem.cpp
Normal file
188
src/render/shadersystem.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include "shadersystem.h"
|
||||
#include "shader.h"
|
||||
#include "gl_shared.h"
|
||||
|
||||
static const char* g_uniformNameTable[UNIFORM_MAX] =
|
||||
{
|
||||
"u_modelMatrix",
|
||||
"u_viewMatrix",
|
||||
"u_projectionMatrix",
|
||||
"u_modelViewProjection",
|
||||
"u_customColor",
|
||||
"u_sunDirection",
|
||||
"u_sunColor",
|
||||
"u_sunAmbientColor",
|
||||
};
|
||||
|
||||
static const char* g_samplersNameTable[SAMPLER_MAX] =
|
||||
{
|
||||
"u_albedoTexture",
|
||||
"u_normalTexture",
|
||||
"u_lightmapTexture",
|
||||
};
|
||||
|
||||
static const char* g_attributeNameTable[SHADERSEMANTIC_MAX] =
|
||||
{
|
||||
"a_position",//SHADERSEMANTIC_POSITION,
|
||||
"a_color", //SHADERSEMANTIC_COLOR
|
||||
"a_texcoord",//SHADERSEMANTIC_TEXCOORD,
|
||||
"a_texcoord0", //SHADERSEMANTIC_TEXCOORD0,
|
||||
"a_texcoord1",//SHADERSEMANTIC_TEXCOORD1,
|
||||
"a_normal",//SHADERSEMANTIC_NORMAL,
|
||||
"a_tangent",//SHADERSEMANTIC_TANGENT,
|
||||
"a_bitangent",//SHADERSEMANTIC_BITANGENT,
|
||||
"a_boneIds",//SHADERSEMANTIC_BONEIDS,
|
||||
"a_weights"//SHADERSEMANTIC_WEIGHTS,
|
||||
};
|
||||
|
||||
static size_t g_attributeSizeTable[VERTEXATTR_MAX] =
|
||||
{
|
||||
sizeof(float) * 2,//VERTEXATTR_VEC2,
|
||||
sizeof(float) * 3,//VERTEXATTR_VEC3,
|
||||
sizeof(float) * 4,//VERTEXATTR_VEC4,
|
||||
sizeof(unsigned int)//VERTEXATTR_UINT
|
||||
};
|
||||
|
||||
size_t g_vertexAttribsSizeTable[VERTEXATTR_MAX] =
|
||||
{
|
||||
2, // VERTEXATTR_VEC2
|
||||
3, // VERTEXATTR_VEC3
|
||||
4, // VERTEXATTR_VEC4
|
||||
4, // VERTEXATTR_UINT
|
||||
};
|
||||
|
||||
size_t g_vertexAttribsRealSizeTable[VERTEXATTR_MAX] =
|
||||
{
|
||||
8, // VERTEXATTR_VEC2
|
||||
12, // VERTEXATTR_VEC3
|
||||
16, // VERTEXATTR_VEC4
|
||||
4, // VERTEXATTR_UINT
|
||||
};
|
||||
|
||||
ShaderSystem* g_pShaderSystem = nullptr;
|
||||
|
||||
ShaderSystem::ShaderSystem()
|
||||
{
|
||||
}
|
||||
|
||||
ShaderSystem::~ShaderSystem()
|
||||
{
|
||||
}
|
||||
|
||||
void ShaderSystem::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void ShaderSystem::Shutdown()
|
||||
{
|
||||
for (int i = 0; i < m_shaders.size(); i++)
|
||||
{
|
||||
if (m_shaders[i])
|
||||
{
|
||||
delete m_shaders[i];
|
||||
m_shaders[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
m_shaders.clear();
|
||||
}
|
||||
|
||||
Shader* ShaderSystem::CreateShader(const char* name, const char* vsfilepath, const char* psfilepath, InputLayoutDesc_t* inputLayout /*= nullptr*/, int inputLayoutCount/* = 0*/)
|
||||
{
|
||||
auto it = std::find_if(m_shaders.begin(), m_shaders.end(), [=](const Shader* shader) { return shader->GetName() == name; });
|
||||
if ( it != m_shaders.end() )
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
|
||||
Shader* pShader = new Shader();
|
||||
|
||||
if ( inputLayout && inputLayoutCount > 0 )
|
||||
{
|
||||
memcpy( pShader->m_layouts, inputLayout, inputLayoutCount * sizeof( InputLayoutDesc_t ) );
|
||||
pShader->m_layoutCount = inputLayoutCount;
|
||||
}
|
||||
|
||||
pShader->Create( name, vsfilepath, psfilepath );
|
||||
|
||||
m_shaders.push_back(pShader);
|
||||
|
||||
return pShader;
|
||||
}
|
||||
|
||||
void ShaderSystem::SetShader(const Shader* shader)
|
||||
{
|
||||
SDL_assert( shader );
|
||||
glUseProgram( shader->m_program );
|
||||
|
||||
// apply input layout
|
||||
|
||||
size_t appliedOffset = 0;
|
||||
for (int i = 0; i < shader->m_layoutCount; i++)
|
||||
{
|
||||
const InputLayoutDesc_t* layoutEntry = &shader->m_layouts[i];
|
||||
|
||||
glEnableVertexAttribArray(GLuint(i));
|
||||
|
||||
if (layoutEntry->attribute == VERTEXATTR_UINT)
|
||||
{
|
||||
glVertexAttribPointer(GLuint(i), GLint(g_vertexAttribsSizeTable[layoutEntry->attribute]),
|
||||
GL_UNSIGNED_BYTE, GL_TRUE, static_cast<GLsizei>(shader->m_stride),
|
||||
(appliedOffset > 0) ? (void*)(appliedOffset * sizeof(unsigned int)) : (void*)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glVertexAttribPointer(GLuint(i), GLint(g_vertexAttribsSizeTable[layoutEntry->attribute]),
|
||||
GL_FLOAT, GL_FALSE, static_cast<GLsizei>(shader->m_stride),
|
||||
(appliedOffset > 0) ? (void*)(appliedOffset * sizeof(float)) : (void*)0);
|
||||
}
|
||||
|
||||
appliedOffset += g_vertexAttribsSizeTable[layoutEntry->attribute];
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderSystem::SetUniformSampler(const Shader* shader, ShaderSamplers_t sampler, int index)
|
||||
{
|
||||
glUniform1i( shader->m_glSamplerLocation[ sampler ], static_cast< GLint >(index) );
|
||||
}
|
||||
|
||||
void ShaderSystem::SetUniformFloat4(const Shader* shader, ShaderUniform_t uniform, const void* data)
|
||||
{
|
||||
glUniform4fv( shader->m_glUniformLocation[ uniform ], 1, ( const GLfloat* )data );
|
||||
}
|
||||
|
||||
void ShaderSystem::SetUniformMatrix( const Shader* shader, ShaderUniform_t uniform, const void* data )
|
||||
{
|
||||
glUniformMatrix4fv( shader->m_glUniformLocation[ uniform ], 1, GL_FALSE, ( const GLfloat* )data );
|
||||
}
|
||||
|
||||
void Shader::AllocateAttributes()
|
||||
{
|
||||
// Allocate input layout
|
||||
for ( int i = 0; i < m_layoutCount; i++ )
|
||||
{
|
||||
const InputLayoutDesc_t& layout = m_layouts[ i ];
|
||||
|
||||
glBindAttribLocation( m_program, i, g_attributeNameTable[ layout.semantic ] );
|
||||
|
||||
GL_CHECK_ERROR();
|
||||
|
||||
// add element size to stride
|
||||
m_stride += (int)g_attributeSizeTable[ layout.attribute ];
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::AllocateUniforms()
|
||||
{
|
||||
// parse shader uniforms
|
||||
for (int i = 0; i < UNIFORM_MAX; i++)
|
||||
{
|
||||
m_glUniformLocation[i] = glGetUniformLocation(m_program, g_uniformNameTable[i]);
|
||||
}
|
||||
|
||||
// parse shader samplers
|
||||
for (int i = 0; i < SAMPLER_MAX; i++)
|
||||
{
|
||||
m_glSamplerLocation[i] = glGetUniformLocation(m_program, g_samplersNameTable[i]);
|
||||
}
|
||||
}
|
||||
32
src/render/shadersystem.h
Normal file
32
src/render/shadersystem.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef SHADERSYSTEM_H
|
||||
#define SHADERSYSTEM_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "shader.h"
|
||||
|
||||
class ShaderSystem
|
||||
{
|
||||
public:
|
||||
ShaderSystem();
|
||||
~ShaderSystem();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
Shader* CreateShader(const char* name, const char* vsfilepath, const char* psfilepath, InputLayoutDesc_t* inputLayout = nullptr, int inputLayoutCount = 0);
|
||||
|
||||
void SetShader(const Shader* shader);
|
||||
|
||||
void SetUniformSampler( const Shader* shader, ShaderSamplers_t sampler, int index );
|
||||
void SetUniformFloat4( const Shader* shader, ShaderUniform_t uniform, const void* data );
|
||||
void SetUniformMatrix( const Shader* shader, ShaderUniform_t uniform, const void* data );
|
||||
|
||||
private:
|
||||
std::vector<Shader*> m_shaders;
|
||||
};
|
||||
|
||||
extern ShaderSystem* g_pShaderSystem;
|
||||
|
||||
#endif // !SHADERSYSTEM_H
|
||||
206
src/render/texture2d.cpp
Normal file
206
src/render/texture2d.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
#include "log.h"
|
||||
#include "ifilesystem.h"
|
||||
#include "texture2d.h"
|
||||
#include "texturesmanager.h"
|
||||
#include "gl_shared.h"
|
||||
|
||||
Texture2D* Texture2D::Create()
|
||||
{
|
||||
return new Texture2D;
|
||||
}
|
||||
|
||||
Texture2D::Texture2D()
|
||||
{
|
||||
m_pf = PF_UNKNOWN;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_channels = 0;
|
||||
m_handle = -1;
|
||||
}
|
||||
|
||||
Texture2D::~Texture2D()
|
||||
{
|
||||
m_pf = PF_UNKNOWN;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_channels = 0;
|
||||
m_handle = -1;
|
||||
}
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
// STB Image loading code
|
||||
void Texture2D::CreateFromFile(const char* filename)
|
||||
{
|
||||
int width, height, channels;
|
||||
m_textureFileName = filename;
|
||||
|
||||
FileHandle_t file = GetFileSystem()->OpenFile(filename, "rb");
|
||||
|
||||
size_t imageSize = GetFileSystem()->GetFileLength(file);
|
||||
|
||||
uint8_t* fileData = (uint8_t*)malloc(imageSize);
|
||||
GetFileSystem()->ReadFile(file, fileData, imageSize);
|
||||
|
||||
GetFileSystem()->CloseFile(file);
|
||||
|
||||
uint8_t* imageData = stbi_load_from_memory(fileData, int(imageSize), &width, &height, &channels, 0);
|
||||
|
||||
if (imageData == NULL) {
|
||||
free(fileData);
|
||||
Msg("Texture loading error: %s (%s)", filename, stbi_failure_reason());
|
||||
SDL_assert(imageData);
|
||||
}
|
||||
|
||||
CreateFromExistedData(imageData, width, height, channels);
|
||||
m_textureFileName = filename;
|
||||
|
||||
free(fileData);
|
||||
|
||||
stbi_image_free(imageData);
|
||||
}
|
||||
|
||||
void Texture2D::CreateBlackTexture(int width, int height, int channels)
|
||||
{
|
||||
size_t textureSize = width * height * channels;
|
||||
uint8_t* data = new uint8_t[textureSize];
|
||||
assert(data);
|
||||
|
||||
for (int i = 0; i < (int)textureSize; i++) {
|
||||
data[i] = 0;
|
||||
}
|
||||
|
||||
CreateFromExistedData(data, width, height, channels);
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void Texture2D::CreateWhiteTexture(int width, int height, int channels)
|
||||
{
|
||||
size_t textureSize = width * height * channels;
|
||||
uint8_t* data = new uint8_t[textureSize];
|
||||
assert(data);
|
||||
|
||||
for (int i = 0; i < (int)textureSize; i++) {
|
||||
data[i] = 255;
|
||||
}
|
||||
|
||||
CreateFromExistedData(data, width, height, channels);
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void Texture2D::CreateGrayTexture(int width, int height, int channels)
|
||||
{
|
||||
size_t textureSize = width * height * channels;
|
||||
uint8_t* data = new uint8_t[textureSize];
|
||||
assert(data);
|
||||
|
||||
for (int i = 0; i < (int)textureSize; i++) {
|
||||
data[i] = 255 / 2;
|
||||
}
|
||||
|
||||
CreateFromExistedData(data, width, height, channels);
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void Texture2D::CreateTexture_Generator(int width, int height, int channels, int color)
|
||||
{
|
||||
size_t textureSize = width * height * channels;
|
||||
uint8_t* data = new uint8_t[textureSize];
|
||||
assert(data);
|
||||
|
||||
m_textureFileName = "$generator_texture$";
|
||||
|
||||
for (int i = 0; i < (int)textureSize; i++) {
|
||||
data[i] = color;
|
||||
}
|
||||
|
||||
CreateFromExistedData(data, width, height, channels);
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void Texture2D::CreateFromExistedData(void* data, int width, int height, int channels)
|
||||
{
|
||||
//assert(data);
|
||||
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_channels = channels;
|
||||
|
||||
glGenTextures(1, &m_handle);
|
||||
glBindTexture(GL_TEXTURE_2D, m_handle);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, (channels == 3) ? GL_RGB : GL_RGBA, width, height, 0, (channels == 3) ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void Texture2D::CreateRaw(void* data, int width, int height, PixelFormat pf)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_channels = (pf == PF_R8G8B8) ? 3 : 4;
|
||||
m_pf = pf;
|
||||
|
||||
glGenTextures(1, &m_handle);
|
||||
glBindTexture(GL_TEXTURE_2D, m_handle);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GetGLInternalPF(pf), width, height, 0, GetGLInternalPF(pf), GL_UNSIGNED_BYTE, data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
|
||||
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
|
||||
|
||||
void Texture2D::GenerateMipmaps()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, m_handle);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
//if (g_texAnisoFilter.getValueB()) {
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, g_texAnisoLevel.getValueI());
|
||||
//}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void Texture2D::Bind()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, m_handle);
|
||||
}
|
||||
|
||||
void Texture2D::setWrapS(TextureWrap wrap)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getGlWrap(wrap));
|
||||
}
|
||||
|
||||
void Texture2D::setWrapT(TextureWrap wrap)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getGlWrap(wrap));
|
||||
}
|
||||
|
||||
void Texture2D::setMin(TextureFilter filter)
|
||||
{
|
||||
GLint param = 0;
|
||||
param = getGlTexFilter(filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
|
||||
}
|
||||
|
||||
void Texture2D::setMag(TextureFilter filter)
|
||||
{
|
||||
GLint param = 0;
|
||||
param = getGlTexFilter(filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
|
||||
}
|
||||
52
src/render/texture2d.h
Normal file
52
src/render/texture2d.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef TEXTURE2D_H
|
||||
#define TEXTURE2D_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "render_shared.h"
|
||||
|
||||
class TexturesManager;
|
||||
|
||||
class Texture2D
|
||||
{
|
||||
friend class TexturesManager;
|
||||
public:
|
||||
static Texture2D* Create();
|
||||
|
||||
public:
|
||||
Texture2D();
|
||||
~Texture2D();
|
||||
|
||||
void CreateBlackTexture(int width, int height, int channels);
|
||||
void CreateWhiteTexture(int width, int height, int channels);
|
||||
void CreateGrayTexture(int width, int height, int channels);
|
||||
void CreateTexture_Generator(int width, int height, int channels, int color);
|
||||
void CreateFromExistedData(void* data, int width, int height, int channels);
|
||||
void CreateFromFile(const char* filename);
|
||||
|
||||
void CreateRaw(void* data, int width, int height, PixelFormat pf);
|
||||
|
||||
void GenerateMipmaps();
|
||||
|
||||
void Bind();
|
||||
|
||||
void setWrapS(TextureWrap wrap);
|
||||
void setWrapT(TextureWrap wrap);
|
||||
void setMin(TextureFilter filter);
|
||||
void setMag(TextureFilter filter);
|
||||
|
||||
uint32_t GetHandle() { return m_handle; }
|
||||
|
||||
int GetWidth() { return m_width; }
|
||||
int GetHeight() { return m_height; }
|
||||
|
||||
private:
|
||||
std::string m_textureFileName;
|
||||
PixelFormat m_pf;
|
||||
int m_width;
|
||||
int m_height;
|
||||
int m_channels;
|
||||
uint32_t m_handle;
|
||||
};
|
||||
|
||||
#endif // !TEXTURE2D_H
|
||||
197
src/render/texturesmanager.cpp
Normal file
197
src/render/texturesmanager.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
#include "core.h"
|
||||
#include "log.h"
|
||||
#include "ifilesystem.h"
|
||||
#include "texture2d.h"
|
||||
#include "texturesmanager.h"
|
||||
|
||||
#include "gl_shared.h"
|
||||
|
||||
#include <stb_image.h>
|
||||
|
||||
static const char* g_texFileExtensions[] = { ".png", ".jpeg", ".jpg", ".tga", ".bmp" };
|
||||
const int kTexFileExtensionsSize = sizeof(g_texFileExtensions) / sizeof(g_texFileExtensions[0]);
|
||||
|
||||
TexturesManager* g_pTexturesManager = nullptr;
|
||||
|
||||
static std::string getFileExtension(const std::string& filename)
|
||||
{
|
||||
size_t whereIsDot = filename.find_last_of('.');
|
||||
if (whereIsDot != std::string::npos) {
|
||||
return filename.substr(whereIsDot);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string getFileNameWithoutExtension(const std::string& filename)
|
||||
{
|
||||
size_t lastindex = filename.find_last_of(".");
|
||||
if (lastindex != std::string::npos) {
|
||||
return filename.substr(0, lastindex);
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
static std::string getFilenameWithoutPathAndExtension(const std::string& filename)
|
||||
{
|
||||
size_t whereIsDot = filename.find_last_of('.');
|
||||
size_t whereIsSlash = filename.find_last_of('/');
|
||||
if (whereIsSlash == std::string::npos) {
|
||||
whereIsSlash = filename.find_last_of('\\');
|
||||
}
|
||||
|
||||
if (whereIsDot == std::string::npos && whereIsSlash == std::string::npos) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
std::string string = filename.substr(whereIsSlash + 1);
|
||||
whereIsDot = string.find_last_of('.');
|
||||
string = string.substr(0, whereIsDot);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
TexturesManager::TexturesManager()
|
||||
{
|
||||
m_notex = nullptr;
|
||||
}
|
||||
|
||||
TexturesManager::~TexturesManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TexturesManager::Init()
|
||||
{
|
||||
stbi_set_flip_vertically_on_load(false);
|
||||
|
||||
m_notex = LoadTexture2D("data/textures/notex.png", true);
|
||||
if (!m_notex) {
|
||||
Core::Error("TexturesManager::Init: Failed to initialize system texture! 'system/notex.png' is not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
void TexturesManager::Shutdown()
|
||||
{
|
||||
if (!m_textures.empty()) {
|
||||
Msg("--- unfreed textures ---");
|
||||
|
||||
for (std::vector<Texture2D*>::iterator it = m_textures.begin(); it != m_textures.end(); ++it) {
|
||||
Msg("%s", (*it)->m_textureFileName.c_str());
|
||||
delete* it;
|
||||
*it = nullptr;
|
||||
}
|
||||
|
||||
m_textures.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void TexturesManager::SetTexture(int slot, Texture2D* texture)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
glBindTexture(GL_TEXTURE_2D, texture ? texture->GetHandle() : 0);
|
||||
}
|
||||
|
||||
Texture2D* TexturesManager::CreateManual2D(const char* name, uint32_t width, uint32_t height, PixelFormat format, void* pData, bool useAsRenderTarget)
|
||||
{
|
||||
for (std::vector<Texture2D*>::iterator it = m_textures.begin(); it != m_textures.end(); ++it) {
|
||||
if ((*it)->m_textureFileName == name) {
|
||||
Msg("TexturesManager::CreateManual2D: texture %s is already created!", name);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate
|
||||
Texture2D* texture = Texture2D::Create();
|
||||
texture->CreateRaw(pData, width, height, format);
|
||||
texture->m_textureFileName = name;
|
||||
|
||||
if (useAsRenderTarget)
|
||||
Msg("Created rt texture [%s]", name);
|
||||
|
||||
m_textures.push_back(texture);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
bool IsSupportedExtension(const char* filename)
|
||||
{
|
||||
std::string ext = getFileExtension(filename);
|
||||
|
||||
for (int i = 0; i < kTexFileExtensionsSize; i++) {
|
||||
if (ext == g_texFileExtensions[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Texture2D* TexturesManager::LoadTexture2D(const char* texturename, bool useMipmaps /*= false*/)
|
||||
{
|
||||
int texturesNbr = m_textures.size();
|
||||
for (int i = 0; i < texturesNbr; i++) {
|
||||
if (m_textures[i]->m_textureFileName == texturename)
|
||||
return m_textures[i];
|
||||
}
|
||||
|
||||
if (strcmp(texturename, "$white$") == 0) {
|
||||
Texture2D* tex = Texture2D::Create();
|
||||
tex->m_textureFileName = "$white$";
|
||||
tex->CreateWhiteTexture(16, 16, 3);
|
||||
m_textures.push_back(tex);
|
||||
return tex;
|
||||
}
|
||||
if (strcmp(texturename, "$black$") == 0) {
|
||||
Texture2D* tex = Texture2D::Create();
|
||||
tex->m_textureFileName = "$black$";
|
||||
tex->CreateBlackTexture(16, 16, 3);
|
||||
m_textures.push_back(tex);
|
||||
return tex;
|
||||
}
|
||||
if (strcmp(texturename, "$gray$") == 0) {
|
||||
Texture2D* tex = Texture2D::Create();
|
||||
tex->m_textureFileName = "$gray$";
|
||||
tex->CreateGrayTexture(16, 16, 3);
|
||||
m_textures.push_back(tex);
|
||||
return tex;
|
||||
}
|
||||
|
||||
if (strlen(texturename) <= 0) {
|
||||
return m_notex;
|
||||
}
|
||||
|
||||
std::string texnamebuf;
|
||||
|
||||
// find texture from disk
|
||||
for (int i = 0; i < kTexFileExtensionsSize; i++)
|
||||
{
|
||||
std::string textureFilename = getFileNameWithoutExtension(texturename);
|
||||
textureFilename += g_texFileExtensions[i];
|
||||
|
||||
if (GetFileSystem()->IsExist(textureFilename.c_str()))
|
||||
{
|
||||
texnamebuf = textureFilename;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!texnamebuf.empty()) {
|
||||
Texture2D* texture = Texture2D::Create();
|
||||
texture->CreateFromFile(texnamebuf.c_str());
|
||||
|
||||
if (useMipmaps)
|
||||
texture->GenerateMipmaps();
|
||||
|
||||
Msg("loaded %s", getFilenameWithoutPathAndExtension(texturename).c_str());
|
||||
m_textures.push_back(texture);
|
||||
return texture;
|
||||
}
|
||||
else if (texnamebuf.empty() && m_notex) {
|
||||
Msg("not found %s", getFilenameWithoutPathAndExtension(texturename).c_str());
|
||||
return m_notex;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
40
src/render/texturesmanager.h
Normal file
40
src/render/texturesmanager.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef TEXTURESMANAGER_H
|
||||
#define TEXTURESMANAGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "render_shared.h"
|
||||
|
||||
class Texture2D;
|
||||
|
||||
class TexturesManager
|
||||
{
|
||||
public:
|
||||
TexturesManager();
|
||||
~TexturesManager();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void SetTexture(int slot, Texture2D* texture);
|
||||
|
||||
Texture2D* CreateManual2D(
|
||||
const char* name,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
PixelFormat format,
|
||||
void* pData = nullptr,
|
||||
bool useAsRenderTarget = false);
|
||||
|
||||
Texture2D* LoadTexture2D(const char* texturename, bool useMipmaps = false);
|
||||
|
||||
private:
|
||||
std::vector<Texture2D*> m_textures;
|
||||
|
||||
Texture2D* m_notex;
|
||||
};
|
||||
|
||||
extern TexturesManager* g_pTexturesManager;
|
||||
|
||||
#endif // !TEXTURESMANAGER_H
|
||||
Reference in New Issue
Block a user