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