From 50a747934d2dad48f2087ced6d938c5a6709f057 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Thu, 19 Mar 2026 13:01:51 -0500 Subject: [PATCH] add lua 'pixel' drawing api --- Makefile | 2 + include/font.h | 2 +- include/lua_api.h | 18 +++++ include/pixel_line_art.h | 12 ++++ include/test.h | 2 + main.lua | 105 ++++++++++++++++++++++++++-- shader/minecraft.frag | 4 +- shader/pixel_line_art.frag | 10 +++ shader/pixel_line_art.vert | 10 +++ src/font.cpp | 7 +- src/hud.cpp | 1 - src/lua_api.cpp | 45 ++++++++++++ src/pixel_line_art.cpp | 138 +++++++++++++++++++++++++++++++++++++ src/test.cpp | 15 +++- 14 files changed, 356 insertions(+), 15 deletions(-) create mode 100644 include/lua_api.h create mode 100644 include/pixel_line_art.h create mode 100644 shader/pixel_line_art.frag create mode 100644 shader/pixel_line_art.vert create mode 100644 src/lua_api.cpp create mode 100644 src/pixel_line_art.cpp diff --git a/Makefile b/Makefile index 1e35602..0aafa8a 100644 --- a/Makefile +++ b/Makefile @@ -45,6 +45,8 @@ OBJS = \ src/collada/effect.o \ src/collada/node_state.o \ src/collada/animate.o \ + src/lua_api.o \ + src/pixel_line_art.o \ data/scenes/ship20/ship20.o \ data/scenes/noodle/noodle.o \ data/scenes/shadow_test/shadow_test.o \ diff --git a/include/font.h b/include/font.h index 56ea488..3b8b649 100644 --- a/include/font.h +++ b/include/font.h @@ -64,5 +64,5 @@ namespace font { void load_fonts(font * const fonts, 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_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); } diff --git a/include/lua_api.h b/include/lua_api.h new file mode 100644 index 0000000..5d78dab --- /dev/null +++ b/include/lua_api.h @@ -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 diff --git a/include/pixel_line_art.h b/include/pixel_line_art.h new file mode 100644 index 0000000..8621b9a --- /dev/null +++ b/include/pixel_line_art.h @@ -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); +} diff --git a/include/test.h b/include/test.h index e0b9c41..04d8cf6 100644 --- a/include/test.h +++ b/include/test.h @@ -6,6 +6,8 @@ extern "C" { void load(const char * source_path); void draw(); + void love2d_state_load(); + void love2d_state_restore(); void update_keyboard(int up, int down, int left, int right, int w, int s, int a, int d, int t, int g, int f, int h, diff --git a/main.lua b/main.lua index af250d3..a9b7936 100644 --- a/main.lua +++ b/main.lua @@ -23,6 +23,15 @@ void update_joystick(int joystick_index, int leftshoulder, int rightshoulder, int start); 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() test = ffi.load(source_path .. "/test.so") @@ -88,11 +97,97 @@ local draw = function() test.draw() 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() init() - --love.timer.step() - return function() love.event.pump() 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() test.update_window(width, height) - --local dt = love.timer.step() local time = love.timer.getTime() update(time) @@ -121,10 +215,9 @@ function love.run() test.update_mouse(x, y) end + nico_draw() + love.graphics.present() love.timer.sleep(0.001) - --love.timer.sleep(0.1) - --local fps = love.timer.getFPS( ) - --print(fps) end end diff --git a/shader/minecraft.frag b/shader/minecraft.frag index ea4a55f..199b28c 100644 --- a/shader/minecraft.frag +++ b/shader/minecraft.frag @@ -40,8 +40,8 @@ void main() vec4 texture_color = texelFetch(TerrainSampler, coord, 0); if (texture_color.w != 1.0) { - discard; - return; + //discard; + //return; } Position = fs_in.BlockPosition.xzy; diff --git a/shader/pixel_line_art.frag b/shader/pixel_line_art.frag new file mode 100644 index 0000000..eae1858 --- /dev/null +++ b/shader/pixel_line_art.frag @@ -0,0 +1,10 @@ +#version 430 core + +out vec4 Color; + +layout (location = 1) uniform vec3 BaseColor; + +void main() +{ + Color = vec4(BaseColor, 1); +} diff --git a/shader/pixel_line_art.vert b/shader/pixel_line_art.vert new file mode 100644 index 0000000..daac93a --- /dev/null +++ b/shader/pixel_line_art.vert @@ -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); +} diff --git a/src/font.cpp b/src/font.cpp index 0fcd13d..cc215b7 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -123,8 +123,8 @@ namespace font { inline static XMFLOAT4X4 glyph_transform(font const& font, int x, int y) { - XMMATRIX transform = - XMMatrixScaling(font.desc->glyph_width, font.desc->glyph_height, 0) + XMMATRIX transform + = XMMatrixScaling(font.desc->glyph_width, font.desc->glyph_height, 0) * XMMatrixTranslation(x, -y, 0) * XMMatrixScaling(2.0f / window::width, 2.0f / window::height, 0) * XMMatrixTranslation(-1, 1, 0); @@ -148,7 +148,7 @@ namespace font { 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; while (s[i] != 0) { @@ -164,5 +164,6 @@ namespace font { x += font.desc->glyph_width; } + return x; } } diff --git a/src/hud.cpp b/src/hud.cpp index f7c0db3..2a6fc64 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -81,7 +81,6 @@ namespace hud { 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); labeled_value(buf, "fov: ", "%.3f", view::state.fov); diff --git a/src/lua_api.cpp b/src/lua_api.cpp new file mode 100644 index 0000000..ea5cc67 --- /dev/null +++ b/src/lua_api.cpp @@ -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); +} diff --git a/src/pixel_line_art.cpp b/src/pixel_line_art.cpp new file mode 100644 index 0000000..4d98296 --- /dev/null +++ b/src/pixel_line_art.cpp @@ -0,0 +1,138 @@ +#include "glad/gl.h" +#include "directxmath/directxmath.h" +#include + +#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); + } +} diff --git a/src/test.cpp b/src/test.cpp index 9253674..5305d7d 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -24,6 +24,7 @@ #include "collada/scene.h" #include "collada/types.h" #include "collada/instance_types.h" +#include "pixel_line_art.h" #include "world/entry_table.h" #include "world/world.h" @@ -88,7 +89,6 @@ void load_quad_index_buffer() glGenBuffers(1, &quad_index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_index_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, data, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } @@ -119,6 +119,12 @@ void load(const char * source_path) fprintf(stderr, "getproc %p\n", SDL_GL_GetProcAddress); gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress); + // + + glBindVertexArray(0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + ////////////////////////////////////////////////////////////////////// // minecraft (drawing data) ////////////////////////////////////////////////////////////////////// @@ -140,6 +146,12 @@ void load(const char * source_path) terminus_fonts = (font::font *)malloc((sizeof (font::font)) * font::terminus_length); font::load_fonts(terminus_fonts, font::terminus, font::terminus_length); + ////////////////////////////////////////////////////////////////////// + // pixel_line_art + ////////////////////////////////////////////////////////////////////// + + pixel_line_art::load(); + ////////////////////////////////////////////////////////////////////// // quad ////////////////////////////////////////////////////////////////////// @@ -370,7 +382,6 @@ float mouse_block[3] = {}; void update_mouse(int x, int y) { - printf("update mouse %d %d\n", x, y); x = clamp(x, geometry_buffer_pnc.width); y = clamp(y, geometry_buffer_pnc.height);