/******************************************************************************** * * * Module: * * NsCamera * * Description: * * Functionality to set up cameras and minipulate them. * * Written by: * * Paul Robinson * * Copyright: * * 2001 Neversoft Entertainment - All rights reserved. * * * ********************************************************************************/ /******************************************************************************** * Includes. * ********************************************************************************/ #include #include "p_camera.h" #include "p_prim.h" #include "p_gx.h" /******************************************************************************** * Defines. * ********************************************************************************/ #define RwV3dDotProductMacro(a, b) \ ((((( (((a)->x) * ((b)->x))) + \ ( (((a)->y) * ((b)->y))))) + \ ( (((a)->z) * ((b)->z))))) \ #define RwV3dScaleMacro(o, a, s) \ { \ (o)->x = (((a)->x) * ( (s))); \ (o)->y = (((a)->y) * ( (s))); \ (o)->z = (((a)->z) * ( (s))); \ } \ #define RwV3dIncrementScaledMacro(o, a, s) \ { \ (o)->x += (((a)->x) * ( (s))); \ (o)->y += (((a)->y) * ( (s))); \ (o)->z += (((a)->z) * ( (s))); \ } \ /******************************************************************************** * Structures. * ********************************************************************************/ /******************************************************************************** * Local variables. * ********************************************************************************/ NsVector movement( 0.0f, 0.0f, 0.0f ); NsVector position( 0.0f, 0.0f, 0.0f ); NsVector rotation( 0.0f, 0.0f, 0.0f ); NsMatrix temp0; NsMatrix temp1; NsMatrix sceneMat; NsMatrix skyMat; /******************************************************************************** * Forward references. * ********************************************************************************/ /******************************************************************************** * Externs. * ********************************************************************************/ extern PADStatus padData[PAD_MAX_CONTROLLERS]; // game pad state PADStatus * pPad = &padData[0]; /******************************************************************************** * * * Method: * * NsCamera * * Inputs: * * * * Output: * * * * Description: * * Generates a camera object. * * * ********************************************************************************/ NsCamera::NsCamera() { // Default border settings. orthographic( 0, 0, 640, 448 ); // Default up vector: y is up. m_up.set( 0.0f, 1.0f, 0.0f ); // Default position. m_camera.set( 0.0f, 0.0f, 0.0f ); // No frame. m_pFrame = NULL; } /******************************************************************************** * * * Method: * * NsCamera * * Inputs: * * * * Output: * * * * Description: * * Deletes a camera object. * * * ********************************************************************************/ NsCamera::~NsCamera() { // if ( m_pFrame ) delete m_pFrame; } void NsCamera::pos ( float x, float y, float z ) { m_camera.set( x, y, z ); } void NsCamera::up ( float x, float y, float z ) { m_up.set( x, y, z ); } void NsCamera::lookAt ( float x, float y, float z ) { NsVector lookat; lookat.set( x, y, z ); m_matrix.lookAt( &m_camera, &m_up, &lookat ); } float line_x0 = 0.0f; float line_y0 = 100.0f; float line_z0 = 0.0f; float line_x1 = 0.0f; float line_y1 = 0.0f; float line_z1 = 0.0f; float gPosX = 320; float gPosY = 240; float gPosZ = 0; float gUpX = 0; float gUpY = 1; float gUpZ = 0; float gAtX = 320; float gAtY = 240; float gAtZ = 1; void NsCamera::_setCurrent ( NsMatrix * object ) { NsMatrix m; NsMatrix m2; movement.set( 0.0f, 0.0f, 0.0f ); // Test pad for rotation. // if ( pPad->button & PAD_BUTTON_X ) { // // Move line. // if ( ( pPad->stickY > 8 ) || ( pPad->stickY < -8 ) ) { // line_z0 -= ((float)pPad->stickY)/256.0f; // line_z1 -= ((float)pPad->stickY)/256.0f; // } // if ( ( pPad->stickX > 8 ) || ( pPad->stickX < -8 ) ) { // line_x0 += ((float)pPad->stickX)/256.0f; // line_x1 += ((float)pPad->stickX)/256.0f; // } // if ( pPad->button & PAD_BUTTON_Y ) { // line_y0 -= 0.25f; // line_y1 -= 0.25f; // } // if ( pPad->button & PAD_BUTTON_B ) { // line_y0 += 0.25f; // line_y1 += 0.25f; // } // } else { // // Rotation. // if ( ( pPad->stickY > 8 ) || ( pPad->stickY < -8 ) ) { // rotation.x = rotation.x - ((float)pPad->stickY)/512.0f; // } // if ( ( pPad->stickX > 8 ) || ( pPad->stickX < -8 ) ) { // rotation.y = rotation.y + ((float)pPad->stickX)/512.0f; // } // } // // Test pad for movement. // if ( ( pPad->substickY > 8 ) || ( pPad->substickY < -8 ) ) { // movement.z = -((float)pPad->substickY)/64.0f; // } // if ( ( pPad->substickX > 8 ) || ( pPad->substickX < -8 ) ) { // movement.x = -((float)-pPad->substickX)/64.0f; // } // if ( pPad->button & PAD_BUTTON_Y ) movement.y -= 0.5f; // if ( pPad->button & PAD_BUTTON_B ) movement.y += 0.5f; // Generate rotation matrix. temp0.rotateX( rotation.x, NsMatrix_Combine_Replace ); temp1.rotateY( rotation.y, NsMatrix_Combine_Replace ); skyMat.cat( temp0, temp1 ); // Generate movement vector by multiplying the desired movement vector // by the inverse of the view matrix. temp1.invert( skyMat ); temp1.multiply( &movement, &movement ); position.add( movement ); // Generate the translation matrix, and concatonate the rotation matrix. sceneMat.translate( &position, NsMatrix_Combine_Replace ); sceneMat.cat( skyMat, sceneMat ); // m.identity(); // m2.identity(); m.copy( *object ); m2.copy( *object ); m.setRight( 1.0f, 0.0f, 0.0f ); m.setUp( 0.0f, 1.0f, 0.0f ); m.setAt( 0.0f, 0.0f, 1.0f ); m.setPos( -m.getPosX(), -m.getPosY(), -m.getPosZ() ); m2.setPos( 0.0f, 0.0f, 0.0f ); m.cat( m2, m ); m.cat( sceneMat, m ); if ( m_type == GX_ORTHOGRAPHIC ) { m2.copy( m_matrix ); NsVector vs( m_clip_w / viewx, m_clip_h / viewy, 1.0f ); m2.scale( &vs, NsMatrix_Combine_Post ); m_current.cat( m2, m ); GX::SetScissorBoxOffset ( ( 320 - ( m_clip_w / 2 ) ) - m_clip_x, ( 224 - ( m_clip_h / 2 ) ) - m_clip_y ); GX::SetScissor (320 - ( m_clip_w / 2 ), 224 - ( m_clip_h / 2 ), m_clip_w, m_clip_h ); } else { m_current.cat( m_matrix, m ); GX::SetScissorBoxOffset ( 0, 0 ); } GX::LoadPosMtxImm( m_current.m_matrix, GX_PNMTX0 ); // This makes the perspective center be at the center of the viewport. //GXSetScissorBoxOffset ( ( 320 - ( m_clip_w / 2 ) ) - m_clip_x, ( 224 - ( m_clip_h / 2 ) ) - m_clip_y ); //GXSetScissor (320 - ( m_clip_w / 2 ), 224 - ( m_clip_h / 2 ), m_clip_w, m_clip_h ); // GXSetScissor (0, 0, m_clip_w, 480/*m_clip_h*/ ); // Previously in viewport. GX::SetProjection( m_viewmatrix, m_type ); } void NsCamera::begin ( void ) { if ( m_pFrame ) { _setCurrent ( m_pFrame->getModelMatrix() ); } else { NsMatrix mId; mId.identity(); _setCurrent ( &mId ); } } void NsCamera::offset ( float x, float y, float z ) { NsMatrix offset; NsVector v( x, y, z ); offset.copy( m_current ); offset.translate( &v, NsMatrix_Combine_Pre ); GX::LoadPosMtxImm( offset.m_matrix, GX_PNMTX0 ); } void NsCamera::end ( void ) { } // Previously in viewport. void NsCamera::perspective ( u32 x, u32 y, u32 width, u32 height ) { float left = -0.080F; float top = 0.060F; float znear = 2.0F; float zfar = 40000.0F; MTXFrustum ( m_viewmatrix, top, -top, left, -left, znear, zfar ); m_type = GX_PERSPECTIVE; clip ( x, y, width, height ); // Default matrix - just like PS2 - aaaah. pos ( 0, 0, 0 ); up ( 0, 1, 0 ); lookAt ( 0, 0, 1 ); } // Previously in viewport. void NsCamera::perspective ( float width, float height, float znear, float zfar ) { MTXFrustum ( m_viewmatrix, height, -height, -width, width, znear, zfar ); m_type = GX_PERSPECTIVE; clip ( 0, 0, 640, 448 ); // Default matrix - just like PS2 - aaaah. pos ( 0, 0, 0 ); up ( 0, 1, 0 ); lookAt ( 0, 0, 1 ); } void NsCamera::perspective ( float fovy, float aspect ) { MTXPerspective ( m_viewmatrix, fovy, aspect, 2.0f, 40000.0f ); m_type = GX_PERSPECTIVE; // Default matrix - just like PS2 - aaaah. pos ( 0, 0, 0 ); up ( 0, 1, 0 ); lookAt ( 0, 0, 1 ); } void NsCamera::orthographic ( u32 x, u32 y, u32 width, u32 height ) { float left = -320.0f; float top = 224.0f; //40.0F; float znear = 1.0F; float zfar = 100000.0F; MTXOrtho ( m_viewmatrix, top, -top, left, -left, znear, zfar ); m_type = GX_ORTHOGRAPHIC; clip ( x, y, width, height ); m_matrix.setRight( 1.0f, 0.0f, 0.0f ); m_matrix.setUp( 0.0f, -1.0f, 0.0f ); m_matrix.setAt( 0.0f, 0.0f, 1.0f ); m_matrix.setPosX( -320 ); m_matrix.setPosY( 224 ); m_matrix.setPosZ( 0 ); // Default viewplane size. setViewWindow( width, height ); } void NsCamera::clip ( u32 x, u32 y, u32 width, u32 height ) { m_clip_x = x; m_clip_y = y; m_clip_w = width; m_clip_h = height; } void NsCamera::setViewWindow( float x, float y ) { viewx = x; viewy = y; view1x = 1.0f / x; view1y = 1.0f / y; } // // Generate rotation matrix. //// rotation.x = 32.0f; // rotation.y += 0.5f; // MTXRotDeg(temp0, 'x', rotation.x ); // MTXRotDeg(temp1, 'y', rotation.y ); // MTXConcat(temp0, temp1, skyMat); // // // Generate movement vector by multiplying the desired movement vector // // by the inverse of the view matrix. // MTXInverse ( skyMat, temp1 ); // MTXMultVec(temp1, &movement, &movement ); // position.x += movement.x; // position.y += movement.y; // position.z += movement.z; // // // Generate the translation matrix, and concatonate the rotation matrix. // MTXTrans (sceneMat, position.x, position.y, position.z ); // MTXConcat(skyMat, sceneMat, sceneMat); NsMatrix * NsCamera::getViewMatrix ( void ) { float scale; NsVector vVector; NsVector temp; NsVector cpos; NsMatrix * cameraLTM; cameraLTM = getFrame()->getModelMatrix(); cpos.set( cameraLTM->getPosX(), cameraLTM->getPosY(), cameraLTM->getPosZ() ); /*INDENT OFF */ /* * Builds the concatenation of the following matrices: * * [ [ -Right_X, Up_X, At_X, 0 ] re-orient * [ -Right_Y, Up_Y, At_Y, 0 ] * [ -Right_Z, Up_Z, At_Z, 0 ] * [ pos Right, -(pos Up), -(pos At), 1 ] ] * [ [ 1, 0, 0, 0 ] offset eye * [ 0, 1, 0, 0 ] * [ off_x, off_y, 1, 0 ] * [ -off_x, -off_y, 0, 1 ] ] * [ [ 0.5 / width, 0, 0, 0 ] scale for view window * [ 0, 0.5 / height, 0, 0 ] * [ 0, 0, 1, 0 ] * [ 0, 0, 0, 1 ] ] * [ [ 1, 0, 0, 0 ] project & flip y * [ 0, -1, 0, 0 ] * [ 0, 0, 1, 1 ] DIFFERS FROM PARALLEL * [ 0, 0, 0, 0 ] ] * [ [ 1, 0, 0, 0 ] xform XY * [ 0, 1, 0, 0 ] from [-0.5..0.5]^2 * [ 0, 0, 1, 0 ] to [0..1]^2 * [ 0.5, 0.5, 0, 1 ] ] */ /*INDENT ON */ /* At */ scale = (view1x * ((float) ((-0.5)))); vVector.scale( *cameraLTM->getRight(), scale ); scale = ( 0.5f - (scale * 0.0f) ); temp.scale( *cameraLTM->getAt(), scale ); vVector.add( temp ); m_view.setRight( &vVector ); m_view.setRightX( vVector.x ); m_view.setUpX( vVector.y ); m_view.setAtX( vVector.z ); m_view.setPosX ( 0.5f - ( scale + cpos.dot( vVector ) ) ); /* Up */ scale = ( view1y * -0.5f ); vVector.scale( *cameraLTM->getUp(), scale ); scale = ( 0.5f + (scale * 0.0f) ); temp.scale( *cameraLTM->getAt(), scale ); vVector.add( temp ); m_view.setRightY( vVector.x ); m_view.setUpY( vVector.y ); m_view.setAtY( vVector.z ); m_view.setPosY ( 0.5f - ( scale + cpos.dot( vVector ) ) ); /* At */ m_view.setRightZ(cameraLTM->getAt()->x ); m_view.setUpZ( cameraLTM->getAt()->y ); m_view.setAtZ( cameraLTM->getAt()->z ); m_view.setPosZ ( -cpos.dot( *cameraLTM->getAt() ) ); return &m_view; }