font: fix linedist calc + add font_print_rect

main
Dominik Madarász 2024-02-08 11:24:55 +01:00
parent ee9bf54d43
commit 295a9d932d
12 changed files with 718 additions and 663 deletions

View File

@ -674,11 +674,13 @@ typedef struct font_metrics_t {
} font_metrics_t; } font_metrics_t;
void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags); void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags);
void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags); void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags);
void font_scale(const char *face_tag, int scale_index, float value);
void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6); void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6);
void font_color(const char *color_tag, uint32_t color); void font_color(const char *color_tag, uint32_t color);
vec2 font_xy(); vec2 font_xy();
void font_goto(float x, float y); void font_goto(float x, float y);
vec2 font_print(const char *text); vec2 font_print(const char *text);
vec2 font_print_rect(const char *text, vec4 rect);
vec2 font_rect(const char *text); vec2 font_rect(const char *text);
font_metrics_t font_metrics(const char *text); font_metrics_t font_metrics(const char *text);
void* font_colorize(const char *text, const char *comma_types, const char *comma_keywords); void* font_colorize(const char *text, const char *comma_types, const char *comma_keywords);
@ -1295,6 +1297,7 @@ typedef struct anim_t {
} anim_t; } anim_t;
anim_t clip(float minframe, float maxframe, float blendtime, unsigned flags); anim_t clip(float minframe, float maxframe, float blendtime, unsigned flags);
anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags); anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags);
anim_t* animlist(const char *filename);
enum MODEL_FLAGS { enum MODEL_FLAGS {
MODEL_NO_ANIMATIONS = 1, MODEL_NO_ANIMATIONS = 1,
MODEL_NO_MESHES = 2, MODEL_NO_MESHES = 2,
@ -1481,6 +1484,8 @@ typedef struct object_t {
vec3 sca, pos, euler, pivot; vec3 sca, pos, euler, pivot;
handle* textures; handle* textures;
model_t model; model_t model;
anim_t anim;
float anim_speed;
aabb bounds; aabb bounds;
unsigned billboard; unsigned billboard;
bool light_cached; bool light_cached;
@ -1493,6 +1498,7 @@ typedef struct object_t {
vec3 object_position(object_t *obj); vec3 object_position(object_t *obj);
void object_scale(object_t *obj, vec3 sca); void object_scale(object_t *obj, vec3 sca);
void object_model(object_t *obj, model_t model); void object_model(object_t *obj, model_t model);
void object_anim(object_t *obj, anim_t anim, float speed);
void object_diffuse(object_t *obj, texture_t tex); void object_diffuse(object_t *obj, texture_t tex);
void object_diffuse_push(object_t *obj, texture_t tex); void object_diffuse_push(object_t *obj, texture_t tex);
void object_diffuse_pop(object_t *obj); void object_diffuse_pop(object_t *obj);

View File

@ -102,14 +102,15 @@ int main() {
//font_print(FONT_LEFT "Left" FONT_CENTER "Center" FONT_RIGHT "Right\n"); //font_print(FONT_LEFT "Left" FONT_CENTER "Center" FONT_RIGHT "Right\n");
// ... alignment must be the first tag in a string for now. this is a temporary hack. // ... alignment must be the first tag in a string for now. this is a temporary hack.
font_goto(0, window_height()*3/4.);
font_print(FONT_LEFT "left"); font_print(FONT_LEFT "left");
font_print(FONT_CENTER "center"); font_print(FONT_CENTER "center");
font_print(FONT_RIGHT "right"); font_print(FONT_RIGHT "right");
font_print(FONT_TOP FONT_CENTER "top\n"); font_print(FONT_TOP FONT_CENTER "top");
font_print(FONT_MIDDLE FONT_RIGHT "middle\n"); font_print(FONT_MIDDLE FONT_RIGHT "middle");
font_print(FONT_BASELINE FONT_RIGHT "baseline\n"); font_print(FONT_BASELINE FONT_RIGHT "baseline");
font_print(FONT_BOTTOM FONT_CENTER "bottom\n"); font_print(FONT_BOTTOM FONT_CENTER "bottom");
{ {
vec2 pos = vec2(1290,120); vec2 pos = vec2(1290,120);
@ -147,6 +148,18 @@ int main() {
ddraw_pop_2d(); ddraw_pop_2d();
} }
for (int i = 1; i <= 6; i++) {
vec2 pos = vec2(830,550 + 55*(i+1));
ddraw_push_2d();
char *txt = va("%cTest line %d", i, i);
font_goto(pos.x, pos.y);
vec2 size=font_rect(txt);
ddraw_aabb(vec3(pos.x,pos.y,0), vec3(pos.x+size.x,pos.y+size.y,0));
font_print(txt);
ddraw_pop_2d();
}
if (ui_panel("Fonts", 0)) { if (ui_panel("Fonts", 0)) {
ui_font(); ui_font();
ui_panel_end(); ui_panel_end();

View File

@ -16130,13 +16130,14 @@ enum FONT_FLAGS {
typedef struct font_metrics_t { typedef struct font_metrics_t {
float ascent; // max distance above baseline for all glyphs float ascent; // max distance above baseline for all glyphs
float descent; // max distance below baseline for all glyphs float descent; // max distance below baseline for all glyphs
float linegap; // distance betwen ascent of next line and descent of current line float linegap; // distance between ascent of next line and descent of current line
float linedist; // distance between the baseline of two lines (ascent - descent + linegap) float linedist; // distance between the baseline of two lines (ascent - descent + linegap)
} font_metrics_t; } font_metrics_t;
// configures // configures
API void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags); API void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags);
API void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags); API void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags);
API void font_scale(const char *face_tag, int scale_index, float value);
API void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6); API void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6);
API void font_color(const char *color_tag, uint32_t color); API void font_color(const char *color_tag, uint32_t color);
@ -16144,6 +16145,7 @@ API void font_color(const char *color_tag, uint32_t color);
API vec2 font_xy(); API vec2 font_xy();
API void font_goto(float x, float y); API void font_goto(float x, float y);
API vec2 font_print(const char *text); API vec2 font_print(const char *text);
API vec2 font_print_rect(const char *text, vec4 rect);
API vec2 font_rect(const char *text); API vec2 font_rect(const char *text);
API font_metrics_t font_metrics(const char *text); API font_metrics_t font_metrics(const char *text);
// void font_clip(vec2 topleft, vec2 bottomright); // void font_clip(vec2 topleft, vec2 bottomright);
@ -17509,7 +17511,7 @@ typedef struct anim_t {
API anim_t clip(float minframe, float maxframe, float blendtime, unsigned flags); API anim_t clip(float minframe, float maxframe, float blendtime, unsigned flags);
API anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags); API anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags);
//API array(anim_t) animlist(const char *filename); // @todo API array(anim_t) animlist(const char *filename);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// models // models
@ -17789,6 +17791,8 @@ typedef struct object_t {
vec3 sca, pos, euler, pivot; vec3 sca, pos, euler, pivot;
array(handle) textures; array(handle) textures;
model_t model; model_t model;
anim_t anim;
float anim_speed;
aabb bounds; aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool light_cached; //< used by scene to update light data bool light_cached; //< used by scene to update light data
@ -17803,6 +17807,7 @@ API vec3 object_position(object_t *obj);
API void object_scale(object_t *obj, vec3 sca); API void object_scale(object_t *obj, vec3 sca);
// //
API void object_model(object_t *obj, model_t model); API void object_model(object_t *obj, model_t model);
API void object_anim(object_t *obj, anim_t anim, float speed);
API void object_diffuse(object_t *obj, texture_t tex); API void object_diffuse(object_t *obj, texture_t tex);
API void object_diffuse_push(object_t *obj, texture_t tex); API void object_diffuse_push(object_t *obj, texture_t tex);
API void object_diffuse_pop(object_t *obj); API void object_diffuse_pop(object_t *obj);
@ -363053,7 +363058,7 @@ in vec4 instanceGlyph;\n\
uniform sampler2D sampler_font;\n\ uniform sampler2D sampler_font;\n\
uniform sampler2D sampler_meta;\n\ uniform sampler2D sampler_meta;\n\
\n\ \n\
uniform float offset_firstline; // ascent - descent - linegap/2\n\ uniform float offset_firstline; // ascent\n\
uniform float scale_factor; // scaling factor proportional to font size\n\ uniform float scale_factor; // scaling factor proportional to font size\n\
uniform vec2 string_offset; // offset of upper-left corner\n\ uniform vec2 string_offset; // offset of upper-left corner\n\
\n\ \n\
@ -363218,6 +363223,20 @@ void ui_font() {
} }
} }
void font_scale(const char *tag, int s, float v) {
font_init();
if (s < 0 || s >= 10) return;
unsigned index = *tag - FONT_FACE1[0];
if( index > FONTS_MAX ) return;
font_t *f = &fonts[index];
if (!f->initialized) return;
f->scale[s] = v / f->font_size;
}
void font_scales(const char *tag, float h1, float h2, float h3, float h4, float h5, float h6) { void font_scales(const char *tag, float h1, float h2, float h3, float h4, float h5, float h6) {
font_init(); font_init();
@ -363600,7 +363619,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
font_t *f = &fonts[0]; font_t *f = &fonts[0];
int S = 3; int S = 3;
uint32_t color = 0; uint32_t color = 0;
float X = 0, Y = 0, W = 0, L = f->ascent*f->factor*f->scale[S], LL = L; // LL=largest linedist float X = 0, Y = 0, W = 0, L = f->ascent*f->factor*f->scale[S], LL = 0; // LL=largest linedist
offset.y = -offset.y; // invert y polarity offset.y = -offset.y; // invert y polarity
// utf8 to utf32 // utf8 to utf32
@ -363632,6 +363651,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
// change size // change size
S = ch; S = ch;
//@hack: use descent when we use >H4
L = f->ascent*f->factor*f->scale[S]; L = f->ascent*f->factor*f->scale[S];
if(L > LL) LL = L; if(L > LL) LL = L;
continue; continue;
@ -363648,10 +363668,27 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
// change face // change face
f = &fonts[ ch - 0x10 ]; f = &fonts[ ch - 0x10 ];
L = f->ascent*f->factor*f->scale[S];
if(L > LL) LL = L;
} }
continue; continue;
} }
if (!LL)
LL = L;
if (ch == FONT_LEFT[0] && (
(unicode[i+1]) == FONT_LEFT[1] ||
(unicode[i+1]) == FONT_CENTER[1] ||
(unicode[i+1]) == FONT_RIGHT[1] ||
(unicode[i+1]) == FONT_TOP[1] ||
(unicode[i+1]) == FONT_MIDDLE[1] ||
(unicode[i+1]) == FONT_BASELINE[1] ||
(unicode[i+1]) == FONT_BOTTOM[1]
)) {
continue;
}
// convert to vbo data // convert to vbo data
int cp = ch - f->begin; // f->cp2iter[ch - f->begin]; int cp = ch - f->begin; // f->cp2iter[ch - f->begin];
//if(cp == 0xFFFD) continue; //if(cp == 0xFFFD) continue;
@ -363906,25 +363943,25 @@ void font_goto(float x, float y) {
} }
// Print and linefeed. Text may include markup code // Print and linefeed. Text may include markup code
vec2 font_print(const char *text) { vec2 font_print_rect(const char *text, vec4 rect) {
// @fixme: remove this hack // @fixme: remove this hack
if( text[0] == FONT_LEFT[0] ) { if( text[0] == FONT_LEFT[0] ) {
int l = text[1] == FONT_LEFT[1]; int l = text[1] == FONT_LEFT[1];
int c = text[1] == FONT_CENTER[1]; int c = text[1] == FONT_CENTER[1];
int r = text[1] == FONT_RIGHT[1]; int r = text[1] == FONT_RIGHT[1];
if( l || c || r ) { if( l || c || r ) {
vec2 rect = font_rect(text + 2); vec2 text_rect = font_rect(text + 2);
gotoxy.x = l ? 0 : r ? (window_width() - rect.x) : window_width()/2 - rect.x/2; gotoxy.x = l ? rect.x : r ? ((rect.x+rect.z) - text_rect.x) : rect.x+rect.z/2. - text_rect.x/2.;
return font_print(text + 2); return font_print_rect(text + 2, rect);
} }
int t = text[1] == FONT_TOP[1]; int t = text[1] == FONT_TOP[1];
int b = text[1] == FONT_BOTTOM[1]; int b = text[1] == FONT_BOTTOM[1];
int m = text[1] == FONT_MIDDLE[1]; int m = text[1] == FONT_MIDDLE[1];
int B = text[1] == FONT_BASELINE[1]; int B = text[1] == FONT_BASELINE[1];
if( t || b || m || B ) { if( t || b || m || B ) {
vec2 rect = font_rect(text + 2); vec2 text_rect = font_rect(text + 2);
gotoxy.y = t ? 0 : b ? (window_height() - rect.y) : m ? window_height()/2-rect.y/2 : window_height()/2-rect.y/1; gotoxy.y = t ? rect.y : b ? ((rect.y+rect.w) - text_rect.y) : m ? rect.y+rect.w/2.-text_rect.y/2. : rect.y+rect.w/2.-text_rect.y/1;
return font_print(text + 2); return font_print_rect(text + 2, rect);
} }
} }
@ -363934,6 +363971,11 @@ vec2 font_print(const char *text) {
return dims; return dims;
} }
vec2 font_print(const char *text) {
vec4 dims = {0, 0, window_width(), window_height()};
return font_print_rect(text, dims);
}
// Print a code snippet with syntax highlighting // Print a code snippet with syntax highlighting
vec2 font_highlight(const char *text, const void *colors) { vec2 font_highlight(const char *text, const void *colors) {
vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd); vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd);
@ -372697,37 +372739,12 @@ typedef struct iqm_t {
vec4 *colormaps; vec4 *colormaps;
} iqm_t; } iqm_t;
#define meshdata (q->meshdata)
#define animdata (q->animdata)
#define nummeshes (q->nummeshes)
#define numtris (q->numtris)
#define numverts (q->numverts)
#define numjoints (q->numjoints)
#define numframes (q->numframes)
#define numanims (q->numanims)
#define meshes (q->meshes)
#define textures (q->textures)
#define joints (q->joints)
#define poses (q->poses)
#define anims (q->anims)
#define baseframe (q->baseframe)
#define inversebaseframe (q->inversebaseframe)
#define outframe (q->outframe)
#define frames (q->frames)
#define vao (q->vao)
#define ibo (q->ibo)
#define vbo (q->vbo)
#define bonematsoffset (q->bonematsoffset)
#define buf (q->buf)
#define bounds (q->bounds)
#define colormaps (q->colormaps)
void model_set_texture(model_t m, texture_t t) { void model_set_texture(model_t m, texture_t t) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
for( int i = 0; i < nummeshes; ++i) { // assume 1 texture per mesh for( int i = 0; i < q->nummeshes; ++i) { // assume 1 texture per mesh
textures[i] = t.id; q->textures[i] = t.id;
} }
} }
@ -372820,9 +372837,9 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
if ((loc = glGetUniformLocation(shader, "proj")) >= 0) { if ((loc = glGetUniformLocation(shader, "proj")) >= 0) {
glUniformMatrix4fv(loc, 1, GL_FALSE, proj); glUniformMatrix4fv(loc, 1, GL_FALSE, proj);
} }
if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, numanims ? GL_TRUE : GL_FALSE); if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, q->numanims ? GL_TRUE : GL_FALSE);
if( numanims ) if( q->numanims )
if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, numjoints, GL_FALSE, outframe[0]); if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, q->numjoints, GL_FALSE, q->outframe[0]);
if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) { if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) {
glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE); glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE);
@ -372833,10 +372850,10 @@ void model_set_state(model_t m) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
glBindVertexArray( vao ); glBindVertexArray( q->vao );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, q->vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, position) ); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, position) );
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord) ); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord) );
@ -372857,7 +372874,7 @@ void model_set_state(model_t m) {
glEnableVertexAttribArray(12); glEnableVertexAttribArray(12);
// animation // animation
if(numframes > 0) { if(q->numframes > 0) {
glVertexAttribPointer( 8, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) ); glVertexAttribPointer( 8, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) );
glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) ); glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) );
glVertexAttribPointer(10, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) ); glVertexAttribPointer(10, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) );
@ -372898,71 +372915,71 @@ void model_set_state(model_t m) {
static static
bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
if(meshdata) return false; if(q->meshdata) return false;
lil32p(&buf[hdr->ofs_vertexarrays], hdr->num_vertexarrays*sizeof(struct iqmvertexarray)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_vertexarrays], hdr->num_vertexarrays*sizeof(struct iqmvertexarray)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_triangles], hdr->num_triangles*sizeof(struct iqmtriangle)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_triangles], hdr->num_triangles*sizeof(struct iqmtriangle)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_meshes], hdr->num_meshes*sizeof(struct iqmmesh)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_meshes], hdr->num_meshes*sizeof(struct iqmmesh)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t));
meshdata = buf; q->meshdata = q->buf;
nummeshes = hdr->num_meshes; q->nummeshes = hdr->num_meshes;
numtris = hdr->num_triangles; q->numtris = hdr->num_triangles;
numverts = hdr->num_vertexes; q->numverts = hdr->num_vertexes;
numjoints = hdr->num_joints; q->numjoints = hdr->num_joints;
outframe = CALLOC(hdr->num_joints, sizeof(mat34)); q->outframe = CALLOC(hdr->num_joints, sizeof(mat34));
float *inposition = NULL, *innormal = NULL, *intangent = NULL, *intexcoord = NULL, *invertexindex = NULL; float *inposition = NULL, *innormal = NULL, *intangent = NULL, *intexcoord = NULL, *invertexindex = NULL;
uint8_t *inblendindex8 = NULL, *inblendweight8 = NULL; uint8_t *inblendindex8 = NULL, *inblendweight8 = NULL;
int *inblendindexi = NULL; float *inblendweightf = NULL; int *inblendindexi = NULL; float *inblendweightf = NULL;
uint8_t *invertexcolor8 = NULL; uint8_t *invertexcolor8 = NULL;
struct iqmvertexarray *vas = (struct iqmvertexarray *)&buf[hdr->ofs_vertexarrays]; struct iqmvertexarray *vas = (struct iqmvertexarray *)&q->buf[hdr->ofs_vertexarrays];
for(int i = 0; i < (int)hdr->num_vertexarrays; i++) { for(int i = 0; i < (int)hdr->num_vertexarrays; i++) {
struct iqmvertexarray *va = &vas[i]; struct iqmvertexarray *va = &vas[i];
switch(va->type) { switch(va->type) {
default: continue; // return PANIC("unknown iqm vertex type (%d)", va->type), false; default: continue; // return PANIC("unknown iqm vertex type (%d)", va->type), false;
break; case IQM_POSITION: ASSERT(va->format == IQM_FLOAT && va->size == 3); inposition = (float *)&buf[va->offset]; lil32pf(inposition, 3*hdr->num_vertexes); break; case IQM_POSITION: ASSERT(va->format == IQM_FLOAT && va->size == 3); inposition = (float *)&q->buf[va->offset]; lil32pf(inposition, 3*hdr->num_vertexes);
break; case IQM_NORMAL: ASSERT(va->format == IQM_FLOAT && va->size == 3); innormal = (float *)&buf[va->offset]; lil32pf(innormal, 3*hdr->num_vertexes); break; case IQM_NORMAL: ASSERT(va->format == IQM_FLOAT && va->size == 3); innormal = (float *)&q->buf[va->offset]; lil32pf(innormal, 3*hdr->num_vertexes);
break; case IQM_TANGENT: ASSERT(va->format == IQM_FLOAT && va->size == 4); intangent = (float *)&buf[va->offset]; lil32pf(intangent, 4*hdr->num_vertexes); break; case IQM_TANGENT: ASSERT(va->format == IQM_FLOAT && va->size == 4); intangent = (float *)&q->buf[va->offset]; lil32pf(intangent, 4*hdr->num_vertexes);
break; case IQM_TEXCOORD: ASSERT(va->format == IQM_FLOAT && va->size == 2); intexcoord = (float *)&buf[va->offset]; lil32pf(intexcoord, 2*hdr->num_vertexes); break; case IQM_TEXCOORD: ASSERT(va->format == IQM_FLOAT && va->size == 2); intexcoord = (float *)&q->buf[va->offset]; lil32pf(intexcoord, 2*hdr->num_vertexes);
break; case IQM_COLOR: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE); invertexcolor8 = (uint8_t *)&buf[va->offset]; break; case IQM_COLOR: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE); invertexcolor8 = (uint8_t *)&q->buf[va->offset];
break; case IQM_BLENDINDEXES: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_INT); break; case IQM_BLENDINDEXES: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_INT);
if(va->format == IQM_UBYTE) inblendindex8 = (uint8_t *)&buf[va->offset]; if(va->format == IQM_UBYTE) inblendindex8 = (uint8_t *)&q->buf[va->offset];
else inblendindexi = (int *)&buf[va->offset]; else inblendindexi = (int *)&q->buf[va->offset];
break; case IQM_BLENDWEIGHTS: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_FLOAT); break; case IQM_BLENDWEIGHTS: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_FLOAT);
if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&buf[va->offset]; if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&q->buf[va->offset];
else inblendweightf = (float *)&buf[va->offset]; else inblendweightf = (float *)&q->buf[va->offset];
invertexindex = (inblendweight8 ? (float*)(inblendweight8 + 4) : inblendweightf + 4 ); invertexindex = (inblendweight8 ? (float*)(inblendweight8 + 4) : inblendweightf + 4 );
} }
} }
if (hdr->ofs_bounds) lil32p(buf + hdr->ofs_bounds, hdr->num_frames * sizeof(struct iqmbounds)); if (hdr->ofs_bounds) lil32p(q->buf + hdr->ofs_bounds, hdr->num_frames * sizeof(struct iqmbounds));
if (hdr->ofs_bounds) bounds = (struct iqmbounds *) &buf[hdr->ofs_bounds]; if (hdr->ofs_bounds) q->bounds = (struct iqmbounds *) &q->buf[hdr->ofs_bounds];
meshes = (struct iqmmesh *)&buf[hdr->ofs_meshes]; q->meshes = (struct iqmmesh *)&q->buf[hdr->ofs_meshes];
joints = (struct iqmjoint *)&buf[hdr->ofs_joints]; q->joints = (struct iqmjoint *)&q->buf[hdr->ofs_joints];
baseframe = CALLOC(hdr->num_joints, sizeof(mat34)); q->baseframe = CALLOC(hdr->num_joints, sizeof(mat34));
inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34)); q->inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34));
for(int i = 0; i < (int)hdr->num_joints; i++) { for(int i = 0; i < (int)hdr->num_joints; i++) {
struct iqmjoint *j = &joints[i]; struct iqmjoint *j = &q->joints[i];
compose34(baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale)); compose34(q->baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale));
invert34(inversebaseframe[i], baseframe[i]); invert34(q->inversebaseframe[i], q->baseframe[i]);
if(j->parent >= 0) { if(j->parent >= 0) {
multiply34x2(baseframe[i], baseframe[j->parent], baseframe[i]); multiply34x2(q->baseframe[i], q->baseframe[j->parent], q->baseframe[i]);
multiply34(inversebaseframe[i], inversebaseframe[j->parent]); multiply34(q->inversebaseframe[i], q->inversebaseframe[j->parent]);
} }
} }
struct iqmtriangle *tris = (struct iqmtriangle *)&buf[hdr->ofs_triangles]; struct iqmtriangle *tris = (struct iqmtriangle *)&q->buf[hdr->ofs_triangles];
m->num_tris = hdr->num_triangles; m->num_tris = hdr->num_triangles;
m->tris = (void*)tris; m->tris = (void*)tris;
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &q->vao);
glBindVertexArray(vao); glBindVertexArray(q->vao);
if(!ibo) glGenBuffers(1, &ibo); if(!q->ibo) glGenBuffers(1, &q->ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, hdr->num_triangles*sizeof(struct iqmtriangle), tris, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, hdr->num_triangles*sizeof(struct iqmtriangle), tris, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@ -372993,8 +373010,8 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
if(invertexcolor8) memcpy(v->color, &invertexcolor8[i*4], sizeof(v->color)); if(invertexcolor8) memcpy(v->color, &invertexcolor8[i*4], sizeof(v->color));
} }
if(!vbo) glGenBuffers(1, &vbo); if(!q->vbo) glGenBuffers(1, &q->vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, q->vbo);
glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
@ -373015,16 +373032,16 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
m->verts = verts; m->verts = verts;
/*m->verts = 0; FREE(verts);*/ /*m->verts = 0; FREE(verts);*/
textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint));
colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4));
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
textures[i] = invalid; q->textures[i] = invalid;
} }
const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
struct iqmmesh *m = &meshes[i]; struct iqmmesh *m = &q->meshes[i];
PRINTF("loaded mesh: %s\n", &str[m->name]); PRINTF("loaded mesh: %s\n", &str[m->name]);
} }
@ -373033,34 +373050,34 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
static static
bool model_load_anims(iqm_t *q, const struct iqmheader *hdr) { bool model_load_anims(iqm_t *q, const struct iqmheader *hdr) {
if((int)hdr->num_poses != numjoints) return false; if((int)hdr->num_poses != q->numjoints) return false;
if(animdata) { if(q->animdata) {
if(animdata != meshdata) FREE(animdata); if(q->animdata != q->meshdata) FREE(q->animdata);
FREE(frames); FREE(q->frames);
animdata = NULL; q->animdata = NULL;
anims = NULL; q->anims = NULL;
frames = 0; q->frames = 0;
numframes = 0; q->numframes = 0;
numanims = 0; q->numanims = 0;
} }
lil32p(&buf[hdr->ofs_poses], hdr->num_poses*sizeof(struct iqmpose)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_poses], hdr->num_poses*sizeof(struct iqmpose)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_anims], hdr->num_anims*sizeof(struct iqmanim)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_anims], hdr->num_anims*sizeof(struct iqmanim)/sizeof(uint32_t));
lil16p((uint16_t *)&buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels); lil16p((uint16_t *)&q->buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels);
animdata = buf; q->animdata = q->buf;
numanims = hdr->num_anims; q->numanims = hdr->num_anims;
numframes = hdr->num_frames; q->numframes = hdr->num_frames;
anims = (struct iqmanim *)&buf[hdr->ofs_anims]; q->anims = (struct iqmanim *)&q->buf[hdr->ofs_anims];
poses = (struct iqmpose *)&buf[hdr->ofs_poses]; q->poses = (struct iqmpose *)&q->buf[hdr->ofs_poses];
frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34)); q->frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34));
uint16_t *framedata = (uint16_t *)&buf[hdr->ofs_frames]; uint16_t *framedata = (uint16_t *)&q->buf[hdr->ofs_frames];
for(int i = 0; i < (int)hdr->num_frames; i++) { for(int i = 0; i < (int)hdr->num_frames; i++) {
for(int j = 0; j < (int)hdr->num_poses; j++) { for(int j = 0; j < (int)hdr->num_poses; j++) {
struct iqmpose *p = &poses[j]; struct iqmpose *p = &q->poses[j];
quat rotate; quat rotate;
vec3 translate, scale; vec3 translate, scale;
translate.x = p->channeloffset[0]; if(p->mask&0x01) translate.x += *framedata++ * p->channelscale[0]; translate.x = p->channeloffset[0]; if(p->mask&0x01) translate.x += *framedata++ * p->channelscale[0];
@ -373084,16 +373101,16 @@ bool model_load_anims(iqm_t *q, const struct iqmheader *hdr) {
// parentPose * childPose * childInverseBasePose // parentPose * childPose * childInverseBasePose
mat34 m; compose34(m, translate, normq(rotate), scale); mat34 m; compose34(m, translate, normq(rotate), scale);
if(p->parent >= 0) multiply34x3(frames[i*hdr->num_poses + j], baseframe[p->parent], m, inversebaseframe[j]); if(p->parent >= 0) multiply34x3(q->frames[i*hdr->num_poses + j], q->baseframe[p->parent], m, q->inversebaseframe[j]);
else multiply34x2(frames[i*hdr->num_poses + j], m, inversebaseframe[j]); else multiply34x2(q->frames[i*hdr->num_poses + j], m, q->inversebaseframe[j]);
} }
} }
const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; // const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
for(int i = 0; i < (int)hdr->num_anims; i++) { // for(int i = 0; i < (int)hdr->num_anims; i++) {
struct iqmanim *a = &anims[i]; // struct iqmanim *a = &anims[i];
PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]); // PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]);
} // }
return true; return true;
} }
@ -373106,14 +373123,14 @@ static char* strcpy_safe(char *d, const char *s) {
static static
bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model) { bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model) {
textures = textures ? textures : CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); // up to 8 textures per mesh q->textures = q->textures ? q->textures : CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); // up to 8 textures per mesh
colormaps = colormaps ? colormaps : CALLOC(hdr->num_meshes * 8, sizeof(vec4)); // up to 8 colormaps per mesh q->colormaps = q->colormaps ? q->colormaps : CALLOC(hdr->num_meshes * 8, sizeof(vec4)); // up to 8 colormaps per mesh
GLuint *out = textures; GLuint *out = q->textures;
const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
struct iqmmesh *m = &meshes[i]; struct iqmmesh *m = &q->meshes[i];
// reuse texture+material if already decoded // reuse texture+material if already decoded
bool reused = 0; bool reused = 0;
@ -373282,13 +373299,23 @@ model_t model_from_mem(const void *mem, int len, int flags) {
if( !memcmp(hdr.magic, IQM_MAGIC, sizeof(hdr.magic))) { if( !memcmp(hdr.magic, IQM_MAGIC, sizeof(hdr.magic))) {
lil32p(&hdr.version, (sizeof(hdr) - sizeof(hdr.magic))/sizeof(uint32_t)); lil32p(&hdr.version, (sizeof(hdr) - sizeof(hdr.magic))/sizeof(uint32_t));
if(hdr.version == IQM_VERSION) { if(hdr.version == IQM_VERSION) {
buf = CALLOC(hdr.filesize, sizeof(uint8_t)); q->buf = CALLOC(hdr.filesize, sizeof(uint8_t));
memcpy(buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr)); memcpy(q->buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr));
error = 0; error = 0;
if( hdr.num_meshes > 0 && !(flags & MODEL_NO_MESHES) ) error |= !model_load_meshes(q, &hdr, &m); if( hdr.num_meshes > 0 && !(flags & MODEL_NO_MESHES) ) error |= !model_load_meshes(q, &hdr, &m);
if( hdr.num_meshes > 0 && !(flags & MODEL_NO_TEXTURES) ) error |= !model_load_textures(q, &hdr, &m); if( hdr.num_meshes > 0 && !(flags & MODEL_NO_TEXTURES) ) error |= !model_load_textures(q, &hdr, &m);
else {
// setup fallback
material_t mt = {0};
mt.name = "placeholder";
mt.count = 1;
mt.layer[0].color = vec4(1,1,1,1);
mt.layer[0].texture = texture_checker().id;
array_push(m.materials, mt);
}
if( hdr.num_anims > 0 && !(flags & MODEL_NO_ANIMATIONS) ) error |= !model_load_anims(q, &hdr); if( hdr.num_anims > 0 && !(flags & MODEL_NO_ANIMATIONS) ) error |= !model_load_anims(q, &hdr);
if( buf != meshdata && buf != animdata ) FREE(buf); if( q->buf != q->meshdata && q->buf != q->animdata ) FREE(q->buf);
} }
} }
} }
@ -373297,31 +373324,23 @@ model_t model_from_mem(const void *mem, int len, int flags) {
PRINTF("Error: cannot load %s", "model"); PRINTF("Error: cannot load %s", "model");
FREE(q), q = 0; FREE(q), q = 0;
} else { } else {
#undef vao
#undef ibo
#undef vbo
m.vao = q->vao; m.vao = q->vao;
m.ibo = q->ibo; m.ibo = q->ibo;
m.vbo = q->vbo; m.vbo = q->vbo;
m.num_verts = numverts; m.num_verts = q->numverts;
#define vao (q->vao)
#define ibo (q->ibo)
#define vbo (q->vbo)
// m.boxes = bounds; // <@todo // m.boxes = bounds; // <@todo
m.num_meshes = nummeshes; m.num_meshes = q->nummeshes;
m.num_triangles = numtris; m.num_triangles = q->numtris;
m.num_joints = numjoints; m.num_joints = q->numjoints;
//m.num_poses = numposes; //m.num_poses = numposes;
m.num_anims = numanims; m.num_anims = q->numanims;
m.num_frames = numframes; m.num_frames = q->numframes;
m.iqm = q; m.iqm = q;
m.curframe = model_animate(m, 0); m.curframe = model_animate(m, 0);
//m.num_textures = nummeshes; // assume 1 texture only per mesh //m.num_textures = q->nummeshes; // assume 1 texture only per mesh
#undef textures
m.textures = (q->textures); m.textures = (q->textures);
#define textures (q->textures)
m.flags = flags; m.flags = flags;
@ -373345,9 +373364,9 @@ bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out) {
if(!m.iqm) return false; if(!m.iqm) return false;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
if(joint >= numjoints) return false; if(joint >= q->numjoints) return false;
multiply34x2(*out, outframe[joint], baseframe[joint]); multiply34x2(*out, q->outframe[joint], q->baseframe[joint]);
return true; return true;
} }
@ -373358,6 +373377,26 @@ anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags) {
return clip(minframe, maxframe, blendtime, flags | ANIM_LOOP); return clip(minframe, maxframe, blendtime, flags | ANIM_LOOP);
} }
array(anim_t) animlist(const char *pathfile) {
anim_t *animlist = 0;
char *anim_file = vfs_read(strendi(pathfile,".txt") ? pathfile : va("%s@animlist.txt", pathfile));
if( anim_file ) {
// deserialize anim
for each_substring(anim_file, "\r\n", anim) {
int from, to;
char anim_name[128] = {0};
if( sscanf(anim, "%*s %d-%d %127[^\r\n]", &from, &to, anim_name) != 3) continue;
array_push(animlist, !!strstri(anim_name, "loop") || !strcmpi(anim_name, "idle") ? loop(from, to, 0, 0) : clip(from, to, 0, 0)); // [from,to,flags]
array_back(animlist)->name = strswap(strswap(strswap(STRDUP(anim_name), "Loop", ""), "loop", ""), "()", ""); // @leak
}
} else {
// placeholder
array_push(animlist, clip(0,1,0,0));
array_back(animlist)->name = STRDUP("Error"); // @leak
}
return animlist;
}
static static
void anim_tick(anim_t *p, bool is_primary, float delta) { // delta can be negative (reverses anim) void anim_tick(anim_t *p, bool is_primary, float delta) { // delta can be negative (reverses anim)
if( !is_primary ) p->active = 0; if( !is_primary ) p->active = 0;
@ -373395,18 +373434,18 @@ float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float
unsigned frame4 = secondary->pose.y; unsigned frame4 = secondary->pose.y;
float alphaB = secondary->pose.z; float alphaB = secondary->pose.z;
mat34 *mat1 = &frames[frame1 * numjoints]; mat34 *mat1 = &q->frames[frame1 * q->numjoints];
mat34 *mat2 = &frames[frame2 * numjoints]; mat34 *mat2 = &q->frames[frame2 * q->numjoints];
mat34 *mat3 = &frames[frame3 * numjoints]; mat34 *mat3 = &q->frames[frame3 * q->numjoints];
mat34 *mat4 = &frames[frame4 * numjoints]; mat34 *mat4 = &q->frames[frame4 * q->numjoints];
for(int i = 0; i < numjoints; i++) { for(int i = 0; i < q->numjoints; i++) {
mat34 matA, matB, matF; mat34 matA, matB, matF;
lerp34(matA, mat1[i], mat2[i], alphaA); lerp34(matA, mat1[i], mat2[i], alphaA);
lerp34(matB, mat3[i], mat4[i], alphaB); lerp34(matB, mat3[i], mat4[i], alphaB);
lerp34(matF, matA, matB, alpha ); lerp34(matF, matA, matB, alpha );
if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], matF); if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], matF);
else copy34(outframe[i], matF); else copy34(q->outframe[i], matF);
} }
return frame1 + alpha; return frame1 + alpha;
@ -373441,20 +373480,20 @@ float model_animate_clip(model_t m, float curframe, int minframe, int maxframe,
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
float retframe = -1; float retframe = -1;
if( numframes > 0 ) { if( q->numframes > 0 ) {
vec3 p = pose(curframe >= m.curframe, curframe, minframe, maxframe, loop, &retframe); vec3 p = pose(curframe >= m.curframe, curframe, minframe, maxframe, loop, &retframe);
int frame1 = p.x; int frame1 = p.x;
int frame2 = p.y; int frame2 = p.y;
float offset = p.z; float offset = p.z;
mat34 *mat1 = &frames[frame1 * numjoints]; mat34 *mat1 = &q->frames[frame1 * q->numjoints];
mat34 *mat2 = &frames[frame2 * numjoints]; mat34 *mat2 = &q->frames[frame2 * q->numjoints];
// @todo: add animation blending and inter-frame blending here // @todo: add animation blending and inter-frame blending here
for(int i = 0; i < numjoints; i++) { for(int i = 0; i < q->numjoints; i++) {
mat34 mat; lerp34(mat, mat1[i], mat2[i], offset); mat34 mat; lerp34(mat, mat1[i], mat2[i], offset);
if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], mat); if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], mat);
else copy34(outframe[i], mat); else copy34(q->outframe[i], mat);
} }
} }
@ -373465,20 +373504,20 @@ void model_render_skeleton(model_t m, mat44 M) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
if(!numjoints) return; if(!q->numjoints) return;
ddraw_ontop_push(true); ddraw_ontop_push(true);
ddraw_color_push(RED); ddraw_color_push(RED);
for( int joint = 0; joint < numjoints; joint++ ) { for( int joint = 0; joint < q->numjoints; joint++ ) {
if( joints[joint].parent < 0) continue; if( q->joints[joint].parent < 0) continue;
// bone space... // bone space...
mat34 f; mat34 f;
model_get_bone_pose(m, joint, &f); model_get_bone_pose(m, joint, &f);
vec3 pos = vec3(f[3],f[7],f[11]); vec3 pos = vec3(f[3],f[7],f[11]);
model_get_bone_pose(m, joints[joint].parent, &f); model_get_bone_pose(m, q->joints[joint].parent, &f);
vec3 src = vec3(f[3],f[7],f[11]); vec3 src = vec3(f[3],f[7],f[11]);
// ...to model space // ...to model space
@ -373506,7 +373545,7 @@ void model_render_skeleton(model_t m, mat44 M) {
float model_animate(model_t m, float curframe) { float model_animate(model_t m, float curframe) {
if(!m.iqm) return -1; if(!m.iqm) return -1;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
return model_animate_clip(m, curframe, 0, numframes-1, true); return model_animate_clip(m, curframe, 0, q->numframes-1, true);
} }
static static
@ -373514,19 +373553,19 @@ void model_draw_call(model_t m, int shader) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
glBindVertexArray( vao ); glBindVertexArray( q->vao );
struct iqmtriangle *tris = NULL; struct iqmtriangle *tris = NULL;
for(int i = 0; i < nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
struct iqmmesh *im = &meshes[i]; struct iqmmesh *im = &q->meshes[i];
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[i] ); glBindTexture(GL_TEXTURE_2D, q->textures[i] );
glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 ); glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 );
int loc; int loc;
if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) {
bool textured = !!textures[i] && textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id;
glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); glUniform1i(loc, textured ? GL_TRUE : GL_FALSE);
if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) {
glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a); glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a);
@ -373586,10 +373625,10 @@ aabb aabb_transform( aabb A, mat44 M ) {
aabb model_aabb(model_t m, mat44 transform) { aabb model_aabb(model_t m, mat44 transform) {
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
if( q && bounds ) { if( q && q->bounds ) {
int f = ( (int)m.curframe ) % (numframes + !numframes); int f = ( (int)m.curframe ) % (q->numframes + !q->numframes);
vec3 bbmin = ptr3(bounds[f].bbmin); vec3 bbmin = ptr3(q->bounds[f].bbmin);
vec3 bbmax = ptr3(bounds[f].bbmax); vec3 bbmax = ptr3(q->bounds[f].bbmax);
return aabb_transform(aabb(bbmin,bbmax), transform); return aabb_transform(aabb(bbmin,bbmax), transform);
} }
return aabb(vec3(0,0,0),vec3(0,0,0)); return aabb(vec3(0,0,0),vec3(0,0,0));
@ -373604,62 +373643,22 @@ void model_destroy(model_t m) {
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh); // if(m.mesh) mesh_destroy(m.mesh);
FREE(outframe); FREE(q->outframe);
FREE(colormaps); FREE(q->colormaps);
FREE(textures); FREE(q->textures);
FREE(baseframe); FREE(q->baseframe);
FREE(inversebaseframe); FREE(q->inversebaseframe);
if(animdata != meshdata) FREE(animdata); if(q->animdata != q->meshdata) FREE(q->animdata);
//FREE(meshdata); //FREE(q->meshdata);
FREE(frames); FREE(q->frames);
FREE(buf); FREE(q->buf);
FREE(q); FREE(q);
} }
#undef program
#undef meshdata
#undef animdata
#undef nummeshes
#undef numtris
#undef numverts
#undef numjoints
#undef numframes
#undef numanims
#undef meshes
#undef textures
#undef joints
#undef poses
#undef anims
#undef baseframe
#undef inversebaseframe
#undef outframe
#undef frames
#undef vao
#undef ibo
#undef vbo
#undef bonematsoffset
#undef buf
#undef bounds
#undef colormaps
anims_t animations(const char *pathfile, int flags) { anims_t animations(const char *pathfile, int flags) {
anims_t a = {0}; anims_t a = {0};
char *anim_file = vfs_read(strendi(pathfile,".txt") ? pathfile : va("%s@animlist.txt", pathfile));
if( anim_file ) {
// deserialize anim
a.speed = 1.0; a.speed = 1.0;
for each_substring(anim_file, "\r\n", anim) { a.anims = animlist(pathfile);
int from, to;
char anim_name[128] = {0};
if( sscanf(anim, "%*s %d-%d %127[^\r\n]", &from, &to, anim_name) != 3) continue;
array_push(a.anims, !!strstri(anim_name, "loop") || !strcmpi(anim_name, "idle") ? loop(from, to, 0, 0) : clip(from, to, 0, 0)); // [from,to,flags]
array_back(a.anims)->name = strswap(strswap(strswap(STRDUP(anim_name), "Loop", ""), "loop", ""), "()", ""); // @leak
}
} else {
// placeholder
array_push(a.anims, clip(0,1,0,0));
array_back(a.anims)->name = STRDUP("Error"); // @leak
}
return a; return a;
} }
@ -374937,6 +374936,8 @@ void object_update(object_t *obj) {
quat p = eulerq(vec3(obj->pivot.x,obj->pivot.y,obj->pivot.z)); quat p = eulerq(vec3(obj->pivot.x,obj->pivot.y,obj->pivot.z));
quat e = eulerq(vec3(obj->euler.x,obj->euler.y,obj->euler.z)); quat e = eulerq(vec3(obj->euler.x,obj->euler.y,obj->euler.z));
compose44(obj->transform, obj->pos, mulq(e, p), obj->sca); compose44(obj->transform, obj->pos, mulq(e, p), obj->sca);
} }
object_t object() { object_t object() {
@ -374986,6 +374987,11 @@ void object_model(object_t *obj, model_t model) {
obj->model = model; obj->model = model;
} }
void object_anim(object_t *obj, anim_t anim, float speed) {
obj->anim = anim;
obj->anim_speed = speed;
}
void object_push_diffuse(object_t *obj, texture_t tex) { void object_push_diffuse(object_t *obj, texture_t tex) {
array_push(obj->textures, tex.id); array_push(obj->textures, tex.id);
} }
@ -375253,6 +375259,7 @@ void scene_render(int flags) {
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) { for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j); object_t *obj = scene_index(j);
model_t *model = &obj->model; model_t *model = &obj->model;
anim_t *anim = &obj->anim;
mat44 *views = (mat44*)(&cam->view); mat44 *views = (mat44*)(&cam->view);
// @todo: avoid heap allocs here? // @todo: avoid heap allocs here?
@ -375277,6 +375284,11 @@ void scene_render(int flags) {
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh); shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
} }
if (anim) {
float delta = window_delta() * obj->anim_speed;
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
}
model->billboard = obj->billboard; model->billboard = obj->billboard;
model_render(*model, cam->proj, cam->view, obj->transform, 0); model_render(*model, cam->proj, cam->view, obj->transform, 0);

View File

@ -1501,7 +1501,7 @@ in vec4 instanceGlyph;\n\
uniform sampler2D sampler_font;\n\ uniform sampler2D sampler_font;\n\
uniform sampler2D sampler_meta;\n\ uniform sampler2D sampler_meta;\n\
\n\ \n\
uniform float offset_firstline; // ascent - descent - linegap/2\n\ uniform float offset_firstline; // ascent\n\
uniform float scale_factor; // scaling factor proportional to font size\n\ uniform float scale_factor; // scaling factor proportional to font size\n\
uniform vec2 string_offset; // offset of upper-left corner\n\ uniform vec2 string_offset; // offset of upper-left corner\n\
\n\ \n\
@ -1666,6 +1666,20 @@ void ui_font() {
} }
} }
void font_scale(const char *tag, int s, float v) {
font_init();
if (s < 0 || s >= 10) return;
unsigned index = *tag - FONT_FACE1[0];
if( index > FONTS_MAX ) return;
font_t *f = &fonts[index];
if (!f->initialized) return;
f->scale[s] = v / f->font_size;
}
void font_scales(const char *tag, float h1, float h2, float h3, float h4, float h5, float h6) { void font_scales(const char *tag, float h1, float h2, float h3, float h4, float h5, float h6) {
font_init(); font_init();
@ -2048,7 +2062,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
font_t *f = &fonts[0]; font_t *f = &fonts[0];
int S = 3; int S = 3;
uint32_t color = 0; uint32_t color = 0;
float X = 0, Y = 0, W = 0, L = f->ascent*f->factor*f->scale[S], LL = L; // LL=largest linedist float X = 0, Y = 0, W = 0, L = f->ascent*f->factor*f->scale[S], LL = 0; // LL=largest linedist
offset.y = -offset.y; // invert y polarity offset.y = -offset.y; // invert y polarity
// utf8 to utf32 // utf8 to utf32
@ -2080,6 +2094,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
// change size // change size
S = ch; S = ch;
//@hack: use descent when we use >H4
L = f->ascent*f->factor*f->scale[S]; L = f->ascent*f->factor*f->scale[S];
if(L > LL) LL = L; if(L > LL) LL = L;
continue; continue;
@ -2096,10 +2111,27 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
// change face // change face
f = &fonts[ ch - 0x10 ]; f = &fonts[ ch - 0x10 ];
L = f->ascent*f->factor*f->scale[S];
if(L > LL) LL = L;
} }
continue; continue;
} }
if (!LL)
LL = L;
if (ch == FONT_LEFT[0] && (
(unicode[i+1]) == FONT_LEFT[1] ||
(unicode[i+1]) == FONT_CENTER[1] ||
(unicode[i+1]) == FONT_RIGHT[1] ||
(unicode[i+1]) == FONT_TOP[1] ||
(unicode[i+1]) == FONT_MIDDLE[1] ||
(unicode[i+1]) == FONT_BASELINE[1] ||
(unicode[i+1]) == FONT_BOTTOM[1]
)) {
continue;
}
// convert to vbo data // convert to vbo data
int cp = ch - f->begin; // f->cp2iter[ch - f->begin]; int cp = ch - f->begin; // f->cp2iter[ch - f->begin];
//if(cp == 0xFFFD) continue; //if(cp == 0xFFFD) continue;
@ -2354,25 +2386,25 @@ void font_goto(float x, float y) {
} }
// Print and linefeed. Text may include markup code // Print and linefeed. Text may include markup code
vec2 font_print(const char *text) { vec2 font_print_rect(const char *text, vec4 rect) {
// @fixme: remove this hack // @fixme: remove this hack
if( text[0] == FONT_LEFT[0] ) { if( text[0] == FONT_LEFT[0] ) {
int l = text[1] == FONT_LEFT[1]; int l = text[1] == FONT_LEFT[1];
int c = text[1] == FONT_CENTER[1]; int c = text[1] == FONT_CENTER[1];
int r = text[1] == FONT_RIGHT[1]; int r = text[1] == FONT_RIGHT[1];
if( l || c || r ) { if( l || c || r ) {
vec2 rect = font_rect(text + 2); vec2 text_rect = font_rect(text + 2);
gotoxy.x = l ? 0 : r ? (window_width() - rect.x) : window_width()/2 - rect.x/2; gotoxy.x = l ? rect.x : r ? ((rect.x+rect.z) - text_rect.x) : rect.x+rect.z/2. - text_rect.x/2.;
return font_print(text + 2); return font_print_rect(text + 2, rect);
} }
int t = text[1] == FONT_TOP[1]; int t = text[1] == FONT_TOP[1];
int b = text[1] == FONT_BOTTOM[1]; int b = text[1] == FONT_BOTTOM[1];
int m = text[1] == FONT_MIDDLE[1]; int m = text[1] == FONT_MIDDLE[1];
int B = text[1] == FONT_BASELINE[1]; int B = text[1] == FONT_BASELINE[1];
if( t || b || m || B ) { if( t || b || m || B ) {
vec2 rect = font_rect(text + 2); vec2 text_rect = font_rect(text + 2);
gotoxy.y = t ? 0 : b ? (window_height() - rect.y) : m ? window_height()/2-rect.y/2 : window_height()/2-rect.y/1; gotoxy.y = t ? rect.y : b ? ((rect.y+rect.w) - text_rect.y) : m ? rect.y+rect.w/2.-text_rect.y/2. : rect.y+rect.w/2.-text_rect.y/1;
return font_print(text + 2); return font_print_rect(text + 2, rect);
} }
} }
@ -2382,6 +2414,11 @@ vec2 font_print(const char *text) {
return dims; return dims;
} }
vec2 font_print(const char *text) {
vec4 dims = {0, 0, window_width(), window_height()};
return font_print_rect(text, dims);
}
// Print a code snippet with syntax highlighting // Print a code snippet with syntax highlighting
vec2 font_highlight(const char *text, const void *colors) { vec2 font_highlight(const char *text, const void *colors) {
vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd); vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd);

View File

@ -73,13 +73,14 @@ enum FONT_FLAGS {
typedef struct font_metrics_t { typedef struct font_metrics_t {
float ascent; // max distance above baseline for all glyphs float ascent; // max distance above baseline for all glyphs
float descent; // max distance below baseline for all glyphs float descent; // max distance below baseline for all glyphs
float linegap; // distance betwen ascent of next line and descent of current line float linegap; // distance between ascent of next line and descent of current line
float linedist; // distance between the baseline of two lines (ascent - descent + linegap) float linedist; // distance between the baseline of two lines (ascent - descent + linegap)
} font_metrics_t; } font_metrics_t;
// configures // configures
API void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags); API void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags);
API void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags); API void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags);
API void font_scale(const char *face_tag, int scale_index, float value);
API void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6); API void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6);
API void font_color(const char *color_tag, uint32_t color); API void font_color(const char *color_tag, uint32_t color);
@ -87,6 +88,7 @@ API void font_color(const char *color_tag, uint32_t color);
API vec2 font_xy(); API vec2 font_xy();
API void font_goto(float x, float y); API void font_goto(float x, float y);
API vec2 font_print(const char *text); API vec2 font_print(const char *text);
API vec2 font_print_rect(const char *text, vec4 rect);
API vec2 font_rect(const char *text); API vec2 font_rect(const char *text);
API font_metrics_t font_metrics(const char *text); API font_metrics_t font_metrics(const char *text);
// void font_clip(vec2 topleft, vec2 bottomright); // void font_clip(vec2 topleft, vec2 bottomright);

View File

@ -2797,37 +2797,12 @@ typedef struct iqm_t {
vec4 *colormaps; vec4 *colormaps;
} iqm_t; } iqm_t;
#define meshdata (q->meshdata)
#define animdata (q->animdata)
#define nummeshes (q->nummeshes)
#define numtris (q->numtris)
#define numverts (q->numverts)
#define numjoints (q->numjoints)
#define numframes (q->numframes)
#define numanims (q->numanims)
#define meshes (q->meshes)
#define textures (q->textures)
#define joints (q->joints)
#define poses (q->poses)
#define anims (q->anims)
#define baseframe (q->baseframe)
#define inversebaseframe (q->inversebaseframe)
#define outframe (q->outframe)
#define frames (q->frames)
#define vao (q->vao)
#define ibo (q->ibo)
#define vbo (q->vbo)
#define bonematsoffset (q->bonematsoffset)
#define buf (q->buf)
#define bounds (q->bounds)
#define colormaps (q->colormaps)
void model_set_texture(model_t m, texture_t t) { void model_set_texture(model_t m, texture_t t) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
for( int i = 0; i < nummeshes; ++i) { // assume 1 texture per mesh for( int i = 0; i < q->nummeshes; ++i) { // assume 1 texture per mesh
textures[i] = t.id; q->textures[i] = t.id;
} }
} }
@ -2920,9 +2895,9 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
if ((loc = glGetUniformLocation(shader, "proj")) >= 0) { if ((loc = glGetUniformLocation(shader, "proj")) >= 0) {
glUniformMatrix4fv(loc, 1, GL_FALSE, proj); glUniformMatrix4fv(loc, 1, GL_FALSE, proj);
} }
if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, numanims ? GL_TRUE : GL_FALSE); if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, q->numanims ? GL_TRUE : GL_FALSE);
if( numanims ) if( q->numanims )
if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, numjoints, GL_FALSE, outframe[0]); if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, q->numjoints, GL_FALSE, q->outframe[0]);
if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) { if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) {
glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE); glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE);
@ -2933,10 +2908,10 @@ void model_set_state(model_t m) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
glBindVertexArray( vao ); glBindVertexArray( q->vao );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, q->vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, position) ); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, position) );
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord) ); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord) );
@ -2957,7 +2932,7 @@ void model_set_state(model_t m) {
glEnableVertexAttribArray(12); glEnableVertexAttribArray(12);
// animation // animation
if(numframes > 0) { if(q->numframes > 0) {
glVertexAttribPointer( 8, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) ); glVertexAttribPointer( 8, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) );
glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) ); glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) );
glVertexAttribPointer(10, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) ); glVertexAttribPointer(10, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) );
@ -2998,71 +2973,71 @@ void model_set_state(model_t m) {
static static
bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
if(meshdata) return false; if(q->meshdata) return false;
lil32p(&buf[hdr->ofs_vertexarrays], hdr->num_vertexarrays*sizeof(struct iqmvertexarray)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_vertexarrays], hdr->num_vertexarrays*sizeof(struct iqmvertexarray)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_triangles], hdr->num_triangles*sizeof(struct iqmtriangle)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_triangles], hdr->num_triangles*sizeof(struct iqmtriangle)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_meshes], hdr->num_meshes*sizeof(struct iqmmesh)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_meshes], hdr->num_meshes*sizeof(struct iqmmesh)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t));
meshdata = buf; q->meshdata = q->buf;
nummeshes = hdr->num_meshes; q->nummeshes = hdr->num_meshes;
numtris = hdr->num_triangles; q->numtris = hdr->num_triangles;
numverts = hdr->num_vertexes; q->numverts = hdr->num_vertexes;
numjoints = hdr->num_joints; q->numjoints = hdr->num_joints;
outframe = CALLOC(hdr->num_joints, sizeof(mat34)); q->outframe = CALLOC(hdr->num_joints, sizeof(mat34));
float *inposition = NULL, *innormal = NULL, *intangent = NULL, *intexcoord = NULL, *invertexindex = NULL; float *inposition = NULL, *innormal = NULL, *intangent = NULL, *intexcoord = NULL, *invertexindex = NULL;
uint8_t *inblendindex8 = NULL, *inblendweight8 = NULL; uint8_t *inblendindex8 = NULL, *inblendweight8 = NULL;
int *inblendindexi = NULL; float *inblendweightf = NULL; int *inblendindexi = NULL; float *inblendweightf = NULL;
uint8_t *invertexcolor8 = NULL; uint8_t *invertexcolor8 = NULL;
struct iqmvertexarray *vas = (struct iqmvertexarray *)&buf[hdr->ofs_vertexarrays]; struct iqmvertexarray *vas = (struct iqmvertexarray *)&q->buf[hdr->ofs_vertexarrays];
for(int i = 0; i < (int)hdr->num_vertexarrays; i++) { for(int i = 0; i < (int)hdr->num_vertexarrays; i++) {
struct iqmvertexarray *va = &vas[i]; struct iqmvertexarray *va = &vas[i];
switch(va->type) { switch(va->type) {
default: continue; // return PANIC("unknown iqm vertex type (%d)", va->type), false; default: continue; // return PANIC("unknown iqm vertex type (%d)", va->type), false;
break; case IQM_POSITION: ASSERT(va->format == IQM_FLOAT && va->size == 3); inposition = (float *)&buf[va->offset]; lil32pf(inposition, 3*hdr->num_vertexes); break; case IQM_POSITION: ASSERT(va->format == IQM_FLOAT && va->size == 3); inposition = (float *)&q->buf[va->offset]; lil32pf(inposition, 3*hdr->num_vertexes);
break; case IQM_NORMAL: ASSERT(va->format == IQM_FLOAT && va->size == 3); innormal = (float *)&buf[va->offset]; lil32pf(innormal, 3*hdr->num_vertexes); break; case IQM_NORMAL: ASSERT(va->format == IQM_FLOAT && va->size == 3); innormal = (float *)&q->buf[va->offset]; lil32pf(innormal, 3*hdr->num_vertexes);
break; case IQM_TANGENT: ASSERT(va->format == IQM_FLOAT && va->size == 4); intangent = (float *)&buf[va->offset]; lil32pf(intangent, 4*hdr->num_vertexes); break; case IQM_TANGENT: ASSERT(va->format == IQM_FLOAT && va->size == 4); intangent = (float *)&q->buf[va->offset]; lil32pf(intangent, 4*hdr->num_vertexes);
break; case IQM_TEXCOORD: ASSERT(va->format == IQM_FLOAT && va->size == 2); intexcoord = (float *)&buf[va->offset]; lil32pf(intexcoord, 2*hdr->num_vertexes); break; case IQM_TEXCOORD: ASSERT(va->format == IQM_FLOAT && va->size == 2); intexcoord = (float *)&q->buf[va->offset]; lil32pf(intexcoord, 2*hdr->num_vertexes);
break; case IQM_COLOR: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE); invertexcolor8 = (uint8_t *)&buf[va->offset]; break; case IQM_COLOR: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE); invertexcolor8 = (uint8_t *)&q->buf[va->offset];
break; case IQM_BLENDINDEXES: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_INT); break; case IQM_BLENDINDEXES: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_INT);
if(va->format == IQM_UBYTE) inblendindex8 = (uint8_t *)&buf[va->offset]; if(va->format == IQM_UBYTE) inblendindex8 = (uint8_t *)&q->buf[va->offset];
else inblendindexi = (int *)&buf[va->offset]; else inblendindexi = (int *)&q->buf[va->offset];
break; case IQM_BLENDWEIGHTS: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_FLOAT); break; case IQM_BLENDWEIGHTS: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_FLOAT);
if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&buf[va->offset]; if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&q->buf[va->offset];
else inblendweightf = (float *)&buf[va->offset]; else inblendweightf = (float *)&q->buf[va->offset];
invertexindex = (inblendweight8 ? (float*)(inblendweight8 + 4) : inblendweightf + 4 ); invertexindex = (inblendweight8 ? (float*)(inblendweight8 + 4) : inblendweightf + 4 );
} }
} }
if (hdr->ofs_bounds) lil32p(buf + hdr->ofs_bounds, hdr->num_frames * sizeof(struct iqmbounds)); if (hdr->ofs_bounds) lil32p(q->buf + hdr->ofs_bounds, hdr->num_frames * sizeof(struct iqmbounds));
if (hdr->ofs_bounds) bounds = (struct iqmbounds *) &buf[hdr->ofs_bounds]; if (hdr->ofs_bounds) q->bounds = (struct iqmbounds *) &q->buf[hdr->ofs_bounds];
meshes = (struct iqmmesh *)&buf[hdr->ofs_meshes]; q->meshes = (struct iqmmesh *)&q->buf[hdr->ofs_meshes];
joints = (struct iqmjoint *)&buf[hdr->ofs_joints]; q->joints = (struct iqmjoint *)&q->buf[hdr->ofs_joints];
baseframe = CALLOC(hdr->num_joints, sizeof(mat34)); q->baseframe = CALLOC(hdr->num_joints, sizeof(mat34));
inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34)); q->inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34));
for(int i = 0; i < (int)hdr->num_joints; i++) { for(int i = 0; i < (int)hdr->num_joints; i++) {
struct iqmjoint *j = &joints[i]; struct iqmjoint *j = &q->joints[i];
compose34(baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale)); compose34(q->baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale));
invert34(inversebaseframe[i], baseframe[i]); invert34(q->inversebaseframe[i], q->baseframe[i]);
if(j->parent >= 0) { if(j->parent >= 0) {
multiply34x2(baseframe[i], baseframe[j->parent], baseframe[i]); multiply34x2(q->baseframe[i], q->baseframe[j->parent], q->baseframe[i]);
multiply34(inversebaseframe[i], inversebaseframe[j->parent]); multiply34(q->inversebaseframe[i], q->inversebaseframe[j->parent]);
} }
} }
struct iqmtriangle *tris = (struct iqmtriangle *)&buf[hdr->ofs_triangles]; struct iqmtriangle *tris = (struct iqmtriangle *)&q->buf[hdr->ofs_triangles];
m->num_tris = hdr->num_triangles; m->num_tris = hdr->num_triangles;
m->tris = (void*)tris; m->tris = (void*)tris;
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &q->vao);
glBindVertexArray(vao); glBindVertexArray(q->vao);
if(!ibo) glGenBuffers(1, &ibo); if(!q->ibo) glGenBuffers(1, &q->ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, hdr->num_triangles*sizeof(struct iqmtriangle), tris, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, hdr->num_triangles*sizeof(struct iqmtriangle), tris, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@ -3093,8 +3068,8 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
if(invertexcolor8) memcpy(v->color, &invertexcolor8[i*4], sizeof(v->color)); if(invertexcolor8) memcpy(v->color, &invertexcolor8[i*4], sizeof(v->color));
} }
if(!vbo) glGenBuffers(1, &vbo); if(!q->vbo) glGenBuffers(1, &q->vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, q->vbo);
glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
@ -3115,16 +3090,16 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
m->verts = verts; m->verts = verts;
/*m->verts = 0; FREE(verts);*/ /*m->verts = 0; FREE(verts);*/
textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint));
colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4));
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
textures[i] = invalid; q->textures[i] = invalid;
} }
const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
struct iqmmesh *m = &meshes[i]; struct iqmmesh *m = &q->meshes[i];
PRINTF("loaded mesh: %s\n", &str[m->name]); PRINTF("loaded mesh: %s\n", &str[m->name]);
} }
@ -3133,34 +3108,34 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
static static
bool model_load_anims(iqm_t *q, const struct iqmheader *hdr) { bool model_load_anims(iqm_t *q, const struct iqmheader *hdr) {
if((int)hdr->num_poses != numjoints) return false; if((int)hdr->num_poses != q->numjoints) return false;
if(animdata) { if(q->animdata) {
if(animdata != meshdata) FREE(animdata); if(q->animdata != q->meshdata) FREE(q->animdata);
FREE(frames); FREE(q->frames);
animdata = NULL; q->animdata = NULL;
anims = NULL; q->anims = NULL;
frames = 0; q->frames = 0;
numframes = 0; q->numframes = 0;
numanims = 0; q->numanims = 0;
} }
lil32p(&buf[hdr->ofs_poses], hdr->num_poses*sizeof(struct iqmpose)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_poses], hdr->num_poses*sizeof(struct iqmpose)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_anims], hdr->num_anims*sizeof(struct iqmanim)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_anims], hdr->num_anims*sizeof(struct iqmanim)/sizeof(uint32_t));
lil16p((uint16_t *)&buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels); lil16p((uint16_t *)&q->buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels);
animdata = buf; q->animdata = q->buf;
numanims = hdr->num_anims; q->numanims = hdr->num_anims;
numframes = hdr->num_frames; q->numframes = hdr->num_frames;
anims = (struct iqmanim *)&buf[hdr->ofs_anims]; q->anims = (struct iqmanim *)&q->buf[hdr->ofs_anims];
poses = (struct iqmpose *)&buf[hdr->ofs_poses]; q->poses = (struct iqmpose *)&q->buf[hdr->ofs_poses];
frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34)); q->frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34));
uint16_t *framedata = (uint16_t *)&buf[hdr->ofs_frames]; uint16_t *framedata = (uint16_t *)&q->buf[hdr->ofs_frames];
for(int i = 0; i < (int)hdr->num_frames; i++) { for(int i = 0; i < (int)hdr->num_frames; i++) {
for(int j = 0; j < (int)hdr->num_poses; j++) { for(int j = 0; j < (int)hdr->num_poses; j++) {
struct iqmpose *p = &poses[j]; struct iqmpose *p = &q->poses[j];
quat rotate; quat rotate;
vec3 translate, scale; vec3 translate, scale;
translate.x = p->channeloffset[0]; if(p->mask&0x01) translate.x += *framedata++ * p->channelscale[0]; translate.x = p->channeloffset[0]; if(p->mask&0x01) translate.x += *framedata++ * p->channelscale[0];
@ -3184,16 +3159,16 @@ bool model_load_anims(iqm_t *q, const struct iqmheader *hdr) {
// parentPose * childPose * childInverseBasePose // parentPose * childPose * childInverseBasePose
mat34 m; compose34(m, translate, normq(rotate), scale); mat34 m; compose34(m, translate, normq(rotate), scale);
if(p->parent >= 0) multiply34x3(frames[i*hdr->num_poses + j], baseframe[p->parent], m, inversebaseframe[j]); if(p->parent >= 0) multiply34x3(q->frames[i*hdr->num_poses + j], q->baseframe[p->parent], m, q->inversebaseframe[j]);
else multiply34x2(frames[i*hdr->num_poses + j], m, inversebaseframe[j]); else multiply34x2(q->frames[i*hdr->num_poses + j], m, q->inversebaseframe[j]);
} }
} }
const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; // const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
for(int i = 0; i < (int)hdr->num_anims; i++) { // for(int i = 0; i < (int)hdr->num_anims; i++) {
struct iqmanim *a = &anims[i]; // struct iqmanim *a = &anims[i];
PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]); // PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]);
} // }
return true; return true;
} }
@ -3206,14 +3181,14 @@ static char* strcpy_safe(char *d, const char *s) {
static static
bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model) { bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model) {
textures = textures ? textures : CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); // up to 8 textures per mesh q->textures = q->textures ? q->textures : CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); // up to 8 textures per mesh
colormaps = colormaps ? colormaps : CALLOC(hdr->num_meshes * 8, sizeof(vec4)); // up to 8 colormaps per mesh q->colormaps = q->colormaps ? q->colormaps : CALLOC(hdr->num_meshes * 8, sizeof(vec4)); // up to 8 colormaps per mesh
GLuint *out = textures; GLuint *out = q->textures;
const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
struct iqmmesh *m = &meshes[i]; struct iqmmesh *m = &q->meshes[i];
// reuse texture+material if already decoded // reuse texture+material if already decoded
bool reused = 0; bool reused = 0;
@ -3382,13 +3357,23 @@ model_t model_from_mem(const void *mem, int len, int flags) {
if( !memcmp(hdr.magic, IQM_MAGIC, sizeof(hdr.magic))) { if( !memcmp(hdr.magic, IQM_MAGIC, sizeof(hdr.magic))) {
lil32p(&hdr.version, (sizeof(hdr) - sizeof(hdr.magic))/sizeof(uint32_t)); lil32p(&hdr.version, (sizeof(hdr) - sizeof(hdr.magic))/sizeof(uint32_t));
if(hdr.version == IQM_VERSION) { if(hdr.version == IQM_VERSION) {
buf = CALLOC(hdr.filesize, sizeof(uint8_t)); q->buf = CALLOC(hdr.filesize, sizeof(uint8_t));
memcpy(buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr)); memcpy(q->buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr));
error = 0; error = 0;
if( hdr.num_meshes > 0 && !(flags & MODEL_NO_MESHES) ) error |= !model_load_meshes(q, &hdr, &m); if( hdr.num_meshes > 0 && !(flags & MODEL_NO_MESHES) ) error |= !model_load_meshes(q, &hdr, &m);
if( hdr.num_meshes > 0 && !(flags & MODEL_NO_TEXTURES) ) error |= !model_load_textures(q, &hdr, &m); if( hdr.num_meshes > 0 && !(flags & MODEL_NO_TEXTURES) ) error |= !model_load_textures(q, &hdr, &m);
else {
// setup fallback
material_t mt = {0};
mt.name = "placeholder";
mt.count = 1;
mt.layer[0].color = vec4(1,1,1,1);
mt.layer[0].texture = texture_checker().id;
array_push(m.materials, mt);
}
if( hdr.num_anims > 0 && !(flags & MODEL_NO_ANIMATIONS) ) error |= !model_load_anims(q, &hdr); if( hdr.num_anims > 0 && !(flags & MODEL_NO_ANIMATIONS) ) error |= !model_load_anims(q, &hdr);
if( buf != meshdata && buf != animdata ) FREE(buf); if( q->buf != q->meshdata && q->buf != q->animdata ) FREE(q->buf);
} }
} }
} }
@ -3397,31 +3382,23 @@ model_t model_from_mem(const void *mem, int len, int flags) {
PRINTF("Error: cannot load %s", "model"); PRINTF("Error: cannot load %s", "model");
FREE(q), q = 0; FREE(q), q = 0;
} else { } else {
#undef vao
#undef ibo
#undef vbo
m.vao = q->vao; m.vao = q->vao;
m.ibo = q->ibo; m.ibo = q->ibo;
m.vbo = q->vbo; m.vbo = q->vbo;
m.num_verts = numverts; m.num_verts = q->numverts;
#define vao (q->vao)
#define ibo (q->ibo)
#define vbo (q->vbo)
// m.boxes = bounds; // <@todo // m.boxes = bounds; // <@todo
m.num_meshes = nummeshes; m.num_meshes = q->nummeshes;
m.num_triangles = numtris; m.num_triangles = q->numtris;
m.num_joints = numjoints; m.num_joints = q->numjoints;
//m.num_poses = numposes; //m.num_poses = numposes;
m.num_anims = numanims; m.num_anims = q->numanims;
m.num_frames = numframes; m.num_frames = q->numframes;
m.iqm = q; m.iqm = q;
m.curframe = model_animate(m, 0); m.curframe = model_animate(m, 0);
//m.num_textures = nummeshes; // assume 1 texture only per mesh //m.num_textures = q->nummeshes; // assume 1 texture only per mesh
#undef textures
m.textures = (q->textures); m.textures = (q->textures);
#define textures (q->textures)
m.flags = flags; m.flags = flags;
@ -3445,9 +3422,9 @@ bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out) {
if(!m.iqm) return false; if(!m.iqm) return false;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
if(joint >= numjoints) return false; if(joint >= q->numjoints) return false;
multiply34x2(*out, outframe[joint], baseframe[joint]); multiply34x2(*out, q->outframe[joint], q->baseframe[joint]);
return true; return true;
} }
@ -3458,6 +3435,26 @@ anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags) {
return clip(minframe, maxframe, blendtime, flags | ANIM_LOOP); return clip(minframe, maxframe, blendtime, flags | ANIM_LOOP);
} }
array(anim_t) animlist(const char *pathfile) {
anim_t *animlist = 0;
char *anim_file = vfs_read(strendi(pathfile,".txt") ? pathfile : va("%s@animlist.txt", pathfile));
if( anim_file ) {
// deserialize anim
for each_substring(anim_file, "\r\n", anim) {
int from, to;
char anim_name[128] = {0};
if( sscanf(anim, "%*s %d-%d %127[^\r\n]", &from, &to, anim_name) != 3) continue;
array_push(animlist, !!strstri(anim_name, "loop") || !strcmpi(anim_name, "idle") ? loop(from, to, 0, 0) : clip(from, to, 0, 0)); // [from,to,flags]
array_back(animlist)->name = strswap(strswap(strswap(STRDUP(anim_name), "Loop", ""), "loop", ""), "()", ""); // @leak
}
} else {
// placeholder
array_push(animlist, clip(0,1,0,0));
array_back(animlist)->name = STRDUP("Error"); // @leak
}
return animlist;
}
static static
void anim_tick(anim_t *p, bool is_primary, float delta) { // delta can be negative (reverses anim) void anim_tick(anim_t *p, bool is_primary, float delta) { // delta can be negative (reverses anim)
if( !is_primary ) p->active = 0; if( !is_primary ) p->active = 0;
@ -3495,18 +3492,18 @@ float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float
unsigned frame4 = secondary->pose.y; unsigned frame4 = secondary->pose.y;
float alphaB = secondary->pose.z; float alphaB = secondary->pose.z;
mat34 *mat1 = &frames[frame1 * numjoints]; mat34 *mat1 = &q->frames[frame1 * q->numjoints];
mat34 *mat2 = &frames[frame2 * numjoints]; mat34 *mat2 = &q->frames[frame2 * q->numjoints];
mat34 *mat3 = &frames[frame3 * numjoints]; mat34 *mat3 = &q->frames[frame3 * q->numjoints];
mat34 *mat4 = &frames[frame4 * numjoints]; mat34 *mat4 = &q->frames[frame4 * q->numjoints];
for(int i = 0; i < numjoints; i++) { for(int i = 0; i < q->numjoints; i++) {
mat34 matA, matB, matF; mat34 matA, matB, matF;
lerp34(matA, mat1[i], mat2[i], alphaA); lerp34(matA, mat1[i], mat2[i], alphaA);
lerp34(matB, mat3[i], mat4[i], alphaB); lerp34(matB, mat3[i], mat4[i], alphaB);
lerp34(matF, matA, matB, alpha ); lerp34(matF, matA, matB, alpha );
if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], matF); if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], matF);
else copy34(outframe[i], matF); else copy34(q->outframe[i], matF);
} }
return frame1 + alpha; return frame1 + alpha;
@ -3541,20 +3538,20 @@ float model_animate_clip(model_t m, float curframe, int minframe, int maxframe,
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
float retframe = -1; float retframe = -1;
if( numframes > 0 ) { if( q->numframes > 0 ) {
vec3 p = pose(curframe >= m.curframe, curframe, minframe, maxframe, loop, &retframe); vec3 p = pose(curframe >= m.curframe, curframe, minframe, maxframe, loop, &retframe);
int frame1 = p.x; int frame1 = p.x;
int frame2 = p.y; int frame2 = p.y;
float offset = p.z; float offset = p.z;
mat34 *mat1 = &frames[frame1 * numjoints]; mat34 *mat1 = &q->frames[frame1 * q->numjoints];
mat34 *mat2 = &frames[frame2 * numjoints]; mat34 *mat2 = &q->frames[frame2 * q->numjoints];
// @todo: add animation blending and inter-frame blending here // @todo: add animation blending and inter-frame blending here
for(int i = 0; i < numjoints; i++) { for(int i = 0; i < q->numjoints; i++) {
mat34 mat; lerp34(mat, mat1[i], mat2[i], offset); mat34 mat; lerp34(mat, mat1[i], mat2[i], offset);
if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], mat); if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], mat);
else copy34(outframe[i], mat); else copy34(q->outframe[i], mat);
} }
} }
@ -3565,20 +3562,20 @@ void model_render_skeleton(model_t m, mat44 M) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
if(!numjoints) return; if(!q->numjoints) return;
ddraw_ontop_push(true); ddraw_ontop_push(true);
ddraw_color_push(RED); ddraw_color_push(RED);
for( int joint = 0; joint < numjoints; joint++ ) { for( int joint = 0; joint < q->numjoints; joint++ ) {
if( joints[joint].parent < 0) continue; if( q->joints[joint].parent < 0) continue;
// bone space... // bone space...
mat34 f; mat34 f;
model_get_bone_pose(m, joint, &f); model_get_bone_pose(m, joint, &f);
vec3 pos = vec3(f[3],f[7],f[11]); vec3 pos = vec3(f[3],f[7],f[11]);
model_get_bone_pose(m, joints[joint].parent, &f); model_get_bone_pose(m, q->joints[joint].parent, &f);
vec3 src = vec3(f[3],f[7],f[11]); vec3 src = vec3(f[3],f[7],f[11]);
// ...to model space // ...to model space
@ -3606,7 +3603,7 @@ void model_render_skeleton(model_t m, mat44 M) {
float model_animate(model_t m, float curframe) { float model_animate(model_t m, float curframe) {
if(!m.iqm) return -1; if(!m.iqm) return -1;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
return model_animate_clip(m, curframe, 0, numframes-1, true); return model_animate_clip(m, curframe, 0, q->numframes-1, true);
} }
static static
@ -3614,19 +3611,19 @@ void model_draw_call(model_t m, int shader) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
glBindVertexArray( vao ); glBindVertexArray( q->vao );
struct iqmtriangle *tris = NULL; struct iqmtriangle *tris = NULL;
for(int i = 0; i < nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
struct iqmmesh *im = &meshes[i]; struct iqmmesh *im = &q->meshes[i];
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[i] ); glBindTexture(GL_TEXTURE_2D, q->textures[i] );
glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 ); glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 );
int loc; int loc;
if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) {
bool textured = !!textures[i] && textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id;
glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); glUniform1i(loc, textured ? GL_TRUE : GL_FALSE);
if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) {
glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a); glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a);
@ -3686,10 +3683,10 @@ aabb aabb_transform( aabb A, mat44 M ) {
aabb model_aabb(model_t m, mat44 transform) { aabb model_aabb(model_t m, mat44 transform) {
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
if( q && bounds ) { if( q && q->bounds ) {
int f = ( (int)m.curframe ) % (numframes + !numframes); int f = ( (int)m.curframe ) % (q->numframes + !q->numframes);
vec3 bbmin = ptr3(bounds[f].bbmin); vec3 bbmin = ptr3(q->bounds[f].bbmin);
vec3 bbmax = ptr3(bounds[f].bbmax); vec3 bbmax = ptr3(q->bounds[f].bbmax);
return aabb_transform(aabb(bbmin,bbmax), transform); return aabb_transform(aabb(bbmin,bbmax), transform);
} }
return aabb(vec3(0,0,0),vec3(0,0,0)); return aabb(vec3(0,0,0),vec3(0,0,0));
@ -3704,62 +3701,22 @@ void model_destroy(model_t m) {
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh); // if(m.mesh) mesh_destroy(m.mesh);
FREE(outframe); FREE(q->outframe);
FREE(colormaps); FREE(q->colormaps);
FREE(textures); FREE(q->textures);
FREE(baseframe); FREE(q->baseframe);
FREE(inversebaseframe); FREE(q->inversebaseframe);
if(animdata != meshdata) FREE(animdata); if(q->animdata != q->meshdata) FREE(q->animdata);
//FREE(meshdata); //FREE(q->meshdata);
FREE(frames); FREE(q->frames);
FREE(buf); FREE(q->buf);
FREE(q); FREE(q);
} }
#undef program
#undef meshdata
#undef animdata
#undef nummeshes
#undef numtris
#undef numverts
#undef numjoints
#undef numframes
#undef numanims
#undef meshes
#undef textures
#undef joints
#undef poses
#undef anims
#undef baseframe
#undef inversebaseframe
#undef outframe
#undef frames
#undef vao
#undef ibo
#undef vbo
#undef bonematsoffset
#undef buf
#undef bounds
#undef colormaps
anims_t animations(const char *pathfile, int flags) { anims_t animations(const char *pathfile, int flags) {
anims_t a = {0}; anims_t a = {0};
char *anim_file = vfs_read(strendi(pathfile,".txt") ? pathfile : va("%s@animlist.txt", pathfile));
if( anim_file ) {
// deserialize anim
a.speed = 1.0; a.speed = 1.0;
for each_substring(anim_file, "\r\n", anim) { a.anims = animlist(pathfile);
int from, to;
char anim_name[128] = {0};
if( sscanf(anim, "%*s %d-%d %127[^\r\n]", &from, &to, anim_name) != 3) continue;
array_push(a.anims, !!strstri(anim_name, "loop") || !strcmpi(anim_name, "idle") ? loop(from, to, 0, 0) : clip(from, to, 0, 0)); // [from,to,flags]
array_back(a.anims)->name = strswap(strswap(strswap(STRDUP(anim_name), "Loop", ""), "loop", ""), "()", ""); // @leak
}
} else {
// placeholder
array_push(a.anims, clip(0,1,0,0));
array_back(a.anims)->name = STRDUP("Error"); // @leak
}
return a; return a;
} }

View File

@ -492,7 +492,7 @@ typedef struct anim_t {
API anim_t clip(float minframe, float maxframe, float blendtime, unsigned flags); API anim_t clip(float minframe, float maxframe, float blendtime, unsigned flags);
API anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags); API anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags);
//API array(anim_t) animlist(const char *filename); // @todo API array(anim_t) animlist(const char *filename);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// models // models

View File

@ -202,6 +202,8 @@ void object_update(object_t *obj) {
quat p = eulerq(vec3(obj->pivot.x,obj->pivot.y,obj->pivot.z)); quat p = eulerq(vec3(obj->pivot.x,obj->pivot.y,obj->pivot.z));
quat e = eulerq(vec3(obj->euler.x,obj->euler.y,obj->euler.z)); quat e = eulerq(vec3(obj->euler.x,obj->euler.y,obj->euler.z));
compose44(obj->transform, obj->pos, mulq(e, p), obj->sca); compose44(obj->transform, obj->pos, mulq(e, p), obj->sca);
} }
object_t object() { object_t object() {
@ -251,6 +253,11 @@ void object_model(object_t *obj, model_t model) {
obj->model = model; obj->model = model;
} }
void object_anim(object_t *obj, anim_t anim, float speed) {
obj->anim = anim;
obj->anim_speed = speed;
}
void object_push_diffuse(object_t *obj, texture_t tex) { void object_push_diffuse(object_t *obj, texture_t tex) {
array_push(obj->textures, tex.id); array_push(obj->textures, tex.id);
} }
@ -518,6 +525,7 @@ void scene_render(int flags) {
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) { for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j); object_t *obj = scene_index(j);
model_t *model = &obj->model; model_t *model = &obj->model;
anim_t *anim = &obj->anim;
mat44 *views = (mat44*)(&cam->view); mat44 *views = (mat44*)(&cam->view);
// @todo: avoid heap allocs here? // @todo: avoid heap allocs here?
@ -542,6 +550,11 @@ void scene_render(int flags) {
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh); shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
} }
if (anim) {
float delta = window_delta() * obj->anim_speed;
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
}
model->billboard = obj->billboard; model->billboard = obj->billboard;
model_render(*model, cam->proj, cam->view, obj->transform, 0); model_render(*model, cam->proj, cam->view, obj->transform, 0);

View File

@ -43,6 +43,8 @@ typedef struct object_t {
vec3 sca, pos, euler, pivot; vec3 sca, pos, euler, pivot;
array(handle) textures; array(handle) textures;
model_t model; model_t model;
anim_t anim;
float anim_speed;
aabb bounds; aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool light_cached; //< used by scene to update light data bool light_cached; //< used by scene to update light data
@ -57,6 +59,7 @@ API vec3 object_position(object_t *obj);
API void object_scale(object_t *obj, vec3 sca); API void object_scale(object_t *obj, vec3 sca);
// //
API void object_model(object_t *obj, model_t model); API void object_model(object_t *obj, model_t model);
API void object_anim(object_t *obj, anim_t anim, float speed);
API void object_diffuse(object_t *obj, texture_t tex); API void object_diffuse(object_t *obj, texture_t tex);
API void object_diffuse_push(object_t *obj, texture_t tex); API void object_diffuse_push(object_t *obj, texture_t tex);
API void object_diffuse_pop(object_t *obj); API void object_diffuse_pop(object_t *obj);

View File

@ -10199,7 +10199,7 @@ in vec4 instanceGlyph;\n\
uniform sampler2D sampler_font;\n\ uniform sampler2D sampler_font;\n\
uniform sampler2D sampler_meta;\n\ uniform sampler2D sampler_meta;\n\
\n\ \n\
uniform float offset_firstline; // ascent - descent - linegap/2\n\ uniform float offset_firstline; // ascent\n\
uniform float scale_factor; // scaling factor proportional to font size\n\ uniform float scale_factor; // scaling factor proportional to font size\n\
uniform vec2 string_offset; // offset of upper-left corner\n\ uniform vec2 string_offset; // offset of upper-left corner\n\
\n\ \n\
@ -10364,6 +10364,20 @@ void ui_font() {
} }
} }
void font_scale(const char *tag, int s, float v) {
font_init();
if (s < 0 || s >= 10) return;
unsigned index = *tag - FONT_FACE1[0];
if( index > FONTS_MAX ) return;
font_t *f = &fonts[index];
if (!f->initialized) return;
f->scale[s] = v / f->font_size;
}
void font_scales(const char *tag, float h1, float h2, float h3, float h4, float h5, float h6) { void font_scales(const char *tag, float h1, float h2, float h3, float h4, float h5, float h6) {
font_init(); font_init();
@ -10746,7 +10760,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
font_t *f = &fonts[0]; font_t *f = &fonts[0];
int S = 3; int S = 3;
uint32_t color = 0; uint32_t color = 0;
float X = 0, Y = 0, W = 0, L = f->ascent*f->factor*f->scale[S], LL = L; // LL=largest linedist float X = 0, Y = 0, W = 0, L = f->ascent*f->factor*f->scale[S], LL = 0; // LL=largest linedist
offset.y = -offset.y; // invert y polarity offset.y = -offset.y; // invert y polarity
// utf8 to utf32 // utf8 to utf32
@ -10778,6 +10792,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
// change size // change size
S = ch; S = ch;
//@hack: use descent when we use >H4
L = f->ascent*f->factor*f->scale[S]; L = f->ascent*f->factor*f->scale[S];
if(L > LL) LL = L; if(L > LL) LL = L;
continue; continue;
@ -10794,10 +10809,27 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
// change face // change face
f = &fonts[ ch - 0x10 ]; f = &fonts[ ch - 0x10 ];
L = f->ascent*f->factor*f->scale[S];
if(L > LL) LL = L;
} }
continue; continue;
} }
if (!LL)
LL = L;
if (ch == FONT_LEFT[0] && (
(unicode[i+1]) == FONT_LEFT[1] ||
(unicode[i+1]) == FONT_CENTER[1] ||
(unicode[i+1]) == FONT_RIGHT[1] ||
(unicode[i+1]) == FONT_TOP[1] ||
(unicode[i+1]) == FONT_MIDDLE[1] ||
(unicode[i+1]) == FONT_BASELINE[1] ||
(unicode[i+1]) == FONT_BOTTOM[1]
)) {
continue;
}
// convert to vbo data // convert to vbo data
int cp = ch - f->begin; // f->cp2iter[ch - f->begin]; int cp = ch - f->begin; // f->cp2iter[ch - f->begin];
//if(cp == 0xFFFD) continue; //if(cp == 0xFFFD) continue;
@ -11052,25 +11084,25 @@ void font_goto(float x, float y) {
} }
// Print and linefeed. Text may include markup code // Print and linefeed. Text may include markup code
vec2 font_print(const char *text) { vec2 font_print_rect(const char *text, vec4 rect) {
// @fixme: remove this hack // @fixme: remove this hack
if( text[0] == FONT_LEFT[0] ) { if( text[0] == FONT_LEFT[0] ) {
int l = text[1] == FONT_LEFT[1]; int l = text[1] == FONT_LEFT[1];
int c = text[1] == FONT_CENTER[1]; int c = text[1] == FONT_CENTER[1];
int r = text[1] == FONT_RIGHT[1]; int r = text[1] == FONT_RIGHT[1];
if( l || c || r ) { if( l || c || r ) {
vec2 rect = font_rect(text + 2); vec2 text_rect = font_rect(text + 2);
gotoxy.x = l ? 0 : r ? (window_width() - rect.x) : window_width()/2 - rect.x/2; gotoxy.x = l ? rect.x : r ? ((rect.x+rect.z) - text_rect.x) : rect.x+rect.z/2. - text_rect.x/2.;
return font_print(text + 2); return font_print_rect(text + 2, rect);
} }
int t = text[1] == FONT_TOP[1]; int t = text[1] == FONT_TOP[1];
int b = text[1] == FONT_BOTTOM[1]; int b = text[1] == FONT_BOTTOM[1];
int m = text[1] == FONT_MIDDLE[1]; int m = text[1] == FONT_MIDDLE[1];
int B = text[1] == FONT_BASELINE[1]; int B = text[1] == FONT_BASELINE[1];
if( t || b || m || B ) { if( t || b || m || B ) {
vec2 rect = font_rect(text + 2); vec2 text_rect = font_rect(text + 2);
gotoxy.y = t ? 0 : b ? (window_height() - rect.y) : m ? window_height()/2-rect.y/2 : window_height()/2-rect.y/1; gotoxy.y = t ? rect.y : b ? ((rect.y+rect.w) - text_rect.y) : m ? rect.y+rect.w/2.-text_rect.y/2. : rect.y+rect.w/2.-text_rect.y/1;
return font_print(text + 2); return font_print_rect(text + 2, rect);
} }
} }
@ -11080,6 +11112,11 @@ vec2 font_print(const char *text) {
return dims; return dims;
} }
vec2 font_print(const char *text) {
vec4 dims = {0, 0, window_width(), window_height()};
return font_print_rect(text, dims);
}
// Print a code snippet with syntax highlighting // Print a code snippet with syntax highlighting
vec2 font_highlight(const char *text, const void *colors) { vec2 font_highlight(const char *text, const void *colors) {
vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd); vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd);
@ -19843,37 +19880,12 @@ typedef struct iqm_t {
vec4 *colormaps; vec4 *colormaps;
} iqm_t; } iqm_t;
#define meshdata (q->meshdata)
#define animdata (q->animdata)
#define nummeshes (q->nummeshes)
#define numtris (q->numtris)
#define numverts (q->numverts)
#define numjoints (q->numjoints)
#define numframes (q->numframes)
#define numanims (q->numanims)
#define meshes (q->meshes)
#define textures (q->textures)
#define joints (q->joints)
#define poses (q->poses)
#define anims (q->anims)
#define baseframe (q->baseframe)
#define inversebaseframe (q->inversebaseframe)
#define outframe (q->outframe)
#define frames (q->frames)
#define vao (q->vao)
#define ibo (q->ibo)
#define vbo (q->vbo)
#define bonematsoffset (q->bonematsoffset)
#define buf (q->buf)
#define bounds (q->bounds)
#define colormaps (q->colormaps)
void model_set_texture(model_t m, texture_t t) { void model_set_texture(model_t m, texture_t t) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
for( int i = 0; i < nummeshes; ++i) { // assume 1 texture per mesh for( int i = 0; i < q->nummeshes; ++i) { // assume 1 texture per mesh
textures[i] = t.id; q->textures[i] = t.id;
} }
} }
@ -19966,9 +19978,9 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
if ((loc = glGetUniformLocation(shader, "proj")) >= 0) { if ((loc = glGetUniformLocation(shader, "proj")) >= 0) {
glUniformMatrix4fv(loc, 1, GL_FALSE, proj); glUniformMatrix4fv(loc, 1, GL_FALSE, proj);
} }
if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, numanims ? GL_TRUE : GL_FALSE); if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, q->numanims ? GL_TRUE : GL_FALSE);
if( numanims ) if( q->numanims )
if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, numjoints, GL_FALSE, outframe[0]); if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, q->numjoints, GL_FALSE, q->outframe[0]);
if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) { if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) {
glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE); glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE);
@ -19979,10 +19991,10 @@ void model_set_state(model_t m) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
glBindVertexArray( vao ); glBindVertexArray( q->vao );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, q->vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, position) ); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, position) );
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord) ); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord) );
@ -20003,7 +20015,7 @@ void model_set_state(model_t m) {
glEnableVertexAttribArray(12); glEnableVertexAttribArray(12);
// animation // animation
if(numframes > 0) { if(q->numframes > 0) {
glVertexAttribPointer( 8, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) ); glVertexAttribPointer( 8, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) );
glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) ); glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) );
glVertexAttribPointer(10, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) ); glVertexAttribPointer(10, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) );
@ -20044,71 +20056,71 @@ void model_set_state(model_t m) {
static static
bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
if(meshdata) return false; if(q->meshdata) return false;
lil32p(&buf[hdr->ofs_vertexarrays], hdr->num_vertexarrays*sizeof(struct iqmvertexarray)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_vertexarrays], hdr->num_vertexarrays*sizeof(struct iqmvertexarray)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_triangles], hdr->num_triangles*sizeof(struct iqmtriangle)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_triangles], hdr->num_triangles*sizeof(struct iqmtriangle)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_meshes], hdr->num_meshes*sizeof(struct iqmmesh)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_meshes], hdr->num_meshes*sizeof(struct iqmmesh)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t));
meshdata = buf; q->meshdata = q->buf;
nummeshes = hdr->num_meshes; q->nummeshes = hdr->num_meshes;
numtris = hdr->num_triangles; q->numtris = hdr->num_triangles;
numverts = hdr->num_vertexes; q->numverts = hdr->num_vertexes;
numjoints = hdr->num_joints; q->numjoints = hdr->num_joints;
outframe = CALLOC(hdr->num_joints, sizeof(mat34)); q->outframe = CALLOC(hdr->num_joints, sizeof(mat34));
float *inposition = NULL, *innormal = NULL, *intangent = NULL, *intexcoord = NULL, *invertexindex = NULL; float *inposition = NULL, *innormal = NULL, *intangent = NULL, *intexcoord = NULL, *invertexindex = NULL;
uint8_t *inblendindex8 = NULL, *inblendweight8 = NULL; uint8_t *inblendindex8 = NULL, *inblendweight8 = NULL;
int *inblendindexi = NULL; float *inblendweightf = NULL; int *inblendindexi = NULL; float *inblendweightf = NULL;
uint8_t *invertexcolor8 = NULL; uint8_t *invertexcolor8 = NULL;
struct iqmvertexarray *vas = (struct iqmvertexarray *)&buf[hdr->ofs_vertexarrays]; struct iqmvertexarray *vas = (struct iqmvertexarray *)&q->buf[hdr->ofs_vertexarrays];
for(int i = 0; i < (int)hdr->num_vertexarrays; i++) { for(int i = 0; i < (int)hdr->num_vertexarrays; i++) {
struct iqmvertexarray *va = &vas[i]; struct iqmvertexarray *va = &vas[i];
switch(va->type) { switch(va->type) {
default: continue; // return PANIC("unknown iqm vertex type (%d)", va->type), false; default: continue; // return PANIC("unknown iqm vertex type (%d)", va->type), false;
break; case IQM_POSITION: ASSERT(va->format == IQM_FLOAT && va->size == 3); inposition = (float *)&buf[va->offset]; lil32pf(inposition, 3*hdr->num_vertexes); break; case IQM_POSITION: ASSERT(va->format == IQM_FLOAT && va->size == 3); inposition = (float *)&q->buf[va->offset]; lil32pf(inposition, 3*hdr->num_vertexes);
break; case IQM_NORMAL: ASSERT(va->format == IQM_FLOAT && va->size == 3); innormal = (float *)&buf[va->offset]; lil32pf(innormal, 3*hdr->num_vertexes); break; case IQM_NORMAL: ASSERT(va->format == IQM_FLOAT && va->size == 3); innormal = (float *)&q->buf[va->offset]; lil32pf(innormal, 3*hdr->num_vertexes);
break; case IQM_TANGENT: ASSERT(va->format == IQM_FLOAT && va->size == 4); intangent = (float *)&buf[va->offset]; lil32pf(intangent, 4*hdr->num_vertexes); break; case IQM_TANGENT: ASSERT(va->format == IQM_FLOAT && va->size == 4); intangent = (float *)&q->buf[va->offset]; lil32pf(intangent, 4*hdr->num_vertexes);
break; case IQM_TEXCOORD: ASSERT(va->format == IQM_FLOAT && va->size == 2); intexcoord = (float *)&buf[va->offset]; lil32pf(intexcoord, 2*hdr->num_vertexes); break; case IQM_TEXCOORD: ASSERT(va->format == IQM_FLOAT && va->size == 2); intexcoord = (float *)&q->buf[va->offset]; lil32pf(intexcoord, 2*hdr->num_vertexes);
break; case IQM_COLOR: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE); invertexcolor8 = (uint8_t *)&buf[va->offset]; break; case IQM_COLOR: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE); invertexcolor8 = (uint8_t *)&q->buf[va->offset];
break; case IQM_BLENDINDEXES: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_INT); break; case IQM_BLENDINDEXES: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_INT);
if(va->format == IQM_UBYTE) inblendindex8 = (uint8_t *)&buf[va->offset]; if(va->format == IQM_UBYTE) inblendindex8 = (uint8_t *)&q->buf[va->offset];
else inblendindexi = (int *)&buf[va->offset]; else inblendindexi = (int *)&q->buf[va->offset];
break; case IQM_BLENDWEIGHTS: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_FLOAT); break; case IQM_BLENDWEIGHTS: ASSERT(va->size == 4); ASSERT(va->format == IQM_UBYTE || va->format == IQM_FLOAT);
if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&buf[va->offset]; if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&q->buf[va->offset];
else inblendweightf = (float *)&buf[va->offset]; else inblendweightf = (float *)&q->buf[va->offset];
invertexindex = (inblendweight8 ? (float*)(inblendweight8 + 4) : inblendweightf + 4 ); invertexindex = (inblendweight8 ? (float*)(inblendweight8 + 4) : inblendweightf + 4 );
} }
} }
if (hdr->ofs_bounds) lil32p(buf + hdr->ofs_bounds, hdr->num_frames * sizeof(struct iqmbounds)); if (hdr->ofs_bounds) lil32p(q->buf + hdr->ofs_bounds, hdr->num_frames * sizeof(struct iqmbounds));
if (hdr->ofs_bounds) bounds = (struct iqmbounds *) &buf[hdr->ofs_bounds]; if (hdr->ofs_bounds) q->bounds = (struct iqmbounds *) &q->buf[hdr->ofs_bounds];
meshes = (struct iqmmesh *)&buf[hdr->ofs_meshes]; q->meshes = (struct iqmmesh *)&q->buf[hdr->ofs_meshes];
joints = (struct iqmjoint *)&buf[hdr->ofs_joints]; q->joints = (struct iqmjoint *)&q->buf[hdr->ofs_joints];
baseframe = CALLOC(hdr->num_joints, sizeof(mat34)); q->baseframe = CALLOC(hdr->num_joints, sizeof(mat34));
inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34)); q->inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34));
for(int i = 0; i < (int)hdr->num_joints; i++) { for(int i = 0; i < (int)hdr->num_joints; i++) {
struct iqmjoint *j = &joints[i]; struct iqmjoint *j = &q->joints[i];
compose34(baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale)); compose34(q->baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale));
invert34(inversebaseframe[i], baseframe[i]); invert34(q->inversebaseframe[i], q->baseframe[i]);
if(j->parent >= 0) { if(j->parent >= 0) {
multiply34x2(baseframe[i], baseframe[j->parent], baseframe[i]); multiply34x2(q->baseframe[i], q->baseframe[j->parent], q->baseframe[i]);
multiply34(inversebaseframe[i], inversebaseframe[j->parent]); multiply34(q->inversebaseframe[i], q->inversebaseframe[j->parent]);
} }
} }
struct iqmtriangle *tris = (struct iqmtriangle *)&buf[hdr->ofs_triangles]; struct iqmtriangle *tris = (struct iqmtriangle *)&q->buf[hdr->ofs_triangles];
m->num_tris = hdr->num_triangles; m->num_tris = hdr->num_triangles;
m->tris = (void*)tris; m->tris = (void*)tris;
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &q->vao);
glBindVertexArray(vao); glBindVertexArray(q->vao);
if(!ibo) glGenBuffers(1, &ibo); if(!q->ibo) glGenBuffers(1, &q->ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, hdr->num_triangles*sizeof(struct iqmtriangle), tris, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, hdr->num_triangles*sizeof(struct iqmtriangle), tris, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@ -20139,8 +20151,8 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
if(invertexcolor8) memcpy(v->color, &invertexcolor8[i*4], sizeof(v->color)); if(invertexcolor8) memcpy(v->color, &invertexcolor8[i*4], sizeof(v->color));
} }
if(!vbo) glGenBuffers(1, &vbo); if(!q->vbo) glGenBuffers(1, &q->vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, q->vbo);
glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
@ -20161,16 +20173,16 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
m->verts = verts; m->verts = verts;
/*m->verts = 0; FREE(verts);*/ /*m->verts = 0; FREE(verts);*/
textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint));
colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4));
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
textures[i] = invalid; q->textures[i] = invalid;
} }
const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
struct iqmmesh *m = &meshes[i]; struct iqmmesh *m = &q->meshes[i];
PRINTF("loaded mesh: %s\n", &str[m->name]); PRINTF("loaded mesh: %s\n", &str[m->name]);
} }
@ -20179,34 +20191,34 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
static static
bool model_load_anims(iqm_t *q, const struct iqmheader *hdr) { bool model_load_anims(iqm_t *q, const struct iqmheader *hdr) {
if((int)hdr->num_poses != numjoints) return false; if((int)hdr->num_poses != q->numjoints) return false;
if(animdata) { if(q->animdata) {
if(animdata != meshdata) FREE(animdata); if(q->animdata != q->meshdata) FREE(q->animdata);
FREE(frames); FREE(q->frames);
animdata = NULL; q->animdata = NULL;
anims = NULL; q->anims = NULL;
frames = 0; q->frames = 0;
numframes = 0; q->numframes = 0;
numanims = 0; q->numanims = 0;
} }
lil32p(&buf[hdr->ofs_poses], hdr->num_poses*sizeof(struct iqmpose)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_poses], hdr->num_poses*sizeof(struct iqmpose)/sizeof(uint32_t));
lil32p(&buf[hdr->ofs_anims], hdr->num_anims*sizeof(struct iqmanim)/sizeof(uint32_t)); lil32p(&q->buf[hdr->ofs_anims], hdr->num_anims*sizeof(struct iqmanim)/sizeof(uint32_t));
lil16p((uint16_t *)&buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels); lil16p((uint16_t *)&q->buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels);
animdata = buf; q->animdata = q->buf;
numanims = hdr->num_anims; q->numanims = hdr->num_anims;
numframes = hdr->num_frames; q->numframes = hdr->num_frames;
anims = (struct iqmanim *)&buf[hdr->ofs_anims]; q->anims = (struct iqmanim *)&q->buf[hdr->ofs_anims];
poses = (struct iqmpose *)&buf[hdr->ofs_poses]; q->poses = (struct iqmpose *)&q->buf[hdr->ofs_poses];
frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34)); q->frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34));
uint16_t *framedata = (uint16_t *)&buf[hdr->ofs_frames]; uint16_t *framedata = (uint16_t *)&q->buf[hdr->ofs_frames];
for(int i = 0; i < (int)hdr->num_frames; i++) { for(int i = 0; i < (int)hdr->num_frames; i++) {
for(int j = 0; j < (int)hdr->num_poses; j++) { for(int j = 0; j < (int)hdr->num_poses; j++) {
struct iqmpose *p = &poses[j]; struct iqmpose *p = &q->poses[j];
quat rotate; quat rotate;
vec3 translate, scale; vec3 translate, scale;
translate.x = p->channeloffset[0]; if(p->mask&0x01) translate.x += *framedata++ * p->channelscale[0]; translate.x = p->channeloffset[0]; if(p->mask&0x01) translate.x += *framedata++ * p->channelscale[0];
@ -20230,16 +20242,16 @@ bool model_load_anims(iqm_t *q, const struct iqmheader *hdr) {
// parentPose * childPose * childInverseBasePose // parentPose * childPose * childInverseBasePose
mat34 m; compose34(m, translate, normq(rotate), scale); mat34 m; compose34(m, translate, normq(rotate), scale);
if(p->parent >= 0) multiply34x3(frames[i*hdr->num_poses + j], baseframe[p->parent], m, inversebaseframe[j]); if(p->parent >= 0) multiply34x3(q->frames[i*hdr->num_poses + j], q->baseframe[p->parent], m, q->inversebaseframe[j]);
else multiply34x2(frames[i*hdr->num_poses + j], m, inversebaseframe[j]); else multiply34x2(q->frames[i*hdr->num_poses + j], m, q->inversebaseframe[j]);
} }
} }
const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; // const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
for(int i = 0; i < (int)hdr->num_anims; i++) { // for(int i = 0; i < (int)hdr->num_anims; i++) {
struct iqmanim *a = &anims[i]; // struct iqmanim *a = &anims[i];
PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]); // PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]);
} // }
return true; return true;
} }
@ -20252,14 +20264,14 @@ static char* strcpy_safe(char *d, const char *s) {
static static
bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model) { bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model) {
textures = textures ? textures : CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); // up to 8 textures per mesh q->textures = q->textures ? q->textures : CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); // up to 8 textures per mesh
colormaps = colormaps ? colormaps : CALLOC(hdr->num_meshes * 8, sizeof(vec4)); // up to 8 colormaps per mesh q->colormaps = q->colormaps ? q->colormaps : CALLOC(hdr->num_meshes * 8, sizeof(vec4)); // up to 8 colormaps per mesh
GLuint *out = textures; GLuint *out = q->textures;
const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
struct iqmmesh *m = &meshes[i]; struct iqmmesh *m = &q->meshes[i];
// reuse texture+material if already decoded // reuse texture+material if already decoded
bool reused = 0; bool reused = 0;
@ -20428,13 +20440,23 @@ model_t model_from_mem(const void *mem, int len, int flags) {
if( !memcmp(hdr.magic, IQM_MAGIC, sizeof(hdr.magic))) { if( !memcmp(hdr.magic, IQM_MAGIC, sizeof(hdr.magic))) {
lil32p(&hdr.version, (sizeof(hdr) - sizeof(hdr.magic))/sizeof(uint32_t)); lil32p(&hdr.version, (sizeof(hdr) - sizeof(hdr.magic))/sizeof(uint32_t));
if(hdr.version == IQM_VERSION) { if(hdr.version == IQM_VERSION) {
buf = CALLOC(hdr.filesize, sizeof(uint8_t)); q->buf = CALLOC(hdr.filesize, sizeof(uint8_t));
memcpy(buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr)); memcpy(q->buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr));
error = 0; error = 0;
if( hdr.num_meshes > 0 && !(flags & MODEL_NO_MESHES) ) error |= !model_load_meshes(q, &hdr, &m); if( hdr.num_meshes > 0 && !(flags & MODEL_NO_MESHES) ) error |= !model_load_meshes(q, &hdr, &m);
if( hdr.num_meshes > 0 && !(flags & MODEL_NO_TEXTURES) ) error |= !model_load_textures(q, &hdr, &m); if( hdr.num_meshes > 0 && !(flags & MODEL_NO_TEXTURES) ) error |= !model_load_textures(q, &hdr, &m);
else {
// setup fallback
material_t mt = {0};
mt.name = "placeholder";
mt.count = 1;
mt.layer[0].color = vec4(1,1,1,1);
mt.layer[0].texture = texture_checker().id;
array_push(m.materials, mt);
}
if( hdr.num_anims > 0 && !(flags & MODEL_NO_ANIMATIONS) ) error |= !model_load_anims(q, &hdr); if( hdr.num_anims > 0 && !(flags & MODEL_NO_ANIMATIONS) ) error |= !model_load_anims(q, &hdr);
if( buf != meshdata && buf != animdata ) FREE(buf); if( q->buf != q->meshdata && q->buf != q->animdata ) FREE(q->buf);
} }
} }
} }
@ -20443,31 +20465,23 @@ model_t model_from_mem(const void *mem, int len, int flags) {
PRINTF("Error: cannot load %s", "model"); PRINTF("Error: cannot load %s", "model");
FREE(q), q = 0; FREE(q), q = 0;
} else { } else {
#undef vao
#undef ibo
#undef vbo
m.vao = q->vao; m.vao = q->vao;
m.ibo = q->ibo; m.ibo = q->ibo;
m.vbo = q->vbo; m.vbo = q->vbo;
m.num_verts = numverts; m.num_verts = q->numverts;
#define vao (q->vao)
#define ibo (q->ibo)
#define vbo (q->vbo)
// m.boxes = bounds; // <@todo // m.boxes = bounds; // <@todo
m.num_meshes = nummeshes; m.num_meshes = q->nummeshes;
m.num_triangles = numtris; m.num_triangles = q->numtris;
m.num_joints = numjoints; m.num_joints = q->numjoints;
//m.num_poses = numposes; //m.num_poses = numposes;
m.num_anims = numanims; m.num_anims = q->numanims;
m.num_frames = numframes; m.num_frames = q->numframes;
m.iqm = q; m.iqm = q;
m.curframe = model_animate(m, 0); m.curframe = model_animate(m, 0);
//m.num_textures = nummeshes; // assume 1 texture only per mesh //m.num_textures = q->nummeshes; // assume 1 texture only per mesh
#undef textures
m.textures = (q->textures); m.textures = (q->textures);
#define textures (q->textures)
m.flags = flags; m.flags = flags;
@ -20491,9 +20505,9 @@ bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out) {
if(!m.iqm) return false; if(!m.iqm) return false;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
if(joint >= numjoints) return false; if(joint >= q->numjoints) return false;
multiply34x2(*out, outframe[joint], baseframe[joint]); multiply34x2(*out, q->outframe[joint], q->baseframe[joint]);
return true; return true;
} }
@ -20504,6 +20518,26 @@ anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags) {
return clip(minframe, maxframe, blendtime, flags | ANIM_LOOP); return clip(minframe, maxframe, blendtime, flags | ANIM_LOOP);
} }
array(anim_t) animlist(const char *pathfile) {
anim_t *animlist = 0;
char *anim_file = vfs_read(strendi(pathfile,".txt") ? pathfile : va("%s@animlist.txt", pathfile));
if( anim_file ) {
// deserialize anim
for each_substring(anim_file, "\r\n", anim) {
int from, to;
char anim_name[128] = {0};
if( sscanf(anim, "%*s %d-%d %127[^\r\n]", &from, &to, anim_name) != 3) continue;
array_push(animlist, !!strstri(anim_name, "loop") || !strcmpi(anim_name, "idle") ? loop(from, to, 0, 0) : clip(from, to, 0, 0)); // [from,to,flags]
array_back(animlist)->name = strswap(strswap(strswap(STRDUP(anim_name), "Loop", ""), "loop", ""), "()", ""); // @leak
}
} else {
// placeholder
array_push(animlist, clip(0,1,0,0));
array_back(animlist)->name = STRDUP("Error"); // @leak
}
return animlist;
}
static static
void anim_tick(anim_t *p, bool is_primary, float delta) { // delta can be negative (reverses anim) void anim_tick(anim_t *p, bool is_primary, float delta) { // delta can be negative (reverses anim)
if( !is_primary ) p->active = 0; if( !is_primary ) p->active = 0;
@ -20541,18 +20575,18 @@ float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float
unsigned frame4 = secondary->pose.y; unsigned frame4 = secondary->pose.y;
float alphaB = secondary->pose.z; float alphaB = secondary->pose.z;
mat34 *mat1 = &frames[frame1 * numjoints]; mat34 *mat1 = &q->frames[frame1 * q->numjoints];
mat34 *mat2 = &frames[frame2 * numjoints]; mat34 *mat2 = &q->frames[frame2 * q->numjoints];
mat34 *mat3 = &frames[frame3 * numjoints]; mat34 *mat3 = &q->frames[frame3 * q->numjoints];
mat34 *mat4 = &frames[frame4 * numjoints]; mat34 *mat4 = &q->frames[frame4 * q->numjoints];
for(int i = 0; i < numjoints; i++) { for(int i = 0; i < q->numjoints; i++) {
mat34 matA, matB, matF; mat34 matA, matB, matF;
lerp34(matA, mat1[i], mat2[i], alphaA); lerp34(matA, mat1[i], mat2[i], alphaA);
lerp34(matB, mat3[i], mat4[i], alphaB); lerp34(matB, mat3[i], mat4[i], alphaB);
lerp34(matF, matA, matB, alpha ); lerp34(matF, matA, matB, alpha );
if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], matF); if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], matF);
else copy34(outframe[i], matF); else copy34(q->outframe[i], matF);
} }
return frame1 + alpha; return frame1 + alpha;
@ -20587,20 +20621,20 @@ float model_animate_clip(model_t m, float curframe, int minframe, int maxframe,
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
float retframe = -1; float retframe = -1;
if( numframes > 0 ) { if( q->numframes > 0 ) {
vec3 p = pose(curframe >= m.curframe, curframe, minframe, maxframe, loop, &retframe); vec3 p = pose(curframe >= m.curframe, curframe, minframe, maxframe, loop, &retframe);
int frame1 = p.x; int frame1 = p.x;
int frame2 = p.y; int frame2 = p.y;
float offset = p.z; float offset = p.z;
mat34 *mat1 = &frames[frame1 * numjoints]; mat34 *mat1 = &q->frames[frame1 * q->numjoints];
mat34 *mat2 = &frames[frame2 * numjoints]; mat34 *mat2 = &q->frames[frame2 * q->numjoints];
// @todo: add animation blending and inter-frame blending here // @todo: add animation blending and inter-frame blending here
for(int i = 0; i < numjoints; i++) { for(int i = 0; i < q->numjoints; i++) {
mat34 mat; lerp34(mat, mat1[i], mat2[i], offset); mat34 mat; lerp34(mat, mat1[i], mat2[i], offset);
if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], mat); if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], mat);
else copy34(outframe[i], mat); else copy34(q->outframe[i], mat);
} }
} }
@ -20611,20 +20645,20 @@ void model_render_skeleton(model_t m, mat44 M) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
if(!numjoints) return; if(!q->numjoints) return;
ddraw_ontop_push(true); ddraw_ontop_push(true);
ddraw_color_push(RED); ddraw_color_push(RED);
for( int joint = 0; joint < numjoints; joint++ ) { for( int joint = 0; joint < q->numjoints; joint++ ) {
if( joints[joint].parent < 0) continue; if( q->joints[joint].parent < 0) continue;
// bone space... // bone space...
mat34 f; mat34 f;
model_get_bone_pose(m, joint, &f); model_get_bone_pose(m, joint, &f);
vec3 pos = vec3(f[3],f[7],f[11]); vec3 pos = vec3(f[3],f[7],f[11]);
model_get_bone_pose(m, joints[joint].parent, &f); model_get_bone_pose(m, q->joints[joint].parent, &f);
vec3 src = vec3(f[3],f[7],f[11]); vec3 src = vec3(f[3],f[7],f[11]);
// ...to model space // ...to model space
@ -20652,7 +20686,7 @@ void model_render_skeleton(model_t m, mat44 M) {
float model_animate(model_t m, float curframe) { float model_animate(model_t m, float curframe) {
if(!m.iqm) return -1; if(!m.iqm) return -1;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
return model_animate_clip(m, curframe, 0, numframes-1, true); return model_animate_clip(m, curframe, 0, q->numframes-1, true);
} }
static static
@ -20660,19 +20694,19 @@ void model_draw_call(model_t m, int shader) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
glBindVertexArray( vao ); glBindVertexArray( q->vao );
struct iqmtriangle *tris = NULL; struct iqmtriangle *tris = NULL;
for(int i = 0; i < nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
struct iqmmesh *im = &meshes[i]; struct iqmmesh *im = &q->meshes[i];
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[i] ); glBindTexture(GL_TEXTURE_2D, q->textures[i] );
glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 ); glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 );
int loc; int loc;
if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) {
bool textured = !!textures[i] && textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id;
glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); glUniform1i(loc, textured ? GL_TRUE : GL_FALSE);
if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) {
glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a); glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a);
@ -20732,10 +20766,10 @@ aabb aabb_transform( aabb A, mat44 M ) {
aabb model_aabb(model_t m, mat44 transform) { aabb model_aabb(model_t m, mat44 transform) {
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
if( q && bounds ) { if( q && q->bounds ) {
int f = ( (int)m.curframe ) % (numframes + !numframes); int f = ( (int)m.curframe ) % (q->numframes + !q->numframes);
vec3 bbmin = ptr3(bounds[f].bbmin); vec3 bbmin = ptr3(q->bounds[f].bbmin);
vec3 bbmax = ptr3(bounds[f].bbmax); vec3 bbmax = ptr3(q->bounds[f].bbmax);
return aabb_transform(aabb(bbmin,bbmax), transform); return aabb_transform(aabb(bbmin,bbmax), transform);
} }
return aabb(vec3(0,0,0),vec3(0,0,0)); return aabb(vec3(0,0,0),vec3(0,0,0));
@ -20750,62 +20784,22 @@ void model_destroy(model_t m) {
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh); // if(m.mesh) mesh_destroy(m.mesh);
FREE(outframe); FREE(q->outframe);
FREE(colormaps); FREE(q->colormaps);
FREE(textures); FREE(q->textures);
FREE(baseframe); FREE(q->baseframe);
FREE(inversebaseframe); FREE(q->inversebaseframe);
if(animdata != meshdata) FREE(animdata); if(q->animdata != q->meshdata) FREE(q->animdata);
//FREE(meshdata); //FREE(q->meshdata);
FREE(frames); FREE(q->frames);
FREE(buf); FREE(q->buf);
FREE(q); FREE(q);
} }
#undef program
#undef meshdata
#undef animdata
#undef nummeshes
#undef numtris
#undef numverts
#undef numjoints
#undef numframes
#undef numanims
#undef meshes
#undef textures
#undef joints
#undef poses
#undef anims
#undef baseframe
#undef inversebaseframe
#undef outframe
#undef frames
#undef vao
#undef ibo
#undef vbo
#undef bonematsoffset
#undef buf
#undef bounds
#undef colormaps
anims_t animations(const char *pathfile, int flags) { anims_t animations(const char *pathfile, int flags) {
anims_t a = {0}; anims_t a = {0};
char *anim_file = vfs_read(strendi(pathfile,".txt") ? pathfile : va("%s@animlist.txt", pathfile));
if( anim_file ) {
// deserialize anim
a.speed = 1.0; a.speed = 1.0;
for each_substring(anim_file, "\r\n", anim) { a.anims = animlist(pathfile);
int from, to;
char anim_name[128] = {0};
if( sscanf(anim, "%*s %d-%d %127[^\r\n]", &from, &to, anim_name) != 3) continue;
array_push(a.anims, !!strstri(anim_name, "loop") || !strcmpi(anim_name, "idle") ? loop(from, to, 0, 0) : clip(from, to, 0, 0)); // [from,to,flags]
array_back(a.anims)->name = strswap(strswap(strswap(STRDUP(anim_name), "Loop", ""), "loop", ""), "()", ""); // @leak
}
} else {
// placeholder
array_push(a.anims, clip(0,1,0,0));
array_back(a.anims)->name = STRDUP("Error"); // @leak
}
return a; return a;
} }
@ -22083,6 +22077,8 @@ void object_update(object_t *obj) {
quat p = eulerq(vec3(obj->pivot.x,obj->pivot.y,obj->pivot.z)); quat p = eulerq(vec3(obj->pivot.x,obj->pivot.y,obj->pivot.z));
quat e = eulerq(vec3(obj->euler.x,obj->euler.y,obj->euler.z)); quat e = eulerq(vec3(obj->euler.x,obj->euler.y,obj->euler.z));
compose44(obj->transform, obj->pos, mulq(e, p), obj->sca); compose44(obj->transform, obj->pos, mulq(e, p), obj->sca);
} }
object_t object() { object_t object() {
@ -22132,6 +22128,11 @@ void object_model(object_t *obj, model_t model) {
obj->model = model; obj->model = model;
} }
void object_anim(object_t *obj, anim_t anim, float speed) {
obj->anim = anim;
obj->anim_speed = speed;
}
void object_push_diffuse(object_t *obj, texture_t tex) { void object_push_diffuse(object_t *obj, texture_t tex) {
array_push(obj->textures, tex.id); array_push(obj->textures, tex.id);
} }
@ -22399,6 +22400,7 @@ void scene_render(int flags) {
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) { for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j); object_t *obj = scene_index(j);
model_t *model = &obj->model; model_t *model = &obj->model;
anim_t *anim = &obj->anim;
mat44 *views = (mat44*)(&cam->view); mat44 *views = (mat44*)(&cam->view);
// @todo: avoid heap allocs here? // @todo: avoid heap allocs here?
@ -22423,6 +22425,11 @@ void scene_render(int flags) {
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh); shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
} }
if (anim) {
float delta = window_delta() * obj->anim_speed;
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
}
model->billboard = obj->billboard; model->billboard = obj->billboard;
model_render(*model, cam->proj, cam->view, obj->transform, 0); model_render(*model, cam->proj, cam->view, obj->transform, 0);

View File

@ -2197,13 +2197,14 @@ enum FONT_FLAGS {
typedef struct font_metrics_t { typedef struct font_metrics_t {
float ascent; // max distance above baseline for all glyphs float ascent; // max distance above baseline for all glyphs
float descent; // max distance below baseline for all glyphs float descent; // max distance below baseline for all glyphs
float linegap; // distance betwen ascent of next line and descent of current line float linegap; // distance between ascent of next line and descent of current line
float linedist; // distance between the baseline of two lines (ascent - descent + linegap) float linedist; // distance between the baseline of two lines (ascent - descent + linegap)
} font_metrics_t; } font_metrics_t;
// configures // configures
API void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags); API void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags);
API void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags); API void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags);
API void font_scale(const char *face_tag, int scale_index, float value);
API void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6); API void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6);
API void font_color(const char *color_tag, uint32_t color); API void font_color(const char *color_tag, uint32_t color);
@ -2211,6 +2212,7 @@ API void font_color(const char *color_tag, uint32_t color);
API vec2 font_xy(); API vec2 font_xy();
API void font_goto(float x, float y); API void font_goto(float x, float y);
API vec2 font_print(const char *text); API vec2 font_print(const char *text);
API vec2 font_print_rect(const char *text, vec4 rect);
API vec2 font_rect(const char *text); API vec2 font_rect(const char *text);
API font_metrics_t font_metrics(const char *text); API font_metrics_t font_metrics(const char *text);
// void font_clip(vec2 topleft, vec2 bottomright); // void font_clip(vec2 topleft, vec2 bottomright);
@ -3576,7 +3578,7 @@ typedef struct anim_t {
API anim_t clip(float minframe, float maxframe, float blendtime, unsigned flags); API anim_t clip(float minframe, float maxframe, float blendtime, unsigned flags);
API anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags); API anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags);
//API array(anim_t) animlist(const char *filename); // @todo API array(anim_t) animlist(const char *filename);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// models // models
@ -3856,6 +3858,8 @@ typedef struct object_t {
vec3 sca, pos, euler, pivot; vec3 sca, pos, euler, pivot;
array(handle) textures; array(handle) textures;
model_t model; model_t model;
anim_t anim;
float anim_speed;
aabb bounds; aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool light_cached; //< used by scene to update light data bool light_cached; //< used by scene to update light data
@ -3870,6 +3874,7 @@ API vec3 object_position(object_t *obj);
API void object_scale(object_t *obj, vec3 sca); API void object_scale(object_t *obj, vec3 sca);
// //
API void object_model(object_t *obj, model_t model); API void object_model(object_t *obj, model_t model);
API void object_anim(object_t *obj, anim_t anim, float speed);
API void object_diffuse(object_t *obj, texture_t tex); API void object_diffuse(object_t *obj, texture_t tex);
API void object_diffuse_push(object_t *obj, texture_t tex); API void object_diffuse_push(object_t *obj, texture_t tex);
API void object_diffuse_pop(object_t *obj); API void object_diffuse_pop(object_t *obj);

Binary file not shown.