add lua 'pixel' drawing api

This commit is contained in:
Zack Buhman 2026-03-19 13:01:51 -05:00
parent a5a304bcae
commit 50a747934d
14 changed files with 356 additions and 15 deletions

View File

@ -45,6 +45,8 @@ OBJS = \
src/collada/effect.o \ src/collada/effect.o \
src/collada/node_state.o \ src/collada/node_state.o \
src/collada/animate.o \ src/collada/animate.o \
src/lua_api.o \
src/pixel_line_art.o \
data/scenes/ship20/ship20.o \ data/scenes/ship20/ship20.o \
data/scenes/noodle/noodle.o \ data/scenes/noodle/noodle.o \
data/scenes/shadow_test/shadow_test.o \ data/scenes/shadow_test/shadow_test.o \

View File

@ -64,5 +64,5 @@ namespace font {
void load_fonts(font * const fonts, font_desc const * const descs, int length); void load_fonts(font * const fonts, font_desc const * const descs, int length);
int best_font(font_desc const * const descs, int length); int best_font(font_desc const * const descs, int length);
void draw_start(font const& font, unsigned int vertex_array_object, unsigned int index_buffer); void draw_start(font const& font, unsigned int vertex_array_object, unsigned int index_buffer);
void draw_string(font const& font, char const * const s, int x, int y); int draw_string(font const& font, char const * const s, int x, int y);
} }

18
include/lua_api.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
int draw_font_start();
int draw_font(int font_ix, char const * text, int x, int y);
void draw_line_quad_start();
void draw_line(int x1, int y1, int x2, int y2);
void draw_set_color(float r, float g, float b);
void draw_quad(int x1, int y1, int x2, int y2,
int x3, int y3, int x4, int y4);
#ifdef __cplusplus
}
#endif

12
include/pixel_line_art.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
namespace pixel_line_art {
void load();
void draw_line_quad_start();
void draw_line(int x1, int y1, int x2, int y2);
void draw_set_color(float r, float g, float b);
void draw_quad(int x1, int y1, int x2, int y2,
int x3, int y3, int x4, int y4);
}

View File

@ -6,6 +6,8 @@ extern "C" {
void load(const char * source_path); void load(const char * source_path);
void draw(); void draw();
void love2d_state_load();
void love2d_state_restore();
void update_keyboard(int up, int down, int left, int right, void update_keyboard(int up, int down, int left, int right,
int w, int s, int a, int d, int w, int s, int a, int d,
int t, int g, int f, int h, int t, int g, int f, int h,

105
main.lua
View File

@ -23,6 +23,15 @@ void update_joystick(int joystick_index,
int leftshoulder, int rightshoulder, int leftshoulder, int rightshoulder,
int start); int start);
void update(float time); void update(float time);
int draw_font_start();
int draw_font(int font_ix, char const * text, int x, int y);
void draw_line_quad_start();
void draw_line(int x1, int y1, int x2, int y2);
void draw_set_color(float r, float g, float b);
void draw_quad(int x1, int y1, int x2, int y2,
int x3, int y3, int x4, int y4);
]] ]]
local source_path = love.filesystem.getSource() local source_path = love.filesystem.getSource()
test = ffi.load(source_path .. "/test.so") test = ffi.load(source_path .. "/test.so")
@ -88,11 +97,97 @@ local draw = function()
test.draw() test.draw()
end end
local nico_draw = function()
----------------------------------------------------------------------
-- font drawing
----------------------------------------------------------------------
-- call "draw_font_start()" prior each "group" of "draw_font()" calls
--
-- a "group" of draw_font() calls are back-to-back/consecutive,
-- with no non-font drawing between them.
--
-- For example:
local font_ix = test.draw_font_start()
local x = 512
local y = 50
y = y + test.draw_font(font_ix, "lua test", x, y)
y = y + test.draw_font(font_ix, "cool", x, y)
-- note that "font_ix" is the current "best font" as calculated
-- from the current window size, and might change next frame if the
-- window is resized.
--
-- Any of this of course could be changed to match your precise
-- requirements.
----------------------------------------------------------------------
-- line drawing
----------------------------------------------------------------------
-- call "draw_line_quad_start()" prior to each "group" of
-- "draw_line()" or "draw_quad()" calls
--
-- a "group" of draw_line()/draw_quad() calls are
-- back-to-back/consecutive, with no non-line/quad drawing between
-- them.
--
-- For example:
test.draw_line_quad_start()
test.draw_set_color(1.0, 0.0, 0.0) -- r, g, b (0.0 to 1.0)
test.draw_line(0, 0, 1024, 1024) -- x1, y1, x2, y2
test.draw_line(700, 300, 400, 500)
test.draw_set_color(0.0, 1.0, 0.0)
test.draw_line(700, 300, 400, 700)
-- x1, y1, x2, y2,
-- x3, y3, x4, y4,
--
-- vertices must be specified In "counter clockwise" order, as in:
--
-- 2──1
-- │ │ valid (counter clockwise)
-- 3──4
--
-- these can also be rotated, as in:
--
-- 3
-- ╱ ╲
-- 4 2 valid (counter clockwise)
-- ╲ ╱
-- 1
--
-- however "mirroring" is not valid, as in:
--
-- 1──2
-- │ │ not valid (clockwise)
-- 4──3
--
test.draw_set_color(0.0, 0.0, 1.0)
test.draw_quad(
600, 600, -- top right
500, 600, -- top left
500, 700, -- bottom left
600, 700 -- bottom right
)
test.draw_set_color(0.0, 0.5, 1.0)
test.draw_quad(
900, 900, -- bottom
950, 850, -- right
900, 800, -- top
850, 850 -- left
)
-- If you want to draw a large number of lines or quads in bulk
-- (e.g: 10,000+ lines/quads per frame), this interface might not be good
-- enough, and we should discuss this in more detail.
end
function love.run() function love.run()
init() init()
--love.timer.step()
return function() return function()
love.event.pump() love.event.pump()
for name, a,b,c,d,e,f,g,h in love.event.poll() do for name, a,b,c,d,e,f,g,h in love.event.poll() do
@ -109,7 +204,6 @@ function love.run()
width, height, flags = love.window.getMode() width, height, flags = love.window.getMode()
test.update_window(width, height) test.update_window(width, height)
--local dt = love.timer.step()
local time = love.timer.getTime() local time = love.timer.getTime()
update(time) update(time)
@ -121,10 +215,9 @@ function love.run()
test.update_mouse(x, y) test.update_mouse(x, y)
end end
nico_draw()
love.graphics.present() love.graphics.present()
love.timer.sleep(0.001) love.timer.sleep(0.001)
--love.timer.sleep(0.1)
--local fps = love.timer.getFPS( )
--print(fps)
end end
end end

View File

@ -40,8 +40,8 @@ void main()
vec4 texture_color = texelFetch(TerrainSampler, coord, 0); vec4 texture_color = texelFetch(TerrainSampler, coord, 0);
if (texture_color.w != 1.0) { if (texture_color.w != 1.0) {
discard; //discard;
return; //return;
} }
Position = fs_in.BlockPosition.xzy; Position = fs_in.BlockPosition.xzy;

View File

@ -0,0 +1,10 @@
#version 430 core
out vec4 Color;
layout (location = 1) uniform vec3 BaseColor;
void main()
{
Color = vec4(BaseColor, 1);
}

View File

@ -0,0 +1,10 @@
#version 430 core
layout (location = 0) in vec2 Position;
layout (location = 0) uniform mat4 Transform;
void main()
{
gl_Position = Transform * vec4(Position, 0, 1);
}

View File

@ -123,8 +123,8 @@ namespace font {
inline static XMFLOAT4X4 glyph_transform(font const& font, int x, int y) inline static XMFLOAT4X4 glyph_transform(font const& font, int x, int y)
{ {
XMMATRIX transform = XMMATRIX transform
XMMatrixScaling(font.desc->glyph_width, font.desc->glyph_height, 0) = XMMatrixScaling(font.desc->glyph_width, font.desc->glyph_height, 0)
* XMMatrixTranslation(x, -y, 0) * XMMatrixTranslation(x, -y, 0)
* XMMatrixScaling(2.0f / window::width, 2.0f / window::height, 0) * XMMatrixScaling(2.0f / window::width, 2.0f / window::height, 0)
* XMMatrixTranslation(-1, 1, 0); * XMMatrixTranslation(-1, 1, 0);
@ -148,7 +148,7 @@ namespace font {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
} }
void draw_string(font const& font, char const * const s, int x, int y) int draw_string(font const& font, char const * const s, int x, int y)
{ {
int i = 0; int i = 0;
while (s[i] != 0) { while (s[i] != 0) {
@ -164,5 +164,6 @@ namespace font {
x += font.desc->glyph_width; x += font.desc->glyph_width;
} }
return x;
} }
} }

View File

@ -81,7 +81,6 @@ namespace hud {
int font_ix = font::best_font(font::terminus, font::terminus_length); int font_ix = font::best_font(font::terminus, font::terminus_length);
font::font const& ter_best = terminus_fonts[font_ix]; font::font const& ter_best = terminus_fonts[font_ix];
font::draw_start(ter_best, empty_vertex_array_object, quad_index_buffer); font::draw_start(ter_best, empty_vertex_array_object, quad_index_buffer);
labeled_value<float>(buf, "fov: ", "%.3f", view::state.fov); labeled_value<float>(buf, "fov: ", "%.3f", view::state.fov);

45
src/lua_api.cpp Normal file
View File

@ -0,0 +1,45 @@
#include "font.h"
#include "pixel_line_art.h"
#include "lua_api.h"
extern font::font * terminus_fonts;
extern unsigned int empty_vertex_array_object;
extern unsigned int quad_index_buffer;
int draw_font_start()
{
int font_ix = font::best_font(font::terminus, font::terminus_length);
font::font const& ter_best = terminus_fonts[font_ix];
font::draw_start(ter_best, empty_vertex_array_object, quad_index_buffer);
return font_ix;
}
int draw_font(int font_ix, char const * text, int x, int y)
{
font::font const& ter_best = terminus_fonts[font_ix];
font::draw_string(ter_best, text, x, y);
return ter_best.desc->glyph_height;
}
void draw_line_quad_start()
{
pixel_line_art::draw_line_quad_start();
}
void draw_line(int x1, int y1, int x2, int y2)
{
pixel_line_art::draw_line(x1, y1, x2, y2);
}
void draw_set_color(float r, float g, float b)
{
pixel_line_art::draw_set_color(r, g, b);
}
void draw_quad(int x1, int y1, int x2, int y2,
int x3, int y3, int x4, int y4)
{
pixel_line_art::draw_quad(x1, y1, x2, y2,
x3, y3, x4, y4);
}

138
src/pixel_line_art.cpp Normal file
View File

@ -0,0 +1,138 @@
#include "glad/gl.h"
#include "directxmath/directxmath.h"
#include <stdio.h>
#include "opengl.h"
#include "window.h"
#include "pixel_line_art.h"
extern unsigned int quad_index_buffer;
namespace pixel_line_art {
struct layout {
struct {
unsigned int position;
} attribute;
struct {
unsigned int transform;
unsigned int base_color;
} uniform;
};
const layout layout = {
.attribute = {
.position = 0,
},
.uniform = {
.transform = 0,
.base_color = 1,
},
};
static unsigned int program;
static unsigned int vertex_array_object;
static unsigned int per_vertex_buffer;
static int const per_vertex_size = (sizeof (float)) * 2;
static void load_program()
{
program = compile_from_files("shader/pixel_line_art.vert",
nullptr,
"shader/pixel_line_art.frag");
}
static void load_vertex_attributes()
{
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
glVertexBindingDivisor(0, 0);
glEnableVertexAttribArray(layout.attribute.position);
glVertexAttribFormat(layout.attribute.position, 2, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(layout.attribute.position, 0);
glBindVertexArray(0);
}
static void load_per_vertex_buffer(int x1, int y1, int x2, int y2)
{
float vertex_data[] = {
(float)x1, (float)y1, (float)x2, (float)y2,
};
int vertex_data_size = (sizeof (vertex_data));
glBindBuffer(GL_ARRAY_BUFFER, per_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, vertex_data_size, vertex_data, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
static void load_per_vertex_buffer2(int x1, int y1, int x2, int y2,
int x3, int y3, int x4, int y4)
{
float vertex_data[] = {
(float)x1, (float)y1, (float)x2, (float)y2,
(float)x3, (float)y3, (float)x4, (float)y4,
};
int vertex_data_size = (sizeof (vertex_data));
glBindBuffer(GL_ARRAY_BUFFER, per_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, vertex_data_size, vertex_data, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void load()
{
load_program();
load_vertex_attributes();
glGenBuffers(1, &per_vertex_buffer);
}
static void set_transform(XMMATRIX const & transform)
{
XMFLOAT4X4 float_transform;
XMStoreFloat4x4(&float_transform, transform);
glUniformMatrix4fv(layout.uniform.transform, 1, false, (float *)&float_transform);
}
void draw_line_quad_start()
{
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, quad_index_buffer);
XMMATRIX transform
= XMMatrixScaling(2.0f / window::width, -2.0f / window::height, 0)
* XMMatrixTranslation(-1, 1, 0);
set_transform(transform);
}
void draw_line(int x1, int y1, int x2, int y2)
{
load_per_vertex_buffer(x1, y1, x2, y2);
glDrawArrays(GL_LINES, 0, 2);
}
void draw_quad(int x1, int y1, int x2, int y2,
int x3, int y3, int x4, int y4)
{
load_per_vertex_buffer2(x1, y1, x2, y2,
x3, y3, x4, y4);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (void *)0);
}
void draw_set_color(float r, float g, float b)
{
glUniform3f(layout.uniform.base_color, r, g, b);
}
}

View File

@ -24,6 +24,7 @@
#include "collada/scene.h" #include "collada/scene.h"
#include "collada/types.h" #include "collada/types.h"
#include "collada/instance_types.h" #include "collada/instance_types.h"
#include "pixel_line_art.h"
#include "world/entry_table.h" #include "world/entry_table.h"
#include "world/world.h" #include "world/world.h"
@ -88,7 +89,6 @@ void load_quad_index_buffer()
glGenBuffers(1, &quad_index_buffer); glGenBuffers(1, &quad_index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, data, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, data, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} }
@ -119,6 +119,12 @@ void load(const char * source_path)
fprintf(stderr, "getproc %p\n", SDL_GL_GetProcAddress); fprintf(stderr, "getproc %p\n", SDL_GL_GetProcAddress);
gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress); gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress);
//
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// minecraft (drawing data) // minecraft (drawing data)
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -140,6 +146,12 @@ void load(const char * source_path)
terminus_fonts = (font::font *)malloc((sizeof (font::font)) * font::terminus_length); terminus_fonts = (font::font *)malloc((sizeof (font::font)) * font::terminus_length);
font::load_fonts(terminus_fonts, font::terminus, font::terminus_length); font::load_fonts(terminus_fonts, font::terminus, font::terminus_length);
//////////////////////////////////////////////////////////////////////
// pixel_line_art
//////////////////////////////////////////////////////////////////////
pixel_line_art::load();
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// quad // quad
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -370,7 +382,6 @@ float mouse_block[3] = {};
void update_mouse(int x, int y) void update_mouse(int x, int y)
{ {
printf("update mouse %d %d\n", x, y);
x = clamp(x, geometry_buffer_pnc.width); x = clamp(x, geometry_buffer_pnc.width);
y = clamp(y, geometry_buffer_pnc.height); y = clamp(y, geometry_buffer_pnc.height);