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) void init_phys2dshape(struct phys2d_shape *shape, struct gameobject *go)
{ {
YughInfo("Making shape with GO %p", go);
shape->go = go; shape->go = go;
cpShapeSetCollisionType(shape->shape, go); cpShapeSetCollisionType(shape->shape, go);
phys2d_shape_apply(shape); 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); struct gameobject *g2 = cpBodyGetUserData(body2);
script_call_sym_args(go->cbs->begin, s7_make_integer(s7, g2->editor.id)); //script_call_sym_args(go->cbs->begin, s7_make_integer(s7, g2->editor.id));
//script_call_sym(go->cbs->begin); s7_call(s7, go->cbs->begin, s7_list(s7, 2, s7_make_integer(s7, g2->editor.id), cpvec2s7(cpArbiterGetNormal(arb))));
return 1; return 1;
} }

View file

@ -9,6 +9,10 @@ struct anim make_anim() {
return a; return a;
} }
void free_anim(struct anim a) {
arrfree(a.frames);
}
struct anim anim_add_keyframe(struct anim a, struct keyframe key) { struct anim anim_add_keyframe(struct anim a, struct keyframe key) {
arrput(a.frames, 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 (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) { double lerp_val(struct anim anim, double t) {

View file

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

View file

@ -13,6 +13,7 @@
#include "openglrender.h" #include "openglrender.h"
#include <stb_truetype.h> #include <stb_truetype.h>
#include "stb_rect_pack.h"
static uint32_t VBO = 0; static uint32_t VBO = 0;
static uint32_t VAO = 0; static uint32_t VAO = 0;
@ -50,7 +51,6 @@ void font_frame(struct window *w) {
shader_use(shader); shader_use(shader);
} }
// Height in pixels
struct sFont *MakeFont(const char *fontfile, int height) struct sFont *MakeFont(const char *fontfile, int height)
{ {
shader_use(shader); shader_use(shader);
@ -62,6 +62,18 @@ struct sFont *MakeFont(const char *fontfile, int height)
snprintf(fontpath, 256, "fonts/%s", fontfile); snprintf(fontpath, 256, "fonts/%s", fontfile);
fread(ttf_buffer, 1, 1<<25, fopen(fontpath, "rb")); 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; stbtt_fontinfo fontinfo;
if (!stbtt_InitFont(&fontinfo, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0))) { 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); 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++) { for (unsigned char c = 32; c < 127; c++) {
unsigned char *bitmap; //unsigned char *bitmap;
int advance, lsb, w, h, x0, y0; int advance, lsb, w, h, x0, y0;
stbtt_GetCodepointHMetrics(&fontinfo, c, &advance, &lsb); 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; struct glrect r;
glGenTextures(1, &ftexture); r.s0 = glyph.x0 / (float)1024;
glBindTexture(GL_TEXTURE_2D, ftexture); r.s1 = glyph.x1 / (float) 1024;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, bitmap); r.t0 = glyph.y0 / (float) 1024;
r.t1 = glyph.y1 / (float) 1024;
glGenerateMipmap(GL_TEXTURE_2D); YughInfo("That is %f %f %f %f", r.s0, r.t0, r.s1, r.t1);
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;
newfont->Characters[c].Advance = advance * scale; newfont->Characters[c].Advance = advance * scale;
newfont->Characters[c].Size[0] = w; newfont->Characters[c].Size[0] = glyphs[c-32].x1 - glyphs[c-32].x0;
newfont->Characters[c].Size[1] = h; newfont->Characters[c].Size[1] = glyphs[c-32].y1 - glyphs[c-32].y0;
newfont->Characters[c].Bearing[0] = x0; newfont->Characters[c].Bearing[0] = x0;
newfont->Characters[c].Bearing[1] = y0*-1; newfont->Characters[c].Bearing[1] = y0*-1;
newfont->Characters[c].rect = r;
} }
return newfont; return newfont;
} }
static int curchar = 0;
void sdrawCharacter(struct Character c, mfloat_t cursor[2], float scale, struct shader *shader, float color[3]) void sdrawCharacter(struct Character c, mfloat_t cursor[2], float scale, struct shader *shader, float color[3])
{ {
float w = c.Size[0] * scale; 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 ypos = cursor[1] + (c.Bearing[1] * scale) - h;
float verts[4 * 4] = { float verts[4 * 4] = {
xpos, ypos, 0.f, 0.f, xpos, ypos, c.rect.s0, c.rect.t1,
xpos+w, ypos, 1.f, 0.f, xpos+w, ypos, c.rect.s1, c.rect.t1,
xpos, ypos + h, 0.f, 1.f, xpos, ypos + h, c.rect.s0, c.rect.t0,
xpos + w, ypos + h, 1.f, 1.f xpos + w, ypos + h, c.rect.s1, c.rect.t0
}; };
glBindTexture(GL_TEXTURE_2D, c.TextureID); glBufferSubData(GL_ARRAY_BUFFER, curchar*sizeof(verts), sizeof(verts), verts);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verts), verts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
////// Outline calculation curchar++;
// 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);
*/
} }
void text_settype(struct sFont *mfont) 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_use(shader);
shader_setvec3(shader, "textColor", color); shader_setvec3(shader, "textColor", color);
int len = strlen(text);
mfloat_t cursor[2] = { 0.f }; mfloat_t cursor[2] = { 0.f };
cursor[0] = pos[0]; cursor[0] = pos[0];
cursor[1] = pos[1]; cursor[1] = pos[1];
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, font->texID);
glBindVertexArray(VAO); glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, len*16*sizeof(float), NULL, GL_STREAM_DRAW);
const unsigned char *line, *wordstart; const unsigned char *line, *wordstart;
line = (unsigned char*)text; line = (unsigned char*)text;
curchar = 0;
while (*line != '\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 shader;
struct window; struct window;
struct glrect {
float s0;
float s1;
float t0;
float t1;
};
/// Holds all state information relevant to a character as loaded using FreeType /// Holds all state information relevant to a character as loaded using FreeType
struct Character { struct Character {
uint32_t TextureID; // ID handle of the glyph texture
mfloat_t Size[2]; // Size of glyph mfloat_t Size[2]; // Size of glyph
mfloat_t Bearing[2]; // Offset from baseline to left/top of glyph mfloat_t Bearing[2]; // Offset from baseline to left/top of glyph
unsigned int Advance; // Horizontal offset to advance to next glyph unsigned int Advance; // Horizontal offset to advance to next glyph
struct glrect rect;
}; };
struct sFont { struct sFont {
uint32_t fontTexture; uint32_t fontTexture;
uint32_t height; uint32_t height;
struct Character Characters[127]; struct Character Characters[127];
uint32_t texID;
}; };

View file

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

View file

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

View file

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

View file

@ -117,6 +117,11 @@ void nuke_tree_pop() {
} }
void nuke_labelf(const char *fmt, ...) { void nuke_labelf(const char *fmt, ...) {
char buf[512];
va_list args; 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_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) { static void null_port(s7_scheme *sc, uint8_t c, s7_pointer port) {

View file

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

View file

@ -168,5 +168,6 @@ void shader_setUBO(struct shader *shader, const char *name, unsigned int index)
void shader_compile_all() 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[] = { float vertices[] = {
// pos // pos
0.f, 0.f, 0.f, 0.f,
1.0f, 0.0f, 0.0f, 1.0f,
0.f, 1.f, 1.f, 0.f,
1.f, 1.f 1.f, 1.f
}; };

View file

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

View file

@ -3,20 +3,20 @@
#include <stb_ds.h> #include <stb_ds.h>
static double time;
struct timer *timers; struct timer *timers;
void check_timer(struct timer *t) void check_timer(struct timer *t, double dt)
{ {
if (!t->on) if (!t->on)
return; return;
if (time >= t->fire_time) { t->remain_time -= dt;
if (t->remain_time <= 0) {
t->cb(t->data); t->cb(t->data);
if (t->repeat) { if (t->repeat) {
t->fire_time = time + t->interval; t->remain_time = t->interval;
return; return;
} }
@ -25,13 +25,9 @@ void check_timer(struct timer *t)
} }
} }
void timer_update(double s) { void timer_update(double dt) {
time = s;
for (int i = 0; i < arrlen(timers); i++) 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) { 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; if (!t->on) return;
t->on = 0; t->on = 0;
t->remain_time = t->fire_time - time;
} }
void timer_stop(struct timer *t) { void timer_stop(struct timer *t) {
@ -68,7 +62,6 @@ void timer_start(struct timer *t) {
if (t->on) return; if (t->on) return;
t->on = 1; t->on = 1;
t->fire_time = time + t->remain_time;
} }
void timer_remove(struct timer *t) { void timer_remove(struct timer *t) {
@ -78,25 +71,6 @@ void timer_remove(struct timer *t) {
} }
void timerr_settime(struct timer *t, double interval) { 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->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 { struct timer {
int timerid; int timerid;
int on; int on;
double fire_time; // Time the timer will fire
double interval; // Time of timer double interval; // Time of timer
double start_time; // Time the timer started this loop
int repeat; int repeat;
double remain_time; // How much time until the timer executes double remain_time; // How much time until the timer executes
void (*cb)(void *data); void (*cb)(void *data);
@ -18,13 +16,7 @@ void timer_remove(struct timer *t);
void timer_start(struct timer *t); void timer_start(struct timer *t);
void timer_pause(struct timer *t); void timer_pause(struct timer *t);
void timer_stop(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 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 #endif

View file

@ -213,7 +213,8 @@ void window_handle_event(struct window *w)
void window_all_handle_events() 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) void window_makefullscreen(struct window *w)

View file

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

View file

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

View file

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

View file

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