diff --git a/README b/README index 4d39492..d0a27e9 100644 --- a/README +++ b/README @@ -13,7 +13,7 @@ TODO: add input abstraction for SDL store meshes separately from entities for reuse add a function to update camera transforms only once per frame, per shader - fix example Makefile dependenies + update camera to use quaternions for rotation Dependencies: assimp >= 5.0.0 diff --git a/examples/Makefile b/examples/Makefile index 28764a4..065f0ff 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -19,14 +19,31 @@ EXAMPLE_SOURCES = \ simple_mesh/main.cpp \ EXAMPLE_OBJECTS = $(patsubst %/, $(OBJDIR)/%.o, $(dir $(EXAMPLE_SOURCES))) -all: mkdirs $(EXAMPLE_OBJECTS) +EXAMPLES = hello_world simple_mesh assimp_loading +BINARIES = $(patsubst %, $(BINDIR)/%, $(EXAMPLES)) --include $(OBJDIR)/*.d +all: mkdirs $(BINARIES) +.PHONY: all + +$(OBJDIR)/hello_world.o: + $(CXX) $(CXXFLAGS) -c -MMD hello_world/main.cpp -o $@ + +$(BINDIR)/hello_world: $(OBJDIR)/hello_world.o + $(CXX) -o $@ $(LDFLAGS) $^ $(LIB) $(ASSIMP_LIB) + +$(OBJDIR)/simple_mesh.o: + $(CXX) $(CXXFLAGS) -c -MMD simple_mesh/main.cpp -o $@ + +$(BINDIR)/simple_mesh: $(OBJDIR)/simple_mesh.o + $(CXX) -o $@ $(LDFLAGS) $^ $(LIB) $(ASSIMP_LIB) -$(EXAMPLE_OBJECTS): - $(CXX) $(CXXFLAGS) -c -MMD $(basename $(notdir $@))/main.cpp -o $@ - $(CXX) -o $(BINDIR)/$(notdir $(basename $@)) $(LDFLAGS) $@ $(LIB) \ - $(ASSIMP_LIB) +$(OBJDIR)/assimp_loading.o: + $(CXX) $(CXXFLAGS) -c -MMD assimp_loading/main.cpp -o $@ + +$(BINDIR)/assimp_loading: $(OBJDIR)/assimp_loading.o + $(CXX) -o $@ $(LDFLAGS) $^ $(LIB) $(ASSIMP_LIB) + +-include $(OBJDIR)/*.d mkdirs: @mkdir -p $(BINDIR) $(OBJDIR) @@ -35,3 +52,4 @@ mkdirs: clean: rm -rf $(OBJDIR)/* bin/* .PHONY: clean + diff --git a/include/camera.h b/include/camera.h index b545645..8346416 100644 --- a/include/camera.h +++ b/include/camera.h @@ -30,16 +30,37 @@ enum projection_type }; -v2f cameraUnproject(camera& cam, int x, int y, int vp_width, int vp_height); +v2f +cameraUnproject(camera& cam, int x, int y, int vp_width, int vp_height); -v3f cameraCreateRay(camera& cam, v2i vp_coords, v2i vp_dims); +v3f +cameraCreateRay(camera& cam, v2i vp_coords, v2i vp_dims); -bool cameraIntersectPlane(camera& cam, v3f ray, v3f plane_origin, v3f plane_normal, v3f& intersection); +bool +cameraIntersectPlane(camera& cam, + v3f ray, + v3f plane_origin, + v3f plane_normal, + v3f& intersection); -void cameraInitPerspective(camera& cam, glm::vec3 position, glm::vec3 target, glm::vec3 world_up); +void +cameraInitPerspective(camera& cam, + glm::vec3 position, + glm::vec3 target, + glm::vec3 world_up, + float aspect_ratio = 16.f / 9.f); -void cameraMove(camera& cam, bool up, bool left, bool down, bool right, bool forward, bool backward); +void +cameraMove(camera& cam, + bool up, + bool left, + bool down, + bool right, + bool forward, + bool backward); -void cameraRotate(camera& cam, int32 xrel, int32 yrel); +void +cameraRotate(camera& cam, int32 xrel, int32 yrel); -void cameraRoll(camera& cam, bool CW, bool CCW); +void +cameraRoll(camera& cam, bool CW, bool CCW); diff --git a/include/entity.h b/include/entity.h index ba65c3a..fc16687 100644 --- a/include/entity.h +++ b/include/entity.h @@ -28,6 +28,8 @@ bool entInitModel(entity& e, const char* model_path); bool entInitMesh(entity& e, simple_mesh* mesh, GLenum draw_mode); +void entUpdateSimpleMesh(entity& e, simple_mesh* mesh, GLenum draw_mode); + void entFree(entity& e); void entSetWorldPosition(entity& e, glm::vec3 v); diff --git a/include/input.h b/include/input.h index 1be9403..806a716 100644 --- a/include/input.h +++ b/include/input.h @@ -1,6 +1,9 @@ #pragma once +#include + + struct input_state { bool window_closed; @@ -11,6 +14,10 @@ struct input_state bool down; }; +void +inputProcessEvent(input_state* is, SDL_Event& e); + +// NOTE: convenience function that provides a while(SDL_PollEvents()) loop void inputProcessEvents(input_state* is); diff --git a/include/render_object.h b/include/render_object.h index eeae99e..5196e47 100644 --- a/include/render_object.h +++ b/include/render_object.h @@ -28,3 +28,5 @@ roDraw(render_objects* r_ojbs, shader_wrapper sw, light_group* lights); +void +roUpdateSimpleMesh(render_objects* r_objs, simple_mesh* mesh, GLenum draw_mode); diff --git a/include/renderer.h b/include/renderer.h index cf7916c..52b3388 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -92,3 +92,6 @@ renAddLight(render_state* rs, glm::vec3 color = glm::vec3(1, 1, 1), float intensity = 1.0); +glm::vec2 +renGetWindowDims(render_state* rs); + diff --git a/src/camera.cpp b/src/camera.cpp index 0fa34f0..e89b563 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -1,4 +1,6 @@ +#include + #include #include "camera.h" @@ -8,7 +10,6 @@ #define ROTATE_SPEED 0.005f #define CAMERA_Z_CLAMP_ANGLE 85.f #define FOV 60.f -#define ASPECT_RATIO 16.f/9.f #define NEAR_CLIP_PLANE 20.f @@ -19,20 +20,29 @@ inline glm::vec3 convertv3f(v3f v); // interface void -cameraInitPerspective(camera& cam, glm::vec3 position, glm::vec3 target, glm::vec3 world_up) +cameraInitPerspective(camera& cam, + glm::vec3 position, + glm::vec3 target, + glm::vec3 world_up, + float aspect_ratio) { + assert(aspect_ratio > 0); + cam.position = position; cam.target = target; cam.world_up = world_up; - cam.projection = glm::infinitePerspective(glm::radians(FOV), ASPECT_RATIO, NEAR_CLIP_PLANE); + cam.projection = glm::infinitePerspective(glm::radians(FOV), + aspect_ratio, + NEAR_CLIP_PLANE); cam.forward = glm::normalize(target - position); cam.left = glm::normalize(glm::cross(cam.world_up, cam.forward)); cam.up = glm::normalize(glm::cross(cam.forward, cam.left)); cam.hAngle = glm::atan(cam.forward.x, cam.forward.y); - // NOTE: using pythagoras' to get absolute value of relative axis for vAngle component - real32 len = glm::sqrt(glm::pow(cam.forward.y, 2) + glm::pow(cam.forward.x, 2)); + // NOTE: get absolute value of relative axis for vAngle component + real32 len = glm::sqrt(glm::pow(cam.forward.y, 2) + + glm::pow(cam.forward.x, 2)); cam.vAngle = glm::atan(cam.forward.z, len); cam.view = glm::lookAt(cam.position, cam.position + cam.forward, cam.up); diff --git a/src/entity.cpp b/src/entity.cpp index 76226ac..5253599 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -45,6 +45,12 @@ entInitMesh(entity& e, simple_mesh* mesh, GLenum draw_mode) return true; } +void +entUpdateSimpleMesh(entity& e, simple_mesh* mesh, GLenum draw_mode) +{ + roUpdateSimpleMesh(e.render_objs, mesh, draw_mode); +} + void entFree(entity& e) { diff --git a/src/input.cpp b/src/input.cpp index 4ff1248..1f2ded3 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1,39 +1,46 @@ -#include +#include #include "input.h" +void +inputProcessEvent(input_state* is, SDL_Event& e) +{ + assert(is != nullptr); + + switch (e.type) { + case SDL_QUIT: + is->window_closed = true; + break; + case SDL_KEYDOWN: + switch (e.key.keysym.sym) { + case SDLK_ESCAPE: is->escape = true; break; + case SDLK_LEFT: is->left = true; break; + case SDLK_RIGHT: is->right = true; break; + case SDLK_UP: is->up = true; break; + case SDLK_DOWN: is->down = true; break; + } + break; + case SDL_KEYUP: + switch (e.key.keysym.sym) { + case SDLK_ESCAPE: is->escape = false; break; + case SDLK_LEFT: is->left = false; break; + case SDLK_RIGHT: is->right = false; break; + case SDLK_UP: is->up = false; break; + case SDLK_DOWN: is->down = false; break; + } + break; + default: break; + } +} + void inputProcessEvents(input_state* is) { SDL_Event e; - while (SDL_PollEvent(&e)) { - switch (e.type) { - case SDL_QUIT: - is->window_closed = true; - break; - case SDL_KEYDOWN: - switch (e.key.keysym.sym) { - case SDLK_ESCAPE: is->escape = true; break; - case SDLK_LEFT: is->left = true; break; - case SDLK_RIGHT: is->right = true; break; - case SDLK_UP: is->up = true; break; - case SDLK_DOWN: is->down = true; break; - } - break; - case SDL_KEYUP: - switch (e.key.keysym.sym) { - case SDLK_ESCAPE: is->escape = false; break; - case SDLK_LEFT: is->left = false; break; - case SDLK_RIGHT: is->right = false; break; - case SDLK_UP: is->up = false; break; - case SDLK_DOWN: is->down = false; break; - } - break; - default: break; - } - } + while (SDL_PollEvent(&e)) + inputProcessEvent(is, e); } diff --git a/src/render_object.cpp b/src/render_object.cpp index 48a00e1..7a216dc 100644 --- a/src/render_object.cpp +++ b/src/render_object.cpp @@ -46,7 +46,10 @@ void drawSimple(render_objects* r_objs, shader_wrapper sw, light_group* lights); inline void enableGLFloatBuffer(uint buffer_id, uint location); -bool initGLFloatBuffer(glm::vec3* buffer, uint count, GLuint& buffer_id); +bool initGLFloatBuffer(glm::vec3* buffer, + uint count, + GLuint& buffer_id, + GLenum usage = GL_STATIC_DRAW); bool initGLIndexBuffer(uint* buffer, uint num_indices, GLuint& buffer_id); bool initGLTexture(const util_image image, GLuint& tex_id); bool loadMeshIntoGL(default_render_object* ro_out, mesh_info* mi_in); @@ -93,10 +96,12 @@ roInitSimpleMesh(simple_mesh& mesh_in, GLenum draw_mode) if (initGLFloatBuffer(mesh_in.vertices, mesh_in.num_vertices, - objects->vertex_buffer_id) && + objects->vertex_buffer_id, + GL_DYNAMIC_DRAW) && initGLFloatBuffer(mesh_in.vert_colors, mesh_in.num_vertices, - objects->vertex_color_buffer_id)) + objects->vertex_color_buffer_id, + GL_DYNAMIC_DRAW)) { objects->model_transform = mesh_in.model_transform; objects->vertex_count = mesh_in.num_vertices; @@ -145,6 +150,28 @@ roDraw(render_objects* r_objs, drawDefault(r_objs, world_transform, cam, sw, lights); } +void +roUpdateSimpleMesh(render_objects* r_objs, simple_mesh* mesh, GLenum draw_mode) +{ + assert(r_objs != nullptr && r_objs->objects != nullptr); + assert(mesh != nullptr && mesh->vertices != nullptr); + simple_render_object* sro = (simple_render_object*) r_objs->objects; + assert(sro->vertex_count == mesh->num_vertices); + + sro->draw_mode = draw_mode; + glBindBuffer(GL_ARRAY_BUFFER, sro->vertex_buffer_id); + glBufferSubData( + GL_ARRAY_BUFFER, + 0, + 3 * sro->vertex_count * sizeof(GLfloat), + mesh->vertices); + glBindBuffer(GL_ARRAY_BUFFER, sro->vertex_color_buffer_id); + glBufferSubData( + GL_ARRAY_BUFFER, + 0, + 3 * sro->vertex_count * sizeof(GLfloat), + mesh->vert_colors); +} // internal @@ -216,14 +243,17 @@ enableGLFloatBuffer(uint buffer_id, uint location) } bool -initGLFloatBuffer(glm::vec3* buffer, uint count, GLuint& buffer_id) +initGLFloatBuffer(glm::vec3* buffer, + uint count, + GLuint& buffer_id, + GLenum usage) { glGenBuffers(1, &buffer_id); glBindBuffer(GL_ARRAY_BUFFER, buffer_id); glBufferData(GL_ARRAY_BUFFER, count * 3 * sizeof(GLfloat), // NOTE: 3 floats per vertex prop buffer, - GL_STATIC_DRAW); + usage); return (glGetError() == GL_NO_ERROR); } diff --git a/src/renderer.cpp b/src/renderer.cpp index d287e47..064f243 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -164,6 +164,15 @@ renAddLight(render_state* rs, glm::vec3 pos, glm::vec3 color, float intensity) return true; } +glm::vec2 +renGetWindowDims(render_state* rs) +{ + int x = 0, y = 0; + SDL_GetWindowSize(rs->handles->window, &x, &y); + glm::vec2 dims(x, y); + return dims; +} + // internal