commit a9a3d1db2af2ca9a43e1884bfda67dfc32afc665
parent c980f07c3d481ee40e06b33b603da5010838b965
Author: Henry Wilson <henry@henryandlizzy.uk>
Date: Wed, 26 Jun 2024 23:01:37 +0100
sdl-gl: Load console raster font and draw test string
Diffstat:
M | src/sdl-gl.cpp | | | 115 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- |
1 file changed, 110 insertions(+), 5 deletions(-)
diff --git a/src/sdl-gl.cpp b/src/sdl-gl.cpp
@@ -17,6 +17,9 @@
#include <random>
#include <ranges>
#include <vector>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <err.h>
extern "C" char const* __asan_default_options() { return "detect_leaks=0"; }
@@ -279,11 +282,7 @@ void panel::draw() const
glEnd();
}
-void draw_UI()
-{
- panel{50, 50, 99, 49}.draw();
- panel{50, 100, 99, 49}.draw();
-}
+
void key(SDL_KeyboardEvent& e)
{
@@ -466,12 +465,118 @@ void init_shape()
shape_wireframe = shape_wireframe.subspan(1, shape.size() - 2);
}
+struct psf2
+{
+ unsigned int magic, version, hdr_size, flags, length, g_size, height, width;
+};
+struct font
+{
+ psf2 hdr;
+ GLuint tex;
+ font(char const* filename)
+ {
+ int fds[2];
+ if (pipe(fds))
+ err(1, "pipe");
+ pid_t child = fork();
+ if (child < 0)
+ err(1, "fork");
+ if (!child)
+ {
+ if (dup2(fds[1], 1) == -1)
+ err(1, "dup2");
+ if (close(fds[0]))
+ err(1, "close");
+ if (close(fds[1]))
+ err(1, "close");
+ execlp("gunzip", "gunzip", "--stdout", filename, nullptr);
+ err(1, "execlp");
+ }
+ close(fds[1]);
+
+ if (read(fds[0], &hdr, sizeof(hdr)) != sizeof(hdr))
+ err(1, "read");
+ if (hdr.magic != 0x864AB572)
+ errx(1, "Not a PSF2 file");
+
+ std::vector<unsigned char> storage(hdr.length * hdr.g_size);
+
+ for (ssize_t read = 0; read < (ssize_t)storage.size(); )
+ {
+ int n = ::read(fds[0], storage.data() + read, storage.size() - read);
+ if (n < 0)
+ err(1, "read");
+ if (n == 0)
+ errx(1, "not enough data from font");
+ read += n;
+ }
+ close(fds[0]);
+ assert(wait(nullptr) == child);
+ std::vector<unsigned char> pix(hdr.length * hdr.height * hdr.width);
+
+ for (size_t i = 0; i < pix.size(); ++i)
+ pix[i] = ((storage[i / 8] >> (7 - i % 8)) & 1) * 255;
+
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, hdr.width, hdr.height * hdr.length, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pix.data());
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ screen_coord draw(unsigned char c, screen_coord pos)
+ {
+ screen_coord br_screen{pos.x + (int)hdr.width, pos.y + (int)hdr.height};
+ float text = (float)c / hdr.length;
+ float texb = (float)(c + 1u) / hdr.length;
+ auto tl = window_to_gl(pos);
+ auto tr = window_to_gl({br_screen.x, pos.y});
+ auto bl = window_to_gl({pos.x, br_screen.y});
+ auto br = window_to_gl(br_screen);
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_TRIANGLE_STRIP);
+ glTexCoord2f(0,text);
+ glVertex(tl);
+ glTexCoord2f(1,text);
+ glVertex(tr);
+ glTexCoord2f(0,texb);
+ glVertex(bl);
+ glTexCoord2f(1,texb);
+ glVertex(br);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ return br_screen;
+ }
+ screen_coord draw(char const* str, screen_coord pos)
+ {
+ while (*str)
+ pos.x = draw(*str++, pos).x;
+ return pos;
+ }
+};
+
+font* fnt;
+
+void draw_UI()
+{
+ panel{50, 50, 149, 49}.draw();
+ glColor3f(1,1,1);
+ fnt->draw("Hello, World!", {51, 51});
+ panel{50, 100, 149, 49}.draw();
+}
+
int main()
{
init_shape();
mouse_task();
initSDL();
atexit(SDL_Quit);
+
+ fnt = new font{"/usr/share/kbd/consolefonts/lat9-16.psf.gz"};
+
for (;;)
{
doInput();