#include "m_view.h" #include "main.h" #include "m_common_data.h" #include "m_field_info.h" #include "sys_matrix.h" #include "libultra/libultra.h" static void set_viewport(Vp* viewport, rect* screen_rect) { int width = screen_rect->r - screen_rect->l; int height = screen_rect->bottom - screen_rect->top; viewport->vp.vscale[0] = width * 4; viewport->vp.vscale[1] = height * 4; viewport->vp.vscale[2] = 511; viewport->vp.vscale[3] = 0; viewport->vp.vtrans[0] = (width + screen_rect->l) * 4; viewport->vp.vtrans[1] = (height + screen_rect->top) * 4; viewport->vp.vtrans[2] = 511; viewport->vp.vtrans[3] = 0; } extern void initView(View* view, GRAPH* graph) { view->graph = graph; view->screen.top = 0; view->screen.bottom = SCREEN_HEIGHT; view->screen.l = 0; view->screen.r = SCREEN_WIDTH; view->fovY = 20.0f; view->near = 200.0f; if (Common_Get(field_type) != mFI_FIELDTYPE2_FG) { view->near = 20.0f; } view->far = 1600.0f; view->scale = 1.0f; view->eye.x = 0.0f; view->eye.y = 0.0f; view->eye.z = -1.0f; /* copy -> paste bug here */ #ifndef BUGFIXES view->center.x = 0.0f; view->center.x = 0.0f; view->center.x = 0.0f; #else view->center.x = 0.0f; view->center.y = 0.0f; view->center.z = 0.0f; #endif view->up.x = 0.0f; view->up.y = 1.0f; view->up.z = 0.0f; view->flag = VIEW_UPDATE_LOOKAT | VIEW_UPDATE_SCISSOR | VIEW_UPDATE_PERSPECTIVE; stretchViewInit(view); } extern void setLookAtView(View* view, xyz_t* eye, xyz_t* center, xyz_t* up) { if (eye->x == center->x && eye->z == center->z) { eye->x += 0.1f; } view->eye = *eye; view->center = *center; view->up = *up; view->flag |= VIEW_UPDATE_LOOKAT; } extern void setScaleView(View* view, f32 scale) { view->scale = scale; view->flag |= VIEW_UPDATE_PERSPECTIVE; } extern void setPerspectiveView(View* view, f32 fovY, f32 near, f32 far) { view->fovY = fovY; view->near = near; view->far = far; view->flag |= VIEW_UPDATE_PERSPECTIVE; } extern void setScissorView(View* view, rect* screen) { view->screen = *screen; view->flag |= VIEW_UPDATE_SCISSOR; } static void setScissorX(Gfx** gfx_p, int left, int top, int right, int bottom) { Gfx* gfx = *gfx_p; if (left == 0 && top == 0 && right == SCREEN_WIDTH && bottom == SCREEN_HEIGHT) { right *= 2; bottom *= 2; } gDPSetScissor(gfx++, G_SC_NON_INTERLACE, left, top, right, bottom); *gfx_p = gfx; } static void setScissor(View* view) { GRAPH* g = view->graph; int left = view->screen.l; int top = view->screen.top; int right = view->screen.r; int bottom = view->screen.bottom; Gfx* gfx; OPEN_DISP(g); gfx = NOW_POLY_OPA_DISP; setScissorX(&gfx, left, top, right, bottom); SET_POLY_OPA_DISP(gfx); gfx = NOW_POLY_XLU_DISP; setScissorX(&gfx, left, top, right, bottom); SET_POLY_XLU_DISP(gfx); gfx = NOW_SHADOW_DISP; setScissorX(&gfx, left, top, right, bottom); SET_SHADOW_DISP(gfx); gfx = NOW_LIGHT_DISP; setScissorX(&gfx, left, top, right, bottom); SET_LIGHT_DISP(gfx); CLOSE_DISP(g); } extern int stretchViewInit(View* view) { view->stretch.target_rotate.x = 0.0f; view->stretch.target_rotate.y = 0.0f; view->stretch.target_rotate.z = 0.0f; view->stretch.target_scale.x = 1.0f; view->stretch.target_scale.y = 1.0f; view->stretch.target_scale.z = 1.0f; view->stretch.rotate = view->stretch.target_rotate; view->stretch.scale = view->stretch.target_scale; view->stretch.step = 0.0f; return 0; } static int do_stretch_view(View* view, Mtx* mtx) { f32 step = view->stretch.step; if (step == 0.0f) { return FALSE; } else if (step == 1.0f) { view->stretch.rotate = view->stretch.target_rotate; view->stretch.scale = view->stretch.target_scale; view->stretch.step = 0.0f; } else { view->stretch.rotate.x += view->stretch.step * (view->stretch.target_rotate.x - view->stretch.rotate.x); view->stretch.rotate.y += view->stretch.step * (view->stretch.target_rotate.y - view->stretch.rotate.y); view->stretch.rotate.z += view->stretch.step * (view->stretch.target_rotate.z - view->stretch.rotate.z); view->stretch.scale.x += view->stretch.step * (view->stretch.target_scale.x - view->stretch.scale.x); view->stretch.scale.y += view->stretch.step * (view->stretch.target_scale.y - view->stretch.scale.y); view->stretch.scale.z += view->stretch.step * (view->stretch.target_scale.z - view->stretch.scale.z); } { s_xyz rot; MtxF mtx_f; rot.x = view->stretch.rotate.x * 10430.378f; // 57.3 degrees? rot.y = view->stretch.rotate.y * 10430.378f; rot.z = view->stretch.rotate.z * 10430.378f; /* push matrix to current */ Matrix_MtxtoMtxF(mtx, &mtx_f); Matrix_put(&mtx_f); /* do rotation */ Matrix_RotateX(rot.x, 1); Matrix_RotateY(rot.y, 1); Matrix_RotateZ(rot.z, 1); /* do scaling */ Matrix_scale(view->stretch.scale.x, view->stretch.scale.y, view->stretch.scale.z, 1); /* undo rotation */ Matrix_RotateZ(-rot.z, 1); Matrix_RotateY(-rot.y, 1); Matrix_RotateX(-rot.x, 1); /* update matrix */ _Matrix_to_Mtx(mtx); } return TRUE; } extern int showView(View* view, int flag_mask) { if (((flag_mask >> 4) | (flag_mask & view->flag)) & VIEW_UPDATE_ORTHOGRAPHIC) { return showOrthoView(view); } else { return showPerspectiveView(view); } } extern int showPerspectiveView(View* view) { GRAPH* g = view->graph; Vp* vp; Mtx* mtx; OPEN_DISP(g); /* update viewport */ vp = GRAPH_ALLOC_TYPE(g, Vp, 1); set_viewport(vp, &view->screen); view->viewport = *vp; /* update scissor */ setScissor(view); /* push viewport */ gSPViewport(NOW_POLY_OPA_DISP++, vp); gSPViewport(NOW_POLY_XLU_DISP++, vp); gSPViewport(NOW_SHADOW_DISP++, vp); gSPViewport(NOW_LIGHT_DISP++, vp); gSPViewport(NOW_BG_OPA_DISP++, vp); gSPViewport(NOW_BG_XLU_DISP++, vp); /* update perspective matrix */ mtx = GRAPH_ALLOC_TYPE(g, Mtx, 1); view->p_projection = mtx; guPerspective( mtx, &view->normal, view->fovY, (f32)(view->screen.r - view->screen.l) / (f32)(view->screen.bottom - view->screen.top), view->near, view->far, view->scale ); view->mtx_projection = *mtx; do_stretch_view(view, mtx); gSPPerspNormalize(NOW_POLY_OPA_DISP++, view->normal); gSPMatrix(NOW_POLY_OPA_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPPerspNormalize(NOW_POLY_XLU_DISP++, view->normal); gSPMatrix(NOW_POLY_XLU_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPPerspNormalize(NOW_SHADOW_DISP++, view->normal); gSPMatrix(NOW_SHADOW_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPPerspNormalize(NOW_LIGHT_DISP++, view->normal); gSPMatrix(NOW_LIGHT_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPPerspNormalize(NOW_BG_OPA_DISP++, view->normal); gSPMatrix(NOW_BG_OPA_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPPerspNormalize(NOW_BG_XLU_DISP++, view->normal); gSPMatrix(NOW_BG_XLU_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); /* update look-at (viewing) matrix */ mtx = GRAPH_ALLOC_TYPE(g, Mtx, 1); view->p_viewing = mtx; guLookAt( mtx, view->eye.x, view->eye.y, view->eye.z, view->center.x, view->center.y, view->center.z, view->up.x, view->up.y, view->up.z ); view->mtx_viewing = *mtx; gSPMatrix(NOW_POLY_OPA_DISP++, mtx, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); gSPMatrix(NOW_POLY_XLU_DISP++, mtx, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); gSPMatrix(NOW_SHADOW_DISP++, mtx, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); gSPMatrix(NOW_LIGHT_DISP++, mtx, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); gSPMatrix(NOW_BG_OPA_DISP++, mtx, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); gSPMatrix(NOW_BG_XLU_DISP++, mtx, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); CLOSE_DISP(g); return TRUE; } extern int showOrthoView(View* view) { GRAPH* g = view->graph; Vp* vp; Mtx* mtx; OPEN_DISP(g); /* update viewport */ vp = GRAPH_ALLOC_TYPE(g, Vp, 1); set_viewport(vp, &view->screen); view->viewport = *vp; /* update scissor */ setScissor(view); /* push viewport */ gSPViewport(NOW_POLY_OPA_DISP++, vp); gSPViewport(NOW_POLY_XLU_DISP++, vp); gSPViewport(NOW_SHADOW_DISP++, vp); gSPViewport(NOW_LIGHT_DISP++, vp); gSPViewport(NOW_OVERLAY_DISP++, vp); gSPViewport(NOW_BG_OPA_DISP++, vp); gSPViewport(NOW_BG_XLU_DISP++, vp); /* update orthographic proj matrix */ mtx = GRAPH_ALLOC_TYPE(g, Mtx, 1); view->p_projection = mtx; guOrtho( mtx, -(f32)ScreenWidth / 2.0f, (f32)ScreenWidth / 2.0f, -(f32)ScreenHeight / 2.0f, (f32)ScreenHeight / 2.0f, view->near, view->far, view->scale ); view->mtx_projection = *mtx; gSPMatrix(NOW_POLY_OPA_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPMatrix(NOW_POLY_XLU_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPMatrix(NOW_SHADOW_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPMatrix(NOW_LIGHT_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPMatrix(NOW_BG_OPA_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); gSPMatrix(NOW_BG_XLU_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); CLOSE_DISP(g); return TRUE; } extern int showView1(View* view, int flag_mask, Gfx** gfx_p) { Gfx* gfx; GRAPH* g; int flags; gfx = *gfx_p; flag_mask = (flag_mask >> 4) | (flag_mask & view->flag); g = view->graph; OPEN_DISP(g); if (flag_mask & VIEW_UPDATE_SCISSOR) { Gfx* gfx_save; Vp* vp = GRAPH_ALLOC_TYPE(g, Vp, 1); set_viewport(vp, &view->screen); view->viewport = *vp; gDPPipeSync(gfx++); gfx_save = gfx; setScissorX(&gfx_save, view->screen.l, view->screen.top, view->screen.r, view->screen.bottom); gfx = gfx_save; gSPViewport(gfx++, vp); } if (flag_mask & VIEW_UPDATE_ORTHOGRAPHIC) { Mtx* m = GRAPH_ALLOC_TYPE(g, Mtx, 1); view->p_projection = m; guOrtho( m, -(f32)ScreenWidth / 2.0f, (f32)ScreenWidth / 2.0f, -(f32)ScreenHeight / 2.0f, (f32)ScreenHeight / 2.0f, view->near, view->far, view->scale ); view->mtx_projection = *m; gSPMatrix(gfx++, m, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); } else if (flag_mask & (VIEW_UPDATE_SCISSOR | VIEW_UPDATE_PERSPECTIVE)) { Mtx* m = GRAPH_ALLOC_TYPE(g, Mtx, 1); view->p_projection = m; guPerspective( m, &view->normal, view->fovY, (f32)(view->screen.r - view->screen.l) / (f32)(view->screen.bottom - view->screen.top), view->near, view->far, view->scale ); view->mtx_projection = *m; gSPPerspNormalize(gfx++, view->normal); gSPMatrix(gfx++, m, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); } if (flag_mask & VIEW_UPDATE_LOOKAT) { Mtx* m = GRAPH_ALLOC_TYPE(g, Mtx, 1); view->p_viewing = m; guLookAt( m, view->eye.x, view->eye.y, view->eye.z, view->center.x, view->center.y, view->center.z, view->up.x, view->up.y, view->up.z ); view->mtx_viewing = *m; gSPMatrix(gfx++, m, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); } CLOSE_DISP(g); view->flag = VIEW_UPDATE_NONE; *gfx_p = gfx; return TRUE; }