diff --git a/src/core/math.h b/src/core/math.h index 26128a22..97e097bb 100644 --- a/src/core/math.h +++ b/src/core/math.h @@ -13,17 +13,9 @@ #define ALIGN_UP(v, alignment) (((v) + (alignment)-1) & ~((alignment)-1)) #define ALIGN_DOWN(v, alignment) ((v) & ~((alignment)-1)) -static inline uint32_t npow2(uint32_t v) { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} - +/* + * bitwise ops + */ static inline uint32_t bswap24(uint32_t v) { return ((v & 0xff) << 16) | (v & 0x00ff00) | ((v & 0xff0000) >> 16); } @@ -95,4 +87,66 @@ static inline uint32_t bswap32(uint32_t v) { #endif +/* + * scalar ops + */ +static inline uint32_t npow2(uint32_t v) { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +/* + * vector ops + */ +static inline float vec3_dot(float *a, float *b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +static inline float vec3_len(float *a) { + return sqrtf(vec3_dot(a, a)); +} + +static inline float vec3_normalize(float *a) { + float len = vec3_len(a); + if (len) { + a[0] /= len; + a[1] /= len; + a[2] /= len; + } + return len; +} + +static inline void vec3_add(float *out, float *a, float *b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; +} +static inline void vec3_sub(float *out, float *a, float *b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; +} + +static inline void vec3_cross(float *out, float *a, float *b) { + out[0] = a[1] * b[2] - a[2] * b[1]; + out[1] = a[2] * b[0] - a[0] * b[2]; + out[2] = a[0] * b[1] - a[1] * b[0]; +} + +static inline void vec2_add(float *out, float *a, float *b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; +} + +static inline void vec2_sub(float *out, float *a, float *b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; +} + #endif diff --git a/src/guest/pvr/ta_types.h b/src/guest/pvr/ta_types.h index 64f5bbc0..34303616 100644 --- a/src/guest/pvr/ta_types.h +++ b/src/guest/pvr/ta_types.h @@ -263,7 +263,7 @@ union vert_param { struct { union pcw pcw; float xyz[3]; - uint16_t vu[2]; + uint16_t uv[2]; uint32_t ignore_0; uint32_t base_color; uint32_t offset_color; @@ -288,7 +288,7 @@ union vert_param { struct { union pcw pcw; float xyz[3]; - uint16_t vu[2]; + uint16_t uv[2]; uint32_t ignore_0; uint32_t ignore_1; uint32_t ignore_2; @@ -313,7 +313,7 @@ union vert_param { struct { union pcw pcw; float xyz[3]; - uint16_t vu[2]; + uint16_t uv[2]; uint32_t ignore_0; float base_intensity; float offset_intensity; @@ -412,7 +412,7 @@ union vert_param { struct { union pcw pcw; float xyz[4][3]; - uint32_t uv[3]; + uint16_t uv[3][2]; } sprite1; }; diff --git a/src/guest/pvr/tr.c b/src/guest/pvr/tr.c index a15a73f9..99e9d8b9 100644 --- a/src/guest/pvr/tr.c +++ b/src/guest/pvr/tr.c @@ -277,10 +277,10 @@ static inline uint8_t fmulu8(uint8_t a, uint8_t b) { (out)[1] = (uv)[1]; \ } -#define PARSE_UV16(vu, out) \ +#define PARSE_UV16(uv, out) \ { \ - uint32_t u = (vu)[1] << 16; \ - uint32_t v = (vu)[0] << 16; \ + uint32_t u = (uv)[1] << 16; \ + uint32_t v = (uv)[0] << 16; \ (out)[0] = *(float *)&u; \ (out)[1] = *(float *)&v; \ } @@ -364,38 +364,38 @@ static void tr_parse_bg(struct tr *tr, const struct ta_context *ctx, surf->params.dst_blend = BLEND_NONE; /* translate the first 3 vertices */ - struct ta_vertex *v0 = tr_reserve_vert(tr, rc); - struct ta_vertex *v1 = tr_reserve_vert(tr, rc); - struct ta_vertex *v2 = tr_reserve_vert(tr, rc); - struct ta_vertex *v3 = tr_reserve_vert(tr, rc); + struct ta_vertex *va = tr_reserve_vert(tr, rc); + struct ta_vertex *vb = tr_reserve_vert(tr, rc); + struct ta_vertex *vc = tr_reserve_vert(tr, rc); + struct ta_vertex *vd = tr_reserve_vert(tr, rc); int offset = 0; - offset = tr_parse_bg_vert(ctx, rc, offset, v0); - offset = tr_parse_bg_vert(ctx, rc, offset, v1); - offset = tr_parse_bg_vert(ctx, rc, offset, v2); + offset = tr_parse_bg_vert(ctx, rc, offset, va); + offset = tr_parse_bg_vert(ctx, rc, offset, vb); + offset = tr_parse_bg_vert(ctx, rc, offset, vc); /* override xyz values supplied by ISP_BACKGND_T. while the hardware docs act like they should be correct, they're most definitely not in most cases */ - v0->xyz[0] = 0.0f; - v0->xyz[1] = (float)ctx->video_height; - v0->xyz[2] = ctx->bg_depth; + va->xyz[0] = 0.0f; + va->xyz[1] = (float)ctx->video_height; + va->xyz[2] = ctx->bg_depth; - v1->xyz[0] = 0.0f; - v1->xyz[1] = 0.0f; - v1->xyz[2] = ctx->bg_depth; + vb->xyz[0] = 0.0f; + vb->xyz[1] = 0.0f; + vb->xyz[2] = ctx->bg_depth; - v2->xyz[0] = (float)ctx->video_width; - v2->xyz[1] = (float)ctx->video_height; - v2->xyz[2] = ctx->bg_depth; + vc->xyz[0] = (float)ctx->video_width; + vc->xyz[1] = (float)ctx->video_height; + vc->xyz[2] = ctx->bg_depth; /* 4th vertex isn't supplied, fill it out automatically */ - v3->xyz[0] = v2->xyz[0]; - v3->xyz[1] = v1->xyz[1]; - v3->xyz[2] = ctx->bg_depth; - v3->uv[0] = v2->uv[0]; - v3->uv[1] = v1->uv[1]; - v3->color = v0->color; - v3->offset_color = v0->offset_color; + vd->xyz[0] = vc->xyz[0]; + vd->xyz[1] = vb->xyz[1]; + vd->xyz[2] = ctx->bg_depth; + vd->uv[0] = vc->uv[0]; + vd->uv[1] = vb->uv[1]; + vd->color = va->color; + vd->offset_color = va->offset_color; tr_commit_surf(tr, rc); @@ -534,7 +534,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct ta_context *ctx, case 4: { struct ta_vertex *vert = tr_reserve_vert(tr, rc); PARSE_XYZ(param->type4.xyz, vert->xyz); - PARSE_UV16(param->type4.vu, vert->uv); + PARSE_UV16(param->type4.uv, vert->uv); PARSE_PACKED_COLOR(param->type4.base_color, &vert->color); PARSE_PACKED_COLOR(param->type4.offset_color, &vert->offset_color); } break; @@ -550,7 +550,7 @@ static void tr_parse_vert_param(struct tr *tr, const struct ta_context *ctx, case 6: { struct ta_vertex *vert = tr_reserve_vert(tr, rc); PARSE_XYZ(param->type6.xyz, vert->xyz); - PARSE_UV16(param->type6.vu, vert->uv); + PARSE_UV16(param->type6.uv, vert->uv); PARSE_FLOAT_COLOR(param->type6.base_color, &vert->color); PARSE_FLOAT_COLOR(param->type6.offset_color, &vert->offset_color); } break; @@ -567,56 +567,88 @@ static void tr_parse_vert_param(struct tr *tr, const struct ta_context *ctx, case 8: { struct ta_vertex *vert = tr_reserve_vert(tr, rc); PARSE_XYZ(param->type8.xyz, vert->xyz); - PARSE_UV16(param->type8.vu, vert->uv); + PARSE_UV16(param->type8.uv, vert->uv); PARSE_BASE_INTENSITY(param->type8.base_intensity, &vert->color); PARSE_OFFSET_INTENSITY(param->type8.offset_intensity, &vert->offset_color); } break; - case 15: { - CHECK(param->type0.pcw.end_of_strip); - - static const int indices[] = {0, 1, 3, 2}; - - for (int i = 0, l = ARRAY_SIZE(indices); i < l; i++) { - int idx = indices[i]; - struct ta_vertex *vert = tr_reserve_vert(tr, rc); - - /* FIXME this is assuming all sprites are billboards */ - vert->xyz[0] = param->sprite0.xyz[idx][0]; - vert->xyz[1] = param->sprite0.xyz[idx][1]; - vert->xyz[2] = param->sprite0.xyz[0][2]; - vert->color = *(uint32_t *)&tr->sprite_color; - vert->offset_color = *(uint32_t *)&tr->sprite_offset_color; - } - } break; - + case 15: case 16: { CHECK(param->type0.pcw.end_of_strip); - static const int indices[] = {0, 1, 3, 2}; + /* + * sprites are input as a quad in a clockwise order: + * + * b (x,y,z,u,v) ---> c (x,y,z,u,v) + * ^ | + * | | + * | | + * | v + * a (x,y,z,u,v) <--- d (x,y,0,0,0) + * + * note that the z, u, v components aren't specified for the final vertex. + * these need to be calculated, and the quad needs to be converted into a + * tristrip to match the rest of the ta input + */ + struct ta_vertex *va = tr_reserve_vert(tr, rc); /* bottom left */ + struct ta_vertex *vb = tr_reserve_vert(tr, rc); /* top left */ + struct ta_vertex *vd = tr_reserve_vert(tr, rc); /* bottom right */ + struct ta_vertex *vc = tr_reserve_vert(tr, rc); /* top right */ - for (int i = 0, l = ARRAY_SIZE(indices); i < l; i++) { - int idx = indices[i]; - struct ta_vertex *vert = tr_reserve_vert(tr, rc); + PARSE_XYZ(param->sprite1.xyz[0], va->xyz); + PARSE_UV16(param->sprite1.uv[0], va->uv); + va->color = *(uint32_t *)&tr->sprite_color; + va->offset_color = *(uint32_t *)&tr->sprite_offset_color; - /* FIXME this is assuming all sprites are billboards */ - vert->xyz[0] = param->sprite1.xyz[idx][0]; - vert->xyz[1] = param->sprite1.xyz[idx][1]; - vert->xyz[2] = param->sprite1.xyz[0][2]; - uint32_t u, v; - if (idx == 3) { - u = (param->sprite1.uv[0] & 0xffff0000); - v = (param->sprite1.uv[2] & 0x0000ffff) << 16; - } else { - u = (param->sprite1.uv[idx] & 0xffff0000); - v = (param->sprite1.uv[idx] & 0x0000ffff) << 16; - } - vert->uv[0] = *(float *)&u; - vert->uv[1] = *(float *)&v; - vert->color = *(uint32_t *)&tr->sprite_color; - vert->offset_color = *(uint32_t *)&tr->sprite_offset_color; + PARSE_XYZ(param->sprite1.xyz[1], vb->xyz); + PARSE_UV16(param->sprite1.uv[1], vb->uv); + vb->color = *(uint32_t *)&tr->sprite_color; + vb->offset_color = *(uint32_t *)&tr->sprite_offset_color; + + PARSE_XYZ(param->sprite1.xyz[2], vc->xyz); + PARSE_UV16(param->sprite1.uv[2], vc->uv); + vc->color = *(uint32_t *)&tr->sprite_color; + vc->offset_color = *(uint32_t *)&tr->sprite_offset_color; + + vd->xyz[0] = param->sprite1.xyz[3][0]; + vd->xyz[1] = param->sprite1.xyz[3][1]; + vd->color = *(uint32_t *)&tr->sprite_color; + vd->offset_color = *(uint32_t *)&tr->sprite_offset_color; + + /* calculate the sprite's plane from the three complete vertices */ + float xyz_ba[3], xyz_bc[3]; + float n[3], len, d; + vec3_sub(xyz_ba, va->xyz, vb->xyz); + vec3_sub(xyz_bc, vc->xyz, vb->xyz); + vec3_cross(n, xyz_ba, xyz_bc); + len = vec3_normalize(n); + d = vec3_dot(n, vb->xyz); + + /* don't commit surf if quad is degenerate or perpendicular to our view */ + if (len == 0.0f || n[2] == 0.0f) { + return; } + + /* + * for all points on a plane, the following must hold true: + * dot(n, p) - d = 0 + * + * using this, the missing corner's z can be solved with: + * n.x * p.x + n.y * p.y + n.z * p.z - d = 0 + * n.x * p.x + n.y * p.y + n.z * p.z = d + * n.z * p.z = d - n.x * p.x - n.y * p.y + * p.z = (d - n.x * p.y - n.y * p.y) / n.z + */ + vd->xyz[2] = (d - n[0] * vd->xyz[0] - n[1] * vd->xyz[1]) / n[2]; + + /* calculate the missing corner's uv */ + float uv_ba[2], uv_bc[2]; + vec2_sub(uv_ba, va->uv, vb->uv); + vec2_sub(uv_bc, vc->uv, vb->uv); + + vec2_add(vd->uv, vb->uv, uv_ba); + vec2_add(vd->uv, vd->uv, uv_bc); } break; default: diff --git a/src/tracer.c b/src/tracer.c index c3b932eb..c3fefe5f 100644 --- a/src/tracer.c +++ b/src/tracer.c @@ -431,7 +431,7 @@ static void tracer_param_tooltip(struct tracer *tracer, struct tr_param *rp) { *(uint32_t *)(float *)¶m->type4.xyz[0], *(uint32_t *)(float *)¶m->type4.xyz[1], *(uint32_t *)(float *)¶m->type4.xyz[2]); - igText("uv: {0x%x, 0x%x}", param->type4.vu[1], param->type4.vu[0]); + igText("uv: {0x%x, 0x%x}", param->type4.uv[1], param->type4.uv[0]); igText("base_color: 0x%x", param->type4.base_color); igText("offset_color: 0x%x", param->type4.offset_color); break; @@ -453,7 +453,7 @@ static void tracer_param_tooltip(struct tracer *tracer, struct tr_param *rp) { case 6: igText("xyz: {%.2f, %.2f, %f}", param->type6.xyz[0], param->type6.xyz[1], param->type6.xyz[2]); - igText("uv: {0x%x, 0x%x}", param->type6.vu[1], param->type6.vu[0]); + igText("uv: {0x%x, 0x%x}", param->type6.uv[1], param->type6.uv[0]); igText("base_color_a: %.2f", param->type6.base_color_a); igText("base_color_r: %.2f", param->type6.base_color_r); igText("base_color_g: %.2f", param->type6.base_color_g); @@ -475,7 +475,7 @@ static void tracer_param_tooltip(struct tracer *tracer, struct tr_param *rp) { case 8: igText("xyz: {%.2f, %.2f, %f}", param->type8.xyz[0], param->type8.xyz[1], param->type8.xyz[2]); - igText("uv: {0x%x, 0x%x}", param->type8.vu[1], param->type8.vu[0]); + igText("uv: {0x%x, 0x%x}", param->type8.uv[1], param->type8.uv[0]); igText("base_intensity: %.2f", param->type8.base_intensity); igText("offset_intensity: %.2f", param->type8.offset_intensity); break;