bresenham

This commit is contained in:
Zack Buhman 2026-03-09 22:56:08 -05:00
parent 50188813f8
commit 175bf4a397
8 changed files with 321 additions and 6 deletions

View File

@ -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

13
include/bresenham.h Normal file
View File

@ -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

View File

@ -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);

View File

@ -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()

18
shader/line.frag Normal file
View File

@ -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);
}

27
shader/line.vert Normal file
View File

@ -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);
}

78
src/bresenham.c Normal file
View File

@ -0,0 +1,78 @@
#include <stdlib.h>
#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);
}

View File

@ -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);