diff --git a/Makefile b/Makefile index 576d40b..0a51c7e 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,8 @@ OBJS = \ src/opengl.o \ src/test.o \ src/font.o \ - src/window.o + src/window.o \ + src/bresenham.o all: test.so diff --git a/include/bresenham.h b/include/bresenham.h new file mode 100644 index 0000000..3504d81 --- /dev/null +++ b/include/bresenham.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void bresenham(int x1, int y1, int z1, + int x2, int y2, int z2, + void (*func)(int x, int y, int z)); + +#ifdef __cplusplus +} +#endif diff --git a/include/test.h b/include/test.h index 65a708a..da9779a 100644 --- a/include/test.h +++ b/include/test.h @@ -6,6 +6,7 @@ extern "C" { void load(const char * source_path); void draw(); + void kb_update(int up, int down, int left, int right); void update(float lx, float ly, float rx, float ry, float tl, float tr, int up, int down, int left, int right, int a, int b, int x, int y); diff --git a/main.lua b/main.lua index d6fa7e3..b9b1425 100644 --- a/main.lua +++ b/main.lua @@ -8,6 +8,7 @@ function init() void load(const char * source_path); void update_window(int width, int height); void draw(); +void kb_update(int kbup, int kbdown, int kbleft, int kbright); void update(float lx, float ly, float rx, float ry, float tl, float tr, int up, int down, int left, int right, int a, int b, int x, int y); @@ -34,8 +35,17 @@ local update = function(dt) local b = joystick:isGamepadDown("b") local x = joystick:isGamepadDown("x") local y = joystick:isGamepadDown("y") - test.update(lx, ly, rx, ry, tl, tr, up, down, left, right, a, b, x, y) + + test.update(lx, ly, rx, ry, tl, tr, + up, down, left, right, + a, b, x, y) end + + local up = love.keyboard.isDown("up") + local down = love.keyboard.isDown("down") + local left = love.keyboard.isDown("left") + local right = love.keyboard.isDown("right") + test.kb_update(up, down, left, right); end local draw = function() diff --git a/shader/line.frag b/shader/line.frag new file mode 100644 index 0000000..7cb18cf --- /dev/null +++ b/shader/line.frag @@ -0,0 +1,18 @@ +#version 330 core + +in VS_OUT { + vec3 Position; // world coordinates + vec3 Normal; + vec2 Texture; +} fs_in; + +layout (location = 0) out vec3 Position; +layout (location = 1) out vec3 Normal; +layout (location = 2) out vec3 Color; + +void main() +{ + Position = fs_in.Position.xzy; + Normal = normalize(fs_in.Normal.xzy); + Color = vec3(0.5, 0, 1); +} diff --git a/shader/line.vert b/shader/line.vert new file mode 100644 index 0000000..4a65cbd --- /dev/null +++ b/shader/line.vert @@ -0,0 +1,27 @@ +#version 330 core + +// per-vertex: +in vec3 Position; +in vec3 Normal; +in vec2 Texture; +// per-instance: +in vec3 BlockPosition; + +out VS_OUT { + vec3 Position; + vec3 Normal; + vec2 Texture; +} vs_out; + +uniform mat4 Transform; + +void main() +{ + vec3 position = Position + BlockPosition; // world coordinates + + vs_out.Position = position; + vs_out.Normal = Normal; + vs_out.Texture = Texture; + + gl_Position = Transform * vec4(position.xzy, 1.0); +} diff --git a/src/bresenham.c b/src/bresenham.c new file mode 100644 index 0000000..d722b9a --- /dev/null +++ b/src/bresenham.c @@ -0,0 +1,78 @@ +#include +#include "bresenham.h" + +void bresenham(int x1, int y1, int z1, + int x2, int y2, int z2, + void (*func)(int x, int y, int z)) +{ + int pt_x = x1; + int pt_y = y1; + int pt_z = z1; + + int dx = x2 - x1; + int dy = y2 - y1; + int dz = z2 - z1; + int x_inc = (dx < 0) ? -1 : 1; + int y_inc = (dy < 0) ? -1 : 1; + int z_inc = (dz < 0) ? -1 : 1; + int l = abs(dx); + int m = abs(dy); + int n = abs(dz); + int dx2 = l << 1; + int dy2 = m << 1; + int dz2 = n << 1; + + if ((l >= m) && (l >= n)) { + int err_1 = dy2 - l; + int err_2 = dz2 - l; + for (int i = 0; i < l; i++) { + func(pt_x, pt_y, pt_z); + if (err_1 > 0) { + pt_y += y_inc; + err_1 -= dx2; + } + if (err_2 > 0) { + pt_z += z_inc; + err_2 -= dx2; + } + err_1 += dy2; + err_2 += dz2; + pt_x += x_inc; + } + } else if ((m >= l) && (m >= n)) { + int err_1 = dx2 - m; + int err_2 = dz2 - m; + for (int i = 0; i < m; i++) { + func(pt_x, pt_y, pt_z); + if (err_1 > 0) { + pt_x += x_inc; + err_1 -= dy2; + } + if (err_2 > 0) { + pt_z += z_inc; + err_2 -= dy2; + } + err_1 += dx2; + err_2 += dz2; + pt_y += y_inc; + } + } else { + int err_1 = dy2 - n; + int err_2 = dx2 - n; + for (int i = 0; i < n; i++) { + func(pt_x, pt_y, pt_z); + if (err_1 > 0) { + pt_y += y_inc; + err_1 -= dz2; + } + if (err_2 > 0) { + pt_x += x_inc; + err_2 -= dz2; + } + err_1 += dy2; + err_2 += dx2; + pt_z += z_inc; + } + } + func(pt_x, pt_y, pt_z); +} diff --git a/src/test.cpp b/src/test.cpp index 8f65ba6..b7bdddd 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -8,6 +8,7 @@ #include "test.h" #include "font.h" #include "window.h" +#include "bresenham.h" #include "data.inc" @@ -33,6 +34,22 @@ struct test_location { static unsigned int test_program; static test_location test_location; +struct line_location { + struct { + unsigned int position; + unsigned int normal; + unsigned int texture; + unsigned int block_position; + } attrib; + struct { + unsigned int transform; + } uniform; +}; +static unsigned int line_program; +static line_location line_location; +static unsigned int line_vertex_array_object; +static unsigned int line_instance_buffer; + struct quad_location { struct { unsigned int texture_sampler; @@ -443,6 +460,105 @@ view_state view_state; font::font * terminus_fonts; +struct short_point { + short x; + short y; + short z; +}; +static_assert((sizeof (short_point)) == 6); + +short_point line_points[128]; +static int line_point_ix = 0; + +void line_point(int x, int y, int z) +{ + if (line_point_ix >= 128) + return; + + printf("%d %d %d\n", x, y, z); + line_points[line_point_ix].x = x; + line_points[line_point_ix].y = y; + line_points[line_point_ix].z = z; + line_point_ix += 1; +} + +void load_line_program() +{ + unsigned int program = compile_from_files("shader/line.vert", + NULL, + "shader/line.frag"); + + line_location.attrib.position = glGetAttribLocation(program, "Position"); + line_location.attrib.normal = glGetAttribLocation(program, "Normal"); + line_location.attrib.texture = glGetAttribLocation(program, "Texture"); + + line_location.attrib.block_position = glGetAttribLocation(program, "BlockPosition"); + + printf("line program:\n"); + printf(" attributes:\n position %u\n normal %u\n texture %u\n block_position %u\n", + line_location.attrib.position, + line_location.attrib.normal, + line_location.attrib.texture, + line_location.attrib.block_position); + + line_location.uniform.transform = glGetUniformLocation(program, "Transform"); + printf(" uniforms:\n transform %u\n\n", + line_location.uniform.transform); + + line_program = program; +} + +void load_line_vertex_attributes() +{ + glGenVertexArrays(1, &line_vertex_array_object); + glBindVertexArray(line_vertex_array_object); + + glVertexBindingDivisor(0, 0); + glVertexBindingDivisor(1, 1); + + glEnableVertexAttribArray(line_location.attrib.position); + glVertexAttribFormat(line_location.attrib.position, 3, GL_HALF_FLOAT, GL_FALSE, 0); + glVertexAttribBinding(line_location.attrib.position, 0); + + glEnableVertexAttribArray(line_location.attrib.normal); + glVertexAttribFormat(line_location.attrib.normal, 3, GL_HALF_FLOAT, GL_FALSE, 6); + glVertexAttribBinding(line_location.attrib.normal, 0); + + glEnableVertexAttribArray(line_location.attrib.texture); + glVertexAttribFormat(line_location.attrib.texture, 2, GL_HALF_FLOAT, GL_FALSE, 12); + glVertexAttribBinding(line_location.attrib.texture, 0); + + glEnableVertexAttribArray(line_location.attrib.block_position); + glVertexAttribFormat(line_location.attrib.block_position, 3, GL_SHORT, GL_FALSE, 0); + glVertexAttribBinding(line_location.attrib.block_position, 1); + + glBindVertexArray(0); +} + +void load_line_instance_buffer() +{ + glBindBuffer(GL_ARRAY_BUFFER, line_instance_buffer); + glBufferData(GL_ARRAY_BUFFER, (sizeof (short_point)) * line_point_ix, line_points, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void load_line() +{ + int x1 = -55; + int z1 = 48; + int y1 = 50; + + int x2 = -60; + int z2 = 55; + int y2 = 53; + + line_point_ix = 0; + bresenham(x1, y1, z1, x2, y2, z2, line_point); + + load_line_instance_buffer(); +} + void load(const char * source_path) { g_source_path_length = strlen(source_path); @@ -487,6 +603,16 @@ void load(const char * source_path) load_lighting_program(); load_light_uniform_buffer(); + + ////////////////////////////////////////////////////////////////////// + // line + ////////////////////////////////////////////////////////////////////// + + load_line_program(); + load_line_vertex_attributes(); + + glGenBuffers(1, &line_instance_buffer); + load_line(); } float _ry = 0.0; @@ -500,6 +626,13 @@ light_parameters lighting = { .linear = 1.0 }; +void kb_update(int up, int down, int left, int right) +{ + XMVECTOR normal = XMVector3NormalizeEst(XMVector3Cross(view_state.forward, view_state.up)); + view_state.eye += view_state.forward * (0.1f * up + -0.1f * down); + view_state.eye += normal * (-0.1f * left + 0.1f * right); +} + void update(float lx, float ly, float rx, float ry, float tl, float tr, int up, int down, int left, int right, int a, int b, int x, int y) @@ -594,11 +727,8 @@ void draw_hud() y += ter_best.desc->glyph_height; } -void draw_minecraft() +XMMATRIX current_view_projection() { - // possibly re-initialize geometry buffer if window width/height changes - init_geometry_buffer(geometry_buffer_pnc, geometry_buffer_pnc_types); - XMVECTOR at = XMVectorAdd(view_state.eye, view_state.direction); XMMATRIX view = XMMatrixLookAtRH(view_state.eye, at, view_state.up); @@ -608,6 +738,13 @@ void draw_minecraft() float far_z = 0.1; XMMATRIX projection = XMMatrixPerspectiveFovRH(fov_angle_y, aspect_ratio, near_z, far_z); XMMATRIX transform = view * projection; + return transform; +} + +void draw_minecraft() +{ + // possibly re-initialize geometry buffer if window width/height changes + init_geometry_buffer(geometry_buffer_pnc, geometry_buffer_pnc_types); glUseProgram(test_program); @@ -618,6 +755,7 @@ void draw_minecraft() glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); + XMMATRIX transform = current_view_projection(); glUniformMatrix4fv(test_location.uniform.transform, 1, false, (float *)&transform); glUniform1i(test_location.uniform.terrain_sampler, 0); @@ -720,6 +858,34 @@ void draw_lighting() glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (void *)0); } +void draw_line() +{ + glUseProgram(line_program); + + glBlendFunc(GL_ONE, GL_ZERO); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_GREATER); + + XMMATRIX transform = current_view_projection(); + glUniformMatrix4fv(line_location.uniform.transform, 1, false, (float *)&transform); + + //glEnable(GL_CULL_FACE); + //glCullFace(GL_FRONT); + //glFrontFace(GL_CCW); + + glBindVertexArray(line_vertex_array_object); + glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size); + int line_instance_vertex_size = (sizeof (short_point)); + glBindVertexBuffer(1, line_instance_buffer, 0, line_instance_vertex_size); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + + int configuration = 63; + int element_count = 6 * popcount(configuration); + const void * indices = (void *)((ptrdiff_t)index_buffer_configuration_offsets[configuration]); // index into configuration.idx + int instance_count = line_point_ix; + glDrawElementsInstanced(GL_TRIANGLES, element_count, GL_UNSIGNED_BYTE, indices, instance_count); +} + void draw() { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -729,6 +895,7 @@ void draw() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_minecraft(); + draw_line(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);