diff --git a/bind/v4k.lua b/bind/v4k.lua index 96d1284..ddd0dd4 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -674,11 +674,13 @@ typedef struct 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_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_color(const char *color_tag, uint32_t color); vec2 font_xy(); void font_goto(float x, float y); vec2 font_print(const char *text); + vec2 font_print_rect(const char *text, vec4 rect); vec2 font_rect(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); @@ -1295,6 +1297,7 @@ typedef struct anim_t { } anim_t; anim_t clip(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 { MODEL_NO_ANIMATIONS = 1, MODEL_NO_MESHES = 2, @@ -1481,6 +1484,8 @@ typedef struct object_t { vec3 sca, pos, euler, pivot; handle* textures; model_t model; + anim_t anim; + float anim_speed; aabb bounds; unsigned billboard; bool light_cached; @@ -1493,6 +1498,7 @@ typedef struct object_t { vec3 object_position(object_t *obj); void object_scale(object_t *obj, vec3 sca); 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_push(object_t *obj, texture_t tex); void object_diffuse_pop(object_t *obj); diff --git a/demos/01-font.c b/demos/01-font.c index fc73def..b6d5dbb 100644 --- a/demos/01-font.c +++ b/demos/01-font.c @@ -102,14 +102,15 @@ int main() { //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. + font_goto(0, window_height()*3/4.); font_print(FONT_LEFT "left"); font_print(FONT_CENTER "center"); font_print(FONT_RIGHT "right"); - font_print(FONT_TOP FONT_CENTER "top\n"); - font_print(FONT_MIDDLE FONT_RIGHT "middle\n"); - font_print(FONT_BASELINE FONT_RIGHT "baseline\n"); - font_print(FONT_BOTTOM FONT_CENTER "bottom\n"); + font_print(FONT_TOP FONT_CENTER "top"); + font_print(FONT_MIDDLE FONT_RIGHT "middle"); + font_print(FONT_BASELINE FONT_RIGHT "baseline"); + font_print(FONT_BOTTOM FONT_CENTER "bottom"); { vec2 pos = vec2(1290,120); @@ -126,7 +127,7 @@ int main() { { vec2 pos = vec2(830,80); ddraw_push_2d(); - char *txt = "Very iffy global text."; + char *txt = "Very iffy global text."; font_goto(pos.x, pos.y); vec2 size=font_rect(txt); @@ -138,7 +139,19 @@ int main() { { vec2 pos = vec2(830,160); ddraw_push_2d(); - char *txt = FONT_H1 "Very iffy global text."; + char *txt = FONT_H1 "Very iffy global text."; + 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(); + } + + 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); diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index 3fc5227..22c4e6e 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -16130,13 +16130,14 @@ enum FONT_FLAGS { typedef struct font_metrics_t { float ascent; // max distance above 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) } font_metrics_t; // configures 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_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_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 void font_goto(float x, float y); 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 font_metrics_t font_metrics(const char *text); // 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 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 @@ -17789,6 +17791,8 @@ typedef struct object_t { vec3 sca, pos, euler, pivot; array(handle) textures; model_t model; + anim_t anim; + float anim_speed; aabb bounds; unsigned billboard; // [0..7] x(4),y(2),z(1) masks 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_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_push(object_t *obj, texture_t tex); API void object_diffuse_pop(object_t *obj); @@ -363053,7 +363058,7 @@ in vec4 instanceGlyph;\n\ uniform sampler2D sampler_font;\n\ uniform sampler2D sampler_meta;\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 vec2 string_offset; // offset of upper-left corner\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) { 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]; int S = 3; 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 // utf8 to utf32 @@ -363632,6 +363651,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm // change size S = ch; + //@hack: use descent when we use >H4 L = f->ascent*f->factor*f->scale[S]; if(L > LL) LL = L; continue; @@ -363648,10 +363668,27 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm // change face f = &fonts[ ch - 0x10 ]; + L = f->ascent*f->factor*f->scale[S]; + if(L > LL) LL = L; } 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 int cp = ch - f->begin; // f->cp2iter[ch - f->begin]; //if(cp == 0xFFFD) continue; @@ -363906,25 +363943,25 @@ void font_goto(float x, float y) { } // 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 if( text[0] == FONT_LEFT[0] ) { int l = text[1] == FONT_LEFT[1]; int c = text[1] == FONT_CENTER[1]; int r = text[1] == FONT_RIGHT[1]; if( l || c || r ) { - vec2 rect = font_rect(text + 2); - gotoxy.x = l ? 0 : r ? (window_width() - rect.x) : window_width()/2 - rect.x/2; - return font_print(text + 2); + vec2 text_rect = font_rect(text + 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_rect(text + 2, rect); } int t = text[1] == FONT_TOP[1]; int b = text[1] == FONT_BOTTOM[1]; int m = text[1] == FONT_MIDDLE[1]; int B = text[1] == FONT_BASELINE[1]; if( t || b || m || B ) { - vec2 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; - return font_print(text + 2); + vec2 text_rect = font_rect(text + 2); + 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_rect(text + 2, rect); } } @@ -363934,6 +363971,11 @@ vec2 font_print(const char *text) { 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 vec2 font_highlight(const char *text, const void *colors) { vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd); @@ -372697,37 +372739,12 @@ typedef struct iqm_t { vec4 *colormaps; } 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) { if(!m.iqm) return; iqm_t *q = m.iqm; - for( int i = 0; i < nummeshes; ++i) { // assume 1 texture per mesh - textures[i] = t.id; + for( int i = 0; i < q->nummeshes; ++i) { // assume 1 texture per mesh + 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) { glUniformMatrix4fv(loc, 1, GL_FALSE, proj); } - if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, numanims ? GL_TRUE : GL_FALSE); - if( numanims ) - if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, numjoints, GL_FALSE, outframe[0]); + if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, q->numanims ? GL_TRUE : GL_FALSE); + if( q->numanims ) + if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, q->numjoints, GL_FALSE, q->outframe[0]); if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) { 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; iqm_t *q = m.iqm; - glBindVertexArray( vao ); + glBindVertexArray( q->vao ); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo); + glBindBuffer(GL_ARRAY_BUFFER, q->vbo); 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) ); @@ -372857,7 +372874,7 @@ void model_set_state(model_t m) { glEnableVertexAttribArray(12); // 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( 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) ); @@ -372898,71 +372915,71 @@ void model_set_state(model_t m) { static 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(&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(&buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_vertexarrays], hdr->num_vertexarrays*sizeof(struct iqmvertexarray)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_triangles], hdr->num_triangles*sizeof(struct iqmtriangle)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_meshes], hdr->num_meshes*sizeof(struct iqmmesh)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t)); - meshdata = buf; - nummeshes = hdr->num_meshes; - numtris = hdr->num_triangles; - numverts = hdr->num_vertexes; - numjoints = hdr->num_joints; - outframe = CALLOC(hdr->num_joints, sizeof(mat34)); + q->meshdata = q->buf; + q->nummeshes = hdr->num_meshes; + q->numtris = hdr->num_triangles; + q->numverts = hdr->num_vertexes; + q->numjoints = hdr->num_joints; + q->outframe = CALLOC(hdr->num_joints, sizeof(mat34)); float *inposition = NULL, *innormal = NULL, *intangent = NULL, *intexcoord = NULL, *invertexindex = NULL; uint8_t *inblendindex8 = NULL, *inblendweight8 = NULL; int *inblendindexi = NULL; float *inblendweightf = 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++) { struct iqmvertexarray *va = &vas[i]; switch(va->type) { 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_NORMAL: ASSERT(va->format == IQM_FLOAT && va->size == 3); innormal = (float *)&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_TEXCOORD: ASSERT(va->format == IQM_FLOAT && va->size == 2); intexcoord = (float *)&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_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 *)&q->buf[va->offset]; lil32pf(innormal, 3*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 *)&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 *)&q->buf[va->offset]; 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]; - else inblendindexi = (int *)&buf[va->offset]; + if(va->format == IQM_UBYTE) inblendindex8 = (uint8_t *)&q->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); - if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&buf[va->offset]; - else inblendweightf = (float *)&buf[va->offset]; + if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&q->buf[va->offset]; + else inblendweightf = (float *)&q->buf[va->offset]; 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) bounds = (struct iqmbounds *) &buf[hdr->ofs_bounds]; + if (hdr->ofs_bounds) lil32p(q->buf + hdr->ofs_bounds, hdr->num_frames * sizeof(struct iqmbounds)); + if (hdr->ofs_bounds) q->bounds = (struct iqmbounds *) &q->buf[hdr->ofs_bounds]; - meshes = (struct iqmmesh *)&buf[hdr->ofs_meshes]; - joints = (struct iqmjoint *)&buf[hdr->ofs_joints]; + q->meshes = (struct iqmmesh *)&q->buf[hdr->ofs_meshes]; + q->joints = (struct iqmjoint *)&q->buf[hdr->ofs_joints]; - baseframe = CALLOC(hdr->num_joints, sizeof(mat34)); - inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34)); + q->baseframe = CALLOC(hdr->num_joints, sizeof(mat34)); + q->inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34)); for(int i = 0; i < (int)hdr->num_joints; i++) { - struct iqmjoint *j = &joints[i]; - compose34(baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale)); - invert34(inversebaseframe[i], baseframe[i]); + struct iqmjoint *j = &q->joints[i]; + compose34(q->baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale)); + invert34(q->inversebaseframe[i], q->baseframe[i]); if(j->parent >= 0) { - multiply34x2(baseframe[i], baseframe[j->parent], baseframe[i]); - multiply34(inversebaseframe[i], inversebaseframe[j->parent]); + multiply34x2(q->baseframe[i], q->baseframe[j->parent], q->baseframe[i]); + 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->tris = (void*)tris; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); + glGenVertexArrays(1, &q->vao); + glBindVertexArray(q->vao); - if(!ibo) glGenBuffers(1, &ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + if(!q->ibo) glGenBuffers(1, &q->ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, hdr->num_triangles*sizeof(struct iqmtriangle), tris, GL_STATIC_DRAW); 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(!vbo) glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); + if(!q->vbo) glGenBuffers(1, &q->vbo); + glBindBuffer(GL_ARRAY_BUFFER, q->vbo); glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW); 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 = 0; FREE(verts);*/ - textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); - colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); + q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); + q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); for(int i = 0; i < (int)hdr->num_meshes; i++) { 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++) { - struct iqmmesh *m = &meshes[i]; + struct iqmmesh *m = &q->meshes[i]; 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 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(animdata != meshdata) FREE(animdata); - FREE(frames); - animdata = NULL; - anims = NULL; - frames = 0; - numframes = 0; - numanims = 0; + if(q->animdata) { + if(q->animdata != q->meshdata) FREE(q->animdata); + FREE(q->frames); + q->animdata = NULL; + q->anims = NULL; + q->frames = 0; + q->numframes = 0; + q->numanims = 0; } - lil32p(&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)); - lil16p((uint16_t *)&buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels); + lil32p(&q->buf[hdr->ofs_poses], hdr->num_poses*sizeof(struct iqmpose)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_anims], hdr->num_anims*sizeof(struct iqmanim)/sizeof(uint32_t)); + lil16p((uint16_t *)&q->buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels); - animdata = buf; - numanims = hdr->num_anims; - numframes = hdr->num_frames; + q->animdata = q->buf; + q->numanims = hdr->num_anims; + q->numframes = hdr->num_frames; - anims = (struct iqmanim *)&buf[hdr->ofs_anims]; - poses = (struct iqmpose *)&buf[hdr->ofs_poses]; - frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34)); - uint16_t *framedata = (uint16_t *)&buf[hdr->ofs_frames]; + q->anims = (struct iqmanim *)&q->buf[hdr->ofs_anims]; + q->poses = (struct iqmpose *)&q->buf[hdr->ofs_poses]; + q->frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34)); + uint16_t *framedata = (uint16_t *)&q->buf[hdr->ofs_frames]; for(int i = 0; i < (int)hdr->num_frames; i++) { for(int j = 0; j < (int)hdr->num_poses; j++) { - struct iqmpose *p = &poses[j]; + struct iqmpose *p = &q->poses[j]; quat rotate; vec3 translate, scale; 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 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]); - else multiply34x2(frames[i*hdr->num_poses + j], 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(q->frames[i*hdr->num_poses + j], m, q->inversebaseframe[j]); } } - const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; - for(int i = 0; i < (int)hdr->num_anims; i++) { - struct iqmanim *a = &anims[i]; - PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]); - } + // const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : ""; + // for(int i = 0; i < (int)hdr->num_anims; i++) { + // struct iqmanim *a = &anims[i]; + // PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]); + // } return true; } @@ -373106,14 +373123,14 @@ static char* strcpy_safe(char *d, const char *s) { static 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 - colormaps = colormaps ? colormaps : CALLOC(hdr->num_meshes * 8, sizeof(vec4)); // up to 8 colormaps per mesh + q->textures = q->textures ? q->textures : CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); // up to 8 textures 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++) { - struct iqmmesh *m = &meshes[i]; + struct iqmmesh *m = &q->meshes[i]; // reuse texture+material if already decoded 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))) { lil32p(&hdr.version, (sizeof(hdr) - sizeof(hdr.magic))/sizeof(uint32_t)); if(hdr.version == IQM_VERSION) { - buf = CALLOC(hdr.filesize, sizeof(uint8_t)); - memcpy(buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr)); + q->buf = CALLOC(hdr.filesize, sizeof(uint8_t)); + memcpy(q->buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr)); 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_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( 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"); FREE(q), q = 0; } else { - #undef vao - #undef ibo - #undef vbo m.vao = q->vao; m.ibo = q->ibo; m.vbo = q->vbo; - m.num_verts = numverts; - #define vao (q->vao) - #define ibo (q->ibo) - #define vbo (q->vbo) + m.num_verts = q->numverts; // m.boxes = bounds; // <@todo - m.num_meshes = nummeshes; - m.num_triangles = numtris; - m.num_joints = numjoints; + m.num_meshes = q->nummeshes; + m.num_triangles = q->numtris; + m.num_joints = q->numjoints; //m.num_poses = numposes; - m.num_anims = numanims; - m.num_frames = numframes; + m.num_anims = q->numanims; + m.num_frames = q->numframes; m.iqm = q; m.curframe = model_animate(m, 0); - //m.num_textures = nummeshes; // assume 1 texture only per mesh - #undef textures + //m.num_textures = q->nummeshes; // assume 1 texture only per mesh m.textures = (q->textures); - #define textures (q->textures) m.flags = flags; @@ -373345,9 +373364,9 @@ bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out) { if(!m.iqm) return false; 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; } @@ -373358,6 +373377,26 @@ anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags) { 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 void anim_tick(anim_t *p, bool is_primary, float delta) { // delta can be negative (reverses anim) 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; float alphaB = secondary->pose.z; - mat34 *mat1 = &frames[frame1 * numjoints]; - mat34 *mat2 = &frames[frame2 * numjoints]; - mat34 *mat3 = &frames[frame3 * numjoints]; - mat34 *mat4 = &frames[frame4 * numjoints]; + mat34 *mat1 = &q->frames[frame1 * q->numjoints]; + mat34 *mat2 = &q->frames[frame2 * q->numjoints]; + mat34 *mat3 = &q->frames[frame3 * q->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; lerp34(matA, mat1[i], mat2[i], alphaA); lerp34(matB, mat3[i], mat4[i], alphaB); lerp34(matF, matA, matB, alpha ); - if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], matF); - else copy34(outframe[i], matF); + if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], matF); + else copy34(q->outframe[i], matF); } 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; float retframe = -1; - if( numframes > 0 ) { + if( q->numframes > 0 ) { vec3 p = pose(curframe >= m.curframe, curframe, minframe, maxframe, loop, &retframe); int frame1 = p.x; int frame2 = p.y; float offset = p.z; - mat34 *mat1 = &frames[frame1 * numjoints]; - mat34 *mat2 = &frames[frame2 * numjoints]; + mat34 *mat1 = &q->frames[frame1 * q->numjoints]; + mat34 *mat2 = &q->frames[frame2 * q->numjoints]; // @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); - if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], mat); - else copy34(outframe[i], mat); + if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], mat); + else copy34(q->outframe[i], mat); } } @@ -373465,20 +373504,20 @@ void model_render_skeleton(model_t m, mat44 M) { if(!m.iqm) return; iqm_t *q = m.iqm; - if(!numjoints) return; + if(!q->numjoints) return; ddraw_ontop_push(true); ddraw_color_push(RED); - for( int joint = 0; joint < numjoints; joint++ ) { - if( joints[joint].parent < 0) continue; + for( int joint = 0; joint < q->numjoints; joint++ ) { + if( q->joints[joint].parent < 0) continue; // bone space... mat34 f; model_get_bone_pose(m, joint, &f); 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]); // ...to model space @@ -373506,7 +373545,7 @@ void model_render_skeleton(model_t m, mat44 M) { float model_animate(model_t m, float curframe) { if(!m.iqm) return -1; 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 @@ -373514,19 +373553,19 @@ void model_draw_call(model_t m, int shader) { if(!m.iqm) return; iqm_t *q = m.iqm; - glBindVertexArray( vao ); + glBindVertexArray( q->vao ); struct iqmtriangle *tris = NULL; - for(int i = 0; i < nummeshes; i++) { - struct iqmmesh *im = &meshes[i]; + for(int i = 0; i < q->nummeshes; i++) { + struct iqmmesh *im = &q->meshes[i]; glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textures[i] ); + glBindTexture(GL_TEXTURE_2D, q->textures[i] ); glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 ); int loc; 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); 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); @@ -373586,10 +373625,10 @@ aabb aabb_transform( aabb A, mat44 M ) { aabb model_aabb(model_t m, mat44 transform) { iqm_t *q = m.iqm; - if( q && bounds ) { - int f = ( (int)m.curframe ) % (numframes + !numframes); - vec3 bbmin = ptr3(bounds[f].bbmin); - vec3 bbmax = ptr3(bounds[f].bbmax); + if( q && q->bounds ) { + int f = ( (int)m.curframe ) % (q->numframes + !q->numframes); + vec3 bbmin = ptr3(q->bounds[f].bbmin); + vec3 bbmax = ptr3(q->bounds[f].bbmax); return aabb_transform(aabb(bbmin,bbmax), transform); } 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; // if(m.mesh) mesh_destroy(m.mesh); - FREE(outframe); - FREE(colormaps); - FREE(textures); - FREE(baseframe); - FREE(inversebaseframe); - if(animdata != meshdata) FREE(animdata); - //FREE(meshdata); - FREE(frames); - FREE(buf); + FREE(q->outframe); + FREE(q->colormaps); + FREE(q->textures); + FREE(q->baseframe); + FREE(q->inversebaseframe); + if(q->animdata != q->meshdata) FREE(q->animdata); + //FREE(q->meshdata); + FREE(q->frames); + FREE(q->buf); 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 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; - 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(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 - } + a.speed = 1.0; + a.anims = animlist(pathfile); 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 e = eulerq(vec3(obj->euler.x,obj->euler.y,obj->euler.z)); compose44(obj->transform, obj->pos, mulq(e, p), obj->sca); + + } object_t object() { @@ -374986,6 +374987,11 @@ void object_model(object_t *obj, model_t 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) { 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 ) { object_t *obj = scene_index(j); model_t *model = &obj->model; + anim_t *anim = &obj->anim; mat44 *views = (mat44*)(&cam->view); // @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); } + 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_render(*model, cam->proj, cam->view, obj->transform, 0); diff --git a/engine/split/v4k_font.c b/engine/split/v4k_font.c index a579e91..a425797 100644 --- a/engine/split/v4k_font.c +++ b/engine/split/v4k_font.c @@ -1501,7 +1501,7 @@ in vec4 instanceGlyph;\n\ uniform sampler2D sampler_font;\n\ uniform sampler2D sampler_meta;\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 vec2 string_offset; // offset of upper-left corner\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) { 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]; int S = 3; 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 // utf8 to utf32 @@ -2080,6 +2094,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm // change size S = ch; + //@hack: use descent when we use >H4 L = f->ascent*f->factor*f->scale[S]; if(L > LL) LL = L; continue; @@ -2096,10 +2111,27 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm // change face f = &fonts[ ch - 0x10 ]; + L = f->ascent*f->factor*f->scale[S]; + if(L > LL) LL = L; } 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 int cp = ch - f->begin; // f->cp2iter[ch - f->begin]; //if(cp == 0xFFFD) continue; @@ -2354,25 +2386,25 @@ void font_goto(float x, float y) { } // 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 if( text[0] == FONT_LEFT[0] ) { int l = text[1] == FONT_LEFT[1]; int c = text[1] == FONT_CENTER[1]; int r = text[1] == FONT_RIGHT[1]; if( l || c || r ) { - vec2 rect = font_rect(text + 2); - gotoxy.x = l ? 0 : r ? (window_width() - rect.x) : window_width()/2 - rect.x/2; - return font_print(text + 2); + vec2 text_rect = font_rect(text + 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_rect(text + 2, rect); } int t = text[1] == FONT_TOP[1]; int b = text[1] == FONT_BOTTOM[1]; int m = text[1] == FONT_MIDDLE[1]; int B = text[1] == FONT_BASELINE[1]; if( t || b || m || B ) { - vec2 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; - return font_print(text + 2); + vec2 text_rect = font_rect(text + 2); + 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_rect(text + 2, rect); } } @@ -2382,6 +2414,11 @@ vec2 font_print(const char *text) { 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 vec2 font_highlight(const char *text, const void *colors) { vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd); diff --git a/engine/split/v4k_font.h b/engine/split/v4k_font.h index 16244ca..aafa625 100644 --- a/engine/split/v4k_font.h +++ b/engine/split/v4k_font.h @@ -73,13 +73,14 @@ enum FONT_FLAGS { typedef struct font_metrics_t { float ascent; // max distance above 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) } font_metrics_t; // configures 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_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_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 void font_goto(float x, float y); 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 font_metrics_t font_metrics(const char *text); // void font_clip(vec2 topleft, vec2 bottomright); diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index ff99f58..c8f972b 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -2797,37 +2797,12 @@ typedef struct iqm_t { vec4 *colormaps; } 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) { if(!m.iqm) return; iqm_t *q = m.iqm; - for( int i = 0; i < nummeshes; ++i) { // assume 1 texture per mesh - textures[i] = t.id; + for( int i = 0; i < q->nummeshes; ++i) { // assume 1 texture per mesh + 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) { glUniformMatrix4fv(loc, 1, GL_FALSE, proj); } - if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, numanims ? GL_TRUE : GL_FALSE); - if( numanims ) - if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, numjoints, GL_FALSE, outframe[0]); + if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, q->numanims ? GL_TRUE : GL_FALSE); + if( q->numanims ) + if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, q->numjoints, GL_FALSE, q->outframe[0]); if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) { 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; iqm_t *q = m.iqm; - glBindVertexArray( vao ); + glBindVertexArray( q->vao ); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo); + glBindBuffer(GL_ARRAY_BUFFER, q->vbo); 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) ); @@ -2957,7 +2932,7 @@ void model_set_state(model_t m) { glEnableVertexAttribArray(12); // 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( 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) ); @@ -2998,71 +2973,71 @@ void model_set_state(model_t m) { static 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(&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(&buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_vertexarrays], hdr->num_vertexarrays*sizeof(struct iqmvertexarray)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_triangles], hdr->num_triangles*sizeof(struct iqmtriangle)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_meshes], hdr->num_meshes*sizeof(struct iqmmesh)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t)); - meshdata = buf; - nummeshes = hdr->num_meshes; - numtris = hdr->num_triangles; - numverts = hdr->num_vertexes; - numjoints = hdr->num_joints; - outframe = CALLOC(hdr->num_joints, sizeof(mat34)); + q->meshdata = q->buf; + q->nummeshes = hdr->num_meshes; + q->numtris = hdr->num_triangles; + q->numverts = hdr->num_vertexes; + q->numjoints = hdr->num_joints; + q->outframe = CALLOC(hdr->num_joints, sizeof(mat34)); float *inposition = NULL, *innormal = NULL, *intangent = NULL, *intexcoord = NULL, *invertexindex = NULL; uint8_t *inblendindex8 = NULL, *inblendweight8 = NULL; int *inblendindexi = NULL; float *inblendweightf = 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++) { struct iqmvertexarray *va = &vas[i]; switch(va->type) { 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_NORMAL: ASSERT(va->format == IQM_FLOAT && va->size == 3); innormal = (float *)&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_TEXCOORD: ASSERT(va->format == IQM_FLOAT && va->size == 2); intexcoord = (float *)&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_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 *)&q->buf[va->offset]; lil32pf(innormal, 3*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 *)&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 *)&q->buf[va->offset]; 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]; - else inblendindexi = (int *)&buf[va->offset]; + if(va->format == IQM_UBYTE) inblendindex8 = (uint8_t *)&q->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); - if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&buf[va->offset]; - else inblendweightf = (float *)&buf[va->offset]; + if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&q->buf[va->offset]; + else inblendweightf = (float *)&q->buf[va->offset]; 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) bounds = (struct iqmbounds *) &buf[hdr->ofs_bounds]; + if (hdr->ofs_bounds) lil32p(q->buf + hdr->ofs_bounds, hdr->num_frames * sizeof(struct iqmbounds)); + if (hdr->ofs_bounds) q->bounds = (struct iqmbounds *) &q->buf[hdr->ofs_bounds]; - meshes = (struct iqmmesh *)&buf[hdr->ofs_meshes]; - joints = (struct iqmjoint *)&buf[hdr->ofs_joints]; + q->meshes = (struct iqmmesh *)&q->buf[hdr->ofs_meshes]; + q->joints = (struct iqmjoint *)&q->buf[hdr->ofs_joints]; - baseframe = CALLOC(hdr->num_joints, sizeof(mat34)); - inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34)); + q->baseframe = CALLOC(hdr->num_joints, sizeof(mat34)); + q->inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34)); for(int i = 0; i < (int)hdr->num_joints; i++) { - struct iqmjoint *j = &joints[i]; - compose34(baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale)); - invert34(inversebaseframe[i], baseframe[i]); + struct iqmjoint *j = &q->joints[i]; + compose34(q->baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale)); + invert34(q->inversebaseframe[i], q->baseframe[i]); if(j->parent >= 0) { - multiply34x2(baseframe[i], baseframe[j->parent], baseframe[i]); - multiply34(inversebaseframe[i], inversebaseframe[j->parent]); + multiply34x2(q->baseframe[i], q->baseframe[j->parent], q->baseframe[i]); + 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->tris = (void*)tris; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); + glGenVertexArrays(1, &q->vao); + glBindVertexArray(q->vao); - if(!ibo) glGenBuffers(1, &ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + if(!q->ibo) glGenBuffers(1, &q->ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, hdr->num_triangles*sizeof(struct iqmtriangle), tris, GL_STATIC_DRAW); 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(!vbo) glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); + if(!q->vbo) glGenBuffers(1, &q->vbo); + glBindBuffer(GL_ARRAY_BUFFER, q->vbo); glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW); 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 = 0; FREE(verts);*/ - textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); - colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); + q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); + q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); for(int i = 0; i < (int)hdr->num_meshes; i++) { 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++) { - struct iqmmesh *m = &meshes[i]; + struct iqmmesh *m = &q->meshes[i]; 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 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(animdata != meshdata) FREE(animdata); - FREE(frames); - animdata = NULL; - anims = NULL; - frames = 0; - numframes = 0; - numanims = 0; + if(q->animdata) { + if(q->animdata != q->meshdata) FREE(q->animdata); + FREE(q->frames); + q->animdata = NULL; + q->anims = NULL; + q->frames = 0; + q->numframes = 0; + q->numanims = 0; } - lil32p(&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)); - lil16p((uint16_t *)&buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels); + lil32p(&q->buf[hdr->ofs_poses], hdr->num_poses*sizeof(struct iqmpose)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_anims], hdr->num_anims*sizeof(struct iqmanim)/sizeof(uint32_t)); + lil16p((uint16_t *)&q->buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels); - animdata = buf; - numanims = hdr->num_anims; - numframes = hdr->num_frames; + q->animdata = q->buf; + q->numanims = hdr->num_anims; + q->numframes = hdr->num_frames; - anims = (struct iqmanim *)&buf[hdr->ofs_anims]; - poses = (struct iqmpose *)&buf[hdr->ofs_poses]; - frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34)); - uint16_t *framedata = (uint16_t *)&buf[hdr->ofs_frames]; + q->anims = (struct iqmanim *)&q->buf[hdr->ofs_anims]; + q->poses = (struct iqmpose *)&q->buf[hdr->ofs_poses]; + q->frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34)); + uint16_t *framedata = (uint16_t *)&q->buf[hdr->ofs_frames]; for(int i = 0; i < (int)hdr->num_frames; i++) { for(int j = 0; j < (int)hdr->num_poses; j++) { - struct iqmpose *p = &poses[j]; + struct iqmpose *p = &q->poses[j]; quat rotate; vec3 translate, scale; 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 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]); - else multiply34x2(frames[i*hdr->num_poses + j], 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(q->frames[i*hdr->num_poses + j], m, q->inversebaseframe[j]); } } - const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; - for(int i = 0; i < (int)hdr->num_anims; i++) { - struct iqmanim *a = &anims[i]; - PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]); - } + // const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : ""; + // for(int i = 0; i < (int)hdr->num_anims; i++) { + // struct iqmanim *a = &anims[i]; + // PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]); + // } return true; } @@ -3206,14 +3181,14 @@ static char* strcpy_safe(char *d, const char *s) { static 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 - colormaps = colormaps ? colormaps : CALLOC(hdr->num_meshes * 8, sizeof(vec4)); // up to 8 colormaps per mesh + q->textures = q->textures ? q->textures : CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); // up to 8 textures 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++) { - struct iqmmesh *m = &meshes[i]; + struct iqmmesh *m = &q->meshes[i]; // reuse texture+material if already decoded 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))) { lil32p(&hdr.version, (sizeof(hdr) - sizeof(hdr.magic))/sizeof(uint32_t)); if(hdr.version == IQM_VERSION) { - buf = CALLOC(hdr.filesize, sizeof(uint8_t)); - memcpy(buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr)); + q->buf = CALLOC(hdr.filesize, sizeof(uint8_t)); + memcpy(q->buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr)); 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_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( 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"); FREE(q), q = 0; } else { - #undef vao - #undef ibo - #undef vbo m.vao = q->vao; m.ibo = q->ibo; m.vbo = q->vbo; - m.num_verts = numverts; - #define vao (q->vao) - #define ibo (q->ibo) - #define vbo (q->vbo) + m.num_verts = q->numverts; // m.boxes = bounds; // <@todo - m.num_meshes = nummeshes; - m.num_triangles = numtris; - m.num_joints = numjoints; + m.num_meshes = q->nummeshes; + m.num_triangles = q->numtris; + m.num_joints = q->numjoints; //m.num_poses = numposes; - m.num_anims = numanims; - m.num_frames = numframes; + m.num_anims = q->numanims; + m.num_frames = q->numframes; m.iqm = q; m.curframe = model_animate(m, 0); - //m.num_textures = nummeshes; // assume 1 texture only per mesh - #undef textures + //m.num_textures = q->nummeshes; // assume 1 texture only per mesh m.textures = (q->textures); - #define textures (q->textures) m.flags = flags; @@ -3445,9 +3422,9 @@ bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out) { if(!m.iqm) return false; 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; } @@ -3458,6 +3435,26 @@ anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags) { 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 void anim_tick(anim_t *p, bool is_primary, float delta) { // delta can be negative (reverses anim) 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; float alphaB = secondary->pose.z; - mat34 *mat1 = &frames[frame1 * numjoints]; - mat34 *mat2 = &frames[frame2 * numjoints]; - mat34 *mat3 = &frames[frame3 * numjoints]; - mat34 *mat4 = &frames[frame4 * numjoints]; + mat34 *mat1 = &q->frames[frame1 * q->numjoints]; + mat34 *mat2 = &q->frames[frame2 * q->numjoints]; + mat34 *mat3 = &q->frames[frame3 * q->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; lerp34(matA, mat1[i], mat2[i], alphaA); lerp34(matB, mat3[i], mat4[i], alphaB); lerp34(matF, matA, matB, alpha ); - if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], matF); - else copy34(outframe[i], matF); + if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], matF); + else copy34(q->outframe[i], matF); } 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; float retframe = -1; - if( numframes > 0 ) { + if( q->numframes > 0 ) { vec3 p = pose(curframe >= m.curframe, curframe, minframe, maxframe, loop, &retframe); int frame1 = p.x; int frame2 = p.y; float offset = p.z; - mat34 *mat1 = &frames[frame1 * numjoints]; - mat34 *mat2 = &frames[frame2 * numjoints]; + mat34 *mat1 = &q->frames[frame1 * q->numjoints]; + mat34 *mat2 = &q->frames[frame2 * q->numjoints]; // @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); - if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], mat); - else copy34(outframe[i], mat); + if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], mat); + else copy34(q->outframe[i], mat); } } @@ -3565,20 +3562,20 @@ void model_render_skeleton(model_t m, mat44 M) { if(!m.iqm) return; iqm_t *q = m.iqm; - if(!numjoints) return; + if(!q->numjoints) return; ddraw_ontop_push(true); ddraw_color_push(RED); - for( int joint = 0; joint < numjoints; joint++ ) { - if( joints[joint].parent < 0) continue; + for( int joint = 0; joint < q->numjoints; joint++ ) { + if( q->joints[joint].parent < 0) continue; // bone space... mat34 f; model_get_bone_pose(m, joint, &f); 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]); // ...to model space @@ -3606,7 +3603,7 @@ void model_render_skeleton(model_t m, mat44 M) { float model_animate(model_t m, float curframe) { if(!m.iqm) return -1; 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 @@ -3614,19 +3611,19 @@ void model_draw_call(model_t m, int shader) { if(!m.iqm) return; iqm_t *q = m.iqm; - glBindVertexArray( vao ); + glBindVertexArray( q->vao ); struct iqmtriangle *tris = NULL; - for(int i = 0; i < nummeshes; i++) { - struct iqmmesh *im = &meshes[i]; + for(int i = 0; i < q->nummeshes; i++) { + struct iqmmesh *im = &q->meshes[i]; glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textures[i] ); + glBindTexture(GL_TEXTURE_2D, q->textures[i] ); glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 ); int loc; 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); 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); @@ -3686,10 +3683,10 @@ aabb aabb_transform( aabb A, mat44 M ) { aabb model_aabb(model_t m, mat44 transform) { iqm_t *q = m.iqm; - if( q && bounds ) { - int f = ( (int)m.curframe ) % (numframes + !numframes); - vec3 bbmin = ptr3(bounds[f].bbmin); - vec3 bbmax = ptr3(bounds[f].bbmax); + if( q && q->bounds ) { + int f = ( (int)m.curframe ) % (q->numframes + !q->numframes); + vec3 bbmin = ptr3(q->bounds[f].bbmin); + vec3 bbmax = ptr3(q->bounds[f].bbmax); return aabb_transform(aabb(bbmin,bbmax), transform); } 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; // if(m.mesh) mesh_destroy(m.mesh); - FREE(outframe); - FREE(colormaps); - FREE(textures); - FREE(baseframe); - FREE(inversebaseframe); - if(animdata != meshdata) FREE(animdata); - //FREE(meshdata); - FREE(frames); - FREE(buf); + FREE(q->outframe); + FREE(q->colormaps); + FREE(q->textures); + FREE(q->baseframe); + FREE(q->inversebaseframe); + if(q->animdata != q->meshdata) FREE(q->animdata); + //FREE(q->meshdata); + FREE(q->frames); + FREE(q->buf); 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 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; - 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(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 - } + a.speed = 1.0; + a.anims = animlist(pathfile); return a; } diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h index cb1ed1f..e752d82 100644 --- a/engine/split/v4k_render.h +++ b/engine/split/v4k_render.h @@ -492,7 +492,7 @@ typedef struct anim_t { 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 array(anim_t) animlist(const char *filename); // @todo +API array(anim_t) animlist(const char *filename); // ----------------------------------------------------------------------------- // models diff --git a/engine/split/v4k_scene.c b/engine/split/v4k_scene.c index 0a5aabd..96a417c 100644 --- a/engine/split/v4k_scene.c +++ b/engine/split/v4k_scene.c @@ -202,6 +202,8 @@ void object_update(object_t *obj) { 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)); compose44(obj->transform, obj->pos, mulq(e, p), obj->sca); + + } object_t object() { @@ -251,6 +253,11 @@ void object_model(object_t *obj, model_t 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) { 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 ) { object_t *obj = scene_index(j); model_t *model = &obj->model; + anim_t *anim = &obj->anim; mat44 *views = (mat44*)(&cam->view); // @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); } + 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_render(*model, cam->proj, cam->view, obj->transform, 0); diff --git a/engine/split/v4k_scene.h b/engine/split/v4k_scene.h index d9cf41e..0052f93 100644 --- a/engine/split/v4k_scene.h +++ b/engine/split/v4k_scene.h @@ -43,6 +43,8 @@ typedef struct object_t { vec3 sca, pos, euler, pivot; array(handle) textures; model_t model; + anim_t anim; + float anim_speed; aabb bounds; unsigned billboard; // [0..7] x(4),y(2),z(1) masks 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_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_push(object_t *obj, texture_t tex); API void object_diffuse_pop(object_t *obj); diff --git a/engine/v4k.c b/engine/v4k.c index 2c5ffeb..5b17b0b 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -10199,7 +10199,7 @@ in vec4 instanceGlyph;\n\ uniform sampler2D sampler_font;\n\ uniform sampler2D sampler_meta;\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 vec2 string_offset; // offset of upper-left corner\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) { 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]; int S = 3; 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 // utf8 to utf32 @@ -10778,6 +10792,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm // change size S = ch; + //@hack: use descent when we use >H4 L = f->ascent*f->factor*f->scale[S]; if(L > LL) LL = L; continue; @@ -10794,10 +10809,27 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm // change face f = &fonts[ ch - 0x10 ]; + L = f->ascent*f->factor*f->scale[S]; + if(L > LL) LL = L; } 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 int cp = ch - f->begin; // f->cp2iter[ch - f->begin]; //if(cp == 0xFFFD) continue; @@ -11052,25 +11084,25 @@ void font_goto(float x, float y) { } // 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 if( text[0] == FONT_LEFT[0] ) { int l = text[1] == FONT_LEFT[1]; int c = text[1] == FONT_CENTER[1]; int r = text[1] == FONT_RIGHT[1]; if( l || c || r ) { - vec2 rect = font_rect(text + 2); - gotoxy.x = l ? 0 : r ? (window_width() - rect.x) : window_width()/2 - rect.x/2; - return font_print(text + 2); + vec2 text_rect = font_rect(text + 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_rect(text + 2, rect); } int t = text[1] == FONT_TOP[1]; int b = text[1] == FONT_BOTTOM[1]; int m = text[1] == FONT_MIDDLE[1]; int B = text[1] == FONT_BASELINE[1]; if( t || b || m || B ) { - vec2 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; - return font_print(text + 2); + vec2 text_rect = font_rect(text + 2); + 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_rect(text + 2, rect); } } @@ -11080,6 +11112,11 @@ vec2 font_print(const char *text) { 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 vec2 font_highlight(const char *text, const void *colors) { vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd); @@ -19843,37 +19880,12 @@ typedef struct iqm_t { vec4 *colormaps; } 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) { if(!m.iqm) return; iqm_t *q = m.iqm; - for( int i = 0; i < nummeshes; ++i) { // assume 1 texture per mesh - textures[i] = t.id; + for( int i = 0; i < q->nummeshes; ++i) { // assume 1 texture per mesh + 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) { glUniformMatrix4fv(loc, 1, GL_FALSE, proj); } - if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, numanims ? GL_TRUE : GL_FALSE); - if( numanims ) - if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, numjoints, GL_FALSE, outframe[0]); + if( (loc = glGetUniformLocation(shader, "SKINNED")) >= 0 ) glUniform1i( loc, q->numanims ? GL_TRUE : GL_FALSE); + if( q->numanims ) + if( (loc = glGetUniformLocation(shader, "vsBoneMatrix")) >= 0 ) glUniformMatrix3x4fv( loc, q->numjoints, GL_FALSE, q->outframe[0]); if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) { 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; iqm_t *q = m.iqm; - glBindVertexArray( vao ); + glBindVertexArray( q->vao ); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo); + glBindBuffer(GL_ARRAY_BUFFER, q->vbo); 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) ); @@ -20003,7 +20015,7 @@ void model_set_state(model_t m) { glEnableVertexAttribArray(12); // 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( 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) ); @@ -20044,71 +20056,71 @@ void model_set_state(model_t m) { static 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(&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(&buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_vertexarrays], hdr->num_vertexarrays*sizeof(struct iqmvertexarray)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_triangles], hdr->num_triangles*sizeof(struct iqmtriangle)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_meshes], hdr->num_meshes*sizeof(struct iqmmesh)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_joints], hdr->num_joints*sizeof(struct iqmjoint)/sizeof(uint32_t)); - meshdata = buf; - nummeshes = hdr->num_meshes; - numtris = hdr->num_triangles; - numverts = hdr->num_vertexes; - numjoints = hdr->num_joints; - outframe = CALLOC(hdr->num_joints, sizeof(mat34)); + q->meshdata = q->buf; + q->nummeshes = hdr->num_meshes; + q->numtris = hdr->num_triangles; + q->numverts = hdr->num_vertexes; + q->numjoints = hdr->num_joints; + q->outframe = CALLOC(hdr->num_joints, sizeof(mat34)); float *inposition = NULL, *innormal = NULL, *intangent = NULL, *intexcoord = NULL, *invertexindex = NULL; uint8_t *inblendindex8 = NULL, *inblendweight8 = NULL; int *inblendindexi = NULL; float *inblendweightf = 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++) { struct iqmvertexarray *va = &vas[i]; switch(va->type) { 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_NORMAL: ASSERT(va->format == IQM_FLOAT && va->size == 3); innormal = (float *)&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_TEXCOORD: ASSERT(va->format == IQM_FLOAT && va->size == 2); intexcoord = (float *)&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_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 *)&q->buf[va->offset]; lil32pf(innormal, 3*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 *)&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 *)&q->buf[va->offset]; 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]; - else inblendindexi = (int *)&buf[va->offset]; + if(va->format == IQM_UBYTE) inblendindex8 = (uint8_t *)&q->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); - if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&buf[va->offset]; - else inblendweightf = (float *)&buf[va->offset]; + if(va->format == IQM_UBYTE) inblendweight8 = (uint8_t *)&q->buf[va->offset]; + else inblendweightf = (float *)&q->buf[va->offset]; 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) bounds = (struct iqmbounds *) &buf[hdr->ofs_bounds]; + if (hdr->ofs_bounds) lil32p(q->buf + hdr->ofs_bounds, hdr->num_frames * sizeof(struct iqmbounds)); + if (hdr->ofs_bounds) q->bounds = (struct iqmbounds *) &q->buf[hdr->ofs_bounds]; - meshes = (struct iqmmesh *)&buf[hdr->ofs_meshes]; - joints = (struct iqmjoint *)&buf[hdr->ofs_joints]; + q->meshes = (struct iqmmesh *)&q->buf[hdr->ofs_meshes]; + q->joints = (struct iqmjoint *)&q->buf[hdr->ofs_joints]; - baseframe = CALLOC(hdr->num_joints, sizeof(mat34)); - inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34)); + q->baseframe = CALLOC(hdr->num_joints, sizeof(mat34)); + q->inversebaseframe = CALLOC(hdr->num_joints, sizeof(mat34)); for(int i = 0; i < (int)hdr->num_joints; i++) { - struct iqmjoint *j = &joints[i]; - compose34(baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale)); - invert34(inversebaseframe[i], baseframe[i]); + struct iqmjoint *j = &q->joints[i]; + compose34(q->baseframe[i], ptr3(j->translate), normq(ptrq(j->rotate)), ptr3(j->scale)); + invert34(q->inversebaseframe[i], q->baseframe[i]); if(j->parent >= 0) { - multiply34x2(baseframe[i], baseframe[j->parent], baseframe[i]); - multiply34(inversebaseframe[i], inversebaseframe[j->parent]); + multiply34x2(q->baseframe[i], q->baseframe[j->parent], q->baseframe[i]); + 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->tris = (void*)tris; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); + glGenVertexArrays(1, &q->vao); + glBindVertexArray(q->vao); - if(!ibo) glGenBuffers(1, &ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + if(!q->ibo) glGenBuffers(1, &q->ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, q->ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, hdr->num_triangles*sizeof(struct iqmtriangle), tris, GL_STATIC_DRAW); 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(!vbo) glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); + if(!q->vbo) glGenBuffers(1, &q->vbo); + glBindBuffer(GL_ARRAY_BUFFER, q->vbo); glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW); 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 = 0; FREE(verts);*/ - textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); - colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); + q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); + q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); for(int i = 0; i < (int)hdr->num_meshes; i++) { 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++) { - struct iqmmesh *m = &meshes[i]; + struct iqmmesh *m = &q->meshes[i]; 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 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(animdata != meshdata) FREE(animdata); - FREE(frames); - animdata = NULL; - anims = NULL; - frames = 0; - numframes = 0; - numanims = 0; + if(q->animdata) { + if(q->animdata != q->meshdata) FREE(q->animdata); + FREE(q->frames); + q->animdata = NULL; + q->anims = NULL; + q->frames = 0; + q->numframes = 0; + q->numanims = 0; } - lil32p(&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)); - lil16p((uint16_t *)&buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels); + lil32p(&q->buf[hdr->ofs_poses], hdr->num_poses*sizeof(struct iqmpose)/sizeof(uint32_t)); + lil32p(&q->buf[hdr->ofs_anims], hdr->num_anims*sizeof(struct iqmanim)/sizeof(uint32_t)); + lil16p((uint16_t *)&q->buf[hdr->ofs_frames], hdr->num_frames*hdr->num_framechannels); - animdata = buf; - numanims = hdr->num_anims; - numframes = hdr->num_frames; + q->animdata = q->buf; + q->numanims = hdr->num_anims; + q->numframes = hdr->num_frames; - anims = (struct iqmanim *)&buf[hdr->ofs_anims]; - poses = (struct iqmpose *)&buf[hdr->ofs_poses]; - frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34)); - uint16_t *framedata = (uint16_t *)&buf[hdr->ofs_frames]; + q->anims = (struct iqmanim *)&q->buf[hdr->ofs_anims]; + q->poses = (struct iqmpose *)&q->buf[hdr->ofs_poses]; + q->frames = CALLOC(hdr->num_frames * hdr->num_poses, sizeof(mat34)); + uint16_t *framedata = (uint16_t *)&q->buf[hdr->ofs_frames]; for(int i = 0; i < (int)hdr->num_frames; i++) { for(int j = 0; j < (int)hdr->num_poses; j++) { - struct iqmpose *p = &poses[j]; + struct iqmpose *p = &q->poses[j]; quat rotate; vec3 translate, scale; 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 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]); - else multiply34x2(frames[i*hdr->num_poses + j], 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(q->frames[i*hdr->num_poses + j], m, q->inversebaseframe[j]); } } - const char *str = hdr->ofs_text ? (char *)&buf[hdr->ofs_text] : ""; - for(int i = 0; i < (int)hdr->num_anims; i++) { - struct iqmanim *a = &anims[i]; - PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]); - } + // const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : ""; + // for(int i = 0; i < (int)hdr->num_anims; i++) { + // struct iqmanim *a = &anims[i]; + // PRINTF("loaded anim[%d]: %s\n", i, &str[a->name]); + // } return true; } @@ -20252,14 +20264,14 @@ static char* strcpy_safe(char *d, const char *s) { static 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 - colormaps = colormaps ? colormaps : CALLOC(hdr->num_meshes * 8, sizeof(vec4)); // up to 8 colormaps per mesh + q->textures = q->textures ? q->textures : CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); // up to 8 textures 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++) { - struct iqmmesh *m = &meshes[i]; + struct iqmmesh *m = &q->meshes[i]; // reuse texture+material if already decoded 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))) { lil32p(&hdr.version, (sizeof(hdr) - sizeof(hdr.magic))/sizeof(uint32_t)); if(hdr.version == IQM_VERSION) { - buf = CALLOC(hdr.filesize, sizeof(uint8_t)); - memcpy(buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr)); + q->buf = CALLOC(hdr.filesize, sizeof(uint8_t)); + memcpy(q->buf + sizeof(hdr), ptr, hdr.filesize - sizeof(hdr)); 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_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( 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"); FREE(q), q = 0; } else { - #undef vao - #undef ibo - #undef vbo m.vao = q->vao; m.ibo = q->ibo; m.vbo = q->vbo; - m.num_verts = numverts; - #define vao (q->vao) - #define ibo (q->ibo) - #define vbo (q->vbo) + m.num_verts = q->numverts; // m.boxes = bounds; // <@todo - m.num_meshes = nummeshes; - m.num_triangles = numtris; - m.num_joints = numjoints; + m.num_meshes = q->nummeshes; + m.num_triangles = q->numtris; + m.num_joints = q->numjoints; //m.num_poses = numposes; - m.num_anims = numanims; - m.num_frames = numframes; + m.num_anims = q->numanims; + m.num_frames = q->numframes; m.iqm = q; m.curframe = model_animate(m, 0); - //m.num_textures = nummeshes; // assume 1 texture only per mesh - #undef textures + //m.num_textures = q->nummeshes; // assume 1 texture only per mesh m.textures = (q->textures); - #define textures (q->textures) m.flags = flags; @@ -20491,9 +20505,9 @@ bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out) { if(!m.iqm) return false; 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; } @@ -20504,6 +20518,26 @@ anim_t loop(float minframe, float maxframe, float blendtime, unsigned flags) { 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 void anim_tick(anim_t *p, bool is_primary, float delta) { // delta can be negative (reverses anim) 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; float alphaB = secondary->pose.z; - mat34 *mat1 = &frames[frame1 * numjoints]; - mat34 *mat2 = &frames[frame2 * numjoints]; - mat34 *mat3 = &frames[frame3 * numjoints]; - mat34 *mat4 = &frames[frame4 * numjoints]; + mat34 *mat1 = &q->frames[frame1 * q->numjoints]; + mat34 *mat2 = &q->frames[frame2 * q->numjoints]; + mat34 *mat3 = &q->frames[frame3 * q->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; lerp34(matA, mat1[i], mat2[i], alphaA); lerp34(matB, mat3[i], mat4[i], alphaB); lerp34(matF, matA, matB, alpha ); - if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], matF); - else copy34(outframe[i], matF); + if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], matF); + else copy34(q->outframe[i], matF); } 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; float retframe = -1; - if( numframes > 0 ) { + if( q->numframes > 0 ) { vec3 p = pose(curframe >= m.curframe, curframe, minframe, maxframe, loop, &retframe); int frame1 = p.x; int frame2 = p.y; float offset = p.z; - mat34 *mat1 = &frames[frame1 * numjoints]; - mat34 *mat2 = &frames[frame2 * numjoints]; + mat34 *mat1 = &q->frames[frame1 * q->numjoints]; + mat34 *mat2 = &q->frames[frame2 * q->numjoints]; // @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); - if(joints[i].parent >= 0) multiply34x2(outframe[i], outframe[joints[i].parent], mat); - else copy34(outframe[i], mat); + if(q->joints[i].parent >= 0) multiply34x2(q->outframe[i], q->outframe[q->joints[i].parent], mat); + else copy34(q->outframe[i], mat); } } @@ -20611,20 +20645,20 @@ void model_render_skeleton(model_t m, mat44 M) { if(!m.iqm) return; iqm_t *q = m.iqm; - if(!numjoints) return; + if(!q->numjoints) return; ddraw_ontop_push(true); ddraw_color_push(RED); - for( int joint = 0; joint < numjoints; joint++ ) { - if( joints[joint].parent < 0) continue; + for( int joint = 0; joint < q->numjoints; joint++ ) { + if( q->joints[joint].parent < 0) continue; // bone space... mat34 f; model_get_bone_pose(m, joint, &f); 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]); // ...to model space @@ -20652,7 +20686,7 @@ void model_render_skeleton(model_t m, mat44 M) { float model_animate(model_t m, float curframe) { if(!m.iqm) return -1; 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 @@ -20660,19 +20694,19 @@ void model_draw_call(model_t m, int shader) { if(!m.iqm) return; iqm_t *q = m.iqm; - glBindVertexArray( vao ); + glBindVertexArray( q->vao ); struct iqmtriangle *tris = NULL; - for(int i = 0; i < nummeshes; i++) { - struct iqmmesh *im = &meshes[i]; + for(int i = 0; i < q->nummeshes; i++) { + struct iqmmesh *im = &q->meshes[i]; glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textures[i] ); + glBindTexture(GL_TEXTURE_2D, q->textures[i] ); glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 ); int loc; 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); 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); @@ -20732,10 +20766,10 @@ aabb aabb_transform( aabb A, mat44 M ) { aabb model_aabb(model_t m, mat44 transform) { iqm_t *q = m.iqm; - if( q && bounds ) { - int f = ( (int)m.curframe ) % (numframes + !numframes); - vec3 bbmin = ptr3(bounds[f].bbmin); - vec3 bbmax = ptr3(bounds[f].bbmax); + if( q && q->bounds ) { + int f = ( (int)m.curframe ) % (q->numframes + !q->numframes); + vec3 bbmin = ptr3(q->bounds[f].bbmin); + vec3 bbmax = ptr3(q->bounds[f].bbmax); return aabb_transform(aabb(bbmin,bbmax), transform); } 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; // if(m.mesh) mesh_destroy(m.mesh); - FREE(outframe); - FREE(colormaps); - FREE(textures); - FREE(baseframe); - FREE(inversebaseframe); - if(animdata != meshdata) FREE(animdata); - //FREE(meshdata); - FREE(frames); - FREE(buf); + FREE(q->outframe); + FREE(q->colormaps); + FREE(q->textures); + FREE(q->baseframe); + FREE(q->inversebaseframe); + if(q->animdata != q->meshdata) FREE(q->animdata); + //FREE(q->meshdata); + FREE(q->frames); + FREE(q->buf); 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 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; - 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(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 - } + a.speed = 1.0; + a.anims = animlist(pathfile); 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 e = eulerq(vec3(obj->euler.x,obj->euler.y,obj->euler.z)); compose44(obj->transform, obj->pos, mulq(e, p), obj->sca); + + } object_t object() { @@ -22132,6 +22128,11 @@ void object_model(object_t *obj, model_t 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) { 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 ) { object_t *obj = scene_index(j); model_t *model = &obj->model; + anim_t *anim = &obj->anim; mat44 *views = (mat44*)(&cam->view); // @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); } + 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_render(*model, cam->proj, cam->view, obj->transform, 0); diff --git a/engine/v4k.h b/engine/v4k.h index 38ef57d..b66fc1d 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -2197,13 +2197,14 @@ enum FONT_FLAGS { typedef struct font_metrics_t { float ascent; // max distance above 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) } font_metrics_t; // configures 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_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_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 void font_goto(float x, float y); 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 font_metrics_t font_metrics(const char *text); // 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 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 @@ -3856,6 +3858,8 @@ typedef struct object_t { vec3 sca, pos, euler, pivot; array(handle) textures; model_t model; + anim_t anim; + float anim_speed; aabb bounds; unsigned billboard; // [0..7] x(4),y(2),z(1) masks 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_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_push(object_t *obj, texture_t tex); API void object_diffuse_pop(object_t *obj); diff --git a/tools/fontview.exe b/tools/fontview.exe index 3910536..5ed9319 100644 Binary files a/tools/fontview.exe and b/tools/fontview.exe differ