Skip to content

Commit

Permalink
In-progress effort towards cooler rendering
Browse files Browse the repository at this point in the history
 - This still works as the previous commit, but some files have been
   renamed and code has been restructured in some places.

 - Notably, you can now toggle between rendering modes by pressing the
   "M" key while the program is running.

 - However, the more sophisticated rendering mode doesn't currently
   work. Just don't press 'M' for now; the rest of it still works as
   before.

 - Committing so I can try some different geometry shader stuff
  • Loading branch information
yalue committed Feb 27, 2022
1 parent d6002ea commit a64f714
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 18 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ keypresses:

- Reload the config file: Press the "R" key.

- Switch between rendering modes: Press the "M" key.

- Quit the program: Close the window, or press the escape key.

Configuring the L-System
Expand Down
27 changes: 24 additions & 3 deletions l_system_3d.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define DEFAULT_WINDOW_WIDTH (800)
#define DEFAULT_WINDOW_HEIGHT (600)
#define DEFAULT_FPS (60.0)
#define DEFAULT_GEOMETRY_THICKNESS (0.5)

static ApplicationState* AllocateApplicationState(void) {
ApplicationState *to_return = NULL;
Expand All @@ -26,6 +27,7 @@ static ApplicationState* AllocateApplicationState(void) {
to_return->aspect_ratio = ((float) to_return->window_width) /
((float) to_return->window_height);
to_return->frame_duration = 1.0 / DEFAULT_FPS;
to_return->shared_uniforms.geometry_thickness = DEFAULT_GEOMETRY_THICKNESS;
return to_return;
}

Expand Down Expand Up @@ -98,6 +100,7 @@ static int GenerateVertices(ApplicationState *s) {
int result;
uint32_t char_index, inst_index;
uint8_t c;
float size_scale;
ResetTurtle3D(t);
for (char_index = 0; char_index < s->l_system_length; char_index++) {
c = s->l_system_string[char_index];
Expand All @@ -117,10 +120,11 @@ static int GenerateVertices(ApplicationState *s) {
return 0;
}
if (!SetTransformInfo(s->turtle, s->mesh->model, s->mesh->normal,
s->mesh->location_offset)) {
s->mesh->location_offset, &size_scale)) {
printf("Failed getting transform matrices.\n");
return 0;
}
s->shared_uniforms.size_scale = size_scale;
return 1;
}

Expand Down Expand Up @@ -233,6 +237,10 @@ static int ProcessInputs(ApplicationState *s) {
glfwSetWindowShouldClose(s->window, 1);
return 1;
}
// TODO: Replace this key-press logic with a single function that checks
// the state of key_pressed_tmp, setting or unsetting it if necessary and
// returning true on a "new" press.

// s->key_pressed_tmp is used to prevent counting one press multiple times,
// and to prevent up and down from being pressed together.
pressed = glfwGetKey(s->window, GLFW_KEY_UP) == GLFW_PRESS;
Expand Down Expand Up @@ -265,6 +273,18 @@ static int ProcessInputs(ApplicationState *s) {
// R pressed -> R released
s->key_pressed_tmp = 0;
}
pressed = glfwGetKey(s->window, GLFW_KEY_M) == GLFW_PRESS;
if (!s->key_pressed_tmp && pressed) {
// Nothing pressed -> M pressed
s->key_pressed_tmp = GLFW_KEY_M;
if (!SwitchRenderingModes(s->mesh)){
printf("Failed switching rendering modes.\n");
return 0;
}
} else if ((s->key_pressed_tmp == GLFW_KEY_M) && !pressed) {
// M pressed -> M released
s->key_pressed_tmp = 0;
}
return 1;
}

Expand Down Expand Up @@ -303,8 +323,9 @@ static int WaitNextFrame(ApplicationState *s) {

static int RunMainLoop(ApplicationState *s) {
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// TODO: Re-enable face culling after getting the geometry shader working.
//glEnable(GL_CULL_FACE);
//glCullFace(GL_BACK);
glClearColor(0, 0, 0, 1.0);
while (!glfwWindowShouldClose(s->window)) {
s->frame_start = glfwGetTime();
Expand Down
3 changes: 3 additions & 0 deletions l_system_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ typedef struct {
mat4 projection;
mat4 view;
vec4 camera_position;
float size_scale;
float geometry_thickness;
float pad[2];
} SharedUniforms;

// Maintains global data about the running program.
Expand Down
45 changes: 39 additions & 6 deletions l_system_mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,13 @@ static GLuint LoadShader(const char *path, GLenum shader_type) {
}

// Links and returns the shader program from the given source file names.
// The geometry_src_file can be NULL if a geometry shader isn't used. A
// vertex and fragment shader are always required.
static GLuint CreateShaderProgram(const char *vertex_src_file,
const char *fragment_src_file) {
const char *geometry_src_file, const char *fragment_src_file) {
GLchar link_log[512];
GLint link_result = 0;
GLuint vertex_shader, fragment_shader, to_return;
GLuint vertex_shader, geometry_shader, fragment_shader, to_return;

vertex_shader = LoadShader(vertex_src_file, GL_VERTEX_SHADER);
if (!vertex_shader) {
Expand All @@ -96,11 +98,28 @@ static GLuint CreateShaderProgram(const char *vertex_src_file,
glDeleteShader(vertex_shader);
return 0;
}

// Only load the geometry shader if requested.
geometry_shader = 0;
if (geometry_src_file != NULL) {
geometry_shader = LoadShader(geometry_src_file, GL_GEOMETRY_SHADER);
if (!geometry_shader) {
printf("Couldn't load geometry shader.\n");
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return 0;
}
}

to_return = glCreateProgram();
glAttachShader(to_return, vertex_shader);
if (geometry_shader) {
glAttachShader(to_return, geometry_shader);
}
glAttachShader(to_return, fragment_shader);
glLinkProgram(to_return);
glDeleteShader(vertex_shader);
glDeleteShader(geometry_shader);
glDeleteShader(fragment_shader);
glGetProgramiv(to_return, GL_LINK_STATUS, &link_result);
memset(link_log, 0, sizeof(link_log));
Expand Down Expand Up @@ -131,11 +150,11 @@ static int UniformIndex(GLuint program, const char *name, GLint *index) {

// Loads the shaders for the model, and looks up uniform indices. Returns 0 on
// error.
static int SetupShaderProgram(LSystemMesh *m) {
static int SetupShaderProgram(LSystemMesh *m, const char *vertex_src,
const char *geometry_src, const char *fragment_src) {
GLuint p;
GLuint block_index;
p = CreateShaderProgram("./mesh_vertex_shader.vert",
"./mesh_fragment_shader.frag");
p = CreateShaderProgram(vertex_src, geometry_src, fragment_src);
if (!p) return 0;
m->shader_program = p;
if (!UniformIndex(p, "model", &(m->model_uniform_index))) return 0;
Expand All @@ -154,6 +173,19 @@ static int SetupShaderProgram(LSystemMesh *m) {
return CheckGLErrors();
}

int SwitchRenderingModes(LSystemMesh *m) {
glDeleteProgram(m->shader_program);
m->shader_program = 0;
if (m->using_geometry_shader) {
m->using_geometry_shader = 0;
return SetupShaderProgram(m, "simple_shader.vert", NULL,
"simple_shader.frag");
}
m->using_geometry_shader = 1;
return SetupShaderProgram(m, "pipes_shader.vert", "pipes_shader.geom",
"pipes_shader.frag");
}

LSystemMesh* CreateLSystemMesh(void) {
LSystemMesh *m = NULL;

Expand Down Expand Up @@ -186,7 +218,8 @@ LSystemMesh* CreateLSystemMesh(void) {
DestroyLSystemMesh(m);
return NULL;
}
if (!SetupShaderProgram(m)) {
if (!SetupShaderProgram(m, "simple_shader.vert", NULL,
"simple_shader.frag")) {
DestroyLSystemMesh(m);
return NULL;
}
Expand Down
7 changes: 7 additions & 0 deletions l_system_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ typedef struct {
uint32_t vertex_count;
// OpenGL stuff needed for drawing this mesh.
GLuint shader_program;
// If nonzero, the shader program is currently the more complex geometry
// version. If zero, we're just rendering the wireframe.
int using_geometry_shader;
GLuint vao;
GLuint vbo;
// The model and normal matrices used when drawing this mesh.
Expand Down Expand Up @@ -62,4 +65,8 @@ int SetMeshVertices(LSystemMesh *m, MeshVertex *vertices, uint32_t count);
// Draws the mesh. Returns 0 on error, including any GL errors if they occur.
int DrawMesh(LSystemMesh *m);

// Cycles between rendering modes (i.e. shader programs) that may be used to
// render the given mesh. Returns 0 on error.
int SwitchRenderingModes(LSystemMesh *m);

#endif // L_SYSTEM_MESH_H
18 changes: 18 additions & 0 deletions pipes_shader.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#version 330 core

in GS_OUT {
vec3 frag_position;
vec3 forward;
vec3 up;
vec3 right;
vec4 color;
} fs_in;


out vec4 frag_color;

//INCLUDE_SHARED_UNIFORMS

void main() {
frag_color = fs_in.color;
}
57 changes: 57 additions & 0 deletions pipes_shader.geom
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#version 330 core
layout (lines) in;
layout (triangle_strip, max_vertices = 4) out;

in VS_OUT {
vec3 position;
vec3 forward;
vec3 up;
vec3 right;
vec4 color;
} gs_in[];

out GS_OUT {
vec3 frag_position;
vec3 forward;
vec3 up;
vec3 right;
vec4 color;
} gs_out;

//INCLUDE_SHARED_UNIFORMS

void main() {
vec3 right = gs_in[0].right;
vec3 forward = gs_in[0].forward;
vec3 bottom = gs_in[0].position;
vec3 top = gs_in[0].position;
// NOTE: verify this is in the correct order.
mat4 projView = shared_uniforms.projection * shared_uniforms.view;
// The normal vectors don't change.
gs_out.forward = forward;
gs_out.up = gs_in[0].up;
gs_out.right = right;
//gs_out.color = gs_in[1].color;
gs_out.color = vec4(0.5, 0.3, 1.0, 1.0);

float half_rect_width = 0.5 * shared_uniforms.geometry_thickness *
shared_uniforms.size_scale;

// Bottom left
gs_out.frag_position = bottom - (right * half_rect_width);
gl_Position = projView * vec4(gs_out.frag_position, 1.0);
EmitVertex();
// Bottom right
gs_out.frag_position = bottom + (right * half_rect_width);
gl_Position = projView * vec4(gs_out.frag_position, 1.0);
EmitVertex();
// Top right
gs_out.frag_position = top + (right * half_rect_width);
gl_Position = projView * vec4(gs_out.frag_position, 1.0);
EmitVertex();
// Top left
gs_out.frag_position = top - (right * half_rect_width);
gl_Position = projView * vec4(gs_out.frag_position, 1.0);
EmitVertex();
EndPrimitive();
}
29 changes: 29 additions & 0 deletions pipes_shader.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#version 330 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec3 forward_in;
layout (location = 2) in vec3 up_in;
layout (location = 3) in vec4 color_in;

// Added to the location of each vertex to center the overall mesh on 0,0,0.
uniform vec3 location_offset;

uniform mat4 model;
uniform mat3 normal;

out VS_OUT {
vec3 position;
vec3 forward;
vec3 up;
vec3 right;
vec4 color;
} vs_out;

//INCLUDE_SHARED_UNIFORMS

void main() {
vs_out.position = (model * vec4(position_in + location_offset, 1.0)).xyz;
vs_out.forward = normalize(normal * forward_in);
vs_out.up = normalize(normal * up_in);
vs_out.right = normalize(cross(vs_out.forward, vs_out.up));
vs_out.color = color_in;
}
3 changes: 3 additions & 0 deletions shared_uniforms.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@ layout(std140) uniform SharedUniforms {
mat4 projection;
mat4 view;
vec4 camera_position;
float size_scale;
float geometry_thickness;
float pad[2];
} shared_uniforms;

3 changes: 3 additions & 0 deletions mesh_fragment_shader.frag → simple_shader.frag
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

in VS_OUT {
vec3 frag_position;
vec3 forward;
vec3 up;
vec3 right;
vec4 color;
} fs_in;

Expand Down
16 changes: 11 additions & 5 deletions mesh_vertex_shader.vert → simple_shader.vert
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ uniform vec3 location_offset;

out VS_OUT {
vec3 frag_position;
vec3 forward;
vec3 up;
vec3 right;
vec4 color;
} vs_out;

Expand All @@ -22,12 +25,15 @@ void main() {
gl_Position = shared_uniforms.projection * shared_uniforms.view * model *
vec4(position_in + location_offset, 1.0);
vs_out.color = color_in;
vs_out.forward = normal * forward_in;
vs_out.up = normal * up_in;
vs_out.right = normalize(cross(vs_out.forward, vs_out.up));

// Prevent optimizing out the normal uniform.
// TODO (eventually): Remove once we actually use the normal uniform.
if (normal[0].x < -1) {
vs_out.color[1] = 1;
// Used to prevent the normal matrix from being optimized out. (I don't want
// to have to ignore the error when looking for its uniform location.)
if (normal[0][0] == 0.0001) {
vs_out.color[0] *= 0.9999;
}

vs_out.frag_position = vec3(model * vec4(position_in, 1.0));
vs_out.frag_position = vec3(model * vec4(position_in + location_offset, 1.0));
}
7 changes: 5 additions & 2 deletions turtle_3d.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ static void ModelToNormalMatrix(mat4 model, mat3 normal) {
glm_mat4_pick3(dst, normal);
}

int SetTransformInfo(Turtle3D *t, mat4 model, mat3 normal, vec3 loc_offset) {
int SetTransformInfo(Turtle3D *t, mat4 model, mat3 normal, vec3 loc_offset,
float *size_scale) {
float dx, dy, dz, max_axis;
*size_scale = 1.0;
dx = t->max_bounds[0] - t->min_bounds[0];
dy = t->max_bounds[1] - t->min_bounds[1];
dz = t->max_bounds[2] - t->min_bounds[2];
Expand All @@ -145,7 +147,8 @@ int SetTransformInfo(Turtle3D *t, mat4 model, mat3 normal, vec3 loc_offset) {
max_axis = Max3(dx, dy, dz);
glm_mat4_identity(model);
if (max_axis > 0) {
glm_scale_uni(model, MESH_CUBE_SIZE / max_axis);
*size_scale = MESH_CUBE_SIZE / max_axis;
glm_scale_uni(model, *size_scale);
}
ModelToNormalMatrix(model, normal);
// TODO (eventually): If I get less stupid, combine the loc_offset
Expand Down
6 changes: 4 additions & 2 deletions turtle_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@ void DestroyTurtle3D(Turtle3D *t);

// Sets the model and normal matrices for the turtle's vertices, and the
// location offset vector (to be added to each vertex location) that will
// center the mesh on 0, 0, 0. Returns 0 on error.
int SetTransformInfo(Turtle3D *t, mat4 model, mat3 normal, vec3 loc_offset);
// center the mesh on 0, 0, 0. Returns 0 on error. Also returns the linear
// scale by which the model matrix scales up or down.
int SetTransformInfo(Turtle3D *t, mat4 model, mat3 normal, vec3 loc_offset,
float *size_scale);

// The type used by all turtle-movement instructions. Some instructions may not
// use the floating-point parameter. All instructions must return 0 on error
Expand Down

0 comments on commit a64f714

Please sign in to comment.