Initial Commit

This commit is contained in:
2026-02-12 11:46:06 +03:00
commit b044c8d1a5
3973 changed files with 1599881 additions and 0 deletions

120
src/render/debugrender.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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;
}

View 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