/* ResidualVM - A 3D game interpreter * * ResidualVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the AUTHORS * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "engines/icb/common/px_common.h" #include "engines/icb/softskin_pc.h" #include "engines/icb/common/px_capri_maths.h" #include "common/util.h" namespace ICB { int32 softskinPC(rap_API *rap, int32 poseBone, MATRIXPC *lw, SVECTORPC *local, int16 *xminLocal, int16 *xmaxLocal, int16 *yminLocal, int16 *ymaxLocal, int16 *zminLocal, int16 *zmaxLocal, int32 screenShift) { // step 1 : make all the local-world and local-screen matrices // This is done prior to this function // step 2 : take all the offsets from the mesh file // and make them into screen positions using the // correct co-ordinate system // step 3 : draw the polygons using the list of created screen positions // // step 2 rap_API *pLink = rap; uint32 nNone = pLink->nNone; uint32 nSingle = pLink->nSingle; uint32 nMulti = pLink->nMultiple; uint32 i, vIndex; Vertex *noneLink = rap->GetNoneLinkPtr(); VertexLink *singleLink = rap->GetSingleLinkPtr(); WeightedVertexLink *multiLink = rap->GetMultiLinkPtr(); uint32 prim; uint32 nVertices = 0; uint32 bothScaleShift = rap->bothScaleShift; // uint32 bothScale = (1 << bothScaleShift); uint32 worldScaleShift = rap->worldScaleShift; bothScaleShift -= screenShift; worldScaleShift -= screenShift; // uint32 worldScale = (1 << worldScaleShift ); // loop over the vertices SVECTORPC *plocal = local; VECTOR lvert, lvert2; int32 flag; uint32 oldPrim = rap->nBones; int32 xmin = *xminLocal; int32 ymin = *yminLocal; int32 zmin = *zminLocal; int32 xmax = *xmaxLocal; int32 ymax = *ymaxLocal; int32 zmax = *zmaxLocal; int32 lvx, lvy, lvz; if (poseBone == -1) { for (i = 0; i < nNone; i++) { vIndex = noneLink->vertId; plocal = local + vIndex; if (vIndex > nVertices) nVertices = vIndex; plocal->vx = noneLink->vx; plocal->vy = noneLink->vy; plocal->vz = noneLink->vz; lvx = plocal->vx; lvy = plocal->vy; lvz = plocal->vz; xmin = MIN(lvx, xmin); ymin = MIN(lvy, ymin); zmin = MIN(lvz, zmin); xmax = MAX(lvx, xmax); ymax = MAX(lvy, ymax); zmax = MAX(lvz, zmax); noneLink++; } } else { // Do the pose vertices gte_SetRotMatrix_pc(lw + poseBone); gte_SetTransMatrix_pc(lw + poseBone); for (i = 0; i < nNone; i++) { gte_RotTrans_pc((SVECTOR *)&(noneLink->vx), &lvert2, &flag); vIndex = noneLink->vertId; plocal = local + vIndex; plocal->vx = (int16)(lvert2.vx >> worldScaleShift); plocal->vy = (int16)(lvert2.vy >> worldScaleShift); plocal->vz = (int16)(lvert2.vz >> worldScaleShift); lvx = plocal->vx; lvy = plocal->vy; lvz = plocal->vz; xmin = MIN(lvx, xmin); ymin = MIN(lvy, ymin); zmin = MIN(lvz, zmin); xmax = MAX(lvx, xmax); ymax = MAX(lvy, ymax); zmax = MAX(lvz, zmax); noneLink++; } nVertices = nNone; } for (i = 0; i < nSingle; i++) { prim = singleLink->primId; // which co-ordinate system to use // Put the correct rot and trans matrix in place // transform to world space : local2world is in workm if (prim != oldPrim) { gte_SetRotMatrix_pc(lw + prim); gte_SetTransMatrix_pc(lw + prim); oldPrim = prim; } gte_RotTrans_pc((SVECTOR *)&(singleLink->vx), &lvert2, &flag); plocal = local + singleLink->vertId; if (singleLink->vertId > nVertices) nVertices = singleLink->vertId; plocal->vx = (int16)(lvert2.vx >> worldScaleShift); plocal->vy = (int16)(lvert2.vy >> worldScaleShift); plocal->vz = (int16)(lvert2.vz >> worldScaleShift); lvx = plocal->vx; lvy = plocal->vy; lvz = plocal->vz; xmin = MIN(lvx, xmin); ymin = MIN(lvy, ymin); zmin = MIN(lvz, zmin); xmax = MAX(lvx, xmax); ymax = MAX(lvy, ymax); zmax = MAX(lvz, zmax); singleLink++; } uint32 curVert = multiLink->link.vertId; lvert.vx = 0; lvert.vy = 0; lvert.vz = 0; for (i = 0; i < nMulti; i++) { uint32 weight = multiLink->weight; prim = multiLink->link.primId; // which co-ordinate system to use // Put the correct rot and trans matrix in place // transform to world space : local2world is in workm if (prim != oldPrim) { gte_SetRotMatrix_pc(lw + prim); gte_SetTransMatrix_pc(lw + prim); oldPrim = prim; } gte_RotTrans_pc((SVECTOR *)&(multiLink->link.vx), &lvert2, &flag); // Do a weighted average of this vector (lvert2) // with the stored weighted average (lvert) // gte_LoadAverage0( &lvert, &lvert2, 1, weight, &lvert ); // gte_LoadAverage0 is not any quicker - and more inaccurate lvert.vx += lvert2.vx * weight; lvert.vy += lvert2.vy * weight; lvert.vz += lvert2.vz * weight; multiLink++; vIndex = multiLink->link.vertId; // A new vertex so tidy up the old one if (vIndex != curVert) { if (curVert > nVertices) nVertices = curVert; plocal = local + curVert; plocal->vx = (int16)(lvert.vx >> bothScaleShift); plocal->vy = (int16)(lvert.vy >> bothScaleShift); plocal->vz = (int16)(lvert.vz >> bothScaleShift); curVert = vIndex; lvert.vx = 0; lvert.vy = 0; lvert.vz = 0; lvx = plocal->vx; lvy = plocal->vy; lvz = plocal->vz; xmin = MIN(lvx, xmin); ymin = MIN(lvy, ymin); zmin = MIN(lvz, zmin); xmax = MAX(lvx, xmax); ymax = MAX(lvy, ymax); zmax = MAX(lvz, zmax); } } *xminLocal = (int16)xmin; *yminLocal = (int16)ymin; *zminLocal = (int16)zmin; *xmaxLocal = (int16)xmax; *ymaxLocal = (int16)ymax; *zmaxLocal = (int16)zmax; nVertices++; return nVertices; } } // End of namespace ICB