Begin move to SDL
This commit is contained in:
149
src/new_platform/font.cpp
Normal file
149
src/new_platform/font.cpp
Normal file
@@ -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<Glyph> 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];
|
||||
}
|
||||
}
|
||||
129
src/new_platform/new_platform.cpp
Normal file
129
src/new_platform/new_platform.cpp
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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 <math.h>
|
||||
#include "math_int.cpp"
|
||||
#include "math.cpp"
|
||||
#include "raylib.h"
|
||||
#include "colors.cpp"
|
||||
#include "raylib_utils.cpp"
|
||||
|
||||
@@ -95,8 +95,7 @@ Int FontSpacing;
|
||||
Int FontLineSpacing;
|
||||
Int FontCharSpacing;
|
||||
|
||||
Int FrameID;
|
||||
|
||||
Int FrameID;
|
||||
String WorkingDir;
|
||||
|
||||
String16 EvalString(Allocator allocator, String16 string16);
|
||||
|
||||
Reference in New Issue
Block a user