Set eol-style to native to keep things sane.

This commit is contained in:
Shamus Hammons 2007-05-29 05:00:36 +00:00
parent ce9f314942
commit b90c77b56b
16 changed files with 292 additions and 722 deletions

View File

@ -54,9 +54,9 @@ TARGET = apple2
# -ffast-math -fomit-frame-pointer `sdl-config --cflags` -fprofile-arcs -ftest-coverage
# No optimization for profiling with gprof...
CFLAGS = -MMD -Wall -Wno-switch -D$(SYSTYPE) \
-ffast-math `sdl-config --cflags` -pg -g
-ffast-math `sdl-config --cflags` -pg
CPPFLAGS = -MMD -Wall -Wno-switch -Wno-non-virtual-dtor -D$(SYSTYPE) \
-ffast-math `sdl-config --cflags` -pg -g
-ffast-math `sdl-config --cflags` -pg
# -fomit-frame-pointer `sdl-config --cflags` -g
# -fomit-frame-pointer `sdl-config --cflags` -DLOG_UNMAPPED_MEMORY_ACCESSES
@ -73,7 +73,6 @@ INCS = -I. -I./src -I/usr/local/include -I/usr/include
OBJS = \
obj/button.o \
obj/draggablewindow.o \
obj/draggablewindow2.o \
obj/element.o \
obj/gui.o \
obj/guimisc.o \

View File

@ -39,7 +39,7 @@ autoSaveState = 1
# Yes, keys???
#floppyImage1 = ./disks/MidnightMagic_etc.dsk
# ???
#floppyImage1 = ./disks/battle_chess_1.dsk
floppyImage1 = ./disks/battle_chess_1.dsk
# Yes
#floppyImage1 = ./disks/MoebiusI-1.dsk
# Yes, but crashes on the attract mode
@ -54,8 +54,8 @@ autoSaveState = 1
#floppyImage1 = ./disks/ultima_ii-1.dsk
#floppyImage2 = ./disks/ultima_ii-2.dsk
# Yes, autoloads!
floppyImage1 = ./disks/u2prog-patched.dsk
floppyImage2 = ./disks/u2player-jlh.dsk
#floppyImage1 = ./disks/u2prog-patched.dsk
#floppyImage2 = ./disks/u2player-jlh.dsk
# OpenGL options: 1 - use OpenGL rendering, 0 - use old style rendering

View File

@ -51,7 +51,7 @@
#include "gui/gui.h"
#include "gui/window.h"
#include "gui/draggablewindow2.h"
#include "gui/draggablewindow.h"
#include "gui/textedit.h"
using namespace std;
@ -98,7 +98,7 @@ static void BlinkTimer(void);
Element * TestWindow(void)
{
Element * win = new DraggableWindow2(10, 10, 128, 128);
Element * win = new DraggableWindow(10, 10, 128, 128);
// ((DraggableWindow *)win)->AddElement(new TextEdit(4, 16, 92, 0, "u2prog.dsk", win));
return win;
@ -316,28 +316,28 @@ if (addr >= 0xC080 && addr <= 0xC08F)
A-9 (Mockingboard)
APPENDIX F Assembly Language Program Listings
1 *PRIMARY ROUTINES
2 *FOR SLOT 4
3 *
4 ORG $9000
5 * ;ADDRESSES
FOR FIRST
6522
6 ORB EQU $C400 ;PORT B
7 ORA EQU $C401 ;PORT A
8 DDRB EQU $C402 ;DATA DIRECTION
REGISTER (A)
9 DDRA EQU $C403 ;DATA DIRECTION
REGISTER (B)
10 * ;ADDRESSES
FOR SECOND
6522
11 ORB2 EQU $C480 ;PORT B
12 ORA2 EQU $C481 ;PORT A
13 DDRB2 EQU $C482 ;DATA DIRECTION
REGISTER (B)
14 DDRA2 EQU $C483 ;DATA DIRECTION
REGISTER (A)
1 *PRIMARY ROUTINES
2 *FOR SLOT 4
3 *
4 ORG $9000
5 * ;ADDRESSES
FOR FIRST
6522
6 ORB EQU $C400 ;PORT B
7 ORA EQU $C401 ;PORT A
8 DDRB EQU $C402 ;DATA DIRECTION
REGISTER (A)
9 DDRA EQU $C403 ;DATA DIRECTION
REGISTER (B)
10 * ;ADDRESSES
FOR SECOND
6522
11 ORB2 EQU $C480 ;PORT B
12 ORA2 EQU $C481 ;PORT A
13 DDRB2 EQU $C482 ;DATA DIRECTION
REGISTER (B)
14 DDRA2 EQU $C483 ;DATA DIRECTION
REGISTER (A)
*/
void WrMem(uint16 addr, uint8 b)
{

View File

@ -27,16 +27,37 @@
// freely available as well.
//
// JLH: Commented out MAME specific crap
// JLH: Removed MAME specific crap
#include <string.h> // for memset()
#include "ay8910.h"
#define MAX_OUTPUT 0x7FFF
///////////////////////////////////////////////////////////
// typedefs & dummy funcs to allow MAME code to compile:
//
//typedef UINT8 (*mem_read_handler)(UINT32);
//typedef void (*mem_write_handler)(UINT32, UINT8);
//
//static void logerror(char* psz, ...)
//{
//}
//
//static unsigned short activecpu_get_pc()
//{
// return 0;
//}
//
//
///////////////////////////////////////////////////////////
#define MAX_OUTPUT 0x7fff
// See AY8910_set_clock() for definition of STEP
#define STEP 0x8000
//This is not used at all...
//static int num = 0, ym_num = 0;
struct AY8910
{
int Channel;
@ -83,70 +104,60 @@ struct AY8910
static struct AY8910 AYPSG[MAX_8910]; /* array of PSG's */
void _AYWriteReg(int n, int r, int v)
{
struct AY8910 *PSG = &AYPSG[n];
int old;
PSG->Regs[r] = v;
/* A note about the period of tones, noise and envelope: for speed reasons, *
* we count down from the period to 0, but careful studies of the chip *
* output prove that it instead counts up from 0 until the counter becomes *
* greater or equal to the period. This is an important difference when the *
* program is rapidly changing the period to modulate the sound. *
* To compensate for the difference, when the period is changed we adjust *
* our internal counter. *
* Also, note that period = 0 is the same as period = 1. This is mentioned *
* in the YM2203 data sheets. However, this does NOT apply to the Envelope *
* period. In that case, period = 0 is half as period = 1. */
switch (r)
/* A note about the period of tones, noise and envelope: for speed reasons,*/
/* we count down from the period to 0, but careful studies of the chip */
/* output prove that it instead counts up from 0 until the counter becomes */
/* greater or equal to the period. This is an important difference when the*/
/* program is rapidly changing the period to modulate the sound. */
/* To compensate for the difference, when the period is changed we adjust */
/* our internal counter. */
/* Also, note that period = 0 is the same as period = 1. This is mentioned */
/* in the YM2203 data sheets. However, this does NOT apply to the Envelope */
/* period. In that case, period = 0 is half as period = 1. */
switch( r )
{
case AY_AFINE:
case AY_ACOARSE:
PSG->Regs[AY_ACOARSE] &= 0x0F;
PSG->Regs[AY_ACOARSE] &= 0x0f;
old = PSG->PeriodA;
PSG->PeriodA = (PSG->Regs[AY_AFINE] + 256 * PSG->Regs[AY_ACOARSE]) * PSG->UpdateStep;
if (PSG->PeriodA == 0) PSG->PeriodA = PSG->UpdateStep;
PSG->CountA += PSG->PeriodA - old;
if (PSG->CountA <= 0) PSG->CountA = 1;
break;
case AY_BFINE:
case AY_BCOARSE:
PSG->Regs[AY_BCOARSE] &= 0x0F;
PSG->Regs[AY_BCOARSE] &= 0x0f;
old = PSG->PeriodB;
PSG->PeriodB = (PSG->Regs[AY_BFINE] + 256 * PSG->Regs[AY_BCOARSE]) * PSG->UpdateStep;
if (PSG->PeriodB == 0) PSG->PeriodB = PSG->UpdateStep;
PSG->CountB += PSG->PeriodB - old;
if (PSG->CountB <= 0) PSG->CountB = 1;
break;
case AY_CFINE:
case AY_CCOARSE:
PSG->Regs[AY_CCOARSE] &= 0x0F;
PSG->Regs[AY_CCOARSE] &= 0x0f;
old = PSG->PeriodC;
PSG->PeriodC = (PSG->Regs[AY_CFINE] + 256 * PSG->Regs[AY_CCOARSE]) * PSG->UpdateStep;
if (PSG->PeriodC == 0) PSG->PeriodC = PSG->UpdateStep;
PSG->CountC += PSG->PeriodC - old;
if (PSG->CountC <= 0) PSG->CountC = 1;
break;
case AY_NOISEPER:
PSG->Regs[AY_NOISEPER] &= 0x1F;
PSG->Regs[AY_NOISEPER] &= 0x1f;
old = PSG->PeriodN;
PSG->PeriodN = PSG->Regs[AY_NOISEPER] * PSG->UpdateStep;
if (PSG->PeriodN == 0) PSG->PeriodN = PSG->UpdateStep;
PSG->CountN += PSG->PeriodN - old;
if (PSG->CountN <= 0) PSG->CountN = 1;
break;
case AY_ENABLE:
@ -169,17 +180,17 @@ void _AYWriteReg(int n, int r, int v)
PSG->lastEnable = PSG->Regs[AY_ENABLE];
break;
case AY_AVOL:
PSG->Regs[AY_AVOL] &= 0x1F;
PSG->Regs[AY_AVOL] &= 0x1f;
PSG->EnvelopeA = PSG->Regs[AY_AVOL] & 0x10;
PSG->VolA = PSG->EnvelopeA ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_AVOL] ? PSG->Regs[AY_AVOL]*2+1 : 0];
break;
case AY_BVOL:
PSG->Regs[AY_BVOL] &= 0x1F;
PSG->Regs[AY_BVOL] &= 0x1f;
PSG->EnvelopeB = PSG->Regs[AY_BVOL] & 0x10;
PSG->VolB = PSG->EnvelopeB ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_BVOL] ? PSG->Regs[AY_BVOL]*2+1 : 0];
break;
case AY_CVOL:
PSG->Regs[AY_CVOL] &= 0x1F;
PSG->Regs[AY_CVOL] &= 0x1f;
PSG->EnvelopeC = PSG->Regs[AY_CVOL] & 0x10;
PSG->VolC = PSG->EnvelopeC ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_CVOL] ? PSG->Regs[AY_CVOL]*2+1 : 0];
break;
@ -187,11 +198,8 @@ void _AYWriteReg(int n, int r, int v)
case AY_ECOARSE:
old = PSG->PeriodE;
PSG->PeriodE = ((PSG->Regs[AY_EFINE] + 256 * PSG->Regs[AY_ECOARSE])) * PSG->UpdateStep;
if (PSG->PeriodE == 0) PSG->PeriodE = PSG->UpdateStep / 2;
PSG->CountE += PSG->PeriodE - old;
if (PSG->CountE <= 0) PSG->CountE = 1;
break;
case AY_ESHAPE:
@ -221,9 +229,8 @@ void _AYWriteReg(int n, int r, int v)
has twice the steps, happening twice as fast. Since the end result is
just a smoother curve, we always use the YM2149 behaviour.
*/
PSG->Regs[AY_ESHAPE] &= 0x0F;
PSG->Attack = (PSG->Regs[AY_ESHAPE] & 0x04) ? 0x1F : 0x00;
PSG->Regs[AY_ESHAPE] &= 0x0f;
PSG->Attack = (PSG->Regs[AY_ESHAPE] & 0x04) ? 0x1f : 0x00;
if ((PSG->Regs[AY_ESHAPE] & 0x08) == 0)
{
/* if Continue = 0, map the shape to the equivalent one which has Continue = 1 */
@ -235,12 +242,10 @@ void _AYWriteReg(int n, int r, int v)
PSG->Hold = PSG->Regs[AY_ESHAPE] & 0x01;
PSG->Alternate = PSG->Regs[AY_ESHAPE] & 0x02;
}
PSG->CountE = PSG->PeriodE;
PSG->CountEnv = 0x1F;
PSG->CountEnv = 0x1f;
PSG->Holding = 0;
PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack];
if (PSG->EnvelopeA) PSG->VolA = PSG->VolE;
if (PSG->EnvelopeB) PSG->VolB = PSG->VolE;
if (PSG->EnvelopeC) PSG->VolC = PSG->VolE;
@ -279,74 +284,76 @@ void _AYWriteReg(int n, int r, int v)
// NB. This should be called at twice the 6522 IRQ rate or (eg) 60Hz if no IRQ.
void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static]
{
struct AY8910 * PSG = &AYPSG[chip];
INT16 * buf1, * buf2, * buf3;
struct AY8910 *PSG = &AYPSG[chip];
INT16 *buf1,*buf2,*buf3;
int outn;
buf1 = buffer[0];
buf2 = buffer[1];
buf3 = buffer[2];
/* The 8910 has three outputs, each output is the mix of one of the three *
* tone generators and of the (single) noise generator. The two are mixed *
* BEFORE going into the DAC. The formula to mix each channel is: *
* (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). *
* Note that this means that if both tone and noise are disabled, the output *
* is 1, not 0, and can be modulated changing the volume. *
* *
* If the channels are disabled, set their output to 1, and increase the *
* counter, if necessary, so they will not be inverted during this update. *
* Setting the output to 1 is necessary because a disabled channel is locked *
* into the ON state (see above); and it has no effect if the volume is 0. *
* If the volume is 0, increase the counter, but don't touch the output. */
/* The 8910 has three outputs, each output is the mix of one of the three */
/* tone generators and of the (single) noise generator. The two are mixed */
/* BEFORE going into the DAC. The formula to mix each channel is: */
/* (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). */
/* Note that this means that if both tone and noise are disabled, the output */
/* is 1, not 0, and can be modulated changing the volume. */
/* If the channels are disabled, set their output to 1, and increase the */
/* counter, if necessary, so they will not be inverted during this update. */
/* Setting the output to 1 is necessary because a disabled channel is locked */
/* into the ON state (see above); and it has no effect if the volume is 0. */
/* If the volume is 0, increase the counter, but don't touch the output. */
if (PSG->Regs[AY_ENABLE] & 0x01)
{
if (PSG->CountA <= length * STEP) PSG->CountA += length * STEP;
if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
PSG->OutputA = 1;
}
else if (PSG->Regs[AY_AVOL] == 0)
{
/* note that I do count += length, NOT count = length + 1. You might think *
* it's the same since the volume is 0, but doing the latter could cause *
* interferencies when the program is rapidly modulating the volume. */
if (PSG->CountA <= length * STEP) PSG->CountA += length * STEP;
/* note that I do count += length, NOT count = length + 1. You might think */
/* it's the same since the volume is 0, but doing the latter could cause */
/* interferencies when the program is rapidly modulating the volume. */
if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
}
if (PSG->Regs[AY_ENABLE] & 0x02)
{
if (PSG->CountB <= length * STEP) PSG->CountB += length * STEP;
if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
PSG->OutputB = 1;
}
else if (PSG->Regs[AY_BVOL] == 0)
{
if (PSG->CountB <= length * STEP) PSG->CountB += length * STEP;
if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
}
if (PSG->Regs[AY_ENABLE] & 0x04)
{
if (PSG->CountC <= length * STEP) PSG->CountC += length * STEP;
if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
PSG->OutputC = 1;
}
else if (PSG->Regs[AY_CVOL] == 0)
{
if (PSG->CountC <= length * STEP) PSG->CountC += length * STEP;
if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
}
/* for the noise channel we must not touch OutputN - it's also not necessary *
* since we use outn. */
/* for the noise channel we must not touch OutputN - it's also not necessary */
/* since we use outn. */
if ((PSG->Regs[AY_ENABLE] & 0x38) == 0x38) /* all off */
if (PSG->CountN <= length * STEP) PSG->CountN += length * STEP;
if (PSG->CountN <= length*STEP) PSG->CountN += length*STEP;
outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
/* buffering loop */
while (length)
{
int vola, volb, volc;
int vola,volb,volc;
int left;
/* vola, volb and volc keep track of how long each square wave stays *
* in the 1 position during the sample period. */
/* vola, volb and volc keep track of how long each square wave stays */
/* in the 1 position during the sample period. */
vola = volb = volc = 0;
left = STEP;
@ -354,38 +361,34 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static]
{
int nextevent;
if (PSG->CountN < left) nextevent = PSG->CountN;
else nextevent = left;
if (outn & 0x08)
{
if (PSG->OutputA) vola += PSG->CountA;
PSG->CountA -= nextevent;
/* PeriodA is the half period of the square wave. Here, in each *
* loop I add PeriodA twice, so that at the end of the loop the *
* square wave is in the same status (0 or 1) it was at the start. *
* vola is also incremented by PeriodA, since the wave has been 1 *
* exactly half of the time, regardless of the initial position. *
* If we exit the loop in the middle, OutputA has to be inverted *
* and vola incremented only if the exit status of the square *
* wave is 1. */
/* PeriodA is the half period of the square wave. Here, in each */
/* loop I add PeriodA twice, so that at the end of the loop the */
/* square wave is in the same status (0 or 1) it was at the start. */
/* vola is also incremented by PeriodA, since the wave has been 1 */
/* exactly half of the time, regardless of the initial position. */
/* If we exit the loop in the middle, OutputA has to be inverted */
/* and vola incremented only if the exit status of the square */
/* wave is 1. */
while (PSG->CountA <= 0)
{
PSG->CountA += PSG->PeriodA;
if (PSG->CountA > 0)
{
PSG->OutputA ^= 1;
if (PSG->OutputA) vola += PSG->PeriodA;
break;
}
PSG->CountA += PSG->PeriodA;
vola += PSG->PeriodA;
}
if (PSG->OutputA) vola -= PSG->CountA;
}
else
@ -394,13 +397,11 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static]
while (PSG->CountA <= 0)
{
PSG->CountA += PSG->PeriodA;
if (PSG->CountA > 0)
{
PSG->OutputA ^= 1;
break;
}
PSG->CountA += PSG->PeriodA;
}
}
@ -408,41 +409,32 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static]
if (outn & 0x10)
{
if (PSG->OutputB) volb += PSG->CountB;
PSG->CountB -= nextevent;
while (PSG->CountB <= 0)
{
PSG->CountB += PSG->PeriodB;
if (PSG->CountB > 0)
{
PSG->OutputB ^= 1;
if (PSG->OutputB) volb += PSG->PeriodB;
break;
}
PSG->CountB += PSG->PeriodB;
volb += PSG->PeriodB;
}
if (PSG->OutputB) volb -= PSG->CountB;
}
else
{
PSG->CountB -= nextevent;
while (PSG->CountB <= 0)
{
PSG->CountB += PSG->PeriodB;
if (PSG->CountB > 0)
{
PSG->OutputB ^= 1;
break;
}
PSG->CountB += PSG->PeriodB;
}
}
@ -450,90 +442,74 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static]
if (outn & 0x20)
{
if (PSG->OutputC) volc += PSG->CountC;
PSG->CountC -= nextevent;
while (PSG->CountC <= 0)
{
PSG->CountC += PSG->PeriodC;
if (PSG->CountC > 0)
{
PSG->OutputC ^= 1;
if (PSG->OutputC) volc += PSG->PeriodC;
break;
}
PSG->CountC += PSG->PeriodC;
volc += PSG->PeriodC;
}
if (PSG->OutputC) volc -= PSG->CountC;
}
else
{
PSG->CountC -= nextevent;
while (PSG->CountC <= 0)
{
PSG->CountC += PSG->PeriodC;
if (PSG->CountC > 0)
{
PSG->OutputC ^= 1;
break;
}
PSG->CountC += PSG->PeriodC;
}
}
PSG->CountN -= nextevent;
if (PSG->CountN <= 0)
{
/* Is noise output going to change? */
if ((PSG->RNG + 1) & 0x00002) /* (bit0^bit1)? */
if ((PSG->RNG + 1) & 2) /* (bit0^bit1)? */
{
PSG->OutputN = ~PSG->OutputN;
outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
}
/* The Random Number Generator of the 8910 is a 17-bit shift *
* register. The input to the shift register is bit0 XOR bit3 *
* (bit0 is the output). This was verified on AY-3-8910 and *
* YM2149 chips. *
* *
* The following is a fast way to compute bit17 = bit0^bit3. *
* Instead of doing all the logic operations, we only check *
* bit0, relying on the fact that after three shifts of the *
* register, what now is bit3 will become bit0, and will *
* invert, if necessary, bit14, which previously was bit17. */
if (PSG->RNG & 0x00001)
PSG->RNG ^= 0x24000; /* This version is called the "Galois configuration". */
/* The Random Number Generator of the 8910 is a 17-bit shift */
/* register. The input to the shift register is bit0 XOR bit3 */
/* (bit0 is the output). This was verified on AY-3-8910 and YM2149 chips. */
/* The following is a fast way to compute bit17 = bit0^bit3. */
/* Instead of doing all the logic operations, we only check */
/* bit0, relying on the fact that after three shifts of the */
/* register, what now is bit3 will become bit0, and will */
/* invert, if necessary, bit14, which previously was bit17. */
if (PSG->RNG & 1) PSG->RNG ^= 0x24000; /* This version is called the "Galois configuration". */
PSG->RNG >>= 1;
PSG->CountN += PSG->PeriodN;
}
left -= nextevent;
}
while (left > 0);
} while (left > 0);
/* update envelope */
if (PSG->Holding == 0)
{
PSG->CountE -= STEP;
if (PSG->CountE <= 0)
{
do
{
PSG->CountEnv--;
PSG->CountE += PSG->PeriodE;
}
while (PSG->CountE <= 0);
} while (PSG->CountE <= 0);
/* check envelope current position */
if (PSG->CountEnv < 0)
@ -541,19 +517,18 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static]
if (PSG->Hold)
{
if (PSG->Alternate)
PSG->Attack ^= 0x1F;
PSG->Attack ^= 0x1f;
PSG->Holding = 1;
PSG->CountEnv = 0;
}
else
{
/* if CountEnv has looped an odd number of times (usually 1), *
* invert the output. */
/* if CountEnv has looped an odd number of times (usually 1), */
/* invert the output. */
if (PSG->Alternate && (PSG->CountEnv & 0x20))
PSG->Attack ^= 0x1F;
PSG->Attack ^= 0x1f;
PSG->CountEnv &= 0x1F;
PSG->CountEnv &= 0x1f;
}
}
@ -569,77 +544,90 @@ void AY8910Update(int chip, int16 ** buffer, int length) // [TC: Removed static]
*(buf1++) = (vola * PSG->VolA) / STEP;
*(buf2++) = (volb * PSG->VolB) / STEP;
*(buf3++) = (volc * PSG->VolC) / STEP;
#else // [Tom's code...]
#else
// Output PCM wave [-32768...32767] instead of MAME's voltage level [0...32767]
// - This allows for better s/w mixing
if (PSG->VolA)
if(PSG->VolA)
{
if (vola)
if(vola)
*(buf1++) = (vola * PSG->VolA) / STEP;
else
*(buf1++) = -(int)PSG->VolA;
*(buf1++) = - (int) PSG->VolA;
}
else
*(buf1++) = 0;
if (PSG->VolB)
{
if (volb)
*(buf1++) = 0;
}
//
if(PSG->VolB)
{
if(volb)
*(buf2++) = (volb * PSG->VolB) / STEP;
else
*(buf2++) = -(int)PSG->VolB;
*(buf2++) = - (int) PSG->VolB;
}
else
*(buf2++) = 0;
if (PSG->VolC)
{
if (volc)
*(buf2++) = 0;
}
//
if(PSG->VolC)
{
if(volc)
*(buf3++) = (volc * PSG->VolC) / STEP;
else
*(buf3++) = -(int)PSG->VolC;
*(buf3++) = - (int) PSG->VolC;
}
else
{
*(buf3++) = 0;
}
#endif
length--;
}
}
static void AY8910_set_clock(int chip, int clock)
static void AY8910_set_clock(int chip,int clock)
{
struct AY8910 * PSG = &AYPSG[chip];
struct AY8910 *PSG = &AYPSG[chip];
/* The step clock for the tone and noise generators is the chip clock *
* divided by 8; for the envelope generator of the AY-3-8910, it is half *
* that much (clock/16), but the envelope of the YM2149 goes twice as *
* fast, therefore again clock/8. *
* Here we calculate the number of steps which happen during one sample *
* at the given sample rate. No. of events = sample rate / (clock/8). *
* STEP is a multiplier used to turn the fraction into a fixed point *
* number. */
PSG->UpdateStep = (unsigned int)(((double)STEP * PSG->SampleRate * 8 + clock / 2) / clock); // [TC: unsigned int cast]
/* the step clock for the tone and noise generators is the chip clock */
/* divided by 8; for the envelope generator of the AY-3-8910, it is half */
/* that much (clock/16), but the envelope of the YM2149 goes twice as */
/* fast, therefore again clock/8. */
/* Here we calculate the number of steps which happen during one sample */
/* at the given sample rate. No. of events = sample rate / (clock/8). */
/* STEP is a multiplier used to turn the fraction into a fixed point */
/* number. */
PSG->UpdateStep = (unsigned int) (((double)STEP * PSG->SampleRate * 8 + clock/2) / clock); // [TC: unsigned int cast]
}
static void build_mixer_table(int chip)
{
struct AY8910 * PSG = &AYPSG[chip];
struct AY8910 *PSG = &AYPSG[chip];
int i;
double out;
/* calculate the volume->voltage conversion table */
/* calculate the volume->voltage conversion table */
/* The AY-3-8910 has 16 levels, in a logarithmic scale (3dB per step) */
/* The YM2149 still has 16 levels for the tone generators, but 32 for */
/* the envelope generator (1.5dB per step). */
double out = MAX_OUTPUT;
for(int i=31; i>0; i--)
/* the envelope generator (1.5dB per step). */
out = MAX_OUTPUT;
for (i = 31;i > 0;i--)
{
PSG->VolTable[i] = (unsigned int)(out + 0.5); /* round to nearest */ // [TC: unsigned int cast]
PSG->VolTable[i] = (unsigned int) (out + 0.5); /* round to nearest */ // [TC: unsigned int cast]
out /= 1.188502227; /* = 10 ^ (1.5/20) = 1.5dB */
}
PSG->VolTable[0] = 0;
}
@ -647,48 +635,59 @@ static void build_mixer_table(int chip)
void AY8910_reset(int chip)
{
int i;
struct AY8910 * PSG = &AYPSG[chip];
struct AY8910 *PSG = &AYPSG[chip];
PSG->register_latch = 0;
PSG->RNG = 1;
PSG->OutputA = 0;
PSG->OutputB = 0;
PSG->OutputC = 0;
PSG->OutputN = 0xFF;
PSG->OutputN = 0xff;
PSG->lastEnable = -1; /* force a write */
for(i=0; i<AY_PORTA; i++)
_AYWriteReg(chip, i, 0); /* AYWriteReg() uses the timer system; we cannot */
/* call it at this time because the timer system */
/* has not been initialized. */
for (i = 0;i < AY_PORTA;i++)
_AYWriteReg(chip,i,0); /* AYWriteReg() uses the timer system; we cannot */
/* call it at this time because the timer system */
/* has not been initialized. */
}
// This stuff looks like Tom's code, so let's streamline and un-MSHungarianize this shit:
// [DONE]
//-------------------------------------
void AY8910_InitAll(int clock, int sampleRate)
void AY8910_InitAll(int nClock, int nSampleRate)
{
for(int chip=0; chip<MAX_8910; chip++)
for(int nChip=0; nChip<MAX_8910; nChip++)
{
struct AY8910 * PSG = &AYPSG[chip];
struct AY8910 *PSG = &AYPSG[nChip];
memset(PSG, 0, sizeof(struct AY8910));
PSG->SampleRate = sampleRate;
AY8910_set_clock(chip, clock);
build_mixer_table(chip);
memset(PSG,0,sizeof(struct AY8910));
PSG->SampleRate = nSampleRate;
// PSG->PortAread = NULL;
// PSG->PortBread = NULL;
// PSG->PortAwrite = NULL;
// PSG->PortBwrite = NULL;
AY8910_set_clock(nChip, nClock);
build_mixer_table(nChip);
}
}
void AY8910_InitClock(int clock)
//-------------------------------------
void AY8910_InitClock(int nClock)
{
for(int chip=0; chip<MAX_8910; chip++)
AY8910_set_clock(chip, clock);
for(int nChip=0; nChip<MAX_8910; nChip++)
{
AY8910_set_clock(nChip, nClock);
}
}
uint8 * AY8910_GetRegsPtr(uint16 chipNum)
//-------------------------------------
uint8 * AY8910_GetRegsPtr(uint16 nAyNum)
{
if (chipNum >= MAX_8910)
if(nAyNum >= MAX_8910)
return NULL;
return &AYPSG[chipNum].Regs[0];
return &AYPSG[nAyNum].Regs[0];
}

View File

@ -26,6 +26,8 @@
#define MASK_A 0xFF000000
#endif
using namespace std; // For STL stuff
//
// Button class implementation
//
@ -33,7 +35,7 @@
/*
Some notes about this class:
- Button colors are hardwired (for plain text buttons)
- Button colors are hardwired
*/
Button::Button(uint32 x/*= 0*/, uint32 y/*= 0*/, uint32 w/*= 0*/, uint32 h/*= 0*/,
@ -76,7 +78,7 @@ Button::Button(uint32 x, uint32 y, SDL_Surface * bU, SDL_Surface * bH/*= NULL*/,
extents.h = buttonUp->h;
}
Button::Button(uint32 x, uint32 y, uint32 w, uint32 h, std::string s, Element * parent/*= NULL*/):
Button::Button(uint32 x, uint32 y, uint32 w, uint32 h, string s, Element * parent/*= NULL*/):
Element(x, y, w, h, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, parent),
activated(false), clicked(false), inside(false),
buttonUp(NULL), buttonDown(NULL), buttonHover(NULL), surfacesAreLocal(true),
@ -85,7 +87,7 @@ Button::Button(uint32 x, uint32 y, uint32 w, uint32 h, std::string s, Element *
// Create the button surfaces here...
}
Button::Button(uint32 x, uint32 y, std::string s, Element * parent/*= NULL*/):
Button::Button(uint32 x, uint32 y, string s, Element * parent/*= NULL*/):
Element(x, y, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, parent),
activated(false), clicked(false), inside(false),
buttonUp(NULL), buttonDown(NULL), buttonHover(NULL), surfacesAreLocal(true),
@ -168,6 +170,8 @@ void Button::Draw(void)
if (buttonUp == NULL)
return; // Bail out if no surface was created...
SDL_Rect rect = GetScreenCoords();
// Now, draw the appropriate button state!
SDL_Surface * picToShow = buttonUp;
@ -178,10 +182,6 @@ void Button::Draw(void)
if (buttonDown != NULL && inside && clicked)
picToShow = buttonDown;
SDL_Rect rect = GetScreenCoords();
//Need to do coverage list blitting here, to avoid unnecessary drawing when doing mouseovers
//Also, need to add suport in Gui()...
SDL_BlitSurface(picToShow, NULL, screen, &rect); // This handles alpha blending too! :-D
needToRefreshScreen = true;

View File

@ -8,7 +8,6 @@
#define __BUTTON_H__
#include <string>
//#include <list>
#include "element.h"
//Apparently this approach doesn't work for inheritance... D'oh!

View File

@ -32,8 +32,9 @@
#define MASK_A 0xFF000000
#endif
using namespace std; // For STL stuff
#define BACKGROUND_IMG_TEST
//#define USE_COVERAGE_LISTS
//
// DraggableWindow class implementation
@ -141,16 +142,6 @@ void DraggableWindow::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
void DraggableWindow::Draw(void)
{
#ifdef USE_COVERAGE_LISTS
// These are *always* top level and parentless, so no need to traverse up through
// the parent chain...
for(std::list<SDL_Rect>::iterator i=coverList.begin(); i!=coverList.end(); i++)
SDL_FillRect(screen, &(*i), bgColor);
// Handle the items this window contains...
for(uint32 i=0; i<list.size(); i++)
list[i]->Draw();
#else
// These are *always* top level and parentless, so no need to traverse up through
// the parent chain...
//Perhaps we can make these parentable, put the parent traversal in the base class?
@ -176,7 +167,6 @@ void DraggableWindow::Draw(void)
// Handle the items this window contains...
for(uint32 i=0; i<list.size(); i++)
list[i]->Draw();
#endif
//Prolly don't need this since the close button will do this for us...
needToRefreshScreen = true;

View File

@ -15,7 +15,6 @@
//
#include "element.h"
#include "guimisc.h" // Various support functions
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define MASK_R 0xFF000000
@ -47,7 +46,6 @@ Element::Element(uint32 x/*= 0*/, uint32 y/*= 0*/, uint32 w/*= 0*/, uint32 h/*=
extents.y = y,
extents.w = w,
extents.h = h;
coverList.push_back(extents);
}
Element::Element(uint32 x, uint32 y, uint32 w, uint32 h,
@ -59,7 +57,6 @@ Element::Element(uint32 x, uint32 y, uint32 w, uint32 h,
extents.y = y,
extents.w = w,
extents.h = h;
coverList.push_back(extents);
// This *should* allow us to store our colors in an endian safe way... :-/
uint8 * c = (uint8 *)&fgColor;
@ -84,7 +81,7 @@ bool Element::Inside(uint32 x, uint32 y)
&& y >= (uint32)extents.y && y < (uint32)(extents.y + extents.h) ? true : false);
}
//Badly named--!!! FIX !!! [DONE]
//Badly named--!!! FIX !!!
//SDL_Rect Element::GetParentCorner(void)
SDL_Rect Element::GetScreenCoords(void)
{
@ -105,7 +102,7 @@ SDL_Rect Element::GetScreenCoords(void)
return rect;
}
#if 1
#if 0
//May use this in the future...
SDL_Rect Element::GetParentRect(void)
{
@ -127,11 +124,6 @@ SDL_Rect Element::GetParentRect(void)
}
#endif
SDL_Rect Element::GetExtents(void)
{
return extents;
}
void Element::CreateBackstore(void)
{
backstore = SDL_CreateRGBSurface(SDL_SWSURFACE, extents.w, extents.h, 32,
@ -148,145 +140,6 @@ void Element::RestoreScreenFromBackstore(void)
SDL_BlitSurface(backstore, NULL, screen, &r);
}
void Element::SaveScreenToBackstore(void)
{
SDL_BlitSurface(screen, &extents, backstore, NULL);
}
void Element::ResetCoverageList(void)
{
// Setup our coverage list with the entire window area
coverList.empty();
coverList.push_back(extents);
}
void Element::AdjustCoverageList(SDL_Rect r)
{
//Prolly should have a bool here to set whether or not to do this crap, since it
//takes a little time...
// Here's where we do the coverage list voodoo... :-)
/*
Steps:
o Check for intersection. If no intersection, then no need to divide rects.
o Loop through current rects. If rect is completely inside passed in rect, remove from list.
o Loop through remaining rects. If rect intersects, decompose to four rects and
exclude degenerate rects, push rest into the coverage list.
*/
// std::list<Element *>::reverse_iterator ri;
// std::list<SDL_Rect>::iterator i;
// Loop through rects and remove those completely covered by passed in rect.
/* for(i=coverList.begin(); i!=coverList.end(); i++)
{
// if (RectanglesIntersect(r, *i))
if (RectangleFirstInsideSecond(*i, r))
{
//This is not right--do a while loop instead of a for loop?
// Remove it from the list...
std::list<SDL_Rect>::iterator next = coverList.erase(i);
}
}
*/
// Loop through rects and remove those completely covered by passed in rect.
std::list<SDL_Rect>::iterator i = coverList.begin();
while (i != coverList.end())
{
if (RectangleFirstInsideSecond(*i, r))
i = coverList.erase(i); // This will also advance i to the next item!
else
i++;
}
//This may not be needed if nothing follows the loop below...!
// if (coverList.empty())
// return;
// Check for intersection. If no intersection, then no need to divide rects.
i = coverList.begin();
while (i != coverList.end())
{
if (RectanglesIntersect(r, *i))
{
// Do the decomposition here. There will always be at least *one* rectangle
// generated by this algorithm, so we know we're OK in removing the original
// from the list. The general pattern looks like this:
//
// +------+
// |1 |
// +-+--+-+
// |2|//|3| <- Rectangle "r" is in the center
// +-+--+-+
// |4 |
// +------+
//
// Even if r extends beyond the bounds of the rectangle under consideration,
// that's OK because we test to see that the rectangle isn't degenerate
// before adding it to the list.
//Should probably use a separate list here and splice it in when we're done here...
//Or, could use push_front() to avoid the problem... Neat! Doesn't require a separate list!
//But, we need to remove the currently referenced rect... Another while loop!
//This approach won't work--if no rect1 then we're screwed! [FIXED]
//Now *that* will work...
SDL_Rect current = *i;
uint32 bottomOfRect1 = current.y;
// uint32 rightOfRect2 = current.x;
// uint32 leftOfRect3 = current.x + current.w;
uint32 topOfRect4 = current.y + current.h;
// Rectangle #1 (top)
if (r.y > current.y) // Simple rectangle degeneracy test...
{
bottomOfRect1 = r.y;
SDL_Rect rect = current;
rect.h = r.y - current.y;
coverList.push_front(rect);
}
// Rectangle #4 (bottom)
if (r.y + r.h < current.y + current.h)
{
topOfRect4 = r.y + r.h;
SDL_Rect rect = current;
rect.y = r.y + r.h;
rect.h = (current.y + current.h) - (r.y + r.h);
coverList.push_front(rect);
}
// Rectangle #2 (left side)
if (r.x > current.x)
{
SDL_Rect rect = current;
rect.w = r.x - current.x;
rect.y = bottomOfRect1;
rect.h = topOfRect4 - bottomOfRect1;
coverList.push_front(rect);
}
// Rectangle #3 (right side)
if (r.x + r.w < current.x + current.w)
{
SDL_Rect rect;
rect.x = r.x + r.w;
rect.w = (current.x + current.w) - (r.x + r.w);
rect.y = bottomOfRect1;
rect.h = topOfRect4 - bottomOfRect1;
coverList.push_front(rect);
}
i = coverList.erase(i); // This will also advance i to the next item!
}
else
i++;
}
}
//
// Class methods
//

View File

@ -13,7 +13,6 @@
enum { WINDOW_CLOSE, MENU_ITEM_CHOSEN, SCREEN_REFRESH_NEEDED };
#include <SDL.h>
#include <list>
#include "types.h"
class Element
@ -35,17 +34,12 @@ class Element
//Badly named, though we may code something that does this...
// SDL_Rect GetParentCorner(void);
SDL_Rect GetScreenCoords(void);
SDL_Rect GetExtents(void);
#if 1
#if 0
//May use this in the future...
SDL_Rect GetParentRect(void);
#endif
void CreateBackstore(void);
void RestoreScreenFromBackstore(void);
void SaveScreenToBackstore(void);
void ResetCoverageList(void);
//Need something to prevent this on Elements that don't have mouseover effects...
void AdjustCoverageList(SDL_Rect r);
// Class methods...
static void SetScreen(SDL_Surface *);
static bool ScreenNeedsRefreshing(void);
@ -58,7 +52,6 @@ class Element
uint32 fgColor;
uint32 bgColor;
SDL_Surface * backstore;
std::list<SDL_Rect> coverList;
// Class variables...
static SDL_Surface * screen;

View File

@ -10,12 +10,12 @@
// --- ---------- ------------------------------------------------------------
// JLH 02/03/2006 Created this file
// JLH 03/13/2006 Added functions to allow shutting down GUI externally
// JLH 03/22/2006 Finalized basic multiple window support
//
// STILL TO DO:
// STILL TO FIX:
//
// - Memory leak on quitting with a window active [DONE]
// - Multiple window handling [DONE]
// - Memory leak on quitting with a window active
// - Multiple window handling
//
#include "gui.h"
@ -27,29 +27,23 @@
//#define DEBUG_MAIN_LOOP
//#ifdef DEBUG_MAIN_LOOP
#ifdef DEBUG_MAIN_LOOP
#include "log.h"
//#endif
#endif
GUI::GUI(SDL_Surface * mainSurface): menuItem(new MenuItems())
GUI::GUI(SDL_Surface * mainSurface): mainMenu(new Menu()), menuItem(new MenuItems())
{
windowList.push_back(new Menu());
Element::SetScreen(mainSurface);
}
GUI::~GUI()
{
// Clean up menuItem, if any
if (mainMenu)
delete mainMenu;
if (menuItem)
delete menuItem;
// Clean up the rest
for(std::list<Element *>::iterator i=windowList.begin(); i!=windowList.end(); i++)
if (*i)
delete *i;
}
void GUI::AddMenuTitle(const char * title)
@ -65,32 +59,25 @@ void GUI::AddMenuItem(const char * item, Element * (* a)(void)/*= NULL*/, SDLKey
void GUI::CommitItemsToMenu(void)
{
//We could just do a simple check here to see if more than one item is in the list,
//and if so fail. Make it so you build the menu first before allowing any other action. [DONE]
//Right now, we just silently fail...
if (windowList.size() > 1)
{
WriteLog("GUI: Can't find menu--more than one item in windowList!\n");
return;
}
((Menu *)(*windowList.begin()))->Add(*menuItem);
mainMenu->Add(*menuItem);
}
void GUI::Run(void)
{
exitGUI = false;
showMouse = true;
bool showMouse = true;
int mouseX = 0, mouseY = 0;
int oldMouseX = 0, oldMouseY = 0;
Element * mainWindow = NULL;
SDL_Event event;
std::list<Element *>::iterator i;
SDL_EnableKeyRepeat(150, 75);
// Initial update... [Now handled correctly in the constructor]
for(i=windowList.begin(); i!=windowList.end(); i++)
(*i)->Draw();
// Initial update...
//Shouldn't we save the state of the GUI instead of doing things this way?
//We have a memory leak whenever a mainWindow is active and we quit... !!! FIX !!!
mainMenu->Draw();
RenderScreenBuffer();
// Main loop
@ -109,47 +96,35 @@ WriteLog(" -- SDL_USEREVENT\n");
//Mebbe add another user event for screen refresh? Why not!
if (event.user.code == WINDOW_CLOSE)
{
for(i=windowList.begin(); i!=windowList.end(); i++)
{
if (*i == (Element *)event.user.data1)
{
delete *i;
windowList.erase(i);
break;
}
}
delete mainWindow;
mainWindow = NULL;
}
else if (event.user.code == MENU_ITEM_CHOSEN)
{
// Confused? Let me enlighten... What we're doing here is casting
// data1 as a pointer to a function which returns a Element pointer and
// which takes no parameters (the "(Element *(*)(void))" part), then
// data1 as a pointer to a function which returns a Window pointer and
// which takes no parameters (the "(Window *(*)(void))" part), then
// derefencing it (the "*" in front of that) in order to call the
// function that it points to. Clear as mud? Yeah, I hate function
// pointers too, but what else are you gonna do?
Element * window = (*(Element *(*)(void))event.user.data1)();
if (window)
windowList.push_back(window);
mainWindow = (*(Element *(*)(void))event.user.data1)();
while (SDL_PollEvent(&event)); // Flush the event queue...
event.type = SDL_MOUSEMOTION;
int mx, my;
SDL_GetMouseState(&mx, &my);
event.motion.x = mx, event.motion.y = my;
SDL_PushEvent(&event); // & update mouse position...!
oldMouse.x = mouse.x, oldMouse.y = mouse.y;
mouse.x = mx, mouse.y = my; // This prevents "mouse flash"...
oldMouseX = mouseX, oldMouseY = mouseY;
mouseX = mx, mouseY = my; // This prevents "mouse flash"...
}
//There's a *small* problem with the following approach--if a window and a bunch of
//child widgets send this message, we'll get a bunch of unnecessary refresh events...
//There's a *small* problem with this approach--if a window and a bunch of child
//widgets send this message, we'll get a bunch of unnecessary refresh events...
//This could be controlled by having the main window refresh itself intelligently...
//What we could do instead is set a variable in Element and check it after the fact
//to see whether or not a refresh is needed.
//[This is what we do now.]
//Dirty rectangle is also possible...
else if (event.user.code == SCREEN_REFRESH_NEEDED)
@ -157,235 +132,58 @@ WriteLog(" -- SDL_USEREVENT\n");
}
else if (event.type == SDL_ACTIVEEVENT)
{
//Need to do a screen refresh here...
if (event.active.state == SDL_APPMOUSEFOCUS)
showMouse = (event.active.gain ? true : false);
RenderScreenBuffer();
}
else if (event.type == SDL_KEYDOWN)
{
#ifdef DEBUG_MAIN_LOOP
WriteLog(" -- SDL_KEYDOWN\n");
#endif
if (event.key.keysym.sym == SDLK_F1)
if (event.key.keysym.sym == SDLK_F5)
exitGUI = true;
//Not sure that this is the right way to handle this...
//Probably should only give this to the top level window...
// for(i=windowList.begin(); i!=windowList.end(); i++)
// (*i)->HandleKey(event.key.keysym.sym);
windowList.back()->HandleKey(event.key.keysym.sym);
if (mainWindow)
mainWindow->HandleKey(event.key.keysym.sym);
else
mainMenu->HandleKey(event.key.keysym.sym);
}
else if (event.type == SDL_MOUSEMOTION)
{
#ifdef DEBUG_MAIN_LOOP
WriteLog(" -- SDL_MOUSEMOTION\n");
#endif
//This is for tracking a custom mouse cursor, which we're not doing--YET.
oldMouse.x = mouse.x, oldMouse.y = mouse.y;
mouse.x = event.motion.x, mouse.y = event.motion.y;
oldMouseX = mouseX, oldMouseY = mouseY;
mouseX = event.motion.x, mouseY = event.motion.y;
//Not sure that this is the right way to handle this...
//Right now, we should probably only do mouseover for the last item in the list...
//And now we do!
//Though, it seems to screw other things up. Maybe it IS better to pass it to all windows?
//Or maybe to just the ones that aren't completely obscured?
//Probably. Right now, a disk's close button that should be obscured by one sitting on
//top of it gets redrawn. Not good.
for(i=windowList.begin(); i!=windowList.end(); i++)
(*i)->HandleMouseMove(mouse.x, mouse.y);
// windowList.back()->HandleMouseMove(mouse.x, mouse.y);
if (mainWindow)
mainWindow->HandleMouseMove(mouseX, mouseY);
else
mainMenu->HandleMouseMove(mouseX, mouseY);
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
#ifdef DEBUG_MAIN_LOOP
WriteLog(" -- SDL_MOUSEBUTTONDOWN\n");
WriteLog(" -- SDL_MOSEBUTTONDOWN\n");
#endif
//Not sure that this is the right way to handle this...
// What we should do here is ensure that whatever has been clicked on gets moved to the
// highest priority--in our current data schema that would be the end of the list... !!! FIX !!!
//[DONE]
uint32 mx = event.button.x, my = event.button.y;
/*
We could do the following:
- Go through list and find which window has been clicked on (if any). If more
than one is clicked on, take the one highest in the Z order (closer to the end
of the list).
- If item is highest in Z order, pack click through to window and exit.
- Otherwise, restore backing store on each window in reverse order.
- Remove item clicked on from the list. Put removed item at the end of the list.
- Go through list and pass click through to each window in the list. Also do a
blit to backing store and a Draw() for each window.
Could also do a check (if not clicked on highest Z window) to see which windows
it overlaps and just do restore/redraw for those that overlap. To wit:
- Create new list containing only those windows that overlap the clicking on window.
- Go through list and do a blit to backing store and a Draw() for each window.
- Go through list and pass click through to each window in the list.
*/
#if 0
#if 0
for(i=windowList.begin(); i!=windowList.end(); i++)
(*i)->HandleMouseButton(event.button.x, event.button.y, true);
#else
// We use the 1st algorithm here, since it's simpler. If we need to, we can optimize
// to the 2nd...
// Walk backward through the list and see if a window was hit.
// This will automagically return us the window with the highest Z.
std::list<Element *>::reverse_iterator ri;
std::list<Element *>::iterator hit;// = windowList.end();
for(ri=windowList.rbegin(); ri!=windowList.rend(); ri++)
{
if ((*ri)->Inside(event.button.x, event.button.y))
{
// Here's a bit of STL weirdness: Converting from a reverse
// iterator to a regular iterator requires backing the iterator
// up a position after grabbing it's base() OR going forward
// one position with the reverse iterator before grabbing base().
// Ugly, but it get the job done...
hit = (++ri).base();
// Put it back where we found it, so the tests following this
// don't fail...
ri--;
break;
}
}
// If we hit the highest in the list, then pass the event through
// to the window for handling. if we hit no windows, then pass the
// event to all windows. Otherwise, we need to shuffle windows.
//NOTE: We need to pass the click to all windows regardless of whether they're topmost or not...
if (ri == windowList.rbegin())
{
for(i=windowList.begin(); i!=windowList.end(); i++)
(*i)->HandleMouseButton(event.button.x, event.button.y, true);
}
else if (ri == windowList.rend())
{
for(i=windowList.begin(); i!=windowList.end(); i++)
(*i)->HandleMouseButton(event.button.x, event.button.y, true);
}
if (mainWindow)
mainWindow->HandleMouseButton(mx, my, true);
else
{
// - Otherwise, restore backing store on each window in reverse order.
for(ri=windowList.rbegin(); ri!=windowList.rend(); ri++)
(*ri)->RestoreScreenFromBackstore();
// At this point, the screen has been restored...
// - Remove item clicked on from the list. Put removed item at the end of the list.
windowList.push_back(*hit);
windowList.erase(hit);
// - Go through list and pass click through to each window in the list. Also do a
// blit to backing store and a Draw() for each window.
for(i=windowList.begin(); i!= windowList.end(); i++)
{
// Grab bg into backstore
(*i)->SaveScreenToBackstore();
// Pass click
(*i)->HandleMouseButton(event.button.x, event.button.y, true);
// Draw?
(*i)->Draw();
}
}
#endif
#endif
/*
A slightly different way to handle this would be to loop through all windows, compare
all those above it to see if they obscure it; if so then subdivide it's update rectangle
to eliminate drawing the parts that aren't shown. The beauty of this approach is that
you don't have to care what order the windows are drawn in and you don't need to worry
about the order of restoring the backing store.
You *do* still need to determine the Z-order of the windows, in order to get the subdivisions
correct, but that's not too terrible.
Also, when doing a window drag, the coverage lists for all windows have to be regenerated.
*/
std::list<Element *>::reverse_iterator ri;
bool movedWindow = false;
for(ri=windowList.rbegin(); ri!=windowList.rend(); ri++)
{
if ((*ri)->Inside(event.button.x, event.button.y))
{
// Remove item clicked on from the list & put removed item at the
// end of the list, thus putting the window at the top of the Z
// order. But IFF window is not already topmost!
if (ri != windowList.rbegin())
{
windowList.push_back(*ri);
// Here's a bit of STL weirdness: Converting from a reverse
// iterator to a regular iterator requires backing the iterator
// up a position after grabbing it's base() OR going forward
// one position with the reverse iterator before grabbing base().
// Ugly, but it get the job done...
windowList.erase((++ri).base());
movedWindow = true;
}
break;
}
}
//Small problem here: we should only pass the *hit* to the topmost window and pass
//*misses* to everyone else... Otherwise, you can have overlapping draggable windows
//and be able to drag both by clicking on a point that intersects both...
//(though that may be an interesting way to handle things!)
// Pass the click on to all windows
for(i=windowList.begin(); i!=windowList.end(); i++)
(*i)->HandleMouseButton(event.button.x, event.button.y, true);
// // & bail if nothing changed...
if (movedWindow)
// return;
{
// Check for overlap/build coverage lists [O((n^2)/2) algorithm!]
//One way to optimize this would be to only reset coverage lists from the point in
//the Z order where the previous window was.
for(i=windowList.begin(); i!=windowList.end(); i++)
{
(*i)->ResetCoverageList();
// This looks odd, but it's just a consequence of iterator weirdness.
// Otherwise we could just stick a j+1 in the for loop below. :-P
std::list<Element *>::iterator j = i;
j++;
for(; j!=windowList.end(); j++)
(*i)->AdjustCoverageList((*j)->GetExtents());
// (*i)->HandleMouseButton(event.button.x, event.button.y, true);
(*i)->Draw();
}
}
mainMenu->HandleMouseButton(mx, my, true);
}
else if (event.type == SDL_MOUSEBUTTONUP)
{
#ifdef DEBUG_MAIN_LOOP
WriteLog(" -- SDL_MOUSEBUTTONUP\n");
#endif
//Not sure that this is the right way to handle this...
for(i=windowList.begin(); i!=windowList.end(); i++)
(*i)->HandleMouseButton(event.button.x, event.button.y, false);
//I think we should only do topmost here...
//Or should we???
// windowList.back()->HandleMouseButton(event.button.x, event.button.y, false);
uint32 mx = event.button.x, my = event.button.y;
if (mainWindow)
mainWindow->HandleMouseButton(mx, my, false);
else
mainMenu->HandleMouseButton(mx, my, false);
}
#ifdef DEBUG_MAIN_LOOP
else

View File

@ -8,7 +8,7 @@
#define __GUI_H__
#include <SDL.h>
#include <list>
#include <vector>
class Menu; // Now *this* should work, since we've got pointers...
class MenuItems;
@ -26,12 +26,10 @@ class GUI
void Stop(void);
private:
// Menu * mainMenu;
Menu * mainMenu;
MenuItems * menuItem;
std::list<Element *> windowList;
std::vector<Element *> windowList;
bool exitGUI;
bool showMouse;
SDL_Rect mouse, oldMouse;
};
#endif // __GUI_H__

View File

@ -156,47 +156,6 @@ void DrawStringOpaque(SDL_Surface * screen, uint32 x, uint32 y, uint32 fg, uint3
SDL_FreeSurface(chr);
}
bool RectanglesIntersect(SDL_Rect r1, SDL_Rect r2)
{
// The strategy here is to see if any of the sides of the smaller rect
// fall within the larger.
/*
+-----------------+ r1
| |
| +------+ r2 |
| | | |
| | | |
| +------+ |
| |
+-----------------+
*/
//This approach fails if r2 is inside of r1. !!! FIX !!! [DONE]
if (RectangleFirstInsideSecond(r2, r1))
return true;
if ((r1.x > r2.x && r1.x < (r2.x + r2.w))
|| ((r1.x + r1.w) > r2.x && (r1.x + r1.w) < (r2.x + r2.w))
|| (r1.y > r2.y && r1.y < (r2.y + r2.h))
|| ((r1.y + r1.h) > r2.y && (r1.y + r1.h) < (r2.y + r2.h)))
return true;
return false;
}
bool RectangleFirstInsideSecond(SDL_Rect r1, SDL_Rect r2)
{
if ((r1.x > r2.x && (r1.x + r1.w) > r2.x)
&& (r1.x < (r2.x + r2.w) && (r1.x + r1.w) < (r2.x + r2.w))
&& (r1.y > r2.y && (r1.y + r1.h) > r2.y)
&& (r1.y < (r2.y + r2.h) && (r1.y + r1.h) < (r2.y + r2.h)))
return true;
return false;
}
//
// Various GUI bitmaps

View File

@ -48,9 +48,7 @@ uint32 GetFontHeight(void);
void DrawStringTrans(SDL_Surface * screen, uint32 x, uint32 y, uint32 color, const char * text, ...);
void DrawStringOpaque(SDL_Surface * screen, uint32 x, uint32 y, uint32 fg, uint32 bg, const char * text, ...);
//Not sure these belong here, but there you go...
bool RectanglesIntersect(SDL_Rect r1, SDL_Rect r2);
bool RectangleFirstInsideSecond(SDL_Rect r1, SDL_Rect r2);
void DrawStringOpaqueSmall(SDL_Surface * screen, uint32 x, uint32 y, uint32 fg, uint32 bg, const char * text, ...);
// GUI bitmaps (exported)

View File

@ -27,12 +27,14 @@
#define MASK_A 0xFF000000
#endif
using namespace std; // For STL stuff
//
// Text edit class implementation
//
TextEdit::TextEdit(uint32 x/*= 0*/, uint32 y/*= 0*/, uint32 w/*= 0*/, uint32 h/*= 0*/,
std::string s/*= ""*/, Element * parent/*= NULL*/):
string s/*= ""*/, Element * parent/*= NULL*/):
Element(x, y, w, h, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x40, 0x40, 0xFF, parent),
activated(false), clicked(false), inside(false),
img(NULL), text(s), caretPos(0), scrollPos(0),
@ -225,7 +227,7 @@ void TextEdit::Notify(Element *)
{
}
std::string TextEdit::GetText(void)
string TextEdit::GetText(void)
{
return text;
}

View File

@ -18,12 +18,6 @@
#include "guimisc.h" // Various support functions
#include <algorithm>
// Debug support...
//#define DESTRUCTOR_TESTING
// Rendering experiment...
#define USE_COVERAGE_LISTS
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define MASK_R 0xFF000000
#define MASK_G 0x00FF0000
@ -36,6 +30,8 @@
#define MASK_A 0xFF000000
#endif
using namespace std; // For STL stuff
//
// Window class implementation
//
@ -63,9 +59,6 @@ Window::Window(uint32 x/*= 0*/, uint32 y/*= 0*/, uint32 w/*= 0*/, uint32 h/*= 0*
Window::~Window()
{
#ifdef DESTRUCTOR_TESTING
printf("Inside ~Window()...\n");
#endif
for(uint32 i=0; i<list.size(); i++)
if (list[i])
delete list[i];
@ -107,16 +100,6 @@ void Window::HandleMouseButton(uint32 x, uint32 y, bool mouseDown)
void Window::Draw(void)
{
#ifdef USE_COVERAGE_LISTS
// These are *always* top level and parentless, so no need to traverse up through
// the parent chain...
for(std::list<SDL_Rect>::iterator i=coverList.begin(); i!=coverList.end(); i++)
SDL_FillRect(screen, &(*i), bgColor);
// Handle the items this window contains...
for(uint32 i=0; i<list.size(); i++)
list[i]->Draw();
#else
// These are *always* top level and parentless, so no need to traverse up through
// the parent chain...
SDL_FillRect(screen, &extents, bgColor);
@ -124,7 +107,6 @@ void Window::Draw(void)
// Handle the items this window contains...
for(uint32 i=0; i<list.size(); i++)
list[i]->Draw();
#endif
//Prolly don't need this since the close button will do this for us...
needToRefreshScreen = true;
@ -135,9 +117,7 @@ void Window::Notify(Element * e)
if (e == closeButton)
{
SDL_Event event;
event.type = SDL_USEREVENT;
event.user.code = WINDOW_CLOSE;
event.user.data1 = (void *)this;
event.type = SDL_USEREVENT, event.user.code = WINDOW_CLOSE;
SDL_PushEvent(&event);
}
}

View File

@ -15,6 +15,7 @@
//However, the Atari version *does* occassionally pick strength while the Apple
//versions do not--which would seem to indicate a bug either in the RNG algorithm,
//the 65C02 core, or the Apple hardware. Need to investigate all three!
//[As it turns out, it was a problem with the Apple RNG written by Origin. Bad Origin!]
#define __DEBUG__
//#define __DEBUGMON__
@ -917,10 +918,10 @@ static void OpDE(void) // DEC ABS, X
Here's one problem: DEX is setting the N flag!
D3EE: A2 09 LDX #$09 [PC=D3F0, SP=01F7, CC=---B-I-C, A=01, X=09, Y=08]
D3F0: 98 TYA [PC=D3F1, SP=01F7, CC=N--B-I-C, A=08, X=09, Y=08]
D3F1: 48 PHA [PC=D3F2, SP=01F6, CC=N--B-I-C, A=08, X=09, Y=08]
D3F0: 98 TYA [PC=D3F1, SP=01F7, CC=N--B-I-C, A=08, X=09, Y=08]
D3F1: 48 PHA [PC=D3F2, SP=01F6, CC=N--B-I-C, A=08, X=09, Y=08]
D3F2: B5 93 LDA $93,X [PC=D3F4, SP=01F6, CC=---B-IZC, A=00, X=09, Y=08]
D3F4: CA DEX [PC=D3F5, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
D3F4: CA DEX [PC=D3F5, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
D3F5: 10 FA BPL $D3F1 [PC=D3F7, SP=01F6, CC=N--B-I-C, A=00, X=08, Y=08]
D3F7: 20 84 E4 JSR $E484 [PC=E484, SP=01F4, CC=N--B-I-C, A=00, X=08, Y=08]
@ -1130,6 +1131,7 @@ JSR Absolute JSR Abs 20 3 6
//This is not jumping to the correct address... !!! FIX !!! [DONE]
static void Op20(void) // JSR
{
// The whole ret - 1 probably stems from a fetch/push/fetch/push sequence...
uint16 addr = RdMemW(regs.pc);
regs.pc++; // Since it pushes return address - 1...
regs.WrMem(0x0100 + regs.sp--, regs.pc >> 8);