1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the AUTHORS
5 * file distributed with this source distribution.
6 *
7 * Additional copyright for this file:
8 * Copyright (C) 1999-2000 Revolution Software Ltd.
9 * This code is based on source code created by Revolution Software,
10 * used with permission.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 *
26 */
27
28 #include "engines/icb/common/px_common.h"
29 #include "engines/icb/softskin_pc.h"
30 #include "engines/icb/common/px_capri_maths.h"
31
32 #include "common/util.h"
33
34 namespace ICB {
35
softskinPC(rap_API * rap,int32 poseBone,MATRIXPC * lw,SVECTORPC * local,int16 * xminLocal,int16 * xmaxLocal,int16 * yminLocal,int16 * ymaxLocal,int16 * zminLocal,int16 * zmaxLocal,int32 screenShift)36 int32 softskinPC(rap_API *rap, int32 poseBone, MATRIXPC *lw, SVECTORPC *local, int16 *xminLocal, int16 *xmaxLocal, int16 *yminLocal, int16 *ymaxLocal, int16 *zminLocal,
37 int16 *zmaxLocal, int32 screenShift) {
38 // step 1 : make all the local-world and local-screen matrices
39 // This is done prior to this function
40 // step 2 : take all the offsets from the mesh file
41 // and make them into screen positions using the
42 // correct co-ordinate system
43 // step 3 : draw the polygons using the list of created screen positions
44 //
45
46 // step 2
47 rap_API *pLink = rap;
48 uint32 nNone = pLink->nNone;
49 uint32 nSingle = pLink->nSingle;
50 uint32 nMulti = pLink->nMultiple;
51 uint32 i, vIndex;
52 Vertex *noneLink = rap->GetNoneLinkPtr();
53 VertexLink *singleLink = rap->GetSingleLinkPtr();
54 WeightedVertexLink *multiLink = rap->GetMultiLinkPtr();
55
56 uint32 prim;
57 uint32 nVertices = 0;
58
59 uint32 bothScaleShift = rap->bothScaleShift;
60 // uint32 bothScale = (1 << bothScaleShift);
61
62 uint32 worldScaleShift = rap->worldScaleShift;
63 bothScaleShift -= screenShift;
64 worldScaleShift -= screenShift;
65 // uint32 worldScale = (1 << worldScaleShift );
66
67 // loop over the vertices
68 SVECTORPC *plocal = local;
69 VECTOR lvert, lvert2;
70
71 int32 flag;
72 uint32 oldPrim = rap->nBones;
73
74 int32 xmin = *xminLocal;
75 int32 ymin = *yminLocal;
76 int32 zmin = *zminLocal;
77
78 int32 xmax = *xmaxLocal;
79 int32 ymax = *ymaxLocal;
80 int32 zmax = *zmaxLocal;
81
82 int32 lvx, lvy, lvz;
83
84 if (poseBone == -1) {
85 for (i = 0; i < nNone; i++) {
86 vIndex = noneLink->vertId;
87 plocal = local + vIndex;
88 if (vIndex > nVertices)
89 nVertices = vIndex;
90 plocal->vx = noneLink->vx;
91 plocal->vy = noneLink->vy;
92 plocal->vz = noneLink->vz;
93
94 lvx = plocal->vx;
95 lvy = plocal->vy;
96 lvz = plocal->vz;
97
98 xmin = MIN(lvx, xmin);
99 ymin = MIN(lvy, ymin);
100 zmin = MIN(lvz, zmin);
101
102 xmax = MAX(lvx, xmax);
103 ymax = MAX(lvy, ymax);
104 zmax = MAX(lvz, zmax);
105
106 noneLink++;
107 }
108 } else {
109 // Do the pose vertices
110 gte_SetRotMatrix_pc(lw + poseBone);
111 gte_SetTransMatrix_pc(lw + poseBone);
112 for (i = 0; i < nNone; i++) {
113 gte_RotTrans_pc((SVECTOR *)&(noneLink->vx), &lvert2, &flag);
114
115 vIndex = noneLink->vertId;
116 plocal = local + vIndex;
117
118 plocal->vx = (int16)(lvert2.vx >> worldScaleShift);
119 plocal->vy = (int16)(lvert2.vy >> worldScaleShift);
120 plocal->vz = (int16)(lvert2.vz >> worldScaleShift);
121
122 lvx = plocal->vx;
123 lvy = plocal->vy;
124 lvz = plocal->vz;
125
126 xmin = MIN(lvx, xmin);
127 ymin = MIN(lvy, ymin);
128 zmin = MIN(lvz, zmin);
129
130 xmax = MAX(lvx, xmax);
131 ymax = MAX(lvy, ymax);
132 zmax = MAX(lvz, zmax);
133
134 noneLink++;
135 }
136 nVertices = nNone;
137 }
138
139 for (i = 0; i < nSingle; i++) {
140 prim = singleLink->primId; // which co-ordinate system to use
141
142 // Put the correct rot and trans matrix in place
143 // transform to world space : local2world is in workm
144 if (prim != oldPrim) {
145 gte_SetRotMatrix_pc(lw + prim);
146 gte_SetTransMatrix_pc(lw + prim);
147 oldPrim = prim;
148 }
149 gte_RotTrans_pc((SVECTOR *)&(singleLink->vx), &lvert2, &flag);
150
151 plocal = local + singleLink->vertId;
152 if (singleLink->vertId > nVertices)
153 nVertices = singleLink->vertId;
154 plocal->vx = (int16)(lvert2.vx >> worldScaleShift);
155 plocal->vy = (int16)(lvert2.vy >> worldScaleShift);
156 plocal->vz = (int16)(lvert2.vz >> worldScaleShift);
157
158 lvx = plocal->vx;
159 lvy = plocal->vy;
160 lvz = plocal->vz;
161
162 xmin = MIN(lvx, xmin);
163 ymin = MIN(lvy, ymin);
164 zmin = MIN(lvz, zmin);
165
166 xmax = MAX(lvx, xmax);
167 ymax = MAX(lvy, ymax);
168 zmax = MAX(lvz, zmax);
169
170 singleLink++;
171 }
172
173 uint32 curVert = multiLink->link.vertId;
174
175 lvert.vx = 0;
176 lvert.vy = 0;
177 lvert.vz = 0;
178 for (i = 0; i < nMulti; i++) {
179 uint32 weight = multiLink->weight;
180 prim = multiLink->link.primId; // which co-ordinate system to use
181
182 // Put the correct rot and trans matrix in place
183 // transform to world space : local2world is in workm
184 if (prim != oldPrim) {
185 gte_SetRotMatrix_pc(lw + prim);
186 gte_SetTransMatrix_pc(lw + prim);
187 oldPrim = prim;
188 }
189 gte_RotTrans_pc((SVECTOR *)&(multiLink->link.vx), &lvert2, &flag);
190
191 // Do a weighted average of this vector (lvert2)
192 // with the stored weighted average (lvert)
193 // gte_LoadAverage0( &lvert, &lvert2, 1, weight, &lvert );
194 // gte_LoadAverage0 is not any quicker - and more inaccurate
195 lvert.vx += lvert2.vx * weight;
196 lvert.vy += lvert2.vy * weight;
197 lvert.vz += lvert2.vz * weight;
198
199 multiLink++;
200 vIndex = multiLink->link.vertId;
201 // A new vertex so tidy up the old one
202 if (vIndex != curVert) {
203 if (curVert > nVertices)
204 nVertices = curVert;
205
206 plocal = local + curVert;
207 plocal->vx = (int16)(lvert.vx >> bothScaleShift);
208 plocal->vy = (int16)(lvert.vy >> bothScaleShift);
209 plocal->vz = (int16)(lvert.vz >> bothScaleShift);
210 curVert = vIndex;
211 lvert.vx = 0;
212 lvert.vy = 0;
213 lvert.vz = 0;
214
215 lvx = plocal->vx;
216 lvy = plocal->vy;
217 lvz = plocal->vz;
218
219 xmin = MIN(lvx, xmin);
220 ymin = MIN(lvy, ymin);
221 zmin = MIN(lvz, zmin);
222
223 xmax = MAX(lvx, xmax);
224 ymax = MAX(lvy, ymax);
225 zmax = MAX(lvz, zmax);
226 }
227 }
228
229 *xminLocal = (int16)xmin;
230 *yminLocal = (int16)ymin;
231 *zminLocal = (int16)zmin;
232
233 *xmaxLocal = (int16)xmax;
234 *ymaxLocal = (int16)ymax;
235 *zmaxLocal = (int16)zmax;
236
237 nVertices++;
238 return nVertices;
239 }
240
241 } // End of namespace ICB
242