Small program to quickly test OpenGL GLSL shaders.
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

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