]> Shamusworld >> Repos - virtualjaguar/blob - src/objectp.cpp
Virtual Jaguar 1.0.4 update (Shamus)
[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         uint32 clippedWidth = 0, phraseClippedWidth = 0;//, phrasePixel = 0;
597         bool in24BPPMode = (((GET16(tom_ram_8, 0x0028) >> 1) & 0x03) == 1 ? true : false);      // VMODE
598         // Not sure if this is Jaguar Two only location or what...
599         // From the docs, it is... If we want to limit here we should think of something else.
600 //      int32 limit = GET16(tom_ram_8, 0x0008);                 // LIMIT
601         int32 limit = 720;
602         int32 lbufWidth = (!in24BPPMode ? limit - 1 : (limit / 2) - 1); // Zero based limit...
603
604         // If the image is completely to the left or right of the line buffer, then bail.
605 //If in REFLECT mode, then these values are swapped! !!! FIX !!! [DONE]
606 //There are four possibilities:
607 //  1. image sits on left edge and no REFLECT; starts out of bounds but ends in bounds.
608 //  2. image sits on left edge and REFLECT; starts in bounds but ends out of bounds.
609 //  3. image sits on right edge and REFLECT; starts out of bounds but ends in bounds.
610 //  4. image sits on right edge and no REFLECT; starts in bounds but ends out of bounds.
611 //Numbers 2 & 4 can be caught by checking the LBUF clip while in the inner loop,
612 // numbers 1 & 3 are of concern.
613 // This *indirectly* handles only cases 2 & 4! And is WRONG is REFLECT is set...!
614 //      if (rightMargin < 0 || leftMargin > lbufWidth)
615
616 // It might be easier to swap these (if REFLECTed) and just use XPOS down below...
617 // That way, you could simply set XPOS to leftMargin if !REFLECT and to rightMargin otherwise.
618 // Still have to be careful with the DATA and IWIDTH values though...
619
620         if ((!(flags & OPFLAG_REFLECT) && (rightMargin < 0 || leftMargin > lbufWidth))
621                 || ((flags & OPFLAG_REFLECT) && (leftMargin < 0 || rightMargin > lbufWidth)))
622                 return;
623
624         // Otherwise, find the clip limits and clip the phrase as well...
625         // NOTE: I'm fudging here by letting the actual blit overstep the bounds of the
626         //       line buffer, but it shouldn't matter since there are two unused line
627         //       buffers below and nothing above and I'll at most write 8 bytes outside
628         //       the line buffer... I could use a fractional clip begin/end value, but
629         //       this makes the blit a *lot* more hairy. I might fix this in the future
630         //       if it becomes necessary. (JLH)
631         //       Probably wouldn't be *that* hairy. Just use a delta that tells the inner loop
632         //       which pixel in the phrase is being written, and quit when either end of phrases
633         //       is reached or line buffer extents are surpassed.
634
635 //This stuff is probably wrong as well... !!! FIX !!!
636 //The strange thing is that it seems to work, but that's no guarantee that it's bulletproof!
637 //Yup. Seems that JagMania doesn't work correctly with this...
638 //Dunno if this is the problem, but Atari Karts is showing *some* of the road now...
639         if (leftMargin < 0)
640                 clippedWidth = 0 - leftMargin,
641                 phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth],
642                 leftMargin = 0 - (clippedWidth % phraseWidthToPixels[depth]);
643 //              leftMargin = 0;
644
645         if (rightMargin > lbufWidth)
646                 clippedWidth = rightMargin - lbufWidth,
647                 phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth],
648                 rightMargin = lbufWidth + (clippedWidth % phraseWidthToPixels[depth]);
649 //              rightMargin = lbufWidth;
650
651         // If the image is sitting on the line buffer left or right edge, we need to compensate
652         // by decreasing the image phrase width accordingly.
653         iwidth -= phraseClippedWidth;
654
655         // Also, if we're clipping the phrase we need to make sure we're in the correct part of
656         // the pixel data.
657         data += phraseClippedWidth * (pitch << 3);
658
659         // NOTE: When the bitmap is in REFLECT mode, the XPOS marks the *right* side of the
660         //       bitmap! This makes clipping & etc. MUCH, much easier...!
661         uint32 lbufAddress = 0x1800 + (!in24BPPMode ? leftMargin * 2 : leftMargin * 4);
662         uint8 * currentLineBuffer = &tom_ram_8[lbufAddress];
663
664         // Render.
665
666 // Hmm. We check above for 24 BPP mode, but don't do anything about it below...
667 // If we *were* in 24 BPP mode, how would you convert CRY to RGB24? Seems to me
668 // that if you're in CRY mode then you wouldn't be able to use 24 BPP bitmaps
669 // anyway.
670
671         if (depth == 0)                                                                 // 1 BPP
672         {
673 //              uint32 paletteIndex = index << 1;
674                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
675                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
676
677                 while (iwidth--)
678                 {
679                         // Fetch phrase...
680                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
681                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
682
683                         for(int i=0; i<64; i++)
684                         {
685                                 uint8 bit = pixels >> 63;
686 // Seems to me that both of these are in the same endian, so we could cast it as
687 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
688 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
689 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
690 // No, it isn't because we read the memory in an endian safe way--this *won't* work...
691                                 if ((flags & OPFLAG_TRANS) && bit == 0)
692                                         ;       // Do nothing...
693                                 else
694                                 {
695                                         if (!(flags & OPFLAG_RMW))
696 //Optimize: Set palleteRAM16 to beginning of palette RAM + index*2 and use only [bit] as index...
697                                                 *(uint16 *)currentLineBuffer = paletteRAM16[index | bit];
698                                         else
699                                                 *currentLineBuffer = 
700                                                         BLEND_CR(*currentLineBuffer, paletteRAM[(index | bit) << 1]),
701                                                 *(currentLineBuffer + 1) = 
702                                                         BLEND_Y(*(currentLineBuffer + 1), paletteRAM[((index | bit) << 1) + 1]);
703                                 }
704
705                                 currentLineBuffer += lbufDelta;
706                                 pixels <<= 1;
707                         }
708                 }
709         }
710         else if (depth == 1)                                                    // 2 BPP
711         {
712                 index &= 0xFC;                                                          // Top six bits form CLUT index
713                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
714                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
715
716                 while (iwidth--)
717                 {
718                         // Fetch phrase...
719                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
720                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
721
722                         for(int i=0; i<32; i++)
723                         {
724                                 uint8 bits = pixels >> 62;
725 // Seems to me that both of these are in the same endian, so we could cast it as
726 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
727 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
728 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
729 // No, it isn't because we read the memory in an endian safe way--this *won't* work...
730                                 if ((flags & OPFLAG_TRANS) && bits == 0)
731                                         ;       // Do nothing...
732                                 else
733                                 {
734                                         if (!(flags & OPFLAG_RMW))
735                                                 *(uint16 *)currentLineBuffer = paletteRAM16[index | bits];
736                                         else
737                                                 *currentLineBuffer = 
738                                                         BLEND_CR(*currentLineBuffer, paletteRAM[(index | bits) << 1]),
739                                                 *(currentLineBuffer + 1) = 
740                                                         BLEND_Y(*(currentLineBuffer + 1), paletteRAM[((index | bits) << 1) + 1]);
741                                 }
742
743                                 currentLineBuffer += lbufDelta;
744                                 pixels <<= 2;
745                         }
746                 }
747         }
748         else if (depth == 2)                                                    // 4 BPP
749         {
750                 index &= 0xF0;                                                          // Top four bits form CLUT index
751                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
752                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
753
754                 while (iwidth--)
755                 {
756                         // Fetch phrase...
757                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
758                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
759
760                         for(int i=0; i<16; i++)
761                         {
762                                 uint8 bits = pixels >> 60;
763 // Seems to me that both of these are in the same endian, so we could cast it as
764 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
765 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
766 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
767 // No, it isn't because we read the memory in an endian safe way--this *won't* work...
768                                 if ((flags & OPFLAG_TRANS) && bits == 0)
769                                         ;       // Do nothing...
770                                 else
771                                 {
772                                         if (!(flags & OPFLAG_RMW))
773                                                 *(uint16 *)currentLineBuffer = paletteRAM16[index | bits];
774                                         else
775                                                 *currentLineBuffer = 
776                                                         BLEND_CR(*currentLineBuffer, paletteRAM[(index | bits) << 1]),
777                                                 *(currentLineBuffer + 1) = 
778                                                         BLEND_Y(*(currentLineBuffer + 1), paletteRAM[((index | bits) << 1) + 1]);
779                                 }
780
781                                 currentLineBuffer += lbufDelta;
782                                 pixels <<= 4;
783                         }
784                 }
785         }
786         else if (depth == 3)                                                    // 8 BPP
787         {
788                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
789                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
790
791                 while (iwidth--)
792                 {
793                         // Fetch phrase...
794                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
795                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
796
797                         for(int i=0; i<8; i++)
798                         {
799                                 uint8 bits = pixels >> 56;
800 // Seems to me that both of these are in the same endian, so we could cast it as
801 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
802 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
803 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
804 // No, it isn't because we read the memory in an endian safe way--this *won't* work...
805                                 if ((flags & OPFLAG_TRANS) && bits == 0)
806                                         ;       // Do nothing...
807                                 else
808                                 {
809                                         if (!(flags & OPFLAG_RMW))
810                                                 *(uint16 *)currentLineBuffer = paletteRAM16[bits];
811                                         else
812                                                 *currentLineBuffer = 
813                                                         BLEND_CR(*currentLineBuffer, paletteRAM[bits << 1]),
814                                                 *(currentLineBuffer + 1) = 
815                                                         BLEND_Y(*(currentLineBuffer + 1), paletteRAM[(bits << 1) + 1]);
816                                 }
817
818                                 currentLineBuffer += lbufDelta;
819                                 pixels <<= 8;
820                         }
821                 }
822         }
823         else if (depth == 4)                                                    // 16 BPP
824         {
825                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it.
826                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 5) | 0x02;
827
828                 while (iwidth--)
829                 {
830                         // Fetch phrase...
831                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
832                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
833
834                         for(int i=0; i<4; i++)
835                         {
836                                 uint8 bitsHi = pixels >> 56, bitsLo = pixels >> 48;
837 // Seems to me that both of these are in the same endian, so we could cast it as
838 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
839 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
840 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
841 // No, it isn't because we read the memory in an endian safe way--it *won't* work...
842                                 if ((flags & OPFLAG_TRANS) && (bitsLo | bitsHi) == 0)
843                                         ;       // Do nothing...
844                                 else
845                                 {
846                                         if (!(flags & OPFLAG_RMW))
847                                                 *currentLineBuffer = bitsHi,
848                                                 *(currentLineBuffer + 1) = bitsLo;
849                                         else
850                                                 *currentLineBuffer = 
851                                                         BLEND_CR(*currentLineBuffer, bitsHi),
852                                                 *(currentLineBuffer + 1) = 
853                                                         BLEND_Y(*(currentLineBuffer + 1), bitsLo);
854                                 }
855
856                                 currentLineBuffer += lbufDelta;
857                                 pixels <<= 16;
858                         }
859                 }
860         }
861         else if (depth == 5)                                                    // 24 BPP
862         {
863 WriteLog("OP: Writing 24 BPP bitmap!\n");
864                 // Not sure, but I think RMW only works with 16 BPP and below, and only in CRY mode...
865                 // The LSB is OPFLAG_REFLECT, so sign extend it and or 4 into it.
866                 int32 lbufDelta = ((int8)((flags << 7) & 0xFF) >> 4) | 0x04;
867
868                 while (iwidth--)
869                 {
870                         // Fetch phrase...
871                         uint64 pixels = ((uint64)jaguar_long_read(data) << 32) | jaguar_long_read(data + 4);
872                         data += pitch << 3;                                             // Multiply pitch * 8 (optimize: precompute this value)
873
874                         for(int i=0; i<2; i++)
875                         {
876                                 uint8 bits3 = pixels >> 56, bits2 = pixels >> 48,
877                                         bits1 = pixels >> 40, bits0 = pixels >> 32;
878 // Seems to me that both of these are in the same endian, so we could cast it as
879 // uint16 * and do straight across copies (what about 24 bpp? Treat it differently...)
880 // This only works for the palettized modes (1 - 8 BPP), since we actually have to
881 // copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?)
882 // No, it isn't because we read the memory in an endian safe way--it *won't* work...
883                                 if ((flags & OPFLAG_TRANS) && (bits3 | bits2 | bits1 | bits0) == 0)
884                                         ;       // Do nothing...
885                                 else
886                                         *currentLineBuffer = bits3,
887                                         *(currentLineBuffer + 1) = bits2,
888                                         *(currentLineBuffer + 2) = bits1,
889                                         *(currentLineBuffer + 3) = bits0;
890
891                                 currentLineBuffer += lbufDelta;
892                                 pixels <<= 32;
893                         }
894                 }
895         }
896 }
897
898 //
899 // *** NEW ***
900 // Store scaled bitmap in line buffer
901 //
902 void OPProcessScaledBitmap(int scanline, uint64 p0, uint64 p1, uint64 p2, bool render)
903 {
904         int32 xpos = (((int32)((p1 << 20) & 0xFFFFFFFF)) >> 20) - tom_getHBlankWidthInPixels();
905 //      uint16 ypos = ((p0 & 0x3FF8) >> 3) / 2;
906         uint16 iwidth = ((p1 >> 28) & 0x3FF) * 4;
907         uint16 dwidth = ((p1 >> 18) & 0x3FF) * 4;               // Unsigned!
908 //      uint16 height = (p0 >> 14) & 0x3FF;                             // Unsigned!
909 //      uint32 link = ((p0 >> 24) & 0x7FFFF) << 3;
910         uint32 ptr = (p0 >> 40) & 0xFFFFF8;
911 //unused        uint32 firstPix = (p1 >> 49) & 0x3F;
912         uint8 flags = (p1 >> 45) & 0x0F;
913         uint8 idx = (p1 >> 38) & 0x7F;
914         uint8 pitch = (p1 >> 15) & 0x07;
915         uint8 bitdepth = (p1 >> 12) & 0x07;
916
917         int16 scanline_width = tom_getVideoModeWidth();
918         uint8 * tom_ram_8 = tom_get_ram_pointer();
919         uint8 * current_line_buffer = &tom_ram_8[0x1800];
920
921         uint32 vscale_fixed3p5 = (p2 >> 8) & 0xFF;
922         uint32 hscale_fixed3p5 = p2 & 0xFF;
923         float vscale = (float)vscale_fixed3p5 / 32.0f, hscale = (float)hscale_fixed3p5 / 32.0f;
924
925 //No hacks!
926 /*      if (jaguar_mainRom_crc32==0x5a5b9c68) // atari karts
927         {
928                 if (vscale == 0.0f) 
929                         vscale = 1.0f;
930
931                 if (ypos == 0)
932                         ypos = scanline;
933         }*/
934 #ifdef OP_DEBUG_BMP
935         if (xpos == -3)
936                 WriteLog("[scanline %i] %ix%i scaled to %ix%i scale (%f, %f)%i bpp pitch %i at (%i,%i) @ 0x%.8x Transluency=%s\n",
937                         scanline, iwidth,height, (int)(iwidth*hscale), (int)(height*vscale), hscale, vscale,
938                         op_bitmap_bit_depth[bitdepth], pitch, xpos, ypos, ptr, (flags&FLAGS_READMODIFY) ? "yes" : "no");
939 #endif
940 //No hacks!
941 /*      if (jaguar_mainRom_crc32==0x2f032271)
942                 ypos += 8;*/
943
944         if (!render || dwidth == 0 || ptr == 0 || pitch == 0)
945                 return;
946
947         if (bitdepth <= 3)                                      // 1, 2, 4, 8 BPP
948                 iwidth *= 2, dwidth *= 2;
949
950         uint16 scaled_width = (uint16)((float)iwidth * hscale);
951
952         if (op_bitmap_bit_depth[bitdepth] == 4) // why ?
953                 scaled_width *= 2;
954
955         if (op_bitmap_bit_depth[bitdepth] == 2) // why ?
956                 scaled_width *= 4;
957
958         if (op_bitmap_bit_depth[bitdepth] == 1) // why ?
959                 scaled_width *= 8;
960
961         // visible ?
962 /*      if ((scanline < ypos) || (scanline > (ypos + scaled_height)) || ((xpos + scaled_width) < 0)
963                 || (xpos >= scanline_width))*/
964         if ((xpos + scaled_width) < 0 || xpos >= scanline_width)
965                 return;
966
967         if (xpos < 0)
968         {
969                 scaled_width += xpos;
970                 ptr += (pitch * op_bitmap_bit_size[bitdepth] * ((uint32)((-xpos) / hscale))) >> 16;
971                 xpos = 0;
972         }
973
974         if (iwidth <= 0)
975                 return;
976
977         if (flags & FLAGS_HFLIP)
978         {
979                 if (xpos < 0 || (xpos-scaled_width) >= scanline_width)
980                         return;
981
982                 if ((xpos - scaled_width) < 0)
983                         scaled_width = xpos;
984         }
985         else
986         {
987                 if ((xpos + scaled_width) < 0 || xpos >= scanline_width)
988                         return;
989
990                 if ((xpos + scaled_width) > scanline_width)
991                         scaled_width = scanline_width-xpos;
992         }
993         
994         current_line_buffer += xpos * 2;
995
996         int32 hscale_fixed = (int32)(65536.0f / hscale);
997         int32 cnt = 0;
998
999         if (op_bitmap_bit_depth[bitdepth] == 1)
1000         {
1001                 if (pitch == 1)
1002                 {
1003 #include "zbmpop1.h"
1004                 }
1005                 else
1006                 {
1007 #include "zbmpop1p.h"
1008                 }
1009         }
1010         else if (op_bitmap_bit_depth[bitdepth] == 2)
1011         {
1012                 if (pitch == 1)
1013                 {
1014 #include "zbmpop2.h"
1015                 }
1016                 else
1017                 {
1018 #include "zbmpop2p.h"
1019                 }
1020         }
1021         else if (op_bitmap_bit_depth[bitdepth] == 4)
1022         {
1023                 if (pitch == 1)
1024                 {
1025 #include "zbmpop4.h"
1026                 }
1027                 else
1028                 {
1029 #include "zbmpop4p.h"
1030                 }
1031         }
1032         else if (op_bitmap_bit_depth[bitdepth] == 8)
1033         {
1034                 if (pitch == 1)
1035                 {
1036 #include "zbmpop8.h"
1037                 }
1038                 else
1039                 {
1040 #include "zbmpop8p.h"
1041                 }
1042         }
1043         else if (op_bitmap_bit_depth[bitdepth] == 16)
1044         {
1045                 if (pitch == 1)
1046                 {
1047 #include "zbmpop16.h"
1048                 }
1049                 else
1050                 {
1051 #include "zbmpop16p.h"
1052                 }
1053         }
1054         else
1055                 WriteLog("(unimplemented) %i bpp scaled bitmap\n",op_bitmap_bit_depth[bitdepth]);
1056 }