1 | /*****************************************************************************\ |
2 | Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. |
3 | This file is licensed under the Snes9x License. |
4 | For further information, consult the LICENSE file in the root directory. |
5 | \*****************************************************************************/ |
6 | |
7 | #include <math.h> |
8 | #include "snes9x.h" |
9 | #include "memmap.h" |
10 | #include "sar.h" |
11 | |
12 | static int16 C4SinTable[512] = |
13 | { |
14 | 0, 402, 804, 1206, 1607, 2009, 2410, 2811, |
15 | 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, |
16 | 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, |
17 | 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, |
18 | 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, |
19 | 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, |
20 | 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, |
21 | 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, |
22 | 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, |
23 | 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, |
24 | 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, |
25 | 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, |
26 | 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, |
27 | 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, |
28 | 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, |
29 | 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765, |
30 | 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, |
31 | 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, |
32 | 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, |
33 | 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, |
34 | 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, |
35 | 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, |
36 | 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, |
37 | 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, |
38 | 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, |
39 | 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, |
40 | 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, |
41 | 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, |
42 | 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, |
43 | 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, |
44 | 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, |
45 | 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, |
46 | 0, -402, -804, -1206, -1607, -2009, -2410, -2811, |
47 | -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, |
48 | -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, |
49 | -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, |
50 | -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, |
51 | -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, |
52 | -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, |
53 | -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, |
54 | -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, |
55 | -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, |
56 | -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, |
57 | -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, |
58 | -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, |
59 | -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, |
60 | -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, |
61 | -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, |
62 | -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, |
63 | -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, |
64 | -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, |
65 | -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, |
66 | -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, |
67 | -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, |
68 | -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, |
69 | -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, |
70 | -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, |
71 | -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, |
72 | -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, |
73 | -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, |
74 | -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, |
75 | -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, |
76 | -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, |
77 | -3211, -2811, -2410, -2009, -1607, -1206, -804, -402 |
78 | }; |
79 | |
80 | static int16 C4CosTable[512] = |
81 | { |
82 | 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, |
83 | 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, |
84 | 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, |
85 | 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, |
86 | 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, |
87 | 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, |
88 | 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, |
89 | 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, |
90 | 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, |
91 | 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, |
92 | 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, |
93 | 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, |
94 | 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, |
95 | 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, |
96 | 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, |
97 | 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, |
98 | 0, -402, -804, -1206, -1607, -2009, -2410, -2811, |
99 | -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, |
100 | -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, |
101 | -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, |
102 | -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, |
103 | -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, |
104 | -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, |
105 | -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, |
106 | -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, |
107 | -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, |
108 | -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, |
109 | -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, |
110 | -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, |
111 | -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, |
112 | -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, |
113 | -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, |
114 | -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, |
115 | -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, |
116 | -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, |
117 | -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, |
118 | -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, |
119 | -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, |
120 | -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, |
121 | -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, |
122 | -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, |
123 | -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, |
124 | -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, |
125 | -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, |
126 | -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, |
127 | -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, |
128 | -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, |
129 | -3211, -2811, -2410, -2009, -1607, -1206, -804, -402, |
130 | 0, 402, 804, 1206, 1607, 2009, 2410, 2811, |
131 | 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, |
132 | 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, |
133 | 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, |
134 | 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, |
135 | 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, |
136 | 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, |
137 | 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, |
138 | 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, |
139 | 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, |
140 | 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, |
141 | 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, |
142 | 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, |
143 | 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, |
144 | 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, |
145 | 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765 |
146 | }; |
147 | |
148 | static uint8 C4TestPattern[12 * 4] = |
149 | { |
150 | 0x00, 0x00, 0x00, 0xff, |
151 | 0xff, 0xff, 0x00, 0xff, |
152 | 0x00, 0x00, 0x00, 0xff, |
153 | 0xff, 0xff, 0x00, 0x00, |
154 | 0xff, 0xff, 0x00, 0x00, |
155 | 0x80, 0xff, 0xff, 0x7f, |
156 | 0x00, 0x80, 0x00, 0xff, |
157 | 0x7f, 0x00, 0xff, 0x7f, |
158 | 0xff, 0x7f, 0xff, 0xff, |
159 | 0x00, 0x00, 0x01, 0xff, |
160 | 0xff, 0xfe, 0x00, 0x01, |
161 | 0x00, 0xff, 0xfe, 0x00 |
162 | }; |
163 | |
164 | static void C4ConvOAM (void); |
165 | static void C4DoScaleRotate (int); |
166 | static void C4DrawLine (int32, int32, int16, int32, int32, int16, uint8); |
167 | static void C4DrawWireFrame (void); |
168 | static void C4TransformLines (void); |
169 | static void C4BitPlaneWave (void); |
170 | static void C4SprDisintegrate (void); |
171 | static void C4ProcessSprites (void); |
172 | |
173 | |
174 | static void C4ConvOAM (void) |
175 | { |
176 | uint8 *OAMptr = Memory.C4RAM + (Memory.C4RAM[0x626] << 2); |
177 | for (uint8 *i = Memory.C4RAM + 0x1fd; i > OAMptr; i -= 4) |
178 | *i = 0xe0; // Clear OAM-to-be |
179 | |
180 | uint8 *OAMptr2; |
181 | uint16 globalX, globalY; |
182 | int16 SprX, SprY; |
183 | uint8 SprName, SprAttr; |
184 | uint8 SprCount; |
185 | |
186 | globalX = READ_WORD(Memory.C4RAM + 0x0621); |
187 | globalY = READ_WORD(Memory.C4RAM + 0x0623); |
188 | OAMptr2 = Memory.C4RAM + 0x200 + (Memory.C4RAM[0x626] >> 2); |
189 | |
190 | #ifdef DEBUGGER |
191 | if (Memory.C4RAM[0x625] != 0) |
192 | printf("$6625=%02x, expected 00\n" , Memory.C4RAM[0x625]); |
193 | if ((Memory.C4RAM[0x626] >> 2) != Memory.C4RAM[0x629]) |
194 | printf("$6629=%02x, expected %02x\n" , Memory.C4RAM[0x629], (Memory.C4RAM[0x626] >> 2)); |
195 | if (((uint16) Memory.C4RAM[0x626] << 2) != READ_WORD(Memory.C4RAM + 0x627)) |
196 | printf("$6627=%04x, expected %04x\n" , READ_WORD(Memory.C4RAM + 0x627), ((uint16) Memory.C4RAM[0x626] << 2)); |
197 | #endif |
198 | |
199 | if (Memory.C4RAM[0x0620] != 0) |
200 | { |
201 | SprCount = 128 - Memory.C4RAM[0x626]; |
202 | |
203 | uint8 offset = (Memory.C4RAM[0x626] & 3) * 2; |
204 | uint8 *srcptr = Memory.C4RAM + 0x220; |
205 | |
206 | for (int i = Memory.C4RAM[0x0620]; i > 0 && SprCount > 0; i--, srcptr += 16) |
207 | { |
208 | SprX = READ_WORD(srcptr) - globalX; |
209 | SprY = READ_WORD(srcptr + 2) - globalY; |
210 | SprName = srcptr[5]; |
211 | SprAttr = srcptr[4] | srcptr[0x06]; // XXX: mask bits? |
212 | |
213 | uint8 *sprptr = C4GetMemPointer(READ_3WORD(srcptr + 7)); |
214 | if (*sprptr != 0) |
215 | { |
216 | int16 X, Y; |
217 | |
218 | for (int SprCnt = *sprptr++; SprCnt > 0 && SprCount > 0; SprCnt--, sprptr += 4) |
219 | { |
220 | X = (int8) sprptr[1]; |
221 | if (SprAttr & 0x40) |
222 | X = -X - ((sprptr[0] & 0x20) ? 16 : 8); // flip X |
223 | X += SprX; |
224 | |
225 | if (X >= -16 && X <= 272) |
226 | { |
227 | Y = (int8) sprptr[2]; |
228 | if (SprAttr & 0x80) |
229 | Y = -Y - ((sprptr[0] & 0x20) ? 16 : 8); |
230 | Y += SprY; |
231 | |
232 | if (Y >= -16 && Y <= 224) |
233 | { |
234 | OAMptr[0] = X & 0xff; |
235 | OAMptr[1] = (uint8) Y; |
236 | OAMptr[2] = SprName + sprptr[3]; |
237 | OAMptr[3] = SprAttr ^ (sprptr[0] & 0xc0); // XXX: Carry from SprName addition? |
238 | |
239 | *OAMptr2 &= ~(3 << offset); |
240 | if (X & 0x100) |
241 | *OAMptr2 |= 1 << offset; |
242 | if (sprptr[0] & 0x20) |
243 | *OAMptr2 |= 2 << offset; |
244 | |
245 | OAMptr += 4; |
246 | SprCount--; |
247 | |
248 | offset = (offset + 2) & 6; |
249 | if (offset == 0) |
250 | OAMptr2++; |
251 | } |
252 | } |
253 | } |
254 | } |
255 | else |
256 | if (SprCount > 0) |
257 | { |
258 | // XXX: Should we be testing -16<=SprX<=272 and -16<=SprY<=224? |
259 | OAMptr[0] = (uint8) SprX; |
260 | OAMptr[1] = (uint8) SprY; |
261 | OAMptr[2] = SprName; |
262 | OAMptr[3] = SprAttr; |
263 | |
264 | *OAMptr2 &= ~(3 << offset); |
265 | if (SprX & 0x100) |
266 | *OAMptr2 |= 3 << offset; |
267 | else |
268 | *OAMptr2 |= 2 << offset; |
269 | |
270 | OAMptr += 4; |
271 | SprCount--; |
272 | |
273 | offset = (offset + 2) & 6; |
274 | if (offset == 0) |
275 | OAMptr2++; |
276 | } |
277 | } |
278 | } |
279 | } |
280 | |
281 | static void C4DoScaleRotate (int row_padding) |
282 | { |
283 | int16 A, B, C, D; |
284 | |
285 | // Calculate matrix |
286 | int32 XScale = READ_WORD(Memory.C4RAM + 0x1f8f); |
287 | if (XScale & 0x8000) |
288 | XScale = 0x7fff; |
289 | |
290 | int32 YScale = READ_WORD(Memory.C4RAM + 0x1f92); |
291 | if (YScale & 0x8000) |
292 | YScale = 0x7fff; |
293 | |
294 | if (READ_WORD(Memory.C4RAM + 0x1f80) == 0) // no rotation |
295 | { |
296 | // XXX: only do this for C and D? |
297 | // XXX: and then only when YScale is 0x1000? |
298 | A = (int16) XScale; |
299 | B = 0; |
300 | C = 0; |
301 | D = (int16) YScale; |
302 | } |
303 | else |
304 | if (READ_WORD(Memory.C4RAM + 0x1f80) == 128) // 90 degree rotation |
305 | { |
306 | // XXX: Really do this? |
307 | A = 0; |
308 | B = (int16) (-YScale); |
309 | C = (int16) XScale; |
310 | D = 0; |
311 | } |
312 | else |
313 | if (READ_WORD(Memory.C4RAM + 0x1f80) == 256) // 180 degree rotation |
314 | { |
315 | // XXX: Really do this? |
316 | A = (int16) (-XScale); |
317 | B = 0; |
318 | C = 0; |
319 | D = (int16) (-YScale); |
320 | } |
321 | else |
322 | if (READ_WORD(Memory.C4RAM + 0x1f80) == 384) // 270 degree rotation |
323 | { |
324 | // XXX: Really do this? |
325 | A = 0; |
326 | B = (int16) YScale; |
327 | C = (int16) (-XScale); |
328 | D = 0; |
329 | } |
330 | else |
331 | { |
332 | A = (int16) SAR(C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * XScale, 15); |
333 | B = (int16) (-SAR(C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * YScale, 15)); |
334 | C = (int16) SAR(C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * XScale, 15); |
335 | D = (int16) SAR(C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * YScale, 15); |
336 | } |
337 | |
338 | // Calculate Pixel Resolution |
339 | uint8 w = Memory.C4RAM[0x1f89] & ~7; |
340 | uint8 h = Memory.C4RAM[0x1f8c] & ~7; |
341 | |
342 | //printf("%dx%d XScale=%04x YScale=%04x angle=%03x\n", w, h, XScale, YScale, READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff); |
343 | //printf("Matrix: [%10g %10g] [%04x %04x]\n", A / 4096.0, B / 4096.0, A & 0xffff, B & 0xffff); |
344 | //printf(" [%10g %10g] [%04x %04x]\n", C / 4096.0, D / 4096.0, C & 0xffff, D & 0xffff); |
345 | |
346 | // Clear the output RAM |
347 | memset(Memory.C4RAM, 0, (w + row_padding / 4) * h / 2); |
348 | |
349 | int32 Cx = (int16) READ_WORD(Memory.C4RAM + 0x1f83); |
350 | int32 Cy = (int16) READ_WORD(Memory.C4RAM + 0x1f86); |
351 | |
352 | #ifdef DEBUGGER |
353 | if (Memory.C4RAM[0x1f97] != 0) |
354 | printf("$7f97=%02x, expected 00\n" , Memory.C4RAM[0x1f97]); |
355 | if ((Cx & ~1) != w / 2 || (Cy & ~1) != h / 2) |
356 | printf("Center is not middle of image! (%d, %d) != (%d, %d)\n" , Cx, Cy, w / 2, h / 2); |
357 | #endif |
358 | |
359 | // Calculate start position (i.e. (Ox, Oy) = (0, 0)) |
360 | // The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in the function. |
361 | // We do Cx*A etc normally because the matrix parameters already have the fractional parts. |
362 | int32 LineX = (Cx << 12) - Cx * A - Cx * B; |
363 | int32 LineY = (Cy << 12) - Cy * C - Cy * D; |
364 | |
365 | // Start loop |
366 | uint32 X, Y; |
367 | uint8 byte; |
368 | int outidx = 0; |
369 | uint8 bit = 0x80; |
370 | |
371 | for (int y = 0; y < h; y++) |
372 | { |
373 | X = LineX; |
374 | Y = LineY; |
375 | |
376 | for (int x = 0; x < w; x++) |
377 | { |
378 | if ((X >> 12) >= w || (Y >> 12) >= h) |
379 | byte = 0; |
380 | else |
381 | { |
382 | uint32 addr = (Y >> 12) * w + (X >> 12); |
383 | byte = Memory.C4RAM[0x600 + (addr >> 1)]; |
384 | if (addr & 1) |
385 | byte >>= 4; |
386 | } |
387 | |
388 | // De-bitplanify |
389 | if (byte & 1) |
390 | Memory.C4RAM[outidx] |= bit; |
391 | if (byte & 2) |
392 | Memory.C4RAM[outidx + 1] |= bit; |
393 | if (byte & 4) |
394 | Memory.C4RAM[outidx + 16] |= bit; |
395 | if (byte & 8) |
396 | Memory.C4RAM[outidx + 17] |= bit; |
397 | |
398 | bit >>= 1; |
399 | if (bit == 0) |
400 | { |
401 | bit = 0x80; |
402 | outidx += 32; |
403 | } |
404 | |
405 | X += A; // Add 1 to output x => add an A and a C |
406 | Y += C; |
407 | } |
408 | |
409 | outidx += 2 + row_padding; |
410 | if (outidx & 0x10) |
411 | outidx &= ~0x10; |
412 | else |
413 | outidx -= w * 4 + row_padding; |
414 | |
415 | LineX += B; // Add 1 to output y => add a B and a D |
416 | LineY += D; |
417 | } |
418 | } |
419 | |
420 | static void C4DrawLine (int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) |
421 | { |
422 | // Transform coordinates |
423 | C4WFXVal = (int16) X1; |
424 | C4WFYVal = (int16) Y1; |
425 | C4WFZVal = Z1; |
426 | C4WFScale = Memory.C4RAM[0x1f90]; |
427 | C4WFX2Val = Memory.C4RAM[0x1f86]; |
428 | C4WFY2Val = Memory.C4RAM[0x1f87]; |
429 | C4WFDist = Memory.C4RAM[0x1f88]; |
430 | C4TransfWireFrame2(); |
431 | X1 = (C4WFXVal + 48) << 8; |
432 | Y1 = (C4WFYVal + 48) << 8; |
433 | |
434 | C4WFXVal = (int16) X2; |
435 | C4WFYVal = (int16) Y2; |
436 | C4WFZVal = Z2; |
437 | C4TransfWireFrame2(); |
438 | X2 = (C4WFXVal + 48) << 8; |
439 | Y2 = (C4WFYVal + 48) << 8; |
440 | |
441 | // Get line info |
442 | C4WFXVal = (int16) (X1 >> 8); |
443 | C4WFYVal = (int16) (Y1 >> 8); |
444 | C4WFX2Val = (int16) (X2 >> 8); |
445 | C4WFY2Val = (int16) (Y2 >> 8); |
446 | C4CalcWireFrame(); |
447 | X2 = (int16) C4WFXVal; |
448 | Y2 = (int16) C4WFYVal; |
449 | |
450 | // Render line |
451 | for (int i = C4WFDist ? C4WFDist : 1; i > 0; i--) |
452 | { |
453 | if (X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) |
454 | { |
455 | uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2; |
456 | uint8 bit = 0x80 >> ((X1 >> 8) & 7); |
457 | |
458 | Memory.C4RAM[addr + 0x300] &= ~bit; |
459 | Memory.C4RAM[addr + 0x301] &= ~bit; |
460 | if (Color & 1) |
461 | Memory.C4RAM[addr + 0x300] |= bit; |
462 | if (Color & 2) |
463 | Memory.C4RAM[addr + 0x301] |= bit; |
464 | } |
465 | |
466 | X1 += X2; |
467 | Y1 += Y2; |
468 | } |
469 | } |
470 | |
471 | static void C4DrawWireFrame (void) |
472 | { |
473 | uint8 *line = C4GetMemPointer(READ_3WORD(Memory.C4RAM + 0x1f80)); |
474 | uint8 *point1, *point2; |
475 | int16 X1, Y1, Z1; |
476 | int16 X2, Y2, Z2; |
477 | uint8 Color; |
478 | |
479 | #ifdef DEBUGGER |
480 | if (READ_3WORD(Memory.C4RAM + 0x1f8f) & 0xff00ff) |
481 | printf("wireframe: Unexpected value in $7f8f: %06x\n" , READ_3WORD(Memory.C4RAM + 0x1f8f)); |
482 | if (READ_3WORD(Memory.C4RAM + 0x1fa4) != 0x001000) |
483 | printf("wireframe: Unexpected value in $7fa4: %06x\n" , READ_3WORD(Memory.C4RAM + 0x1fa4)); |
484 | #endif |
485 | |
486 | for (int i = Memory.C4RAM[0x0295]; i > 0; i--, line += 5) |
487 | { |
488 | if (line[0] == 0xff && line[1] == 0xff) |
489 | { |
490 | uint8 *tmp = line - 5; |
491 | while (tmp[2] == 0xff && tmp[3] == 0xff) |
492 | tmp -= 5; |
493 | point1 = C4GetMemPointer((Memory.C4RAM[0x1f82] << 16) | (tmp[2] << 8) | tmp[3]); |
494 | } |
495 | else |
496 | point1 = C4GetMemPointer((Memory.C4RAM[0x1f82] << 16) | (line[0] << 8) | line[1]); |
497 | |
498 | point2 = C4GetMemPointer((Memory.C4RAM[0x1f82] << 16) | (line[2] << 8) | line[3]); |
499 | |
500 | X1 = (point1[0] << 8) | point1[1]; |
501 | Y1 = (point1[2] << 8) | point1[3]; |
502 | Z1 = (point1[4] << 8) | point1[5]; |
503 | X2 = (point2[0] << 8) | point2[1]; |
504 | Y2 = (point2[2] << 8) | point2[3]; |
505 | Z2 = (point2[4] << 8) | point2[5]; |
506 | |
507 | Color = line[4]; |
508 | |
509 | C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color); |
510 | } |
511 | } |
512 | |
513 | static void C4TransformLines (void) |
514 | { |
515 | C4WFX2Val = Memory.C4RAM[0x1f83]; |
516 | C4WFY2Val = Memory.C4RAM[0x1f86]; |
517 | C4WFDist = Memory.C4RAM[0x1f89]; |
518 | C4WFScale = Memory.C4RAM[0x1f8c]; |
519 | |
520 | #ifdef DEBUGGER |
521 | if (Memory.C4RAM[0x1f8a] != 0x90) |
522 | printf("lines: $7f8a = %02x, expected 90\n" , READ_WORD(Memory.C4RAM + 0x1f8a)); |
523 | #endif |
524 | |
525 | // Transform vertices |
526 | uint8 *ptr = Memory.C4RAM; |
527 | |
528 | for (int i = READ_WORD(Memory.C4RAM + 0x1f80); i > 0; i--, ptr += 0x10) |
529 | { |
530 | C4WFXVal = READ_WORD(ptr + 1); |
531 | C4WFYVal = READ_WORD(ptr + 5); |
532 | C4WFZVal = READ_WORD(ptr + 9); |
533 | C4TransfWireFrame(); |
534 | |
535 | // Displace |
536 | WRITE_WORD(ptr + 1, C4WFXVal + 0x80); |
537 | WRITE_WORD(ptr + 5, C4WFYVal + 0x50); |
538 | } |
539 | |
540 | WRITE_WORD(Memory.C4RAM + 0x600, 23); |
541 | WRITE_WORD(Memory.C4RAM + 0x602, 0x60); |
542 | WRITE_WORD(Memory.C4RAM + 0x605, 0x40); |
543 | WRITE_WORD(Memory.C4RAM + 0x600 + 8, 23); |
544 | WRITE_WORD(Memory.C4RAM + 0x602 + 8, 0x60); |
545 | WRITE_WORD(Memory.C4RAM + 0x605 + 8, 0x40); |
546 | |
547 | ptr = Memory.C4RAM + 0xb02; |
548 | uint8 *ptr2 = Memory.C4RAM; |
549 | |
550 | for (int i = READ_WORD(Memory.C4RAM + 0xb00); i > 0; i--, ptr += 2, ptr2 += 8) |
551 | { |
552 | C4WFXVal = READ_WORD(Memory.C4RAM + (ptr[0] << 4) + 1); |
553 | C4WFYVal = READ_WORD(Memory.C4RAM + (ptr[0] << 4) + 5); |
554 | C4WFX2Val = READ_WORD(Memory.C4RAM + (ptr[1] << 4) + 1); |
555 | C4WFY2Val = READ_WORD(Memory.C4RAM + (ptr[1] << 4) + 5); |
556 | C4CalcWireFrame(); |
557 | |
558 | WRITE_WORD(ptr2 + 0x600, C4WFDist ? C4WFDist : 1); |
559 | WRITE_WORD(ptr2 + 0x602, C4WFXVal); |
560 | WRITE_WORD(ptr2 + 0x605, C4WFYVal); |
561 | } |
562 | } |
563 | |
564 | static void C4BitPlaneWave (void) |
565 | { |
566 | static uint16 bmpdata[] = |
567 | { |
568 | 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, 0x000E, |
569 | 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020A, 0x020C, 0x020E, |
570 | 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, 0x040E, |
571 | 0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060A, 0x060C, 0x060E, |
572 | 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080A, 0x080C, 0x080E |
573 | }; |
574 | |
575 | uint8 *dst = Memory.C4RAM; |
576 | uint32 waveptr = Memory.C4RAM[0x1f83]; |
577 | uint16 mask1 = 0xc0c0; |
578 | uint16 mask2 = 0x3f3f; |
579 | |
580 | #ifdef DEBUGGER |
581 | if (READ_3WORD(Memory.C4RAM + 0x1f80) != Memory.C4RAM[waveptr + 0xb00]) |
582 | printf("$7f80=%06x, expected %02x\n" , READ_3WORD(Memory.C4RAM + 0x1f80), Memory.C4RAM[waveptr + 0xb00]); |
583 | #endif |
584 | |
585 | for (int j = 0; j < 0x10; j++) |
586 | { |
587 | do |
588 | { |
589 | int16 height = -((int8) Memory.C4RAM[waveptr + 0xb00]) - 16; |
590 | |
591 | for (int i = 0; i < 40; i++) |
592 | { |
593 | uint16 tmp = READ_WORD(dst + bmpdata[i]) & mask2; |
594 | if (height >= 0) |
595 | { |
596 | if (height < 8) |
597 | tmp |= mask1 & READ_WORD(Memory.C4RAM + 0xa00 + height * 2); |
598 | else |
599 | tmp |= mask1 & 0xff00; |
600 | } |
601 | |
602 | WRITE_WORD(dst + bmpdata[i], tmp); |
603 | |
604 | height++; |
605 | } |
606 | |
607 | waveptr = (waveptr + 1) & 0x7f; |
608 | mask1 = (mask1 >> 2) | (mask1 << 6); |
609 | mask2 = (mask2 >> 2) | (mask2 << 6); |
610 | } |
611 | while (mask1 != 0xc0c0); |
612 | |
613 | dst += 16; |
614 | |
615 | do |
616 | { |
617 | int16 height = -((int8) Memory.C4RAM[waveptr + 0xb00]) - 16; |
618 | |
619 | for (int i = 0; i < 40; i++) |
620 | { |
621 | uint16 tmp = READ_WORD(dst + bmpdata[i]) & mask2; |
622 | if (height >= 0) |
623 | { |
624 | if (height < 8) |
625 | tmp |= mask1 & READ_WORD(Memory.C4RAM + 0xa10 + height * 2); |
626 | else |
627 | tmp |= mask1 & 0xff00; |
628 | } |
629 | |
630 | WRITE_WORD(dst + bmpdata[i], tmp); |
631 | |
632 | height++; |
633 | } |
634 | |
635 | waveptr = (waveptr + 1) & 0x7f; |
636 | mask1 = (mask1 >> 2) | (mask1 << 6); |
637 | mask2 = (mask2 >> 2) | (mask2 << 6); |
638 | } |
639 | while (mask1 != 0xc0c0); |
640 | |
641 | dst += 16; |
642 | } |
643 | } |
644 | |
645 | static void C4SprDisintegrate (void) |
646 | { |
647 | uint8 *src; |
648 | uint8 width, height; |
649 | uint32 StartX, StartY; |
650 | int32 scaleX, scaleY; |
651 | int32 Cx, Cy; |
652 | |
653 | width = Memory.C4RAM[0x1f89]; |
654 | height = Memory.C4RAM[0x1f8c]; |
655 | Cx = (int16) READ_WORD(Memory.C4RAM + 0x1f80); |
656 | Cy = (int16) READ_WORD(Memory.C4RAM + 0x1f83); |
657 | |
658 | #ifdef DEBUGGER |
659 | if ((Cx & ~1) != width / 2 || (Cy & ~1) != height / 2) |
660 | printf("Center is not middle of image for disintegrate! (%d, %d) != (%d, %d)\n" , Cx, Cy, width / 2, height / 2); |
661 | #endif |
662 | |
663 | scaleX = (int16) READ_WORD(Memory.C4RAM + 0x1f86); |
664 | scaleY = (int16) READ_WORD(Memory.C4RAM + 0x1f8f); |
665 | StartX = -Cx * scaleX + (Cx << 8); |
666 | StartY = -Cy * scaleY + (Cy << 8); |
667 | |
668 | src = Memory.C4RAM + 0x600; |
669 | |
670 | memset(Memory.C4RAM, 0, width * height / 2); |
671 | |
672 | for (uint32 y = StartY, i = 0; i < height; i++, y += scaleY) |
673 | { |
674 | for (uint32 x = StartX, j = 0; j < width; j++, x += scaleX) |
675 | { |
676 | if ((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) |
677 | { |
678 | uint8 pixel = (j & 1) ? (*src >> 4) : *src; |
679 | int idx = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2; |
680 | uint8 mask = 0x80 >> ((x >> 8) & 7); |
681 | |
682 | if (pixel & 1) |
683 | Memory.C4RAM[idx] |= mask; |
684 | if (pixel & 2) |
685 | Memory.C4RAM[idx + 1] |= mask; |
686 | if (pixel & 4) |
687 | Memory.C4RAM[idx + 16] |= mask; |
688 | if (pixel & 8) |
689 | Memory.C4RAM[idx + 17] |= mask; |
690 | } |
691 | |
692 | if (j & 1) |
693 | src++; |
694 | } |
695 | } |
696 | } |
697 | |
698 | static void C4ProcessSprites (void) |
699 | { |
700 | switch (Memory.C4RAM[0x1f4d]) |
701 | { |
702 | case 0x00: // Build OAM |
703 | #ifdef DEBUGGER |
704 | //printf("00 00 Build OAM!\n"); |
705 | #endif |
706 | C4ConvOAM(); |
707 | break; |
708 | |
709 | case 0x03: // Scale/Rotate |
710 | #ifdef DEBUGGER |
711 | //printf("00 03 Scale/Rotate!\n"); |
712 | #endif |
713 | C4DoScaleRotate(0); |
714 | break; |
715 | |
716 | case 0x05: // Transform Lines |
717 | #ifdef DEBUGGER |
718 | //printf("00 05 Transform Lines!\n"); |
719 | #endif |
720 | C4TransformLines(); |
721 | break; |
722 | |
723 | case 0x07: // Scale/Rotate |
724 | #ifdef DEBUGGER |
725 | //printf("00 07 Scale/Rotate!\n"); |
726 | #endif |
727 | C4DoScaleRotate(64); |
728 | break; |
729 | |
730 | case 0x08: // Draw wireframe |
731 | #ifdef DEBUGGER |
732 | //printf("00 08 Draw wireframe!\n"); |
733 | #endif |
734 | C4DrawWireFrame(); |
735 | break; |
736 | |
737 | case 0x0b: // Disintegrate |
738 | #ifdef DEBUGGER |
739 | //printf("00 0b Disintegrate!\n"); |
740 | #endif |
741 | C4SprDisintegrate(); |
742 | break; |
743 | |
744 | case 0x0c: // Wave |
745 | #ifdef DEBUGGER |
746 | //printf("00 0b Wave!\n"); |
747 | #endif |
748 | C4BitPlaneWave(); |
749 | break; |
750 | |
751 | default: |
752 | #ifdef DEBUGGER |
753 | printf("Unknown C4 sprite command (%02x)\n" , Memory.C4RAM[0x1f4d]); |
754 | #endif |
755 | break; |
756 | } |
757 | } |
758 | |
759 | void S9xInitC4 (void) |
760 | { |
761 | // Stupid zsnes code, we can't do the logical thing without breaking savestates |
762 | // Memory.C4RAM = &Memory.FillRAM [0x6000]; |
763 | memset(Memory.C4RAM, 0, 0x2000); |
764 | } |
765 | |
766 | uint8 S9xGetC4 (uint16 Address) |
767 | { |
768 | if (Address == 0x7f5e) |
769 | return (0); |
770 | |
771 | return (Memory.C4RAM[Address - 0x6000]); |
772 | } |
773 | |
774 | void S9xSetC4 (uint8 byte, uint16 Address) |
775 | { |
776 | Memory.C4RAM[Address - 0x6000] = byte; |
777 | |
778 | if (Address == 0x7f4f) |
779 | { |
780 | if (Memory.C4RAM[0x1f4d] == 0x0e && byte < 0x40 && (byte & 3) == 0) |
781 | { |
782 | #ifdef DEBUGGER |
783 | printf("Test command %02x 0e used!\n" , byte); |
784 | #endif |
785 | Memory.C4RAM[0x1f80] = byte >> 2; |
786 | } |
787 | else |
788 | { |
789 | switch (byte) |
790 | { |
791 | case 0x00: // Sprite |
792 | #ifdef DEBUGGER |
793 | //printf("00 Sprite!\n"); |
794 | #endif |
795 | C4ProcessSprites(); |
796 | break; |
797 | |
798 | case 0x01: // Draw wireframe |
799 | #ifdef DEBUGGER |
800 | //printf("01 Draw wireframe!\n"); |
801 | if (Memory.C4RAM[0x1f4d] != 8) |
802 | printf("$7f4d=%02x, expected 08 for command 01 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
803 | #endif |
804 | memset(Memory.C4RAM + 0x300, 0, 16 * 12 * 3 * 4); |
805 | C4DrawWireFrame(); |
806 | break; |
807 | |
808 | case 0x05: // Propulsion (?) |
809 | { |
810 | #ifdef DEBUGGER |
811 | //printf("05 Propulsion (?)!\n"); |
812 | if (Memory.C4RAM[0x1f4d] != 2) |
813 | printf("$7f4d=%02x, expected 02 for command 05 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
814 | #endif |
815 | int32 tmp = 0x10000; |
816 | if (READ_WORD(Memory.C4RAM + 0x1f83)) |
817 | tmp = SAR((tmp / READ_WORD(Memory.C4RAM + 0x1f83)) * READ_WORD(Memory.C4RAM + 0x1f81), 8); |
818 | |
819 | WRITE_WORD(Memory.C4RAM + 0x1f80, (uint16) tmp); |
820 | break; |
821 | } |
822 | |
823 | case 0x0d: // Set vector length |
824 | #ifdef DEBUGGER |
825 | //printf("0d Set vector length!\n"); |
826 | if (Memory.C4RAM[0x1f4d] != 2) |
827 | printf("$7f4d=%02x, expected 02 for command 0d %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
828 | #endif |
829 | C41FXVal = READ_WORD(Memory.C4RAM + 0x1f80); |
830 | C41FYVal = READ_WORD(Memory.C4RAM + 0x1f83); |
831 | C41FDistVal = READ_WORD(Memory.C4RAM + 0x1f86); |
832 | C4Op0D(); |
833 | WRITE_WORD(Memory.C4RAM + 0x1f89, C41FXVal); |
834 | WRITE_WORD(Memory.C4RAM + 0x1f8c, C41FYVal); |
835 | break; |
836 | |
837 | case 0x10: // Polar to rectangluar |
838 | { |
839 | #ifdef DEBUGGER |
840 | //printf("10 Polar->Rect!\n"); |
841 | if (Memory.C4RAM[0x1f4d] != 2) |
842 | printf("$7f4d=%02x, expected 02 for command 10 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
843 | #endif |
844 | int32 tmp; |
845 | int32 r1; |
846 | r1 = READ_WORD(Memory.C4RAM + 0x1f83); |
847 | if (r1 & 0x8000) |
848 | r1 |= ~0x7fff; |
849 | else |
850 | r1 &= 0x7fff; |
851 | |
852 | tmp = SAR(r1 * C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 16); |
853 | WRITE_3WORD(Memory.C4RAM + 0x1f86, tmp); |
854 | tmp = SAR(r1 * C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 16); |
855 | WRITE_3WORD(Memory.C4RAM + 0x1f89, (tmp - SAR(tmp, 6))); |
856 | break; |
857 | } |
858 | |
859 | case 0x13: // Polar to rectangluar |
860 | { |
861 | #ifdef DEBUGGER |
862 | //printf("13 Polar->Rect!\n"); |
863 | if (Memory.C4RAM[0x1f4d] != 2) |
864 | printf("$7f4d=%02x, expected 02 for command 13 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
865 | #endif |
866 | int32 tmp; |
867 | tmp = SAR((int32) READ_WORD(Memory.C4RAM + 0x1f83) * C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 8); |
868 | WRITE_3WORD(Memory.C4RAM + 0x1f86, tmp); |
869 | tmp = SAR((int32) READ_WORD(Memory.C4RAM + 0x1f83) * C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 8); |
870 | WRITE_3WORD(Memory.C4RAM + 0x1f89, tmp); |
871 | break; |
872 | } |
873 | |
874 | case 0x15: // Pythagorean |
875 | #ifdef DEBUGGER |
876 | //printf("15 Pythagorean!\n"); |
877 | if (Memory.C4RAM[0x1f4d] != 2) |
878 | printf("$7f4d=%02x, expected 02 for command 15 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
879 | #endif |
880 | C41FXVal = READ_WORD(Memory.C4RAM + 0x1f80); |
881 | C41FYVal = READ_WORD(Memory.C4RAM + 0x1f83); |
882 | //C4Op15(); // optimized to: |
883 | C41FDist = (int16) sqrt((double) C41FXVal * C41FXVal + (double) C41FYVal * C41FYVal); |
884 | WRITE_WORD(Memory.C4RAM + 0x1f80, C41FDist); |
885 | break; |
886 | |
887 | case 0x1f: // atan |
888 | #ifdef DEBUGGER |
889 | //printf("1f atan!\n"); |
890 | if (Memory.C4RAM[0x1f4d] != 2) |
891 | printf("$7f4d=%02x, expected 02 for command 1f %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
892 | #endif |
893 | C41FXVal = READ_WORD(Memory.C4RAM + 0x1f80); |
894 | C41FYVal = READ_WORD(Memory.C4RAM + 0x1f83); |
895 | C4Op1F(); |
896 | WRITE_WORD(Memory.C4RAM + 0x1f86, C41FAngleRes); |
897 | break; |
898 | |
899 | case 0x22: // Trapezoid |
900 | { |
901 | #ifdef DEBUGGER |
902 | //printf("22 Trapezoid!\n"); |
903 | if (Memory.C4RAM[0x1f4d] != 2) |
904 | printf("$7f4d=%02x, expected 02 for command 22 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
905 | #endif |
906 | int16 angle1 = READ_WORD(Memory.C4RAM + 0x1f8c) & 0x1ff; |
907 | int16 angle2 = READ_WORD(Memory.C4RAM + 0x1f8f) & 0x1ff; |
908 | |
909 | #ifdef DEBUGGER |
910 | if (C4CosTable[angle1] == 0) |
911 | fprintf(stderr, "22 Trapezoid: Invalid tangent! angle1=%d\n" , angle1); |
912 | if (C4CosTable[angle2] == 0) |
913 | fprintf(stderr, "22 Trapezoid: Invalid tangent! angle2=%d\n" , angle2); |
914 | #endif |
915 | |
916 | int32 tan1 = (C4CosTable[angle1] != 0) ? ((((int32) C4SinTable[angle1]) << 16) / C4CosTable[angle1]) : 0x80000000; |
917 | int32 tan2 = (C4CosTable[angle2] != 0) ? ((((int32) C4SinTable[angle2]) << 16) / C4CosTable[angle2]) : 0x80000000; |
918 | |
919 | int16 y = READ_WORD(Memory.C4RAM + 0x1f83) - READ_WORD(Memory.C4RAM + 0x1f89); |
920 | int16 left, right; |
921 | |
922 | for (int j = 0; j < 225; j++) |
923 | { |
924 | if (y >= 0) |
925 | { |
926 | left = SAR((int32) tan1 * y, 16) - READ_WORD(Memory.C4RAM + 0x1f80) + READ_WORD(Memory.C4RAM + 0x1f86); |
927 | right = SAR((int32) tan2 * y, 16) - READ_WORD(Memory.C4RAM + 0x1f80) + READ_WORD(Memory.C4RAM + 0x1f86) + READ_WORD(Memory.C4RAM + 0x1f93); |
928 | |
929 | if (left < 0 && right < 0) |
930 | { |
931 | left = 1; |
932 | right = 0; |
933 | } |
934 | else |
935 | if (left < 0) |
936 | left = 0; |
937 | else |
938 | if (right < 0) |
939 | right = 0; |
940 | |
941 | if (left > 255 && right > 255) |
942 | { |
943 | left = 255; |
944 | right = 254; |
945 | } |
946 | else |
947 | if (left > 255) |
948 | left = 255; |
949 | else |
950 | if (right > 255) |
951 | right = 255; |
952 | } |
953 | else |
954 | { |
955 | left = 1; |
956 | right = 0; |
957 | } |
958 | |
959 | Memory.C4RAM[j + 0x800] = (uint8) left; |
960 | Memory.C4RAM[j + 0x900] = (uint8) right; |
961 | |
962 | y++; |
963 | } |
964 | |
965 | break; |
966 | } |
967 | |
968 | case 0x25: // Multiply |
969 | { |
970 | #ifdef DEBUGGER |
971 | //printf("25 Multiply!\n"); |
972 | if (Memory.C4RAM[0x1f4d] != 2) |
973 | printf("$7f4d=%02x, expected 02 for command 25 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
974 | #endif |
975 | int32 foo = READ_3WORD(Memory.C4RAM + 0x1f80); |
976 | int32 bar = READ_3WORD(Memory.C4RAM + 0x1f83); |
977 | foo *= bar; |
978 | WRITE_3WORD(Memory.C4RAM + 0x1f80, foo); |
979 | break; |
980 | } |
981 | |
982 | case 0x2d: // Transform Coords |
983 | #ifdef DEBUGGER |
984 | //printf("2d Transform Coords!\n"); |
985 | if (Memory.C4RAM[0x1f4d] != 2) |
986 | printf("$7f4d=%02x, expected 02 for command 2d %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
987 | if (READ_3WORD(Memory.C4RAM + 0x1f8f) & 0xff00ff) |
988 | printf("2d transform coords: Unexpected value in $7f8f: %06x\n" , READ_3WORD(Memory.C4RAM + 0x1f8f)); |
989 | if (READ_3WORD(Memory.C4RAM + 0x1f8c) != 0x001000) |
990 | printf("0d transform coords: Unexpected value in $7f8c: %06x\n" , READ_3WORD(Memory.C4RAM + 0x1f8c)); |
991 | #endif |
992 | C4WFXVal = READ_WORD(Memory.C4RAM + 0x1f81); |
993 | C4WFYVal = READ_WORD(Memory.C4RAM + 0x1f84); |
994 | C4WFZVal = READ_WORD(Memory.C4RAM + 0x1f87); |
995 | C4WFX2Val = Memory.C4RAM[0x1f89]; |
996 | C4WFY2Val = Memory.C4RAM[0x1f8a]; |
997 | C4WFDist = Memory.C4RAM[0x1f8b]; |
998 | C4WFScale = READ_WORD(Memory.C4RAM + 0x1f90); |
999 | C4TransfWireFrame2(); |
1000 | WRITE_WORD(Memory.C4RAM + 0x1f80, C4WFXVal); |
1001 | WRITE_WORD(Memory.C4RAM + 0x1f83, C4WFYVal); |
1002 | break; |
1003 | |
1004 | case 0x40: // Sum |
1005 | { |
1006 | #ifdef DEBUGGER |
1007 | //printf("40 Sum!\n"); |
1008 | if (Memory.C4RAM[0x1f4d] != 0x0e) |
1009 | printf("$7f4d=%02x, expected 0e for command 40 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
1010 | #endif |
1011 | uint16 sum = 0; |
1012 | for (int i = 0; i < 0x800; sum += Memory.C4RAM[i++]) ; |
1013 | WRITE_WORD(Memory.C4RAM + 0x1f80, sum); |
1014 | break; |
1015 | } |
1016 | |
1017 | case 0x54: // Square |
1018 | { |
1019 | #ifdef DEBUGGER |
1020 | //printf("54 Square!\n"); |
1021 | if (Memory.C4RAM[0x1f4d] != 0x0e) |
1022 | printf("$7f4d=%02x, expected 0e for command 54 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
1023 | #endif |
1024 | int64 a = (int64)READ_3WORD(Memory.C4RAM + 0x1f80); |
1025 | a |= 0xffffffffff000000 * ((a >> 23) & 1); |
1026 | //printf("%08X%08X\n", (uint32) (a>>32), (uint32) (a&0xFFFFFFFF)); |
1027 | a *= a; |
1028 | //printf("%08X%08X\n", (uint32) (a>>32), (uint32) (a&0xFFFFFFFF)); |
1029 | WRITE_3WORD(Memory.C4RAM + 0x1f83, a); |
1030 | WRITE_3WORD(Memory.C4RAM + 0x1f86, (a >> 24)); |
1031 | break; |
1032 | } |
1033 | |
1034 | case 0x5c: // Immediate Reg |
1035 | #ifdef DEBUGGER |
1036 | //printf("5c Immediate Reg!\n"); |
1037 | if (Memory.C4RAM[0x1f4d] != 0x0e) |
1038 | printf("$7f4d=%02x, expected 0e for command 5c %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
1039 | #endif |
1040 | for (int i = 0; i < 12 * 4; i++) |
1041 | Memory.C4RAM[i] = C4TestPattern[i]; |
1042 | break; |
1043 | |
1044 | case 0x89: // Immediate ROM |
1045 | #ifdef DEBUGGER |
1046 | //printf("89 Immediate ROM!\n"); |
1047 | if (Memory.C4RAM[0x1f4d] != 0x0e) |
1048 | printf("$7f4d=%02x, expected 0e for command 89 %02x\n" , Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); |
1049 | #endif |
1050 | Memory.C4RAM[0x1f80] = 0x36; |
1051 | Memory.C4RAM[0x1f81] = 0x43; |
1052 | Memory.C4RAM[0x1f82] = 0x05; |
1053 | break; |
1054 | |
1055 | default: |
1056 | #ifdef DEBUGGER |
1057 | printf("Unknown C4 command (%02x)\n" , byte); |
1058 | #endif |
1059 | break; |
1060 | } |
1061 | } |
1062 | } |
1063 | else |
1064 | if (Address == 0x7f47) |
1065 | { |
1066 | #ifdef DEBUGGER |
1067 | //printf("C4 load memory %06x => %04x, %04x bytes\n", READ_3WORD(Memory.C4RAM + 0x1f40), READ_WORD(Memory.C4RAM + 0x1f45), READ_WORD(Memory.C4RAM + 0x1f43)); |
1068 | if (byte != 0) |
1069 | printf("C4 load: non-0 written to $7f47! Wrote %02x\n" , byte); |
1070 | if (READ_WORD(Memory.C4RAM + 0x1f45) < 0x6000 || (READ_WORD(Memory.C4RAM + 0x1f45) + READ_WORD(Memory.C4RAM + 0x1f43)) > 0x6c00) |
1071 | printf("C4 load: Dest unusual! It's %04x\n" , READ_WORD(Memory.C4RAM + 0x1f45)); |
1072 | #endif |
1073 | memmove(Memory.C4RAM + (READ_WORD(Memory.C4RAM + 0x1f45) & 0x1fff), C4GetMemPointer(READ_3WORD(Memory.C4RAM + 0x1f40)), READ_WORD(Memory.C4RAM + 0x1f43)); |
1074 | } |
1075 | } |
1076 | |