A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
21 *
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
24 *
25 ****************************************************************************/
26
27#include "pacbox.h"
28#include "arcade.h"
29#include "hardware.h"
30#include "wsg3.h"
31#include <string.h>
32#include "plugin.h"
33
34#ifndef HAVE_LCD_COLOR
35/* Convert RGB888 to 2-bit greyscale - logic taken from bmp2rb.c */
36static fb_data rgb_to_gray(unsigned int r, unsigned int g, unsigned int b)
37{
38 int brightness = ( 2*r + 4*g + b );
39 if( r == 0 && g == 0 && b == 0 )
40 return 3;
41
42 brightness = (brightness/450);
43 if( brightness > 2 ) return 0;
44 else return 2-brightness;
45}
46#endif
47
48static unsigned char color_data_[256] = {
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x01,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x03,
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x05,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x07,
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x09,
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x01, 0x0c, 0x0f,
57 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0c, 0x0b, 0x0e,
58 0x00, 0x0c, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x01, 0x02, 0x0f, 0x00, 0x07, 0x0c, 0x02,
60 0x00, 0x09, 0x06, 0x0f, 0x00, 0x0d, 0x0c, 0x0f,
61 0x00, 0x05, 0x03, 0x09, 0x00, 0x0f, 0x0b, 0x00,
62 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x0b,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x01,
64 0x00, 0x0f, 0x0b, 0x0e, 0x00, 0x0e, 0x00, 0x0f,
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
81};
82
83static unsigned char palette_data_[0x20] = {
84 0x00, 0x07, 0x66, 0xef, 0x00, 0xf8, 0xea, 0x6f,
85 0x00, 0x3f, 0x00, 0xc9, 0x38, 0xaa, 0xaf, 0xf6,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
88};
89
90enum {
91 Normal = 0x00,
92 FlipY = 0x01,
93 FlipX = 0x02,
94 FlipXY = 0x03
95};
96
97// Namco 3-channel Wave Sound Generator wave data (8 waveforms with 32 4-bit entries each)
98static unsigned char default_sound_prom[] =
99{
100 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0D, 0x0E,
101 0x0E, 0x0E, 0x0D, 0x0D, 0x0C, 0x0B, 0x0A, 0x09,
102 0x07, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x00,
103 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05,
104 0x07, 0x0C, 0x0E, 0x0E, 0x0D, 0x0B, 0x09, 0x0A,
105 0x0B, 0x0B, 0x0A, 0x09, 0x06, 0x04, 0x03, 0x05,
106 0x07, 0x09, 0x0B, 0x0A, 0x08, 0x05, 0x04, 0x03,
107 0x03, 0x04, 0x05, 0x03, 0x01, 0x00, 0x00, 0x02,
108 0x07, 0x0A, 0x0C, 0x0D, 0x0E, 0x0D, 0x0C, 0x0A,
109 0x07, 0x04, 0x02, 0x01, 0x00, 0x01, 0x02, 0x04,
110 0x07, 0x0B, 0x0D, 0x0E, 0x0D, 0x0B, 0x07, 0x03,
111 0x01, 0x00, 0x01, 0x03, 0x07, 0x0E, 0x07, 0x00,
112 0x07, 0x0D, 0x0B, 0x08, 0x0B, 0x0D, 0x09, 0x06,
113 0x0B, 0x0E, 0x0C, 0x07, 0x09, 0x0A, 0x06, 0x02,
114 0x07, 0x0C, 0x08, 0x04, 0x05, 0x07, 0x02, 0x00,
115 0x03, 0x08, 0x05, 0x01, 0x03, 0x06, 0x03, 0x01,
116 0x00, 0x08, 0x0F, 0x07, 0x01, 0x08, 0x0E, 0x07,
117 0x02, 0x08, 0x0D, 0x07, 0x03, 0x08, 0x0C, 0x07,
118 0x04, 0x08, 0x0B, 0x07, 0x05, 0x08, 0x0A, 0x07,
119 0x06, 0x08, 0x09, 0x07, 0x07, 0x08, 0x08, 0x07,
120 0x07, 0x08, 0x06, 0x09, 0x05, 0x0A, 0x04, 0x0B,
121 0x03, 0x0C, 0x02, 0x0D, 0x01, 0x0E, 0x00, 0x0F,
122 0x00, 0x0F, 0x01, 0x0E, 0x02, 0x0D, 0x03, 0x0C,
123 0x04, 0x0B, 0x05, 0x0A, 0x06, 0x09, 0x07, 0x08,
124 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
125 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
126 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
127 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
128 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
129 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
130 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
131 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
132};
133
134/* Putting this in IRAM actually slows down the iPods, but is good for
135 the Coldfire
136*/
137#ifdef CPU_COLDFIRE
138fb_data palette[256] IBSS_ATTR; /* Color palette */
139#else
140fb_data palette[256]; /* Color palette */
141#endif
142
143
144void init_PacmanMachine(int dip)
145{
146 int i;
147
148 /* Initialize the CPU and the RAM */
149 z80_reset();
150 rb->memset( &ram_[0x4000], 0xFF, 0x1000 );
151
152 /* Initialize the WSG3 */
153 wsg3_init(SoundClock);
154
155 /* Set the sound PROM to the default values for the original Namco chip */
156 wsg3_set_sound_prom(default_sound_prom);
157
158 /* Initialize parameters */
159 port1_ = 0xFF;
160 port2_ = 0xFF;
161 coin_counter_ = 0;
162
163 /* Reset the machine */
164 reset_PacmanMachine();
165
166 /* Set the DIP switches to a default configuration */
167 setDipSwitches( dip );
168
169 /* Initialize the video character translation tables: video memory has a
170 very peculiar arrangement in Pacman so we precompute a few tables to
171 move around faster */
172
173 for( i=0x000; i<0x400; i++ ) {
174 int x, y;
175
176 if( i < 0x040 ) {
177 x = 29 - (i & 0x1F);
178 y = 34 + (i >> 5);
179 }
180 else if( i >= 0x3C0 ) {
181 x = 29 - (i & 0x1F);
182 y = ((i-0x3C0) >> 5);
183 }
184 else {
185 x = 27 - ((i-0x40) >> 5);
186 y = 2 + ((i-0x40) & 0x1F);
187 }
188 if( (y >= 0) && (y < 36) && (x >= 0) && (x < 28) )
189 vchar_to_i_[i] = y*28 + x;
190 else
191 vchar_to_i_[i] = 0x3FF;
192 }
193}
194
195void reset_PacmanMachine(void)
196{
197 int i;
198
199 z80_reset();
200 output_devices_ = 0;
201 interrupt_vector_ = 0;
202
203 rb->memset( ram_+0x4000, 0, 0x1000 );
204 rb->memset( color_mem_, 0, sizeof(color_mem_) );
205 rb->memset( video_mem_, 0, sizeof(video_mem_) );
206 rb->memset( dirty_, 0, sizeof(dirty_) );
207
208 for( i=0; i<8; i++ ) {
209 sprites_[i].color = 0;
210 sprites_[i].x = ScreenWidth;
211 }
212}
213
214/*
215 Run the machine for one frame.
216*/
217int run(void)
218{
219 /* Run until the CPU has executed the number of cycles per frame
220 (the function returns the number of "extra" cycles spent by the
221 last instruction but that is not really important here) */
222
223 unsigned extraCycles = z80_run( CpuCyclesPerFrame );
224
225 /* Reset the CPU cycle counter to make sure it doesn't overflow,
226 also take into account the extra cycles from the previous run */
227
228 setCycles( extraCycles );
229
230 /* If interrupts are enabled, force a CPU interrupt with the vector
231 set by the program */
232
233 if( output_devices_ & InterruptEnabled ) {
234 z80_interrupt( interrupt_vector_ );
235 }
236
237 return 0;
238}
239
240/** Returns the status of the coin lockout door. */
241static unsigned char getCoinLockout(void) {
242 return output_devices_ & CoinLockout ? 1 : 0;
243}
244
245static void decodeCharByte( unsigned char b, unsigned char * charbuf, int charx, int chary, int charwidth )
246{
247 int i;
248
249 for( i=3; i>=0; i-- ) {
250 charbuf[charx+(chary+i)*charwidth] = (b & 1) | ((b >> 3) & 2);
251 b >>= 1;
252 }
253}
254
255static void decodeCharLine( unsigned char * src, unsigned char * charbuf, int charx, int chary, int charwidth )
256{
257 int x;
258
259 for( x=7; x>=0; x-- ) {
260 decodeCharByte( *src++, charbuf, x+charx, chary, charwidth );
261 }
262}
263
264static void decodeCharSet( unsigned char * mem, unsigned char * charset )
265{
266 int i;
267
268 for( i=0; i<256; i++ ) {
269 unsigned char * src = mem + 16*i;
270 unsigned char * dst = charset + 64*i;
271
272 decodeCharLine( src, dst, 0, 4, 8 );
273 decodeCharLine( src+8, dst, 0, 0, 8 );
274 }
275}
276
277static void decodeSprites( unsigned char * mem, unsigned char * sprite_data )
278{
279 int i;
280
281 for( i=0; i<64; i++ ) {
282 unsigned char * src = mem + i*64;
283 unsigned char * dst = sprite_data + 256*i;
284
285 decodeCharLine( src , dst, 8, 12, 16 );
286 decodeCharLine( src+ 8, dst, 8, 0, 16 );
287 decodeCharLine( src+16, dst, 8, 4, 16 );
288 decodeCharLine( src+24, dst, 8, 8, 16 );
289 decodeCharLine( src+32, dst, 0, 12, 16 );
290 decodeCharLine( src+40, dst, 0, 0, 16 );
291 decodeCharLine( src+48, dst, 0, 4, 16 );
292 decodeCharLine( src+56, dst, 0, 8, 16 );
293 }
294}
295
296/*
297 Decode one byte from the encoded color palette.
298
299 An encoded palette byte contains RGB information bit-packed as follows:
300
301 bit: 7 6 5 4 3 2 1 0
302 color: b b g g g r r r
303*/
304static unsigned decodePaletteByte( unsigned char value )
305{
306 unsigned bit0, bit1, bit2;
307 unsigned red, green, blue;
308
309 bit0 = (value >> 0) & 0x01;
310 bit1 = (value >> 1) & 0x01;
311 bit2 = (value >> 2) & 0x01;
312 red = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
313
314 bit0 = (value >> 3) & 0x01;
315 bit1 = (value >> 4) & 0x01;
316 bit2 = (value >> 5) & 0x01;
317 green = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
318
319 bit0 = 0;
320 bit1 = (value >> 6) & 0x01;
321 bit2 = (value >> 7) & 0x01;
322 blue = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
323
324 return (blue << 16 ) | (green << 8) | red;
325}
326
327void decodeROMs(void)
328{
329 unsigned decoded_palette[0x20];
330 unsigned c;
331
332 int i;
333
334 decodeCharSet( charset_rom_, charmap_ );
335 decodeSprites( spriteset_rom_, spritemap_ );
336
337 for( i=0x00; i<0x20; i++ ) {
338 decoded_palette[i] = decodePaletteByte( palette_data_[i] );
339 }
340 for( i=0; i<256; i++ ) {
341 c = decoded_palette[ color_data_[i] & 0x0F ];
342#ifdef HAVE_LCD_COLOR
343 palette[i] = FB_RGBPACK((unsigned char) (c),
344 (unsigned char) (c >> 8),
345 (unsigned char) (c >> 16));
346#else
347 palette[i] = rgb_to_gray((unsigned char) (c),
348 (unsigned char) (c >> 8),
349 (unsigned char) (c >> 16) );
350#endif
351 }
352
353#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
354 rb->lcd_pal256_update_pal(palette);
355#endif
356}
357
358static void getDeviceInfo( enum InputDevice device, unsigned char * mask, unsigned char ** port )
359{
360 static unsigned char MaskInfo[] = {
361 0x01 , // Joy1_Up
362 0x02 , // Joy1_Left
363 0x04 , // Joy1_Right
364 0x08 , // Joy1_Down
365 0x10 , // Switch_RackAdvance
366 0x20 , // CoinSlot_1
367 0x40 , // CoinSlot_2
368 0x80 , // Switch_AddCredit
369 0x01 , // Joy2_Up
370 0x02 , // Joy2_Left
371 0x04 , // Joy2_Right
372 0x08 , // Joy2_Down
373 0x10 , // Switch_Test
374 0x20 , // Key_OnePlayer
375 0x40 , // Key_TwoPlayers
376 0x80 // Switch_CocktailMode
377 };
378
379 *mask = MaskInfo[device];
380
381 switch( device ) {
382 case Joy1_Up:
383 case Joy1_Left:
384 case Joy1_Right:
385 case Joy1_Down:
386 case Switch_RackAdvance:
387 case CoinSlot_1:
388 case CoinSlot_2:
389 case Switch_AddCredit:
390 *port = &port1_;
391 break;
392 case Joy2_Up:
393 case Joy2_Left:
394 case Joy2_Right:
395 case Joy2_Down:
396 case Switch_Test:
397 case Key_OnePlayer:
398 case Key_TwoPlayers:
399 case Switch_CocktailMode:
400 *port = &port2_;
401 break;
402 default:
403 *port = 0;
404 break;
405 }
406}
407
408static enum InputDeviceMode getDeviceMode( enum InputDevice device )
409{
410 unsigned char mask;
411 unsigned char * port;
412
413 getDeviceInfo( device, &mask, &port );
414
415 return (*port & mask) == 0 ? DeviceOn : DeviceOff;
416}
417
418/*
419 Fire an input event, telling the emulator for example
420 that the joystick has been released from the down position.
421*/
422void setDeviceMode( enum InputDevice device, enum InputDeviceMode mode )
423{
424 if( (getCoinLockout() == 0) && ((device == CoinSlot_1)||(device == CoinSlot_2)||(device == Switch_AddCredit)) ) {
425 // Coin slots are locked, ignore command and exit
426 return;
427 }
428
429 unsigned char mask;
430 unsigned char * port;
431
432 getDeviceInfo( device, &mask, &port );
433
434 if( mode == DeviceOn )
435 *port &= ~mask;
436 else if( mode == DeviceOff )
437 *port |= mask;
438 else if( mode == DeviceToggle )
439 *port ^= mask;
440}
441
442void setDipSwitches( unsigned value ) {
443 dip_switches_ = (unsigned char) value;
444
445 setDeviceMode( Switch_RackAdvance, value & DipRackAdvance_Auto ? DeviceOn : DeviceOff );
446 setDeviceMode( Switch_Test, value & DipMode_Test ? DeviceOn : DeviceOff );
447 setDeviceMode( Switch_CocktailMode, value & DipCabinet_Cocktail ? DeviceOn : DeviceOff );
448}
449
450unsigned getDipSwitches(void) {
451 unsigned result = dip_switches_;
452
453 if( getDeviceMode(Switch_RackAdvance) == DeviceOn ) result |= DipRackAdvance_Auto;
454 if( getDeviceMode(Switch_Test) == DeviceOn ) result |= DipMode_Test;
455 if( getDeviceMode(Switch_CocktailMode) == DeviceOn ) result |= DipCabinet_Cocktail;
456
457 return result;
458}
459
460#if defined (CPU_COLDFIRE)
461extern void drawChar( unsigned char * buffer, int index, int ox, int oy, int color );
462#else
463static inline void drawChar( unsigned char * buffer, int index, int ox, int oy, int color )
464{
465 int x,y;
466
467 /* Make the index point to the character offset into the character table */
468 unsigned char * chrmap = charmap_ + index*64;
469 buffer += ox + oy*224; /* Make the buffer point to the character position*/
470 color = (color & 0x3F)*4;
471
472 if( color == 0 )
473 {
474 for( y=7; y>=0; y-- )
475 {
476 rb->memset( buffer, 0, 8 );
477 buffer += ScreenWidth;
478 };
479 return;
480 };
481
482 if( output_devices_ & FlipScreen ) {
483 // Flip character
484 buffer += 7*ScreenWidth;
485 for( y=7; y>=0; y-- ) {
486 for( x=7; x>=0; x-- ) {
487 *buffer++ = (*chrmap++) + color;
488 }
489 buffer -= ScreenWidth + 8; // Go to the next line
490 }
491 }
492 else {
493 for( y=7; y>=0; y-- ) {
494 for( x=7; x>=0; x-- ) {
495 *buffer++ = (*chrmap++) + color;
496 }
497 buffer += ScreenWidth - 8; // Go to the next line
498 }
499 }
500}
501#endif
502
503static inline void drawSprite( unsigned char * buffer, int index )
504{
505 struct PacmanSprite ps = sprites_[index];
506 int x,y;
507 char * s, * s2;
508
509 // Exit now if sprite not visible at all
510 if( (ps.color == 0) || (ps.x >= ScreenWidth) || (ps.y < 16) || (ps.y >= (ScreenHeight-32)) ) {
511 return;
512 }
513
514 // Clip the sprite coordinates to cut the parts that fall off the screen
515 int start_x = (ps.x < 0) ? 0 : ps.x;
516 int end_x = (ps.x < (ScreenWidth-16)) ? ps.x+15 : ScreenWidth-1;
517
518 // Prepare variables for drawing
519 int color = (ps.color & 0x3F)*4;
520 unsigned char * spritemap_base = spritemap_ + ((ps.n & 0x3F)*256);
521
522 buffer += ScreenWidth*ps.y;
523
524 dirty_[(start_x >> 3) + (ps.y >> 3)*28] = 1;
525 dirty_[(start_x >> 3) + 1 + (ps.y >> 3)*28] = 1;
526 dirty_[(end_x >> 3) + (ps.y >> 3)*28] = 1;
527 dirty_[(start_x >> 3) + ((ps.y >> 3)+1)*28] = 1;
528 dirty_[(start_x >> 3) + 1 + ((ps.y >> 3)+1)*28] = 1;
529 dirty_[(end_x >> 3) + ((ps.y >> 3)+1)*28] = 1;
530 dirty_[(start_x >> 3) + ((ps.y+15) >> 3)*28] = 1;
531 dirty_[(start_x >> 3) + 1 + ((ps.y+15) >> 3)*28] = 1;
532 dirty_[(end_x >> 3) + ((ps.y+15) >> 3)*28] = 1;
533
534 // Draw the 16x16 sprite
535 if( ps.mode == 0 ) { // Normal
536 s2 = spritemap_base + start_x-ps.x;
537 // Draw the 16x16 sprite
538 for( y=15; y>=0; y-- ) {
539 s = s2;
540 for( x=start_x; x<=end_x; x++, s++ ) {
541 if( *s ) {
542 buffer[x] = color + *s;
543 }
544 }
545 buffer += ScreenWidth;
546 s2 += 16;
547 }
548 } else if( ps.mode == 1 ) { // Flip Y
549 s2 = spritemap_base + start_x-ps.x + 240;
550 for( y=15; y>=0; y-- ) {
551 s = s2;
552 for( x=start_x; x<=end_x; x++, s++ ) {
553 if( *s ) {
554 buffer[x] = color + *s;
555 }
556 }
557 buffer += ScreenWidth;
558 s2 -= 16;
559 }
560 } else if( ps.mode == 2 ) { // Flip X
561 s2 = spritemap_base + 15 + ps.x-start_x;
562 for( y=15; y>=-0; y-- ) {
563 s = s2;
564 for( x=start_x; x<=end_x; x++, s-- ) {
565 if( *s ) {
566 buffer[x] = color + *s;
567 }
568 }
569 buffer += ScreenWidth;
570 s2 += 16;
571 }
572 } else { // Flip X and Y
573 s2 = spritemap_base + 255 + ps.x-start_x;
574 for( y=15; y>=0; y-- ) {
575 s = s2;
576 for( x=start_x; x<=end_x; x++, s-- ) {
577 if( *s ) {
578 buffer[x] = color + *s;
579 }
580 }
581 buffer += ScreenWidth;
582 s2 -= 16;
583 }
584 }
585}
586
587/*
588 Draw the video into the specified buffer.
589*/
590bool renderBackground( unsigned char * buffer )
591{
592 unsigned char * video = video_mem_;
593 unsigned char * color = color_mem_;
594 unsigned char * dirty = dirty_;
595 int x,y;
596 bool changed=false;
597
598 // Draw the background first...
599 if( output_devices_ & FlipScreen ) {
600 for( y=ScreenHeight-CharHeight; y>=0; y-=CharHeight ) {
601 for( x=ScreenWidth-CharWidth; x>=0; x-=CharWidth ) {
602 if (*dirty) {
603 drawChar( buffer, *video++, x, y, *color++ );
604 *(dirty++)=0;
605 changed=true;
606 } else {
607 dirty++;
608 video++;
609 color++;
610 }
611 }
612 }
613 }
614 else {
615 for( y=0; y<ScreenHeight; y+=CharHeight ) {
616 for( x=0; x<ScreenWidth; x+=CharWidth ) {
617 if (*dirty) {
618 drawChar( buffer, *video++, x, y, *color++ );
619 *(dirty++)=0;
620 changed=true;
621 } else {
622 dirty++;
623 video++;
624 color++;
625 }
626 }
627 }
628 }
629
630 return changed;
631}
632
633void renderSprites( unsigned char * buffer )
634{
635 int i;
636
637 // ...then add the sprites
638 for( i=7; i>=0; i-- ) {
639 drawSprite( buffer, i );
640 }
641}
642
643void playSound( int16_t * buf, int len )
644{
645 /* Clear the buffer */
646 memset( buf, 0, sizeof (int16_t)*len);
647
648 /* Exit now if sound is disabled */
649 if( (output_devices_ & SoundEnabled) == 0 )
650 return;
651
652 /* Let the chip play the sound */
653 wsg3_play_sound( buf, len );
654}
655
656/* Enables/disables the speed hack. */
657/* rockbox: not used
658int setSpeedHack( int enabled )
659{
660 int result = 0;
661
662 if( enabled ) {
663 if( (ram_[0x180B] == 0xBE) && (ram_[0x1FFD] == 0x00) ) {
664 // Patch the ROM to activate the speed hack
665 ram_[0x180B] = 0x01; // Activate speed hack
666 ram_[0x1FFD] = 0xBD; // Fix ROM checksum
667
668 result = 1;
669 }
670 }
671 else {
672 if( (ram_[0x180B] == 0x01) && (ram_[0x1FFD] == 0xBD) ) {
673 // Restore the patched ROM locations
674 ram_[0x180B] = 0xBE;
675 ram_[0x1FFD] = 0x00;
676
677 result = 1;
678 }
679 }
680
681 return result;
682}
683*/