diff --git a/hardware/Makefile b/hardware/Makefile index 693f689..21a7d05 100644 --- a/hardware/Makefile +++ b/hardware/Makefile @@ -1,10 +1,10 @@ CC=vc +kick13 CFLAGS=-c99 -I$(NDK_INC) -DDEBUG -O2 -all: startup sprites playfield1 scoopex1 +all: startup sprites playfield1 scoopex1 soundfx clean: - rm -f *.o startup sprites playfield1 scoopex2 + rm -f *.o startup sprites playfield1 scoopex2 soundfx startup: startup.o common.o $(CC) $(CFLAGS) $^ -lamiga -lauto -o $@ @@ -18,3 +18,6 @@ playfield1: playfield1.o common.o scoopex1: scoopex1.c $(CC) $(CFLAGS) $^ -lamiga -lauto -o $@ +soundfx: soundfx.o common.o + $(CC) $(CFLAGS) $^ -lamiga -lauto -o $@ + diff --git a/hardware/common.c b/hardware/common.c index 34b51cb..2dc0b06 100644 --- a/hardware/common.c +++ b/hardware/common.c @@ -17,7 +17,7 @@ static ULONG oldresolution; struct ExecBase **exec_base_ptr = (struct ExecBase **) (4L); -static void ApplySpriteFix(void) +static void apply_sprite_fix(void) { if (wbscreen = LockPubScreen(WB_SCREEN_NAME)) { struct TagItem video_control_tags[] = { @@ -36,7 +36,7 @@ static void ApplySpriteFix(void) } } -static void UnapplySpriteFix(void) +static void unapply_sprite_fix(void) { if (wbscreen) { struct TagItem video_control_tags[] = { @@ -60,11 +60,9 @@ BOOL init_display(void) // Kickstart > 3.0: fix sprite bug if (lib_version >= 39) { - ApplySpriteFix(); + apply_sprite_fix(); is_pal = (((struct GfxBase *) GfxBase)->DisplayFlags & PAL) == PAL; } else { - // Note: FS-UAE reports 0 this, so essentially, there is no information - // for 1.x int vblank_freq = (*exec_base_ptr)->VBlankFrequency; printf("Gfx Lib version: %u, Vertical Blank Frequency: %d\n", lib_version, vblank_freq); is_pal = vblank_freq == VFREQ_PAL; @@ -76,7 +74,7 @@ void reset_display(void) { struct View *current_view = ((struct GfxBase *) GfxBase)->ActiView; UWORD lib_version = GfxBase->LibNode.lib_Version; - if (lib_version >= 39) UnapplySpriteFix(); + if (lib_version >= 39) unapply_sprite_fix(); LoadView(current_view); WaitTOF(); WaitTOF(); diff --git a/hardware/laser.raw8 b/hardware/laser.raw8 new file mode 100644 index 0000000..330ba4f Binary files /dev/null and b/hardware/laser.raw8 differ diff --git a/hardware/playfield1.c b/hardware/playfield1.c index 77d52fd..24fec08 100644 --- a/hardware/playfield1.c +++ b/hardware/playfield1.c @@ -5,7 +5,7 @@ #include "common.h" #define NUM_BITPLANES 5 -#define INTERLEAVED +//#define INTERLEAVED #ifdef USE_PAL @@ -57,6 +57,7 @@ static UWORD __chip coplist[] = { COP_MOVE(BPL4PTL, 0), COP_MOVE(BPL5PTH, 0), COP_MOVE(BPL5PTL, 0), + COP_MOVE(COLOR00, 0), COP_WAIT_END, COP_WAIT_END }; @@ -87,6 +88,7 @@ int main(int argc, char **argv) custom.diwstrt = DIWSTRT_VALUE; custom.diwstop = DIWSTOP_VALUE; + // should be done in copper list, because workbench copper list could overwrite it for (int i = 0; i < NUM_COLORS; i++) { custom.color[i] = image_colors[i]; } @@ -95,6 +97,7 @@ int main(int argc, char **argv) #ifdef INTERLEAVED // in interleaved mode, each plane's *rows* are organized // consecutively one after another + printf("interleaved\n"); for (int i = 0; i < NUM_BITPLANES; i++) { ULONG addr = (ULONG) &(image_data[i * 20]); coplist[i * 4 + 1] = (addr >> 16) & 0xffff; @@ -103,6 +106,7 @@ int main(int argc, char **argv) #else // in non-interleaved mode, each plane's data is placed // consecutively one after another + printf("non-interleaved\n"); for (int i = 0; i < NUM_BITPLANES; i++) { ULONG addr = (ULONG) &(image_data[i * 20 * NUM_RASTER_LINES]); coplist[i * 4 + 1] = (addr >> 16) & 0xffff; diff --git a/hardware/soundfx.c b/hardware/soundfx.c new file mode 100644 index 0000000..a9de82f --- /dev/null +++ b/hardware/soundfx.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include + +#include "common.h" + +/* + * This is essentially the code for startup.asm from + * "Amiga Demo Coders Reference Manual" translated to C. + * + * This allows a program which operates directly on the hardware + * to play nice with the operating system and ensure a clean exit + * to Workbench. + * A great starting point to use as a template for demos and games. + */ +extern struct Custom custom; +char VERSION_STRING[] = "\0$VER: startup 1.0 (21.09.2016)\0"; + +static UWORD __chip coplist_pal[] = { + COP_MOVE(BPLCON0, BPLCON0_COMPOSITE_COLOR), + COP_MOVE(COLOR00, 0x000), + 0x8107, 0xfffe, // wait for $8107,$fffe + COP_MOVE(COLOR00, 0xf00), + 0xd607, 0xfffe, // wait for $d607,$fffe + COP_MOVE(COLOR00, 0xff0), + COP_WAIT_END, + COP_WAIT_END +}; +static UWORD __chip coplist_ntsc[] = { + COP_MOVE(BPLCON0, BPLCON0_COMPOSITE_COLOR), + COP_MOVE(COLOR00, 0x000), + 0x6e07, 0xfffe, // wait for $6e07,$fffe + COP_MOVE(COLOR00, 0xf00), + 0xb007, 0xfffe, // wait for $b007,$fffe + COP_MOVE(COLOR00, 0xff0), + COP_WAIT_END, + COP_WAIT_END +}; + +// Assuming a 14k sample rate +#define SOUND_DATA_SIZE (25074) +// 0-64 +#define MAX_VOLUME (64) +#define SAMPLE_PERIOD (256) + +static UBYTE __chip sound_data[SOUND_DATA_SIZE]; + +void start_channel(int channel) +{ + int channel_bits = 0; + switch (channel) { + case 0: + channel_bits = DMAF_AUD0; + break; + case 1: + channel_bits = DMAF_AUD1; + break; + case 2: + channel_bits = DMAF_AUD2; + break; + case 3: + channel_bits = DMAF_AUD3; + break; + default: + break; + } + custom.dmacon = (DMAF_SETCLR | channel_bits | DMAF_MASTER); +} + +void stop_channel(int channel) +{ + int channel_bits = 0; + switch (channel) { + case 0: + channel_bits = DMAF_AUD0; + break; + case 1: + channel_bits = DMAF_AUD1; + break; + case 2: + channel_bits = DMAF_AUD2; + break; + case 3: + channel_bits = DMAF_AUD3; + break; + default: + break; + } + custom.dmacon = channel_bits; +} + +int main(int argc, char **argv) +{ + struct Task *current_task = FindTask(NULL); + BYTE old_prio = SetTaskPri(current_task, TASK_PRIORITY); + BOOL is_pal = init_display(); + FILE *fp = fopen("laser.raw8", "rb"); + int bytes_read = fread(sound_data, sizeof(UBYTE), SOUND_DATA_SIZE, fp); + custom.aud[0].ac_ptr = (UWORD *) sound_data; + custom.aud[0].ac_len = SOUND_DATA_SIZE / 2; + custom.aud[0].ac_vol = MAX_VOLUME; + custom.aud[0].ac_per = SAMPLE_PERIOD; + start_channel(0); + + + custom.cop1lc = is_pal ? (ULONG) coplist_pal : (ULONG) coplist_ntsc; + + // strobe the COPJMP1 register to make sure the system is using + // copper list 1 (I found out that leaving this out can lead to + // strange effects on an emulated 4000 system) + custom.copjmp1 = 1; + + waitmouse(); + stop_channel(0); + + reset_display(); + return 0; +} diff --git a/utils/png2image.py b/utils/png2image.py index 4072de5..cbe0e08 100755 --- a/utils/png2image.py +++ b/utils/png2image.py @@ -75,6 +75,8 @@ def write_amiga_image(im, outfile, img_name, use_intuition, interleaved, verbose # colors is a list of 3-integer lists ([[r1, g1, b1], ...]) colors = [i for i in chunks([b for b in im.palette.tobytes()], 3)] depth = round(math.log(len(colors), 2)) + if depth == 0: + raise Exception("images with only 1 color can't be handled") # fill the missing colors with black entries num_missing_colors = 2 ** depth - len(colors) colors += [[0, 0, 0]] * num_missing_colors