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
8.1 KiB
349 lines
8.1 KiB
|
|
#include <cassert> |
|
#include <cstdlib> |
|
#include <cstring> |
|
#include <string> |
|
#include <fstream> |
|
#include <iostream> |
|
|
|
#include <SDL2/SDL.h> |
|
#include <glm/geometric.hpp> |
|
#include <glm/gtc/matrix_transform.hpp> |
|
|
|
#include "shader_testing.h" |
|
|
|
#include "dumpShader.inl" |
|
|
|
|
|
SDL_Window *g_window = 0; |
|
SDL_GLContext g_glContext; |
|
SDL_DisplayMode g_display_mode; |
|
|
|
transforms g_xforms; |
|
mesh g_cube_mesh; |
|
const u32 NUM_CUBES = 4; |
|
gl_mesh g_gl_cubes[NUM_CUBES]; |
|
glm::vec3 g_cube_locs[NUM_CUBES] = { |
|
glm::vec3(-10, 10, 0), |
|
glm::vec3(-10, -10, 0), |
|
glm::vec3( 10, 10, 0), |
|
glm::vec3( 10, -10, 0), |
|
}; |
|
|
|
|
|
void |
|
openglDebugCallback(GLenum source, |
|
GLenum type, |
|
GLuint id, |
|
GLenum severity, |
|
GLsizei length, |
|
const GLchar* message, |
|
const void* userParam) |
|
{ |
|
std::cout << ((type == GL_DEBUG_TYPE_ERROR) ? "Error" : "Debug") |
|
<< (type == GL_DEBUG_TYPE_ERROR ? "** GL Error **" : "") |
|
<< ", type: " << type |
|
<< ", severity: " << severity |
|
<< ", message: " << message << "\n"; |
|
} |
|
|
|
bool |
|
init() |
|
{ |
|
g_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, &g_display_mode); |
|
|
|
g_glContext = SDL_GL_CreateContext(g_window); |
|
|
|
if (!g_glContext) { |
|
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 g_window != nullptr; |
|
} |
|
|
|
const std::string |
|
dumpTextFile(const char* filepath) |
|
{ |
|
std::ifstream fs { filepath }; |
|
std::string s { |
|
std::istreambuf_iterator<char>(fs), |
|
std::istreambuf_iterator<char>()}; |
|
|
|
if (!fs || !fs.good()) |
|
std::cout << "error reading file, " << filepath << "\n"; |
|
|
|
return s; |
|
} |
|
|
|
bool |
|
loadShaderProgram(const char* vs, const char* fs, shader* s) |
|
{ |
|
std::string vert = dumpTextFile(vs); |
|
std::string frag = dumpTextFile(fs); |
|
|
|
if (vert.size() > 0 && frag.size() > 0) { |
|
const char* vert_c = vert.c_str(); |
|
const char* frag_c = frag.c_str(); |
|
|
|
GLuint vs_id = glCreateShader(GL_VERTEX_SHADER); |
|
GLuint fs_id = glCreateShader(GL_FRAGMENT_SHADER); |
|
glShaderSource(vs_id, 1, &vert_c, NULL); |
|
glShaderSource(fs_id, 1, &frag_c, NULL); |
|
glCompileShader(vs_id); |
|
glCompileShader(fs_id); |
|
s->prog_id = glCreateProgram(); |
|
glAttachShader(s->prog_id, vs_id); |
|
glAttachShader(s->prog_id, fs_id); |
|
|
|
glLinkProgram(s->prog_id); |
|
|
|
glDetachShader(s->prog_id, vs_id); |
|
glDetachShader(s->prog_id, fs_id); |
|
glDeleteShader(vs_id); |
|
glDeleteShader(fs_id); |
|
|
|
GLint is_linked = 0; |
|
glGetProgramiv(s->prog_id, GL_LINK_STATUS, &is_linked); |
|
return (is_linked == GL_TRUE); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
transforms |
|
initXformUBO(shader* s, |
|
float fov, |
|
float near_clip_plane, |
|
float aspect_ratio, |
|
glm::vec3 cam_pos, |
|
glm::vec3 look_pos) |
|
{ |
|
transforms xforms; |
|
xforms.view_xform = glm::lookAt(cam_pos, look_pos, glm::vec3(0, 1, 0)); |
|
xforms.proj_xform = glm::infinitePerspective( |
|
glm::radians(fov), aspect_ratio, near_clip_plane); |
|
xforms.normal_xform = glm::mat4(1); |
|
|
|
glGenBuffers(1, &s->xforms_ubo_id); |
|
glBindBufferBase(GL_UNIFORM_BUFFER, 0, s->xforms_ubo_id); |
|
glBindBuffer(GL_UNIFORM_BUFFER, s->xforms_ubo_id); |
|
glBufferData(GL_UNIFORM_BUFFER, sizeof(xforms), &xforms, GL_STATIC_DRAW); |
|
glBindBuffer(GL_UNIFORM_BUFFER, 0); |
|
|
|
return xforms; |
|
}; |
|
|
|
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; |
|
} |
|
|
|
gl_mesh |
|
loadGLMesh(shader* s, const mesh& m, GLenum draw_mode, const glm::vec3& pos) |
|
{ |
|
gl_mesh gm = {0}; |
|
gm.num_indices = m.num_indices; |
|
gm.draw_mode = draw_mode; |
|
|
|
glUseProgram(s->prog_id); |
|
glGenVertexArrays(1, &gm.vao_id); |
|
glBindVertexArray(gm.vao_id); |
|
|
|
gm.model_xform = (glm::mat4*) std::calloc(1, sizeof(glm::mat4)); |
|
*gm.model_xform = glm::translate(glm::mat4(1), pos); |
|
|
|
gm.model_xform_id = glGetUniformLocation(s->prog_id, "model_xform"); |
|
glUniformMatrix4fv( |
|
gm.model_xform_id, 1, GL_FALSE, (float*) gm.model_xform); |
|
|
|
glGenBuffers(1, &gm.vert_buf_id); |
|
glBindBuffer(GL_ARRAY_BUFFER, gm.vert_buf_id); |
|
glBufferData(GL_ARRAY_BUFFER, |
|
m.num_vertices * 3 * sizeof(GLfloat), |
|
m.vertices, |
|
GL_STATIC_DRAW); |
|
glVertexAttribPointer(POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0); |
|
glEnableVertexAttribArray(POSITION); |
|
|
|
glGenBuffers(1, &gm.idx_buf_id); |
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gm.idx_buf_id); |
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, |
|
m.num_indices * sizeof(GLuint), |
|
m.indices, |
|
GL_STATIC_DRAW); |
|
|
|
glBindVertexArray(0); |
|
glUseProgram(0); |
|
|
|
return gm; |
|
} |
|
|
|
void |
|
loop(shader* s, gl_mesh* mesh_arr, u32 num_meshes) |
|
{ |
|
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); |
|
glUseProgram(s->prog_id); |
|
glBindBuffer(GL_UNIFORM_BUFFER, s->xforms_ubo_id); |
|
|
|
for (u32 i = 0; i < num_meshes; i++) { |
|
const gl_mesh& m = mesh_arr[i]; |
|
*m.model_xform = glm::rotate( |
|
*m.model_xform, (float) M_PI / 60, glm::vec3(0, 1, 0)); |
|
glBindVertexArray(m.vao_id); |
|
glUniformMatrix4fv( |
|
m.model_xform_id, 1, GL_FALSE, (float*) m.model_xform); |
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m.idx_buf_id); |
|
glDrawElements(m.draw_mode, m.num_indices, GL_UNSIGNED_INT, 0); |
|
glBindVertexArray(0); |
|
} |
|
|
|
SDL_GL_SwapWindow(g_window); |
|
glUseProgram(0); |
|
frame_time = SDL_GetTicks() - frame_start; |
|
|
|
if (delay > frame_time) |
|
SDL_Delay(delay - frame_time); |
|
} |
|
} |
|
|
|
void |
|
quit(shader* s) |
|
{ |
|
glDeleteProgram(s->prog_id); |
|
SDL_GL_DeleteContext(g_glContext); |
|
SDL_DestroyWindow(g_window); |
|
SDL_Quit(); |
|
|
|
for (u32 i = 0; i < NUM_CUBES; i++) { |
|
gl_mesh& c = g_gl_cubes[i]; |
|
|
|
if (c.model_xform != nullptr) |
|
free(c.model_xform); |
|
} |
|
|
|
mesh& cm = g_cube_mesh; |
|
|
|
if (cm.vertices != nullptr) |
|
free(cm.vertices); |
|
if (cm.normals != nullptr) |
|
free(cm.normals); |
|
if (cm.uvs != nullptr) |
|
free(cm.uvs); |
|
if (cm.colors != nullptr) |
|
free(cm.colors); |
|
if (cm.indices != nullptr) |
|
free(cm.indices); |
|
} |
|
|
|
int |
|
main() |
|
{ |
|
if (!init()) |
|
return 1; |
|
|
|
shader s = {0}; |
|
|
|
if (loadShaderProgram("data/shader.vert", "data/shader.frag", &s)) { |
|
dumpShader(s.prog_id); |
|
g_xforms = initXformUBO(&s); |
|
g_cube_mesh = initCubeMesh(); |
|
|
|
for (u32 i = 0; i < NUM_CUBES; i++) { |
|
g_gl_cubes[i] = |
|
loadGLMesh(&s, g_cube_mesh, GL_TRIANGLES, g_cube_locs[i]); |
|
assert(g_gl_cubes[i].vao_id != 0); |
|
} |
|
|
|
loop(&s, g_gl_cubes, NUM_CUBES); |
|
quit(&s); |
|
return 0; |
|
} |
|
|
|
std::cout << "error loading shader program\n"; |
|
quit(&s); |
|
return 1; |
|
} |
|
|
|
|