From ee6df45e2dea3d73f321068d92fdbdf9baf25f34 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Fri, 26 Jul 2024 11:33:12 +0200 Subject: [PATCH] Begin move to SDL --- build_file.cpp | 61 +++++++++- src/{text_editor => basic}/math.cpp | 0 src/{text_editor => basic}/math_int.cpp | 0 src/{text_editor => basic}/string16.cpp | 0 src/new_platform/font.cpp | 149 ++++++++++++++++++++++++ src/new_platform/new_platform.cpp | 129 ++++++++++++++++++++ src/text_editor/text_editor.cpp | 12 +- src/text_editor/text_editor.h | 3 +- 8 files changed, 344 insertions(+), 10 deletions(-) rename src/{text_editor => basic}/math.cpp (100%) rename src/{text_editor => basic}/math_int.cpp (100%) rename src/{text_editor => basic}/string16.cpp (100%) create mode 100644 src/new_platform/font.cpp create mode 100644 src/new_platform/new_platform.cpp diff --git a/build_file.cpp b/build_file.cpp index b747335..196bcc7 100644 --- a/build_file.cpp +++ b/build_file.cpp @@ -27,12 +27,34 @@ struct Library { Array objects; Array include_paths; Array defines; + Array link; }; Library PrepareSDL() { + Library l = {}; + l.include_paths.add("../src/external/SDL/include"); + l.objects.add("../src/external/SDL/VisualC/static_x64/Release/SDL3.lib"); + l.link.add("/SUBSYSTEM:WINDOWS"); + l.link.add("opengl32.lib"); + l.link.add("imm32.lib"); + l.link.add("gdi32.lib"); + l.link.add("winmm.lib"); + l.link.add("shell32.lib"); + l.link.add("user32.lib"); + l.link.add("advapi32.lib"); + l.link.add("Setupapi.lib"); + l.link.add("ole32.lib"); + l.link.add("oleaut32.lib"); + l.link.add("Version.lib"); + return l; +} + +Library PrepareSDLDynamic() { Library l = {}; l.include_paths.add("../src/external/SDL/include"); l.objects.add("../src/external/SDL/VisualC/x64/Release/SDL3.lib"); + l.link.add("/SUBSYSTEM:WINDOWS"); + OS_CopyFile("../src/external/SDL/VisualC/x64/Release/SDL3.dll", "./SDL3.dll", false); return l; } @@ -77,7 +99,7 @@ Library PrepareLua() { Library PrepareGlad() { Library l = {}; l.sources.add("../src/external/glad/glad.c"); - l.include_paths.add("../src/external/glad"); + l.include_paths.add("../src/external/glad/"); l.objects.add("glad.obj"); if (!OS_FileExists(l.objects[0])) { Array cmd = {}; @@ -101,6 +123,7 @@ int CompileTextEditor() { cmd.add("cl.exe"); cmd.add("-Fe:te.exe"); cmd.add("-Fd:te.pdb"); + cmd.add("-I ../src"); AddCommonFlags(&cmd); For2(lib, libs) For(lib.defines) cmd.add(it); @@ -122,10 +145,44 @@ int CompileTextEditor() { return result; } +int CompileNewPlatform() { + int result = 0; + + Array libs = {}; + libs.add(PrepareGlad()); + libs.add(PrepareLua()); + libs.add(PrepareSDLDynamic()); + + Array cmd = {}; + cmd.add("cl.exe"); + cmd.add("-Fe:te.exe"); + cmd.add("-Fd:te.pdb"); + cmd.add("-I ../src"); + AddCommonFlags(&cmd); + For2(lib, libs) For(lib.defines) cmd.add(it); + + cmd.add("../src/new_platform/new_platform.cpp"); + cmd.add("../src/basic/win32.cpp"); + + For2(lib, libs) For(lib.include_paths) cmd.add(Fmt("-I %.*s", S8_Expand(it))); + + cmd.add("/link"); + cmd.add("/incremental:no"); + For2(lib, libs) For(lib.link) cmd.add(it); + For(libs) For2(o, it.objects) cmd.add(o); + + OS_DeleteFile("te.pdb"); + // For(cmd) IO_Printf("%.*s\n", S8_Expand(it)); + + result += Run(cmd); + return result; +} + int main() { MA_InitScratch(); SRC_InitCache(Perm, "te.cache"); - int result = CompileTextEditor(); + // int result = CompileTextEditor(); + int result = CompileNewPlatform(); if (result != 0) { OS_DeleteFile("te.cache"); diff --git a/src/text_editor/math.cpp b/src/basic/math.cpp similarity index 100% rename from src/text_editor/math.cpp rename to src/basic/math.cpp diff --git a/src/text_editor/math_int.cpp b/src/basic/math_int.cpp similarity index 100% rename from src/text_editor/math_int.cpp rename to src/basic/math_int.cpp diff --git a/src/text_editor/string16.cpp b/src/basic/string16.cpp similarity index 100% rename from src/text_editor/string16.cpp rename to src/basic/string16.cpp diff --git a/src/new_platform/font.cpp b/src/new_platform/font.cpp new file mode 100644 index 0000000..58ce29e --- /dev/null +++ b/src/new_platform/font.cpp @@ -0,0 +1,149 @@ +struct Glyph { + Vec2I size; + Vec2I offset; + int32_t xadvance; + int32_t left_side_bearing; + Rect2 atlas_bounding_box; +}; + +struct Font { + Array glyphs; + uint32_t first_char, last_char; + uint32_t texture_id; + + int32_t size; + int32_t descent; + int32_t ascent; + int32_t line_gap; + + Rect2 white_texture_bounding_box; +}; + +struct Atlas { + uint8_t *bitmap; + Vec2I size; + Vec2 inverse_size; + int xcursor; + int ycursor; + + int32_t biggest_height; + Rect2 white_texture_bounding_box; + uint32_t texture_id; +}; + +Atlas CreateAtlas(Allocator allocator, Vec2I size) { + Atlas result = {}; + result.size = size; + result.inverse_size.x = 1.f / (float)result.size.x; + result.inverse_size.y = 1.f / (float)result.size.y; + result.bitmap = AllocArray(allocator, uint8_t, size.x * size.y); + + // Add a whitebox first for rectangle rendering + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 16; x++) { + uint8_t *dst = result.bitmap + x + y * result.size.x; + *dst = 0xff; + } + } + + result.white_texture_bounding_box = {2.f * result.inverse_size.x, 2.f / (float)result.size.y, 14.f * result.inverse_size.x, 14.f / (float)result.size.y}; + result.xcursor += 16; + result.biggest_height += 16; + return result; +} + +Rect2 PackBitmap(Atlas *atlas, uint8_t *bitmap, int width, int height) { + // Packing into a texture atlas + // @Inefficient The algorithm is a simplest thing I had in mind, first we advance + // through the atlas in X packing consecutive glyphs. After we get to the end of the row + // we advance to the next row by the Y size of the biggest packed glyph. If we get to the + // end of atlas and fail to pack everything the app panics. + + int spacing = 4; + if (atlas->xcursor + width > atlas->size.x) { + if (atlas->ycursor + height < atlas->size.y) { + atlas->xcursor = 0; + atlas->ycursor += atlas->biggest_height + spacing; + } else { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Font loading error!", "Error while packing a font into atlas. Atlas size for this font scale is a bit too small", NULL); + } + } + + uint8_t *src = bitmap; + for (int y = atlas->ycursor; y < atlas->ycursor + height; y += 1) { + for (int x = atlas->xcursor; x < atlas->xcursor + width; x += 1) { + uint8_t *dst = atlas->bitmap + x + y * atlas->size.x; + *dst = *src++; + } + } + + Vec2 size = {(float)width * atlas->inverse_size.x, (float)height * atlas->inverse_size.y}; + Vec2 pos = {(float)atlas->xcursor * atlas->inverse_size.x, (float)atlas->ycursor * atlas->inverse_size.y}; + Rect2 result = {pos.x, pos.y, pos.x + size.x, pos.y + size.y}; + + atlas->xcursor += width + spacing; + if (height > atlas->biggest_height) { + atlas->biggest_height = height; + } + + return result; +} + +Font CreateFont(Atlas *atlas, int32_t size, String path) { + Scratch scratch; + Font result = {}; + + String file = ReadFile(scratch, path); + if (file.len == 0) { + return result; + } + + stbtt_fontinfo stb_font; + int success = stbtt_InitFont(&stb_font, (const unsigned char *)file.data, 0); + if (!success) { + return result; + } + + float scale = stbtt_ScaleForPixelHeight(&stb_font, (float)result.size); + float em_scale = stbtt_ScaleForMappingEmToPixels(&stb_font, (float)result.size); + + int ascent, descent, line_gap; + stbtt_GetFontVMetrics(&stb_font, &ascent, &descent, &line_gap); + result.ascent = (int32_t)((float)ascent * scale); + result.descent = (int32_t)((float)descent * scale); + result.line_gap = (int32_t)((float)line_gap * scale); + result.size = size; + result.first_char = ' '; + result.last_char = '~'; + result.white_texture_bounding_box = atlas->white_texture_bounding_box; + + for (uint32_t ascii_symbol = result.first_char; ascii_symbol <= result.last_char; ascii_symbol++) { + int width, height, xoff, yoff; + uint8_t *bitmap = (uint8_t *)stbtt_GetCodepointBitmap(&stb_font, 0, scale, ascii_symbol, &width, &height, &xoff, &yoff); + defer { stbtt_FreeBitmap(bitmap, 0); }; + + int xadvance, left_side_bearing; + stbtt_GetCodepointHMetrics(&stb_font, ascii_symbol, &xadvance, &left_side_bearing); + + Glyph glyph = {}; + glyph.atlas_bounding_box = PackBitmap(atlas, bitmap, width, height); + glyph.size = {width, height}; + glyph.offset = {xoff, yoff}; + glyph.xadvance = (int32_t)((float)xadvance * scale); + glyph.left_side_bearing = (int32_t)((float)left_side_bearing * scale); + Add(&result.glyphs, glyph); + } + + return result; +} + +Glyph *GetGlyph(Font *font, uint32_t codepoint) { + bool is_in_range = codepoint >= font->first_char && codepoint <= font->last_char; + if (is_in_range) { + uint32_t index = codepoint - font->first_char; + return &font->glyphs[index]; + } else { + uint32_t index = '?' - font->first_char; + return &font->glyphs[index]; + } +} \ No newline at end of file diff --git a/src/new_platform/new_platform.cpp b/src/new_platform/new_platform.cpp new file mode 100644 index 0000000..82f7e8b --- /dev/null +++ b/src/new_platform/new_platform.cpp @@ -0,0 +1,129 @@ +#define BASIC_IMPL +#include "basic/basic.h" +#include "basic/filesystem.h" + +#include "SDL3/SDL.h" +#include "external/glad/glad.h" +#include "external/stb_truetype.h" +#include "external/stb_truetype.c" + +#include "basic/math_int.cpp" +#include "basic/math.cpp" +#include "font.cpp" + +bool AppIsRunning = true; + +void ProcessSDLEvent(SDL_Event *event) { + switch (event->type) { + case SDL_EVENT_QUIT: AppIsRunning = false; return; + case SDL_EVENT_KEY_DOWN: { + SDL_KeyboardEvent &key = event->key; + bool shift = key.mod & SDL_KMOD_SHIFT; + bool ctrl = key.mod & SDL_KMOD_CTRL; + bool alt = key.mod & SDL_KMOD_ALT; + bool super = key.mod & SDL_KMOD_GUI; + + if (key.key == SDLK_F5) { + AppIsRunning = false; + return; + } + + } break; + case SDL_EVENT_KEY_UP: { + SDL_KeyboardEvent &key = event->key; + bool shift = key.mod & SDL_KMOD_SHIFT; + bool ctrl = key.mod & SDL_KMOD_CTRL; + bool alt = key.mod & SDL_KMOD_ALT; + bool super = key.mod & SDL_KMOD_GUI; + + } break; + case SDL_EVENT_TEXT_INPUT: { + } break; + case SDL_EVENT_MOUSE_MOTION: { + } break; + case SDL_EVENT_MOUSE_BUTTON_DOWN: { + } break; + case SDL_EVENT_MOUSE_BUTTON_UP: { + } break; + case SDL_EVENT_MOUSE_WHEEL: { + } break; + } +} + +void GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user) { + printf("%s", message); + if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenGL error", message, NULL); + } +} + +#if _WIN32 +int WinMain(void *hInstance, void *hPrevInstance, const char *lpCmdLine, int nShowCmd) +#else +int main() +#endif +{ + InitScratch(); + if (SDL_Init(SDL_INIT_VIDEO) == -1) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL); + return 1; + } + + const char *glsl_version = "#version 130"; + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; + SDL_Window *window = SDL_CreateWindow("Text editor", 640, 480, window_flags); + if (window == NULL) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window!", SDL_GetError(), NULL); + return 1; + } + + SDL_GLContext gl_context = SDL_GL_CreateContext(window); + SDL_GL_MakeCurrent(window, gl_context); + SDL_GL_SetSwapInterval(1); // Enable vsync + SDL_ShowWindow(window); + + if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load opengl!", SDL_GetError(), NULL); + return 1; + } + + glDebugMessageCallback(&GLDebugCallback, NULL); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + + Arena Perm = {}; + InitArena(&Perm); + Atlas atlas = CreateAtlas(Perm, {1024, 1024}); + Font font = CreateFont(&atlas, 16, "c:\\Windows\\Fonts\\consola.ttf"); + { + glCreateTextures(GL_TEXTURE_2D, 1, &atlas.texture_id); + glTextureParameteri(atlas.texture_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTextureParameteri(atlas.texture_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTextureStorage2D(atlas.texture_id, 1, GL_R8, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y); + glTextureSubImage2D(atlas.texture_id, 0, 0, 0, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y, GL_RED, GL_UNSIGNED_BYTE, atlas.bitmap); + } + font.texture_id = atlas.texture_id; + + while (AppIsRunning) { + glClearColor(255, 255, 255, 255); + glClear(GL_COLOR_BUFFER_BIT); + SDL_Event event; + SDL_WaitEvent(&event); + ProcessSDLEvent(&event); + SDL_GL_SwapWindow(window); + } + + SDL_DestroyWindow(window); + SDL_Quit(); + + return 0; +} \ No newline at end of file diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index 2d11391..1d21295 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -1,12 +1,12 @@ #define BASIC_IMPL -#include "../basic/basic.h" -#include "../basic/filesystem.h" -#include "../profiler/profiler.cpp" +#include "basic/basic.h" +#include "basic/filesystem.h" +#include "basic/string16.cpp" +#include "basic/math_int.cpp" +#include "basic/math.cpp" +#include "profiler/profiler.cpp" #include "new_basic.cpp" -#include "string16.cpp" #include -#include "math_int.cpp" -#include "math.cpp" #include "raylib.h" #include "colors.cpp" #include "raylib_utils.cpp" diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 0d30bfd..8b4a063 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -95,8 +95,7 @@ Int FontSpacing; Int FontLineSpacing; Int FontCharSpacing; -Int FrameID; - +Int FrameID; String WorkingDir; String16 EvalString(Allocator allocator, String16 string16);