You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
358 lines
7.8 KiB
358 lines
7.8 KiB
|
|
#include <cstring> |
|
#include <iostream> |
|
|
|
#include <SDL2/SDL.h> |
|
#include <glm/gtc/matrix_transform.hpp> |
|
|
|
#include "asset.h" |
|
#include "dumbLog.h" |
|
#include "GLDebug.h" |
|
#include "shader.h" |
|
#include "types.h" |
|
|
|
|
|
struct SDLHandles |
|
{ |
|
SDL_Window* window; |
|
SDL_GLContext sdl_gl_ctx; |
|
SDL_DisplayMode display_mode; |
|
}; |
|
|
|
struct RenderState |
|
{ |
|
memory_arena* arena; |
|
model_assets* assets; |
|
texture_assets* textures; |
|
|
|
transforms* xforms; // NOTE: would be part of camera in libTangerine |
|
SDLHandles* handles; |
|
|
|
GLContext* gl_ctx; |
|
gl_mesh_array* gl_mesh_arr; |
|
light_array lights; |
|
}; |
|
|
|
mesh |
|
initCubeMesh() |
|
{ |
|
mesh m = {0}; |
|
m.num_vertices = 8; |
|
m.vertices = (glm::vec3*) std::calloc(m.num_vertices, sizeof(glm::vec3)); |
|
m.vertices[0] = { -1, 1, -1 }; |
|
m.vertices[1] = { -1, -1, -1 }; |
|
m.vertices[2] = { 1, -1, -1 }; |
|
m.vertices[3] = { 1, 1, -1 }; |
|
m.vertices[4] = { -1, 1, 1 }; |
|
m.vertices[5] = { -1, -1, 1 }; |
|
m.vertices[6] = { 1, -1, 1 }; |
|
m.vertices[7] = { 1, 1, 1 }; |
|
|
|
m.num_indices = 36; // 6 sides, 2 tris per side, 3 verts per tri |
|
m.indices = (u32*) std::calloc(m.num_indices, sizeof(u32)); |
|
u32 indices[36] = { |
|
0, 1, 2, 0, 2, 3, |
|
3, 2, 6, 3, 6, 7, |
|
7, 6, 5, 7, 5, 4, |
|
4, 5, 0, 4, 1, 0, |
|
0, 3, 4, 0, 3, 7, |
|
1, 2, 5, 2, 6, 5 |
|
}; |
|
std::memcpy(m.indices, indices, m.num_indices * sizeof(u32)); |
|
|
|
return m; |
|
} |
|
|
|
shader_program* |
|
getShaderByName(const char* name, GLContext* gl_ctx) |
|
{ |
|
u64 hash = utilFNV64a_str(name); |
|
|
|
for (u32 i = 0; i < gl_ctx->num_shaders; i++) { |
|
if (utilFNV64a_str(gl_ctx->shaders[i].name) == hash) |
|
return &gl_ctx->shaders[i]; |
|
} |
|
|
|
printf("%s(), shader not found, %s\n", __FUNCTION__, name); |
|
return nullptr; |
|
} |
|
|
|
shader_program* |
|
getShaderByID(GLContext* gl_ctx, GLuint prog_id) |
|
{ |
|
for (u32 i = 0; i < gl_ctx->num_shaders; i++) { |
|
if (gl_ctx->shaders[i].prog_id) |
|
return &gl_ctx->shaders[i]; |
|
} |
|
|
|
printf("%s(), shader not found, %d\n", __FUNCTION__, prog_id); |
|
return nullptr; |
|
} |
|
|
|
// NOTE: equivalent to rgAppend() in libTangerine |
|
model* |
|
getModel(RenderState* rs, const char* filepath) |
|
{ |
|
model* mdl = assetGetCached(rs->assets, utilFNV64a_str(filepath)); |
|
|
|
if (!mdl) |
|
mdl = assetLoadFromFile(rs->assets, rs->textures, rs->arena, filepath); |
|
|
|
return mdl; |
|
} |
|
|
|
gl_mesh* |
|
getFreeGLMesh(gl_mesh_array* gma) |
|
{ |
|
if (gma->count < gma->max) { |
|
gl_mesh* glm = &gma->gl_meshes[gma->count]; |
|
gma->count++; |
|
|
|
return glm; |
|
} |
|
|
|
std::cout << "Error, gl_mesh_array is full\n"; |
|
return nullptr; |
|
} |
|
|
|
gl_mesh_array* |
|
initGLMeshArray(memory_arena* arena, u32 count) |
|
{ |
|
gl_mesh_array* gma = |
|
(gl_mesh_array*) arenaAllocateBlock(arena, sizeof(gl_mesh_array)); |
|
gma->max = count; |
|
gma->count = 0; |
|
gma->gl_meshes = |
|
(gl_mesh*) arenaAllocateBlock(arena, count * sizeof(gl_mesh)); |
|
|
|
return gma; |
|
} |
|
|
|
#define DEFAULT_SHADER_COUNT 64 |
|
#define DEFAULT_UBO_COUNT 32 |
|
GLContext* |
|
initGLContext(memory_arena* arena) |
|
{ |
|
GLContext* gl_ctx = |
|
(GLContext*) arenaAllocateBlock(arena, sizeof(GLContext)); |
|
gl_ctx->max_shaders = DEFAULT_SHADER_COUNT; |
|
gl_ctx->num_shaders = 0; |
|
gl_ctx->shaders = (shader_program*) arenaAllocateBlock( |
|
arena, DEFAULT_SHADER_COUNT * sizeof(shader_program)); |
|
gl_ctx->max_ubos = DEFAULT_UBO_COUNT; |
|
gl_ctx->num_ubos = 0; |
|
gl_ctx->uniform_buffers = (gl_buffer*) arenaAllocateBlock(arena, |
|
gl_ctx->max_ubos * sizeof(gl_buffer)); |
|
gl_ctx->binding_count = 0; |
|
|
|
return gl_ctx; |
|
} |
|
|
|
RenderState* |
|
initRenderState(memory_arena* arena) |
|
{ |
|
RenderState* rs = |
|
(RenderState*) arenaAllocateBlock(arena, sizeof(RenderState)); |
|
|
|
if (rs) { |
|
rs->arena = arena; |
|
rs->assets = assetInitModelBlock(arena, 256); |
|
rs->textures = assetInitTextureBlock(arena, 256); |
|
rs->gl_ctx = initGLContext(arena); |
|
rs->xforms = |
|
(transforms*) arenaAllocateBlock(arena, sizeof(transforms)); |
|
rs->handles = |
|
(SDLHandles*) arenaAllocateBlock(arena, sizeof(SDLHandles)); |
|
rs->gl_mesh_arr = initGLMeshArray(arena, 256); |
|
} |
|
|
|
return rs; |
|
} |
|
|
|
bool |
|
initGraphics(SDLHandles* handles) |
|
{ |
|
handles->window = SDL_CreateWindow( |
|
"shader_testing", |
|
SDL_WINDOWPOS_CENTERED_DISPLAY(0), |
|
SDL_WINDOWPOS_CENTERED_DISPLAY(0), |
|
1280, |
|
720, |
|
SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); |
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) != 0) { |
|
std::cout << "error, sdl init: " << SDL_GetError() << "\n"; |
|
return false; |
|
} |
|
|
|
SDL_GL_SetSwapInterval(1); |
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, |
|
SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); |
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, |
|
SDL_GL_CONTEXT_PROFILE_CORE); |
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); |
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); |
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); |
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); |
|
SDL_GetCurrentDisplayMode(0, &handles->display_mode); |
|
|
|
handles->sdl_gl_ctx = SDL_GL_CreateContext(handles->window); |
|
|
|
if (!handles->sdl_gl_ctx) { |
|
std::cout << "error creating context\n"; |
|
return false; |
|
} |
|
|
|
if (glewInit()) { |
|
std::cout << "error initializing opengl\n"; |
|
return false; |
|
} |
|
|
|
std::cout << "opengl vendor: " << glGetString(GL_VENDOR) << "\n"; |
|
std::cout << "opengl renderer: " << glGetString(GL_RENDERER) << "\n"; |
|
std::cout << "opengl version: " << glGetString(GL_VERSION) << "\n"; |
|
|
|
glEnable(GL_DEPTH_TEST); |
|
glEnable(GL_LINE_SMOOTH); |
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); |
|
|
|
glEnable (GL_DEBUG_OUTPUT); |
|
glDebugMessageCallback((GLDEBUGPROC) openglDebugCallback, 0); |
|
|
|
return handles->window != nullptr; |
|
} |
|
|
|
bool |
|
loadScene(RenderState* rs) |
|
{ |
|
mesh cube = initCubeMesh(); |
|
const u32 NUM_CUBES = 4; |
|
glm::vec3 cube_locs[NUM_CUBES] = { |
|
glm::vec3(-10, 10, 0), |
|
glm::vec3(-10, -10, 0), |
|
glm::vec3( 10, 10, 0), |
|
glm::vec3( 10, -10, 0), |
|
}; |
|
|
|
// TODO: full lighting model |
|
//model* tex_cube = getModel(rs, "data/textured_cube.gltf"); |
|
|
|
// TODO: load debug shader from libTangerine for textured_cube |
|
shader_program* s = getShaderByName("default", rs->gl_ctx); |
|
|
|
if (!s) |
|
return false; |
|
|
|
for (u32 i = 0; i < NUM_CUBES; i++) { |
|
gl_mesh* gmesh = getFreeGLMesh(rs->gl_mesh_arr); |
|
|
|
if (!gmesh) |
|
return false; |
|
|
|
*gmesh = loadGLMesh(s, cube, GL_TRIANGLES, cube_locs[i]); |
|
|
|
if (gmesh->vao_id == 0) |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void |
|
loop(RenderState* rs) |
|
{ |
|
u32 delay = 60; |
|
u32 frame_start, frame_time; |
|
bool running = true; |
|
SDL_Event e; |
|
|
|
while (running) { |
|
frame_start = SDL_GetTicks(); |
|
|
|
while (SDL_PollEvent(&e)) { |
|
if (e.type == SDL_QUIT || |
|
(e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE)) |
|
{ |
|
running = false; |
|
break; |
|
} |
|
} |
|
|
|
glClearColor(0.2, 0.2, 0.2, 1); |
|
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); |
|
|
|
for (u32 i = 0; i < rs->gl_mesh_arr->count; i++) { |
|
gl_mesh& glm = rs->gl_mesh_arr->gl_meshes[i]; |
|
*glm.model_xform = glm::rotate( |
|
*glm.model_xform, (float) M_PI / 60, glm::vec3(0, 1, 0)); |
|
renderVAO(&glm); |
|
} |
|
|
|
SDL_GL_SwapWindow(rs->handles->window); |
|
glUseProgram(0); |
|
frame_time = SDL_GetTicks() - frame_start; |
|
|
|
if (delay > frame_time) |
|
SDL_Delay(delay - frame_time); |
|
} |
|
} |
|
|
|
void |
|
quit(RenderState* rs) |
|
{ |
|
SDL_GL_DeleteContext(rs->handles->sdl_gl_ctx); |
|
SDL_DestroyWindow(rs->handles->window); |
|
SDL_Quit(); |
|
std::free(rs->arena); |
|
} |
|
|
|
int |
|
main() |
|
{ |
|
memory_arena* arena = arenaInit(DEFAULT_ARENA_SIZE); |
|
RenderState* rs = initRenderState(arena); |
|
|
|
if (!initGraphics(rs->handles)) |
|
return 1; |
|
|
|
if (rs) { |
|
|
|
// FIXME: need to test this with another shader that has another UBO |
|
gl_buffer& ubo = rs->gl_ctx->uniform_buffers[rs->gl_ctx->num_ubos++]; |
|
initTransforms(arena, rs->xforms, &ubo, rs->gl_ctx); |
|
|
|
if (!addShaderProgram(arena, |
|
rs->gl_ctx, |
|
"../data/shader.vert", |
|
"../data/shader.frag", |
|
"default")) |
|
{ |
|
LOG(Error) << "error loading shaders\n"; |
|
return 1; |
|
} |
|
|
|
if (!addShaderProgram(arena, |
|
rs->gl_ctx, |
|
"../data/colored_vertices.vert", |
|
"../data/colored_vertices.frag", |
|
"colored_vertices")) |
|
{ |
|
LOG(Error) << "error loading shaders\n"; |
|
return 1; |
|
} |
|
|
|
if (!loadScene(rs)) { |
|
LOG(Error) << "error loading scene\n"; |
|
return 1; |
|
} |
|
|
|
loop(rs); |
|
quit(rs); |
|
return 0; |
|
} |
|
|
|
std::cout << "error loading scene\n"; |
|
return 1; |
|
} |
|
|
|
|