diff --git a/Makefile b/Makefile index 289dee7..726d0bc 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,8 @@ OBJS = \ src/view.o \ src/minecraft.o \ src/hud.o \ - src/lighting.o + src/lighting.o \ + src/collision_scene.o all: test.so diff --git a/include/collision.h b/include/collision.h new file mode 100644 index 0000000..73735c6 --- /dev/null +++ b/include/collision.h @@ -0,0 +1,25 @@ +#pragma once + +#include "directxmath/directxmath.h" + +namespace collision { + + struct AABB { + XMVECTOR min; + XMVECTOR max; + }; + + static inline AABB cube_aabb(XMVECTOR const & center, float half) + { + half = fabsf(half); + XMVECTOR min = center + XMVectorReplicate(-half); + XMVECTOR max = center + XMVectorReplicate( half); + return AABB(min, max); + } + + static inline XMVECTOR closest_point_point_aabb(XMVECTOR const & p, AABB const & aabb) + { + return XMVectorClamp(p, aabb.min, aabb.max); + } + +} diff --git a/include/collision_scene.h b/include/collision_scene.h new file mode 100644 index 0000000..b1ee898 --- /dev/null +++ b/include/collision_scene.h @@ -0,0 +1,7 @@ +#pragma once + +namespace collision_scene { + void load(); + void draw(); + void update(int up, int down, int left, int right); +} diff --git a/shader/collision_scene.frag b/shader/collision_scene.frag new file mode 100644 index 0000000..9b9da0a --- /dev/null +++ b/shader/collision_scene.frag @@ -0,0 +1,14 @@ +#version 330 core + +out vec4 Color; + +flat in int InstanceID; + +uniform vec3 BaseColor; + +void main() +{ + float intensity = (InstanceID == 0) ? 0.7 : 0.3; + + Color = vec4(BaseColor * intensity, 1); +} diff --git a/shader/collision_scene.vert b/shader/collision_scene.vert new file mode 100644 index 0000000..67dc63b --- /dev/null +++ b/shader/collision_scene.vert @@ -0,0 +1,39 @@ +#version 330 core + +// per-vertex +in vec2 Position; + +flat out int InstanceID; + +uniform mat4 Transform; +uniform bool UseGridTransform; + +vec2 world_translation() +{ + if (gl_InstanceID == 0) + return vec2(0, 0); + int instance = gl_InstanceID + 1; + float negative = ((instance % 2) == 0) ? -1.0 : 1.0; + + vec2 translation = (Position.x == 0) ? vec2(1, 0) : vec2(0, 1); + + return translation * negative * (instance >> 1); +} + +vec2 grid_transform(vec2 position) +{ + return position * 4 + world_translation(); +} + +void main() +{ + InstanceID = gl_InstanceID; + + vec2 position; + if (UseGridTransform) + position = grid_transform(Position); + else + position = Position; + + gl_Position = Transform * vec4(position, 0, 1); +} diff --git a/src/collision.cpp b/src/collision.cpp deleted file mode 100644 index 1620ef3..0000000 --- a/src/collision.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "directxmath/directxmath.h" - -struct AABB { - XMVECTOR min; - XMVECTOR max; -}; - -XMVECTOR closest_point_point_aabb(XMVECTOR const &p, AABB const& aabb) -{ - return XMVectorClamp(p, aabb.min, aabb.max); -} diff --git a/src/collision_scene.cpp b/src/collision_scene.cpp new file mode 100644 index 0000000..c2ebfb2 --- /dev/null +++ b/src/collision_scene.cpp @@ -0,0 +1,246 @@ +#include "glad/gl.h" +#include "directxmath/directxmath.h" +#include "opengl.h" + +#include "collision.h" +#include "collision_scene.h" + +namespace collision_scene { + + struct location { + struct { + unsigned int position; + } attrib; + struct { + unsigned int transform; + unsigned int use_grid_transform; + unsigned int base_color; + } uniform; + }; + + static unsigned int program; + static location location; + + static unsigned int vertex_array_object; + static unsigned int per_vertex_buffer; + + static unsigned int index_buffer; + + static XMVECTOR point_position; + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wnarrowing" + const _Float16 vertex_data[] = { + // 0: lines + -1.0, 0.0, 1.0, 0.0, // horizontal, left to right + 0.0, 1.0, 0.0, -1.0, // vertical, top to bottom + + // 4: "cube" + -1.0, 1.0, // tl + 1.0, 1.0, // tr + 1.0, -1.0, // br + -1.0, -1.0, // bl + + // 8: "circle" + 0.000000, -1.000000, + -0.195090, -0.980785, + -0.382683, -0.923880, + -0.555570, -0.831470, + -0.707107, -0.707107, + -0.831470, -0.555570, + -0.923880, -0.382683, + -0.980785, -0.195090, + -1.000000, 0.000000, + -0.980785, 0.195090, + -0.923880, 0.382683, + -0.831470, 0.555570, + -0.707107, 0.707107, + -0.555570, 0.831470, + -0.382683, 0.923880, + -0.195090, 0.980785, + 0.000000, 1.000000, + 0.195090, 0.980785, + 0.382683, 0.923880, + 0.555570, 0.831470, + 0.707107, 0.707107, + 0.831470, 0.555570, + 0.923880, 0.382683, + 0.980785, 0.195090, + 1.000000, 0.000000, + 0.980785, -0.195090, + 0.923880, -0.382683, + 0.831470, -0.555570, + 0.707107, -0.707107, + 0.555570, -0.831470, + 0.382683, -0.923880, + 0.195090, -0.980785, + }; + #pragma GCC diagnostic pop + const int vertex_data_size = (sizeof (vertex_data)); + + const int per_vertex_size = (sizeof (_Float16)) * 2; + + const unsigned short index_data[] = { + // "cube" (line strip) + 0, 1, 2, 3, 0, + + // "circle" (line strip) + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 0, + }; + const int index_data_size = (sizeof (index_data)); + + void load_program() + { + program = compile_from_files("shader/collision_scene.vert", + nullptr, + "shader/collision_scene.frag"); + + location.attrib.position = glGetAttribLocation(program, "Position"); + + location.uniform.transform = glGetUniformLocation(program, "Transform"); + location.uniform.use_grid_transform = glGetUniformLocation(program, "UseGridTransform"); + location.uniform.base_color = glGetUniformLocation(program, "BaseColor"); + } + + void load_vertex_attributes() + { + glGenVertexArrays(1, &vertex_array_object); + glBindVertexArray(vertex_array_object); + + glVertexBindingDivisor(0, 0); + + glEnableVertexAttribArray(location.attrib.position); + glVertexAttribFormat(location.attrib.position, 2, GL_HALF_FLOAT, GL_FALSE, 0); + glVertexAttribBinding(location.attrib.position, 0); + + glBindVertexArray(0); + } + + void load_per_vertex_buffer() + { + glGenBuffers(1, &per_vertex_buffer); + + glBindBuffer(GL_ARRAY_BUFFER, per_vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, vertex_data_size, vertex_data, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + void load_index_buffer() + { + glGenBuffers(1, &index_buffer); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_data_size, index_data, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + void load() + { + load_program(); + load_vertex_attributes(); + + load_per_vertex_buffer(); + + load_index_buffer(); + + point_position = XMVectorSet(0, 0, 0, 1); + } + + static inline XMMATRIX view() + { + XMVECTOR eye = XMVectorSet(0, 0, 1, 0); + XMVECTOR at = XMVectorSet(0, 0, 0, 0); + XMVECTOR up = XMVectorSet(0, 1, 0, 0); + return XMMatrixLookAtRH(eye, at, up); + } + + static inline XMMATRIX projection() + { + return XMMatrixOrthographicRH(10, 10, 0, 10); + } + + void update(int up, int down, int left, int right) + { + float rate = 0.1f; + float forward = (rate * up + -rate * down); + float strafe = (-rate * left + rate * right); + + point_position = XMVector3Transform(point_position, XMMatrixTranslation(strafe, forward, 0)); + } + + static inline void set_transform(XMMATRIX const & transform) + { + XMFLOAT4X4 float_transform; + XMStoreFloat4x4(&float_transform, transform); + glUniformMatrix4fv(location.uniform.transform, 1, false, (float *)&float_transform); + } + + void draw() + { + glUseProgram(program); + + glBlendFunc(GL_ONE, GL_ZERO); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + + glBindVertexArray(vertex_array_object); + glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + + XMMATRIX transform = view() * projection(); + XMFLOAT4X4 float_transform; + XMStoreFloat4x4(&float_transform, transform); + + // grid + glUniformMatrix4fv(location.uniform.transform, 1, false, (float *)&float_transform); + glUniform3f(location.uniform.base_color, 0, 1, 0); + glUniform1i(location.uniform.use_grid_transform, 1); + glDrawArraysInstanced(GL_LINES, 0, 4, 7); + + // cube + float cube_half = 0.5; + XMVECTOR cube_position = XMVectorSet(1, 0, 0, 0); + XMMATRIX cube_transform + = XMMatrixScaling(cube_half, cube_half, cube_half) + * XMMatrixTranslationFromVector(cube_position) + * transform; + set_transform(cube_transform); + glUniform3f(location.uniform.base_color, 0, 0.5, 1.0); + glUniform1i(location.uniform.use_grid_transform, 0); + const int cube_base_vertex = 4; + const int cube_base_index = 0; + glDrawElementsBaseVertex(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, (void*)(cube_base_index), cube_base_vertex); + + // circle + const int circle_base_vertex = 8; + const int circle_base_index = 5 * (sizeof (unsigned short)); + + XMMATRIX point_scale = XMMatrixScaling(0.05, 0.05, 0.05); + + // point + glUniform3f(location.uniform.base_color, 1.0, 0.5, 0.0); + + XMMATRIX point_transform + = point_scale + * XMMatrixTranslationFromVector(point_position) + * transform; + set_transform(point_transform); + glDrawElementsBaseVertex(GL_LINE_STRIP, 33, GL_UNSIGNED_SHORT, (void*)(circle_base_index), circle_base_vertex); + + // closest point + glUniform3f(location.uniform.base_color, 1.0, 0.0, 0.0); + + collision::AABB cube_aabb = collision::cube_aabb(cube_position, cube_half); + XMVECTOR closest_point_position = collision::closest_point_point_aabb(point_position, cube_aabb); + XMMATRIX closest_point_transform + = point_scale + * XMMatrixTranslationFromVector(closest_point_position) + * transform; + set_transform(closest_point_transform); + glDrawElementsBaseVertex(GL_LINE_STRIP, 33, GL_UNSIGNED_SHORT, (void*)(circle_base_index), circle_base_vertex); + } +} diff --git a/src/test.cpp b/src/test.cpp index eb27854..6809cab 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -17,6 +17,7 @@ #include "minecraft.h" #include "hud.h" #include "lighting.h" +#include "collision_scene.h" struct line_location { struct { @@ -278,6 +279,12 @@ void load(const char * source_path) non_block::load_index_buffer(); non_block::load_per_vertex_buffer(); non_block::load_vertex_attributes(); + + ////////////////////////////////////////////////////////////////////// + // collision_scene + ////////////////////////////////////////////////////////////////////// + + collision_scene::load(); } void update_keyboard(int up, int down, int left, int right) @@ -285,6 +292,7 @@ void update_keyboard(int up, int down, int left, int right) //float forward = (0.1f * up + -0.1f * down); //float strafe = (-0.1f * left + 0.1f * right); //view::third_person::apply_translation(forward, strafe, 0); + collision_scene::update(up, down, left, right); } const int max_joysticks = 8; @@ -452,6 +460,7 @@ void draw() glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearDepth(-1.0f); + /* // possibly re-initialize geometry buffer if window width/height changes init_geometry_buffer(geometry_buffer_pnc, geometry_buffer_pnc_types); @@ -468,6 +477,11 @@ void draw() lighting::draw(); //draw_quad(); hud::draw(); + */ + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + collision_scene::draw(); last_frame_time = current_time; }