Adding a Title Screen
This commit is contained in:
parent
124a858e4d
commit
117806bc32
|
@ -3,3 +3,4 @@
|
|||
*.o
|
||||
*.map
|
||||
*.bak
|
||||
*.s
|
||||
|
|
|
@ -19,7 +19,7 @@ linux: $(LINUX_SRC)
|
|||
$(LINUX_CC) -o $(LINUX_OUT) $? $(LINUX_CFLAGS)
|
||||
|
||||
apple2: $(APPLE2_SRC)
|
||||
$(APPLE2_CL) -m $(APPLE2_MAP) -o $(APPLE2_OUT) $? $(APPLE2_CFLAGS)
|
||||
$(APPLE2_CL) -m $(APPLE2_MAP) -o $(APPLE2_OUT) $? $(APPLE2_CFLAGS) -C src/game-of-life.cfg
|
||||
|
||||
apple2-asm: $(APPLE2_SRC)
|
||||
$(APPLE2_CC) $(APPLE2_CFLAGS) -r -T $?
|
||||
|
|
|
@ -22,6 +22,13 @@ Two binaries will be produced.
|
|||
|
||||
Run the *add-to-disk.sh* script.
|
||||
|
||||
**Title screen**
|
||||
|
||||
The title screen art is located in the *assets* folder. It has to be
|
||||
manually loaded on the disk image using the *AppleCommander's GUI*, for the
|
||||
command line loads a corrupted file!
|
||||
This screen was converted from a PNG using [*Rgb2Hires*](https://github.com/Pixinn/Rgb2Hires).
|
||||
|
||||
---
|
||||
|
||||
For more information, you can refer to these posts on [my blog](https://www.xtof/info/blog/).
|
||||
|
|
Binary file not shown.
|
@ -1,19 +1,19 @@
|
|||
#!/bin/bash
|
||||
# Adds the gol.a2 Apple2 binary exceutable to the provided disk.dsk
|
||||
# Adds the required files to the provided disk.dsk
|
||||
# usage: add_to_disk PATH_TO_APPLECOMMANDER.jar
|
||||
|
||||
set -e
|
||||
|
||||
if (( $# != 1 )); then
|
||||
|
||||
if (( $# != 3 )); then
|
||||
echo "Bad number of arguments"
|
||||
echo "usage: add_to_disk.sh PATH_TO_APPLECOMMANDER.jar"
|
||||
echo "usage: add_to_disk.sh PATH_TO_APPLECOMMANDER.jar PATH_TO_BINARY.a2 PATH_TO_DISK"
|
||||
exit
|
||||
fi
|
||||
|
||||
echo " . revoving previous instance of GOL form the disk"
|
||||
java -jar ${1} -d disk.dsk GOL
|
||||
java -jar ${1} -d ${3} GOL
|
||||
|
||||
echo " .. adding GOL to the disk"
|
||||
java -jar ${1} -cc65 disk.dsk GOL BIN < gol.a2
|
||||
java -jar ${1} -cc65 ${3} GOL BIN < ${2}
|
||||
|
||||
echo "DONE."
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
import os.path
|
||||
import argparse
|
||||
from PIL import Image
|
||||
|
||||
# HiRes colors
|
||||
BLACK = [0x00, 0x00, 0x00]
|
||||
WHITE = [0xFF, 0xFF, 0xFF]
|
||||
GREEN = [0x00, 0xFF, 0x00]
|
||||
BLUE = [0x00, 0x00, 0xFF]
|
||||
ORANGE = [0xFF, 0x77, 0x00]
|
||||
VIOLET = [0xFF, 0x00, 0xFF]
|
||||
|
||||
Msg_Warning = ""
|
||||
Color_Last = BLACK
|
||||
|
||||
def error(msg, err_code):
|
||||
print(msg)
|
||||
exit(err_code)
|
||||
|
||||
|
||||
# Compute the Euclidean distance between 2 colors
|
||||
def distance(color1, color2):
|
||||
return (color1[0] - color2[0])**2 + (color1[1] - color2[1])**2 + (color1[2] - color2[2])**2
|
||||
|
||||
|
||||
# Returns the nearest color
|
||||
def nearest_color(color):
|
||||
dist_black = distance(BLACK, color)
|
||||
dist_white = distance(WHITE, color)
|
||||
dist_green = distance(GREEN, color)
|
||||
dist_blue = distance(BLUE, color)
|
||||
dist_orange = distance(ORANGE, color)
|
||||
dist_violet = distance(VIOLET, color)
|
||||
dist_min = min([dist_black, dist_white, dist_green, dist_blue, dist_violet, dist_orange])
|
||||
if dist_min == dist_black:
|
||||
return BLACK
|
||||
elif dist_min == dist_white:
|
||||
return WHITE
|
||||
elif dist_min == dist_green:
|
||||
return GREEN
|
||||
elif dist_min == dist_blue:
|
||||
return BLUE
|
||||
elif dist_min == dist_orange:
|
||||
return ORANGE
|
||||
else:
|
||||
return VIOLET
|
||||
|
||||
# Returns True if the 7 pixel block can be converted into hires with no artifact
|
||||
# Returns False otherwise
|
||||
def compliant_hires(block):
|
||||
global Msg_Warning
|
||||
global Color_Last
|
||||
# Test if colors from the two groups are in the block, aka "clashing"
|
||||
group_one = False
|
||||
group_two = False
|
||||
nb_pixels = len(block)//3
|
||||
for i in range(0, nb_pixels):
|
||||
color = block[3*i:3*(i+1)]
|
||||
if color == ORANGE or color == BLUE:
|
||||
group_one = True
|
||||
if color == GREEN or color == VIOLET:
|
||||
group_two = True
|
||||
if group_one and group_two:
|
||||
Msg_Warning = "Colors from two groups, some clashing will occur!"
|
||||
return False
|
||||
# Test if there are two consecutive different colors in the group
|
||||
Msg_Warning = "Two consecutive different colors may lead to an artifact"
|
||||
color = block[0:3]
|
||||
if Color_Last != BLACK and Color_Last != WHITE \
|
||||
and color != BLACK and color != WHITE \
|
||||
and color != Color_Last:
|
||||
return False
|
||||
for i in range(0, nb_pixels-1):
|
||||
color = block[3*i:3*(i+1)]
|
||||
if color != BLACK and color != WHITE:
|
||||
color_next = block[3*(i+1):3*(i+2)]
|
||||
if color_next != BLACK and color_next != WHITE \
|
||||
and color != BLACK and color != WHITE \
|
||||
and color != color_next:
|
||||
return False
|
||||
Color_Last = block[3*(nb_pixels-1):3*nb_pixels]
|
||||
return True
|
||||
|
||||
|
||||
# PARSING COMMAND LINE ARGUMENTS
|
||||
parser = argparse.ArgumentParser(description="This script converts a 24bit RGB image file into an Apple II HiRes image.")
|
||||
parser.add_argument("file", help="file to convert")
|
||||
parser.add_argument("-o", "--output", help="output filename", required=False)
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
# SANITIZE PARAMETERS
|
||||
if not os.path.exists(args.file):
|
||||
error("File " + args.file + " does not exist!", -1)
|
||||
|
||||
|
||||
# MAIN
|
||||
try:
|
||||
# Open source image
|
||||
image_rgb = Image.open(args.file).convert('RGB')
|
||||
w = image_rgb.size[0]
|
||||
h = image_rgb.size[1]
|
||||
|
||||
if w != 140 or h != 192:
|
||||
error("Source image must be 140x192 pixels", -1)
|
||||
|
||||
# Quantize image to the HiRes's 6 colors
|
||||
image_quantized = []
|
||||
for y in range(0, h):
|
||||
for x in range(0, w):
|
||||
color = nearest_color(image_rgb.getpixel((x, y)))
|
||||
for i in range(0, 3):
|
||||
image_quantized.append(color[i])
|
||||
if len(image_quantized) != 3*140*192:
|
||||
error("Bad quantized size", -1)
|
||||
|
||||
# image_test = Image.frombytes('RGB', (140, 192), bytes(image_quantized))
|
||||
# image_test.show()
|
||||
|
||||
# Test image conpliance to HiRes limitations
|
||||
nb_pixels = 7 # nb pixels per line block
|
||||
for i in range(0, 140 * 192 // nb_pixels):
|
||||
block = image_quantized[3*i*nb_pixels:
|
||||
3*(i+1)*nb_pixels]
|
||||
if not compliant_hires(block):
|
||||
print("Warning @block #" + str(i+1) + ": " + Msg_Warning)
|
||||
|
||||
except ValueError:
|
||||
error(ValueError, -1)
|
|
@ -0,0 +1,49 @@
|
|||
# Default configuration (allowing for 3KB in LC)
|
||||
|
||||
FEATURES {
|
||||
STARTADDRESS: default = $0803;
|
||||
}
|
||||
SYMBOLS {
|
||||
__EXEHDR__: type = import;
|
||||
__STACKSIZE__: type = weak, value = $0800; # 2k stack
|
||||
__HIRESP2__: type = weak, value = $4000; # Start of HIRES PAGE2
|
||||
__BSS__: type = weak, value = $6000; # Start of BSS after HIRES PAGE2
|
||||
__HIMEM__: type = weak, value = $9600; # Presumed RAM end
|
||||
__LCADDR__: type = weak, value = $D400; # Behind quit code
|
||||
__LCSIZE__: type = weak, value = $0C00; # Rest of bank two
|
||||
}
|
||||
MEMORY {
|
||||
ZP: file = "", define = yes, start = $0080, size = $001A;
|
||||
HEADER: file = %O, start = %S - 4, size = $0004;
|
||||
MAIN: file = %O, define = yes, start = %S, size = __HIRESP2__ - %S;
|
||||
BSS: file = "", start = __BSS__, size = __HIMEM__ - __BSS__;
|
||||
LC: file = "", define = yes, start = __LCADDR__, size = __LCSIZE__;
|
||||
}
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
EXEHDR: load = HEADER, type = ro;
|
||||
STARTUP: load = MAIN, type = ro;
|
||||
LOWCODE: load = MAIN, type = ro, optional = yes;
|
||||
CODE: load = MAIN, type = ro;
|
||||
RODATA: load = MAIN, type = ro;
|
||||
DATA: load = MAIN, type = rw;
|
||||
INIT: load = MAIN, type = rw;
|
||||
ONCE: load = MAIN, type = ro, define = yes;
|
||||
LC: load = MAIN, run = LC, type = ro, optional = yes;
|
||||
BSS: load = BSS, type = bss, define = yes;
|
||||
}
|
||||
FEATURES {
|
||||
CONDES: type = constructor,
|
||||
label = __CONSTRUCTOR_TABLE__,
|
||||
count = __CONSTRUCTOR_COUNT__,
|
||||
segment = ONCE;
|
||||
CONDES: type = destructor,
|
||||
label = __DESTRUCTOR_TABLE__,
|
||||
count = __DESTRUCTOR_COUNT__,
|
||||
segment = RODATA;
|
||||
CONDES: type = interruptor,
|
||||
label = __INTERRUPTOR_TABLE__,
|
||||
count = __INTERRUPTOR_COUNT__,
|
||||
segment = RODATA,
|
||||
import = __CALLIRQ__;
|
||||
}
|
|
@ -40,7 +40,7 @@ void editor( void ); /* lets the user draw some starting cell
|
|||
int8_t editor_load_save( const uint8_t load_or_save );
|
||||
void toggle_cell( const uint8_t x, const uint8_t y ); /* toggles the cell at the given coordinates. \
|
||||
Returns the cursor X position */
|
||||
|
||||
void title_screen( void ); /* Loads and display the title screen */
|
||||
void run( void ); /* runs the simulation */
|
||||
void __fastcall__ update( void ); /* updates the simulation */
|
||||
uint8_t __fastcall__ count_neighbours( uint8_t* cell ); /* counts nb neighbours of the cell */
|
||||
|
@ -85,6 +85,7 @@ enum {
|
|||
static uint8_t Cells[ NB_COLUMNS ][ NB_LINES ];
|
||||
static uint8_t Cells_Future[ NB_COLUMNS ][ NB_LINES ];
|
||||
static uint8_t Cells_Initial[ NB_COLUMNS ][ NB_LINES ];
|
||||
//static uint8_t Title_Screen[ 0x2000 ];
|
||||
|
||||
/******************** CODE ************************/
|
||||
|
||||
|
@ -94,6 +95,9 @@ int main( int argc, char** argv )
|
|||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
/* Displaying the Title Screen */
|
||||
title_screen();
|
||||
|
||||
init_asm( (uint8_t*)Cells, (uint8_t*)Cells_Future );
|
||||
init_rnd_color();
|
||||
|
||||
|
@ -211,7 +215,7 @@ void editor( void )
|
|||
uint8_t color_pixel;
|
||||
uint8_t update_color = 1;
|
||||
|
||||
const char* const text = "J L I K: Move the cursor\nSPACE : Toggle a cell\n\n(L)oad - (S)ave - (D)one";
|
||||
const char* const text = "H K U J: Move the cursor\nSPACE : Toggle a cell\n\n(L)oad - (S)ave - (D)one";
|
||||
set_text( text );
|
||||
|
||||
//Place the cursor middle screen
|
||||
|
@ -376,3 +380,31 @@ void run( void )
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****** HIRES SCREEN DEFINITIONS ***********/
|
||||
#define HIRES_PAGE2 (char*)0x4000
|
||||
#define HIRES_PAGE_SIZE 0x2000
|
||||
#define SWITCH_GRAPHICS *((uint8_t*)0xC050)=1
|
||||
#define SWITCH_FULLSCREEN *((uint8_t*)0xC052)=1
|
||||
#define SWITCH_PAGE2 *((uint8_t*)0xC055)=1
|
||||
#define SWITCH_HIRES *((uint8_t*)0xC057)=1
|
||||
|
||||
//The Title Screen asset is located in the "assets" folder
|
||||
void title_screen( void )
|
||||
{
|
||||
uint8_t handle;
|
||||
file_open("GOL.SCREEN", &handle);
|
||||
if(file_read( handle, HIRES_PAGE2, HIRES_PAGE_SIZE ) != HIRES_PAGE_SIZE ) {
|
||||
printf("\nERROR, CANNOT READ GOL.SCREEN\nERRNO: %x\n\n", file_error());
|
||||
file_close(handle);
|
||||
exit(-1);
|
||||
}
|
||||
file_close(handle);
|
||||
|
||||
SWITCH_GRAPHICS;
|
||||
SWITCH_FULLSCREEN;
|
||||
SWITCH_PAGE2;
|
||||
SWITCH_HIRES;
|
||||
|
||||
cgetc();
|
||||
}
|
||||
|
|
|
@ -32,13 +32,6 @@ _call_to_mli:
|
|||
JSR popa
|
||||
STA Mli_Call
|
||||
|
||||
;+ DEBUG
|
||||
; CMP #$CE
|
||||
; BNE continue
|
||||
;debug: JMP debug
|
||||
;continue:
|
||||
;- DEBUG
|
||||
|
||||
; Call MLI and return
|
||||
JSR $BF00 ; MLI call entry point
|
||||
Mli_Call:
|
||||
|
|
Loading…
Reference in New Issue