]> Shamusworld >> Repos - virtualjaguar/blob - src/objectp.cpp
Fixed bitmap clipping
[virtualjaguar] / src / objectp.cpp
1 //
2 // Object Processor
3 //
4 // by cal2
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Cleanups/fixes/rewrites by James L. Hammons
7 //
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "jaguar.h"
13
14 //#define OP_DEBUG
15 //#define OP_DEBUG_BMP
16
17 #define BLEND_Y(dst, src)       op_blend_y[(((uint16)dst<<8)) | ((uint16)(src))]
18 #define BLEND_CR(dst, src)      op_blend_cr[(((uint16)dst)<<8) | ((uint16)(src))]
19 //Delete this once we're rid of zbmpop*.h...
20 #define BLEND_CC(dst, src)      op_blend_cr[(((uint16)dst)<<8) | ((uint16)(src))]
21
22 #define OBJECT_TYPE_BITMAP      0                       // 000
23 #define OBJECT_TYPE_SCALE       1                       // 001
24 #define OBJECT_TYPE_GPU         2                       // 010
25 #define OBJECT_TYPE_BRANCH      3                       // 011
26 #define OBJECT_TYPE_STOP        4                       // 100
27
28 #define CONDITION_EQUAL                         0
29 #define CONDITION_LESS_THAN                     1
30 #define CONDITION_GREATER_THAN          2
31 #define CONDITION_OP_FLAG_SET           3
32 #define CONDITION_SECOND_HALF_LINE      4
33
34 //Delete this once we're rid of zbmpop*.h...
35 #define FLAGS_RELEASE           8
36 #define FLAGS_TRANSPARENT       4
37 #define FLAGS_READMODIFY        2
38 #define FLAGS_HFLIP                     1
39
40 #define OPFLAG_RELEASE          8                       // Bus release bit
41 #define OPFLAG_TRANS            4                       // Transparency bit
42 #define OPFLAG_RMW                      2                       // Read-Modify-Write bit
43 #define OPFLAG_REFLECT          1                       // Horizontal mirror bit
44
45 // Private function prototypes
46
47 void OPProcessFixedBitmap(int scanline, uint64 p0, uint64 p1, bool render);
48 void OPProcessScaledBitmap(int scanline, uint64 p0, uint64 p1, uint64 p2, bool render);
49
50 // External global variables
51
52 extern uint32 jaguar_mainRom_crc32;
53
54 // Local global variables
55
56 static uint8 * op_blend_y;
57 static uint8 * op_blend_cr;
58 // There may be a problem with this "RAM" overlapping some of the
59 // regular TOM RAM...
60 static uint8 objectp_ram[0x40];                 // This is based at $F00000
61 uint8 objectp_running;
62 bool objectp_stop_reading_list;
63
64 static uint8 op_bitmap_bit_depth[8] = { 1, 2, 4, 8, 16, 24, 32, 0 };
65 static uint32 op_bitmap_bit_size[8] =
66         { (uint32)(0.125*65536), (uint32)(0.25*65536), (uint32)(0.5*65536), (uint32)(1*65536),
67           (uint32)(2*65536),     (uint32)(1*65536),    (uint32)(1*65536),   (uint32)(1*65536) };
68 static uint32 op_pointer;
69
70
71 //
72 // Object Processor initialization
73 //
74 void op_init(void)
75 {
76         // Blend tables (64K each)
77         memory_malloc_secure((void **)&op_blend_y, 0x10000, "Jaguar Object processor Y blend lookup table");
78         memory_malloc_secure((void **)&op_blend_cr, 0x10000, "Jaguar Object processor CR blend lookup table");
79
80         // Here we calculate the saturating blend of a signed 4-bit value and an
81         // existing Cyan/Red value as well as a signed 8-bit value and an existing intensity...
82         // Note: CRY is 4 bits Cyan, 4 bits Red, 16 bits intensitY
83         for(int i=0; i<256*256; i++)
84         {
85                 int y = (i >> 8) & 0xFF;
86                 int dy = (INT8)i;                                       // Sign extend the Y index
87                 int c1 = (i >> 8) & 0x0F;
88                 int dc1 = (INT8)(i << 4) >> 4;          // Sign extend the R index
89                 int c2 = (i >> 12) & 0x0F;
90                 int dc2 = (INT8)(i & 0xF0) >> 4;        // Sign extend the C index
91
92                 y += dy;
93                 if (y < 0)
94                         y = 0;
95                 else if (y > 0xFF)
96                         y = 0xFF;
97                 op_blend_y[i] = y;
98
99                 c1 += dc1;
100                 if (c1 < 0)
101                         c1 = 0;
102                 else if (c1 > 0x0F)
103                         c1 = 0x0F;
104                 c2 += dc2;
105
106                 if (c2 < 0)
107                         c2 = 0;
108                 else if (c2 > 0x0F)
109                         c2 = 0x0F;
110                 op_blend_cr[i] = (c2 << 4) | c1;
111         }
112
113         op_reset();
114 }
115
116 //
117 // Object Processor reset
118 //
119 void op_reset(void)
120 {
121         memset(objectp_ram, 0x00, 0x40);
122         objectp_running = 0;
123 }
124
125 void op_done(void)
126 {
127 }
128
129 //
130 // Object Processor memory access
131 // Memory range: F00010 (F00008?) - F00027
132 //
133 void op_byte_write(uint32 offset, uint8 data)
134 {
135         offset &= 0x3F;
136         objectp_ram[offset] = data;
137 }
138
139 void op_word_write(uint32 offset, uint16 data)
140 {
141         offset &= 0x3F;
142 //      objectp_ram[offset] = (data >> 8) & 0xFF;
143 //      objectp_ram[offset+1] = data & 0xFF;
144         SET16(objectp_ram, offset, data);
145
146 /*if (offset == 0x20)
147 WriteLog("OP: Setting lo list pointer: %04X\n", data);
148 if (offset == 0x22)
149 WriteLog("OP: Setting hi list pointer: %04X\n", data);//*/
150 }
151
152 uint8 op_byte_read(uint32 offset)
153 {
154         offset &= 0x3F;
155         return objectp_ram[offset];
156 }
157
158 uint16 op_word_read(uint32 offset)
159 {
160 //      return (objectp_ram[offset & 0x3F] << 8) | objectp_ram[(offset+1) & 0x3F];
161         offset &= 0x3F;
162         return GET16(objectp_ram, offset);
163 }
164
165 //      F00010-F00017   R     xxxxxxxx xxxxxxxx   OB - current object code from the graphics processor
166 //      F00020-F00023     W   xxxxxxxx xxxxxxxx   OLP - start of the object list
167 //      F00026            W   -------- -------x   OBF - object processor flag
168
169 uint32 op_get_list_pointer(void)
170 {
171         // Note: This register is LO / HI WORD, hence the funky look of this...
172 //      return (objectp_ram[0x22] << 24) | (objectp_ram[0x23] << 16) | (objectp_ram[0x20] << 8) | objectp_ram[0x21];
173         return GET16(objectp_ram, 0x20) | (GET16(objectp_ram, 0x22) << 16);
174 }
175
176 // This is WRONG, since the OBF is only 16 bits wide!!! [FIXED]
177
178 uint32 op_get_status_register(void)
179 {
180 //      return (objectp_ram[0x26] << 24) | (objectp_ram[0x27] << 16) | (objectp_ram[0x28] << 8) | objectp_ram[0x29];
181 //      return GET32(objectp_ram, 0x26);
182         return GET16(objectp_ram, 0x26);
183 }
184
185 // This is WRONG, since the OBF is only 16 bits wide!!! [FIXED]
186
187 void op_set_status_register(uint32 data)
188 {
189 /*      objectp_ram[0x26] = (data & 0xFF000000) >> 24;
190         objectp_ram[0x27] = (data & 0x00FF0000) >> 16;
191         objectp_ram[0x28] = (data & 0x0000FF00) >> 8;
192         objectp_ram[0x29] |= (data & 0xFE);*/
193         objectp_ram[0x26] = (data & 0x0000FF00) >> 8;
194         objectp_ram[0x27] |= (data & 0xFE);
195 }
196
197 void op_set_current_object(uint64 object)
198 {
199 //Not sure this is right... Wouldn't it just be stored 64 bit BE?
200         // Stored as least significant 32 bits first, ms32 last in big endian
201         objectp_ram[0x13] = object & 0xFF; object >>= 8;
202         objectp_ram[0x12] = object & 0xFF; object >>= 8;
203         objectp_ram[0x11] = object & 0xFF; object >>= 8;
204         objectp_ram[0x10] = object & 0xFF; object >>= 8;
205
206         objectp_ram[0x17] = object & 0xFF; object >>= 8;
207         objectp_ram[0x16] = object & 0xFF; object >>= 8;
208         objectp_ram[0x15] = object & 0xFF; object >>= 8;
209         objectp_ram[0x14] = object & 0xFF; 
210 }
211
212 uint64 op_load_phrase(uint32 offset)
213 {
214         offset &= ~0x07;                                                // 8 byte alignment
215         return ((uint64)jaguar_long_read(offset) << 32) | (uint64)jaguar_long_read(offset+4);
216 }
217
218 //
219 // OP replacement functions
220 //
221
222 void OPStorePhrase(uint32 offset, uint64 p)
223 {
224         offset &= ~0x07;                                                // 8 byte alignment
225         jaguar_long_write(offset, p >> 32);
226         jaguar_long_write(offset + 4, p & 0xFFFFFFFF);
227 }
228
229 //
230 // *** NEW ***
231 // Object Processor main routine
232 //
233 void OPProcessList(int scanline, bool render)
234 {
235 extern int op_start_log;
236 //      char * condition_to_str[8] =
237 //              { "==", "<", ">", "(opflag set)", "(second half line)", "?", "?", "?" };
238
239 // If jaguar_exec() is working right, we should *never* have to check for this
240 // condition...
241         if (scanline < tom_get_vdb())
242                 return;
243
244         if (scanline >= 525)//tom_getVideoModeHeight()+tom_get_vdb())
245                 return;
246
247         op_pointer = op_get_list_pointer();
248
249         objectp_stop_reading_list = false;
250
251 // *** BEGIN OP PROCESSOR TESTING ONLY ***
252 extern bool interactiveMode;
253 extern bool iToggle;
254 extern int objectPtr;
255 bool inhibit;
256 int bitmapCounter = 0;
257 // *** END OP PROCESSOR TESTING ONLY ***
258
259 //      if (op_pointer) WriteLog(" new op list at 0x%.8x scanline %i\n",op_pointer,scanline);
260         while (op_pointer)
261         {
262 // *** BEGIN OP PROCESSOR TESTING ONLY ***
263 if (interactiveMode && bitmapCounter == objectPtr)
264         inhibit = iToggle;
265 else
266         inhibit = false;
267 // *** END OP PROCESSOR TESTING ONLY ***
268                 if (objectp_stop_reading_list)
269                         return;
270                         
271                 uint64 p0 = op_load_phrase(op_pointer);
272                 op_pointer += 8;
273 if (scanline == tom_get_vdb() && op_start_log)
274 {
275 WriteLog("%08X --> phrase %08X %08X", op_pointer - 8, (int)(p0>>32), (int)(p0&0xFFFFFFFF));
276 if ((p0 & 0x07) == OBJECT_TYPE_BITMAP)
277 {
278 WriteLog(" (BITMAP) ");
279 uint64 p1 = op_load_phrase(op_pointer);
280 WriteLog("\n%08X --> phrase %08X %08X ", op_pointer, (int)(p1>>32), (int)(p1&0xFFFFFFFF));
281         uint8 bitdepth = (p1 >> 12) & 0x07;
282         int16 ypos = ((p0 >> 3) & 0x3FF);                       // ??? What if not interlaced (/2)?
283 int32 xpos = p1 & 0xFFF;
284 xpos = (xpos & 0x800 ? xpos | 0xFFFFF000 : xpos);
285         uint32 iwidth = ((p1 >> 28) & 0x3FF);
286         uint32 dwidth = ((p1 >> 18) & 0x3FF);           // Unsigned!
287         uint16 height = ((p0 >> 14) & 0x3FF) - 1;
288         uint32 link = ((p0 >> 24) & 0x7FFFF) << 3;
289         uint32 ptr = ((p0 >> 43) & 0x1FFFFF) << 3;
290         uint32 firstPix = (p1 >> 49) & 0x3F;
291         uint8 flags = (p1 >> 45) & 0x0F;
292         uint8 idx = (p1 >> 38) & 0x7F;
293         uint32 pitch = (p1 >> 15) & 0x07;
294 WriteLog("\n    [%u (%u) x %u @ %i, %u (%u bpp), l: %08X, p: %08X fp: %02X, fl:%s%s%s%s, idx:%02X, pt:%02X]\n",
295         iwidth, dwidth, height, xpos, ypos, op_bitmap_bit_depth[bitdepth], link, ptr, firstPix, (flags&FLAGS_HFLIP ? "REFLECT " : ""), (flags&FLAGS_READMODIFY ? "RMW " : ""), (flags&FLAGS_TRANSPARENT ? "TRANS " : ""), (flags&FLAGS_RELEASE ? "RELEASE" : ""), idx, pitch);
296 }
297 if ((p0 & 0x07) == OBJECT_TYPE_SCALE)
298 {
299 WriteLog(" (SCALED BITMAP)");
300 uint64 p1 = op_load_phrase(op_pointer), p2 = op_load_phrase(op_pointer+8);
301 WriteLog("\n%08X --> phrase %08X %08X ", op_pointer, (int)(p1>>32), (int)(p1&0xFFFFFFFF));
302         uint8 bitdepth = (p1 >> 12) & 0x07;
303         int16 ypos = ((p0 >> 3) & 0x3FF);                       // ??? What if not interlaced (/2)?
304 int32 xpos = p1 & 0xFFF;
305 xpos = (xpos & 0x800 ? xpos | 0xFFFFF000 : xpos);
306         uint32 iwidth = ((p1 >> 28) & 0x3FF);
307         uint32 dwidth = ((p1 >> 18) & 0x3FF);           // Unsigned!
308         uint16 height = ((p0 >> 14) & 0x3FF) - 1;
309         uint32 link = ((p0 >> 24) & 0x7FFFF) << 3;
310         uint32 ptr = ((p0 >> 43) & 0x1FFFFF) << 3;
311         uint32 firstPix = (p1 >> 49) & 0x3F;
312         uint8 flags = (p1 >> 45) & 0x0F;
313         uint8 idx = (p1 >> 38) & 0x7F;
314         uint32 pitch = (p1 >> 15) & 0x07;
315 WriteLog("\n    [%u (%u) x %u @ %i, %u (%u bpp), l: %08X, p: %08X fp: %02X, fl:%s%s%s%s, idx:%02X, pt:%02X]\n",
316         iwidth, dwidth, height, xpos, ypos, op_bitmap_bit_depth[bitdepth], link, ptr, firstPix, (flags&FLAGS_HFLIP ? "REFLECT " : ""), (flags&FLAGS_READMODIFY ? "RMW " : ""), (flags&FLAGS_TRANSPARENT ? "TRANS " : ""), (flags&FLAGS_RELEASE ? "RELEASE" : ""), idx, pitch);
317         uint32 hscale = p2 & 0xFF;
318         uint32 vscale = (p2 >> 8) & 0xFF;
319         uint32 remainder = (p2 >> 16) & 0xFF;
320 WriteLog("    [hsc: %02X, vsc: %02X, rem: %02X]\n", hscale, vscale, remainder);
321 }
322 if ((p0 & 0x07) == OBJECT_TYPE_GPU)
323 WriteLog(" (GPU)\n");
324 if ((p0 & 0x07) == OBJECT_TYPE_BRANCH)
325 {
326 WriteLog(" (BRANCH)\n");
327 uint8 * jaguar_mainRam = GetRamPtr();
328 WriteLog("[RAM] --> ");
329 for(int k=0; k<8; k++)
330         WriteLog("%02X ", jaguar_mainRam[op_pointer-8 + k]);
331 WriteLog("\n");
332 }
333 if ((p0 & 0x07) == OBJECT_TYPE_STOP)
334 WriteLog("    --> List end\n");
335 }//*/
336                 
337 //              WriteLog("%08X type %i\n", op_pointer, (uint8)p0 & 0x07);               
338                 switch ((uint8)p0 & 0x07)
339                 {
340                 case OBJECT_TYPE_BITMAP:
341                 {
342                         // Would *not* be /2 if interlaced...!
343                         uint16 ypos = ((p0 >> 3) & 0x3FF) / 2;
344 // This is only theory implied by Rayman...!
345 // It seems that if the YPOS is zero, then bump the YPOS value so that it coincides with
346 // the VDB value. With interlacing, this would be slightly more tricky.
347 // There's probably another bit somewhere that enables this mode--but so far, doesn't seem
348 // to affect any other game in a negative way (that I've seen).
349 // Either that, or it's an undocumented bug...
350                         if (ypos == 0)
351                                 ypos = tom_word_read(0xF00046) / 2;                     // Get the VDB value
352                         uint32 height = (p0 & 0xFFC000) >> 14;
353                         uint32 oldOPP = op_pointer - 8;
354 // *** BEGIN OP PROCESSOR TESTING ONLY ***
355 if (inhibit && op_start_log)
356         WriteLog("!!! ^^^ This object is INHIBITED! ^^^ !!!\n");
357 bitmapCounter++;
358 if (!inhibit)   // For OP testing only!
359 // *** END OP PROCESSOR TESTING ONLY ***
360                         if (scanline >= ypos && height > 0)
361                         {
362                                 uint64 p1 = op_load_phrase(op_pointer);
363                                 op_pointer += 8;
364 //WriteLog("OP: Writing scanline %d with ypos == %d...\n", scanline, ypos);
365 //WriteLog("--> Writing %u BPP bitmap...\n", op_bitmap_bit_depth[(p1 >> 12) & 0x07]);
366                                 OPProcessFixedBitmap(scanline, p0, p1, render);
367
368                                 // OP write-backs
369
370 //???Does this really happen??? Doesn't seem to work if you do this...!
371 //                              uint32 link = (p0 & 0x7FFFF000000) >> 21;
372 //                              SET16(objectp_ram, 0x20, link & 0xFFFF);        // OLP
373 //                              SET16(objectp_ram, 0x22, link >> 16);
374 /*                              uint32 height = (p0 & 0xFFC000) >> 14;
375                                 if (height - 1 > 0)
376                                         height--;*/
377                                 // NOTE: Would subtract 2 if in interlaced mode...!
378 //                              uint64 height = ((p0 & 0xFFC000) - 0x4000) & 0xFFC000;
379 //                              if (height)
380                                         height--;
381
382                                 uint64 data = (p0 & 0xFFFFF80000000000) >> 40;
383                                 uint64 dwidth = (p1 & 0xFFC0000) >> 15;
384                                 data += dwidth;
385
386                                 p0 &= ~0xFFFFF80000FFC000;                      // Mask out old data...
387                                 p0 |= (uint64)height << 14;
388                                 p0 |= data << 40;
389                                 OPStorePhrase(oldOPP, p0);
390                         }
391                         op_pointer = (p0 & 0x000007FFFF000000) >> 21;
392                         break;
393                 }
394                 case OBJECT_TYPE_SCALE:
395                 {
396                         // Would *not* be /2 if interlaced...!
397                         uint16 ypos = ((p0 >> 3) & 0x3FF) / 2;
398 // This is only theory implied by Rayman...!
399 // It seems that if the YPOS is zero, then bump the YPOS value so that it coincides with
400 // the VDB value. With interlacing, this would be slightly more tricky.
401 // There's probably another bit somewhere that enables this mode--but so far, doesn't seem
402 // to affect any other game in a negative way (that I've seen).
403 // Either that, or it's an undocumented bug...
404                         if (ypos == 0)
405                                 ypos = tom_word_read(0xF00046) / 2;                     // Get the VDB value
406                         uint32 height = (p0 & 0xFFC000) >> 14;
407                         uint32 oldOPP = op_pointer - 8;
408 // *** BEGIN OP PROCESSOR TESTING ONLY ***
409 if (inhibit && op_start_log)
410         WriteLog("!!! ^^^ This object is INHIBITED! ^^^ !!!\n");
411 bitmapCounter++;
412 if (!inhibit)   // For OP testing only!
413 // *** END OP PROCESSOR TESTING ONLY ***
414                         if (scanline >= ypos && height > 0)
415                         {
416                                 uint64 p1 = op_load_phrase(op_pointer);
417                                 op_pointer += 8;
418                                 uint64 p2 = op_load_phrase(op_pointer);
419                                 op_pointer += 8;
420 //WriteLog("OP: %08X (%d) %08X%08X %08X%08X %08X%08X\n", oldOPP, scanline, (uint32)(p0>>32), (uint32)(p0&0xFFFFFFFF), (uint32)(p1>>32), (uint32)(p1&0xFFFFFFFF), (uint32)(p2>>32), (uint32)(p2&0xFFFFFFFF));
421                                 OPProcessScaledBitmap(scanline, p0, p1, p2, render);
422
423                                 // OP write-backs
424
425 //???Does this really happen??? Doesn't seem to work if you do this...!
426 //                              uint32 link = (p0 & 0x7FFFF000000) >> 21;
427 //                              SET16(objectp_ram, 0x20, link & 0xFFFF);        // OLP
428 //                              SET16(objectp_ram, 0x22, link >> 16);
429 /*                              uint32 height = (p0 & 0xFFC000) >> 14;
430                                 if (height - 1 > 0)
431                                         height--;*/
432                                 // NOTE: Would subtract 2 if in interlaced mode...!
433 //                              uint64 height = ((p0 & 0xFFC000) - 0x4000) & 0xFFC000;
434
435                                 uint8 remainder = p2 >> 16, vscale = p2 >> 8;
436                                 if (vscale == 0)
437                                         vscale = 0x20;                                  // OP bug???
438
439                                 remainder -= 0x20;                                      // 1.0f in [3.5] fixed point format
440                                 if (remainder & 0x80)                           // I.e., it's negative
441                                 {
442                                         uint64 data = (p0 & 0xFFFFF80000000000) >> 40;
443                                         uint64 dwidth = (p1 & 0xFFC0000) >> 15;
444
445                                         while (remainder & 0x80)
446                                         {
447                                                 remainder += vscale;
448                                                 if (height)
449                                                         height--;
450
451                                                 data += dwidth;
452                                         }
453                                         p0 &= ~0xFFFFF80000FFC000;              // Mask out old data...
454                                         p0 |= (uint64)height << 14;
455                                         p0 |= data << 40;
456                                         OPStorePhrase(oldOPP, p0);
457                                 }
458
459 //WriteLog(" [%08X%08X -> ", (uint32)(p2>>32), (uint32)(p2&0xFFFFFFFF));
460                                 p2 &= ~0x0000000000FF0000;
461                                 p2 |= (uint64)remainder << 16;
462 //WriteLog("%08X%08X]\n", (uint32)(p2>>32), (uint32)(p2&0xFFFFFFFF));
463                                 OPStorePhrase(oldOPP+16, p2);
464 //remainder = (uint8)(p2 >> 16), vscale = (uint8)(p2 >> 8);
465 //WriteLog(" [after]: rem=%02X, vscale=%02X\n", remainder, vscale);
466                         }
467                         op_pointer = (p0 & 0x000007FFFF000000) >> 21;
468                         break;
469                 }
470                 case OBJECT_TYPE_GPU:
471                 {
472                         op_set_current_object(p0);
473                         gpu_set_irq_line(3, 1);
474                         break;
475                 }
476                 case OBJECT_TYPE_BRANCH:
477                 {
478                         uint16 ypos = (p0 >> 3) & 0x7FF;
479                         uint8  cc   = (p0 >> 14) & 0x03;
480                         uint32 link = (p0 >> 21) & 0x3FFFF8;
481                         
482 //                      if ((ypos!=507)&&(ypos!=25))
483 //                              WriteLog("\t%i%s%i link=0x%.8x\n",scanline,condition_to_str[cc],ypos>>1,link);
484                         switch (cc)
485                         {
486                         case CONDITION_EQUAL:
487                                 if (ypos != 0x7FF && (ypos & 0x01))
488                                         ypos ^= 0x01;
489                                 if ((2 * tom_get_scanline()) == ypos || ypos == 0x7FF)
490                                         op_pointer = link;
491                                 break;
492                         case CONDITION_LESS_THAN:
493                                 if ((2 * tom_get_scanline()) < ypos)
494                                         op_pointer = link;
495                                 break;
496                         case CONDITION_GREATER_THAN:
497                                 if ((2 * tom_get_scanline()) > ypos)
498                                         op_pointer = link;
499                                 break;
500                         case CONDITION_OP_FLAG_SET:
501                                 if (op_get_status_register() & 0x01)
502                                         op_pointer = link;
503                                 break;
504                         case CONDITION_SECOND_HALF_LINE:
505                                 // This basically means branch if bit 10 of HC is set
506                                 WriteLog("OP: Unexpected CONDITION_SECOND_HALF_LINE in BRANCH object\nop: shuting down\n");
507                                 fclose(log_get());
508                                 exit(0);
509                                 break;
510                         default:
511                                 WriteLog("OP: Unimplemented branch condition %i\n", cc);
512                         }
513                         break;
514                 }
515                 case OBJECT_TYPE_STOP:
516                 {
517 //op_start_log = 0;
518                         // unsure
519 //WriteLog("OP: --> STOP\n");
520                         op_set_status_register(((p0>>3) & 0xFFFFFFFF));
521                         
522                         if (p0 & 0x8)
523                         {
524                                 tom_set_pending_object_int();
525                                 if (tom_irq_enabled(2) && jaguar_interrupt_handler_is_valid(64))
526                                         m68k_set_irq(7);                                // Cause an NMI to occur...
527                         }
528
529                         return;
530                         break;
531                 }
532                 default:
533                         WriteLog("op: unknown object type %i\n", ((uint8)p0 & 0x07)); 
534                         return;
535                 }
536         }
537 }
538
539 //
540 // *** NEW ***
541 // Store fixed size bitmap in line buffer
542 //
543
544 // Interesting thing about Rayman: There seems to be a transparent bitmap (1/8/16 bpp--which?)
545 // being rendered under his feet--doesn't align when walking... Check it out!
546
547 void OPProcessFixedBitmap(int scanline, uint64 p0, uint64 p1, bool render)
548 {
549 // Need to make sure that when writing that it stays within the line buffer...
550 // LBUF ($F01800 - $F01D9E) 360 x 32-bit RAM
551         uint8 depth = (p1 >> 12) & 0x07;                                // Color depth of image
552 //Why is HBlankWidthInPixels subtracted from this???
553 //      int32 xpos = (((int32)((p1 << 20) & 0xFFFFFFFF)) >> 20) - tom_getHBlankWidthInPixels();
554         int32 xpos = ((int16)((p1 << 4) & 0xFFFF)) >> 4;// Image xpos in LBUF
555         uint32 iwidth = (p1 >> 28) & 0x3FF;                             // Image width in *phrases*
556         uint32 data = (p0 >> 40) & 0xFFFFF8;                    // Pixel data address
557 #ifdef OP_DEBUG_BMP
558 // Prolly should use this... Though not sure exactly how.
559         uint32  firstPix = (p1 >> 49) & 0x3F;
560 #endif
561 // We can ignore the RELEASE (high order) bit for now--probably forever...!
562 //      uint8 flags = (p1 >> 45) & 0x0F;        // REFLECT, RMW, TRANS, RELEASE
563 //Optimize: break these out to their own BOOL values
564         uint8 flags = (p1 >> 45) & 0x07;                                // REFLECT (0), RMW (1), TRANS (2)
565 // "For images with 1 to 4 bits/pixel the top 7 to 4 bits of the index
566 //  provide the most significant bits of the palette address."
567         uint8 index = (p1 >> 37) & 0xFE;                                // CLUT index offset (upper pix, 1-4 bpp)
568         uint32 pitch = (p1 >> 15) & 0x07;                               // Phrase pitch
569
570 //      int16 scanlineWidth = tom_getVideoModeWidth();
571         uint8 * tom_ram_8 = tom_get_ram_pointer();
572         uint8 * paletteRAM = &tom_ram_8[0x400];
573         // This is OK as long as it's used correctly: For 16-bit RAM to RAM direct copies--NOT
574         // for use when using endian-corrected data (i.e., any of the *_word_read functions!)
575         uint16 * paletteRAM16 = (uint16 *)paletteRAM;
576
577 //      WriteLog("bitmap %ix? %ibpp at %i,? firstpix=? data=0x%.8x pitch %i hflipped=%s dwidth=? (linked to ?) RMW=%s Tranparent=%s\n",
578 //              iwidth, op_bitmap_bit_depth[bitdepth], xpos, ptr, pitch, (flags&FLAGS_HFLIP ? "yes" : "no"), (flags&FLAGS_READMODIFY ? "yes" : "no"), (flags&FLAGS_TRANSPARENT ? "yes" : "no"));
579
580 // Is it OK to have a 0 for the data width??? (i.e., undocumented?)
581 // Seems to be... Seems that dwidth *can* be zero (i.e., reuse same line) as well.
582 // Pitch == 0 is OK too...
583 //      if (!render || op_pointer == 0 || dwidth == 0 || ptr == 0 || pitch == 0)
584 //I'm not convinced that we need to concern ourselves with data & op_pointer here either!
585         if (!render || iwidth == 0) // || data == 0 || op_pointer == 0)
586                 return;
587
588 //#define OP_DEBUG_BMP
589 //#ifdef OP_DEBUG_BMP
590 //      WriteLog("bitmap %ix%i %ibpp at %i,%i firstpix=%i data=0x%.8x pitch %i hflipped=%s dwidth=%i (linked to 0x%.8x) Transluency=%s\n",
591 //              iwidth, height, op_bitmap_bit_depth[bitdepth], xpos, ypos, firstPix, ptr, pitch, (flags&FLAGS_HFLIP ? "yes" : "no"), dwidth, op_pointer, (flags&FLAGS_READMODIFY ? "yes" : "no"));
592 //#endif
593
594         int32 phraseWidthToPixels[8] = { 64, 32, 16, 8, 4, 2, 0, 0 };
595 //      int32 leftMargin = xpos, rightMargin = (xpos + (phraseWidthToPixels[depth] * iwidth)) - 1;
596         int32 startPos = xpos, endPos = xpos +
597                 (!(flags & OPFLAG_REFLECT) ? (phraseWidthToPixels[depth] * iwidth) - 1
598                 : -((phraseWidthToPixels[depth] * iwidth) + 1));
599         uint32 clippedWidth = 0, phraseClippedWidth = 0, dataClippedWidth = 0;//, phrasePixel = 0;
600         bool in24BPPMode = (((GET16(tom_ram_8, 0x0028) >> 1) & 0x03) == 1 ? true : false);      // VMODE
601         // Not sure if this is Jaguar Two only location or what...
602         // From the docs, it is... If we want to limit here we should think of something else.
603 //      int32 limit = GET16(tom_ram_8, 0x0008);                 // LIMIT
604         int32 limit = 720;
605         int32 lbufWidth = (!in24BPPMode ? limit - 1 : (limit / 2) - 1); // Zero based limit...
606
607         // If the image is completely to the left or right of the line buffer, then bail.
608 //If in REFLECT mode, then these values are swapped! !!! FIX !!! [DONE]
609 //There are four possibilities:
610 //  1. image sits on left edge and no REFLECT; starts out of bounds but ends in bounds.
611 //  2. image sits on left edge and REFLECT; starts in bounds but ends out of bounds.
612 //  3. image sits on right edge and REFLECT; starts out of bounds but ends in bounds.
613 //  4. image sits on right edge and no REFLECT; starts in bounds but ends out of bounds.
614 //Numbers 2 & 4 can be caught by checking the LBUF clip while in the inner loop,
615 // numbers 1 & 3 are of concern.
616 // This *indirectly* handles only cases 2 & 4! And is WRONG is REFLECT is set...!
617 //      if (rightMargin < 0 || leftMargin > lbufWidth)
618
619 // It might be easier to swap these (if REFLECTed) and just use XPOS down below...
620 // That way, you could simply set XPOS to leftMargin if !REFLECT and to rightMargin otherwise.
621 // Still have to be careful with the DATA and IWIDTH values though...
622
623 //      if ((!(flags & OPFLAG_REFLECT) && (rightMargin < 0 || leftMargin > lbufWidth))
624 //              || ((flags & OPFLAG_REFLECT) && (leftMargin < 0 || rightMargin > lbufWidth)))
625 //              return;
626         if ((!(flags & OPFLAG_REFLECT) && (endPos < 0 || startPos > lbufWidth))
627                 || ((flags & OPFLAG_REFLECT) && (startPos < 0 || endPos > lbufWidth)))
628                 return;
629
630         // Otherwise, find the clip limits and clip the phrase as well...
631         // NOTE: I'm fudging here by letting the actual blit overstep the bounds of the
632         //       line buffer, but it shouldn't matter since there are two unused line
633         //       buffers below and nothing above and I'll at most write 8 bytes outside
634         //       the line buffer... I could use a fractional clip begin/end value, but
635         //       this makes the blit a *lot* more hairy. I might fix this in the future
636         //       if it becomes necessary. (JLH)
637         //       Probably wouldn't be *that* hairy. Just use a delta that tells the inner loop
638         //       which pixel in the phrase is being written, and quit when either end of phrases
639         //       is reached or line buffer extents are surpassed.
640
641 //This stuff is probably wrong as well... !!! FIX !!!
642 //The strange thing is that it seems to work, but that's no guarantee that it's bulletproof!
643 //Yup. Seems that JagMania doesn't work correctly with this...
644 //Dunno if this is the problem, but Atari Karts is showing *some* of the road now...
645 //      if (!(flags & OPFLAG_REFLECT))
646
647 /*
648         if (leftMargin < 0)
649                 clippedWidth = 0 - leftMargin,
650                 phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth],
651                 leftMargin = 0 - (clippedWidth % phraseWidthToPixels[depth]);
652 //              leftMargin = 0;
653
654         if (rightMargin > lbufWidth)
655                 clippedWidth = rightMargin - lbufWidth,
656                 phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth];//,
657 //              rightMargin = lbufWidth + (clippedWidth % phraseWidthToPixels[depth]);
658 //              rightMargin = lbufWidth;
659 */
660         // NOTE: We're just using endPos to figure out how much, if any, to clip by.
661         // ALSO: There may be another case where we start out of bounds and end out of bounds...!
662         if (startPos < 0)                       // Case #1: Begin out, end in, L to R
663                 clippedWidth = 0 - startPos,
664                 dataClippedWidth = phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth],
665                 startPos = 0 - (clippedWidth % phraseWidthToPixels[depth]);
666
667         if (endPos < 0)                         // Case #2: Begin in, end out, R to L
668                 clippedWidth = 0 - endPos,
669                 phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth];
670
671         if (endPos > lbufWidth)         // Case #3: Begin in, end out, L to R
672                 clippedWidth = endPos - lbufWidth,
673                 phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth];
674
675         if (startPos > lbufWidth)       // Case #4: Begin out, end in, R to L
676                 clippedWidth = startPos - lbufWidth,
677                 dataClippedWidth = phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth],
678                 startPos = lbufWidth + (clippedWidth % phraseWidthToPixels[depth]);
679
680         // If the image is sitting on the line buffer left or right edge, we need to compensate
681         // by decreasing the image phrase width accordingly.
682         iwidth -= phraseClippedWidth;
683
684         // Also, if we're clipping the phrase we need to make sure we're in the correct part of
685         // the pixel data.
686 //      data += phraseClippedWidth * (pitch << 3);
687         data += dataClippedWidth * (pitch << 3);
688
689         // NOTE: When the bitmap is in REFLECT mode, the XPOS marks the *right* side of the
690         //       bitmap! This makes clipping & etc. MUCH, much easier...!
691 //      uint32 lbufAddress = 0x1800 + (!in24BPPMode ? leftMargin * 2 : leftMargin * 4);
692         uint32 lbufAddress = 0x1800 + (!in24BPPMode ? startPos * 2 : startPos * 4);
693         uint8 * currentLineBuffer = &tom_ram_8[lbufAddress];
694
695         // Render.
696
697 // Hmm. We check above for 24 BPP mode, but don't do anything about it below...
698 // If we *were* in 24 BPP mode, how would you convert CRY to RGB24? Seems to me
699 // that if you're in CRY mode then you wouldn't be able to use 24 BPP bitmaps
700 // anyway.
701
702         if (depth == 0)                                                                 // 1 BPP
703         {
704 //              uint32 paletteIndex = index << 1;
705                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
706                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
707
708                 while (iwidth--)
709                 {
710                         // Fetch phrase...
711                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
712                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
713
714                         for(int i=0; i<64; i++)
715                         {
716                                 uint8 bit = pixels >> 63;
717 // Seems to me that both of these are in the same endian, so we could cast it as
718 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
719 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
720 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
721 // No, it isn't because we read the memory in an endian safe way--this *won't* work...
722                                 if ((flags & OPFLAG_TRANS) && bit == 0)
723                                         ;       // Do nothing...
724                                 else
725                                 {
726                                         if (!(flags & OPFLAG_RMW))
727 //Optimize: Set palleteRAM16 to beginning of palette RAM + index*2 and use only [bit] as index...
728                                                 *(uint16 *)currentLineBuffer = paletteRAM16[index | bit];
729                                         else
730                                                 *currentLineBuffer = 
731                                                         BLEND_CR(*currentLineBuffer, paletteRAM[(index | bit) << 1]),
732                                                 *(currentLineBuffer + 1) = 
733                                                         BLEND_Y(*(currentLineBuffer + 1), paletteRAM[((index | bit) << 1) + 1]);
734                                 }
735
736                                 currentLineBuffer += lbufDelta;
737                                 pixels <<= 1;
738                         }
739                 }
740         }
741         else if (depth == 1)                                                    // 2 BPP
742         {
743                 index &= 0xFC;                                                          // Top six bits form CLUT index
744                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
745                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
746
747                 while (iwidth--)
748                 {
749                         // Fetch phrase...
750                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
751                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
752
753                         for(int i=0; i<32; i++)
754                         {
755                                 uint8 bits = pixels >> 62;
756 // Seems to me that both of these are in the same endian, so we could cast it as
757 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
758 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
759 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
760 // No, it isn't because we read the memory in an endian safe way--this *won't* work...
761                                 if ((flags & OPFLAG_TRANS) && bits == 0)
762                                         ;       // Do nothing...
763                                 else
764                                 {
765                                         if (!(flags & OPFLAG_RMW))
766                                                 *(uint16 *)currentLineBuffer = paletteRAM16[index | bits];
767                                         else
768                                                 *currentLineBuffer = 
769                                                         BLEND_CR(*currentLineBuffer, paletteRAM[(index | bits) << 1]),
770                                                 *(currentLineBuffer + 1) = 
771                                                         BLEND_Y(*(currentLineBuffer + 1), paletteRAM[((index | bits) << 1) + 1]);
772                                 }
773
774                                 currentLineBuffer += lbufDelta;
775                                 pixels <<= 2;
776                         }
777                 }
778         }
779         else if (depth == 2)                                                    // 4 BPP
780         {
781                 index &= 0xF0;                                                          // Top four bits form CLUT index
782                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
783                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
784
785                 while (iwidth--)
786                 {
787                         // Fetch phrase...
788                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
789                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
790
791                         for(int i=0; i<16; i++)
792                         {
793                                 uint8 bits = pixels >> 60;
794 // Seems to me that both of these are in the same endian, so we could cast it as
795 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
796 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
797 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
798 // No, it isn't because we read the memory in an endian safe way--this *won't* work...
799                                 if ((flags & OPFLAG_TRANS) && bits == 0)
800                                         ;       // Do nothing...
801                                 else
802                                 {
803                                         if (!(flags & OPFLAG_RMW))
804                                                 *(uint16 *)currentLineBuffer = paletteRAM16[index | bits];
805                                         else
806                                                 *currentLineBuffer = 
807                                                         BLEND_CR(*currentLineBuffer, paletteRAM[(index | bits) << 1]),
808                                                 *(currentLineBuffer + 1) = 
809                                                         BLEND_Y(*(currentLineBuffer + 1), paletteRAM[((index | bits) << 1) + 1]);
810                                 }
811
812                                 currentLineBuffer += lbufDelta;
813                                 pixels <<= 4;
814                         }
815                 }
816         }
817         else if (depth == 3)                                                    // 8 BPP
818         {
819                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
820                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
821
822                 while (iwidth--)
823                 {
824                         // Fetch phrase...
825                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
826                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
827
828                         for(int i=0; i<8; i++)
829                         {
830                                 uint8 bits = pixels >> 56;
831 // Seems to me that both of these are in the same endian, so we could cast it as
832 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
833 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
834 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
835 // No, it isn't because we read the memory in an endian safe way--this *won't* work...
836                                 if ((flags & OPFLAG_TRANS) && bits == 0)
837                                         ;       // Do nothing...
838                                 else
839                                 {
840                                         if (!(flags & OPFLAG_RMW))
841                                                 *(uint16 *)currentLineBuffer = paletteRAM16[bits];
842                                         else
843                                                 *currentLineBuffer = 
844                                                         BLEND_CR(*currentLineBuffer, paletteRAM[bits << 1]),
845                                                 *(currentLineBuffer + 1) = 
846                                                         BLEND_Y(*(currentLineBuffer + 1), paletteRAM[(bits << 1) + 1]);
847                                 }
848
849                                 currentLineBuffer += lbufDelta;
850                                 pixels <<= 8;
851                         }
852                 }
853         }
854         else if (depth == 4)                                                    // 16 BPP
855         {
856                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
857                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
858
859                 while (iwidth--)
860                 {
861                         // Fetch phrase...
862                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
863                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
864
865                         for(int i=0; i<4; i++)
866                         {
867                                 uint8 bitsHi = pixels >> 56, bitsLo = pixels >> 48;
868 // Seems to me that both of these are in the same endian, so we could cast it as
869 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
870 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
871 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
872 // No, it isn't because we read the memory in an endian safe way--it *won't* work...
873                                 if ((flags & OPFLAG_TRANS) && (bitsLo | bitsHi) == 0)
874                                         ;       // Do nothing...
875                                 else
876                                 {
877                                         if (!(flags & OPFLAG_RMW))
878                                                 *currentLineBuffer = bitsHi,
879                                                 *(currentLineBuffer + 1) = bitsLo;
880                                         else
881                                                 *currentLineBuffer = 
882                                                         BLEND_CR(*currentLineBuffer, bitsHi),
883                                                 *(currentLineBuffer + 1) = 
884                                                         BLEND_Y(*(currentLineBuffer + 1), bitsLo);
885                                 }
886
887                                 currentLineBuffer += lbufDelta;
888                                 pixels <<= 16;
889                         }
890                 }
891         }
892         else if (depth == 5)                                                    // 24 BPP
893         {
894 WriteLog("OP: Writing 24 BPP bitmap!\n");
895                 // Not sure, but I think RMW only works with 16 BPP and below, and only in CRY mode...
896                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 4 into it.
897                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 4) | 0x04;
898
899                 while (iwidth--)
900                 {
901                         // Fetch phrase...
902                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
903                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
904
905                         for(int i=0; i<2; i++)
906                         {
907                                 uint8 bits3 = pixels >> 56, bits2 = pixels >> 48,
908                                         bits1 = pixels >> 40, bits0 = pixels >> 32;
909 // Seems to me that both of these are in the same endian, so we could cast it as
910 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
911 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
912 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
913 // No, it isn't because we read the memory in an endian safe way--it *won't* work...
914                                 if ((flags & OPFLAG_TRANS) && (bits3 | bits2 | bits1 | bits0) == 0)
915                                         ;       // Do nothing...
916                                 else
917                                         *currentLineBuffer = bits3,
918                                         *(currentLineBuffer + 1) = bits2,
919                                         *(currentLineBuffer + 2) = bits1,
920                                         *(currentLineBuffer + 3) = bits0;
921
922                                 currentLineBuffer += lbufDelta;
923                                 pixels <<= 32;
924                         }
925                 }
926         }
927 }
928
929 //
930 // *** NEW ***
931 // Store scaled bitmap in line buffer
932 //
933 void OPProcessScaledBitmap(int scanline, uint64 p0, uint64 p1, uint64 p2, bool render)
934 {
935         int32 xpos = (((int32)((p1 << 20) & 0xFFFFFFFF)) >> 20) - tom_getHBlankWidthInPixels();
936 //      uint16 ypos = ((p0 & 0x3FF8) >> 3) / 2;
937         uint16 iwidth = ((p1 >> 28) & 0x3FF) * 4;
938         uint16 dwidth = ((p1 >> 18) & 0x3FF) * 4;               // Unsigned!
939 //      uint16 height = (p0 >> 14) & 0x3FF;                             // Unsigned!
940 //      uint32 link = ((p0 >> 24) & 0x7FFFF) << 3;
941         uint32 ptr = (p0 >> 40) & 0xFFFFF8;
942 //unused        uint32 firstPix = (p1 >> 49) & 0x3F;
943         uint8 flags = (p1 >> 45) & 0x0F;
944         uint8 idx = (p1 >> 38) & 0x7F;
945         uint8 pitch = (p1 >> 15) & 0x07;
946         uint8 bitdepth = (p1 >> 12) & 0x07;
947
948         int16 scanline_width = tom_getVideoModeWidth();
949         uint8 * tom_ram_8 = tom_get_ram_pointer();
950         uint8 * current_line_buffer = &tom_ram_8[0x1800];
951
952         uint32 vscale_fixed3p5 = (p2 >> 8) & 0xFF;
953         uint32 hscale_fixed3p5 = p2 & 0xFF;
954         float vscale = (float)vscale_fixed3p5 / 32.0f, hscale = (float)hscale_fixed3p5 / 32.0f;
955
956 //No hacks!
957 /*      if (jaguar_mainRom_crc32==0x5a5b9c68) // atari karts
958         {
959                 if (vscale == 0.0f) 
960                         vscale = 1.0f;
961
962                 if (ypos == 0)
963                         ypos = scanline;
964         }*/
965 #ifdef OP_DEBUG_BMP
966         if (xpos == -3)
967                 WriteLog("[scanline %i] %ix%i scaled to %ix%i scale (%f, %f)%i bpp pitch %i at (%i,%i) @ 0x%.8x Transluency=%s\n",
968                         scanline, iwidth,height, (int)(iwidth*hscale), (int)(height*vscale), hscale, vscale,
969                         op_bitmap_bit_depth[bitdepth], pitch, xpos, ypos, ptr, (flags&FLAGS_READMODIFY) ? "yes" : "no");
970 #endif
971 //No hacks!
972 /*      if (jaguar_mainRom_crc32==0x2f032271)
973                 ypos += 8;*/
974
975         if (!render || dwidth == 0 || ptr == 0 || pitch == 0)
976                 return;
977
978         if (bitdepth <= 3)                                      // 1, 2, 4, 8 BPP
979                 iwidth *= 2, dwidth *= 2;
980
981         uint16 scaled_width = (uint16)((float)iwidth * hscale);
982
983         if (op_bitmap_bit_depth[bitdepth] == 4) // why ?
984                 scaled_width *= 2;
985
986         if (op_bitmap_bit_depth[bitdepth] == 2) // why ?
987                 scaled_width *= 4;
988
989         if (op_bitmap_bit_depth[bitdepth] == 1) // why ?
990                 scaled_width *= 8;
991
992         // visible ?
993 /*      if ((scanline < ypos) || (scanline > (ypos + scaled_height)) || ((xpos + scaled_width) < 0)
994                 || (xpos >= scanline_width))*/
995         if ((xpos + scaled_width) < 0 || xpos >= scanline_width)
996                 return;
997
998         if (xpos < 0)
999         {
1000                 scaled_width += xpos;
1001                 ptr += (pitch * op_bitmap_bit_size[bitdepth] * ((uint32)((-xpos) / hscale))) >> 16;
1002                 xpos = 0;
1003         }
1004
1005         if (iwidth <= 0)
1006                 return;
1007
1008         if (flags & FLAGS_HFLIP)
1009         {
1010                 if (xpos < 0 || (xpos-scaled_width) >= scanline_width)
1011                         return;
1012
1013                 if ((xpos - scaled_width) < 0)
1014                         scaled_width = xpos;
1015         }
1016         else
1017         {
1018                 if ((xpos + scaled_width) < 0 || xpos >= scanline_width)
1019                         return;
1020
1021                 if ((xpos + scaled_width) > scanline_width)
1022                         scaled_width = scanline_width-xpos;
1023         }
1024         
1025         current_line_buffer += xpos * 2;
1026
1027         int32 hscale_fixed = (int32)(65536.0f / hscale);
1028         int32 cnt = 0;
1029
1030         if (op_bitmap_bit_depth[bitdepth] == 1)
1031         {
1032                 if (pitch == 1)
1033                 {
1034 #include "zbmpop1.h"
1035                 }
1036                 else
1037                 {
1038 #include "zbmpop1p.h"
1039                 }
1040         }
1041         else if (op_bitmap_bit_depth[bitdepth] == 2)
1042         {
1043                 if (pitch == 1)
1044                 {
1045 #include "zbmpop2.h"
1046                 }
1047                 else
1048                 {
1049 #include "zbmpop2p.h"
1050                 }
1051         }
1052         else if (op_bitmap_bit_depth[bitdepth] == 4)
1053         {
1054                 if (pitch == 1)
1055                 {
1056 #include "zbmpop4.h"
1057                 }
1058                 else
1059                 {
1060 #include "zbmpop4p.h"
1061                 }
1062         }
1063         else if (op_bitmap_bit_depth[bitdepth] == 8)
1064         {
1065                 if (pitch == 1)
1066                 {
1067 #include "zbmpop8.h"
1068                 }
1069                 else
1070                 {
1071 #include "zbmpop8p.h"
1072                 }
1073         }
1074         else if (op_bitmap_bit_depth[bitdepth] == 16)
1075         {
1076                 if (pitch == 1)
1077                 {
1078 #include "zbmpop16.h"
1079                 }
1080                 else
1081                 {
1082 #include "zbmpop16p.h"
1083                 }
1084         }
1085         else
1086                 WriteLog("(unimplemented) %i bpp scaled bitmap\n",op_bitmap_bit_depth[bitdepth]);
1087 }