diff options
Diffstat (limited to 'apps/plugins/pacbox/arcade.c')
-rw-r--r-- | apps/plugins/pacbox/arcade.c | 577 |
1 files changed, 577 insertions, 0 deletions
diff --git a/apps/plugins/pacbox/arcade.c b/apps/plugins/pacbox/arcade.c new file mode 100644 index 0000000000..e7bf124700 --- /dev/null +++ b/apps/plugins/pacbox/arcade.c | |||
@@ -0,0 +1,577 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Pacbox - a Pacman Emulator for Rockbox | ||
11 | * | ||
12 | * Based on PIE - Pacman Instructional Emulator | ||
13 | * | ||
14 | * Copyright (c) 1997-2003,2004 Alessandro Scotti | ||
15 | * http://www.ascotti.org/ | ||
16 | * | ||
17 | * All files in this archive are subject to the GNU General Public License. | ||
18 | * See the file COPYING in the source tree root for full license agreement. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | |||
25 | #include "arcade.h" | ||
26 | #include "hardware.h" | ||
27 | #include <string.h> | ||
28 | #include "plugin.h" | ||
29 | |||
30 | extern struct plugin_api* rb; | ||
31 | |||
32 | #ifndef HAVE_LCD_COLOR | ||
33 | /* Convert RGB888 to 2-bit greyscale - logic taken from bmp2rb.c */ | ||
34 | static fb_data rgb_to_gray(unsigned int r, unsigned int g, unsigned int b) | ||
35 | { | ||
36 | int brightness = ((3*r + 6*g + b) / 10); | ||
37 | return ((brightness & 0xc0) >> 6); | ||
38 | } | ||
39 | #endif | ||
40 | |||
41 | unsigned char color_data_[256] = { | ||
42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x01, | ||
43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x03, | ||
44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x05, | ||
45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x07, | ||
46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x09, | ||
47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
49 | 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x01, 0x0c, 0x0f, | ||
50 | 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0c, 0x0b, 0x0e, | ||
51 | 0x00, 0x0c, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
52 | 0x00, 0x01, 0x02, 0x0f, 0x00, 0x07, 0x0c, 0x02, | ||
53 | 0x00, 0x09, 0x06, 0x0f, 0x00, 0x0d, 0x0c, 0x0f, | ||
54 | 0x00, 0x05, 0x03, 0x09, 0x00, 0x0f, 0x0b, 0x00, | ||
55 | 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x0b, | ||
56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x01, | ||
57 | 0x00, 0x0f, 0x0b, 0x0e, 0x00, 0x0e, 0x00, 0x0f, | ||
58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
68 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
74 | }; | ||
75 | |||
76 | unsigned char palette_data_[0x20] = { | ||
77 | 0x00, 0x07, 0x66, 0xef, 0x00, 0xf8, 0xea, 0x6f, | ||
78 | 0x00, 0x3f, 0x00, 0xc9, 0x38, 0xaa, 0xaf, 0xf6, | ||
79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
81 | }; | ||
82 | |||
83 | enum { | ||
84 | Normal = 0x00, | ||
85 | FlipY = 0x01, | ||
86 | FlipX = 0x02, | ||
87 | FlipXY = 0x03 | ||
88 | }; | ||
89 | |||
90 | fb_data palette[256]; /* Color palette */ | ||
91 | int vchar_to_x_[1024]; | ||
92 | int vchar_to_y_[1024]; | ||
93 | |||
94 | void init_PacmanMachine(int dip) | ||
95 | { | ||
96 | int i; | ||
97 | |||
98 | /* Initialize the CPU and the RAM */ | ||
99 | z80_reset(); | ||
100 | rb->memset( &ram_[0x4000], 0xFF, 0x1000 ); | ||
101 | |||
102 | /* Initialize parameters */ | ||
103 | port1_ = 0xFF; | ||
104 | port2_ = 0xFF; | ||
105 | coin_counter_ = 0; | ||
106 | |||
107 | /* Reset the machine */ | ||
108 | reset_PacmanMachine(); | ||
109 | |||
110 | /* Set the DIP switches to a default configuration */ | ||
111 | setDipSwitches( dip ); | ||
112 | |||
113 | /* Initialize the video character translation tables: video memory has a | ||
114 | very peculiar arrangement in Pacman so we precompute a few tables to | ||
115 | move around faster */ | ||
116 | |||
117 | for( i=0x000; i<0x400; i++ ) { | ||
118 | int x, y; | ||
119 | |||
120 | if( i < 0x040 ) { | ||
121 | x = 29 - (i & 0x1F); | ||
122 | y = 34 + (i >> 5); | ||
123 | } | ||
124 | else if( i >= 0x3C0 ) { | ||
125 | x = 29 - (i & 0x1F); | ||
126 | y = ((i-0x3C0) >> 5); | ||
127 | } | ||
128 | else { | ||
129 | x = 27 - ((i-0x40) >> 5); | ||
130 | y = 2 + ((i-0x40) & 0x1F); | ||
131 | } | ||
132 | vchar_to_x_[i] = x; | ||
133 | vchar_to_y_[i] = y; | ||
134 | if( (y >= 0) && (y < 36) && (x >= 0) && (x < 28) ) | ||
135 | vchar_to_i_[i] = y*28 + x; | ||
136 | else | ||
137 | vchar_to_i_[i] = 0x3FF; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | void reset_PacmanMachine(void) | ||
142 | { | ||
143 | int i; | ||
144 | |||
145 | z80_reset(); | ||
146 | output_devices_ = 0; | ||
147 | interrupt_vector_ = 0; | ||
148 | |||
149 | rb->memset( ram_+0x4000, 0, 0x1000 ); | ||
150 | rb->memset( color_mem_, 0, sizeof(color_mem_) ); | ||
151 | rb->memset( video_mem_, 0, sizeof(video_mem_) ); | ||
152 | rb->memset( dirty_, 0, sizeof(dirty_) ); | ||
153 | |||
154 | for( i=0; i<8; i++ ) { | ||
155 | sprites_[i].color = 0; | ||
156 | sprites_[i].x = ScreenWidth; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | Run the machine for one frame. | ||
162 | */ | ||
163 | int run(void) | ||
164 | { | ||
165 | /* Run until the CPU has executed the number of cycles per frame | ||
166 | (the function returns the number of "extra" cycles spent by the | ||
167 | last instruction but that is not really important here) */ | ||
168 | |||
169 | unsigned extraCycles = z80_run( CpuCyclesPerFrame ); | ||
170 | |||
171 | /* Reset the CPU cycle counter to make sure it doesn't overflow, | ||
172 | also take into account the extra cycles from the previous run */ | ||
173 | |||
174 | setCycles( extraCycles ); | ||
175 | |||
176 | /* If interrupts are enabled, force a CPU interrupt with the vector | ||
177 | set by the program */ | ||
178 | |||
179 | if( output_devices_ & InterruptEnabled ) { | ||
180 | z80_interrupt( interrupt_vector_ ); | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /** Returns the status of the coin lockout door. */ | ||
187 | unsigned char getCoinLockout(void) { | ||
188 | return output_devices_ & CoinLockout ? 1 : 0; | ||
189 | } | ||
190 | |||
191 | static void decodeCharByte( unsigned char b, unsigned char * charbuf, int charx, int chary, int charwidth ) | ||
192 | { | ||
193 | int i; | ||
194 | |||
195 | for( i=3; i>=0; i-- ) { | ||
196 | charbuf[charx+(chary+i)*charwidth] = (b & 1) | ((b >> 3) & 2); | ||
197 | b >>= 1; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | static void decodeCharLine( unsigned char * src, unsigned char * charbuf, int charx, int chary, int charwidth ) | ||
202 | { | ||
203 | int x; | ||
204 | |||
205 | for( x=7; x>=0; x-- ) { | ||
206 | decodeCharByte( *src++, charbuf, x+charx, chary, charwidth ); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | static void decodeCharSet( unsigned char * mem, unsigned char * charset ) | ||
211 | { | ||
212 | int i; | ||
213 | |||
214 | for( i=0; i<256; i++ ) { | ||
215 | unsigned char * src = mem + 16*i; | ||
216 | unsigned char * dst = charset + 64*i; | ||
217 | |||
218 | decodeCharLine( src, dst, 0, 4, 8 ); | ||
219 | decodeCharLine( src+8, dst, 0, 0, 8 ); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | static void decodeSprites( unsigned char * mem, unsigned char * sprite_data ) | ||
224 | { | ||
225 | int i; | ||
226 | |||
227 | for( i=0; i<64; i++ ) { | ||
228 | unsigned char * src = mem + i*64; | ||
229 | unsigned char * dst = sprite_data + 256*i; | ||
230 | |||
231 | decodeCharLine( src , dst, 8, 12, 16 ); | ||
232 | decodeCharLine( src+ 8, dst, 8, 0, 16 ); | ||
233 | decodeCharLine( src+16, dst, 8, 4, 16 ); | ||
234 | decodeCharLine( src+24, dst, 8, 8, 16 ); | ||
235 | decodeCharLine( src+32, dst, 0, 12, 16 ); | ||
236 | decodeCharLine( src+40, dst, 0, 0, 16 ); | ||
237 | decodeCharLine( src+48, dst, 0, 4, 16 ); | ||
238 | decodeCharLine( src+56, dst, 0, 8, 16 ); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | Decode one byte from the encoded color palette. | ||
244 | |||
245 | An encoded palette byte contains RGB information bit-packed as follows: | ||
246 | |||
247 | bit: 7 6 5 4 3 2 1 0 | ||
248 | color: b b g g g r r r | ||
249 | */ | ||
250 | static unsigned decodePaletteByte( unsigned char value ) | ||
251 | { | ||
252 | unsigned bit0, bit1, bit2; | ||
253 | unsigned red, green, blue; | ||
254 | |||
255 | bit0 = (value >> 0) & 0x01; | ||
256 | bit1 = (value >> 1) & 0x01; | ||
257 | bit2 = (value >> 2) & 0x01; | ||
258 | red = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2; | ||
259 | |||
260 | bit0 = (value >> 3) & 0x01; | ||
261 | bit1 = (value >> 4) & 0x01; | ||
262 | bit2 = (value >> 5) & 0x01; | ||
263 | green = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2; | ||
264 | |||
265 | bit0 = 0; | ||
266 | bit1 = (value >> 6) & 0x01; | ||
267 | bit2 = (value >> 7) & 0x01; | ||
268 | blue = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2; | ||
269 | |||
270 | return (blue << 16 ) | (green << 8) | red; | ||
271 | } | ||
272 | |||
273 | void decodeROMs(void) | ||
274 | { | ||
275 | unsigned decoded_palette[0x20]; | ||
276 | unsigned c; | ||
277 | |||
278 | int i; | ||
279 | |||
280 | decodeCharSet( charset_rom_, charmap_ ); | ||
281 | decodeSprites( spriteset_rom_, spritemap_ ); | ||
282 | |||
283 | for( i=0x00; i<0x20; i++ ) { | ||
284 | decoded_palette[i] = decodePaletteByte( palette_data_[i] ); | ||
285 | } | ||
286 | for( i=0; i<256; i++ ) { | ||
287 | c = decoded_palette[ color_data_[i] & 0x0F ]; | ||
288 | #ifdef HAVE_LCD_COLOR | ||
289 | palette[i] = LCD_RGBPACK((unsigned char) (c), | ||
290 | (unsigned char) (c >> 8), | ||
291 | (unsigned char) (c >> 16)); | ||
292 | #else | ||
293 | palette[i] = rgb_to_gray(c, c >> 8, c >> 16); | ||
294 | #endif | ||
295 | } | ||
296 | } | ||
297 | |||
298 | void getDeviceInfo( enum InputDevice device, unsigned char * mask, unsigned char ** port ) | ||
299 | { | ||
300 | static unsigned char MaskInfo[] = { | ||
301 | 0x01 , // Joy1_Up | ||
302 | 0x02 , // Joy1_Left | ||
303 | 0x04 , // Joy1_Right | ||
304 | 0x08 , // Joy1_Down | ||
305 | 0x10 , // Switch_RackAdvance | ||
306 | 0x20 , // CoinSlot_1 | ||
307 | 0x40 , // CoinSlot_2 | ||
308 | 0x80 , // Switch_AddCredit | ||
309 | 0x01 , // Joy2_Up | ||
310 | 0x02 , // Joy2_Left | ||
311 | 0x04 , // Joy2_Right | ||
312 | 0x08 , // Joy2_Down | ||
313 | 0x10 , // Switch_Test | ||
314 | 0x20 , // Key_OnePlayer | ||
315 | 0x40 , // Key_TwoPlayers | ||
316 | 0x80 // Switch_CocktailMode | ||
317 | }; | ||
318 | |||
319 | *mask = MaskInfo[device]; | ||
320 | |||
321 | switch( device ) { | ||
322 | case Joy1_Up: | ||
323 | case Joy1_Left: | ||
324 | case Joy1_Right: | ||
325 | case Joy1_Down: | ||
326 | case Switch_RackAdvance: | ||
327 | case CoinSlot_1: | ||
328 | case CoinSlot_2: | ||
329 | case Switch_AddCredit: | ||
330 | *port = &port1_; | ||
331 | break; | ||
332 | case Joy2_Up: | ||
333 | case Joy2_Left: | ||
334 | case Joy2_Right: | ||
335 | case Joy2_Down: | ||
336 | case Switch_Test: | ||
337 | case Key_OnePlayer: | ||
338 | case Key_TwoPlayers: | ||
339 | case Switch_CocktailMode: | ||
340 | *port = &port2_; | ||
341 | break; | ||
342 | default: | ||
343 | *port = 0; | ||
344 | break; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | enum InputDeviceMode getDeviceMode( enum InputDevice device ) | ||
349 | { | ||
350 | unsigned char mask; | ||
351 | unsigned char * port; | ||
352 | |||
353 | getDeviceInfo( device, &mask, &port ); | ||
354 | |||
355 | return (*port & mask) == 0 ? DeviceOn : DeviceOff; | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | Fire an input event, telling the emulator for example | ||
360 | that the joystick has been released from the down position. | ||
361 | */ | ||
362 | void setDeviceMode( enum InputDevice device, enum InputDeviceMode mode ) | ||
363 | { | ||
364 | if( (getCoinLockout() == 0) && ((device == CoinSlot_1)||(device == CoinSlot_2)||(device == Switch_AddCredit)) ) { | ||
365 | // Coin slots are locked, ignore command and exit | ||
366 | return; | ||
367 | } | ||
368 | |||
369 | unsigned char mask; | ||
370 | unsigned char * port; | ||
371 | |||
372 | getDeviceInfo( device, &mask, &port ); | ||
373 | |||
374 | if( mode == DeviceOn ) | ||
375 | *port &= ~mask; | ||
376 | else if( mode == DeviceOff ) | ||
377 | *port |= mask; | ||
378 | else if( mode == DeviceToggle ) | ||
379 | *port ^= mask; | ||
380 | } | ||
381 | |||
382 | void setDipSwitches( unsigned value ) { | ||
383 | dip_switches_ = (unsigned char) value; | ||
384 | |||
385 | setDeviceMode( Switch_RackAdvance, value & DipRackAdvance_Auto ? DeviceOn : DeviceOff ); | ||
386 | setDeviceMode( Switch_Test, value & DipMode_Test ? DeviceOn : DeviceOff ); | ||
387 | setDeviceMode( Switch_CocktailMode, value & DipCabinet_Cocktail ? DeviceOn : DeviceOff ); | ||
388 | } | ||
389 | |||
390 | unsigned getDipSwitches(void) { | ||
391 | unsigned result = dip_switches_; | ||
392 | |||
393 | if( getDeviceMode(Switch_RackAdvance) == DeviceOn ) result |= DipRackAdvance_Auto; | ||
394 | if( getDeviceMode(Switch_Test) == DeviceOn ) result |= DipMode_Test; | ||
395 | if( getDeviceMode(Switch_CocktailMode) == DeviceOn ) result |= DipCabinet_Cocktail; | ||
396 | |||
397 | return result; | ||
398 | } | ||
399 | |||
400 | static inline void drawChar( unsigned char * buffer, int index, int ox, int oy, int color ) | ||
401 | { | ||
402 | buffer += ox + oy*224; // Make the buffer point to the character position | ||
403 | index *= 64; // Make the index point to the character offset into the character table | ||
404 | color = (color & 0x3F)*4; | ||
405 | int x,y; | ||
406 | |||
407 | if( output_devices_ & FlipScreen ) { | ||
408 | // Flip character | ||
409 | buffer += 7*ScreenWidth; | ||
410 | for( y=0; y<8; y++ ) { | ||
411 | for( x=7; x>=0; x-- ) { | ||
412 | buffer[x] = charmap_[ index++ ] + color; | ||
413 | } | ||
414 | buffer -= ScreenWidth; // Go to the next line | ||
415 | } | ||
416 | } | ||
417 | else { | ||
418 | for( y=0; y<8; y++ ) { | ||
419 | for( x=0; x<=7; x++ ) { | ||
420 | buffer[x] = charmap_[ index++ ] + color; | ||
421 | } | ||
422 | buffer += ScreenWidth; // Go to the next line | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | |||
427 | inline void drawSprite( unsigned char * buffer, int index ) | ||
428 | { | ||
429 | struct PacmanSprite ps = sprites_[index]; | ||
430 | int x,y; | ||
431 | |||
432 | // Exit now if sprite not visible at all | ||
433 | if( (ps.color == 0) || (ps.x >= ScreenWidth) || (ps.y < 16) || (ps.y >= (ScreenHeight-32)) ) { | ||
434 | return; | ||
435 | } | ||
436 | |||
437 | // Clip the sprite coordinates to cut the parts that fall off the screen | ||
438 | int start_x = (ps.x < 0) ? 0 : ps.x; | ||
439 | int end_x = (ps.x < (ScreenWidth-16)) ? ps.x+16 : ScreenWidth; | ||
440 | |||
441 | // Prepare variables for drawing | ||
442 | int color = (ps.color & 0x3F)*4; | ||
443 | unsigned char * spritemap_base = spritemap_ + ((ps.n & 0x3F)*256); | ||
444 | |||
445 | buffer += ScreenWidth*ps.y; | ||
446 | |||
447 | // Draw the 16x16 sprite | ||
448 | if( ps.mode == 0 ) { // Normal | ||
449 | // Draw the 16x16 sprite | ||
450 | for( y=0; y<16; y++ ) { | ||
451 | char* s = &spritemap_base[start_x-ps.x+y*16]; | ||
452 | for( x=start_x; x<end_x; x++ ) { | ||
453 | int c = *(s++); | ||
454 | if( c ) { | ||
455 | buffer[x] = c + color; | ||
456 | } | ||
457 | } | ||
458 | buffer += ScreenWidth; | ||
459 | } | ||
460 | } else if( ps.mode == 1 ) { // Flip Y | ||
461 | for( y=0; y<16; y++ ) { | ||
462 | char* s = &spritemap_base[start_x-ps.x+(15-y)*16]; | ||
463 | for( x=start_x; x<end_x; x++ ) { | ||
464 | int c = *(s++); | ||
465 | if( c ) { | ||
466 | buffer[x] = c + color; | ||
467 | } | ||
468 | } | ||
469 | buffer += ScreenWidth; | ||
470 | } | ||
471 | } else if( ps.mode == 2 ) { // Flip X | ||
472 | for( y=0; y<16; y++ ) { | ||
473 | char* s = &spritemap_base[15-start_x+ps.x+y*16]; | ||
474 | for( x=start_x; x<end_x; x++ ) { | ||
475 | int c = *(s--); | ||
476 | if( c ) { | ||
477 | buffer[x] = c + color; | ||
478 | } | ||
479 | } | ||
480 | buffer += ScreenWidth; | ||
481 | } | ||
482 | } else { // Flip X and Y | ||
483 | for( y=0; y<16; y++ ) { | ||
484 | char* s = &spritemap_base[15-start_x+ps.x+(15-y)*16]; | ||
485 | for( x=start_x; x<end_x; x++ ) { | ||
486 | int c = *(s--); | ||
487 | if( c ) { | ||
488 | buffer[x] = c + color; | ||
489 | } | ||
490 | } | ||
491 | buffer += ScreenWidth; | ||
492 | } | ||
493 | } | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | Draw the video into the specified buffer. | ||
498 | */ | ||
499 | bool renderBackground( unsigned char * buffer ) | ||
500 | { | ||
501 | unsigned char * video = video_mem_; | ||
502 | unsigned char * color = color_mem_; | ||
503 | unsigned char * dirty = dirty_; | ||
504 | int x,y; | ||
505 | bool changed=false; | ||
506 | |||
507 | // Draw the background first... | ||
508 | if( output_devices_ & FlipScreen ) { | ||
509 | for( y=ScreenHeight-CharHeight; y>=0; y-=CharHeight ) { | ||
510 | for( x=ScreenWidth-CharWidth; x>=0; x-=CharWidth ) { | ||
511 | if (*dirty) { | ||
512 | drawChar( buffer, *video++, x, y, *color++ ); | ||
513 | *(dirty++)=0; | ||
514 | changed=true; | ||
515 | } else { | ||
516 | dirty++; | ||
517 | video++; | ||
518 | color++; | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | } | ||
523 | else { | ||
524 | for( y=0; y<ScreenHeight; y+=CharHeight ) { | ||
525 | for( x=0; x<ScreenWidth; x+=CharWidth ) { | ||
526 | if (*dirty) { | ||
527 | drawChar( buffer, *video++, x, y, *color++ ); | ||
528 | *(dirty++)=0; | ||
529 | changed=true; | ||
530 | } else { | ||
531 | dirty++; | ||
532 | video++; | ||
533 | color++; | ||
534 | } | ||
535 | } | ||
536 | } | ||
537 | } | ||
538 | |||
539 | return changed; | ||
540 | } | ||
541 | |||
542 | void renderSprites( unsigned char * buffer ) | ||
543 | { | ||
544 | int i; | ||
545 | |||
546 | // ...then add the sprites | ||
547 | for( i=7; i>=0; i-- ) { | ||
548 | drawSprite( buffer, i ); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | /* Enables/disables the speed hack. */ | ||
553 | int setSpeedHack( int enabled ) | ||
554 | { | ||
555 | int result = 0; | ||
556 | |||
557 | if( enabled ) { | ||
558 | if( (ram_[0x180B] == 0xBE) && (ram_[0x1FFD] == 0x00) ) { | ||
559 | // Patch the ROM to activate the speed hack | ||
560 | ram_[0x180B] = 0x01; // Activate speed hack | ||
561 | ram_[0x1FFD] = 0xBD; // Fix ROM checksum | ||
562 | |||
563 | result = 1; | ||
564 | } | ||
565 | } | ||
566 | else { | ||
567 | if( (ram_[0x180B] == 0x01) && (ram_[0x1FFD] == 0xBD) ) { | ||
568 | // Restore the patched ROM locations | ||
569 | ram_[0x180B] = 0xBE; | ||
570 | ram_[0x1FFD] = 0x00; | ||
571 | |||
572 | result = 1; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | return result; | ||
577 | } | ||