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.
403 lines
9.3 KiB
403 lines
9.3 KiB
|
|
#include <cassert> |
|
#include <cstring> |
|
#include <iostream> |
|
|
|
#include <SDL2/SDL.h> |
|
|
|
#include "asset.h" |
|
#include "entity.h" |
|
#include "dumbLog.h" |
|
#include "GLDebug.h" |
|
#include "shader.h" |
|
#include "types.h" |
|
#define UTIL_IMPLEMENTATION |
|
#include "util.h" |
|
|
|
|
|
struct SDLHandles |
|
{ |
|
SDL_Window* window; |
|
SDL_GLContext sdl_gl_ctx; |
|
SDL_DisplayMode display_mode; |
|
}; |
|
|
|
// TODO: node/tree structure for entities |
|
struct Node; |
|
|
|
struct RenderGroup |
|
{ |
|
shader_program* shader; |
|
u32 num_entites; |
|
u32 max_entities; |
|
Entity* entities; |
|
char* name; |
|
}; |
|
|
|
struct RenderState |
|
{ |
|
transforms* xforms; // NOTE: would be part of camera in libTangerine |
|
SDLHandles* handles; |
|
GLContext* gl_ctx; |
|
Assets assets; |
|
|
|
MemoryArena* rg_arena; |
|
u32 num_render_groups; |
|
u32 max_render_groups; |
|
RenderGroup* render_groups; |
|
|
|
u32 num_lights; |
|
u32 max_lights; |
|
PointLight* lights; |
|
}; |
|
|
|
|
|
#define DEFAULT_ENTITY_COUNT 256 |
|
void |
|
initRenderGroup(RenderGroup* rg, |
|
MemoryArena* arena, |
|
shader_program* shader, |
|
u32 num_entities = DEFAULT_ENTITY_COUNT, |
|
const char* name = "") |
|
{ |
|
rg->max_entities = num_entities; |
|
rg->shader = shader; |
|
rg->name = arenaCopyCStr(arena, name); |
|
rg->entities = ARENA_ALLOC(arena, Entity, num_entities); |
|
} |
|
|
|
void |
|
freeRenderGroup(RenderGroup* rg, MemoryArena* arena) |
|
{ |
|
printf("%s(), should probably look into freeing arena memory?\n", |
|
__FUNCTION__); |
|
assert(0); |
|
} |
|
|
|
Entity* |
|
getFreeEntity(RenderGroup* rg) |
|
{ |
|
if (rg->num_entites < rg->max_entities) |
|
return &rg->entities[rg->num_entites++]; |
|
|
|
printf("%s(), render group full\n", __FUNCTION__); |
|
return nullptr; |
|
} |
|
|
|
RenderGroup* |
|
getFreeRenderGroup(RenderState* rs) |
|
{ |
|
if (rs->num_render_groups < rs->max_render_groups) |
|
return &rs->render_groups[rs->num_render_groups++]; |
|
|
|
printf("%s(), no free render group\n", __FUNCTION__); |
|
return nullptr; |
|
} |
|
|
|
#define DEFAULT_TEXTURE_COUNT 64 |
|
#define DEFAULT_SHADER_COUNT 64 |
|
#define DEFAULT_UBO_COUNT 32 |
|
GLContext* |
|
initGLContext(MemoryArena* arena) |
|
{ |
|
GLContext* gl_ctx = ARENA_ALLOC(arena, GLContext, 1); |
|
gl_ctx->max_shaders = DEFAULT_SHADER_COUNT; |
|
gl_ctx->shaders = ARENA_ALLOC(arena, shader_program, DEFAULT_SHADER_COUNT); |
|
gl_ctx->max_ubos = DEFAULT_UBO_COUNT; |
|
gl_ctx->uniform_buffers = ARENA_ALLOC(arena, gl_buffer, gl_ctx->max_ubos); |
|
gl_ctx->max_textures = DEFAULT_TEXTURE_COUNT; |
|
gl_ctx->textures = ARENA_ALLOC(arena, GLTexture, gl_ctx->max_textures); |
|
|
|
return gl_ctx; |
|
} |
|
|
|
#define DEFAULT_MODEL_COUNT 256 |
|
#define DEFAULT_RENDER_GROUP_COUNT 256 |
|
RenderState* |
|
initRenderState(u32 max_models = DEFAULT_MODEL_COUNT, |
|
u32 max_textures = DEFAULT_TEXTURE_COUNT) |
|
{ |
|
RenderState* rs = UTIL_ALLOC(1, RenderState); |
|
|
|
if (rs) { |
|
rs->assets.arena = arenaInit(DEFAULT_ARENA_SIZE); |
|
rs->assets.max_models = max_models; |
|
rs->assets.models = ARENA_ALLOC(rs->assets.arena, model, max_models); |
|
rs->assets.max_textures = max_textures; |
|
rs->assets.textures = |
|
ARENA_ALLOC(rs->assets.arena, util_image, max_textures); |
|
|
|
rs->rg_arena = arenaInit(DEFAULT_ARENA_SIZE); |
|
rs->max_render_groups = DEFAULT_RENDER_GROUP_COUNT; |
|
rs->render_groups = ARENA_ALLOC(rs->rg_arena, RenderGroup, |
|
DEFAULT_RENDER_GROUP_COUNT); |
|
|
|
rs->gl_ctx = initGLContext(rs->assets.arena); |
|
rs->xforms = ARENA_ALLOC(rs->assets.arena, transforms, 1); |
|
rs->handles = UTIL_ALLOC(1, SDLHandles); |
|
} |
|
|
|
return rs; |
|
} |
|
|
|
void |
|
freeRenderState(RenderState*& rs) |
|
{ |
|
if (rs) { |
|
arenaFree(rs->assets.arena); |
|
utilSafeFree(rs->handles); |
|
utilSafeFree(rs); |
|
rs = nullptr; |
|
} |
|
} |
|
|
|
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 |
|
addShaders(RenderState* rs) |
|
{ |
|
if (!addShaderProgram(rs->assets.arena, |
|
rs->gl_ctx, |
|
"../data/shader.vert", |
|
"../data/shader.frag", |
|
"default")) |
|
{ |
|
LOG(Error) << "error loading default shader\n"; |
|
return false; |
|
} |
|
|
|
if (!addShaderProgram(rs->assets.arena, |
|
rs->gl_ctx, |
|
"../data/colored_vertices.vert", |
|
"../data/colored_vertices.frag", |
|
"colored_vertices")) |
|
{ |
|
LOG(Error) << "error loading colored_vertices shader\n"; |
|
return false; |
|
} |
|
|
|
if (!addShaderProgram(rs->assets.arena, |
|
rs->gl_ctx, |
|
"../data/debug.vert", |
|
"../data/debug.frag", |
|
"debug")) |
|
{ |
|
LOG(Error) << "error loading debug shader\n"; |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool |
|
loadScene(RenderState* rs) |
|
{ |
|
shader_program* s_default = getShaderByName("default", rs->gl_ctx); |
|
shader_program* s_debug = getShaderByName("debug", rs->gl_ctx); |
|
if (!s_default || !s_debug) return false; |
|
|
|
// TODO: full lighting model |
|
model* tex_cube = getModelByPath(&rs->assets, "../data/textured_cube.gltf"); |
|
assert(tex_cube != nullptr); |
|
const mesh& texmesh = tex_cube->meshes[0]; |
|
|
|
GLVertexAttrib* db_pos_attrib = getVertexAttribByName(s_debug, "position"); |
|
GLVertexAttrib* db_normal_attrib = getVertexAttribByName(s_debug, "normal"); |
|
if (!db_pos_attrib || !db_normal_attrib) return false; |
|
|
|
GLBufferToAttribMapping debug_mappings[2] = { |
|
{ "position", db_pos_attrib, texmesh.vertices }, |
|
{ "normal", db_normal_attrib, texmesh.normals } |
|
}; |
|
|
|
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), |
|
}; |
|
|
|
RenderGroup* orange_cubes = getFreeRenderGroup(rs); |
|
assert(orange_cubes != nullptr); |
|
initRenderGroup(orange_cubes, rs->rg_arena, s_debug, NUM_CUBES, |
|
"debug_cubes"); |
|
|
|
for (u32 i = 0; i < NUM_CUBES; i++) { |
|
Entity* e = getFreeEntity(orange_cubes); |
|
assert(e != nullptr); |
|
|
|
if (!initEntity(e, rs->gl_ctx, rs->rg_arena, tex_cube, |
|
2, debug_mappings, "debug_box")) |
|
{ |
|
// FIXME: this doesn't actually do anything |
|
freeRenderGroup(orange_cubes, rs->rg_arena); |
|
return false; |
|
} |
|
|
|
setEntityPosition(e, cube_locs[i]); |
|
} |
|
|
|
RenderGroup* debug_cube_group = getFreeRenderGroup(rs); |
|
assert(debug_cube_group != nullptr); |
|
initRenderGroup(debug_cube_group, rs->rg_arena, s_default, 1, |
|
"orange_cubes"); |
|
Entity* e = getFreeEntity(debug_cube_group); |
|
assert(e != nullptr); |
|
|
|
GLVertexAttrib* df_pos_attrib = |
|
getVertexAttribByName(s_default, "position"); |
|
GLVertexAttrib* df_uv_attrib = getVertexAttribByName(s_default, "uv"); |
|
if (!df_pos_attrib || !df_uv_attrib) return false; |
|
|
|
GLBufferToAttribMapping default_mappings[2] = { |
|
{ "position", df_pos_attrib, texmesh.vertices }, |
|
{ "uvs", df_uv_attrib, texmesh.uvs } |
|
}; |
|
|
|
initEntity(e, rs->gl_ctx, rs->rg_arena, tex_cube, |
|
2, default_mappings, "textured_box"); |
|
|
|
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->num_render_groups; i++) { |
|
RenderGroup& rg = rs->render_groups[i]; |
|
|
|
for (u32 j = 0; j < rg.num_entites; j++) { |
|
Entity& e = rg.entities[j]; |
|
rotateEntity(&e, glm::vec3(0, 1, 0), (float) M_PI / 60); |
|
|
|
for (u32 k = 0; k < e.num_meshes; k++) { |
|
GLmesh& glm = e.meshes[k]; |
|
renderVAO(&glm, e.xform, rg.shader); |
|
} |
|
} |
|
} |
|
|
|
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(); |
|
freeRenderState(rs); |
|
} |
|
|
|
int |
|
main() |
|
{ |
|
RenderState* rs = initRenderState(); |
|
|
|
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(rs->assets.arena, rs->xforms, &ubo, rs->gl_ctx); |
|
|
|
if (!addShaders(rs)) { |
|
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; |
|
} |
|
|
|
|