/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * Additional copyright for this file: * Copyright (C) 1999-2000 Revolution Software Ltd. * This code is based on source code created by Revolution Software, * used with permission. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "engines/icb/common/px_common.h" #include "engines/icb/debug.h" #include "engines/icb/gfx/psx_pcdefines.h" #include "engines/icb/actor_pc.h" #include "engines/icb/gfx/psx_scrn.h" #include "engines/icb/gfx/psx_pchmd.h" #include "engines/icb/global_objects_psx.h" #include "engines/icb/drawpoly_pc.h" #include "engines/icb/light_pc.h" #include "engines/icb/softskin_pc.h" #include "engines/icb/shadow_pc.h" #include "engines/icb/common/px_capri_maths.h" #include "engines/icb/gfx/psx_poly.h" #include "common/system.h" namespace ICB { int32 tutorialMode = 0; #define MAX_LW_MATRICES 64 #if _PSX_ON_PC #define MAX_VECTORS 4096 #else #define MAX_VECTORS 512 #endif int32 littpc; int32 mattpc; int32 verttpc; int32 polytpc; int32 hiertpc; int32 shadtpc; // Local prototypes void drawBboxPC(SVECTOR *scrn, CVECTOR colour); void drawOutlinePC(SVECTOR *min, SVECTOR *max, CVECTOR colour); void DrawModel4PC(RapAPI *mrap, int32 poseBone, MATRIXPC *lw, MATRIXPC *local2screen, int32 uvframe, uint32 debug, SVECTOR *bbox, SVECTOR *minbbox, SVECTOR *maxbbox); // My home grown replacement for the DrawActor routine // which uses home grown replacement to do the drawing // and also does the skinning using the co-ordinate animation data // using soft-skinning specific data void DrawActor4PC(psxActor *actor, psxCamera *camera, Bone_Frame *frame, RapAPI *mesh, RapAPI *pose, RapAPI *smesh, PSXrgb *ambient, PSXLampList *lamplist, PSXShadeList *shadelist, int32 nShadows, SVECTORPC *p_n, int32 *p_d, uint32 debug, int32 uvframe, BoneDeformation **boneDeforms, int32 *brightness, MATRIXPC *local2screen // filled in ) { // The position actor->pos is the world position // lw is the local to world matrix // camera->view is the world to screen matrix (without projection) MATRIXPC ll, lw; MATRIXPC lightDirects; MATRIXPC bone2actor[MAX_LW_MATRICES]; MatrixHierarchyPC skeleton[MAX_LW_MATRICES]; MATRIXPC *lwPtr; BoneLink *bones = RapAPIObject::GetBonePtr(mesh); SVECTOR poseBox[8]; SVECTOR poseMinBox, poseMaxBox; SVECTOR *shadowBox[MAX_SHADOWS] = {actor->shadowBox[0], actor->shadowBox[1], actor->shadowBox[2]}; // Set the focal length in the GTE gte_SetGeomScreen_pc(camera->focLen * ZSCALE); int32 p, flag; // Prepare the gte lighting variables and make the // light direction matrix // Sets the direciton lights colour matrix // Sets the ambient colour // Fills in the lightDirects matrix // prepareLightsGlobal( &lightDirects ); littpc = g_system->getMillis(); LampInfo linfo[3]; VECTOR mpos; mpos.vx = actor->truePos.x; mpos.vy = actor->truePos.y; mpos.vz = actor->truePos.z; *brightness = prepareLightsPC(&mpos, ambient, lamplist, shadelist, &lightDirects, linfo); littpc = g_system->getMillis() - littpc; mattpc = g_system->getMillis(); // Loop over the bones in the hierarchy // pre-computing the conversion matrices if (mesh->nBones >= MAX_LW_MATRICES) { Fatal_error("ERROR Too many bones %d max %d", mesh->nBones, MAX_LW_MATRICES); } // loop over the skeleton : // Making the matrices // copy in the skeleton translations from the RAP file // make the rotation part from the angles in the RAB file MatrixHierarchyPC *bone = skeleton; BoneLink *skelPiece = bones; LinkedMatrix *angles = frame->bones; SVECTOR rot; uint32 b; for (b = 0; b < mesh->nBones; bone++, angles++, skelPiece++, b++) { // Make the translation part bone->matrix.t[0] = skelPiece->tx; bone->matrix.t[1] = skelPiece->ty; bone->matrix.t[2] = skelPiece->tz; // Make the rotation part ExpandSVECTOR(angles->crot, &rot); for (int32 d = 0; d < MAX_DEFORMABLE_BONES; d++) { if ((boneDeforms[d]) && ((int32)b == boneDeforms[d]->boneNumber)) { rot.vx = (int16)(rot.vx + boneDeforms[d]->boneValue.vx); rot.vy = (int16)(rot.vy + boneDeforms[d]->boneValue.vy); rot.vz = (int16)(rot.vz + boneDeforms[d]->boneValue.vz); } } RotMatrix_gte_pc(&rot, &(bone->matrix)); // Make the parent pointer : parent == nBones means not linked if (skelPiece->parent != mesh->nBones) { bone->parent = skeleton + skelPiece->parent; } else bone->parent = nullptr; } int32 hasUpperBodyDeform = 0; SVECTOR upperBodyDeform; // no upper body deform upperBodyDeform.vx = 0; upperBodyDeform.vy = 0; upperBodyDeform.vz = 0; // check for any bone transformations on bone 1 which will effect the gun position... for (int32 d = 0; d < MAX_DEFORMABLE_BONES; d++) { // if this is the upper body twist... (bone 1) if ((boneDeforms[d]) && (boneDeforms[d]->boneNumber == 1)) { hasUpperBodyDeform = 1; upperBodyDeform.vx = (int16)(upperBodyDeform.vx + boneDeforms[d]->boneValue.vx); upperBodyDeform.vy = (int16)(upperBodyDeform.vy + boneDeforms[d]->boneValue.vy); upperBodyDeform.vz = (int16)(upperBodyDeform.vz + boneDeforms[d]->boneValue.vz); } } // Is there an accesory to draw ? uint32 nBones = mesh->nBones; int32 pb = 0; if (frame->poseBone.parent != mesh->nBones) { pb = nBones; // Make the translation part bone->matrix.t[0] = frame->poseBone.tx; bone->matrix.t[1] = frame->poseBone.ty; bone->matrix.t[2] = frame->poseBone.tz; // we have an upper body deform if (hasUpperBodyDeform) { // first subtract hip-upperBody #define HIP_TO_BONE 50 bone->matrix.t[2] -= HIP_TO_BONE; bone->matrix.t[0] += 20; MATRIXPC matrix; SVECTOR gun_rot; gun_rot.vx = upperBodyDeform.vx; gun_rot.vy = upperBodyDeform.vy; gun_rot.vz = (int16)(48 * upperBodyDeform.vz / 64); RotMatrix_gte_pc(&gun_rot, &matrix); ApplyMatrixLV_pc(&matrix, (VECTOR *)&bone->matrix.t, (VECTOR *)&bone->matrix.t); bone->matrix.t[2] += HIP_TO_BONE; bone->matrix.t[0] -= 20; } // Make the rotation part ExpandSVECTOR(angles->crot, &rot); RotMatrix_gte_pc(&rot, &(bone->matrix)); if (hasUpperBodyDeform) { MATRIXPC matrix; RotMatrix_gte_pc(&upperBodyDeform, &matrix); gte_MulMatrix0_pc(&matrix, &(bone->matrix), &(bone->matrix)); } bone->parent = skeleton + frame->poseBone.parent; nBones++; } mattpc = g_system->getMillis() - mattpc; hiertpc = g_system->getMillis(); // Loop over the bones in the hierarchy // pre-computing the conversion matrices lwPtr = bone2actor; bone = skeleton; MatrixHierarchyPC *pcoord; MATRIXPC tempWorkm0; MATRIXPC tempWorkm1; VECTOR tempTvec; MATRIXPC *workm0; MATRIXPC *workm1; VECTOR *tvec; workm0 = &tempWorkm0; workm1 = &tempWorkm1; tvec = &tempTvec; for (b = 0; b < nBones; bone++, lwPtr++, b++) { // Store the units local-world matrix in the workm variable // Store the local-screen matrix in the ls array in hmdAnim pcoord = bone->parent; // Calculate Local-World Matrix // and store it in the work matrix for this co-ordinate *workm0 = bone->matrix; // Does it have a parent co-ordinate system ? // If so, then apply that coord system to current matrix while (pcoord) { // parent*daughter and then store in lwPtr *workm1 = pcoord->matrix; ApplyMatrixLV_pc(workm1, (VECTOR *)&workm0->t[0], tvec); gte_MulMatrix0_pc(workm1, workm0, workm0); workm0->t[0] = tvec->vx + workm1->t[0]; workm0->t[1] = tvec->vy + workm1->t[1]; workm0->t[2] = tvec->vz + workm1->t[2]; pcoord = pcoord->parent; } *lwPtr = *workm0; bone->parent = nullptr; bone->matrix = *workm0; } hiertpc = g_system->getMillis() - hiertpc; // Make a local to screen matrix // local2world is actor->lw // Calculate Local-Screen Matrix // Make the rotation matrix MATRIXPC cam_pc, act_pc; const int32 MSCALE = ONE_PC / ONE; cam_pc.m[0][0] = camera->view.m[0][0] * MSCALE; cam_pc.m[0][1] = camera->view.m[0][1] * MSCALE; cam_pc.m[0][2] = camera->view.m[0][2] * MSCALE; cam_pc.m[1][0] = camera->view.m[1][0] * MSCALE; cam_pc.m[1][1] = camera->view.m[1][1] * MSCALE; cam_pc.m[1][2] = camera->view.m[1][2] * MSCALE; cam_pc.m[2][0] = camera->view.m[2][0] * MSCALE * ZSCALE; cam_pc.m[2][1] = camera->view.m[2][1] * MSCALE * ZSCALE; cam_pc.m[2][2] = camera->view.m[2][2] * MSCALE * ZSCALE; cam_pc.t[0] = camera->view.t[0]; cam_pc.t[1] = camera->view.t[1]; cam_pc.t[2] = camera->view.t[2] * ZSCALE; act_pc.m[0][0] = actor->lw.m[0][0] * MSCALE; act_pc.m[0][1] = actor->lw.m[0][1] * MSCALE; act_pc.m[0][2] = actor->lw.m[0][2] * MSCALE; act_pc.m[1][0] = actor->lw.m[1][0] * MSCALE; act_pc.m[1][1] = actor->lw.m[1][1] * MSCALE; act_pc.m[1][2] = actor->lw.m[1][2] * MSCALE; act_pc.m[2][0] = actor->lw.m[2][0] * MSCALE; act_pc.m[2][1] = actor->lw.m[2][1] * MSCALE; act_pc.m[2][2] = actor->lw.m[2][2] * MSCALE; act_pc.t[0] = actor->lw.t[0]; act_pc.t[1] = actor->lw.t[1]; act_pc.t[2] = actor->lw.t[2]; gte_MulMatrix0_pc(&cam_pc, &act_pc, local2screen); ApplyMatrixLV_pc(&cam_pc, (VECTOR *)&(actor->lw.t[0]), (VECTOR *)&(local2screen->t[0])); local2screen->t[0] += cam_pc.t[0]; local2screen->t[1] += cam_pc.t[1]; local2screen->t[2] += cam_pc.t[2]; // Make the GTE local light matrix by lightDirects * local-world // destroys GTE rot matrix // SVECTOR trot; SVECTOR hip; MATRIXPC hipm; trot = actor->rot; // HIP is root bone in the hierarchy angles = frame->bones; ExpandSVECTOR(angles->crot, &hip); // Include the orientation of the HIP in the local-world transformation // So that the lighting is correct for HIP rotation e.g. lying down dead, turning, turning around on stairs // Note: hip axis is not aligned to local axis: // world axis: local.vx = hip.vx + 90 deg, local.vy = hip.vz, local.vz = hip.vy // Ignore the hip.vy - which represents roll because the hips roll independently of the whole body movement // e.g. when walking along rolling the hips ! trot.vx = (int16)(hip.vx + (ONE / 4)); trot.vy = (int16)(hip.vz); trot.vz = 0; // Make the rotation matrix to account for the hips orientation relative to the actor coords RotMatrix_gte_pc(&trot, &hipm); // Make the rotation matrix to account for the actor orientation in world coords RotMatrix_gte_pc(&actor->rot, &lw); // Make the combined matrix gte_MulMatrix0_pc(&lw, &hipm, &lw); gte_MulMatrix0_pc(&lightDirects, &lw, &ll); // Set the GTE lighting direction matrix gte_SetLightMatrix_pc(&ll); // Do the soft-skinning drawing of the model // use the linkage info in mesh file and the co-ordinate data // from the hmd file // Draw the model DrawModel4PC(mesh, -1, bone2actor, local2screen, uvframe, debug, actor->bboxScrn, &actor->minBbox, &actor->maxBbox); // At most 3 shadows ! if (nShadows > MAX_SHADOWS) { Fatal_error("ERROR Too many shadows %d max %d", nShadows, MAX_SHADOWS); } SVECTORPC ldirs[MAX_SHADOWS]; CVECTOR lcolours[MAX_SHADOWS]; int32 l; int32 ns = 0; int32 work; for (l = 0; l < nShadows; l++) { // Only use lights which are on and point downwards if ((linfo[l].intens != 0) && (linfo[l].direct.vy < 0)) { ldirs[ns].vx = (int16)linfo[l].direct.vx; ldirs[ns].vy = (int16)linfo[l].direct.vy; ldirs[ns].vz = (int16)linfo[l].direct.vz; work = (linfo[l].colour.vx >> 4); if (work > 255) work = 255; lcolours[ns].r = (uint8)work; work = (linfo[l].colour.vy >> 4); if (work > 255) work = 255; lcolours[ns].g = (uint8)work; work = (linfo[l].colour.vz >> 4); if (work > 255) work = 255; lcolours[ns].b = (uint8)work; ns++; } } // In simple shadow mode just have a single top-down BLACK shadow if (nShadows == -1) { ns = 1; ldirs[0].vx = 0; ldirs[0].vy = -4096; ldirs[0].vz = 0; lcolours[0].r = 0x80; lcolours[0].g = 0x80; lcolours[0].b = 0x80; } // In complex mode add a top-down BLACK shadow if no shadows are being // drawn if ((nShadows > 0) && (ns == 0)) { ns = 1; ldirs[0].vx = 0; ldirs[0].vy = -4096; ldirs[0].vz = 0; lcolours[0].r = 0x80; lcolours[0].g = 0x80; lcolours[0].b = 0x80; } // draw the shadow if (smesh != nullptr) { shadtpc = g_system->getMillis(); DrawShadow1PC(smesh, -1, bone2actor, &cam_pc, &act_pc, ns, ldirs, lcolours, p_n, p_d, debug, shadowBox, actor->shadowMinBox, actor->shadowMaxBox); shadtpc = g_system->getMillis() - shadtpc; actor->nShadows = ns; } else { actor->nShadows = 0; } // Draw the accessory if ((pose != nullptr) && (pb != 0)) { DrawModel4PC(pose, pb, bone2actor, local2screen, uvframe, debug, poseBox, &poseMinBox, &poseMaxBox); // WARNING // the accessory bounding box is not added onto the actors proper bounding box ! // it is only added onto the min, max bounding box outline // Add the accessory bounding box onto the min, max actors bounding box if (poseMinBox.vx < actor->minBbox.vx) actor->minBbox.vx = poseMinBox.vx; if (poseMinBox.vy < actor->minBbox.vy) actor->minBbox.vy = poseMinBox.vy; if (poseMinBox.vz < actor->minBbox.vz) actor->minBbox.vz = poseMinBox.vz; if (poseMaxBox.vx > actor->maxBbox.vx) actor->maxBbox.vx = poseMaxBox.vx; if (poseMaxBox.vy > actor->maxBbox.vy) actor->maxBbox.vy = poseMaxBox.vy; if (poseMaxBox.vz > actor->maxBbox.vz) actor->maxBbox.vz = poseMaxBox.vz; } // Set the local-screen matrix in the GTE gte_SetRotMatrix_pc(local2screen); gte_SetTransMatrix_pc(local2screen); gte_SetScreenScaleShift_pc(0); // Compute the screen position of the models local origin // Which is the translation part of the GTE matrix SVECTORPC origin; origin.vx = origin.vy = origin.vz = 0; SVECTORPC sxy0; gte_RotTransPers_pc(&origin, &sxy0, &p, &flag, (int32 *)&(actor->sPos.vz)); actor->sPos.vx = (int16)sxy0.vx; actor->sPos.vy = (int16)sxy0.vy; if (true) { // FIXME: Enable this with debug level / channel CVECTOR bboxColour = {(uint8)bboxRed, (uint8)bboxGreen, (uint8)bboxBlue, 0}; if (_drawBbox) drawBboxPC(actor->bboxScrn, bboxColour); CVECTOR sbColour = {240, 240, 240, 0}; if (_drawSolidBbox) drawSolidBboxPC(actor->bboxScrn, &sbColour); bboxColour.r = 255; bboxColour.g = 20; bboxColour.b = 180; if (_drawShadowBbox) { for (b = 0; b < actor->nShadows; b++) { drawBboxPC(shadowBox[b], bboxColour); } } // 2 LINE_F3's : e.g. a rectangle CVECTOR slColour; if (_drawSline) { slColour.r = (uint8)slineRed; slColour.g = (uint8)slineGreen; slColour.b = (uint8)slineBlue; drawOutlinePC(&actor->minBbox, &actor->maxBbox, slColour); } if (_drawShadowSline) { for (b = 0; b < actor->nShadows; b++) { slColour.r = (uint8)180; slColour.g = (uint8)(20 + b * 70); slColour.b = (uint8)255; drawOutlinePC(actor->shadowMinBox + b, actor->shadowMaxBox + b, slColour); } } } } void drawOutlinePC(SVECTOR *min, SVECTOR *max, CVECTOR colour) { LINE_F3 *line = (LINE_F3 *)drawpacket; setLineF3(line); setRGB0(line, colour.r, colour.g, colour.b); // minx, miny => maxx, miny => maxx, maxy setXY3(line, min->vx, min->vy, max->vx, min->vy, max->vx, max->vy); myAddPrimClip(min->vz, drawpacket); myAddPacket(sizeof(LINE_F3)); // maxx, maxy => minx, maxy => minx, miny line = (LINE_F3 *)drawpacket; setLineF3(line); setRGB0(line, colour.r, colour.g, colour.b); setXY3(line, max->vx, max->vy, min->vx, max->vy, min->vx, min->vy); myAddPrimClip(min->vz, drawpacket); myAddPacket(sizeof(LINE_F3)); } // New version using soft-skinning specific data-files void DrawModel4PC(RapAPI *mrap, int32 poseBone, MATRIXPC *lw, MATRIXPC *local2screen, int32 uvframe, uint32 debug, SVECTOR *bbox, SVECTOR *minbbox, SVECTOR *maxbbox) { SVECTORPC local[MAX_VECTORS]; SVECTORPC screen[MAX_VECTORS]; int16 xminLocal = +32767; int16 xmaxLocal = -32767; int16 yminLocal = +32767; int16 ymaxLocal = -32767; int16 zminLocal = +32767; int16 zmaxLocal = -32767; verttpc = g_system->getMillis(); int32 screenScale = mrap->worldScaleShift; int32 nVertices = softskinPC(mrap, poseBone, lw, local, &xminLocal, &xmaxLocal, &yminLocal, &ymaxLocal, &zminLocal, &zmaxLocal, screenScale); // So all the local positions have been made verttpc = g_system->getMillis() - verttpc; polytpc = g_system->getMillis(); // step 3 : draw the polygons using the list of created screen positions // Need to get the pointer to HMD stored data out of HMD file // Put the correct rot and trans matrix in place // transform model from world space to screen space gte_SetRotMatrix_pc(local2screen); gte_SetTransMatrix_pc(local2screen); gte_SetScreenScaleShift_pc(screenScale); int32 flag, p; int32 i; SVECTOR *pbbox; // Convert the bounding box from local co-ordinates into screen co-ordinates bbox[0].vx = xminLocal; bbox[0].vy = yminLocal; bbox[0].vz = zminLocal; bbox[1].vx = xminLocal; bbox[1].vy = yminLocal; bbox[1].vz = zmaxLocal; bbox[2].vx = xmaxLocal; bbox[2].vy = yminLocal; bbox[2].vz = zminLocal; bbox[3].vx = xmaxLocal; bbox[3].vy = yminLocal; bbox[3].vz = zmaxLocal; bbox[4].vx = xmaxLocal; bbox[4].vy = ymaxLocal; bbox[4].vz = zminLocal; bbox[5].vx = xmaxLocal; bbox[5].vy = ymaxLocal; bbox[5].vz = zmaxLocal; bbox[6].vx = xminLocal; bbox[6].vy = ymaxLocal; bbox[6].vz = zminLocal; bbox[7].vx = xminLocal; bbox[7].vy = ymaxLocal; bbox[7].vz = zmaxLocal; pbbox = bbox; SVECTORPC sxy0; for (i = 0; i < 8; i++) { gte_RotTransPers_pc(pbbox, &sxy0, &p, &flag, (int32 *)&(pbbox->vz)); pbbox->vx = (int16)sxy0.vx; pbbox->vy = (int16)sxy0.vy; pbbox++; } // Find the minimum and maximum screen positions (plus z) pbbox = bbox; copyVector(minbbox, pbbox); copyVector(maxbbox, pbbox); pbbox++; for (i = 1; i < 8; i++, pbbox++) { if (pbbox->vx < minbbox->vx) minbbox->vx = pbbox->vx; if (pbbox->vy < minbbox->vy) minbbox->vy = pbbox->vy; if (pbbox->vz < minbbox->vz) minbbox->vz = pbbox->vz; if (pbbox->vx > maxbbox->vx) maxbbox->vx = pbbox->vx; if (pbbox->vy > maxbbox->vy) maxbbox->vy = pbbox->vy; if (pbbox->vz > maxbbox->vz) maxbbox->vz = pbbox->vz; } // Loop over the vector pool converting them all to screen co-ordinates if (debug == 0) { ConvertToScreenCoords(local, screen, nVertices); } // Now go and find the actual polygon data for this primitive uint32 *polyStart; uint32 nPolys; uint32 *pNormal = RapAPIObject::GetNormalPtr(mrap); nPolys = mrap->nFUS3; if (nPolys != 0) { polyStart = RapAPIObject::GetFUS3Ptr(mrap); // Do the drawing using internal C based debugging drawing code if (debug) { drawFUS3PC(polyStart, nPolys, local); } else { fastDrawFUS3PC(polyStart, nPolys, screen); } } nPolys = mrap->nGUS3; if (nPolys != 0) { polyStart = RapAPIObject::GetGUS3Ptr(mrap); // Do the drawing using internal C based debugging drawing code if (debug) { drawGUS3PC(polyStart, nPolys, local); } else { fastDrawGUS3PC(polyStart, nPolys, screen); } } nPolys = mrap->nFTS3; if (nPolys != 0) { polyStart = RapAPIObject::GetFTS3Ptr(mrap); // Do the drawing using internal C based debugging drawing code if (debug) { drawFTS3PC(polyStart, nPolys, local); } else { fastDrawFTS3PC(polyStart, nPolys, screen); } } nPolys = mrap->nGTS3; if (nPolys != 0) { polyStart = RapAPIObject::GetGTS3Ptr(mrap); // Do the drawing using internal C based debugging drawing code if (debug) { drawGTS3PC(polyStart, nPolys, local); } else { fastDrawGTS3PC(polyStart, nPolys, screen); } } nPolys = mrap->nFUL3; if (nPolys != 0) { polyStart = RapAPIObject::GetFUL3Ptr(mrap); // Do the drawing using internal C based debugging drawing code if (debug) { drawFUL3PC(polyStart, nPolys, local, (SVECTOR *)pNormal); } else { fastDrawFUL3PC(polyStart, nPolys, screen, (SVECTOR *)pNormal); } } nPolys = mrap->nGUL3; if (nPolys != 0) { polyStart = RapAPIObject::GetGUL3Ptr(mrap); // Do the drawing using internal C based debugging drawing code if (debug) { drawGUL3PC(polyStart, nPolys, local, (SVECTOR *)pNormal); } else { fastDrawGUL3PC(polyStart, nPolys, screen, (SVECTOR *)pNormal); } } nPolys = mrap->nFTL3; if (nPolys != 0) { polyStart = RapAPIObject::GetFTL3Ptr(mrap); // Do the drawing using internal C based debugging drawing code if (debug) { drawFTL3PC(polyStart, nPolys, local, (SVECTOR *)pNormal); } else { fastDrawFTL3PC(polyStart, nPolys, screen, (SVECTOR *)pNormal); } } nPolys = mrap->nGTL3; if (nPolys != 0) { polyStart = RapAPIObject::GetGTL3Ptr(mrap); // Do the drawing using internal C based debugging drawing code if (debug) { drawGTL3PC(polyStart, nPolys, local, (SVECTOR *)pNormal); } else { fastDrawGTL3PC(polyStart, nPolys, screen, (SVECTOR *)pNormal); } } // Now do the animating polygons uint32 nTypes = mrap->nAnimTypes; if (nTypes != 0) { int32 nFrames = mrap->nFrames; if (nFrames == 0) nFrames = 1; int32 frm = uvframe % nFrames; // for dead things uvframe = -1 : and in that case draw the last frame of the animation if (uvframe == -1) { frm = 0; deadObject = 1; } else { deadObject = 0; } uint32 *typePtr = RapAPIObject::GetAnimPolyPtr(mrap); polyStart = RapAPIObject::GetAnimPolyFrame(mrap, frm); for (uint32 t = 0; t < nTypes; t++) { switch (*typePtr++) { // ++ skips the type field case HMD_FUS3: { nPolys = *typePtr++; if (debug) { drawFUS3PC(polyStart, nPolys, local); } else { fastDrawFUS3PC(polyStart, nPolys, screen); } polyStart += (nPolys * HMD_FUS3_SIZE); // skip to the next polygon break; } case HMD_GUS3: { nPolys = *typePtr++; if (debug) { drawGUS3PC(polyStart, nPolys, local); } else { fastDrawGUS3PC(polyStart, nPolys, screen); } polyStart += (nPolys * HMD_GUS3_SIZE); // skip to the next polygon break; } case HMD_FTS3: { nPolys = *typePtr++; if (debug) { drawFTS3PC(polyStart, nPolys, local); } else { fastDrawFTS3PC(polyStart, nPolys, screen); } polyStart += (nPolys * HMD_FTS3_SIZE); // skip to the next polygon break; } case HMD_GTS3: { nPolys = *typePtr++; if (debug) { drawGTS3PC(polyStart, nPolys, local); } else { fastDrawGTS3PC(polyStart, nPolys, screen); } polyStart += (nPolys * HMD_GTS3_SIZE); // skip to the next polygon break; } case HMD_FUL3: { nPolys = *typePtr++; if (debug) { drawFUL3PC(polyStart, nPolys, local, (SVECTOR *)pNormal); } else { fastDrawFUL3PC(polyStart, nPolys, screen, (SVECTOR *)pNormal); } polyStart += (nPolys * HMD_FUL3_SIZE); // skip to the next polygon break; } case HMD_GUL3: { nPolys = *typePtr++; if (debug) { drawGUL3PC(polyStart, nPolys, local, (SVECTOR *)pNormal); } else { fastDrawGUL3PC(polyStart, nPolys, screen, (SVECTOR *)pNormal); } polyStart += (nPolys * HMD_GUL3_SIZE); // skip to the next polygon break; } case HMD_FTL3: { nPolys = *typePtr++; if (debug) { drawFTL3PC(polyStart, nPolys, local, (SVECTOR *)pNormal); } else { fastDrawFTL3PC(polyStart, nPolys, screen, (SVECTOR *)pNormal); } polyStart += (nPolys * HMD_FTL3_SIZE); // skip to the next polygon break; } case HMD_GTL3: { nPolys = *typePtr++; if (debug) { drawGTL3PC(polyStart, nPolys, local, (SVECTOR *)pNormal); } else { fastDrawGTL3PC(polyStart, nPolys, screen, (SVECTOR *)pNormal); } polyStart += (nPolys * HMD_GTL3_SIZE); // skip to the next polygon break; } default: { Fatal_error("ERROR Unknown animating polygon %X", *(polyStart - 1)); } } } } polytpc = g_system->getMillis() - polytpc; } void DrawActorTiePC(psxCamera *camera, SVECTORPC *pos, uint32 size, CVECTOR *) { SVECTORPC wcorners[8]; SVECTORPC scorners[8]; wcorners[0].vx = (int16)(pos->vx - size); wcorners[0].vy = pos->vy; wcorners[0].vz = (int16)(pos->vz + size / 2); wcorners[1].vx = (int16)(pos->vx - size); wcorners[1].vy = pos->vy; wcorners[1].vz = (int16)(pos->vz - size / 2); wcorners[2].vx = (int16)(pos->vx - size / 2); wcorners[2].vy = pos->vy; wcorners[2].vz = (int16)(pos->vz - size); wcorners[3].vx = (int16)(pos->vx + size / 2); wcorners[3].vy = pos->vy; wcorners[3].vz = (int16)(pos->vz - size); wcorners[4].vx = (int16)(pos->vx + size); wcorners[4].vy = pos->vy; wcorners[4].vz = (int16)(pos->vz - size / 2); wcorners[5].vx = (int16)(pos->vx + size); wcorners[5].vy = pos->vy; wcorners[5].vz = (int16)(pos->vz + size / 2); wcorners[6].vx = (int16)(pos->vx + size / 2); wcorners[6].vy = pos->vy; wcorners[6].vz = (int16)(pos->vz + size); wcorners[7].vx = (int16)(pos->vx - size / 2); wcorners[7].vy = pos->vy; wcorners[7].vz = (int16)(pos->vz + size); SVECTORPC *local = wcorners; SVECTORPC *scrn; // Make the rotation matrix MATRIXPC cam_pc; const int32 MSCALE = ONE_PC / ONE; cam_pc.m[0][0] = camera->view.m[0][0] * MSCALE; cam_pc.m[0][1] = camera->view.m[0][1] * MSCALE; cam_pc.m[0][2] = camera->view.m[0][2] * MSCALE; cam_pc.m[1][0] = camera->view.m[1][0] * MSCALE; cam_pc.m[1][1] = camera->view.m[1][1] * MSCALE; cam_pc.m[1][2] = camera->view.m[1][2] * MSCALE; cam_pc.m[2][0] = camera->view.m[2][0] * MSCALE * ZSCALE; cam_pc.m[2][1] = camera->view.m[2][1] * MSCALE * ZSCALE; cam_pc.m[2][2] = camera->view.m[2][2] * MSCALE * ZSCALE; cam_pc.t[0] = camera->view.t[0]; cam_pc.t[1] = camera->view.t[1]; cam_pc.t[2] = camera->view.t[2] * ZSCALE; int32 i; int32 p, flag, z0; gte_SetGeomScreen_pc(camera->focLen * ZSCALE); gte_SetRotMatrix_pc(&cam_pc); gte_SetTransMatrix_pc(&cam_pc); gte_SetScreenScaleShift_pc(0); SVECTORPC mine; scrn = &mine; gte_RotTransPers_pc(pos, scrn, &p, &flag, &z0); scrn->vz = (int16)z0; scrn = scorners; for (i = 0; i < 8; i++, local++, scrn++) { gte_RotTransPers_pc(local, scrn, &p, &flag, &z0); scrn->vz = (int16)z0; } TPOLY_G3 *tie; int32 inz0; inz0 = 0; for (i = 0; i < 8; i++) inz0 += scorners[0].vz; inz0 /= 8; for (i = 0; i < 8; i++) { int32 next = i + 1; if (next == 8) next = 0; tie = (TPOLY_G3 *)drawpacket; setTPolyG3(tie); setXY3(tie, scorners[i].vx, scorners[i].vy, scorners[next].vx, scorners[next].vy, mine.vx, mine.vy); setRGB0(tie, 0, 0, 0); setRGB1(tie, 0, 0, 0); setRGB2(tie, 96, 96, 96); setTSemiTrans(tie, 1); setTABRMode(tie, 2); z0 = myAddPrimClip(inz0, drawpacket); myAddPacket(sizeof(TPOLY_G3)); } } void drawBboxPC(SVECTOR *scrn, CVECTOR colour) { // 6 LINE_F3's i.e. 6 pairs of lines = 12 lines in total // The 6 pairs of lines are the following vertex links: // 0->1->3 // 2->3->5 // 0->2->4 // 0->6->7 // 1->7->5 // 6->4->5 LINE_F3 *line = (LINE_F3 *)drawpacket; setLineF3(line); setRGB0(line, colour.r, colour.g, colour.b); // Pair0: 0->1->3 setXY3(line, scrn[0].vx, scrn[0].vy, scrn[1].vx, scrn[1].vy, scrn[3].vx, scrn[3].vy); myAddPrimClip(scrn[3].vz, drawpacket); myAddPacket(sizeof(LINE_F3)); // Pair1: 2->3->5 line = (LINE_F3 *)drawpacket; setLineF3(line); setRGB0(line, colour.r, colour.g, colour.b); setXY3(line, scrn[2].vx, scrn[2].vy, scrn[3].vx, scrn[3].vy, scrn[5].vx, scrn[5].vy); myAddPrimClip(scrn[5].vz, drawpacket); myAddPacket(sizeof(LINE_F3)); // Pair2: 0->2->4 line = (LINE_F3 *)drawpacket; setLineF3(line); setRGB0(line, colour.r, colour.g, colour.b); setXY3(line, scrn[0].vx, scrn[0].vy, scrn[2].vx, scrn[2].vy, scrn[4].vx, scrn[4].vy); myAddPrimClip(scrn[5].vz, drawpacket); myAddPacket(sizeof(LINE_F3)); // Pair3: 0->6->7 line = (LINE_F3 *)drawpacket; setLineF3(line); setRGB0(line, colour.r, colour.g, colour.b); setXY3(line, scrn[0].vx, scrn[0].vy, scrn[6].vx, scrn[6].vy, scrn[7].vx, scrn[7].vy); myAddPrimClip(scrn[7].vz, drawpacket); myAddPacket(sizeof(LINE_F3)); // Pair4: 1->7->5 line = (LINE_F3 *)drawpacket; setLineF3(line); setRGB0(line, colour.r, colour.g, colour.b); setXY3(line, scrn[1].vx, scrn[1].vy, scrn[7].vx, scrn[7].vy, scrn[5].vx, scrn[5].vy); myAddPrimClip(scrn[5].vz, drawpacket); myAddPacket(sizeof(LINE_F3)); // Pair5: 6->4->5 line = (LINE_F3 *)drawpacket; setLineF3(line); setRGB0(line, colour.r, colour.g, colour.b); setXY3(line, scrn[6].vx, scrn[6].vy, scrn[4].vx, scrn[4].vy, scrn[5].vx, scrn[5].vy); myAddPrimClip(scrn[5].vz, drawpacket); myAddPacket(sizeof(LINE_F3)); } void ConvertToScreenCoords(SVECTORPC *local, SVECTORPC *screen, int32 nVertices) { int32 i; SVECTORPC *in = local; SVECTORPC *out = screen; int32 flag, p; for (i = 0; i < nVertices; i++) { // Note, store the result back on top of itself ! gte_RotTransPers_pc(in, out, &p, &flag, (int32 *)&(out->vz)); out->vz <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4 p = (flag & (1 << 31)); out->pad = (int16)(p >> 16); in++; out++; } } void ConvertToScreenCoords(SVECTOR *local, SVECTOR *screen, int32 nVertices) { int32 i; SVECTOR *in = local; SVECTOR *out = screen; int32 flag, p; for (i = 0; i < nVertices; i++) { // Note, store the result back on top of itself ! gte_RotTransPers(in, (int32 *)out, &p, &flag, (int32 *)&(out->vz)); out->vz <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4 p = (flag & (1 << 31)); out->pad = (int16)(p >> 16); in++; out++; } } } // End of namespace ICB