Files
ac-decomp/rel/m_view.c
T
2023-06-16 22:02:37 -04:00

438 lines
11 KiB
C

#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;
}