#include "driver.h" #include "video/segaic24.h" #include #define LOG_TGP_VIDEO 0 #if LOG_TGP_VIDEO #define LOG_TGP logerror #else static void dummy_log(const char *s,...) {} #define LOG_TGP dummy_log #endif UINT16 *model1_display_list0, *model1_display_list1; UINT16 *model1_color_xlat; static UINT16 listctl[2]; static UINT16 *glist; // Model 1 geometrizer TGP and rasterizer simulation enum { FRAC_SHIFT = 16 }; static int render_done; static UINT16 *tgp_ram; static float trans_mat[12]; static float vxx, vyy, vzz, ayy, ayyc, ayys; struct vector { float x, y, z; }; static struct { int xc, yc, x1, y1, x2, y2; float zoomx, zoomy, transx, transy; float a_bottom, a_top, a_left, a_right; struct vector light; } view; struct spoint { INT32 x, y; }; struct point { float x, y, z; float xx, yy; struct spoint s; }; static struct lightparam { float a; float d; float s; int p; } lightparams[32]; enum { MOIRE = 0x00010000 }; struct quad { struct point *p[4]; float z; int col; }; static struct point *pointdb, *pointpt; static struct quad *quaddb, *quadpt; static struct quad **quadind; static UINT32 *poly_rom,*poly_ram; static UINT32 readi(const UINT16 *adr) { return adr[0]|(adr[1] << 16); } static INT16 readi16(const UINT16 *adr) { return adr[0]; } static float readf(const UINT16 *adr) { return u2f(readi(adr)); } static void transform_point(struct point *p) { struct point q = *p; float xx, zz; xx = trans_mat[0]*q.x+trans_mat[3]*q.y+trans_mat[6]*q.z+trans_mat[9]+vxx; p->y = trans_mat[1]*q.x+trans_mat[4]*q.y+trans_mat[7]*q.z+trans_mat[10]+vyy; zz = trans_mat[2]*q.x+trans_mat[5]*q.y+trans_mat[8]*q.z+trans_mat[11]+vzz; p->x = ayyc*xx-ayys*zz; p->z = ayys*xx+ayyc*zz; } static void transform_vector(struct vector *p) { struct vector q = *p; p->x = trans_mat[0]*q.x+trans_mat[3]*q.y+trans_mat[6]*q.z; p->y = trans_mat[1]*q.x+trans_mat[4]*q.y+trans_mat[7]*q.z; p->z = trans_mat[2]*q.x+trans_mat[5]*q.y+trans_mat[8]*q.z; } static void normalize_vector(struct vector *p) { float norm = sqrt(p->x*p->x+p->y*p->y+p->z*p->z); if(norm) { p->x /= norm; p->y /= norm; p->z /= norm; } } static float mult_vector(const struct vector *p, const struct vector *q) { return p->x*q->x+p->y*q->y+p->z*q->z; } static float view_determinant(const struct point *p1, const struct point *p2, const struct point *p3) { float x1 = p2->x - p1->x; float y1 = p2->y - p1->y; float z1 = p2->z - p1->z; float x2 = p3->x - p1->x; float y2 = p3->y - p1->y; float z2 = p3->z - p1->z; return p1->x*(y1*z2-y2*z1) + p1->y*(z1*x2-z2*x1) + p1->z*(x1*y2-x2*y1); } static void project_point(struct point *p) { p->xx = p->x / p->z; p->yy = p->y / p->z; p->s.x = view.xc+(p->xx*view.zoomx+view.transx); p->s.y = view.yc-(p->yy*view.zoomy+view.transy); } static void project_point_direct(struct point *p) { p->xx = p->x /*/ p->z*/; p->yy = p->y /*/ p->z*/; p->s.x = view.xc+(p->xx); p->s.y = view.yc-(p->yy); } static void draw_hline(mame_bitmap *bitmap, int x1, int x2, int y, int color) { UINT16 *base = BITMAP_ADDR16(bitmap, y, 0); while(x1 <= x2) { base[x1] = color; x1++; } } static void draw_hline_moired(mame_bitmap *bitmap, int x1, int x2, int y, int color) { UINT16 *base = BITMAP_ADDR16(bitmap, y, 0); while(x1 <= x2) { if((x1^y)&1) base[x1] = color; x1++; } } static void fill_slope(mame_bitmap *bitmap, int color, INT32 x1, INT32 x2, INT32 sl1, INT32 sl2, INT32 y1, INT32 y2, INT32 *nx1, INT32 *nx2) { if(y1 > view.y2) return; if(y2 <= view.y1) { int delta = y2-y1; *nx1 = x1+delta*sl1; *nx2 = x2+delta*sl2; return; } if(y2 > view.y2) y2 = view.y2+1; if(y1 < view.y1) { int delta = view.y1 - y1; x1 += delta*sl1; x2 += delta*sl2; y1 = view.y1; } if(x1 > x2 || (x1==x2 && sl1 > sl2)) { INT32 t, *tp; t = x1; x1 = x2; x2 = t; t = sl1; sl1 = sl2; sl2 = t; tp = nx1; nx1 = nx2; nx2 = tp; } while(y1 < y2) { if(y1 >= view.y1) { int xx1 = x1>>FRAC_SHIFT; int xx2 = x2>>FRAC_SHIFT; if(xx1 <= view.x2 || xx2 >= view.x1) { if(xx1 < view.x1) xx1 = view.x1; if(xx2 > view.x2) xx2 = view.x2; if(color & MOIRE) draw_hline_moired(bitmap, xx1, xx2, y1, color); else draw_hline(bitmap, xx1, xx2, y1, color); } } x1 += sl1; x2 += sl2; y1++; } *nx1 = x1; *nx2 = x2; } static void fill_line(mame_bitmap *bitmap, int color, INT32 y, INT32 x1, INT32 x2) { int xx1 = x1>>FRAC_SHIFT; int xx2 = x2>>FRAC_SHIFT; if(y > view.y2 || y < view.y1) return; if(xx1 <= view.x2 || xx2 >= view.x1) { if(xx1 < view.x1) xx1 = view.x1; if(xx2 > view.x2) xx2 = view.x2; if(color & MOIRE) draw_hline_moired(bitmap, xx1, xx2, y, color); else draw_hline(bitmap, xx1, xx2, y, color); } } static void fill_quad(mame_bitmap *bitmap, const struct quad *q) { INT32 sl1, sl2, cury, limy, x1, x2; int pmin, pmax, i, ps1, ps2; struct spoint p[8]; int color = q->col; if(color < 0) { color = -1-color; LOG_TGP("VIDEOD: Q (%d, %d)-(%d, %d)-(%d, %d)-(%d, %d)\n", q->p[0]->s.x, q->p[0]->s.y, q->p[1]->s.x, q->p[1]->s.y, q->p[2]->s.x, q->p[2]->s.y, q->p[3]->s.x, q->p[3]->s.y); } for(i=0; i<4; i++) { p[i].x = p[i+4].x = q->p[i]->s.x << FRAC_SHIFT; p[i].y = p[i+4].y = q->p[i]->s.y; } pmin = pmax = 0; for(i=1; i<4; i++) { if(p[i].y < p[pmin].y) pmin = i; if(p[i].y > p[pmax].y) pmax = i; } cury = p[pmin].y; limy = p[pmax].y; if(cury == limy) { x1 = x2 = p[0].x; for(i=1; i<4; i++) { if(p[i].x < x1) x1 = p[i].x; if(p[i].x > x2) x2 = p[i].x; } fill_line(bitmap, color, cury, x1, x2); return; } if(cury > view.y2) return; if(limy <= view.y1) return; if(limy > view.y2) limy = view.y2; ps1 = pmin+4; ps2 = pmin; goto startup; for(;;) { if(p[ps1-1].y == p[ps2+1].y) { fill_slope(bitmap, color, x1, x2, sl1, sl2, cury, p[ps1-1].y, &x1, &x2); cury = p[ps1-1].y; if(cury >= limy) break; ps1--; ps2++; startup: while(p[ps1-1].y == cury) ps1--; while(p[ps2+1].y == cury) ps2++; x1 = p[ps1].x; x2 = p[ps2].x; sl1 = (x1-p[ps1-1].x)/(cury-p[ps1-1].y); sl2 = (x2-p[ps2+1].x)/(cury-p[ps2+1].y); } else if(p[ps1-1].y < p[ps2+1].y) { fill_slope(bitmap, color, x1, x2, sl1, sl2, cury, p[ps1-1].y, &x1, &x2); cury = p[ps1-1].y; if(cury >= limy) break; ps1--; while(p[ps1-1].y == cury) ps1--; x1 = p[ps1].x; sl1 = (x1-p[ps1-1].x)/(cury-p[ps1-1].y); } else { fill_slope(bitmap, color, x1, x2, sl1, sl2, cury, p[ps2+1].y, &x1, &x2); cury = p[ps2+1].y; if(cury >= limy) break; ps2++; while(p[ps2+1].y == cury) ps2++; x2 = p[ps2].x; sl2 = (x2-p[ps2+1].x)/(cury-p[ps2+1].y); } } if(cury == limy) fill_line(bitmap, color, cury, x1, x2); } #if 0 static void draw_line(mame_bitmap *bitmap, int color, int x1, int y1, int x2, int y2) { int s1x, s1y, s2x, s2y; int d1, d2; int cur; int x, y; if((x1 < view.x1 && x2 < view.x1) || (x1 > view.x2 && x2 > view.x2) || (y1 < view.y1 && y2 < view.y1) || (y1 > view.y2 && y2 > view.y2)) return; x = x1; y = y1; s1x = 1; s1y = 0; s2x = 0; s2y = 1; d1 = x2-x1; d2 = y2-y1; if(d1<0) { s1x = -s1x; d1 = -d1; } if(d2<0) { s2y = -s2y; d2 = -d2; } if(d1 < d2) { int t; t = s1x; s1x = s2x; s2x = t; t = s1y; s1y = s2y; s2y = t; t = d1; d1 = d2; d2 = t; } if(d1 > 600) return; cur = 0; while(x != x2 || y != y2) { if(x>=view.x1 && x<=view.x2 && y>=view.y1 && y<=view.y2) *BITMAP_ADDR16(bitmap, y, x) = color; x += s1x; y += s1y; cur += d2; if(cur >= d1) { cur -= d1; x += s2x; y += s2y; } } if(x>=view.x1 && x<=view.x2 && y>=view.y1 && y<=view.y2) *BITMAP_ADDR16(bitmap, y, x) = color; } #endif static int comp_quads(const void *q1, const void *q2) { float z1 = (*(const struct quad **)q1)->z; float z2 = (*(const struct quad **)q2)->z; if(z1z2) return -1; if (*(const struct quad **)q1 - quaddb < *(const struct quad **)q2 - quaddb) return -1; return +1; } static void sort_quads(void) { int count = quadpt - quaddb; int i; for(i=0; imin_x); view.x2 = MIN(view.x2, cliprect->max_x); view.y1 = MAX(view.y1, cliprect->min_y); view.y2 = MIN(view.y2, cliprect->max_y); for(i=0; ip[0]->s.x, q->p[0]->s.y, q->p[1]->s.x, q->p[1]->s.y); draw_line(bitmap, get_black_pen(machine), q->p[1]->s.x, q->p[1]->s.y, q->p[2]->s.x, q->p[2]->s.y); draw_line(bitmap, get_black_pen(machine), q->p[2]->s.x, q->p[2]->s.y, q->p[3]->s.x, q->p[3]->s.y); draw_line(bitmap, get_black_pen(machine), q->p[3]->s.x, q->p[3]->s.y, q->p[0]->s.x, q->p[0]->s.y); #endif } view.x1 = save_x1; view.x2 = save_x2; view.y1 = save_y1; view.y2 = save_y2; } #if 0 static UINT16 scale_color(UINT16 color, float level) { int r, g, b; r = ((color >> 10) & 31)*level; g = ((color >> 5) & 31)*level; b = (color & 31)*level; return (r<<10)|(g<<5)|b; } #endif // xe = xc + (x/z * zm + tx) // xe < x1 => xc + (x/z * zm + tx) < x1 // => x/z < (x1-xc-tx)/zm // => x < z*(x1-xc-tx)/zm // ye = yc - (y/z * zm + ty) // ye < y1 => yc - (y/z * zm + ty) < y1 // => -y/z < (y1-yc+ty)/zm // => y > -z*(y1-yc+ty)/zm // xf = zf*a // xx = x1*t+x2(1-t); zz = z1*t+z2(1-t) // => x1*t+x2(1-t) = z1*t*a+z2*(1-t)*a // => t*(x1-x2+a*(z2-z1) = -x2+a*z2 // => t = (z2*a-x2)/((z2-z1)*a-(x2-x1)) static void recompute_frustrum(void) { view.a_left = ( view.x1-view.xc-view.transx)/view.zoomx; view.a_right = ( view.x2-view.xc-view.transx)/view.zoomx; view.a_bottom = (-view.y1+view.yc-view.transy)/view.zoomy; view.a_top = (-view.y2+view.yc-view.transy)/view.zoomy; } static int fclip_isc_bottom(struct point *p) { return p->y > p->z*view.a_bottom; } static struct point *fclip_clip_bottom(struct point *p1, struct point *p2) { float t = (p2->z*view.a_bottom-p2->y)/((p2->z-p1->z)*view.a_bottom-(p2->y-p1->y)); pointpt->x = p1->x*t + p2->x*(1-t); pointpt->y = p1->y*t + p2->y*(1-t); pointpt->z = p1->z*t + p2->z*(1-t); project_point(pointpt); return pointpt++; } static int fclip_isc_top(struct point *p) { return p->y < p->z*view.a_top; } static struct point *fclip_clip_top(struct point *p1, struct point *p2) { float t = (p2->z*view.a_top-p2->y)/((p2->z-p1->z)*view.a_top-(p2->y-p1->y)); pointpt->x = p1->x*t + p2->x*(1-t); pointpt->y = p1->y*t + p2->y*(1-t); pointpt->z = p1->z*t + p2->z*(1-t); project_point(pointpt); return pointpt++; } static int fclip_isc_left(struct point *p) { return p->x < p->z*view.a_left; } static struct point *fclip_clip_left(struct point *p1, struct point *p2) { float t = (p2->z*view.a_left-p2->x)/((p2->z-p1->z)*view.a_left-(p2->x-p1->x)); pointpt->x = p1->x*t + p2->x*(1-t); pointpt->y = p1->y*t + p2->y*(1-t); pointpt->z = p1->z*t + p2->z*(1-t); project_point(pointpt); return pointpt++; } static int fclip_isc_right(struct point *p) { return p->x > p->z*view.a_right; } static struct point *fclip_clip_right(struct point *p1, struct point *p2) { float t = (p2->z*view.a_right-p2->x)/((p2->z-p1->z)*view.a_right-(p2->x-p1->x)); pointpt->x = p1->x*t + p2->x*(1-t); pointpt->y = p1->y*t + p2->y*(1-t); pointpt->z = p1->z*t + p2->z*(1-t); project_point(pointpt); return pointpt++; } static struct { int (*isclipped)(struct point *p); struct point *(*clip)(struct point *p1, struct point *p2); } clipfn[4] = { { fclip_isc_bottom, fclip_clip_bottom }, { fclip_isc_top, fclip_clip_top }, { fclip_isc_left, fclip_clip_left }, { fclip_isc_right, fclip_clip_right }, }; static void fclip_push_quad(int level, struct quad *q); static void fclip_push_quad_next(int level, struct quad *q, struct point *p1, struct point *p2, struct point *p3, struct point *p4) { struct quad q2; q2.col = q->col; q2.z = q->z; q2.p[0] = p1; q2.p[1] = p2; q2.p[2] = p3; q2.p[3] = p4; fclip_push_quad(level+1, &q2); } static void fclip_push_quad(int level, struct quad *q) { int i, j; struct point *pt[4], *pi1, *pi2; int is_out[4], is_out2[4]; struct point *(*fclip_point)(struct point *p1, struct point *p2); if(level == 4) { LOG_TGP("VIDEOCQ %d", level); for(i=0; i<4; i++) LOG_TGP(" (%f, %f, %f)", q->p[i]->x, q->p[i]->y, q->p[i]->z); LOG_TGP("\n"); *quadpt = *q; quadpt++; return; } for(i=0; i<4; i++) is_out[i] = clipfn[level].isclipped(q->p[i]); LOG_TGP("VIDEOCQ %d", level); for(i=0; i<4; i++) LOG_TGP(" (%f, %f, %f, %d)", q->p[i]->x, q->p[i]->y, q->p[i]->z, is_out[i]); LOG_TGP("\n"); // No clipping if(!is_out[0] && !is_out[1] && !is_out[2] && !is_out[3]) { fclip_push_quad(level+1, q); return; } fclip_point = clipfn[level].clip; // Full clipping if(is_out[0] && is_out[1] && is_out[2] && is_out[3]) return; // Find n so that point n is clipped and n-1 isn't for(i=0; i<4; i++) if(is_out[i] && !is_out[(i-1)&3]) break; for(j=0; j<4; j++) { pt[j] = q->p[(i+j)&3]; is_out2[j] = is_out[(i+j)&3]; } // At this point, pt[0] is clipped out and pt[3] isn't. Test for the 4 possible cases if(is_out2[1]) if(is_out2[2]) { // pt 0,1,2 clipped out, one triangle left pi1 = fclip_point(pt[2], pt[3]); pi2 = fclip_point(pt[3], pt[0]); fclip_push_quad_next(level, q, pi1, pt[3], pi2, pi2); } else { // pt 0,1 clipped out, one quad left pi1 = fclip_point(pt[1], pt[2]); pi2 = fclip_point(pt[3], pt[0]); fclip_push_quad_next(level, q, pi1, pt[2], pt[3], pi2); } else if(is_out2[2]) { // pt 0,2 clipped out, shouldn't happen, two triangles pi1 = fclip_point(pt[0], pt[1]); pi2 = fclip_point(pt[1], pt[2]); fclip_push_quad_next(level, q, pi1, pt[1], pi2, pi2); pi1 = fclip_point(pt[2], pt[3]); pi2 = fclip_point(pt[3], pt[0]); fclip_push_quad_next(level, q, pi1, pt[3], pi2, pi2); } else { // pt 0 clipped out, one decagon left, split in quad+tri pi1 = fclip_point(pt[0], pt[1]); pi2 = fclip_point(pt[3], pt[0]); fclip_push_quad_next(level, q, pi1, pt[1], pt[2], pt[3]); fclip_push_quad_next(level, q, pt[3], pi2, pi1, pi1); } } static float min4f(float a, float b, float c, float d) { float m = a; if(bm) m = b; if(c>m) m = c; if(d>m) m = d; return m; } static const UINT8 num_of_times[]={1,1,1,1,2,2,2,3}; static float compute_specular(struct vector *normal, struct vector *light,float diffuse,int lmode) { #if 0 float s; int p=lightparams[lmode].p&7; int i; float sv=lightparams[lmode].s; //This is how it should be according to model2 geo program, but doesn't work fine s=2*(diffuse*normal->z-light->z); for(i=0;i1.0) return 1.0; return s; return fabs(diffuse)*sv; #endif return 0; } static void push_object(UINT32 tex_adr, UINT32 poly_adr, UINT32 size) { int i; UINT32 flags; struct point *old_p0, *old_p1, *p0, *p1; struct vector vn; int link, type; int dump; int lightmode; float old_z; struct quad cquad; float *poly_data; if(poly_adr & 0x800000) poly_data=(float *) poly_ram; else poly_data=(float *) poly_rom; poly_adr &= 0x7fffff; dump = poly_adr == 0x944ea; dump = 0; #if 0 if(poly_adr < 0x10000 || poly_adr >= 0x80000) return; if(poly_adr < 0x40000 || poly_adr >= 0x50000) return; if(poly_adr == 0x4c7db || poly_adr == 0x4cdaa || poly_adr == 0x4d3e7) return; if(poly_adr != 0x483e5) return; #endif if(1) { LOG_TGP("XVIDEO: draw object (%x, %x, %x)\n", tex_adr, poly_adr, size); } if(!size) size = 0xffffffff; old_p0 = pointpt++; old_p1 = pointpt++; old_p0->x = poly_data[poly_adr+0]; old_p0->y = poly_data[poly_adr+1]; old_p0->z = poly_data[poly_adr+2]; old_p1->x = poly_data[poly_adr+3]; old_p1->y = poly_data[poly_adr+4]; old_p1->z = poly_data[poly_adr+5]; transform_point(old_p0); transform_point(old_p1); if(old_p0->z > 0) project_point(old_p0); else old_p0->s.x = old_p0->s.y = 0; if(old_p1->z > 0) project_point(old_p1); else old_p1->s.x = old_p1->s.y = 0; old_z = 0; poly_adr += 6; for(i=0; i>17)&15; p0 = pointpt++; p1 = pointpt++; vn.x = poly_data[poly_adr+1]; vn.y = poly_data[poly_adr+2]; vn.z = poly_data[poly_adr+3]; p0->x = poly_data[poly_adr+4]; p0->y = poly_data[poly_adr+5]; p0->z = poly_data[poly_adr+6]; p1->x = poly_data[poly_adr+7]; p1->y = poly_data[poly_adr+8]; p1->z = poly_data[poly_adr+9]; link = (flags >> 8) & 3; transform_vector(&vn); transform_point(p0); transform_point(p1); if(p0->z > 0) project_point(p0); else p0->s.x = p0->s.y = 0; if(p1->z > 0) project_point(p1); else p1->s.x = p1->s.y = 0; #if 0 if(dump) LOG_TGP("VIDEO: %08x (%f, %f, %f) (%f, %f, %f)\n", *(UINT32 *)(poly_data+poly_adr), p0->x, p0->y, p0->z, p1->x, p1->y, p1->z); #endif #if 0 if(1 || dump) { LOG_TGP("VIDEO: %08x (%d, %d) (%d, %d) (%d, %d) (%d, %d)\n", *(UINT32 *)(poly_data+poly_adr), old_p0->s.x, old_p0->s.y, old_p1->s.x, old_p1->s.y, p0->s.x, p0->s.y, p1->s.x, p1->s.y); } #endif if(!link) goto next; if(!(flags & 0x00004000) && view_determinant(old_p1, old_p0, p0) > 0) goto next; normalize_vector(&vn); cquad.p[0] = old_p1; cquad.p[1] = old_p0; cquad.p[2] = p0; cquad.p[3] = p1; switch((flags >> 10) & 3) { case 0: cquad.z = old_z; break; case 1: cquad.z = old_z = min4f(old_p1->z, old_p0->z, p0->z, p1->z); break; case 2: cquad.z = old_z = max4f(old_p1->z, old_p0->z, p0->z, p1->z); break; case 3: default: cquad.z = 0.0; break; } { /*float dif=mult_vector(&vn, &view.light); float ln=lightparams[lightmode].a + lightparams[lightmode].d*MAX(0.0,dif); cquad.col = scale_color(Machine->pens[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)], MIN(1.0,ln)); cquad.col = scale_color(Machine->pens[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)], MIN(1.0,ln)); */ float dif=mult_vector(&vn, &view.light); float spec=compute_specular(&vn,&view.light,dif,lightmode); float ln=lightparams[lightmode].a + lightparams[lightmode].d*MAX(0.0,dif) + spec; int lumval=255.0*MIN(1.0,ln); int color=paletteram16[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)]; int r=(color>>0x0)&0x1f; int g=(color>>0x5)&0x1f; int b=(color>>0xA)&0x1f; lumval>>=2; //there must be a luma translation table somewhere if(lumval>0x3f) lumval=0x3f; else if(lumval<0) lumval=0; r=(model1_color_xlat[(r<<8)|lumval|0x0]>>3)&0x1f; g=(model1_color_xlat[(g<<8)|lumval|0x2000]>>3)&0x1f; b=(model1_color_xlat[(b<<8)|lumval|0x4000]>>3)&0x1f; cquad.col=(r<<10)|(g<<5)|(b<<0); } if(flags & 0x00002000) cquad.col |= MOIRE; fclip_push_quad(0, &cquad); next: poly_adr += 10; switch(link) { case 0: case 2: old_p0 = p0; old_p1 = p1; break; case 1: old_p1 = p0; break; case 3: old_p0 = p1; break; } } } static UINT16 *push_direct(UINT16 *list) { UINT32 flags; UINT32 tex_adr, lum, v1, v2; struct point *old_p0, *old_p1, *p0, *p1; int link, type; float z; struct quad cquad; tex_adr = readi(list); v1 = readi(list+2); v2 = readi(list+10); old_p0 = pointpt++; old_p1 = pointpt++; old_p0->x = readf(list+4); old_p0->y = readf(list+6); old_p0->z = readf(list+8); old_p1->x = readf(list+12); old_p1->y = readf(list+14); old_p1->z = readf(list+16); LOG_TGP("VIDEOD start direct\n"); LOG_TGP("VIDEOD (%f, %f, %f) (%f, %f, %f)\n", old_p0->x, old_p0->y, old_p0->z, old_p1->x, old_p1->y, old_p1->z); // transform_point(old_p0); // transform_point(old_p1); if(old_p0->z > 0) project_point_direct(old_p0); else old_p0->s.x = old_p0->s.y = 0; if(old_p1->z > 0) project_point_direct(old_p1); else old_p1->s.x = old_p1->s.y = 0; list += 18; for(;;) { flags = readi(list); type = flags & 3; if(!type) break; if(flags & 0x00001000) tex_adr ++; // list+2 is luminosity // list+4 is 0? // list+12 is z? p0 = pointpt++; p1 = pointpt++; lum = readi(list+2); v1 = readi(list+4); if(type == 2) { p0->x = readf(list+6); p0->y = readf(list+8); p0->z = readf(list+10); z = p0->z; LOG_TGP("VIDEOD %08x %08x (%f, %f, %f)\n", flags, lum, p0->x, p0->y, p0->z); *p1 = *p0; list += 12; } else { p0->x = readf(list+6); p0->y = readf(list+8); p0->z = readf(list+10); p1->x = readf(list+14); p1->y = readf(list+16); p1->z = readf(list+18); z = readf(list+12); LOG_TGP("VIDEOD %08x %08x (%f, %f, %f) (%f, %f, %f)\n", flags, lum, p0->x, p0->y, p0->z, p1->x, p1->y, p1->z); list += 20; } link = (flags >> 8) & 3; // transform_point(p0); // transform_point(p1); if(p0->z > 0) project_point_direct(p0); if(p1->z > 0) project_point_direct(p1); #if 1 if(old_p0 && old_p1) LOG_TGP("VIDEOD: %08x (%d, %d) (%d, %d) (%d, %d) (%d, %d)\n", flags, old_p0->s.x, old_p0->s.y, old_p1->s.x, old_p1->s.y, p0->s.x, p0->s.y, p1->s.x, p1->s.y); else LOG_TGP("VIDEOD: %08x (%d, %d) (%d, %d)\n", flags, p0->s.x, p0->s.y, p1->s.x, p1->s.y); #endif if(!link) goto next; cquad.p[0] = old_p1; cquad.p[1] = old_p0; cquad.p[2] = p0; cquad.p[3] = p1; cquad.z = z; { int lumval=((float) (lum>>24)) * 2.0; int color=paletteram16[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)]; int r=(color>>0x0)&0x1f; int g=(color>>0x5)&0x1f; int b=(color>>0xA)&0x1f; lumval>>=2; //there must be a luma translation table somewhere if(lumval>0x3f) lumval=0x3f; else if(lumval<0) lumval=0; r=(model1_color_xlat[(r<<8)|lumval|0x0]>>3)&0x1f; g=(model1_color_xlat[(g<<8)|lumval|0x2000]>>3)&0x1f; b=(model1_color_xlat[(b<<8)|lumval|0x4000]>>3)&0x1f; cquad.col=(r<<10)|(g<<5)|(b<<0); } //cquad.col = scale_color(Machine->pens[0x1000|(tgp_ram[tex_adr-0x40000] & 0x3ff)],((float) (lum>>24)) / 128.0); if(flags & 0x00002000) cquad.col |= MOIRE; fclip_push_quad(0, &cquad); next: switch(link) { case 0: case 2: old_p0 = p0; old_p1 = p1; break; case 1: old_p1 = p0; break; case 3: old_p0 = p1; break; } } return list+2; } static UINT16 *skip_direct(UINT16 *list) { UINT32 flags; int type; list += 18; for(;;) { flags = readi(list); type = flags & 3; if(!type) break; if(type == 2) list += 12; else list += 20; } return list+2; } static void draw_objects(mame_bitmap *bitmap, const rectangle *cliprect) { if(quadpt != quaddb) { LOG_TGP("VIDEO: sort&draw\n"); sort_quads(); draw_quads(bitmap, cliprect); } quadpt = quaddb; pointpt = pointdb; } static UINT16 *draw_direct(UINT16 *list, mame_bitmap *bitmap, const rectangle *cliprect) { UINT16 *res; LOG_TGP("VIDEO: draw direct %x\n", readi(list)); draw_objects(bitmap, cliprect); res = push_direct(list); unsort_quads(); draw_quads(bitmap, cliprect); quadpt = quaddb; pointpt = pointdb; return res; } static UINT16 *get_list(void) { if(!(listctl[0] & 4)) listctl[0] = (listctl[0] & ~0x40) | (listctl[0] & 8 ? 0x40 : 0); return listctl[0] & 0x40 ? model1_display_list1 : model1_display_list0; } static int get_list_number(void) { if(!(listctl[0] & 4)) listctl[0] = (listctl[0] & ~0x40) | (listctl[0] & 8 ? 0x40 : 0); return listctl[0] & 0x40 ? 0 : 1; } static void end_frame(void) { if((listctl[0] & 4) && (cpu_getcurrentframe() & 1)) listctl[0] ^= 0x40; } READ16_HANDLER( model1_listctl_r ) { if(!offset) return listctl[0] | 0x30; else return listctl[1]; } WRITE16_HANDLER( model1_listctl_w ) { COMBINE_DATA(listctl+offset); LOG_TGP("VIDEO: control=%08x\n", (listctl[1]<<16)|listctl[0]); } static void tgp_render(mame_bitmap *bitmap, const rectangle *cliprect) { render_done = 1; if((listctl[1] & 0x1f) == 0x1f) { UINT16 *list = get_list(); int zz = 0; LOG_TGP("VIDEO: render list %d\n", get_list_number()); memset(trans_mat, 0, sizeof(trans_mat)); trans_mat[0] = 1.0; trans_mat[4] = 1.0; trans_mat[8] = 1.0; for(;;) { int type = (list[1]<<16)|list[0]; glist=list; switch(type & 15) { case 0: list += 2; break; case 1: // 1 = plane 1 // 2 = ?? draw object (413d3, 17c4c, e) // 3 = plane 2 // 4 = ?? draw object (408a8, a479, 9) // 5 = decor // 6 = ?? draw object (57bd4, 387460, 2ad) if(1 || zz >= 666) push_object(readi(list+2), readi(list+4), readi(list+6)); list += 8; break; case 2: list = draw_direct(list+2, bitmap, cliprect); break; case 3: LOG_TGP("VIDEO: viewport (%d, %d, %d, %d, %d, %d, %d)\n", readi(list+2), readi16(list+4), readi16(list+6), readi16(list+8), readi16(list+10), readi16(list+12), readi16(list+14)); draw_objects(bitmap, cliprect); view.xc = readi16(list+4); view.yc = 383-(readi16(list+6)-39); view.x1 = readi16(list+8); view.y2 = 383-(readi16(list+10)-39); view.x2 = readi16(list+12); view.y1 = 383-(readi16(list+14)-39); recompute_frustrum(); list += 16; break; case 4: { int adr = readi(list+2); int len = readi(list+4)+1; int i; LOG_TGP("ZVIDEO: color write, adr=%x, len=%x\n", adr, len); for(i=0; i>8)&0xff))/255.0; lightparams[i+adr].s=((float) ((v>>16)&0xff))/255.0; lightparams[i+adr].p=(v>>24)&0xff; } list += 6+len*2; break; } case 7: LOG_TGP("VIDEO: code 7 (%d)\n", readi(list+2)); zz++; list += 4; break; case 8: LOG_TGP("VIDEO: select mode %08x\n", readi(list+2)); list += 4; break; case 9: LOG_TGP("VIDEO: zoom (%f, %f)\n", readf(list+2), readf(list+4)); view.zoomx = readf(list+2)*4; view.zoomy = readf(list+4)*4; recompute_frustrum(); list += 6; break; case 0xa: LOG_TGP("VIDEO: light vector (%f, %f, %f)\n", readf(list+2), readf(list+4), readf(list+6)); view.light.x = readf(list+2); view.light.y = readf(list+4); view.light.z = readf(list+6); normalize_vector(&view.light); list += 8; break; case 0xb: { int i; LOG_TGP("VIDEO: matrix (%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f)\n", readf(list+2), readf(list+4), readf(list+6), readf(list+8), readf(list+10), readf(list+12), readf(list+14), readf(list+16), readf(list+18), readf(list+20), readf(list+22), readf(list+24)); for(i=0; i<12; i++) trans_mat[i] = readf(list+2+2*i); list += 26; break; } case 0xc: LOG_TGP("VIDEO: trans (%f, %f)\n", readf(list+2), readf(list+4)); view.transx = readf(list+2); view.transy = readf(list+4); recompute_frustrum(); list += 6; break; case 0xf: case -1: goto end; default: LOG_TGP("VIDEO: unknown type %d\n", type); goto end; } } end: draw_objects(bitmap, cliprect); } } static void tgp_scan(void) { #if 0 if (input_code_pressed_once(KEYCODE_F)) { FILE *fp; fp=fopen("tgp-ram.bin", "w+b"); if (fp) { fwrite(tgp_ram, (0x100000-0x40000)*2, 1, fp); fclose(fp); } exit(0); } #endif if(!render_done && (listctl[1] & 0x1f) == 0x1f) { UINT16 *list = get_list(); // Skip everything but the data uploads LOG_TGP("VIDEO: scan list %d\n", get_list_number()); for(;;) { int type = (list[1]<<16)|list[0]; switch(type) { case 0: list += 2; break; case 1: list += 8; break; case 2: list = skip_direct(list+2); break; case 3: list += 16; break; case 4: { int adr = readi(list+2); int len = readi(list+4)+1; int i; LOG_TGP("ZVIDEO: scan color write, adr=%x, len=%x\n", adr, len); for(i=0; i>8)&0xff))/255.0; lightparams[i+adr].s=((float) ((v>>16)&0xff))/255.0; lightparams[i+adr].p=(v>>24)&0xff; //LOG_TGP(" %02X\n",v); } list += 6+len*2; break; } case 7: list += 4; break; case 8: list += 4; break; case 9: list += 6; break; case 0xa: list += 8; break; case 0xb: list += 26; break; case 0xc: list += 6; break; case 0xf: case -1: goto end; default: LOG_TGP("VIDEO: unknown type %d\n", type); goto end; } } end: ; } render_done = 0; } VIDEO_START(model1) { vxx=vyy=vzz=0; ayy = 0; sys24_tile_vh_start(machine, 0x3fff); poly_rom = (UINT32 *)memory_region(REGION_USER1); poly_ram = auto_malloc(0x400000*4); memset(poly_ram, 0, 0x400000*4); tgp_ram = auto_malloc((0x100000-0x40000)*2); memset(tgp_ram, 0, (0x100000-0x40000)*2); pointdb = auto_malloc(1000000*2*sizeof(struct point)); memset(pointdb, 0, 1000000*2*sizeof(struct point)); quaddb = auto_malloc(1000000*sizeof(struct quad)); memset(quaddb, 0, 1000000*sizeof(struct quad)); quadind = auto_malloc(1000000*sizeof(struct quad *)); memset(quadind, 0, 1000000*sizeof(struct quad *)); pointpt = pointdb; quadpt = quaddb; listctl[0] = listctl[1] = 0; state_save_register_global_pointer(tgp_ram, 0x100000-0x40000); state_save_register_global_pointer(poly_ram, 0x40000); state_save_register_global_array(listctl); } VIDEO_UPDATE(model1) { sys24_tile_update(machine); #if 0 { int mod = 0; double delta; delta = 1; if(input_code_pressed(KEYCODE_F)) { mod = 1; vxx -= delta; } if(input_code_pressed(KEYCODE_G)) { mod = 1; vxx += delta; } if(input_code_pressed(KEYCODE_H)) { mod = 1; vyy -= delta; } if(input_code_pressed(KEYCODE_J)) { mod = 1; vyy += delta; } if(input_code_pressed(KEYCODE_K)) { mod = 1; vzz -= delta; } if(input_code_pressed(KEYCODE_L)) { mod = 1; vzz += delta; } if(input_code_pressed(KEYCODE_U)) { mod = 1; ayy -= 0.05; } if(input_code_pressed(KEYCODE_I)) { mod = 1; ayy += 0.05; } if(mod) popmessage("%g,%g,%g:%g", vxx, vyy, vzz, ayy); } #endif ayyc = cos(ayy); ayys = sin(ayy); fillbitmap(priority_bitmap, 0, NULL); fillbitmap(bitmap, machine->pens[0], &machine->screen[0].visarea); sys24_tile_draw(machine, bitmap, cliprect, 6, 0, 0); sys24_tile_draw(machine, bitmap, cliprect, 4, 0, 0); sys24_tile_draw(machine, bitmap, cliprect, 2, 0, 0); sys24_tile_draw(machine, bitmap, cliprect, 0, 0, 0); tgp_render(bitmap, cliprect); sys24_tile_draw(machine, bitmap, cliprect, 7, 0, 0); sys24_tile_draw(machine, bitmap, cliprect, 5, 0, 0); sys24_tile_draw(machine, bitmap, cliprect, 3, 0, 0); sys24_tile_draw(machine, bitmap, cliprect, 1, 0, 0); return 0; } VIDEO_EOF(model1) { tgp_scan(); end_frame(); LOG_TGP("TGP: vsync\n"); }