Packed font rendering

This commit is contained in:
John Alanbrook 2022-12-28 22:50:54 +00:00
parent 329e10f2d6
commit 76273e1c54
23 changed files with 211 additions and 132 deletions

View file

@ -47,6 +47,7 @@ void phys2d_shape_apply(struct phys2d_shape *shape)
void init_phys2dshape(struct phys2d_shape *shape, struct gameobject *go)
{
YughInfo("Making shape with GO %p", go);
shape->go = go;
cpShapeSetCollisionType(shape->shape, go);
phys2d_shape_apply(shape);
@ -462,8 +463,9 @@ static cpBool s7_phys_cb_begin(cpArbiter *arb, cpSpace *space, void *data) {
struct gameobject *g2 = cpBodyGetUserData(body2);
script_call_sym_args(go->cbs->begin, s7_make_integer(s7, g2->editor.id));
//script_call_sym(go->cbs->begin);
//script_call_sym_args(go->cbs->begin, s7_make_integer(s7, g2->editor.id));
s7_call(s7, go->cbs->begin, s7_list(s7, 2, s7_make_integer(s7, g2->editor.id), cpvec2s7(cpArbiterGetNormal(arb))));
return 1;
}

View file

@ -9,6 +9,10 @@ struct anim make_anim() {
return a;
}
void free_anim(struct anim a) {
arrfree(a.frames);
}
struct anim anim_add_keyframe(struct anim a, struct keyframe key) {
arrput(a.frames, key);
@ -27,6 +31,8 @@ double near_val(struct anim anim, double t) {
return (interval(anim.frames[i], anim.frames[i+1], t) >= 0.5f ? anim.frames[i+1].val : anim.frames[i].val);
}
return arrlast(anim.frames).val;
}
double lerp_val(struct anim anim, double t) {

View file

@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "nuke.h"
#include "texture.h"
#include "log.h"

View file

@ -13,6 +13,7 @@
#include "openglrender.h"
#include <stb_truetype.h>
#include "stb_rect_pack.h"
static uint32_t VBO = 0;
static uint32_t VAO = 0;
@ -50,7 +51,6 @@ void font_frame(struct window *w) {
shader_use(shader);
}
// Height in pixels
struct sFont *MakeFont(const char *fontfile, int height)
{
shader_use(shader);
@ -62,6 +62,18 @@ struct sFont *MakeFont(const char *fontfile, int height)
snprintf(fontpath, 256, "fonts/%s", fontfile);
fread(ttf_buffer, 1, 1<<25, fopen(fontpath, "rb"));
unsigned char *bitmap = malloc(1024*1024);
stbtt_packedchar glyphs[95];
stbtt_pack_context pc;
stbtt_PackBegin(&pc, bitmap, 1024, 1024, 0, 1, NULL);
stbtt_PackSetOversampling(&pc, 1, 1);
stbtt_PackFontRange(&pc, ttf_buffer, 0, height, 32, 95, glyphs);
stbtt_PackEnd(&pc);
stbtt_fontinfo fontinfo;
if (!stbtt_InitFont(&fontinfo, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0))) {
@ -69,47 +81,45 @@ struct sFont *MakeFont(const char *fontfile, int height)
}
float scale = stbtt_ScaleForPixelHeight(&fontinfo, height);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &newfont->texID);
glBindTexture(GL_TEXTURE_2D, newfont->texID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 1024, 1024, 0, GL_RED, GL_UNSIGNED_BYTE, bitmap);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
int ascent, descent, linegap;
stbtt_GetFontVMetrics(&fontinfo, &ascent, &descent, &linegap);
ascent = roundf(ascent*scale);
descent = roundf(descent*scale);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (unsigned char c = 32; c < 127; c++) {
unsigned char *bitmap;
//unsigned char *bitmap;
int advance, lsb, w, h, x0, y0;
stbtt_GetCodepointHMetrics(&fontinfo, c, &advance, &lsb);
stbtt_packedchar glyph = glyphs[c-32];
bitmap = stbtt_GetCodepointBitmap(&fontinfo, scale, scale, c, &w, &h, &x0, &y0);
YughInfo("Packed char is at %d, %d, %d, %d", glyphs[c-32].x0, glyphs[c-32].y0, glyphs[c-32].x1, glyphs[c-32].y1);
GLuint ftexture;
glGenTextures(1, &ftexture);
glBindTexture(GL_TEXTURE_2D, ftexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, bitmap);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
newfont->Characters[c].TextureID = ftexture;
struct glrect r;
r.s0 = glyph.x0 / (float)1024;
r.s1 = glyph.x1 / (float) 1024;
r.t0 = glyph.y0 / (float) 1024;
r.t1 = glyph.y1 / (float) 1024;
YughInfo("That is %f %f %f %f", r.s0, r.t0, r.s1, r.t1);
newfont->Characters[c].Advance = advance * scale;
newfont->Characters[c].Size[0] = w;
newfont->Characters[c].Size[1] = h;
newfont->Characters[c].Size[0] = glyphs[c-32].x1 - glyphs[c-32].x0;
newfont->Characters[c].Size[1] = glyphs[c-32].y1 - glyphs[c-32].y0;
newfont->Characters[c].Bearing[0] = x0;
newfont->Characters[c].Bearing[1] = y0*-1;
newfont->Characters[c].rect = r;
}
return newfont;
}
static int curchar = 0;
void sdrawCharacter(struct Character c, mfloat_t cursor[2], float scale, struct shader *shader, float color[3])
{
float w = c.Size[0] * scale;
@ -119,58 +129,15 @@ void sdrawCharacter(struct Character c, mfloat_t cursor[2], float scale, struct
float ypos = cursor[1] + (c.Bearing[1] * scale) - h;
float verts[4 * 4] = {
xpos, ypos, 0.f, 0.f,
xpos+w, ypos, 1.f, 0.f,
xpos, ypos + h, 0.f, 1.f,
xpos + w, ypos + h, 1.f, 1.f
xpos, ypos, c.rect.s0, c.rect.t1,
xpos+w, ypos, c.rect.s1, c.rect.t1,
xpos, ypos + h, c.rect.s0, c.rect.t0,
xpos + w, ypos + h, c.rect.s1, c.rect.t0
};
glBindTexture(GL_TEXTURE_2D, c.TextureID);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verts), verts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBufferSubData(GL_ARRAY_BUFFER, curchar*sizeof(verts), sizeof(verts), verts);
////// Outline calculation
// float outlineWidth = 1.1;
// float ow = c.Size[0] * scale * outlineWidth;
// float oh = c.Size[1] * scale * outlineWidth;
// float oxpos = cursor[0] + c.Bearing[0] * scale * outlineWidth - ((ow-w)/2);
// float oypos = cursor[1] - (c.Size[1] - c.Bearing[1]) * scale * outlineWidth - ((oh-h)/2);
// float overts[4*4] = {
// oxpos, oypos + oh, 0.f, 0.f,
// oxpos, oypos, 0.f, 1.f,
// oxpos + ow, oypos + oh, 1.f, 0.f,
// oxpos + ow, oypos, 1.f, 1.f
// };
/////////// Shadow calculation
/*
float shadowOffset = 6.f;
float sxpos = cursor[0] + c.Bearing[0] * scale + (scale * shadowOffset);
float sypos = cursor[1] - (c.Size[1] - c.Bearing[1]) * scale - (scale * shadowOffset);
float sverts[4 * 4] = {
sxpos, sypos, 0.f, 0.f,
sxpos+w, sypos, 1.f, 0.f,
sxpos, sypos + h, 0.f, 1.f,
sxpos + w, sypos+h, 1.f, 1.f
};
//// Shadow pass
float black[3] = { 0, 0, 0 };
shader_setvec3(shader, "textColor", black);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(sverts), sverts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
*/
curchar++;
}
void text_settype(struct sFont *mfont)
@ -183,17 +150,24 @@ void renderText(const char *text, mfloat_t pos[2], float scale, mfloat_t color[3
shader_use(shader);
shader_setvec3(shader, "textColor", color);
int len = strlen(text);
mfloat_t cursor[2] = { 0.f };
cursor[0] = pos[0];
cursor[1] = pos[1];
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, font->texID);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, len*16*sizeof(float), NULL, GL_STREAM_DRAW);
const unsigned char *line, *wordstart;
line = (unsigned char*)text;
curchar = 0;
while (*line != '\0') {
@ -230,4 +204,6 @@ void renderText(const char *text, mfloat_t pos[2], float scale, mfloat_t color[3
}
}
}
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4*curchar);
}

View file

@ -6,18 +6,26 @@
struct shader;
struct window;
struct glrect {
float s0;
float s1;
float t0;
float t1;
};
/// Holds all state information relevant to a character as loaded using FreeType
struct Character {
uint32_t TextureID; // ID handle of the glyph texture
mfloat_t Size[2]; // Size of glyph
mfloat_t Bearing[2]; // Offset from baseline to left/top of glyph
unsigned int Advance; // Horizontal offset to advance to next glyph
struct glrect rect;
};
struct sFont {
uint32_t fontTexture;
uint32_t height;
struct Character Characters[127];
uint32_t texID;
};

View file

@ -131,7 +131,7 @@ int gameobject_makefromprefab(char *path)
FILE *fprefab = fopen(path, "rb");
if (fprefab == NULL) {
YughError("Could not find prefab %s.", path);
return;
return -1;
}
struct gameobject *new = get_gameobject_from_id(MakeGameobject());
@ -142,6 +142,8 @@ int gameobject_makefromprefab(char *path)
fclose(fprefab);
arrlast(gameobjects).editor.id = arrlen(gameobjects)-1;
return arrlen(gameobjects)-1;
}

View file

@ -31,6 +31,8 @@ cpVect s7tovec2(s7_scheme *sc, s7_pointer s7vec) {
return ret;
}
extern s7_scheme *s7;
/* FFI */
@ -330,6 +332,10 @@ s7_pointer s7_set_body(s7_scheme *sc, s7_pointer args) {
case 3:
gameobject_move(go, s7tovec2(sc, s7_caddr(args)));
break;
case 4:
cpBodyApplyImpulseAtWorldPoint(go->body, s7tovec2(sc, s7_caddr(args)), cpBodyGetPosition(go->body));
break;
}
return args;
@ -456,7 +462,10 @@ s7_pointer s7_anim(s7_scheme *sc, s7_pointer args) {
for (double i = 0; i < 3.0; i = i + 0.1) {
YughInfo("Val is now %f at time %f", anim_val(a, i), i);
s7_symbol_set_value(sc, prop, s7_make_real(sc, anim_val(a, i)));
}
free_anim(a);
}
#define S7_FUNC(NAME, ARGS) s7_define_function(s7, #NAME, s7_ ##NAME, ARGS, 0, 0, "")

View file

@ -3,4 +3,5 @@
void ffi_load();
#endif

View file

@ -117,6 +117,11 @@ void nuke_tree_pop() {
}
void nuke_labelf(const char *fmt, ...) {
char buf[512];
va_list args;
nk_labelf(ctx, NK_TEXT_LEFT, fmt, args);
va_start(args, fmt);
vsnprintf(buf, 512, fmt, args);
nuke_label(buf);
va_end(args);
}

55
source/engine/particle.c Normal file
View file

@ -0,0 +1,55 @@
#include "particle.h"
struct emitter make_emitter()
{
struct emitter e = { 0 };
return e;
}
struct emitter set_emitter(struct emitter e)
{
arrsetlen(e.particles, e.max);
e.first = &e.particles[0];
for (int i = 0; i < arrlen(e.particles)-1; i++) {
e.particles[i].next = &e.particles[i+1];
}
}
void free_emitter(struct emitter e)
{
arrfree(e.particles);
}
void start_emitter(struct emitter e)
{
}
void pause_emitter(struct emitter e)
{
}
void stop_emitter(struct emitter e)
{
}
void emitter_step(struct emitter e, double dt)
{
for (int i = 0; i < arrlen(e.particles); i++) {
if (e.particles[i].life <= 0)
continue;
e.particles[i].pos = cpvadd(e.particles[i].pos, cpvmult(e.particles[i].v, dt));
e.particles[i].angle += e.particles[i].av * dt;
e.particles[i].life -= dt;
if (e.particles[i].life <= 0) {
e.particles[i].next = e.first;
e.first = &e.particles[i];
}
}
}

36
source/engine/particle.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef PARTICLE_H
#define PARTICLE_H
#include <chipmunk/chipmunk.h>
struct particle {
cpVect pos;
cpVect v; /* velocity */
double angle;
double av; /* angular velocity */
union {
double life;
struct particle *next;
};
};
struct emitter {
struct particle *particles;
struct particle *first;
int max;
double life;
void (*seeder)(struct particle *p); /* Called to initialize each particle */
};
struct emitter make_emitter();
void free_emitter(struct emitter e);
void start_emitter(struct emitter e);
void pause_emitter(struct emitter e);
void stop_emitter(struct emitter e);
void emitter_step(struct emitter e, double dt);
#endif

View file

@ -9,7 +9,13 @@
s7_scheme *s7 = NULL;
s7_pointer cpvec2s7(cpVect v) {
s7_pointer ret = s7_make_vector(s7, 2);
s7_vector_set(s7, ret, 0, s7_make_real(s7, v.x));
s7_vector_set(s7, ret, 1, s7_make_real(s7, v.y));
return ret;
}
static void null_port(s7_scheme *sc, uint8_t c, s7_pointer port) {

View file

@ -2,6 +2,7 @@
#define SCRIPT_H
#include "s7.h"
#include <chipmunk/chipmunk.h>
extern s7_scheme *s7;
@ -26,4 +27,6 @@ void call_gui();
void register_physics(s7_pointer sym);
void call_physics(double dt);
s7_pointer cpvec2s7(cpVect v);
#endif

View file

@ -168,5 +168,6 @@ void shader_setUBO(struct shader *shader, const char *name, unsigned int index)
void shader_compile_all()
{
arrwalk(shaders, shader_compile);
for (int i = 0; i < arrlen(shaders); i++)
shader_compile(&shaders[i]);
}

View file

@ -115,8 +115,8 @@ void sprite_initialize()
float vertices[] = {
// pos
0.f, 0.f,
1.0f, 0.0f,
0.f, 1.f,
0.0f, 1.0f,
1.f, 0.f,
1.f, 1.f
};

View file

@ -29,7 +29,7 @@ struct Texture *texture_pullfromfile(const char *path)
tex->anim.ms = 1;
int n;
stbi_set_flip_vertically_on_load(1);
stbi_set_flip_vertically_on_load(0);
unsigned char *data = stbi_load(path, &tex->width, &tex->height, &n, 4);
while (data == NULL) {

View file

@ -3,20 +3,20 @@
#include <stb_ds.h>
static double time;
struct timer *timers;
void check_timer(struct timer *t)
void check_timer(struct timer *t, double dt)
{
if (!t->on)
return;
if (time >= t->fire_time) {
t->remain_time -= dt;
if (t->remain_time <= 0) {
t->cb(t->data);
if (t->repeat) {
t->fire_time = time + t->interval;
t->remain_time = t->interval;
return;
}
@ -25,13 +25,9 @@ void check_timer(struct timer *t)
}
}
void timer_update(double s) {
time = s;
void timer_update(double dt) {
for (int i = 0; i < arrlen(timers); i++)
check_timer(&timers[i]);
check_timer(&timers[i], dt);
}
struct timer *timer_make(double interval, void (*callback)(void *param), void *param) {
@ -53,8 +49,6 @@ void timer_pause(struct timer *t) {
if (!t->on) return;
t->on = 0;
t->remain_time = t->fire_time - time;
}
void timer_stop(struct timer *t) {
@ -68,7 +62,6 @@ void timer_start(struct timer *t) {
if (t->on) return;
t->on = 1;
t->fire_time = time + t->remain_time;
}
void timer_remove(struct timer *t) {
@ -78,25 +71,6 @@ void timer_remove(struct timer *t) {
}
void timerr_settime(struct timer *t, double interval) {
//double elapsed = time - (t->fire_time - t->interval);
t->remain_time += (interval - t->interval);
t->interval = interval;
t->remain_time = t->interval;
// TODO: timerr_settime reacts to elapsed time
}
void *arrfind(void *arr, int (*valid)(void *arr, void *cmp), void *cmp)
{
for (int i = 0; i < arrlen(arr); i++) {
if (valid(&arr[i], cmp))
return &arr[i];
}
return NULL;
}
void arrwalk(void *arr, void (*fn)(void *data))
{
for (int i = 0; i < arrlen(arr); i++)
fn(&arr[i]);
}

View file

@ -4,9 +4,7 @@
struct timer {
int timerid;
int on;
double fire_time; // Time the timer will fire
double interval; // Time of timer
double start_time; // Time the timer started this loop
int repeat;
double remain_time; // How much time until the timer executes
void (*cb)(void *data);
@ -18,13 +16,7 @@ void timer_remove(struct timer *t);
void timer_start(struct timer *t);
void timer_pause(struct timer *t);
void timer_stop(struct timer *t);
void timer_update(double s);
void timer_update(double dt);
void timerr_settime(struct timer *t, double interval);
void *arrfind(void *arr, int (*valid)(void *arr, void *cmp), void *cmp);
void arrwalk(void *arr, void (*fn)(void *data));
#endif

View file

@ -213,7 +213,8 @@ void window_handle_event(struct window *w)
void window_all_handle_events()
{
arrwalk(windows, window_handle_event);
for (int i = 0; i < arrlen(windows); i++)
window_handle_event(&windows[i]);
}
void window_makefullscreen(struct window *w)

View file

@ -174,7 +174,7 @@ int main(int argc, char **args) {
lastTick = glfwGetTime();
timer_update(lastTick);
timer_update(elapsed);
if (sim_play) {
physlag += elapsed;

View file

@ -124,7 +124,7 @@
(define-macro (register-phys type . expr)
(let ((f (gensym)))
`(begin
(define (,f hit) (begin . ,expr))
(define (,f hit norm) (begin . ,expr))
(phys_cmd body ,(case type
((collide) 0)
((separate) 3)) ,f))))

View file

@ -12,5 +12,6 @@ uniform mat4 model;
void main()
{
texcoords = vertex.xy;
texcoords.y *= -1;
gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
}

View file

@ -10,5 +10,5 @@ layout (std140) uniform Projection
void main()
{
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
TexCoords = vec2(vertex.z, 1.0 - vertex.w);
TexCoords = vertex.zw;
}