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.
 
 
 

349 lines
7.7 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;
// FIXME: revert back to num_/max_(models|textures)
model_assets* assets;
texture_assets* textures;
transforms* xforms; // NOTE: would be part of camera in libTangerine
SDLHandles* handles;
GLContext* gl_ctx;
u32 num_gl_meshes;
u32 max_gl_meshes;
GLmesh* gl_meshes;
u32 num_lights;
u32 max_lights;
PointLight* 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 = (u16*) std::calloc(m.num_indices, sizeof(u16));
u16 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(u16));
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;
}
GLmesh*
getFreeGLMesh(RenderState* rs)
{
if (rs->num_gl_meshes < rs->max_gl_meshes)
return &rs->gl_meshes[rs->num_gl_meshes++];
printf("%s(), Error, rs->gl_meshes is full\n", __FUNCTION__);
return nullptr;
}
#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->max_gl_meshes = 256;
rs->gl_meshes = (GLmesh*) arenaAllocateBlock(
arena, rs->max_gl_meshes * sizeof(GLmesh));
}
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++) {
GLmesh* gmesh = getFreeGLMesh(rs);
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->num_gl_meshes; i++) {
GLmesh& glm = rs->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;
}