add the text primitive, finally
This commit is contained in:
parent
0f03c18806
commit
9892bf71dc
@ -57,7 +57,6 @@ set(TOWNENGINE_SOURCE_FILES
|
|||||||
townengine/util.c townengine/util.h
|
townengine/util.c townengine/util.h
|
||||||
townengine/rendering.c townengine/rendering.h
|
townengine/rendering.c townengine/rendering.h
|
||||||
townengine/input/input.c townengine/input.h
|
townengine/input/input.c townengine/input.h
|
||||||
townengine/text.c townengine/text.h
|
|
||||||
townengine/camera.c townengine/camera.h
|
townengine/camera.c townengine/camera.h
|
||||||
townengine/textures/textures.c
|
townengine/textures/textures.c
|
||||||
|
|
||||||
|
@ -17,6 +17,34 @@ static void title_tick(struct state *state) {
|
|||||||
|
|
||||||
m_sprite("/assets/title.png", ((t_frect) {
|
m_sprite("/assets/title.png", ((t_frect) {
|
||||||
(RENDER_BASE_WIDTH / 2) - (320 / 2), 64, 320, 128 }));
|
(RENDER_BASE_WIDTH / 2) - (320 / 2), 64, 320, 128 }));
|
||||||
|
|
||||||
|
|
||||||
|
/* draw the tick count as an example of dynamic text */
|
||||||
|
size_t text_str_len = snprintf(NULL, 0, "%ld", state->ctx->tick_count) + 1;
|
||||||
|
char *text_str = cmalloc(text_str_len);
|
||||||
|
snprintf(text_str, text_str_len, "%ld", state->ctx->tick_count);
|
||||||
|
|
||||||
|
const char *font = "fonts/kenney-pixel.ttf";
|
||||||
|
int text_h = 32;
|
||||||
|
int text_w = get_text_width(text_str, text_h, font);
|
||||||
|
|
||||||
|
push_rectangle(
|
||||||
|
(t_frect) {
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.w = (float)text_w,
|
||||||
|
.h = (float)text_h,
|
||||||
|
},
|
||||||
|
(t_color) { 0, 0, 0, 255 }
|
||||||
|
);
|
||||||
|
push_text(
|
||||||
|
text_str,
|
||||||
|
(t_fvec2){ 0, 0 },
|
||||||
|
text_h,
|
||||||
|
(t_color) { 255, 255, 255, 255 },
|
||||||
|
font
|
||||||
|
);
|
||||||
|
free(text_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BIN
data/fonts/kenney-pixel.ttf
Executable file
BIN
data/fonts/kenney-pixel.ttf
Executable file
Binary file not shown.
@ -1,6 +1,10 @@
|
|||||||
#ifndef CONFIG_H
|
#ifndef CONFIG_H
|
||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this file is for configuration values which are to be set at
|
* this file is for configuration values which are to be set at
|
||||||
* compile time. generally speaking, it's for things that would be unwise to
|
* compile time. generally speaking, it's for things that would be unwise to
|
||||||
@ -28,6 +32,10 @@
|
|||||||
#define AUDIO_FREQUENCY 48000
|
#define AUDIO_FREQUENCY 48000
|
||||||
#define AUDIO_N_CHANNELS 2
|
#define AUDIO_N_CHANNELS 2
|
||||||
|
|
||||||
|
#define TEXT_FONT_TEXTURE_SIZE 1024
|
||||||
|
#define TEXT_FONT_OVERSAMPLING 4
|
||||||
|
#define TEXT_FONT_FILTERING GL_LINEAR
|
||||||
|
|
||||||
/* 1024 * 1024 */
|
/* 1024 * 1024 */
|
||||||
/* #define UMKA_STACK_SIZE 1048576 */
|
/* #define UMKA_STACK_SIZE 1048576 */
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define CONTEXT_H
|
#define CONTEXT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "rendering/internal_api.h"
|
||||||
#include "textures/internal_api.h"
|
#include "textures/internal_api.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ typedef struct context {
|
|||||||
|
|
||||||
struct primitive_2d *render_queue_2d;
|
struct primitive_2d *render_queue_2d;
|
||||||
struct mesh_batch_item *uncolored_mesh_batches;
|
struct mesh_batch_item *uncolored_mesh_batches;
|
||||||
|
struct text_cache text_cache;
|
||||||
|
|
||||||
struct audio_channel_item *audio_channels;
|
struct audio_channel_item *audio_channels;
|
||||||
SDL_AudioDeviceID audio_device;
|
SDL_AudioDeviceID audio_device;
|
||||||
|
@ -356,12 +356,14 @@ static bool initialize(void) {
|
|||||||
/* rendering */
|
/* rendering */
|
||||||
/* these are dynamic arrays and will be allocated lazily by stb_ds */
|
/* these are dynamic arrays and will be allocated lazily by stb_ds */
|
||||||
ctx.render_queue_2d = NULL;
|
ctx.render_queue_2d = NULL;
|
||||||
|
ctx.uncolored_mesh_batches = NULL;
|
||||||
|
|
||||||
textures_cache_init(&ctx.texture_cache, ctx.window);
|
textures_cache_init(&ctx.texture_cache, ctx.window);
|
||||||
if (TTF_Init() < 0) {
|
if (TTF_Init() < 0) {
|
||||||
CRY_SDL("SDL_ttf initialization failed.");
|
CRY_SDL("SDL_ttf initialization failed.");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
text_cache_init(&ctx.text_cache);
|
||||||
|
|
||||||
/* input */
|
/* input */
|
||||||
input_state_init(&ctx.input);
|
input_state_init(&ctx.input);
|
||||||
@ -391,7 +393,15 @@ static void clean_up(void) {
|
|||||||
|
|
||||||
input_state_deinit(&ctx.input);
|
input_state_deinit(&ctx.input);
|
||||||
|
|
||||||
|
/* if you're gonna remove this, it's also being done in rendering.c */
|
||||||
|
for (size_t i = 0; i < arrlenu(ctx.render_queue_2d); ++i) {
|
||||||
|
if (ctx.render_queue_2d[i].type == PRIMITIVE_2D_TEXT) {
|
||||||
|
free(ctx.render_queue_2d[i].text.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
arrfree(ctx.render_queue_2d);
|
arrfree(ctx.render_queue_2d);
|
||||||
|
|
||||||
|
text_cache_deinit(&ctx.text_cache);
|
||||||
textures_cache_deinit(&ctx.texture_cache);
|
textures_cache_deinit(&ctx.texture_cache);
|
||||||
|
|
||||||
SDL_DestroyMutex(game_object_mutex);
|
SDL_DestroyMutex(game_object_mutex);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "rendering/sprites.h"
|
#include "rendering/sprites.h"
|
||||||
#include "rendering/triangles.h"
|
#include "rendering/triangles.h"
|
||||||
#include "rendering/circles.h"
|
#include "rendering/circles.h"
|
||||||
|
#include "rendering/text.h"
|
||||||
#include "textures/internal_api.h"
|
#include "textures/internal_api.h"
|
||||||
#include "townengine/context.h"
|
#include "townengine/context.h"
|
||||||
|
|
||||||
@ -19,6 +20,14 @@ static t_matrix4 camera_look_at_matrix;
|
|||||||
|
|
||||||
|
|
||||||
void render_queue_clear(void) {
|
void render_queue_clear(void) {
|
||||||
|
/* this doesn't even _deserve_ a TODO */
|
||||||
|
/* if you're gonna remove it, this is also being done in main.c */
|
||||||
|
for (size_t i = 0; i < arrlenu(ctx.render_queue_2d); ++i) {
|
||||||
|
if (ctx.render_queue_2d[i].type == PRIMITIVE_2D_TEXT) {
|
||||||
|
free(ctx.render_queue_2d[i].text.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* since i don't intend to free the queues, */
|
/* since i don't intend to free the queues, */
|
||||||
/* it's faster and simpler to just "start over" */
|
/* it's faster and simpler to just "start over" */
|
||||||
/* and start overwriting the existing data */
|
/* and start overwriting the existing data */
|
||||||
@ -103,6 +112,9 @@ static void render_2d(void) {
|
|||||||
case PRIMITIVE_2D_CIRCLE:
|
case PRIMITIVE_2D_CIRCLE:
|
||||||
render_circle(¤t->circle);
|
render_circle(¤t->circle);
|
||||||
break;
|
break;
|
||||||
|
case PRIMITIVE_2D_TEXT:
|
||||||
|
render_text(¤t->text);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,11 @@ void push_rectangle(t_frect rect, t_color color);
|
|||||||
/* pushes a filled circle onto the circle render queue */
|
/* pushes a filled circle onto the circle render queue */
|
||||||
void push_circle(t_fvec2 position, float radius, t_color color);
|
void push_circle(t_fvec2 position, float radius, t_color color);
|
||||||
|
|
||||||
|
void text_cache_init(struct text_cache *cache);
|
||||||
|
void text_cache_deinit(struct text_cache *cache);
|
||||||
|
void push_text(char *string, t_fvec2 position, int height_px, t_color color, const char *font_path);
|
||||||
|
int get_text_width(char *string, int height_px, const char *font_path);
|
||||||
|
|
||||||
/* pushes a textured 3d triangle onto the render queue */
|
/* pushes a textured 3d triangle onto the render queue */
|
||||||
/* vertices are in absolute coordinates, relative to world origin */
|
/* vertices are in absolute coordinates, relative to world origin */
|
||||||
/* texture coordinates are in pixels */
|
/* texture coordinates are in pixels */
|
||||||
|
@ -34,10 +34,19 @@ struct circle_primitive {
|
|||||||
t_fvec2 position;
|
t_fvec2 position;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct text_primitive {
|
||||||
|
t_color color;
|
||||||
|
t_fvec2 position;
|
||||||
|
char *text;
|
||||||
|
const char *font;
|
||||||
|
int height_px;
|
||||||
|
};
|
||||||
|
|
||||||
enum primitive_2d_type {
|
enum primitive_2d_type {
|
||||||
PRIMITIVE_2D_SPRITE,
|
PRIMITIVE_2D_SPRITE,
|
||||||
PRIMITIVE_2D_RECT,
|
PRIMITIVE_2D_RECT,
|
||||||
PRIMITIVE_2D_CIRCLE,
|
PRIMITIVE_2D_CIRCLE,
|
||||||
|
PRIMITIVE_2D_TEXT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct primitive_2d {
|
struct primitive_2d {
|
||||||
@ -47,6 +56,7 @@ struct primitive_2d {
|
|||||||
struct sprite_primitive sprite;
|
struct sprite_primitive sprite;
|
||||||
struct rect_primitive rect;
|
struct rect_primitive rect;
|
||||||
struct circle_primitive circle;
|
struct circle_primitive circle;
|
||||||
|
struct text_primitive text;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,6 +95,10 @@ struct mesh_batch_item {
|
|||||||
struct mesh_batch value;
|
struct mesh_batch value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct text_cache {
|
||||||
|
struct font_data **data;
|
||||||
|
};
|
||||||
|
|
||||||
/* renders the background, then the primitives in all render queues */
|
/* renders the background, then the primitives in all render queues */
|
||||||
void render(void);
|
void render(void);
|
||||||
|
|
||||||
|
248
townengine/rendering/text.h
Normal file
248
townengine/rendering/text.h
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
/* a rendering.c mixin */
|
||||||
|
#ifndef TEXT_H
|
||||||
|
#define TEXT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "../util.h"
|
||||||
|
#include "townengine/config.h"
|
||||||
|
#include "townengine/context.h"
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#include <stb_truetype.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define ASCII_START 32
|
||||||
|
#define ASCII_END 128
|
||||||
|
#define NUM_DISPLAY_ASCII ((ASCII_END - ASCII_START) + 1)
|
||||||
|
|
||||||
|
|
||||||
|
struct font_data {
|
||||||
|
stbtt_packedchar char_data[NUM_DISPLAY_ASCII];
|
||||||
|
stbtt_fontinfo info;
|
||||||
|
|
||||||
|
const char *file_path;
|
||||||
|
unsigned char *file_bytes;
|
||||||
|
size_t file_bytes_len;
|
||||||
|
|
||||||
|
GLuint texture;
|
||||||
|
|
||||||
|
int height_px;
|
||||||
|
float scale_factor;
|
||||||
|
int ascent;
|
||||||
|
int descent;
|
||||||
|
int line_gap;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct font_data *text_load_font_data(const char *path, int height_px) {
|
||||||
|
struct font_data *font_data = ccalloc(1, sizeof *font_data);
|
||||||
|
font_data->file_path = path;
|
||||||
|
font_data->height_px = height_px;
|
||||||
|
|
||||||
|
unsigned char* bitmap = ccalloc(TEXT_FONT_TEXTURE_SIZE * TEXT_FONT_TEXTURE_SIZE, 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned char *buf = NULL;
|
||||||
|
int64_t buf_len = file_to_bytes(path, &buf);
|
||||||
|
stbtt_InitFont(&font_data->info, buf, stbtt_GetFontOffsetForIndex(buf, 0));
|
||||||
|
|
||||||
|
/* might as well get these now, for later */
|
||||||
|
font_data->file_bytes = buf;
|
||||||
|
font_data->file_bytes_len = buf_len;
|
||||||
|
font_data->scale_factor = stbtt_ScaleForPixelHeight(&font_data->info, (float)height_px);
|
||||||
|
stbtt_GetFontVMetrics(
|
||||||
|
&font_data->info,
|
||||||
|
&font_data->ascent,
|
||||||
|
&font_data->descent,
|
||||||
|
&font_data->line_gap
|
||||||
|
);
|
||||||
|
font_data->ascent = (int)((float)font_data->ascent * font_data->scale_factor);
|
||||||
|
font_data->descent = (int)((float)font_data->descent * font_data->scale_factor);
|
||||||
|
font_data->line_gap = (int)((float)font_data->line_gap * font_data->scale_factor);
|
||||||
|
|
||||||
|
stbtt_pack_context pctx;
|
||||||
|
stbtt_PackBegin(&pctx, bitmap, TEXT_FONT_TEXTURE_SIZE, TEXT_FONT_TEXTURE_SIZE, 0, 1, NULL);
|
||||||
|
stbtt_PackSetOversampling(&pctx, TEXT_FONT_OVERSAMPLING, TEXT_FONT_OVERSAMPLING);
|
||||||
|
stbtt_PackFontRange(&pctx, buf, 0, (float)height_px, ASCII_START, NUM_DISPLAY_ASCII, font_data->char_data);
|
||||||
|
stbtt_PackEnd(&pctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
glGenTextures(1, &font_data->texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, font_data->texture);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_ALPHA,
|
||||||
|
TEXT_FONT_TEXTURE_SIZE,
|
||||||
|
TEXT_FONT_TEXTURE_SIZE,
|
||||||
|
0,
|
||||||
|
GL_ALPHA,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
bitmap
|
||||||
|
);
|
||||||
|
free(bitmap);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TEXT_FONT_FILTERING);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TEXT_FONT_FILTERING);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
|
||||||
|
return font_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void text_destroy_font_data(struct font_data *font_data) {
|
||||||
|
free(font_data->file_bytes);
|
||||||
|
glDeleteTextures(1, &font_data->texture);
|
||||||
|
free(font_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void text_draw_with(struct font_data* font_data, char* text, t_fvec2 position, t_color color) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, font_data->texture);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDepthFunc(GL_ALWAYS);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
|
||||||
|
glColor4ub(color.r, color.g, color.b, color.a);
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
for (const char *p = text; *p != '\0'; ++p) {
|
||||||
|
const char c = *p;
|
||||||
|
|
||||||
|
/* outside the range of what we want to display */
|
||||||
|
//if (c < ASCII_START || c > ASCII_END)
|
||||||
|
if (c < ASCII_START)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* stb_truetype.h conveniently provides everything we need to draw here! */
|
||||||
|
stbtt_aligned_quad quad;
|
||||||
|
stbtt_GetPackedQuad(
|
||||||
|
font_data->char_data,
|
||||||
|
TEXT_FONT_TEXTURE_SIZE,
|
||||||
|
TEXT_FONT_TEXTURE_SIZE,
|
||||||
|
c - ASCII_START,
|
||||||
|
&position.x,
|
||||||
|
&position.y,
|
||||||
|
&quad,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
/* have to do this so the "origin" is at the top left */
|
||||||
|
/* maybe there's a better way, or maybe this isn't a good idea... */
|
||||||
|
/* who knows */
|
||||||
|
quad.y0 += (float)font_data->ascent;
|
||||||
|
quad.y1 += (float)font_data->ascent;
|
||||||
|
|
||||||
|
/* TODO: you know... */
|
||||||
|
glTexCoord2f(quad.s0, quad.t0);
|
||||||
|
glVertex2f(quad.x0, quad.y0);
|
||||||
|
glTexCoord2f(quad.s1, quad.t0);
|
||||||
|
glVertex2f(quad.x1, quad.y0);
|
||||||
|
glTexCoord2f(quad.s1, quad.t1);
|
||||||
|
glVertex2f(quad.x1, quad.y1);
|
||||||
|
glTexCoord2f(quad.s0, quad.t1);
|
||||||
|
glVertex2f(quad.x0, quad.y1);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
glColor4ub(255, 255, 255, 255);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ensure_font_cache(const char *font_path, int height_px) {
|
||||||
|
/* HACK: stupid, bad, don't do this */
|
||||||
|
bool is_cached = false;
|
||||||
|
for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) {
|
||||||
|
struct font_data *font_data = ctx.text_cache.data[i];
|
||||||
|
if ((strcmp(font_path, font_data->file_path) == 0) && height_px == font_data->height_px) {
|
||||||
|
is_cached = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_cached) {
|
||||||
|
struct font_data *new_font_data = text_load_font_data(font_path, height_px);
|
||||||
|
arrput(ctx.text_cache.data, new_font_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct font_data *get_font_data(const char *font_path, int height_px) {
|
||||||
|
struct font_data *font_data = NULL;
|
||||||
|
for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) {
|
||||||
|
font_data = ctx.text_cache.data[i];
|
||||||
|
if ((strcmp(font_path, font_data->file_path) == 0) && height_px == font_data->height_px) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return font_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void render_text(const struct text_primitive *text) {
|
||||||
|
struct font_data *font_data = get_font_data(text->font, text->height_px);
|
||||||
|
text_draw_with(font_data, text->text, text->position, text->color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void text_cache_init(struct text_cache *cache) {
|
||||||
|
arrsetlen(cache->data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void text_cache_deinit(struct text_cache *cache) {
|
||||||
|
for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) {
|
||||||
|
text_destroy_font_data(ctx.text_cache.data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
arrfree(cache->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void push_text(char *string, t_fvec2 position, int height_px, t_color color, const char *font_path) {
|
||||||
|
ensure_font_cache(font_path, height_px);
|
||||||
|
|
||||||
|
/* the string might not be around by the time it's used, so copy it */
|
||||||
|
/* TODO: arena */
|
||||||
|
/* NOTE: can we trust strlen? */
|
||||||
|
char *dup_string = cmalloc(strlen(string) + 1);
|
||||||
|
strcpy(dup_string, string);
|
||||||
|
|
||||||
|
struct text_primitive text = {
|
||||||
|
.color = color,
|
||||||
|
.position = position,
|
||||||
|
.text = dup_string,
|
||||||
|
.font = font_path,
|
||||||
|
.height_px = height_px,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct primitive_2d primitive = {
|
||||||
|
.type = PRIMITIVE_2D_TEXT,
|
||||||
|
.text = text,
|
||||||
|
};
|
||||||
|
|
||||||
|
arrput(ctx.render_queue_2d, primitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int get_text_width(char *string, int height_px, const char *font_path) {
|
||||||
|
ensure_font_cache(font_path, height_px);
|
||||||
|
struct font_data *font_data = get_font_data(font_path, height_px);
|
||||||
|
|
||||||
|
int length = 0;
|
||||||
|
for (const char *p = string; *p != '\0'; ++p) {
|
||||||
|
const char c = *p;
|
||||||
|
int advance_width = 0;
|
||||||
|
int left_side_bearing = 0;
|
||||||
|
stbtt_GetCodepointHMetrics(&font_data->info, (int)c, &advance_width, &left_side_bearing);
|
||||||
|
length += advance_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)((float)length * font_data->scale_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -1,5 +0,0 @@
|
|||||||
#include "text.h"
|
|
||||||
|
|
||||||
#include "SDL.h"
|
|
||||||
#include "SDL_ttf.h"
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
#ifndef TEXT_H
|
|
||||||
#define TEXT_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
|
|
||||||
struct text {
|
|
||||||
char *text;
|
|
||||||
t_color color;
|
|
||||||
int ptsize;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct text_cache_item {
|
|
||||||
char *key;
|
|
||||||
struct text *value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct text_cache {
|
|
||||||
struct text_cache_item *hash;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -5,12 +5,12 @@
|
|||||||
#include <physfsrwops.h>
|
#include <physfsrwops.h>
|
||||||
#define STB_DS_IMPLEMENTATION
|
#define STB_DS_IMPLEMENTATION
|
||||||
#define STBDS_ASSERT SDL_assert
|
#define STBDS_ASSERT SDL_assert
|
||||||
#define STBDS_REALLOC(c,p,s) crealloc(p, s)
|
|
||||||
#define STBDS_FREE(c,p) free(p)
|
|
||||||
#include <stb_ds.h>
|
#include <stb_ds.h>
|
||||||
#define STB_RECT_PACK_IMPLEMENTATION
|
#define STB_RECT_PACK_IMPLEMENTATION
|
||||||
#define STBRP_ASSERT SDL_assert
|
#define STBRP_ASSERT SDL_assert
|
||||||
#include <stb_rect_pack.h>
|
#include <stb_rect_pack.h>
|
||||||
|
#define STB_TRUETYPE_IMPLEMENTATION
|
||||||
|
#include <stb_truetype.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
Loading…
Reference in New Issue
Block a user