Browse Source
new file: .gitignore new file: Makefile new file: dumpShader.inl new file: main.cpp new file: shader_testing new file: shader_testing.hmain
commit
3afa3d9cc8
6 changed files with 528 additions and 0 deletions
@ -0,0 +1,15 @@
|
||||
|
||||
SHELL = /bin/sh
|
||||
CXX = g++
|
||||
CXXFLAGS = -std=c++11 -g -ggdb3 -Wall -I/usr/include/SDL2
|
||||
LDFLAGS = -lSDL2 -lGLEW -lGL
|
||||
BIN = shader_testing
|
||||
|
||||
all: |
||||
$(CXX) $(CXXFLAGS) -MMD main.cpp -o $(BIN) $(LDFLAGS)
|
||||
.PHONY: all |
||||
|
||||
clean: |
||||
rm -rf $(BIN)
|
||||
.PHONY: clean |
||||
|
||||
@ -0,0 +1,61 @@
|
||||
|
||||
#include <GL/glew.h> |
||||
|
||||
#include "shader_testing.h" |
||||
|
||||
|
||||
const char* gl_enum_to_string(GLenum e); |
||||
|
||||
|
||||
void |
||||
dumpShader(GLuint prog_id) |
||||
{ |
||||
std::cout << "dumping shader info, program id: " << prog_id << "\n"; |
||||
|
||||
GLint active_uniforms; |
||||
GLint active_uniform_blocks; |
||||
GLint active_attribs; |
||||
|
||||
// NOTE: unused uniforms/attributes get optimized away |
||||
// https://www.khronos.org/opengl/wiki/Program_Introspection#Attributes |
||||
// https://stackoverflow.com/questions/54811319/how-to-get-from-glgetattriblocation-to-glgetactiveattrib-index |
||||
glGetProgramiv(prog_id, GL_ACTIVE_UNIFORMS, &active_uniforms); |
||||
glGetProgramiv(prog_id, GL_ACTIVE_UNIFORM_BLOCKS, &active_uniform_blocks); |
||||
glGetProgramiv(prog_id, GL_ACTIVE_ATTRIBUTES, &active_attribs); |
||||
|
||||
printf("active uniforms: %d\n", active_uniforms); |
||||
printf("active uniform blocks: %d\n", active_uniform_blocks); |
||||
printf("active attributes: %d\n", active_attribs); |
||||
|
||||
GLchar uni_name[256]; |
||||
GLsizei length; |
||||
GLint size; |
||||
GLenum type; |
||||
|
||||
for (int i = 0; i < active_uniforms; i++) { |
||||
glGetActiveUniform(prog_id, i, sizeof(uni_name), |
||||
&length, &size, &type, uni_name); |
||||
printf("uniform idx: %d, len: %d, type: %s, name: %s \n", |
||||
i, length, gl_enum_to_string(type), uni_name); |
||||
} |
||||
|
||||
for (int i = 0; i < active_attribs; i++) { |
||||
glGetActiveAttrib(prog_id, i, sizeof(uni_name), |
||||
&length, &size, &type, uni_name); |
||||
printf("attribute idx: %d, len: %d, type: %s, name: %s \n", |
||||
i, length, gl_enum_to_string(type), uni_name); |
||||
} |
||||
|
||||
} |
||||
|
||||
const char* |
||||
gl_enum_to_string(GLenum e) |
||||
{ |
||||
switch (e) { |
||||
case 0x8b5c: return "GL_FLOAT_MAT4"; |
||||
case 0x8b51: return "GL_FLOAT_VEC3"; |
||||
|
||||
default: return "???"; |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,349 @@
|
||||
|
||||
#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; |
||||
} |
||||
|
||||
Binary file not shown.
@ -0,0 +1,96 @@
|
||||
|
||||
#pragma once |
||||
|
||||
#include <GL/glew.h> |
||||
#include <glm/glm.hpp> |
||||
|
||||
|
||||
typedef uint32_t u32; |
||||
|
||||
|
||||
struct gl_uniform |
||||
{ |
||||
GLenum id; |
||||
GLenum data_type; |
||||
}; |
||||
|
||||
struct gl_buffer |
||||
{ |
||||
GLuint id; |
||||
GLenum data_type; |
||||
}; |
||||
|
||||
struct shader |
||||
{ |
||||
GLuint prog_id; |
||||
GLuint xforms_ubo_id; |
||||
}; |
||||
|
||||
struct transforms |
||||
{ |
||||
glm::mat4 view_xform; |
||||
glm::mat4 proj_xform; |
||||
glm::mat4 normal_xform; |
||||
}; |
||||
|
||||
enum glsl_layout |
||||
{ |
||||
POSITION, |
||||
NORMAL, |
||||
UV, |
||||
COLOR |
||||
}; |
||||
|
||||
struct mesh |
||||
{ |
||||
u32 num_vertices; |
||||
u32 num_indices; |
||||
glm::vec3* vertices; |
||||
glm::vec3* normals; |
||||
glm::vec3* uvs; |
||||
glm::vec3* colors; |
||||
u32* indices; |
||||
}; |
||||
|
||||
struct gl_mesh |
||||
{ |
||||
u32 num_indices; |
||||
GLuint vao_id; |
||||
GLuint tex_id; |
||||
GLenum draw_mode; |
||||
|
||||
glm::mat4* model_xform; |
||||
GLuint model_xform_id; |
||||
|
||||
GLuint vert_buf_id; |
||||
GLuint norm_buf_id; |
||||
GLuint uv_buf_id; |
||||
GLuint clr_buf_id; |
||||
GLuint idx_buf_id; |
||||
}; |
||||
|
||||
struct node; |
||||
struct entity; |
||||
struct light; |
||||
struct animation; |
||||
|
||||
|
||||
const float DEFAULT_FOV = 60.f; |
||||
const float NEAR_CLIP_PLANE = 5.f; |
||||
const float DEFAULT_ASPECT_RATIO = 16.f / 9.f; |
||||
const glm::vec3 DEFAULT_CAM_POS = { 0, 0, -30.f }; |
||||
const glm::vec3 DEFAULT_LOOK_POS = { 0, 0, 0 }; |
||||
|
||||
|
||||
bool loadShaderProgram(const char* vs, const char* fs, shader* s); |
||||
transforms initXformUBO(shader* s, |
||||
float fov = DEFAULT_FOV, |
||||
float near_clip_plane = NEAR_CLIP_PLANE, |
||||
float aspect_ratio = DEFAULT_ASPECT_RATIO, |
||||
glm::vec3 cam_pos = DEFAULT_CAM_POS, |
||||
glm::vec3 look_pos = DEFAULT_LOOK_POS); |
||||
mesh initCubeMesh(); |
||||
gl_mesh loadGLMesh(shader* s, const mesh& m, const glm::vec3& pos); |
||||
void loop(shader* s, gl_mesh* mesh_arr, u32 num_meshes); |
||||
void quit(shader* s); |
||||
|
||||
Loading…
Reference in new issue