restore changes lost from 2.3.0 core upgrade (GameCube virtual memory,

optimizations from dancinninjac, GB color palettes, rotation/tilt for
WarioWare Twisted, in-game rumble)
This commit is contained in:
Daryl Borth 2018-08-29 20:55:36 -06:00
parent 87995ca4f1
commit eabe325fb0
21 changed files with 2398 additions and 2161 deletions

View File

@ -38,6 +38,12 @@ https://github.com/dborth/vbagx/releases
|0O×øo· UPDATE HISTORY ·oø×O0| |0O×øo· UPDATE HISTORY ·oø×O0|
`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' `¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨'
[2.3.8]
* Restored changes lost from 2.3.0 core upgrade (GameCube virtual memory,
optimizations from dancinninjac, GB color palettes, rotation/tilt for
WarioWare Twisted, in-game rumble)
[2.3.7 - August 28, 2018] [2.3.7 - August 28, 2018]
* Allow loader to pass two arguments instead of three (libertyernie) * Allow loader to pass two arguments instead of three (libertyernie)
@ -724,8 +730,8 @@ Medal Of Honour Underground, Medal Of Honour Infiltrator
One Piece can be played with One Piece Unlimited Adventure controls. One Piece can be played with One Piece Unlimited Adventure controls.
Boktai 1, Boktai 2, Boktai 3, and Kirby's Tilt n Tumble can be played with Boktai 1, Boktai 2, Boktai 3, and Kirby's Tilt n Tumble, and WarioWare Twisted
controls designed for them. can be played with controls designed for them.
-=[ Zelda, Match Wii Controls ]=- -=[ Zelda, Match Wii Controls ]=-
@ -893,6 +899,7 @@ ZR = fast forward (8-bit Game Boy only)
In Super Mario World and Super Mario Land 2, you can use the A or R In Super Mario World and Super Mario Land 2, you can use the A or R
buttons for a spin jump. buttons for a spin jump.
-=[ Yoshi's Universal Gravitation (Topsy Turvy), Match Wii Controls ]=- -=[ Yoshi's Universal Gravitation (Topsy Turvy), Match Wii Controls ]=-
Turn "Match Wii Controls" ON to use these controls. Turn "Match Wii Controls" ON to use these controls.
@ -984,9 +991,20 @@ Z or 1 = change element, or change subscreen (L)
-=[ WarioWare Twisted, Match Wii Controls ]=- -=[ WarioWare Twisted, Match Wii Controls ]=-
NOTE: For unknown reasons (but probably related to the update of the VBA-M Turn "Match Wii Controls" ON to use these controls.
emulator code), WarioWare Twisted will no longer work on VBA-GX. For now, you
will need to go back to VBA-GX 2.2.8 to play it. WarioWare Twisted uses similar controls to the Gameboy game.
The Wii WarioWare Twisted controls are:
=======================================
Rotate the Wii Remote to rotate.
Hold Z to lock the current menu item.
A = Select
B = Cancel
+ = Start
-=[ Kirby's Tilt n Tumble, Match Wii Controls ]=- -=[ Kirby's Tilt n Tumble, Match Wii Controls ]=-

View File

@ -1,6 +1,8 @@
#ifndef SYSTEM_H #ifndef SYSTEM_H
#define SYSTEM_H #define SYSTEM_H
#include "common/Types.h" #include "common/Types.h"
#include <zlib.h> #include <zlib.h>
class SoundDriver; class SoundDriver;
@ -44,6 +46,7 @@ struct EmulatedSystem {
}; };
extern void log(const char *,...); extern void log(const char *,...);
extern bool systemPauseOnFrame(); extern bool systemPauseOnFrame();
extern void systemGbPrint(u8 *,int,int,int,int,int); extern void systemGbPrint(u8 *,int,int,int,int,int);
extern void systemScreenCapture(int); extern void systemScreenCapture(int);
@ -52,6 +55,11 @@ extern void systemDrawScreen();
extern bool systemReadJoypads(); extern bool systemReadJoypads();
// return information about the given joystick, -1 for default joystick // return information about the given joystick, -1 for default joystick
extern u32 systemReadJoypad(int); extern u32 systemReadJoypad(int);
// this function should turn on or off rumble on the gamepad
extern void systemCartridgeRumble(bool);
extern void systemPossibleCartridgeRumble(bool);
// This should be called once per frame
extern void updateRumbleFrame();
extern u32 systemGetClock(); extern u32 systemGetClock();
extern void systemMessage(int, const char *, ...); extern void systemMessage(int, const char *, ...);
extern void systemSetTitle(const char *); extern void systemSetTitle(const char *);
@ -67,6 +75,7 @@ extern void systemShowSpeed(int);
extern void system10Frames(int); extern void system10Frames(int);
extern void systemFrame(); extern void systemFrame();
extern void systemGbBorderOn(); extern void systemGbBorderOn();
extern void Sm60FPS_Init(); extern void Sm60FPS_Init();
extern bool Sm60FPS_CanSkipFrame(); extern bool Sm60FPS_CanSkipFrame();
extern void Sm60FPS_Sleep(); extern void Sm60FPS_Sleep();
@ -78,8 +87,10 @@ extern void winlog(const char *,...);
#endif #endif
extern void (*dbgOutput)(const char *s, u32 addr); extern void (*dbgOutput)(const char *s, u32 addr);
extern void (*dbgSignal)(int sig,int number); extern void (*dbgSignal)(int sig,int number);
extern u16 systemColorMap16[0x10000]; extern u16 systemColorMap16[0x10000];
extern u32 systemColorMap32[0x10000]; //extern u32 systemColorMap32[0x10000];
extern u32 *systemColorMap32;
extern u16 systemGbPalette[24]; extern u16 systemGbPalette[24];
extern int systemRedShift; extern int systemRedShift;
extern int systemGreenShift; extern int systemGreenShift;
@ -90,6 +101,8 @@ extern int systemVerbose;
extern int systemFrameSkip; extern int systemFrameSkip;
extern int systemSaveUpdateCounter; extern int systemSaveUpdateCounter;
extern int systemSpeed; extern int systemSpeed;
#define SYSTEM_SAVE_UPDATED 30 #define SYSTEM_SAVE_UPDATED 30
#define SYSTEM_SAVE_NOT_UPDATED 0 #define SYSTEM_SAVE_NOT_UPDATED 0
#endif // SYSTEM_H #endif // SYSTEM_H

View File

@ -26,7 +26,6 @@ extern "C" {
#include "common/memgzio.h" #include "common/memgzio.h"
} }
#include "gba/gbafilter.h"
#include "gb/gbGlobals.h" #include "gb/gbGlobals.h"
#ifndef _MSC_VER #ifndef _MSC_VER
@ -39,7 +38,7 @@ extern int systemGreenShift;
extern int systemBlueShift; extern int systemBlueShift;
extern u16 systemColorMap16[0x10000]; extern u16 systemColorMap16[0x10000];
extern u32 systemColorMap32[0x10000]; extern u32 *systemColorMap32;
static int (ZEXPORT *utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL; static int (ZEXPORT *utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL;
static int (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; static int (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL;
@ -657,6 +656,7 @@ long utilGzMemTell(gzFile file)
return memtell(file); return memtell(file);
} }
#ifndef GEKKO
void utilGBAFindSave(const u8 *data, const int size) void utilGBAFindSave(const u8 *data, const int size)
{ {
u32 *p = (u32 *)data; u32 *p = (u32 *)data;
@ -743,3 +743,4 @@ bool utilFileExists( const char *filename )
return true; return true;
} }
} }
#endif

View File

@ -29,7 +29,7 @@ int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
Blip_Buffer::Blip_Buffer() Blip_Buffer::Blip_Buffer()
{ {
factor_ = (blip_ulong)LONG_MAX; factor_ = LONG_MAX;
buffer_ = 0; buffer_ = 0;
buffer_size_ = 0; buffer_size_ = 0;
sample_rate_ = 0; sample_rate_ = 0;
@ -126,7 +126,7 @@ Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const
{ {
double ratio = (double) sample_rate_ / rate; double ratio = (double)(sample_rate_) / double(rate);
blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 ); blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
return (blip_resampled_time_t) factor; return (blip_resampled_time_t) factor;
@ -226,15 +226,17 @@ static void gen_sinc( float* out, int count, double oversample, double treble, d
treble = 5.0; treble = 5.0;
double const maxh = 4096.0; double const maxh = 4096.0;
double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) ); double const rolloff = pow( 10.0, treble / (maxh * 20.0 * (1.0 - cutoff)) );
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff ); double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
double const to_angle = PI / 2 / maxh / oversample; double const to_angle = PI / (2.0 * maxh * oversample);
for ( int i = 0; i < count; i++ ) for ( int i = 0; i < count; i++ )
{ {
double angle = ((i - count) * 2 + 1) * to_angle; double angle = double(((i - count)<<1) + 1) * to_angle;
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle ); double maxhAngle = maxh * angle;
double cos_nc_angle = cos( maxh * cutoff * angle ); double c = rolloff * cos( maxhAngle - angle ) - cos( maxhAngle );
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle ); double cos_nc_angle = cos( maxhAngle * cutoff );
double cos_nc1_angle = cos( maxhAngle * cutoff - angle );
double cos_angle = cos( angle ); double cos_angle = cos( angle );
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle; c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
@ -250,7 +252,7 @@ void blip_eq_t::generate( float* out, int count ) const
{ {
// lower cutoff freq for narrow kernels with their wider transition band // lower cutoff freq for narrow kernels with their wider transition band
// (8 points->1.49, 16 points->1.15) // (8 points->1.49, 16 points->1.15)
double oversample = blip_res * 2.25 / count + 0.85; double oversample = blip_res * 2.25 / double(count) + 0.85;
double half_rate = sample_rate * 0.5; double half_rate = sample_rate * 0.5;
if ( cutoff_freq ) if ( cutoff_freq )
oversample = half_rate / cutoff_freq; oversample = half_rate / cutoff_freq;
@ -268,7 +270,9 @@ void Blip_Synth_::adjust_impulse()
{ {
// sum pairs for each phase and add error correction to end of first half // sum pairs for each phase and add error correction to end of first half
int const size = impulses_size(); int const size = impulses_size();
for ( int p = blip_res; p-- >= blip_res / 2; )
int blipRes2 = blip_res >> 1;
for ( int p = blip_res; p-- >= blipRes2; )
{ {
int p2 = blip_res - 2 - p; int p2 = blip_res - 2 - p;
long error = kernel_unit; long error = kernel_unit;
@ -290,9 +294,11 @@ void Blip_Synth_::adjust_impulse()
void Blip_Synth_::treble_eq( blip_eq_t const& eq ) void Blip_Synth_::treble_eq( blip_eq_t const& eq )
{ {
float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2]; int blipRes2 = blip_res >> 1;
int const half_size = blip_res / 2 * (width - 1); float fimpulse [blipRes2 * (blip_widest_impulse_ - 1) + blip_res * 2];
int const half_size = blipRes2 * (width - 1);
eq.generate( &fimpulse [blip_res], half_size ); eq.generate( &fimpulse [blip_res], half_size );
int i; int i;
@ -302,25 +308,25 @@ void Blip_Synth_::treble_eq( blip_eq_t const& eq )
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i]; fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
// starts at 0 // starts at 0
for ( i = 0; i < blip_res; i++ ) for ( i = 0; i < blip_res; ++i )
fimpulse [i] = 0.0f; fimpulse [i] = 0.0f;
// find rescale factor // find rescale factor
double total = 0.0; double total = 0.0;
for ( i = 0; i < half_size; i++ ) for ( i = 0; i < half_size; ++i )
total += fimpulse [blip_res + i]; total += fimpulse [blip_res + i];
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB //double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
//double const base_unit = 37888.0; // allows treble to +5 dB //double const base_unit = 37888.0; // allows treble to +5 dB
double const base_unit = 32768.0; // necessary for blip_unscaled to work double const base_unit = 32768.0; // necessary for blip_unscaled to work
double rescale = base_unit / 2 / total; double rescale = base_unit / (2 * total);
kernel_unit = (long) base_unit; kernel_unit = (long) base_unit;
// integrate, first difference, rescale, convert to int // integrate, first difference, rescale, convert to int
double sum = 0.0; double sum = 0.0;
double next = 0.0; double next = 0.0;
int const size = this->impulses_size(); int const size = this->impulses_size();
for ( i = 0; i < size; i++ ) for ( i = 0; i < size; ++i )
{ {
impulses [i] = (short) (int) floor( (next - sum) * rescale + 0.5 ); impulses [i] = (short) (int) floor( (next - sum) * rescale + 0.5 );
sum += fimpulse [i]; sum += fimpulse [i];
@ -355,7 +361,7 @@ void Blip_Synth_::volume_unit( double new_unit )
// if unit is really small, might need to attenuate kernel // if unit is really small, might need to attenuate kernel
while ( factor < 2.0 ) while ( factor < 2.0 )
{ {
shift++; ++shift;
factor *= 2.0; factor *= 2.0;
} }
@ -411,7 +417,7 @@ long Blip_Buffer::read_samples( blip_sample_t* out_, long max_samples, int stere
blip_long s = BLIP_READER_READ( reader ); blip_long s = BLIP_READER_READ( reader );
BLIP_READER_NEXT_IDX_( reader, bass, offset ); BLIP_READER_NEXT_IDX_( reader, bass, offset );
BLIP_CLAMP( s, s ); BLIP_CLAMP( s, s );
out [offset * 2] = (blip_sample_t) s; out [offset << 1] = (blip_sample_t) s;
} }
while ( ++offset ); while ( ++offset );
} }

View File

@ -505,7 +505,7 @@ void Effects_Buffer::mix_effects( blip_sample_t* out_, int pair_count )
int bufs_remain = bufs_size; int bufs_remain = bufs_size;
do do
{ {
if ( buf->non_silent() && ( buf->echo == !!echo_phase ) ) if ( buf->non_silent() && ( buf->echo == (bool)echo_phase ) )
{ {
stereo_fixed_t* BLIP_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos]; stereo_fixed_t* BLIP_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos];
int const bass = BLIP_READER_BASS( *buf ); int const bass = BLIP_READER_BASS( *buf );

View File

@ -1433,10 +1433,12 @@ void gbWriteMemory(register u16 address, register u8 value)
int paletteHiLo = (v & 0x01); int paletteHiLo = (v & 0x01);
// No access to gbPalette during mode 3 (Color Panel Demo) // No access to gbPalette during mode 3 (Color Panel Demo)
if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || // CAK - The following check has to be commented out for
(gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || // colourised roms like Metroid 2 DX
((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || //if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) ||
((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) // (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) ||
// ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) ||
// ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2))))))
{ {
gbMemory[0xff69] = value; gbMemory[0xff69] = value;
gbPalette[paletteIndex] = (paletteHiLo ? gbPalette[paletteIndex] = (paletteHiLo ?
@ -1487,10 +1489,12 @@ void gbWriteMemory(register u16 address, register u8 value)
paletteIndex += 32; paletteIndex += 32;
// No access to gbPalette during mode 3 (Color Panel Demo) // No access to gbPalette during mode 3 (Color Panel Demo)
if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || // CAK - The following check has to be commented out for
(gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || // colourised roms like Metroid 2 DX
((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || //if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) ||
((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) // (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) ||
// ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) ||
// ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2))))))
{ {
gbMemory[0xff6b] = value; gbMemory[0xff6b] = value;
gbPalette[paletteIndex] = (paletteHiLo ? gbPalette[paletteIndex] = (paletteHiLo ?
@ -1567,7 +1571,7 @@ u8 gbReadOpcode(register u16 address)
if(address < 0x8000) if(address < 0x8000)
return gbMemoryMap[address>>12][address&0x0fff]; return gbMemoryMap[address>>12][address&0x0fff];
if (address < 0xa000) if(address < 0xa000)
{ {
// A lot of 'ugly' checks... But only way to emulate this particular behaviour... // A lot of 'ugly' checks... But only way to emulate this particular behaviour...
if ( if (
@ -1683,13 +1687,13 @@ u8 gbReadOpcode(register u16 address)
if (gbCgbMode) if (gbCgbMode)
{ {
// No access to gbPalette during mode 3 (Color Panel Demo) // No access to gbPalette during mode 3 (Color Panel Demo)
if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || //if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) ||
(gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || // (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) ||
((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || // ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) ||
((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) // ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2))))))
return (gbMemory[address]); return (gbMemory[address]);
else //else
return 0xff; // return 0xff;
} }
else else
return 0xff; return 0xff;
@ -1733,8 +1737,7 @@ u8 gbReadMemory(register u16 address)
if(address < 0x8000) if(address < 0x8000)
return gbMemoryMap[address>>12][address&0x0fff]; return gbMemoryMap[address>>12][address&0x0fff];
if(address < 0xa000)
if (address < 0xa000)
{ {
// A lot of 'ugly' checks... But only way to emulate this particular behaviour... // A lot of 'ugly' checks... But only way to emulate this particular behaviour...
if ( if (
@ -1759,8 +1762,7 @@ u8 gbReadMemory(register u16 address)
) )
) )
) )
return gbMemoryMap[address >> 12][address & 0x0fff]; return gbMemoryMap[address>>12][address&0x0fff];
return 0xff; return 0xff;
} }
@ -1961,13 +1963,13 @@ u8 gbReadMemory(register u16 address)
if (gbCgbMode) if (gbCgbMode)
{ {
// No access to gbPalette during mode 3 (Color Panel Demo) // No access to gbPalette during mode 3 (Color Panel Demo)
if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) || //if (((gbLcdModeDelayed != 3) && (!((gbLcdMode == 0) && (gbLcdTicks>=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-1)))) && (!gbSpeed)) ||
(gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) || // (gbSpeed && ((gbLcdMode == 1) || (gbLcdMode == 2) ||
((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) || // ((gbLcdMode == 3) && (gbLcdTicks>(GBLCD_MODE_3_CLOCK_TICKS-2))) ||
((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2)))))) // ((gbLcdMode == 0) && (gbLcdTicks<=(GBLCD_MODE_0_CLOCK_TICKS-gbSpritesTicks[299]-2))))))
return (gbMemory[address]); return (gbMemory[address]);
else //else
return 0xff; // return 0xff;
} }
else else
return 0xff; return 0xff;
@ -2124,7 +2126,7 @@ void gbCPUInit(const char *biosFileName, bool useBiosFile)
useBios = false; useBios = false;
if (useBiosFile) if (useBiosFile)
{ {
int size = 0x100; /* int size = 0x100;
if(utilLoad(biosFileName, if(utilLoad(biosFileName,
CPUIsGBBios, CPUIsGBBios,
bios, bios,
@ -2133,7 +2135,7 @@ void gbCPUInit(const char *biosFileName, bool useBiosFile)
useBios = true; useBios = true;
else else
systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file size")); systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file size"));
} }*/
} }
} }
@ -2149,7 +2151,7 @@ void gbGetHardwareType()
} }
} }
if((gbCgbMode == 0) && (gbRom[0x146] == 0x03)) { if((gbCgbMode == 0 ) && (gbRom[0x146] == 0x03)) {
if(gbEmulatorType == 0 || if(gbEmulatorType == 0 ||
gbEmulatorType == 2 || gbEmulatorType == 2 ||
gbEmulatorType == 5) gbEmulatorType == 5)
@ -2172,7 +2174,9 @@ void gbGetHardwareType()
void gbReset() void gbReset()
{ {
systemCartridgeRumble(false);
gbGetHardwareType(); gbGetHardwareType();
gbPaletteReset();
oldRegister_WY = 146; oldRegister_WY = 146;
gbInterruptLaunched = 0; gbInterruptLaunched = 0;
@ -2468,7 +2472,7 @@ void gbReset()
gbTimerOn = false; gbTimerOn = false;
if(gbCgbMode) { if(gbCgbMode) {
for (i = 0; i<0x20; i++) for (int i = 0; i<0x20; i++)
gbPalette[i] = 0x7fff; gbPalette[i] = 0x7fff;
// This is just to show that the starting values of the OBJ palettes are different // This is just to show that the starting values of the OBJ palettes are different
@ -2586,12 +2590,12 @@ void gbReset()
} }
} else { } else {
if(gbSgbMode) { if(gbSgbMode) {
for(i = 0; i < 8; i++) for(int i = 0; i < 12; i++)
gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; gbPalette[i] = systemGbPalette[gbPaletteOption*12+i];
} }
for(i = 0; i < 8; i++) for(int i = 0; i < 12; i++)
gbPalette[i] = systemGbPalette[gbPaletteOption*8+i]; gbPalette[i] = systemGbPalette[gbPaletteOption*12+i];
} }
GBTIMER_MODE_0_CLOCK_TICKS = 256; GBTIMER_MODE_0_CLOCK_TICKS = 256;
@ -2645,6 +2649,8 @@ void gbReset()
memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); memset(&gbDataMBC5, 0, sizeof(gbDataMBC5));
gbDataMBC5.mapperROMBank = 1; gbDataMBC5.mapperROMBank = 1;
if (gbRomType >= 0x1c && gbRomType<=0x1e)
gbDataMBC5.isRumbleCartridge = 1;
memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); memset(&gbDataHuC1, 0, sizeof(gbDataHuC1));
gbDataHuC1.mapperROMBank = 1; gbDataHuC1.mapperROMBank = 1;
@ -2746,7 +2752,7 @@ void gbWriteSaveMBC2(const char * name)
return; return;
} }
fwrite(gbMemoryMap[0x0a], fwrite(&gbMemoryMap[0x0a],
1, 1,
512, 512,
file); file);
@ -2928,7 +2934,7 @@ bool gbReadSaveMBC2(const char * name)
return false; return false;
} }
size_t read = fread(gbMemoryMap[0x0a], size_t read = fread(&gbMemoryMap[0x0a],
1, 1,
512, 512,
file); file);
@ -4007,16 +4013,18 @@ bool gbReadSaveState(const char *name)
bool gbWritePNGFile(const char *fileName) bool gbWritePNGFile(const char *fileName)
{ {
if(gbBorderOn) /* if(gbBorderOn)
return utilWritePNGFile(fileName, 256, 224, pix); return utilWritePNGFile(fileName, 256, 224, pix);
return utilWritePNGFile(fileName, 160, 144, pix); return utilWritePNGFile(fileName, 160, 144, pix);*/
return false;
} }
bool gbWriteBMPFile(const char *fileName) bool gbWriteBMPFile(const char *fileName)
{ {
if(gbBorderOn) /* if(gbBorderOn)
return utilWriteBMPFile(fileName, 256, 224, pix); return utilWriteBMPFile(fileName, 256, 224, pix);
return utilWriteBMPFile(fileName, 160, 144, pix); return utilWriteBMPFile(fileName, 160, 144, pix);*/
return false;
} }
void gbCleanUp() void gbCleanUp()
@ -4081,10 +4089,10 @@ bool gbLoadRom(const char *szFile)
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
gbRom = utilLoad(szFile, /* gbRom = utilLoad(szFile,
utilIsGBImage, utilIsGBImage,
NULL, NULL,
size); size);*/
if(!gbRom) if(!gbRom)
return false; return false;
@ -4513,6 +4521,7 @@ void gbEmulate(int ticksToStop)
} }
#endif #endif
u16 oldPCW = PC.W; u16 oldPCW = PC.W;
if(IFF & 0x80) { if(IFF & 0x80) {

View File

@ -583,10 +583,18 @@ void mapperMBC5ROM(u16 address, u8 value)
gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
} }
break; break;
case 0x4000: // RAM bank select case 0x4000: // RAM bank select, plus rumble
if(gbDataMBC5.isRumbleCartridge) // Some games support rumble, such as Disney Tarzan, but aren't on a
// rumble cartridge. As long as the RAM is less than or equal to 256Kbit
// we know that the last address line is not used for real RAM addresses,
// so it must be a rumble signal instead.
if(gbDataMBC5.isRumbleCartridge) {
systemCartridgeRumble(value & 0x08);
value &= 0x07; value &= 0x07;
else } else if (gbRamSizeMask <= 0x7FFF) {
systemPossibleCartridgeRumble(value & 0x08);
value &= 0x07;
} else
value &= 0x0f; value &= 0x0f;
if(value == gbDataMBC5.mapperRAMBank) if(value == gbDataMBC5.mapperRAMBank)
break; break;

View File

@ -521,11 +521,11 @@ void CPUUpdateWindow0()
int x01 = WIN0H & 255; int x01 = WIN0H & 255;
if(x00 <= x01) { if(x00 <= x01) {
for(int i = 0; i < 240; i++) { for(int i = 0; i < 240; ++i) {
gfxInWin0[i] = (i >= x00 && i < x01); gfxInWin0[i] = (i >= x00 && i < x01);
} }
} else { } else {
for(int i = 0; i < 240; i++) { for(int i = 0; i < 240; ++i) {
gfxInWin0[i] = (i >= x00 || i < x01); gfxInWin0[i] = (i >= x00 || i < x01);
} }
} }
@ -537,11 +537,11 @@ void CPUUpdateWindow1()
int x01 = WIN1H & 255; int x01 = WIN1H & 255;
if(x00 <= x01) { if(x00 <= x01) {
for(int i = 0; i < 240; i++) { for(int i = 0; i < 240; ++i) {
gfxInWin1[i] = (i >= x00 && i < x01); gfxInWin1[i] = (i >= x00 && i < x01);
} }
} else { } else {
for(int i = 0; i < 240; i++) { for(int i = 0; i < 240; ++i) {
gfxInWin1[i] = (i >= x00 || i < x01); gfxInWin1[i] = (i >= x00 || i < x01);
} }
} }
@ -667,7 +667,6 @@ bool CPUWriteState(const char *file)
return res; return res;
} }
bool CPUWriteMemState(char *memory, int available) bool CPUWriteMemState(char *memory, int available)
{ {
gzFile gzFile = utilMemGzOpen(memory, available, "w"); gzFile gzFile = utilMemGzOpen(memory, available, "w");
@ -1325,12 +1324,12 @@ bool CPUReadBatteryFile(const char *fileName)
bool CPUWritePNGFile(const char *fileName) bool CPUWritePNGFile(const char *fileName)
{ {
return utilWritePNGFile(fileName, 240, 160, pix); return false; //utilWritePNGFile(fileName, 240, 160, pix);
} }
bool CPUWriteBMPFile(const char *fileName) bool CPUWriteBMPFile(const char *fileName)
{ {
return utilWriteBMPFile(fileName, 240, 160, pix); return false; //utilWriteBMPFile(fileName, 240, 160, pix);
} }
bool CPUIsZipFile(const char * file) bool CPUIsZipFile(const char * file)
@ -1494,7 +1493,7 @@ int CPULoadRom(const char *szFile)
return 0; return 0;
} }
u8 *whereToLoad = cpuIsMultiBoot ? workRAM : rom; //u8 *whereToLoad = cpuIsMultiBoot ? workRAM : rom;
#ifndef NO_DEBUGGER #ifndef NO_DEBUGGER
if(CPUIsELF(szFile)) { if(CPUIsELF(szFile)) {
@ -1519,7 +1518,7 @@ int CPULoadRom(const char *szFile)
} }
} else } else
#endif //NO_DEBUGGER #endif //NO_DEBUGGER
if(szFile!=NULL) /* if(szFile!=NULL)
{ {
if(!utilLoad(szFile, if(!utilLoad(szFile,
utilIsGBAImage, utilIsGBAImage,
@ -1538,7 +1537,7 @@ int CPULoadRom(const char *szFile)
for(i = (romSize+1)&~1; i < 0x2000000; i+=2) { for(i = (romSize+1)&~1; i < 0x2000000; i+=2) {
WRITE16LE(temp, (i >> 1) & 0xFFFF); WRITE16LE(temp, (i >> 1) & 0xFFFF);
temp++; temp++;
} }*/
bios = (u8 *)calloc(1,0x4000); bios = (u8 *)calloc(1,0x4000);
if(bios == NULL) { if(bios == NULL) {
@ -2201,7 +2200,7 @@ void CPUCompareVCOUNT()
} }
if (layerEnableDelay>0) if (layerEnableDelay>0)
{ {
layerEnableDelay--; --layerEnableDelay;
if (layerEnableDelay==1) if (layerEnableDelay==1)
layerEnable = layerSettings & DISPCNT; layerEnable = layerSettings & DISPCNT;
} }
@ -2233,7 +2232,7 @@ void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
while(c != 0) { while(c != 0) {
CPUWriteMemory(d, 0); CPUWriteMemory(d, 0);
d += di; d += di;
c--; --c;
} }
} else { } else {
while(c != 0) { while(c != 0) {
@ -2241,7 +2240,7 @@ void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
CPUWriteMemory(d, cpuDmaLast); CPUWriteMemory(d, cpuDmaLast);
d += di; d += di;
s += si; s += si;
c--; --c;
} }
} }
} else { } else {
@ -2252,7 +2251,7 @@ void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
while(c != 0) { while(c != 0) {
CPUWriteHalfWord(d, 0); CPUWriteHalfWord(d, 0);
d += di; d += di;
c--; --c;
} }
} else { } else {
while(c != 0) { while(c != 0) {
@ -2261,7 +2260,7 @@ void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
cpuDmaLast |= (cpuDmaLast<<16); cpuDmaLast |= (cpuDmaLast<<16);
d += di; d += di;
s += si; s += si;
c--; --c;
} }
} }
} }
@ -2521,7 +2520,6 @@ void CPUCheckDMA(int reason, int dmamask)
doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement, doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement,
DM3CNT_L ? DM3CNT_L : 0x10000, DM3CNT_L ? DM3CNT_L : 0x10000,
DM3CNT_H & 0x0400); DM3CNT_H & 0x0400);
if(DM3CNT_H & 0x4000) { if(DM3CNT_H & 0x4000) {
IF |= 0x0800; IF |= 0x0800;
UPDATE_REG(0x202, IF); UPDATE_REG(0x202, IF);
@ -2568,7 +2566,7 @@ void CPUUpdateRegister(u32 address, u16 value)
windowOn = (layerEnable & 0x6000) ? true : false; windowOn = (layerEnable & 0x6000) ? true : false;
if(change && !((value & 0x80))) { if(change && !((value & 0x80))) {
if(!(DISPSTAT & 1)) { if(!(DISPSTAT & 1)) {
//lcdTicks = 1008; lcdTicks = 1008;
// VCOUNT = 0; // VCOUNT = 0;
// UPDATE_REG(0x06, VCOUNT); // UPDATE_REG(0x06, VCOUNT);
DISPSTAT &= 0xFFFC; DISPSTAT &= 0xFFFC;
@ -2963,65 +2961,61 @@ void CPUUpdateRegister(u32 address, u16 value)
timerOnOffDelay|=8; timerOnOffDelay|=8;
cpuNextEvent = cpuTotalTicks; cpuNextEvent = cpuTotalTicks;
break; break;
case 0x128:
#ifdef LINK_EMULATION
#ifndef NO_LINK if (linkenable)
case COMM_SIOCNT: {
StartLink(value); StartLink(value);
break; }
else
case COMM_SIODATA8:
UPDATE_REG(COMM_SIODATA8, value);
break;
#endif #endif
{
if(value & 0x80) {
value &= 0xff7f;
if(value & 1 && (value & 0x4000)) {
UPDATE_REG(0x12a, 0xFF);
IF |= 0x80;
UPDATE_REG(0x202, IF);
value &= 0x7f7f;
}
}
UPDATE_REG(0x128, value);
}
break;
case 0x12a:
#ifdef LINK_EMULATION
if(linkenable && lspeed)
LinkSSend(value);
#endif
{
UPDATE_REG(0x134, value);
}
break;
case 0x130: case 0x130:
P1 |= (value & 0x3FF); P1 |= (value & 0x3FF);
UPDATE_REG(0x130, P1); UPDATE_REG(0x130, P1);
break; break;
case 0x132: case 0x132:
UPDATE_REG(0x132, value & 0xC3FF); UPDATE_REG(0x132, value & 0xC3FF);
break; break;
case 0x134:
#ifndef NO_LINK #ifdef LINK_EMULATION
case COMM_RCNT: if (linkenable)
StartGPLink(value); StartGPLink(value);
break; else
case COMM_JOYCNT:
{
u16 cur = READ16LE(&ioMem[COMM_JOYCNT]);
if (value & JOYCNT_RESET) cur &= ~JOYCNT_RESET;
if (value & JOYCNT_RECV_COMPLETE) cur &= ~JOYCNT_RECV_COMPLETE;
if (value & JOYCNT_SEND_COMPLETE) cur &= ~JOYCNT_SEND_COMPLETE;
if (value & JOYCNT_INT_ENABLE) cur |= JOYCNT_INT_ENABLE;
UPDATE_REG(COMM_JOYCNT, cur);
}
break;
case COMM_JOY_RECV_L:
UPDATE_REG(COMM_JOY_RECV_L, value);
break;
case COMM_JOY_RECV_H:
UPDATE_REG(COMM_JOY_RECV_H, value);
break;
case COMM_JOY_TRANS_L:
UPDATE_REG(COMM_JOY_TRANS_L, value);
UPDATE_REG(COMM_JOYSTAT, READ16LE(&ioMem[COMM_JOYSTAT]) | JOYSTAT_SEND);
break;
case COMM_JOY_TRANS_H:
UPDATE_REG(COMM_JOY_TRANS_H, value);
break;
case COMM_JOYSTAT:
UPDATE_REG(COMM_JOYSTAT, (READ16LE(&ioMem[COMM_JOYSTAT]) & 0xf) | (value & 0xf0));
break;
#endif #endif
UPDATE_REG(0x134, value);
break;
case 0x140:
#ifdef LINK_EMULATION
if (linkenable)
StartJOYLink(value);
else
#endif
UPDATE_REG(0x140, value);
break;
case 0x200: case 0x200:
IE = value & 0x3FFF; IE = value & 0x3FFF;
UPDATE_REG(0x200, IE); UPDATE_REG(0x200, IE);
@ -3061,7 +3055,7 @@ void CPUUpdateRegister(u32 address, u16 value)
for(int i = 8; i < 15; i++) { for(int i = 8; i < 15; i++) {
memoryWait32[i] = memoryWait[i] + memoryWaitSeq[i] + 1; memoryWait32[i] = memoryWait[i] + memoryWaitSeq[i] + 1;
memoryWaitSeq32[i] = memoryWaitSeq[i]*2 + 1; memoryWaitSeq32[i] = (memoryWaitSeq[i]<<1) + 1;
} }
if((value & 0x4000) == 0x4000) { if((value & 0x4000) == 0x4000) {
@ -3173,7 +3167,7 @@ void CPUInit(const char *biosFileName, bool useBiosFile)
saveType = 0; saveType = 0;
useBios = false; useBios = false;
if(useBiosFile) { /* if(useBiosFile) {
int size = 0x4000; int size = 0x4000;
if(utilLoad(biosFileName, if(utilLoad(biosFileName,
CPUIsGBABios, CPUIsGBABios,
@ -3184,7 +3178,7 @@ void CPUInit(const char *biosFileName, bool useBiosFile)
else else
systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BIOS file size")); systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BIOS file size"));
} }
} }*/
if(!useBios) { if(!useBios) {
memcpy(bios, myROM, sizeof(myROM)); memcpy(bios, myROM, sizeof(myROM));
@ -3256,6 +3250,7 @@ void CPUInit(const char *biosFileName, bool useBiosFile)
void CPUReset() void CPUReset()
{ {
systemCartridgeRumble(false);
if(gbaSaveType == 0) { if(gbaSaveType == 0) {
if(eepromInUse) if(eepromInUse)
gbaSaveType = 3; gbaSaveType = 3;
@ -3552,7 +3547,7 @@ void CPUReset()
cpuDmaHack = false; cpuDmaHack = false;
lastTime = systemGetClock(); //lastTime = systemGetClock();
SWITicks = 0; SWITicks = 0;
} }
@ -3672,7 +3667,7 @@ void CPULoop(int ticks)
// if in V-Blank mode, keep computing... // if in V-Blank mode, keep computing...
if(DISPSTAT & 2) { if(DISPSTAT & 2) {
lcdTicks += 1008; lcdTicks += 1008;
VCOUNT++; ++VCOUNT;
UPDATE_REG(0x06, VCOUNT); UPDATE_REG(0x06, VCOUNT);
DISPSTAT &= 0xFFFD; DISPSTAT &= 0xFFFD;
UPDATE_REG(0x04, DISPSTAT); UPDATE_REG(0x04, DISPSTAT);
@ -3687,7 +3682,7 @@ void CPULoop(int ticks)
} }
} }
if(VCOUNT > 227) { //Reaching last line if(VCOUNT >= 228) { //Reaching last line
DISPSTAT &= 0xFFFC; DISPSTAT &= 0xFFFC;
UPDATE_REG(0x04, DISPSTAT); UPDATE_REG(0x04, DISPSTAT);
VCOUNT = 0; VCOUNT = 0;
@ -3701,26 +3696,26 @@ void CPULoop(int ticks)
if(DISPSTAT & 2) { if(DISPSTAT & 2) {
// if in H-Blank, leave it and move to drawing mode // if in H-Blank, leave it and move to drawing mode
VCOUNT++; ++VCOUNT;
UPDATE_REG(0x06, VCOUNT); UPDATE_REG(0x06, VCOUNT);
lcdTicks += 1008; lcdTicks += 1008;
DISPSTAT &= 0xFFFD; DISPSTAT &= 0xFFFD;
if(VCOUNT == 160) { if(VCOUNT == 160) {
count++; ++count;
systemFrame(); systemFrame();
if((count % 10) == 0) { if((count % 10) == 0) {
system10Frames(60); system10Frames(60);
} }
if(count == 60) { if(count == 60) {
u32 time = systemGetClock(); /*u32 time = systemGetClock();
if(time != lastTime) { if(time != lastTime) {
u32 t = 100000/(time - lastTime); u32 t = 100000/(time - lastTime);
systemShowSpeed(t); systemShowSpeed(t);
} else } else
systemShowSpeed(0); systemShowSpeed(0);
lastTime = time; lastTime = time;*/
count = 0; count = 0;
} }
u32 joy = 0; u32 joy = 0;
@ -3729,7 +3724,7 @@ void CPULoop(int ticks)
// read default joystick // read default joystick
joy = systemReadJoypad(-1); joy = systemReadJoypad(-1);
P1 = 0x03FF ^ (joy & 0x3FF); P1 = 0x03FF ^ (joy & 0x3FF);
if(cpuEEPROMSensorEnabled) //if(cpuEEPROMSensorEnabled)
systemUpdateMotionSensor(); systemUpdateMotionSensor();
UPDATE_REG(0x130, P1); UPDATE_REG(0x130, P1);
u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132])); u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132]));
@ -3759,7 +3754,7 @@ void CPULoop(int ticks)
capture = (ext & 2) ? true : false; capture = (ext & 2) ? true : false;
if(capture && !capturePrevious) { if(capture && !capturePrevious) {
captureNumber++; ++captureNumber;
systemScreenCapture(captureNumber); systemScreenCapture(captureNumber);
} }
capturePrevious = capture; capturePrevious = capture;
@ -3776,7 +3771,7 @@ void CPULoop(int ticks)
systemDrawScreen(); systemDrawScreen();
frameCount = 0; frameCount = 0;
} else } else
frameCount++; ++frameCount;
if(systemPauseOnFrame()) if(systemPauseOnFrame())
ticks = 0; ticks = 0;
} }
@ -3791,8 +3786,8 @@ void CPULoop(int ticks)
switch(systemColorDepth) { switch(systemColorDepth) {
case 16: case 16:
{ {
u16 *dest = (u16 *)pix + 242 * VCOUNT; u16 *dest = (u16 *)pix + 242 * (VCOUNT+1);
for(int x = 0; x < 240;) { for(u32 x = 0; x < 240u;) {
*dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
*dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
*dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
@ -3819,8 +3814,8 @@ void CPULoop(int ticks)
break; break;
case 24: case 24:
{ {
u8 *dest = (u8 *)pix + 240 * VCOUNT * 3; u8 *dest = (u8 *)pix + VCOUNT * 720;
for(int x = 0; x < 240;) { for(u32 x = 0; x < 240u;) {
*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
dest += 3; dest += 3;
*((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
@ -3861,8 +3856,8 @@ void CPULoop(int ticks)
break; break;
case 32: case 32:
{ {
u32 *dest = (u32 *)pix + 241 * VCOUNT; u32 *dest = (u32 *)pix + 241 * (VCOUNT+1);
for(int x = 0; x < 240; ) { for(u32 x = 0; x < 240u; ) {
*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
*dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
@ -3928,7 +3923,7 @@ void CPULoop(int ticks)
if(timer1On) { if(timer1On) {
if(TM1CNT & 4) { if(TM1CNT & 4) {
if(timerOverflow & 1) { if(timerOverflow & 1) {
TM1D++; ++TM1D;
if(TM1D == 0) { if(TM1D == 0) {
TM1D += timer1Reload; TM1D += timer1Reload;
timerOverflow |= 2; timerOverflow |= 2;
@ -3959,7 +3954,7 @@ void CPULoop(int ticks)
if(timer2On) { if(timer2On) {
if(TM2CNT & 4) { if(TM2CNT & 4) {
if(timerOverflow & 2) { if(timerOverflow & 2) {
TM2D++; ++TM2D;
if(TM2D == 0) { if(TM2D == 0) {
TM2D += timer2Reload; TM2D += timer2Reload;
timerOverflow |= 4; timerOverflow |= 4;
@ -3988,7 +3983,7 @@ void CPULoop(int ticks)
if(timer3On) { if(timer3On) {
if(TM3CNT & 4) { if(TM3CNT & 4) {
if(timerOverflow & 4) { if(timerOverflow & 4) {
TM3D++; ++TM3D;
if(TM3D == 0) { if(TM3D == 0) {
TM3D += timer3Reload; TM3D += timer3Reload;
if(TM3CNT & 0x40) { if(TM3CNT & 0x40) {
@ -4065,7 +4060,6 @@ void CPULoop(int ticks)
if(gba_link_enabled) if(gba_link_enabled)
cpuNextEvent = 1; cpuNextEvent = 1;
#endif #endif
if(IF && (IME & 1) && armIrqEnable) { if(IF && (IME & 1) && armIrqEnable) {
int res = IF & IE; int res = IF & IE;
if(stopState) if(stopState)
@ -4131,6 +4125,7 @@ void CPULoop(int ticks)
} }
} }
#ifdef TILED_RENDERING #ifdef TILED_RENDERING
union u8h union u8h
{ {
@ -4398,7 +4393,6 @@ void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs, u32 *line)
} }
#endif #endif
struct EmulatedSystem GBASystem = { struct EmulatedSystem GBASystem = {
// emuMain // emuMain
CPULoop, CPULoop,

View File

@ -5,11 +5,7 @@ extern int armExecute();
extern int thumbExecute(); extern int thumbExecute();
#ifdef __GNUC__ #ifdef __GNUC__
#ifndef __APPLE__
# define INSN_REGPARM __attribute__((regparm(1)))
#else
# define INSN_REGPARM /*nothing*/ # define INSN_REGPARM /*nothing*/
#endif
# define LIKELY(x) __builtin_expect(!!(x),1) # define LIKELY(x) __builtin_expect(!!(x),1)
# define UNLIKELY(x) __builtin_expect(!!(x),0) # define UNLIKELY(x) __builtin_expect(!!(x),0)
#else #else

View File

@ -6,8 +6,7 @@
#include "RTC.h" #include "RTC.h"
#include "Sound.h" #include "Sound.h"
#include "agbprint.h" #include "agbprint.h"
#include "GBAcpu.h" #include "vmmem.h" // Nintendo GC Virtual Memory
#include "GBALink.h"
extern const u32 objTilesAddress[3]; extern const u32 objTilesAddress[3];
@ -34,16 +33,83 @@ extern bool timer3On;
extern int timer3Ticks; extern int timer3Ticks;
extern int timer3ClockReload; extern int timer3ClockReload;
extern int cpuTotalTicks; extern int cpuTotalTicks;
extern u32 RomIdCode;
#define CPUReadByteQuick(addr) \ #define gid(a,b,c) (a|(b<<8)|(c<<16))
#define CORVETTE gid('A','V','C')
/*****************************************************************************
* Nintendo GC Virtual Memory function override
* Tantric September 2008
****************************************************************************/
#define CPUReadByteQuickDef(addr) \
map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
#define CPUReadHalfWordQuick(addr) \ #define CPUReadHalfWordQuickDef(addr) \
READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
#define CPUReadMemoryQuick(addr) \ #define CPUReadMemoryQuickDef(addr) \
READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
u8 inline CPUReadByteQuick( u32 addr )
{
switch(addr >> 24 )
{
case 0x08:
case 0x09:
case 0x0A:
case 0x0C:
#ifdef USE_VM
return VMRead8( addr & 0x1FFFFFF );
#endif
default:
return CPUReadByteQuickDef(addr);
}
return 0;
}
u16 inline CPUReadHalfWordQuick( u32 addr )
{
switch(addr >> 24)
{
case 0x08:
case 0x09:
case 0x0A:
case 0x0C:
#ifdef USE_VM
return VMRead16( addr & 0x1FFFFFF );
#endif
default:
return CPUReadHalfWordQuickDef(addr);
}
return 0;
}
u32 inline CPUReadMemoryQuick( u32 addr )
{
switch(addr >> 24)
{
case 0x08:
case 0x09:
case 0x0A:
case 0x0C:
#ifdef USE_VM
return VMRead32( addr & 0x1FFFFFF );
#endif
default:
return CPUReadMemoryQuickDef(addr);
}
return 0;
}
/*****************************************************************************
* End of VM override
****************************************************************************/
static inline u32 CPUReadMemory(u32 address) static inline u32 CPUReadMemory(u32 address)
{ {
u32 value; u32 value;
@ -80,8 +146,8 @@ static inline u32 CPUReadMemory(u32 address)
if((address < 0x4000400) && ioReadable[address & 0x3fc]) { if((address < 0x4000400) && ioReadable[address & 0x3fc]) {
if(ioReadable[(address & 0x3fc) + 2]) { if(ioReadable[(address & 0x3fc) + 2]) {
value = READ32LE(((u32 *)&ioMem[address & 0x3fC])); value = READ32LE(((u32 *)&ioMem[address & 0x3fC]));
if ((address & 0x3fc) == COMM_JOY_RECV_L) //if ((address & 0x3fc) == COMM_JOY_RECV_L)
UPDATE_REG(COMM_JOYSTAT, READ16LE(&ioMem[COMM_JOYSTAT]) & ~JOYSTAT_RECV); // UPDATE_REG(COMM_JOYSTAT, READ16LE(&ioMem[COMM_JOYSTAT]) & ~JOYSTAT_RECV);
} else { } else {
value = READ16LE(((u16 *)&ioMem[address & 0x3fc])); value = READ16LE(((u16 *)&ioMem[address & 0x3fc]));
} }
@ -107,36 +173,65 @@ static inline u32 CPUReadMemory(u32 address)
value = READ32LE(((u32 *)&oam[address & 0x3FC])); value = READ32LE(((u32 *)&oam[address & 0x3FC]));
break; break;
case 8: case 8:
// Must be cartridge ROM, reading other sensors doesn't allow 32-bit access.
case 9: case 9:
case 10: case 10:
case 11: case 11:
case 12: case 12:
#ifdef USE_VM // Nintendo GC Virtual Memory
value = VMRead32( address & 0x1FFFFFC );
#else
value = READ32LE(((u32 *)&rom[address&0x1FFFFFC])); value = READ32LE(((u32 *)&rom[address&0x1FFFFFC]));
#endif
break; break;
case 13: case 13:
value = eepromRead(address); value = eepromRead(address);
break; break;
case 14: case 14:
case 15: case 15:
// Yoshi's Universal Gravitation (Topsy Turvy)
// Koro Koro
if(cpuEEPROMSensorEnabled) {
switch(address & 0x00008f00) {
case 0x8200:
return systemGetSensorX() & 255;
case 0x8300:
return (systemGetSensorX() >> 8)|0x80;
case 0x8400:
return systemGetSensorY() & 255;
case 0x8500:
return systemGetSensorY() >> 8;
}
}
value = flashRead(address) * 0x01010101; value = flashRead(address) * 0x01010101;
break; break;
// default // default
default: default:
unreadable: unreadable:
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) { if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal word read: %08x at %08x\n", address, armMode ? log("Illegal word read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2); armNextPC - 4 : armNextPC - 2);
} }
#endif #endif
if(cpuDmaHack) { if(cpuDmaHack) {
value = cpuDmaLast; value = cpuDmaLast;
} else { } else {
if(armState) { if(armState) {
#ifdef USE_VM // Nintendo GC Virtual Memory
return CPUReadMemoryQuick(reg[15].I); return CPUReadMemoryQuick(reg[15].I);
#else
return CPUReadMemoryQuickDef(reg[15].I);
#endif
} else { } else {
#ifdef USE_VM // Nintendo GC Virtual Memory
return CPUReadHalfWordQuick(reg[15].I) | return CPUReadHalfWordQuick(reg[15].I) |
CPUReadHalfWordQuick(reg[15].I) << 16; CPUReadHalfWordQuick(reg[15].I) << 16;
#else
return CPUReadHalfWordQuickDef(reg[15].I) |
CPUReadHalfWordQuickDef(reg[15].I) << 16;
#endif
} }
} }
break; break;
@ -250,32 +345,64 @@ static inline u32 CPUReadHalfWord(u32 address)
value = READ16LE(((u16 *)&oam[address & 0x3fe])); value = READ16LE(((u16 *)&oam[address & 0x3fe]));
break; break;
case 8: case 8:
// Use existing case statement and faster test for potential speed improvement
// This is possibly the GPIO port that controls the real time clock,
// WarioWare Twisted! tilt sensors, rumble, and solar sensors.
if(address >= 0x80000c4 && address <= 0x80000c8) {
// this function still works if there is no real time clock
// and does a normal memory read in that case.
value = rtcRead(address & 0xFFFFFFE);
break;
}
case 9: case 9:
case 10: case 10:
case 11: case 11:
case 12: case 12:
if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) #ifdef USE_VM // Nintendo GC Virtual Memory
value = rtcRead(address); value = VMRead16( address & 0x1FFFFFE );
else #else
value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE])); value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE]));
#endif
break; break;
case 13: case 13:
value = eepromRead(address); value = eepromRead(address);
break; break;
case 14: case 14:
case 15: case 15:
// Yoshi's Universal Gravitation (Topsy Turvy)
// Koro Koro
if(cpuEEPROMSensorEnabled) {
switch(address & 0x00008f00) {
case 0x8200:
return systemGetSensorX() & 255;
case 0x8300:
return (systemGetSensorX() >> 8)|0x80;
case 0x8400:
return systemGetSensorY() & 255;
case 0x8500:
return systemGetSensorY() >> 8;
}
}
value = flashRead(address) * 0x0101; value = flashRead(address) * 0x0101;
break; break;
// default // default
default: default:
unreadable: unreadable:
if(cpuDmaHack) { if(cpuDmaHack) {
value = cpuDmaLast & 0xFFFF; value = cpuDmaLast & 0xFFFF;
} else { } else {
if(armState) { if(armState) {
#ifdef USE_VM // Nintendo GC Virtual Memory
value = CPUReadHalfWordQuick(reg[15].I + (address & 2)); value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
#else
value = CPUReadHalfWordQuickDef(reg[15].I + (address & 2));
#endif
} else { } else {
#ifdef USE_VM // Nintendo GC Virtual Memory
value = CPUReadHalfWordQuick(reg[15].I); value = CPUReadHalfWordQuick(reg[15].I);
#else
value = CPUReadHalfWordQuickDef(reg[15].I);
#endif
} }
} }
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
@ -350,22 +477,29 @@ static inline u8 CPUReadByte(u32 address)
case 7: case 7:
return oam[address & 0x3ff]; return oam[address & 0x3ff];
case 8: case 8:
// the real time clock doesn't support byte reads, so don't bother checking for it.
case 9: case 9:
case 10: case 10:
case 11: case 11:
case 12: case 12:
#ifdef USE_VM // Nintendo GC Virtual Memory
return VMRead8( address & 0x1FFFFFF );
#else
return rom[address & 0x1FFFFFF]; return rom[address & 0x1FFFFFF];
#endif
case 13: case 13:
return eepromRead(address); return eepromRead(address);
case 14: case 14:
case 15: case 15:
{ {
if (cpuEEPROMSensorEnabled) { // Yoshi's Universal Gravitation (Topsy Turvy)
switch (address & 0x00008f00) { // Koro Koro
if(cpuEEPROMSensorEnabled) {
switch(address & 0x00008f00) {
case 0x8200: case 0x8200:
return systemGetSensorX() & 255; return systemGetSensorX() & 255;
case 0x8300: case 0x8300:
return (systemGetSensorX() >> 8) | 0x80; return (systemGetSensorX() >> 8)|0x80;
case 0x8400: case 0x8400:
return systemGetSensorY() & 255; return systemGetSensorY() & 255;
case 0x8500: case 0x8500:
@ -376,7 +510,7 @@ static inline u8 CPUReadByte(u32 address)
} }
// default // default
default: default:
unreadable: unreadable:
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) { if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal byte read: %08x at %08x\n", address, armMode ? log("Illegal byte read: %08x at %08x\n", address, armMode ?
@ -387,11 +521,20 @@ unreadable:
return cpuDmaLast & 0xFF; return cpuDmaLast & 0xFF;
} else { } else {
if(armState) { if(armState) {
return CPUReadByteQuick(reg[15].I + (address & 3)); #ifdef USE_VM // Nintendo GC Virtual Memory
return CPUReadByteQuick(reg[15].I+(address & 3));
#else
return CPUReadByteQuickDef(reg[15].I+(address & 3));
#endif
} else { } else {
return CPUReadByteQuick(reg[15].I + (address & 1)); #ifdef USE_VM // Nintendo GC Virtual Memory
return CPUReadByteQuick(reg[15].I+(address & 1));
#else
return CPUReadByteQuickDef(reg[15].I+(address & 1));
#endif
} }
} }
break;
} }
} }
@ -443,6 +586,7 @@ static inline void CPUWriteMemory(u32 address, u32 value)
value); value);
else else
#endif #endif
if(address < 0x5000400 || (RomIdCode & 0xFFFFFF) != CORVETTE)
WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value); WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
break; break;
case 0x06: case 0x06:
@ -542,6 +686,7 @@ static inline void CPUWriteHalfWord(u32 address, u16 value)
value); value);
else else
#endif #endif
if(address < 0x5000400 || (RomIdCode & 0xFFFFFF) != CORVETTE)
WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value); WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
break; break;
case 6: case 6:

View File

@ -1,3 +1,11 @@
/*
Mode 0 is the tiled graphics mode, with all the layers available.
There is no rotation or scaling in this mode.
It can be either 16 colours (with 16 different palettes) or 256 colors.
There are 1024 tiles available.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -7,9 +15,18 @@ void mode0RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) { int x = 232; //240 - 8
lineMix[x] = 0x7fff; do{
} lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
return; return;
} }
@ -38,10 +55,54 @@ void mode0RenderLine()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(u32 x = 0; x < 240u; ++x) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
//--DCN
//
// !NON-PORTABLE!!NON-PORTABLE!
//
// This takes advantage of the fact that the Wii has far more registers
// (32 vs 8) than IA-32 based processors processors (Intel, AMD).
// This actually runs SLOWER on those. This code will only show
// improvements on a PowerPC machine! (19.5% improvement: isolated tests)
//*
u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 li4 = (u8)(lineOBJ[x]>>24);
u8 r = (li2 < li1) ? (li2) : (li1);
if(li3 < r) {
r = (li4 < li3) ? (li4) : (li3);
}else if(li4 < r){
r = (li4);
}
if(line0[x] < backdrop) {
color = line0[x];
top = 0x01;
}
if(r < (u8)(color >> 24)) {
if(r == li1){
color = line1[x];
top = 0x02;
}else if(r == li2){
color = line2[x];
top = 0x04;
}else if(r == li3){
color = line3[x];
top = 0x08;
}else if(r == li4){
color = lineOBJ[x];
top = 0x10;
}
}
//Original
/*
if(line0[x] < color) { if(line0[x] < color) {
color = line0[x]; color = line0[x];
top = 0x01; top = 0x01;
@ -56,41 +117,49 @@ void mode0RenderLine()
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
if((u8)(line3[x]>>24) < (u8)(color >> 24)) { if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
color = line3[x]; color = line3[x];
top = 0x08; top = 0x08;
} }
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
//*/
if((top & 0x10) && (color & 0x00010000)) { if((top & 0x10) && (color & 0x00010000)) {
// semi-transparent OBJ // semi-transparent OBJ
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((u8)(line0[x]>>24) < (u8)(back >> 24)) { u8 li0 = (u8)(line0[x]>>24);
u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 r = (li1 < li0) ? (li1) : (li0);
if(li2 < r) {
r = (li3 < li2) ? (li3) : (li2);
}else if(li3 < r){
r = (li3);
}
if(r < (u8)(color >> 24)) {
if(r == li0){
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }else if(r == li1){
if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
} }else if(r == li2){
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }else if(r == li3){
if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -119,9 +188,20 @@ void mode0RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
return; return;
} }
@ -156,30 +236,39 @@ void mode0RenderLineNoWindow()
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
if(line0[x] < color) { u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 li4 = (u8)(lineOBJ[x]>>24);
u8 r = (li2 < li1) ? (li2) : (li1);
if(li3 < r) {
r = (li4 < li3) ? (li4) : (li3);
}else if(li4 < r){
r = (li4);
}
if(line0[x] < backdrop) {
color = line0[x]; color = line0[x];
top = 0x01; top = 0x01;
} }
if(line1[x] < (color & 0xFF000000)) { if(r < (u8)(color >> 24)) {
if(r == li1){
color = line1[x]; color = line1[x];
top = 0x02; top = 0x02;
} }else if(r == li2){
if(line2[x] < (color & 0xFF000000)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }else if(r == li3){
if(line3[x] < (color & 0xFF000000)) {
color = line3[x]; color = line3[x];
top = 0x08; top = 0x08;
} }else if(r == li4){
if(lineOBJ[x] < (color & 0xFF000000)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
}
if(!(color & 0x00010000)) { if(!(color & 0x00010000)) {
switch(effect) { switch(effect) {
@ -190,40 +279,30 @@ void mode0RenderLineNoWindow()
if(top & BLDMOD) { if(top & BLDMOD) {
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line0[x] < back) {
if(top != 0x01) { if((top != 0x01) && line0[x] < back) {
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }
} if((top != 0x02) && line1[x] < (back & 0xFF000000)) {
if(line1[x] < (back & 0xFF000000)) {
if(top != 0x02) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
} }
}
if(line2[x] < (back & 0xFF000000)) { if((top != 0x04) && line2[x] < (back & 0xFF000000)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if(line3[x] < (back & 0xFF000000)) { if((top != 0x08) && line3[x] < (back & 0xFF000000)) {
if(top != 0x08) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
} }
}
if(lineOBJ[x] < (back & 0xFF000000)) { if((top != 0x10) && lineOBJ[x] < (back & 0xFF000000)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -247,25 +326,43 @@ void mode0RenderLineNoWindow()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line0[x] < back) { //--DCN
// This is pretty much the exact same result:
// line1[x] < (back & 0xFF000000)
//
// (u8)(line0[x]>>24) < (u8)(back >> 24)
//
// The only difference is that the first is stored in a u32,
// and the second is stored in a u8
//*
u8 li0 = (u8)(line0[x]>>24);
u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 r = (li1 < li0) ? (li1) : (li0);
if(li2 < r) {
r = (li3 < li2) ? (li3) : (li2);
}else if(li3 < r){
r = (li3);
}
if(r < (u8)(color >> 24)) {
if(r == li0){
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }else if(r == li1){
if(line1[x] < (back & 0xFF000000)) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
} }else if(r == li2){
if(line2[x] < (back & 0xFF000000)) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }else if(r == li3){
if(line3[x] < (back & 0xFF000000)) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -294,9 +391,20 @@ void mode0RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
return; return;
} }
@ -448,40 +556,31 @@ void mode0RenderLineAll()
if(top & BLDMOD) { if(top & BLDMOD) {
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
if(top != 0x01) { if((mask & 1) && (top != 0x01) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }
}
if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) { if((mask & 2) && (top != 0x02) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
if(top != 0x02) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
} }
}
if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) { if((mask & 4) && (top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) { if((mask & 8) && (top != 0x08) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
if(top != 0x08) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
} }
}
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,

View File

@ -1,3 +1,12 @@
/*
Mode 1 is a tiled graphics mode, but with background layer 2 supporting scaling and rotation.
There is no layer 3 in this mode.
Layers 0 and 1 can be either 16 colours (with 16 different palettes) or 256 colours.
There are 1024 tiles available.
Layer 2 is 256 colours and allows only 256 tiles.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -7,9 +16,20 @@ void mode1RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -40,49 +60,64 @@ void mode1RenderLine()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(u32 x = 0; x < 240u; ++x) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
if(line0[x] < color) { u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 li4 = (u8)(lineOBJ[x]>>24);
u8 r = (li2 < li1) ? (li2) : (li1);
if(li4 < r){
r = (li4);
}
if(line0[x] < backdrop) {
color = line0[x]; color = line0[x];
top = 0x01; top = 0x01;
} }
if((u8)(line1[x]>>24) < (u8)(color >> 24)) { if(r < (u8)(color >> 24)) {
if(r == li1){
color = line1[x]; color = line1[x];
top = 0x02; top = 0x02;
} }else if(r == li2){
if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }else if(r == li4){
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
}
if((top & 0x10) && (color & 0x00010000)) { if((top & 0x10) && (color & 0x00010000)) {
// semi-transparent OBJ // semi-transparent OBJ
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((u8)(line0[x]>>24) < (u8)(back >> 24)) { u8 li0 = (u8)(line0[x]>>24);
u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 r = (li1 < li0) ? (li1) : (li0);
if(li2 < r) {
r = (li2);
}
if(r < (u8)(back >> 24)) {
if(r == li0){
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }else if(r == li1){
if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
} }else if(r == li2){
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -113,9 +148,20 @@ void mode1RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -147,29 +193,37 @@ void mode1RenderLineNoWindow()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
if(line0[x] < color) { u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 li4 = (u8)(lineOBJ[x]>>24);
u8 r = (li2 < li1) ? (li2) : (li1);
if(li4 < r){
r = (li4);
}
if(line0[x] < backdrop) {
color = line0[x]; color = line0[x];
top = 0x01; top = 0x01;
} }
if((u8)(line1[x]>>24) < (u8)(color >> 24)) { if(r < (u8)(color >> 24)) {
if(r == li1){
color = line1[x]; color = line1[x];
top = 0x02; top = 0x02;
} }else if(r == li2){
if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }else if(r == li4){
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
}
if(!(color & 0x00010000)) { if(!(color & 0x00010000)) {
switch((BLDMOD >> 6) & 3) { switch((BLDMOD >> 6) & 3) {
@ -180,33 +234,26 @@ void mode1RenderLineNoWindow()
if(top & BLDMOD) { if(top & BLDMOD) {
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
if(top != 0x01) { if((top != 0x01) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }
}
if((u8)(line1[x]>>24) < (u8)(back >> 24)) { if((top != 0x02) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
if(top != 0x02) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
} }
}
if((u8)(line2[x]>>24) < (u8)(back >> 24)) { if((top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -229,20 +276,28 @@ void mode1RenderLineNoWindow()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((u8)(line0[x]>>24) < (u8)(back >> 24)) { u8 li0 = (u8)(line0[x]>>24);
u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 r = (li1 < li0) ? (li1) : (li0);
if(li2 < r) {
r = (li2);
}
if(r < (u8)(back >> 24)) {
if(r == li0){
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }else if(r == li1){
if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
} }else if(r == li2){
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -273,9 +328,20 @@ void mode1RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -333,7 +399,7 @@ void mode1RenderLineAll()
u8 inWin1Mask = WININ >> 8; u8 inWin1Mask = WININ >> 8;
u8 outMask = WINOUT & 0xFF; u8 outMask = WINOUT & 0xFF;
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 mask = outMask; u8 mask = outMask;
@ -353,22 +419,23 @@ void mode1RenderLineAll()
} }
} }
if(line0[x] < color && (mask & 1)) { // At the very least, move the inexpensive 'mask' operation up front
if((mask & 1) && line0[x] < backdrop) {
color = line0[x]; color = line0[x];
top = 0x01; top = 0x01;
} }
if((u8)(line1[x]>>24) < (u8)(color >> 24) && (mask & 2)) { if((mask & 2) && (u8)(line1[x]>>24) < (u8)(color >> 24)) {
color = line1[x]; color = line1[x];
top = 0x02; top = 0x02;
} }
if((u8)(line2[x]>>24) < (u8)(color >> 24) && (mask & 4)) { if((mask & 4) && (u8)(line2[x]>>24) < (u8)(color >> 24)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) { if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
@ -378,7 +445,7 @@ void mode1RenderLineAll()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) { if((mask & 1) && (u8)(line0[x]>>24) < (u8)(backdrop >> 24)) {
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }
@ -420,33 +487,25 @@ void mode1RenderLineAll()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) { if((mask & 1) && (top != 0x01) && (u8)(line0[x]>>24) < (u8)(backdrop >> 24)) {
if(top != 0x01) {
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }
}
if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) { if((mask & 2) && (top != 0x02) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
if(top != 0x02) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
} }
}
if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) { if((mask & 4) && (top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,

View File

@ -1,3 +1,11 @@
/*
Mode 2 is a 256 colour tiled graphics mode which supports scaling and rotation.
There is no background layer 0 or 1 in this mode. Only background layers 2 and 3.
There are 256 tiles available.
It does not support flipping.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -7,9 +15,20 @@ void mode2RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -43,40 +62,51 @@ void mode2RenderLine()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 li4 = (u8)(lineOBJ[x]>>24);
if((u8)(line2[x]>>24) < (u8)(color >> 24)) { u8 r = (li3 < li2) ? (li3) : (li2);
if(li4 < r){
r = (li4);
}
if(r < (u8)(color >> 24)) {
if(r == li2){
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }else if(r == li3){
if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
color = line3[x]; color = line3[x];
top = 0x08; top = 0x08;
} }else if(r == li4){
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
}
if((top & 0x10) && (color & 0x00010000)) { if((top & 0x10) && (color & 0x00010000)) {
// semi-transparent OBJ // semi-transparent OBJ
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((u8)(line2[x]>>24) < (u8)(back >> 24)) { u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 r = (li3 < li2) ? (li3) : (li2);
if(r < (u8)(back >> 24)) {
if(r == li2){
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }else if(r == li3){
if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -108,9 +138,20 @@ void mode2RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -144,25 +185,32 @@ void mode2RenderLineNoWindow()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 li4 = (u8)(lineOBJ[x]>>24);
if((u8)(line2[x]>>24) < (u8)(color >> 24)) { u8 r = (li3 < li2) ? (li3) : (li2);
if(li4 < r){
r = (li4);
}
if(r < (u8)(color >> 24)) {
if(r == li2){
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }else if(r == li3){
if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
color = line3[x]; color = line3[x];
top = 0x08; top = 0x08;
} }else if(r == li4){
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
}
if(!(color & 0x00010000)) { if(!(color & 0x00010000)) {
switch((BLDMOD >> 6) & 3) { switch((BLDMOD >> 6) & 3) {
@ -174,26 +222,20 @@ void mode2RenderLineNoWindow()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((u8)(line2[x]>>24) < (u8)(back >> 24)) { if((top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((u8)(line3[x]>>24) < (u8)(back >> 24)) { if((top != 0x08) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
if(top != 0x08) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
} }
}
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -216,15 +258,19 @@ void mode2RenderLineNoWindow()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((u8)(line2[x]>>24) < (u8)(back >> 24)) { u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 r = (li3 < li2) ? (li3) : (li2);
if(r < (u8)(back >> 24)) {
if(r == li2){
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }else if(r == li3){
if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -256,9 +302,20 @@ void mode2RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -339,17 +396,17 @@ void mode2RenderLineAll()
} }
} }
if(line2[x] < color && (mask & 4)) { if((mask & 4) && line2[x] < color) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
if((u8)(line3[x]>>24) < (u8)(color >> 24) && (mask & 8)) { if((mask & 8) && (u8)(line3[x]>>24) < (u8)(color >> 24)) {
color = line3[x]; color = line3[x];
top = 0x08; top = 0x08;
} }
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) { if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
@ -396,26 +453,20 @@ void mode2RenderLineAll()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && line2[x] < back) { if((mask & 4) && (top != 0x04) && line2[x] < back) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) { if((mask & 8) && (top != 0x08) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
if(top != 0x08) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
} }
}
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,

View File

@ -1,3 +1,10 @@
/*
Mode 3 is a 15-bit (32768) colour bitmap graphics mode.
It has a single layer, background layer 2, the same size as the screen.
It doesn't support paging, scrolling, flipping, rotation or tiles.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -7,9 +14,20 @@ void mode3RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -36,7 +54,7 @@ void mode3RenderLine()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
@ -55,7 +73,7 @@ void mode3RenderLine()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line2[x] < back) { if(line2[x] < background) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
@ -89,9 +107,20 @@ void mode3RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -118,11 +147,11 @@ void mode3RenderLineNoWindow()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < color) { if(line2[x] < background) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -142,19 +171,15 @@ void mode3RenderLineNoWindow()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line2[x] < back) { if(top != 0x04 && (line2[x] < background) ) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if(top != 0x10 && ((u8)(lineOBJ[x]>>24) < (u8)(back >> 24))) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -178,7 +203,7 @@ void mode3RenderLineNoWindow()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line2[x] < back) { if(line2[x] < background) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
@ -212,9 +237,20 @@ void mode3RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -268,7 +304,7 @@ void mode3RenderLineAll()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
u8 mask = outMask; u8 mask = outMask;
@ -288,7 +324,7 @@ void mode3RenderLineAll()
} }
} }
if((mask & 4) && (line2[x] < color)) { if((mask & 4) && line2[x] < background) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -303,7 +339,7 @@ void mode3RenderLineAll()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && line2[x] < back) { if((mask & 4) && line2[x] < background) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
@ -334,25 +370,20 @@ void mode3RenderLineAll()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && line2[x] < back) { if((mask & 4) && (top != 0x04) && line2[x] < back) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
coeff[COLEV & 0x1F], coeff[COLEV & 0x1F],
coeff[(COLEV >> 8) & 0x1F]); coeff[(COLEV >> 8) & 0x1F]);
} }
} }
break; break;

View File

@ -1,3 +1,10 @@
/*
Mode 4 is a 256 colour bitmap graphics mode with 2 swappable pages.
It has a single layer, background layer 2, the same size as the screen.
It doesn't support scrolling, flipping, rotation or tiles.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "GBAGfx.h" #include "GBAGfx.h"
#include "Globals.h" #include "Globals.h"
@ -7,9 +14,20 @@ void mode4RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -35,11 +53,11 @@ void mode4RenderLine()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < color) { if(line2[x] < backdrop) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -54,7 +72,7 @@ void mode4RenderLine()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line2[x] < back) { if(line2[x] < backdrop) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
@ -88,9 +106,20 @@ void mode4RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -116,11 +145,11 @@ void mode4RenderLineNoWindow()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < color) { if(line2[x] < backdrop) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -140,19 +169,15 @@ void mode4RenderLineNoWindow()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line2[x] < back) { if((top != 0x04) && line2[x] < backdrop) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -210,9 +235,20 @@ void mode4RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -265,7 +301,7 @@ void mode4RenderLineAll()
u8 inWin1Mask = WININ >> 8; u8 inWin1Mask = WININ >> 8;
u8 outMask = WINOUT & 0xFF; u8 outMask = WINOUT & 0xFF;
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 mask = outMask; u8 mask = outMask;
@ -285,7 +321,7 @@ void mode4RenderLineAll()
} }
} }
if((mask & 4) && (line2[x] < color)) { if((mask & 4) && (line2[x] < backdrop)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -331,25 +367,20 @@ void mode4RenderLineAll()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && line2[x] < back) { if((mask & 4) && (top != 0x04) && (line2[x] < backdrop)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
coeff[COLEV & 0x1F], coeff[COLEV & 0x1F],
coeff[(COLEV >> 8) & 0x1F]); coeff[(COLEV >> 8) & 0x1F]);
} }
} }
break; break;

View File

@ -1,3 +1,11 @@
/*
Mode 5 is a low resolution (160x128) 15-bit colour bitmap graphics mode
with 2 swappable pages!
It has a single layer, background layer 2, lower resolution than the screen.
It doesn't support scrolling, flipping, rotation or tiles.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -5,9 +13,20 @@
void mode5RenderLine() void mode5RenderLine()
{ {
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -36,11 +55,11 @@ void mode5RenderLine()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < color) { if(line2[x] < background) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -87,9 +106,20 @@ void mode5RenderLine()
void mode5RenderLineNoWindow() void mode5RenderLineNoWindow()
{ {
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -118,11 +148,11 @@ void mode5RenderLineNoWindow()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < color) { if(line2[x] < background) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -142,19 +172,15 @@ void mode5RenderLineNoWindow()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line2[x] < back) { if((top != 0x04) && line2[x] < background) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -210,9 +236,19 @@ void mode5RenderLineNoWindow()
void mode5RenderLineAll() void mode5RenderLineAll()
{ {
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
lineMix[x] = 0x7fff; int x = 232; //240 - 8
} do{
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -268,7 +304,7 @@ void mode5RenderLineAll()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; ++x) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
u8 mask = outMask; u8 mask = outMask;
@ -288,7 +324,7 @@ void mode5RenderLineAll()
} }
} }
if((mask & 4) && (line2[x] < color)) { if((mask & 4) && (line2[x] < background)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -334,19 +370,15 @@ void mode5RenderLineAll()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && line2[x] < back) { if((mask & 4) && (top != 0x04) && (line2[x] < background)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
}
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
} }
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,

View File

@ -9,9 +9,6 @@
#include <time.h> #include <time.h>
#include <string.h> #include <string.h>
// Defined in VGA-GX input.cpp
void systemCartridgeRumble(bool);
enum RTCSTATE enum RTCSTATE
{ {
IDLE = 0, IDLE = 0,

View File

@ -50,8 +50,8 @@ int soundTicks = SOUND_CLOCK_TICKS_;
static float soundVolume = 1.0f; static float soundVolume = 1.0f;
static int soundEnableFlag = 0x3ff; // emulator channels enabled static int soundEnableFlag = 0x3ff; // emulator channels enabled
static float soundFiltering_ = -1; static float soundFiltering_ = -1.0f;
static float soundVolume_ = -1; static float soundVolume_ = -1.0f;
void interp_rate() { /* empty for now */ } void interp_rate() { /* empty for now */ }
@ -82,8 +82,8 @@ public:
int readIndex; int readIndex;
int count; int count;
int writeIndex; int writeIndex;
u8 fifo [32];
int dac; int dac;
u8 fifo [32];
private: private:
int timer; int timer;
@ -115,7 +115,7 @@ void Gba_Pcm::apply_control( int idx )
int ch = 0; int ch = 0;
if ( (soundEnableFlag >> idx & 0x100) && (ioMem [NR52] & 0x80) ) if ( (soundEnableFlag >> idx & 0x100) && (ioMem [NR52] & 0x80) )
ch = ioMem [SGCNT0_H+1] >> (idx * 4) & 3; ch = ioMem [SGCNT0_H+1] >> (idx <<2) & 3;
Blip_Buffer* out = 0; Blip_Buffer* out = 0;
switch ( ch ) switch ( ch )
@ -162,11 +162,10 @@ void Gba_Pcm::update( int dac )
int filter = 0; int filter = 0;
if ( soundInterpolation ) if ( soundInterpolation )
{ {
// base filtering on how long since last sample was output unsigned period = unsigned(time - last_time);
int period = time - last_time; unsigned idx = period >> 9;
int idx = (unsigned) period / 512; if ( idx > 3 )
if ( idx >= 3 )
idx = 3; idx = 3;
static int const filters [4] = { 0, 0, 1, 2 }; static int const filters [4] = { 0, 0, 1, 2 };
@ -204,7 +203,7 @@ void Gba_Pcm_Fifo::timer_overflowed( int which_timer )
} }
// Read next sample from FIFO // Read next sample from FIFO
count--; --count;
dac = fifo [readIndex]; dac = fifo [readIndex];
readIndex = (readIndex + 1) & 31; readIndex = (readIndex + 1) & 31;
pcm.update( dac ); pcm.update( dac );
@ -284,14 +283,17 @@ static void apply_volume( bool apu_only = false )
if ( gb_apu ) if ( gb_apu )
{ {
static float const apu_vols [4] = { 0.25, 0.5, 1, 0.25 }; static float const apu_vols [4] = { 0.25f, 0.5f, 1.0f, 0.25f };
gb_apu->volume( soundVolume_ * apu_vols [ioMem [SGCNT0_H] & 3] ); gb_apu->volume( soundVolume_ * apu_vols [ioMem [SGCNT0_H] & 3] );
} }
if ( !apu_only ) if ( !apu_only )
{ {
for ( int i = 0; i < 3; i++ ) double tmpVol = 0.002578125 * soundVolume_; // 0.66 / 256 * soundVolume_
pcm_synth [i].volume( 0.66 / 256 * soundVolume_ );
pcm_synth[0].volume( tmpVol );
pcm_synth[1].volume( tmpVol );
pcm_synth[2].volume( tmpVol );
} }
} }
@ -352,19 +354,14 @@ static void end_frame( blip_time_t time )
void flush_samples(Multi_Buffer * buffer) void flush_samples(Multi_Buffer * buffer)
{ {
#ifdef __LIBRETRO__
int numSamples = buffer->read_samples( (blip_sample_t*) soundFinalWave, buffer->samples_avail() );
soundDriver->write(soundFinalWave, numSamples);
systemOnWriteDataToSoundBuffer(soundFinalWave, numSamples);
#else
// We want to write the data frame by frame to support legacy audio drivers // We want to write the data frame by frame to support legacy audio drivers
// that don't use the length parameter of the write method. // that don't use the length parameter of the write method.
// TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the // TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the
// samples at once to help reducing the audio delay on all platforms. // samples at once to help reducing the audio delay on all platforms.
int soundBufferLen = ( soundSampleRate / 60 ) * 4; int soundBufferLen = ( soundSampleRate / 60 ) << 2;
// soundBufferLen should have a whole number of sample pairs // soundBufferLen should have a whole number of sample pairs
assert( soundBufferLen % (2 * sizeof *soundFinalWave) == 0 ); assert( soundBufferLen % ((sizeof *soundFinalWave)<<1) == 0 );
// number of samples in output buffer // number of samples in output buffer
int const out_buf_size = soundBufferLen / sizeof *soundFinalWave; int const out_buf_size = soundBufferLen / sizeof *soundFinalWave;
@ -379,15 +376,16 @@ void flush_samples(Multi_Buffer * buffer)
soundDriver->write(soundFinalWave, soundBufferLen); soundDriver->write(soundFinalWave, soundBufferLen);
systemOnWriteDataToSoundBuffer(soundFinalWave, soundBufferLen); systemOnWriteDataToSoundBuffer(soundFinalWave, soundBufferLen);
} }
#endif
} }
static void apply_filtering() static void apply_filtering()
{ {
soundFiltering_ = soundFiltering; soundFiltering_ = soundFiltering;
int const base_freq = (int) (32768 - soundFiltering_ * 16384); // Yes, I changed soundFiltering_ to soundFiltering, the reason is
int const nyquist = stereo_buffer->sample_rate() / 2; // to eliminate a write-read dependency
int const base_freq = 32768 - (int) (soundFiltering * 16384.0f);
int const nyquist = stereo_buffer->sample_rate() >> 1;
for ( int i = 0; i < 3; i++ ) for ( int i = 0; i < 3; i++ )
{ {
@ -456,13 +454,6 @@ static void remake_stereo_buffer()
pcm [0].pcm.init(); pcm [0].pcm.init();
pcm [1].pcm.init(); pcm [1].pcm.init();
// APU
if ( !gb_apu )
{
gb_apu = new Gb_Apu; // TODO: handle out of memory
reset_apu();
}
// Stereo_Buffer // Stereo_Buffer
delete stereo_buffer; delete stereo_buffer;
stereo_buffer = 0; stereo_buffer = 0;
@ -476,7 +467,13 @@ static void remake_stereo_buffer()
pcm [1].which = 1; pcm [1].which = 1;
apply_filtering(); apply_filtering();
// Volume Level // APU
if ( !gb_apu )
{
gb_apu = new Gb_Apu; // TODO: handle out of memory
reset_apu();
}
apply_muting(); apply_muting();
apply_volume(); apply_volume();
} }
@ -595,8 +592,8 @@ static struct {
gb_apu_state_t apu; gb_apu_state_t apu;
// old state // old state
u8 soundDSAValue;
int soundDSBValue; int soundDSBValue;
u8 soundDSAValue;
} state; } state;
// Old GBA sound state format // Old GBA sound state format
@ -754,25 +751,16 @@ static void skip_read( gzFile in, int count )
} }
} }
#ifdef __LIBRETRO__
void soundSaveGame( u8 *&out )
#else
void soundSaveGame( gzFile out ) void soundSaveGame( gzFile out )
#endif
{ {
gb_apu->save_state( &state.apu ); gb_apu->save_state( &state.apu );
// Be sure areas for expansion get written as zero // Be sure areas for expansion get written as zero
memset( dummy_state, 0, sizeof dummy_state ); memset( dummy_state, 0, sizeof dummy_state );
#ifdef __LIBRETRO__
utilWriteDataMem( out, gba_state );
#else
utilWriteData( out, gba_state ); utilWriteData( out, gba_state );
#endif
} }
#ifndef __LIBRETRO__
static void soundReadGameOld( gzFile in, int version ) static void soundReadGameOld( gzFile in, int version )
{ {
// Read main data // Read main data
@ -807,28 +795,19 @@ static void soundReadGameOld( gzFile in, int version )
(void) utilReadInt( in ); // ignore quality (void) utilReadInt( in ); // ignore quality
} }
#endif
#include <stdio.h> #include <stdio.h>
#ifdef __LIBRETRO__
void soundReadGame(const u8*& in, int version )
#else
void soundReadGame( gzFile in, int version ) void soundReadGame( gzFile in, int version )
#endif
{ {
// Prepare APU and default state // Prepare APU and default state
reset_apu(); reset_apu();
gb_apu->save_state( &state.apu ); gb_apu->save_state( &state.apu );
if ( version > SAVE_GAME_VERSION_9 ) if ( version > SAVE_GAME_VERSION_9 )
#ifdef __LIBRETRO__
utilReadDataMem( in, gba_state );
#else
utilReadData( in, gba_state ); utilReadData( in, gba_state );
else else
soundReadGameOld( in, version ); soundReadGameOld( in, version );
#endif
gb_apu->load_state( state.apu ); gb_apu->load_state( state.apu );
write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F ); write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F );

View File

@ -1,227 +0,0 @@
#include "gbafilter.h"
#include <math.h>
extern int systemColorDepth;
extern int systemRedShift;
extern int systemGreenShift;
extern int systemBlueShift;
extern u16 systemColorMap16[0x10000];
extern u32 systemColorMap32[0x10000];
static const unsigned char curve[32] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x10, 0x12,
0x14, 0x16, 0x18, 0x1c, 0x20, 0x28, 0x30, 0x38,
0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x80,
0x88, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0};
// output R G B
static const unsigned char influence[3 * 3] = { 16, 4, 4, // red
8, 16, 8, // green
0, 8, 16};// blue
inline void swap(short & a, short & b)
{
short temp = a;
a = b;
b = temp;
}
void gbafilter_pal(u16 * buf, int count)
{
short temp[3 * 3], s;
unsigned pix;
u8 red, green, blue;
while (count--)
{
pix = *buf;
s = curve[(pix >> systemGreenShift) & 0x1f];
temp[3] = s * influence[3];
temp[4] = s * influence[4];
temp[5] = s * influence[5];
s = curve[(pix >> systemRedShift) & 0x1f];
temp[0] = s * influence[0];
temp[1] = s * influence[1];
temp[2] = s * influence[2];
s = curve[(pix >> systemBlueShift) & 0x1f];
temp[6] = s * influence[6];
temp[7] = s * influence[7];
temp[8] = s * influence[8];
if (temp[0] < temp[3]) swap(temp[0], temp[3]);
if (temp[0] < temp[6]) swap(temp[0], temp[6]);
if (temp[3] < temp[6]) swap(temp[3], temp[6]);
temp[3] <<= 1;
temp[0] <<= 2;
temp[0] += temp[3] + temp[6];
red = ((int(temp[0]) * 160) >> 17) + 4;
if (red > 31) red = 31;
if (temp[2] < temp[5]) swap(temp[2], temp[5]);
if (temp[2] < temp[8]) swap(temp[2], temp[8]);
if (temp[5] < temp[8]) swap(temp[5], temp[8]);
temp[5] <<= 1;
temp[2] <<= 2;
temp[2] += temp[5] + temp[8];
blue = ((int(temp[2]) * 160) >> 17) + 4;
if (blue > 31) blue = 31;
if (temp[1] < temp[4]) swap(temp[1], temp[4]);
if (temp[1] < temp[7]) swap(temp[1], temp[7]);
if (temp[4] < temp[7]) swap(temp[4], temp[7]);
temp[4] <<= 1;
temp[1] <<= 2;
temp[1] += temp[4] + temp[7];
green = ((int(temp[1]) * 160) >> 17) + 4;
if (green > 31) green = 31;
pix = red << systemRedShift;
pix += green << systemGreenShift;
pix += blue << systemBlueShift;
*buf++ = pix;
}
}
void gbafilter_pal32(u32 * buf, int count)
{
short temp[3 * 3], s;
unsigned pix;
u8 red, green, blue;
while (count--)
{
pix = *buf;
s = curve[(pix >> systemGreenShift) & 0x1f];
temp[3] = s * influence[3];
temp[4] = s * influence[4];
temp[5] = s * influence[5];
s = curve[(pix >> systemRedShift) & 0x1f];
temp[0] = s * influence[0];
temp[1] = s * influence[1];
temp[2] = s * influence[2];
s = curve[(pix >> systemBlueShift) & 0x1f];
temp[6] = s * influence[6];
temp[7] = s * influence[7];
temp[8] = s * influence[8];
if (temp[0] < temp[3]) swap(temp[0], temp[3]);
if (temp[0] < temp[6]) swap(temp[0], temp[6]);
if (temp[3] < temp[6]) swap(temp[3], temp[6]);
temp[3] <<= 1;
temp[0] <<= 2;
temp[0] += temp[3] + temp[6];
//red = ((int(temp[0]) * 160) >> 17) + 4;
red = ((int(temp[0]) * 160) >> 14) + 32;
if (temp[2] < temp[5]) swap(temp[2], temp[5]);
if (temp[2] < temp[8]) swap(temp[2], temp[8]);
if (temp[5] < temp[8]) swap(temp[5], temp[8]);
temp[5] <<= 1;
temp[2] <<= 2;
temp[2] += temp[5] + temp[8];
//blue = ((int(temp[2]) * 160) >> 17) + 4;
blue = ((int(temp[2]) * 160) >> 14) + 32;
if (temp[1] < temp[4]) swap(temp[1], temp[4]);
if (temp[1] < temp[7]) swap(temp[1], temp[7]);
if (temp[4] < temp[7]) swap(temp[4], temp[7]);
temp[4] <<= 1;
temp[1] <<= 2;
temp[1] += temp[4] + temp[7];
//green = ((int(temp[1]) * 160) >> 17) + 4;
green = ((int(temp[1]) * 160) >> 14) + 32;
//pix = red << redshift;
//pix += green << greenshift;
//pix += blue << blueshift;
pix = red << (systemRedShift - 3);
pix += green << (systemGreenShift - 3);
pix += blue << (systemBlueShift - 3);
*buf++ = pix;
}
}
// for palette mode to work with the three spoony filters in 32bpp depth
void gbafilter_pad(u8 * buf, int count)
{
union
{
struct
{
u8 r;
u8 g;
u8 b;
u8 a;
} part;
unsigned whole;
}
mask;
mask.whole = 0x1f << systemRedShift;
mask.whole += 0x1f << systemGreenShift;
mask.whole += 0x1f << systemBlueShift;
switch (systemColorDepth)
{
case 24:
while (count--)
{
*buf++ &= mask.part.r;
*buf++ &= mask.part.g;
*buf++ &= mask.part.b;
}
break;
case 32:
while (count--)
{
*((u32*)buf) &= mask.whole;
buf += 4;
}
}
}
/*
void UpdateSystemColorMaps(int lcd)
{
switch(systemColorDepth) {
case 16:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd == 1) gbafilter_pal(systemColorMap16, 0x10000);
}
break;
case 24:
case 32:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd == 1) gbafilter_pal32(systemColorMap32, 0x10000);
}
break;
}
}
*/

View File

@ -1,5 +0,0 @@
#include "../System.h"
void gbafilter_pal(u16 * buf, int count);
void gbafilter_pal32(u32 * buf, int count);
void gbafilter_pad(u8 * buf, int count);

View File

@ -77,7 +77,7 @@ int systemGreenShift = 0;
int systemColorDepth = 0; int systemColorDepth = 0;
u16 systemGbPalette[24]; u16 systemGbPalette[24];
u16 systemColorMap16[0x10000]; u16 systemColorMap16[0x10000];
u32 systemColorMap32[0x10000]; u32 *systemColorMap32 = NULL;
void gbSetPalette(u32 RRGGBB[]); void gbSetPalette(u32 RRGGBB[]);
bool StartColorizing(); bool StartColorizing();