initial commit

This commit is contained in:
R-type
2015-12-14 14:00:35 +01:00
commit 5a96c0ca66
377 changed files with 149124 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
atari800.cfg
autom4te.cache
config.h
config.h.in
config.log
config.status
config.cache
configure
Makefile
SDL_win32_main.c
emuos.img
atari800
+158
View File
@@ -0,0 +1,158 @@
CC = @CC@
RC = windres
DEFS = @DEFS@
LIBS = @LIBS@
TARGET_BASE_NAME = atari800
TARGET = $(TARGET_BASE_NAME)@EXEEXT@
CONFIGURE_TARGET = @CONFIGURE_TARGET@
CONFIGURE_HOST = @CONFIGURE_HOST@
ifeq (@CONFIGURE_HOST@, javanvm)
FINALTARGET = $(TARGET_BASE_NAME).jar
JAVAFLAGS = @JAVAFLAGS@
JAVA = java
JAVACFLAGS = @JAVACFLAGS@
JAVAC = javac
else
ifeq (@CONFIGURE_TARGET@,android)
FINALTARGET = android
else
FINALTARGET = $(TARGET)
endif
endif
CFLAGS = @CFLAGS@ @CPPFLAGS@
LDFLAGS = @LDFLAGS@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ -s
INSTALL_DATA = @INSTALL_DATA@
BIN_DIR = @prefix@/bin
MAN_DIR = @prefix@/share/man/man1
DOC_DIR = @prefix@/share/doc/atari800
DESTDIR =
OBJS = \
afile.o \
antic.o \
atari.o \
binload.o \
cartridge.o \
cassette.o \
compfile.o \
cfg.o \
cpu.o \
crc32.o \
devices.o \
emuos.o \
esc.o \
gtia.o \
img_tape.o \
log.o \
memory.o \
monitor.o \
pbi.o \
pia.o \
pokey.o \
rtime.o \
sio.o \
sysrom.o \
util.o \
@OBJS@
all: $(FINALTARGET)
# A special rule for SDL_win32_main.c to suppress warnings since this file is
# from SDL and should not have to be modified
SDL_win32_main.o: SDL_win32_main.c
$(CC) -c -o $@ $(DEFS) -I. $(CFLAGS) -Wno-missing-declarations -Wno-missing-prototypes $<
# A special rule for win32 to not compile with -ansi -pedantic
win32/%.o: win32/%.c
$(CC) -c -o $@ $(DEFS) -I. $(patsubst -pedantic,,$(patsubst -ansi,,$(CFLAGS))) $<
ide.o: ide.c ide.h ide_internal.h
$(CC) -c -o $@ $(DEFS) -I. $(CFLAGS:-ansi=) $<
%.o: %.c
$(CC) -c -o $@ $(DEFS) -I. $(CFLAGS) $<
%.ro: %.rc
$(RC) --define WIN32 --define __MINGW32__ --include-dir . $< $@
%.o: %.cpp
$(CC) -c -o $@ $(DEFS) -I. $(CFLAGS) $<
%.o: %.S
$(CC) -c -o $@ $(DEFS) -I. $(CFLAGS) $<
ifeq ($(CONFIGURE_HOST),javanvm)
$(TARGET_BASE_NAME).class: javanvm/$(TARGET_BASE_NAME).java | $(TARGET_BASE_NAME)_runtime.class
$(JAVAC) -d . $(JAVACFLAGS) javanvm/$(TARGET_BASE_NAME).java
RUNTIME = _runtime
else
RUNTIME =
endif
$(TARGET_BASE_NAME)$(RUNTIME).class: $(TARGET)
#To compile using java bytecode directly:
# $(JAVA) $(JAVAFLAGS) org.ibex.nestedvm.Compiler -o UnixRuntime -outfile $@ $(TARGET_BASE_NAME)$(RUNTIME) $(TARGET)
$(JAVA) $(JAVAFLAGS) org.ibex.nestedvm.Compiler -o UnixRuntime -outformat javasource -outfile $(TARGET_BASE_NAME)$(RUNTIME).java $(TARGET_BASE_NAME)$(RUNTIME) $(TARGET)
$(JAVAC) -d . $(JAVACFLAGS) -J-Xmx256m $(TARGET_BASE_NAME)$(RUNTIME).java
##Also, -o UnixRuntime fixes directory browsing but requires /c:/-style paths
$(TARGET_BASE_NAME).jar: $(TARGET_BASE_NAME).class $(TARGET_BASE_NAME)$(RUNTIME).class
printf "Manifest-Version: 1.0\nMain-Class: $(TARGET_BASE_NAME)\nClass-Path: unix_runtime.jar\n" > .manifest
jar cfm $(TARGET_BASE_NAME).jar .manifest *.class
# Allow parallel execution in sub-make with '+'
android:
+ ndk-build -C android
ant -f android/build.xml debug
.PHONY: android
$(TARGET): $(OBJS)
$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
dep:
@if ! makedepend -Y $(DEFS) -I. ${OBJS:.o=.c} 2>/dev/null; \
then echo warning: makedepend failed; fi
clean:
rm -f *.o *.class .manifest $(TARGET) $(TARGET_BASE_NAME).jar $(TARGET_BASE_NAME)_runtime.java core *.bak *~
rm -f dos/*.o dos/*.bak dos/*~
rm -f falcon/*.o falcon/*.bak falcon/*~
rm -f sdl/*.o sdl/*.bak sdl/*~
rm -f win32/*.o win32/*.ro win32/*.bak win32/*~
rm -f javanvm/*.o javanvm/*.bak javanvm/*~
rm -f atari_ntsc/*.o atari_ntsc/*.bak atari_ntsc/*~
rm -rf android/libs android/obj android/bin android/gen
distclean: clean
-rm -f Makefile configure config.log config.status config.h android/jni/Android.mk
-rm -rf autom4te.cache
install: $(TARGET) installdirs
$(INSTALL_PROGRAM) $(TARGET) ${DESTDIR}${BIN_DIR}/$(TARGET)
$(INSTALL_DATA) atari800.man ${DESTDIR}${MAN_DIR}/atari800.1
# install also the documentation
$(INSTALL_DATA) ../COPYING ${DESTDIR}${DOC_DIR}/COPYING
$(INSTALL_DATA) ../README.1ST ${DESTDIR}${DOC_DIR}/README.1ST
$(INSTALL_DATA) ../DOC/README ${DESTDIR}${DOC_DIR}/README
$(INSTALL_DATA) ../DOC/INSTALL ${DESTDIR}${DOC_DIR}/INSTALL
$(INSTALL_DATA) ../DOC/USAGE ${DESTDIR}${DOC_DIR}/USAGE
$(INSTALL_DATA) ../DOC/NEWS ${DESTDIR}${DOC_DIR}/NEWS
readme.html: $(TARGET)
./$(TARGET) -help </dev/null | ../util/usage2html.pl \
../DOC/readme.html.in ../DOC/USAGE ./atari.h > $@
doc: readme.html
installdirs:
mkdir -p $(DESTDIR)$(BIN_DIR) $(DESTDIR)$(MAN_DIR) $(DESTDIR)$(DOC_DIR)
+187
View File
@@ -0,0 +1,187 @@
##############################################
## The following part is copied from sdl.m4 ##
##############################################
# Configure paths for SDL
# Sam Lantinga 9/21/99
# stolen from Manish Singh
# stolen back from Frank Belew
# stolen from Manish Singh
# Shamelessly stolen from Owen Taylor
dnl AM_PATH_SDL([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
dnl
AC_DEFUN([AM_PATH_SDL],
[dnl
dnl Get the cflags and libraries from the sdl-config script
dnl
AC_ARG_WITH(sdl-prefix,[ --with-sdl-prefix=PFX Prefix where SDL is installed (optional)],
sdl_prefix="$withval", sdl_prefix="")
AC_ARG_WITH(sdl-exec-prefix,[ --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)],
sdl_exec_prefix="$withval", sdl_exec_prefix="")
AC_ARG_ENABLE(sdltest, [ --disable-sdltest Do not try to compile and run a test SDL program],
, enable_sdltest=yes)
if test x$sdl_exec_prefix != x ; then
sdl_config_args="$sdl_config_args --exec-prefix=$sdl_exec_prefix"
if test x${SDL_CONFIG+set} != xset ; then
SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
fi
fi
if test x$sdl_prefix != x ; then
sdl_config_args="$sdl_config_args --prefix=$sdl_prefix"
if test x${SDL_CONFIG+set} != xset ; then
SDL_CONFIG=$sdl_prefix/bin/sdl-config
fi
fi
as_save_PATH="$PATH"
if test "x$prefix" != xNONE; then
PATH="$prefix/bin:$prefix/usr/bin:$PATH"
fi
AC_PATH_PROG(SDL_CONFIG, sdl-config, no, [$PATH])
PATH="$as_save_PATH"
min_sdl_version=ifelse([$1], ,0.11.0,$1)
AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
no_sdl=""
if test "$SDL_CONFIG" = "no" ; then
no_sdl=yes
else
SDL_CFLAGS=`$SDL_CONFIG $sdl_config_args --cflags`
SDL_LIBS=`$SDL_CONFIG $sdl_config_args --libs`
sdl_major_version=`$SDL_CONFIG $sdl_config_args --version | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
sdl_minor_version=`$SDL_CONFIG $sdl_config_args --version | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
if test "x$enable_sdltest" = "xyes" ; then
ac_save_CFLAGS="$CFLAGS"
ac_save_CXXFLAGS="$CXXFLAGS"
ac_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $SDL_CFLAGS"
CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
LIBS="$LIBS $SDL_LIBS"
dnl
dnl Now check if the installed SDL is sufficiently new. (Also sanity
dnl checks the results of sdl-config to some extent
dnl
rm -f conf.sdltest
AC_TRY_RUN([
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL.h"
char*
my_strdup (char *str)
{
char *new_str;
if (str)
{
new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
strcpy (new_str, str);
}
else
new_str = NULL;
return new_str;
}
int main (int argc, char *argv[])
{
int major, minor, micro;
char *tmp_version;
/* This hangs on some systems (?)
system ("touch conf.sdltest");
*/
{ FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); }
/* HP/UX 9 (%@#!) writes to sscanf strings */
tmp_version = my_strdup("$min_sdl_version");
if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
printf("%s, bad version string\n", "$min_sdl_version");
exit(1);
}
if (($sdl_major_version > major) ||
(($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
(($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
{
return 0;
}
else
{
printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then it is\n", major, minor, micro);
printf("*** best to upgrade to the required version.\n");
printf("*** If sdl-config was wrong, set the environment variable SDL_CONFIG\n");
printf("*** to point to the correct copy of sdl-config, and remove the file\n");
printf("*** config.cache before re-running configure\n");
return 1;
}
}
],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
CFLAGS="$ac_save_CFLAGS"
CXXFLAGS="$ac_save_CXXFLAGS"
LIBS="$ac_save_LIBS"
fi
fi
if test "x$no_sdl" = x ; then
AC_MSG_RESULT(yes)
ifelse([$2], , :, [$2])
else
AC_MSG_RESULT(no)
if test "$SDL_CONFIG" = "no" ; then
echo "*** The sdl-config script installed by SDL could not be found"
echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
echo "*** your path, or set the SDL_CONFIG environment variable to the"
echo "*** full path to sdl-config."
else
if test -f conf.sdltest ; then
:
else
echo "*** Could not run SDL test program, checking why..."
CFLAGS="$CFLAGS $SDL_CFLAGS"
CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
LIBS="$LIBS $SDL_LIBS"
AC_TRY_LINK([
#include <stdio.h>
#include "SDL.h"
int main(int argc, char *argv[])
{ return 0; }
#undef main
#define main K_and_R_C_main
], [ return 0; ],
[ echo "*** The test program compiled, but did not run. This usually means"
echo "*** that the run-time linker is not finding SDL or finding the wrong"
echo "*** version of SDL. If it is not finding SDL, you'll need to set your"
echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
echo "*** to the installed location Also, make sure you have run ldconfig if that"
echo "*** is required on your system"
echo "***"
echo "*** If you have an old version installed, it is best to remove it, although"
echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
[ echo "*** The test program failed to compile or link. See the file config.log for the"
echo "*** exact error that occured. This usually means SDL was incorrectly installed"
echo "*** or that you have moved SDL since it was installed. In the latter case, you"
echo "*** may want to edit the sdl-config script: $SDL_CONFIG" ])
CFLAGS="$ac_save_CFLAGS"
CXXFLAGS="$ac_save_CXXFLAGS"
LIBS="$ac_save_LIBS"
fi
fi
SDL_CFLAGS=""
SDL_LIBS=""
ifelse([$3], , :, [$3])
fi
AC_SUBST(SDL_CFLAGS)
AC_SUBST(SDL_LIBS)
rm -f conf.sdltest
])
+390
View File
@@ -0,0 +1,390 @@
/*
* af80.c - Emulation of the Austin Franklin 80 column card.
*
* Copyright (C) 2009 Perry McFarlane
* Copyright (C) 2009 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "af80.h"
#include "atari.h"
#include "util.h"
#include "log.h"
#include "memory.h"
#include "cpu.h"
#include <stdlib.h>
static UBYTE *af80_rom = NULL;
static char af80_rom_filename[FILENAME_MAX];
static UBYTE *af80_charset = NULL;
static char af80_charset_filename[FILENAME_MAX];
static UBYTE *af80_screen = NULL;
static UBYTE *af80_attrib = NULL;
int AF80_enabled = FALSE;
/* Austin Franklin information from forum posts by warerat at Atariage */
static int rom_bank_select; /* bits 0-3 of d5f7, $0-$f 16 banks */
static int not_rom_output_enable; /* bit 4 of d5f7 0 = Enable ROM 1 = Disable ROM */
static int not_right_cartridge_rd4_control; /* 0=$8000-$9fff cart ROM, 1= $8000-$9fff system RAM */
static int not_enable_2k_character_ram;
static int not_enable_2k_attribute_ram;
static int not_enable_crtc_registers;
static int not_enable_80_column_output;
static int video_bank_select; /* bits 0-3 of d5f6, $0-$f 16 banks */
static int crtreg[0x40];
static int const rgbi_palette[16] = {
0x000000, /* black */
0x0000AA, /* blue */
0x00AA00, /* green */
0x00AAAA, /* cyan */
0xAA0000, /* red */
0xAA00AA, /* magenta */
0xAA5500, /* brown */
0xAAAAAA, /* white */
0x555555, /* grey */
0x5555FF, /* light blue */
0x55FF55, /* light green */
0x55FFFF, /* light cyan */
0xFF5555, /* light red */
0xFF55FF, /* light magenta */
0xFFFF55, /* yellow */
0xFFFFFF /* white (high intensity) */
};
int AF80_palette[16];
#ifdef AF80_DEBUG
#define D(a) a
#else
#define D(a) do{}while(0)
#endif
static void update_d6(void)
{
if (!not_enable_2k_character_ram) {
memcpy(MEMORY_mem + 0xd600, af80_screen + (video_bank_select<<7), 0x80);
memcpy(MEMORY_mem + 0xd680, af80_screen + (video_bank_select<<7), 0x80);
}
else if (!not_enable_2k_attribute_ram) {
memcpy(MEMORY_mem + 0xd600, af80_attrib + (video_bank_select<<7), 0x80);
memcpy(MEMORY_mem + 0xd680, af80_attrib + (video_bank_select<<7), 0x80);
}
else if (not_enable_crtc_registers) {
memset(MEMORY_mem + 0xd600, 0xff, 0x100);
}
}
static void update_d5(void)
{
if (not_rom_output_enable) {
memset(MEMORY_mem + 0xd500, 0xff, 0x100);
}
else {
memcpy(MEMORY_mem + 0xd500, af80_rom + (rom_bank_select<<8), 0x100);
}
}
static void update_8000_9fff(void)
{
if (not_right_cartridge_rd4_control) return;
if (not_rom_output_enable) {
memset(MEMORY_mem + 0x8000, 0xff, 0x2000);
}
else {
int i;
for (i=0; i<32; i++) {
memcpy(MEMORY_mem + 0x8000 + (i<<8), af80_rom + (rom_bank_select<<8), 0x100);
}
}
}
int AF80_Initialise(int *argc, char *argv[])
{
int i, j;
int help_only = FALSE;
for (i = j = 1; i < *argc; i++) {
if (strcmp(argv[i], "-af80") == 0) {
AF80_enabled = TRUE;
}
else {
if (strcmp(argv[i], "-help") == 0) {
help_only = TRUE;
Log_print("\t-af80 Emulate the Austin Franklin 80 column board");
}
argv[j++] = argv[i];
}
}
*argc = j;
if (help_only)
return TRUE;
if (AF80_enabled) {
Log_print("Austin Franklin 80 enabled");
af80_rom = (UBYTE *)Util_malloc(0x1000);
if (!Atari800_LoadImage(af80_rom_filename, af80_rom, 0x1000)) {
free(af80_rom);
af80_rom = NULL;
AF80_enabled = FALSE;
Log_print("Couldn't load Austin Franklin ROM image");
return FALSE;
}
else {
Log_print("loaded Austin Franklin rom image");
}
af80_charset = (UBYTE *)Util_malloc(0x1000);
if (!Atari800_LoadImage(af80_charset_filename, af80_charset, 0x1000)) {
free(af80_charset);
free(af80_rom);
af80_charset = af80_rom = NULL;
AF80_enabled = FALSE;
Log_print("Couldn't load Austin Franklin charset image");
return FALSE;
}
else {
Log_print("loaded Austin Franklin charset image");
}
af80_screen = (UBYTE *)Util_malloc(0x800);
af80_attrib = (UBYTE *)Util_malloc(0x800);
AF80_Reset();
/* swap palette */
for (i=0; i<16; i++ ) {
j=i;
j = (j&0x0a) + ((j&0x01) << 2) + ((j&0x04) >> 2);
AF80_palette[i] = rgbi_palette[j];
}
}
return TRUE;
}
void AF80_Exit(void)
{
free(af80_screen);
free(af80_attrib);
free(af80_charset);
free(af80_rom);
af80_screen = af80_attrib = af80_charset = af80_rom = NULL;
}
void AF80_InsertRightCartridge(void)
{
MEMORY_Cart809fEnable();
update_d5();
update_8000_9fff();
}
int AF80_ReadConfig(char *string, char *ptr)
{
if (strcmp(string, "AF80_ROM") == 0)
Util_strlcpy(af80_rom_filename, ptr, sizeof(af80_rom_filename));
else if (strcmp(string, "AF80_CHARSET") == 0)
Util_strlcpy(af80_charset_filename, ptr, sizeof(af80_charset_filename));
else return FALSE; /* no match */
return TRUE; /* matched something */
}
void AF80_WriteConfig(FILE *fp)
{
fprintf(fp, "AF80_ROM=%s\n", af80_rom_filename);
fprintf(fp, "AF80_CHARSET=%s\n", af80_charset_filename);
}
int AF80_D6GetByte(UWORD addr, int no_side_effects)
{
int result = 0xff;
if (!not_enable_2k_character_ram) {
result = MEMORY_dGetByte(addr);
}
else if (!not_enable_2k_attribute_ram) {
result = MEMORY_dGetByte(addr);
}
else if (!not_enable_crtc_registers) {
if (video_bank_select == 0 ) {
if ((addr&0xff)<0x40) {
result = crtreg[addr&0xff];
if ((addr&0xff) == 0x3a) {
result = 0x01;
}
}
D(printf("AF80 Read addr:%4x cpu:%4x\n", addr, CPU_remember_PC[(CPU_remember_PC_curpos-1)%CPU_REMEMBER_PC_STEPS]));
}
}
return result;
}
void AF80_D6PutByte(UWORD addr, UBYTE byte)
{
if (!not_enable_2k_character_ram) {
MEMORY_dPutByte((addr&0xff7f),byte);
MEMORY_dPutByte((addr&0xff7f)+0x80,byte);
af80_screen[(addr&0x7f) + (video_bank_select<<7)] = byte;
}
else if (!not_enable_2k_attribute_ram) {
MEMORY_dPutByte((addr&0xff7f),byte);
MEMORY_dPutByte((addr&0xff7f)+0x80,byte);
af80_attrib[(addr&0x7f) + (video_bank_select<<7)] = byte;
D(printf("AF80 Write, attribute, addr:%4x byte:%2x, cpu:%4x\n", addr, byte,CPU_remember_PC[(CPU_remember_PC_curpos-1)%CPU_REMEMBER_PC_STEPS]));
}
else if (!not_enable_crtc_registers) {
if (video_bank_select == 0 ) {
if ((addr&0xff)<0x40) {
crtreg[addr&0xff] = byte;
}
D(if (1 || (addr!=0xd618 && addr!=0xd619)) printf("AF80 Write addr:%4x byte:%2x, cpu:%4x\n", addr, byte,CPU_remember_PC[(CPU_remember_PC_curpos-1)%CPU_REMEMBER_PC_STEPS]));
}
else {
D(printf("AF80 Write, video_bank_select!=0, addr:%4x byte:%2x, cpu:%4x\n", addr, byte,CPU_remember_PC[(CPU_remember_PC_curpos-1)%CPU_REMEMBER_PC_STEPS]));
}
}
}
int AF80_D5GetByte(UWORD addr, int no_side_effects)
{
int result = MEMORY_dGetByte(addr);
return result;
}
void AF80_D5PutByte(UWORD addr, UBYTE byte)
{
if (addr == 0xd5f6) {
int need_update_d6 = FALSE;
if ((byte&0x10) != not_enable_2k_character_ram) {
not_enable_2k_character_ram = (byte & 0x10);
need_update_d6 = TRUE;
}
if ((byte&0x20) != not_enable_2k_attribute_ram) {
not_enable_2k_attribute_ram = (byte & 0x20);
need_update_d6 = TRUE;
}
if ((byte&0x40) != not_enable_crtc_registers) {
not_enable_crtc_registers = (byte & 0x40);
need_update_d6 = TRUE;
}
if ((byte&0x80) != not_enable_80_column_output) {
not_enable_80_column_output = (byte & 0x80);
}
if ((byte&0x0f) != video_bank_select) {
video_bank_select = (byte & 0x0f);
need_update_d6 = TRUE;
}
if (need_update_d6) {
update_d6();
}
}
else if (addr == 0xd5f7) {
int need_update_d5 = FALSE;
int need_update_8000_9fff = FALSE;
if ((byte&0x10) != not_rom_output_enable) {
not_rom_output_enable = (byte & 0x10);
need_update_d5 = TRUE;
if (byte&0x20) {
need_update_8000_9fff = TRUE;
}
}
if ((byte&0x20) != not_right_cartridge_rd4_control) {
not_right_cartridge_rd4_control = (byte & 0x20);
if (not_right_cartridge_rd4_control) {
MEMORY_Cart809fDisable();
}
else {
MEMORY_Cart809fEnable();
need_update_8000_9fff = TRUE;
}
}
if ((byte&0x0f) != rom_bank_select) {
rom_bank_select = (byte & 0x0f);
if (!not_rom_output_enable) {
need_update_d5 = TRUE;
if (!not_right_cartridge_rd4_control) {
need_update_8000_9fff = TRUE;
}
}
}
if (need_update_d5) {
update_d5();
}
if (need_update_8000_9fff) {
update_8000_9fff();
}
}
D(if (addr!=0xd5f7 && addr!=0xd5f6) printf("AF80 Write addr:%4x byte:%2x, cpu:%4x\n", addr, byte,CPU_remember_PC[(CPU_remember_PC_curpos-1)%CPU_REMEMBER_PC_STEPS]));
}
UBYTE AF80_GetPixels(int scanline, int column, int *colour, int blink)
{
#define AF80_ROWS 25
#define AF80_CELL_HEIGHT 10
UBYTE character;
int attrib;
UBYTE font_data;
int table_start = crtreg[0x0c] + ((crtreg[0x0d]&0x3f)<<8);
int row = scanline / AF80_CELL_HEIGHT;
int line = scanline % AF80_CELL_HEIGHT;
int screen_pos;
if (row >= AF80_ROWS) {
return 0;
}
if (row >= crtreg[0x10]) {
screen_pos = (row-crtreg[0x10])*80 + column + crtreg[0x0e] + ((crtreg[0x0f]&0x3f)<<8);
}
else {
screen_pos = row*80+column + table_start;
}
screen_pos &= 0x7ff;
character = af80_screen[screen_pos];
attrib = af80_attrib[screen_pos];
font_data = af80_charset[character*16 + line];
if (attrib & 0x01) {
font_data ^= 0xff; /* invert */
}
if ((attrib & 0x02) && blink) {
font_data = 0x00; /* blink */
}
if (line+1 == AF80_CELL_HEIGHT && (attrib & 0x04)) {
font_data = 0xff; /* underline */
}
if (row == crtreg[0x18] && column == crtreg[0x19] && !blink) {
font_data = 0xff; /* cursor */
}
*colour = attrib>>4; /* set number of palette entry */
return font_data;
}
void AF80_Reset(void)
{
memset(af80_screen, 0, 0x800);
memset(af80_attrib, 0, 0x800);
rom_bank_select = 0;
not_rom_output_enable = 0;
not_right_cartridge_rd4_control = 0;
not_enable_2k_character_ram = 0;
not_enable_2k_attribute_ram = 0;
not_enable_crtc_registers = 0;
not_enable_80_column_output = 0;
video_bank_select = 0;
memset(crtreg, 0, 0x40);
}
/*
vim:ts=4:sw=4:
*/
+21
View File
@@ -0,0 +1,21 @@
#ifndef AF80_H_
#define AF80_H_
#include "atari.h"
#include <stdio.h>
extern int AF80_palette[16];
int AF80_Initialise(int *argc, char *argv[]);
void AF80_Exit(void);
void AF80_InsertRightCartridge(void);
int AF80_ReadConfig(char *string, char *ptr);
void AF80_WriteConfig(FILE *fp);
int AF80_D5GetByte(UWORD addr, int no_side_effects);
void AF80_D5PutByte(UWORD addr, UBYTE byte);
int AF80_D6GetByte(UWORD addr, int no_side_effects);
void AF80_D6PutByte(UWORD addr, UBYTE byte);
UBYTE AF80_GetPixels(int scanline, int column, int *colour, int blink);
extern int AF80_enabled;
void AF80_Reset(void);
#endif /* AF80_H_ */
+245
View File
@@ -0,0 +1,245 @@
/*
* afile.c - Detection and opening of different Atari file types.
*
* Copyright (c) 1998-2008 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "atari.h"
#include "afile.h"
#include "binload.h"
#include "cartridge.h"
#include "cassette.h"
#include "gtia.h"
#include "img_tape.h"
#include "log.h"
#include "sio.h"
#include "statesav.h"
#include "util.h"
#ifndef BASIC
#include "ui.h"
#endif /* BASIC */
#ifdef HAVE_LIBZ
#include <zlib.h>
#endif
#include <stdio.h>
int AFILE_DetectFileType(const char *filename)
{
UBYTE header[4];
int file_length;
FILE *fp = fopen(filename, "rb");
if (fp == NULL)
return AFILE_ERROR;
if (fread(header, 1, 4, fp) != 4) {
fclose(fp);
return AFILE_ERROR;
}
switch (header[0]) {
case 0:
if (header[1] == 0 && (header[2] != 0 || header[3] != 0) /* && file_length < 37 * 1024 */) {
fclose(fp);
return AFILE_BAS;
}
break;
case 0x1f:
if (header[1] == 0x8b) {
#ifndef HAVE_LIBZ
fclose(fp);
Log_print("\"%s\" is a compressed file.", filename);
Log_print("This executable does not support compressed files. You can uncompress this file");
Log_print("with an external program that supports gzip (*.gz) files (e.g. gunzip)");
Log_print("and then load into this emulator.");
return AFILE_ERROR;
#else /* HAVE_LIBZ */
gzFile gzf;
fclose(fp);
gzf = gzopen(filename, "rb");
if (gzf == NULL)
return AFILE_ERROR;
if (gzread(gzf, header, 4) != 4) {
gzclose(gzf);
return AFILE_ERROR;
}
gzclose(gzf);
if (header[0] == 0x96 && header[1] == 0x02)
return AFILE_ATR_GZ;
if (header[0] == 'A' && header[1] == 'T' && header[2] == 'A' && header[3] == 'R')
return AFILE_STATE_GZ;
return AFILE_XFD_GZ;
#endif /* HAVE_LIBZ */
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if ((header[1] >= '0' && header[1] <= '9') || header[1] == ' ') {
fclose(fp);
return AFILE_LST;
}
break;
case 'A':
if (header[1] == 'T' && header[2] == 'A' && header[3] == 'R') {
fclose(fp);
return AFILE_STATE;
}
if (header[1] == 'T' && header[2] == '8' && header[3] == 'X') {
fclose(fp);
return AFILE_ATX;
}
break;
case 'C':
if (header[1] == 'A' && header[2] == 'R' && header[3] == 'T') {
fclose(fp);
return AFILE_CART;
}
break;
case 0x96:
if (header[1] == 0x02) {
fclose(fp);
return AFILE_ATR;
}
break;
case 0xf9:
case 0xfa:
fclose(fp);
return AFILE_DCM;
case 0xff:
if (header[1] == 0xff && (header[2] != 0xff || header[3] != 0xff)) {
fclose(fp);
return AFILE_XEX;
}
break;
default:
break;
}
file_length = Util_flen(fp);
fclose(fp);
/* Detect .pro images */
/* # of sectors is in header */
if ((file_length-16)%(128+12) == 0 &&
header[0]*256 + header[1] == (file_length-16)/(128+12) &&
header[2] == 'P') {
#ifdef DEBUG_PRO
Log_print(".pro file detected");
#endif
return AFILE_PRO;
}
/* 40K or a-power-of-two between 4K and CARTRIDGE_MAX_SIZE */
if (file_length >= 4 * 1024 && file_length <= CARTRIDGE_MAX_SIZE
&& ((file_length & (file_length - 1)) == 0 || file_length == 40 * 1024))
return AFILE_ROM;
/* BOOT_TAPE is a raw file containing a program booted from a tape */
if ((header[1] << 7) == file_length)
return AFILE_BOOT_TAPE;
if ((file_length & 0x7f) == 0)
return AFILE_XFD;
if (IMG_TAPE_FileSupported(header))
return AFILE_CAS;
return AFILE_ERROR;
}
int AFILE_OpenFile(const char *filename, int reboot, int diskno, int readonly)
{
int type = AFILE_DetectFileType(filename);
switch (type) {
case AFILE_ATR:
case AFILE_ATX:
case AFILE_XFD:
case AFILE_ATR_GZ:
case AFILE_XFD_GZ:
case AFILE_DCM:
case AFILE_PRO:
if (!SIO_Mount(diskno, filename, readonly))
return AFILE_ERROR;
if (reboot)
Atari800_Coldstart();
break;
case AFILE_XEX:
case AFILE_BAS:
case AFILE_LST:
if (!BINLOAD_Loader(filename))
return AFILE_ERROR;
break;
case AFILE_CART:
case AFILE_ROM:
{
int r;
if (reboot)
r = CARTRIDGE_InsertAutoReboot(filename);
else
r = CARTRIDGE_Insert(filename);
switch (r) {
case CARTRIDGE_CANT_OPEN:
case CARTRIDGE_BAD_FORMAT:
return AFILE_ERROR;
case CARTRIDGE_BAD_CHECKSUM:
case 0:
/* ok */
break;
default:
#ifdef BASIC
Log_print("Raw cartridge images are not supported in BASIC version.");
return AFILE_ERROR;
#else /* BASIC */
/* r > 0 */
#ifndef ANDROID
CARTRIDGE_SetTypeAutoReboot(&CARTRIDGE_main, UI_SelectCartType(r));
#else
return (r << 8) | AFILE_ROM;
#endif /* ANDROID */
break;
#endif /* BASIC */
}
}
break;
case AFILE_CAS:
case AFILE_BOOT_TAPE:
if (!CASSETTE_Insert(filename))
return AFILE_ERROR;
if (reboot) {
CASSETTE_hold_start = TRUE;
Atari800_Coldstart();
}
break;
case AFILE_STATE:
case AFILE_STATE_GZ:
#ifdef BASIC
Log_print("State files are not supported in BASIC version");
return AFILE_ERROR;
#else
if (!StateSav_ReadAtariState(filename, "rb"))
return AFILE_ERROR;
/* Don't press Start nor Option */
GTIA_consol_override = 0;
break;
#endif
default:
break;
}
return type;
}
+50
View File
@@ -0,0 +1,50 @@
#ifndef AFILE_H_
#define AFILE_H_
/* File types returned by AFILE_DetectFileType() and AFILE_OpenFile(). */
#define AFILE_ERROR 0
#define AFILE_ATR 1
#define AFILE_XFD 2
#define AFILE_ATR_GZ 3
#define AFILE_XFD_GZ 4
#define AFILE_DCM 5
#define AFILE_XEX 6
#define AFILE_BAS 7
#define AFILE_LST 8
#define AFILE_CART 9
#define AFILE_ROM 10
#define AFILE_CAS 11
#define AFILE_BOOT_TAPE 12
#define AFILE_STATE 13
#define AFILE_STATE_GZ 14
#define AFILE_PRO 15
#define AFILE_ATX 16
/* ATR format header */
struct AFILE_ATR_Header {
unsigned char magic1;
unsigned char magic2;
unsigned char seccountlo;
unsigned char seccounthi;
unsigned char secsizelo;
unsigned char secsizehi;
unsigned char hiseccountlo;
unsigned char hiseccounthi;
unsigned char gash[7];
unsigned char writeprotect;
};
/* First two bytes of an ATR file. */
#define AFILE_ATR_MAGIC1 0x96
#define AFILE_ATR_MAGIC2 0x02
/* Auto-detects file type and returns one of AFILE_* values. */
int AFILE_DetectFileType(const char *filename);
/* Auto-detects file type and mounts the file in the emulator.
reboot: Atari800_Coldstart() for disks, cartridges and tapes
diskno: drive number for disks (1-8)
readonly: mount disks as read-only */
int AFILE_OpenFile(const char *filename, int reboot, int diskno, int readonly);
#endif /* AFILE_H_ */
+255
View File
@@ -0,0 +1,255 @@
#ifndef AKEY_H_
#define AKEY_H_
/* akey.h: Atari key codes */
/* INPUT_key_code values */
#define AKEY_NONE -1
/* Special key codes. */
#define AKEY_WARMSTART -2
#define AKEY_COLDSTART -3
#define AKEY_EXIT -4
#define AKEY_BREAK -5
#define AKEY_UI -7
#define AKEY_SCREENSHOT -8
#define AKEY_SCREENSHOT_INTERLACE -9
#define AKEY_START -10
#define AKEY_SELECT -11
#define AKEY_OPTION -12
#define AKEY_PBI_BB_MENU -13
#define AKEY_CX85_1 -14
#define AKEY_CX85_2 -15
#define AKEY_CX85_3 -16
#define AKEY_CX85_4 -17
#define AKEY_CX85_5 -18
#define AKEY_CX85_6 -19
#define AKEY_CX85_7 -20
#define AKEY_CX85_8 -21
#define AKEY_CX85_9 -22
#define AKEY_CX85_0 -23
#define AKEY_CX85_PERIOD -24
#define AKEY_CX85_MINUS -25
#define AKEY_CX85_PLUS_ENTER -26
#define AKEY_CX85_ESCAPE -27
#define AKEY_CX85_NO -28
#define AKEY_CX85_DELETE -29
#define AKEY_CX85_YES -30
#define AKEY_TURBO -31
#ifdef USE_UI_BASIC_ONSCREEN_KEYBOARD
#define AKEY_KEYB -32
#endif
#ifdef DIRECTX
/* special menu directives */
#define AKEY32_MENU_SAVE_CONFIG -107
#define AKEY32_UI_MOUSE_CLICK -108
#endif
#define AKEY_SHFT 0x40
#define AKEY_CTRL 0x80
#define AKEY_SHFTCTRL 0xc0
#define AKEY_0 0x32
#define AKEY_1 0x1f
#define AKEY_2 0x1e
#define AKEY_3 0x1a
#define AKEY_4 0x18
#define AKEY_5 0x1d
#define AKEY_6 0x1b
#define AKEY_7 0x33
#define AKEY_8 0x35
#define AKEY_9 0x30
#define AKEY_CTRL_0 (AKEY_CTRL | AKEY_0)
#define AKEY_CTRL_1 (AKEY_CTRL | AKEY_1)
#define AKEY_CTRL_2 (AKEY_CTRL | AKEY_2)
#define AKEY_CTRL_3 (AKEY_CTRL | AKEY_3)
#define AKEY_CTRL_4 (AKEY_CTRL | AKEY_4)
#define AKEY_CTRL_5 (AKEY_CTRL | AKEY_5)
#define AKEY_CTRL_6 (AKEY_CTRL | AKEY_6)
#define AKEY_CTRL_7 (AKEY_CTRL | AKEY_7)
#define AKEY_CTRL_8 (AKEY_CTRL | AKEY_8)
#define AKEY_CTRL_9 (AKEY_CTRL | AKEY_9)
#define AKEY_a 0x3f
#define AKEY_b 0x15
#define AKEY_c 0x12
#define AKEY_d 0x3a
#define AKEY_e 0x2a
#define AKEY_f 0x38
#define AKEY_g 0x3d
#define AKEY_h 0x39
#define AKEY_i 0x0d
#define AKEY_j 0x01
#define AKEY_k 0x05
#define AKEY_l 0x00
#define AKEY_m 0x25
#define AKEY_n 0x23
#define AKEY_o 0x08
#define AKEY_p 0x0a
#define AKEY_q 0x2f
#define AKEY_r 0x28
#define AKEY_s 0x3e
#define AKEY_t 0x2d
#define AKEY_u 0x0b
#define AKEY_v 0x10
#define AKEY_w 0x2e
#define AKEY_x 0x16
#define AKEY_y 0x2b
#define AKEY_z 0x17
#define AKEY_A (AKEY_SHFT | AKEY_a)
#define AKEY_B (AKEY_SHFT | AKEY_b)
#define AKEY_C (AKEY_SHFT | AKEY_c)
#define AKEY_D (AKEY_SHFT | AKEY_d)
#define AKEY_E (AKEY_SHFT | AKEY_e)
#define AKEY_F (AKEY_SHFT | AKEY_f)
#define AKEY_G (AKEY_SHFT | AKEY_g)
#define AKEY_H (AKEY_SHFT | AKEY_h)
#define AKEY_I (AKEY_SHFT | AKEY_i)
#define AKEY_J (AKEY_SHFT | AKEY_j)
#define AKEY_K (AKEY_SHFT | AKEY_k)
#define AKEY_L (AKEY_SHFT | AKEY_l)
#define AKEY_M (AKEY_SHFT | AKEY_m)
#define AKEY_N (AKEY_SHFT | AKEY_n)
#define AKEY_O (AKEY_SHFT | AKEY_o)
#define AKEY_P (AKEY_SHFT | AKEY_p)
#define AKEY_Q (AKEY_SHFT | AKEY_q)
#define AKEY_R (AKEY_SHFT | AKEY_r)
#define AKEY_S (AKEY_SHFT | AKEY_s)
#define AKEY_T (AKEY_SHFT | AKEY_t)
#define AKEY_U (AKEY_SHFT | AKEY_u)
#define AKEY_V (AKEY_SHFT | AKEY_v)
#define AKEY_W (AKEY_SHFT | AKEY_w)
#define AKEY_X (AKEY_SHFT | AKEY_x)
#define AKEY_Y (AKEY_SHFT | AKEY_y)
#define AKEY_Z (AKEY_SHFT | AKEY_z)
#define AKEY_CTRL_a (AKEY_CTRL | AKEY_a)
#define AKEY_CTRL_b (AKEY_CTRL | AKEY_b)
#define AKEY_CTRL_c (AKEY_CTRL | AKEY_c)
#define AKEY_CTRL_d (AKEY_CTRL | AKEY_d)
#define AKEY_CTRL_e (AKEY_CTRL | AKEY_e)
#define AKEY_CTRL_f (AKEY_CTRL | AKEY_f)
#define AKEY_CTRL_g (AKEY_CTRL | AKEY_g)
#define AKEY_CTRL_h (AKEY_CTRL | AKEY_h)
#define AKEY_CTRL_i (AKEY_CTRL | AKEY_i)
#define AKEY_CTRL_j (AKEY_CTRL | AKEY_j)
#define AKEY_CTRL_k (AKEY_CTRL | AKEY_k)
#define AKEY_CTRL_l (AKEY_CTRL | AKEY_l)
#define AKEY_CTRL_m (AKEY_CTRL | AKEY_m)
#define AKEY_CTRL_n (AKEY_CTRL | AKEY_n)
#define AKEY_CTRL_o (AKEY_CTRL | AKEY_o)
#define AKEY_CTRL_p (AKEY_CTRL | AKEY_p)
#define AKEY_CTRL_q (AKEY_CTRL | AKEY_q)
#define AKEY_CTRL_r (AKEY_CTRL | AKEY_r)
#define AKEY_CTRL_s (AKEY_CTRL | AKEY_s)
#define AKEY_CTRL_t (AKEY_CTRL | AKEY_t)
#define AKEY_CTRL_u (AKEY_CTRL | AKEY_u)
#define AKEY_CTRL_v (AKEY_CTRL | AKEY_v)
#define AKEY_CTRL_w (AKEY_CTRL | AKEY_w)
#define AKEY_CTRL_x (AKEY_CTRL | AKEY_x)
#define AKEY_CTRL_y (AKEY_CTRL | AKEY_y)
#define AKEY_CTRL_z (AKEY_CTRL | AKEY_z)
#define AKEY_CTRL_A (AKEY_CTRL | AKEY_A)
#define AKEY_CTRL_B (AKEY_CTRL | AKEY_B)
#define AKEY_CTRL_C (AKEY_CTRL | AKEY_C)
#define AKEY_CTRL_D (AKEY_CTRL | AKEY_D)
#define AKEY_CTRL_E (AKEY_CTRL | AKEY_E)
#define AKEY_CTRL_F (AKEY_CTRL | AKEY_F)
#define AKEY_CTRL_G (AKEY_CTRL | AKEY_G)
#define AKEY_CTRL_H (AKEY_CTRL | AKEY_H)
#define AKEY_CTRL_I (AKEY_CTRL | AKEY_I)
#define AKEY_CTRL_J (AKEY_CTRL | AKEY_J)
#define AKEY_CTRL_K (AKEY_CTRL | AKEY_K)
#define AKEY_CTRL_L (AKEY_CTRL | AKEY_L)
#define AKEY_CTRL_M (AKEY_CTRL | AKEY_M)
#define AKEY_CTRL_N (AKEY_CTRL | AKEY_N)
#define AKEY_CTRL_O (AKEY_CTRL | AKEY_O)
#define AKEY_CTRL_P (AKEY_CTRL | AKEY_P)
#define AKEY_CTRL_Q (AKEY_CTRL | AKEY_Q)
#define AKEY_CTRL_R (AKEY_CTRL | AKEY_R)
#define AKEY_CTRL_S (AKEY_CTRL | AKEY_S)
#define AKEY_CTRL_T (AKEY_CTRL | AKEY_T)
#define AKEY_CTRL_U (AKEY_CTRL | AKEY_U)
#define AKEY_CTRL_V (AKEY_CTRL | AKEY_V)
#define AKEY_CTRL_W (AKEY_CTRL | AKEY_W)
#define AKEY_CTRL_X (AKEY_CTRL | AKEY_X)
#define AKEY_CTRL_Y (AKEY_CTRL | AKEY_Y)
#define AKEY_CTRL_Z (AKEY_CTRL | AKEY_Z)
#define AKEY_HELP 0x11
#define AKEY_DOWN 0x8f
#define AKEY_LEFT 0x86
#define AKEY_RIGHT 0x87
#define AKEY_UP 0x8e
#define AKEY_BACKSPACE 0x34
#define AKEY_DELETE_CHAR 0xb4
#define AKEY_DELETE_LINE 0x74
#define AKEY_INSERT_CHAR 0xb7
#define AKEY_INSERT_LINE 0x77
#define AKEY_ESCAPE 0x1c
#define AKEY_ATARI 0x27
#define AKEY_CAPSLOCK 0x7c
#define AKEY_CAPSTOGGLE 0x3c
#define AKEY_TAB 0x2c
#define AKEY_SETTAB 0x6c
#define AKEY_CLRTAB 0xac
#define AKEY_RETURN 0x0c
#define AKEY_SPACE 0x21
#define AKEY_EXCLAMATION 0x5f
#define AKEY_DBLQUOTE 0x5e
#define AKEY_HASH 0x5a
#define AKEY_DOLLAR 0x58
#define AKEY_PERCENT 0x5d
#define AKEY_AMPERSAND 0x5b
#define AKEY_QUOTE 0x73
#define AKEY_AT 0x75
#define AKEY_PARENLEFT 0x70
#define AKEY_PARENRIGHT 0x72
#define AKEY_LESS 0x36
#define AKEY_GREATER 0x37
#define AKEY_EQUAL 0x0f
#define AKEY_QUESTION 0x66
#define AKEY_MINUS 0x0e
#define AKEY_PLUS 0x06
#define AKEY_ASTERISK 0x07
#define AKEY_SLASH 0x26
#define AKEY_COLON 0x42
#define AKEY_SEMICOLON 0x02
#define AKEY_COMMA 0x20
#define AKEY_FULLSTOP 0x22
#define AKEY_UNDERSCORE 0x4e
#define AKEY_BRACKETLEFT 0x60
#define AKEY_BRACKETRIGHT 0x62
#define AKEY_CIRCUMFLEX 0x47
#define AKEY_BACKSLASH 0x46
#define AKEY_BAR 0x4f
#define AKEY_CLEAR (AKEY_SHFT | AKEY_LESS)
#define AKEY_CARET (AKEY_SHFT | AKEY_ASTERISK)
#define AKEY_F1 0x03
#define AKEY_F2 0x04
#define AKEY_F3 0x13
#define AKEY_F4 0x14
/* Following keys cannot be read with both shift and control pressed:
J K L ; + * Z X C V B F1 F2 F3 F4 HELP */
/* 5200 key codes */
#define AKEY_5200_START 0x39
#define AKEY_5200_PAUSE 0x31
#define AKEY_5200_RESET 0x29
#define AKEY_5200_0 0x25
#define AKEY_5200_1 0x3f
#define AKEY_5200_2 0x3d
#define AKEY_5200_3 0x3b
#define AKEY_5200_4 0x37
#define AKEY_5200_5 0x35
#define AKEY_5200_6 0x33
#define AKEY_5200_7 0x2f
#define AKEY_5200_8 0x2d
#define AKEY_5200_9 0x2b
#define AKEY_5200_HASH 0x23
#define AKEY_5200_ASTERISK 0x27
#endif /* AKEY_H_ */
+3
View File
@@ -0,0 +1,3 @@
ppc-amigaos-objs
Atari800
Atari800.debug
+109
View File
@@ -0,0 +1,109 @@
@DATABASE "Atari800.guide"
@$VER: Atari800.guide 1.0 (23.03.00)
@AUTHOR Sebastian Bauer
@(C) ©2000
@NODE MAIN "Atari800 - Guide"
@SMARTWRAP
@{b}Atari800 1.0 @{AMIGAGUIDE}@{ub}
Note that the @{" guide author's " link CONTACTING} native language is German. So please
forgive any spelling and gramer mistakes. Or better correct them and send them
to @{" me " link CONTACTING}.
@{b}Attention!@{ub} This guide is designed for use with version 40 of the
amigaguide.datatype which is supplied with AmigaOS 3.1. Under other versions
this guide may look @{b}"less than optimal"@{ub}. Note further that if you
are presently running Kickstart 3.0, you may @{b}still@{ub} use Workbench
3.1 with it, including the newer amigaguide.datatype.
@{CODE}
@{" Copyright " link COPYRIGHT} Copyright and disclaimer
@{" Introduction " link INTRO} What does it do ?
@{" Requirements " link REQUIRE} What does it need ?
@{" Installation " link INSTALL} How to install (and remove) ?
@{" Usage " link USAGE} How to use it?
@{" Contacting " link CONTACTING } Where to send bug reports ?
@ENDNODE
@NODE COPYRIGHT "Atari800 - Copyright and disclamer"
@SMARTWRAP
@{b}Copyright@{ub}
Copyright (C) 1995 David Firth. E-Mail: david@signus.demon.co.uk
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
@{" GNU General Public License " link COPYING/main}
@ENDNODE
@NODE INTRO "Atari800 - Introduction"
@SMARTWRAP
@{b}Introduction@{ub}
@ENDNODE
@NODE REQUIRE "Atari800 - Requirements"
@SMARTWRAP
@{b}Requirements@{ub}
The Amiga port of the Emulator requires a 68020 processor, OS3.0 and
MUI3.8. For sound support AHI is needed.
It also requires the Atari ROMs.
@ENDNODE
@NODE INSTALL "Atari800 - Installation"
@SMARTWRAP
@{b}How to install Atari800@{ub}
To install Atari800 simply copy the whole Atari800 drawer to the destination of your
choice. The ROM files must be in the copied in the same directory (but this can
be also changed).
@ENDNODE
@NODE USAGE "Atari800 - Usage"
@SMARTWRAP
@{b}Usage@{ub}
Sorry, but not written yet.
@ENDNODE
@NODE CONTACTING "Atari800 - Contacting"
@SMARTWRAP
@{b}Contacting@{ub}
The Amiga port of the Atari800 emulator was created by Sebastian Bauer.
Any comments which are related to the Amiga version should be sent to@{LINE}
@{" sebauer@t-online.de " system "YAM:YAM MAILTO sebauer@t-online.de NOCHECK"} or @{" Sebastian.Bauer@in.stud.tu-ilmenau.de " system "YAM:YAM MAILTO Sebastian.Bauer@in.stud.tu-ilmenau.de NOCHECK"}@{LINE}
The latest version of the emulator can be obtained from my homepage:@{LINE}
@{" http://home.t-online.de/home/sebauer/english.html " system "C:OpenURL http://home.t-online.de/home/sebauer/english.html"}
Also look on the official Atari800 Emulator support page at:
@{" http://cas3.zlin.vutbr.cz/~stehlik/a800.htm " system "C:OpenURL http://cas3.zlin.vutbr.cz/~stehlik/a800.htm"}
@ENDNODE
+6
View File
@@ -0,0 +1,6 @@
#define VERSION 2
#define REVISION 1
#define DATE "30.03.2009"
#define VERS "Atari800 2.1.0"
#define VSTRING "Atari800 2.1.0 (30.03.2009)\r\n"
#define VERSTAG "\0$VER: Atari800 2.1.0 (30.03.2009)"
+18
View File
@@ -0,0 +1,18 @@
VERSION EQU 2
REVISION EQU 4
DATE MACRO
dc.b '31.03.2009'
ENDM
VERS MACRO
dc.b 'Atari800 2.1'
ENDM
VSTRING MACRO
dc.b 'Atari800 2.1 (31.03.2009)',13,10,0
ENDM
VERSTAG MACRO
dc.b 0,'$VER: Atari800 2.1 (31.03.2009)',0
ENDM
+1
View File
@@ -0,0 +1 @@
1
+21
View File
@@ -0,0 +1,21 @@
VERSION = 2
REVISION = 1
.macro DATE
.ascii "31.03.2009"
.endm
.macro VERS
.ascii "Atari800 2.1"
.endm
.macro VSTRING
.ascii "Atari800 2.1 (31.03.2009)"
.byte 13,10,0
.endm
.macro VERSTAG
.byte 0
.ascii "$VER: Atari800 2.1 (31.03.2009)"
.byte 0
.endm
+79
View File
@@ -0,0 +1,79 @@
Short: V2.4 of the Atari 8-bit emulator
Uploader: mail@sebastianbauer.info (Sebastian Bauer)
Author: mail@sebastianbauer.info (Sebastian Bauer), Atari800 Emulator Development Team
Type: misc/emu
Kurz: V2.4 des Atari 8-bit Emulator
Requires: OS4
Version: 2.4
This is the Amiga port of the Atari800 Emulator. It requires at
least OS4 (e.g. the prerelease CD).
Install
~~~~~~~
Extract the archive and copy the resulting Atari800 drawer
anywhere you like. Later, copy the ROM Files into the ROMs
directory. Those ROMs can be extracted from an old XFormer
Archive. See http://atari800.sourceforge.net for details.
From there you find also the information how to obtain the
source code which is released under the GPL.
History
~~~~~~~
Version 2.4 (16.3.2005)
- matches version 1.3.6 of original sources
Version 2.3 (29.12.2004)
- matches version 1.3.4 of original sources
Version 2.2 (8.10.2004)
- the workbench window is now an appwindow. Drop in a file to
boot/run its contents
- tries to start a given workbench argument
- added an iconify option (menu entry and title gadget)
Version 2.1 (24.09.2004)
- major changes within the Amiga front end, including
o) ported to OS4, requires PPC processor
o) dropped MUI GUI, GUI is now menu driven
o) dropped overlay support for now
o) Atari joystick can be mapped to the keyboard
o) sound fixes
- matches 1.3.3 of original sources
Version 1.2 (15.10.2000)
- compiled the latest source
- a special 68060 version has been added
Version 1.1 (12.06.2000)
- console keys and sound should work better now
Version 1.0 (31.05.2000)
- initial public release
How can you reach me?
~~~~~~~~~~~~~~~~~~~~~
My e-mail address is:
mail@sebastianbauer.info
Address:
Sebastian Bauer
Neustädter Str. 50
07768 Kahla
Germany
Visit my homepage at
http://www.sebastianbauer.info/
Here you can find the latest version of the Atari800 emulator for
Amiga but also other things for Amiga, for example SimpleFind3,
SimpleHTML, SimplePac and the Freeciv Port.
Also look at the offical Atari800 Emulator homepage at
http://atari800.sourceforce.net/
__
/ /
__ / / Only Amiga makes it possible...
\ \/ /
\__/
File diff suppressed because it is too large Load Diff
+70
View File
@@ -0,0 +1,70 @@
#ifndef _ATARI_AMIGA_H_
#define _ATARI_AMIGA_H_
LONG InsertROM(LONG CartType);
LONG InsertDisk( LONG Drive );
VOID FreeDisplay(void);
LONG SetupDisplay(void);
VOID Iconify(void);
enum{
MEN_PROJECT=1,
MEN_PROJECT_ABOUT,
MEN_PROJECT_LOADSTATE,
MEN_PROJECT_SAVESTATE,
MEN_PROJECT_LOADBIN,
MEN_PROJECT_ICONIFY,
MEN_PROJECT_QUIT,
MEN_SYSTEM,
MEN_SYSTEM_BOOT,
MEN_SYSTEM_ID,
MEN_SYSTEM_ID1,
MEN_SYSTEM_ID2,
MEN_SYSTEM_ID3,
MEN_SYSTEM_ID4,
MEN_SYSTEM_ID5,
MEN_SYSTEM_ID6,
MEN_SYSTEM_ID7,
MEN_SYSTEM_ID8,
MEN_SYSTEM_ED,
MEN_SYSTEM_ED1,
MEN_SYSTEM_ED2,
MEN_SYSTEM_ED3,
MEN_SYSTEM_ED4,
MEN_SYSTEM_ED5,
MEN_SYSTEM_ED6,
MEN_SYSTEM_ED7,
MEN_SYSTEM_ED8,
MEN_SYSTEM_UI,
MEN_CONSOLE,
MEN_CONSOLE_OPTION,
MEN_CONSOLE_SELECT,
MEN_CONSOLE_START,
MEN_CONSOLE_HELP,
MEN_CONSOLE_BREAK,
MEN_CONSOLE_RESET,
MEN_CONSOLE_COLDSTART,
MEN_SETTINGS,
MEN_SETTINGS_FRAMERATE,
MEN_SETTINGS_CUSTOMSCREEN,
MEN_SETTINGS_WINDOW,
MEN_SETTINGS_SCALABLEWINDOW,
MEN_SETTINGS_SAVE,
MEN_SETTINGS_PORT0_GAMEPORT,
MEN_SETTINGS_PORT0_NUMERICPAD,
MEN_SETTINGS_PORT0_CURSORKEYS,
MEN_SETTINGS_PORT0_UNASSIGNED,
MEN_SETTINGS_PORT1_GAMEPORT,
MEN_SETTINGS_PORT1_NUMERICPAD,
MEN_SETTINGS_PORT1_CURSORKEYS,
MEN_SETTINGS_PORT1_UNASSIGNED,
};
#endif /* _ATARI_AMIGA_H_ */
+133
View File
@@ -0,0 +1,133 @@
; atari_asm.asm - Amiga specific port code
;
; Copyright (c) 2000 Sebastian Bauer
; Copyright (C) 2000-2003 Atari800 development team (see DOC/CREDITS)
;
; This file is part of the Atari800 emulator project which emulates
; the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
;
; Atari800 is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; Atari800 is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with Atari800; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
MC68020
XDEF _ScreenData28bit
; a0 - UBYTE *screen
; a1 - UBYTE *destscreendata
; a2 - UBYTE *colortable8
; d0 - UWORD width
; d1 - UWORD height
_ScreenData28bit:
movem.l d2/d7,-(a7)
lsr.w #2,d0
subq.l #1,d1
subq.l #1,d0
moveq #0,d2
; moveq #0,d3
; moveq #0,d4
; moveq #0,d5
.heightloop: move.l d0,d7
.widthloop:
; move.b (a0)+,d2
; move.b (a0)+,d3
; move.b (a0)+,d4
; move.b (a0)+,d5
; move.b (a2,d2),(a1)+
; move.b (a2,d3),(a1)+
; move.b (a2,d4),(a1)+
; move.b (a2,d5),(a1)+
move.b (a0)+,d2
move.b (a2,d2),(a1)+
move.b (a0)+,d2
move.b (a2,d2),(a1)+
move.b (a0)+,d2
move.b (a2,d2),(a1)+
move.b (a0)+,d2
move.b (a2,d2),(a1)+
; moveq #0,d3
; moveq #0,d5
; move.b (a0)+,d2
; move.b (a2,d2),d3
; move.b (a0)+,d2
; lsl.w #8,d3
; move.b (a2,d2),d4
; move.b (a0)+,d2
; or.w d4,d3
; move.b (a2,d2),d5
; swap d3
; move.b (a0)+,d2
; lsl.w #8,d5
; move.b (a2,d2),d3
; or.w d5,d3
; move.l d3,(a1)+
dbra d7,.widthloop
dbra d1,.heightloop
movem.l (a7)+,d2/d7
rts
XDEF _ScreenData215bit
; a0 - UBYTE *screen
; a1 - UWORD *destscreendata
; a2 - UWORD *colortable15
; d0 - UWORD width
; d1 - UWORD height
_ScreenData215bit:
movem.l d2/d3/d7,-(a7)
lsr.l #1,d0
subq.l #1,d1
subq.l #1,d0
moveq #0,d2
.heightloop: move.l d0,d7
.widthloop:
move.b (a0)+,d2
move.w (a2,d2*2),d3
move.b (a0)+,d2
swap d3
move.w (a2,d2*2),d3
move.l d3,(a1)+
dbra d7,.widthloop
dbra d1,.heightloop
movem.l (a7)+,d2/d3/d7
rts
end
+17
View File
@@ -0,0 +1,17 @@
#ifndef _AMIGA_ASM_H_
#define _AMIGA_ASM_H_
ASM void ScreenData28bit( register __a0 UBYTE *screen,
register __a1 UBYTE *tempscreendata,
register __a2 UBYTE *colortable8,
register __d0 ULONG width,
register __d1 ULONG height);
ASM void ScreenData215bit( register __a0 UBYTE *screen,
register __a1 UWORD *,
register __a2 UWORD *colortable15,
register __d0 ULONG width,
register __d1 ULONG height);
#endif /* _AMIGA_ASM_H_ */
+579
View File
@@ -0,0 +1,579 @@
/*
* async.c - async I/O code
*
* Copyright (c) 2000 Sebastian Bauer
* Copyright (c) 2000-2003 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "async.h"
//-------------------------------------
// AS_OpenAsnycFH
#ifdef ASIO_NOEXTERNALS
AsyncFile*
AS_OpenAsyncFH(
BPTR handle,
OpenModes mode,
LONG bufferSize,
BOOL closeIt,
struct ExecBase *SysBase,
struct DosLibrary *DOSBase )
#else
AsyncFile *
AS_OpenAsyncFH( BPTR handle, OpenModes mode, LONG bufferSize, BOOL closeIt )
#endif
{
struct FileHandle *fh;
AsyncFile *file = NULL;
BPTR lock = NULL;
LONG blockSize, blockSize2;
D_S( struct InfoData, infoData );
if( mode == MODE_READ )
{
if( handle )
{
lock = DupLockFromFH( handle );
}
}
else
{
if( mode == MODE_APPEND )
{
/* in append mode, we open for writing, and then seek to the
* end of the file. That way, the initial write will happen at
* the end of the file, thus extending it
*/
if( handle )
{
if( Seek( handle, 0, OFFSET_END ) < 0 )
{
if( closeIt )
{
Close( handle );
}
handle = NULL;
}
}
}
/* we want a lock on the same device as where the file is. We can't
* use DupLockFromFH() for a write-mode file though. So we get sneaky
* and get a lock on the parent of the file
*/
if( handle )
{
lock = ParentOfFH( handle );
}
}
if( handle )
{
/* if it was possible to obtain a lock on the same device as the
* file we're working on, get the block size of that device and
* round up our buffer size to be a multiple of the block size.
* This maximizes DMA efficiency.
*/
blockSize = 512;
blockSize2 = 1024;
if( lock )
{
if( Info( lock, infoData ) )
{
blockSize = infoData->id_BytesPerBlock;
blockSize2 = blockSize * 2;
bufferSize = ( ( bufferSize + blockSize2 - 1 ) / blockSize2 ) * blockSize2;
}
UnLock(lock);
}
/* now allocate the ASyncFile structure, as well as the read buffers.
* Add 15 bytes to the total size in order to allow for later
* quad-longword alignement of the buffers
*/
for( ;; )
{
if(( file = AllocVec( sizeof( AsyncFile ) + bufferSize + 15, MEMF_PUBLIC | MEMF_ANY ) ))
{
break;
}
else
{
if( bufferSize > blockSize2 )
{
bufferSize -= blockSize2;
}
else
{
break;
}
}
}
if( file )
{
file->af_File = handle;
file->af_ReadMode = ( mode == MODE_READ );
file->af_BlockSize = blockSize;
file->af_CloseFH = closeIt;
/* initialize the ASyncFile structure. We do as much as we can here,
* in order to avoid doing it in more critical sections
*
* Note how the two buffers used are quad-longword aligned. This
* helps performance on 68040 systems with copyback cache. Aligning
* the data avoids a nasty side-effect of the 040 caches on DMA.
* Not aligning the data causes the device driver to have to do
* some magic to avoid the cache problem. This magic will generally
* involve flushing the CPU caches. This is very costly on an 040.
* Aligning things avoids the need for magic, at the cost of at
* most 15 bytes of ram.
*/
fh = BADDR( file->af_File );
file->af_Handler = fh->fh_Type;
file->af_BufferSize = ( ULONG ) bufferSize / 2;
file->af_Buffers[ 0 ] = ( APTR ) ( ( ( ULONG ) file + sizeof( AsyncFile ) + 15 ) & 0xfffffff0 );
file->af_Buffers[ 1 ] = file->af_Buffers[ 0 ] + file->af_BufferSize;
file->af_CurrentBuf = 0;
file->af_SeekOffset = 0;
file->af_PacketPending = FALSE;
file->af_SeekPastEOF = FALSE;
#ifdef ASIO_NOEXTERNALS
file->af_SysBase = SysBase;
file->af_DOSBase = DOSBase;
#endif
/* this is the port used to get the packets we send out back.
* It is initialized to PA_IGNORE, which means that no signal is
* generated when a message comes in to the port. The signal bit
* number is initialized to SIGB_SINGLE, which is the special bit
* that can be used for one-shot signalling. The signal will never
* be set, since the port is of type PA_IGNORE. We'll change the
* type of the port later on to PA_SIGNAL whenever we need to wait
* for a message to come in.
*
* The trick used here avoids the need to allocate an extra signal
* bit for the port. It is quite efficient.
*/
file->af_PacketPort.mp_MsgList.lh_Head = ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Tail;
file->af_PacketPort.mp_MsgList.lh_Tail = NULL;
file->af_PacketPort.mp_MsgList.lh_TailPred = ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Head;
file->af_PacketPort.mp_Node.ln_Type = NT_MSGPORT;
/* MH: Avoid problems with SnoopDos */
file->af_PacketPort.mp_Node.ln_Name = NULL;
file->af_PacketPort.mp_Flags = PA_IGNORE;
file->af_PacketPort.mp_SigBit = SIGB_SINGLE;
file->af_PacketPort.mp_SigTask = FindTask( NULL );
file->af_Packet.sp_Pkt.dp_Link = &file->af_Packet.sp_Msg;
file->af_Packet.sp_Pkt.dp_Arg1 = fh->fh_Arg1;
file->af_Packet.sp_Pkt.dp_Arg3 = file->af_BufferSize;
file->af_Packet.sp_Pkt.dp_Res1 = 0;
file->af_Packet.sp_Pkt.dp_Res2 = 0;
file->af_Packet.sp_Msg.mn_Node.ln_Name = ( STRPTR ) &file->af_Packet.sp_Pkt;
file->af_Packet.sp_Msg.mn_Node.ln_Type = NT_MESSAGE;
file->af_Packet.sp_Msg.mn_Length = sizeof( struct StandardPacket );
if( mode == MODE_READ )
{
/* if we are in read mode, send out the first read packet to
* the file system. While the application is getting ready to
* read data, the file system will happily fill in this buffer
* with DMA transfers, so that by the time the application
* needs the data, it will be in the buffer waiting
*/
file->af_Packet.sp_Pkt.dp_Type = ACTION_READ;
file->af_BytesLeft = 0;
/* MH: We set the offset to the buffer not being filled, in
* order to avoid special case code in SeekAsync. ReadAsync
* isn't affected by this, since af_BytesLeft == 0.
*/
file->af_Offset = file->af_Buffers[ 1 ];
if( file->af_Handler )
{
AS_SendPacket( file, file->af_Buffers[ 0 ] );
}
}
else
{
file->af_Packet.sp_Pkt.dp_Type = ACTION_WRITE;
file->af_BytesLeft = file->af_BufferSize;
file->af_Offset = file->af_Buffers[ 0 ];
}
}
else
{
if( closeIt )
{
Close( handle );
}
}
}
return( file );
}
//-------------------------------------
// AS_SendPacket
/* send out an async packet to the file system. */
VOID
AS_SendPacket( struct AsyncFile *file, APTR arg2 )
{
#ifdef ASIO_NOEXTERNALS
struct ExecBase *SysBase;
SysBase = file->af_SysBase;
#endif
file->af_Packet.sp_Pkt.dp_Port = &file->af_PacketPort;
file->af_Packet.sp_Pkt.dp_Arg2 = ( LONG ) arg2;
PutMsg( file->af_Handler, &file->af_Packet.sp_Msg );
file->af_PacketPending = TRUE;
}
//-------------------------------------
// AS_WaitPacket
/* this function waits for a packet to come back from the file system. If no
* packet is pending, state from the previous packet is returned. This ensures
* that once an error occurs, it state is maintained for the rest of the life
* of the file handle.
*
* This function also deals with IO errors, bringing up the needed DOS
* requesters to let the user retry an operation or cancel it.
*/
LONG
AS_WaitPacket( AsyncFile *file )
{
#ifdef ASIO_NOEXTERNALS
struct ExecBase *SysBase = file->af_SysBase;
struct DosLibrary *DOSBase = file->af_DOSBase;
#endif
LONG bytes;
if( file->af_PacketPending )
{
while( TRUE )
{
/* This enables signalling when a packet comes back to the port */
file->af_PacketPort.mp_Flags = PA_SIGNAL;
/* Wait for the packet to come back, and remove it from the message
* list. Since we know no other packets can come in to the port, we can
* safely use Remove() instead of GetMsg(). If other packets could come in,
* we would have to use GetMsg(), which correctly arbitrates access in such
* a case
*/
Remove( ( struct Node * ) WaitPort( &file->af_PacketPort ) );
/* set the port type back to PA_IGNORE so we won't be bothered with
* spurious signals
*/
file->af_PacketPort.mp_Flags = PA_IGNORE;
/* mark packet as no longer pending since we removed it */
file->af_PacketPending = FALSE;
bytes = file->af_Packet.sp_Pkt.dp_Res1;
if( bytes >= 0 )
{
/* packet didn't report an error, so bye... */
return( bytes );
}
/* see if the user wants to try again... */
if( ErrorReport( file->af_Packet.sp_Pkt.dp_Res2, REPORT_STREAM, file->af_File, NULL ) )
{
return( -1 );
}
/* user wants to try again, resend the packet */
AS_SendPacket( file,
file->af_Buffers[ file->af_ReadMode ?
file->af_CurrentBuf :
1 - file->af_CurrentBuf ] );
}
}
/* last packet's error code, or 0 if packet was never sent */
SetIoErr( file->af_Packet.sp_Pkt.dp_Res2 );
return( file->af_Packet.sp_Pkt.dp_Res1 );
}
//-------------------------------------
// AS_RequeuePacket( AsyncFile *file )
/* this function puts the packet back on the message list of our
* message port.
*/
VOID
AS_RequeuePacket( AsyncFile *file )
{
#ifdef ASIO_NOEXTERNALS
struct ExecBase *SysBase = file->af_SysBase;
#endif
AddHead( &file->af_PacketPort.mp_MsgList, &file->af_Packet.sp_Msg.mn_Node );
file->af_PacketPending = TRUE;
}
//-------------------------------------
//-------------------------------------
// AsyncFile *OpenAsync()
#ifdef ASIO_NOEXTERNALS
_LIBCALL AsyncFile *
OpenAsync(
_REG( a0 ) const STRPTR fileName,
_REG( d0 ) OpenModes mode,
_REG( d1 ) LONG bufferSize,
_REG( a1 ) struct ExecBase *SysBase,
_REG( a2 ) struct DosLibrary *DOSBase )
#else
_LIBCALL AsyncFile *
OpenAsync(
_REG( a0 ) const STRPTR fileName,
_REG( d0 ) OpenModes mode,
_REG( d1 ) LONG bufferSize )
#endif
{
static const WORD PrivateOpenModes[] =
{
MODE_OLDFILE, MODE_NEWFILE, MODE_READWRITE
};
BPTR handle;
AsyncFile *file = NULL;
if(( handle = Open( fileName, PrivateOpenModes[ mode ] ) ))
{
#ifdef ASIO_NOEXTERNALS
file = AS_OpenAsyncFH( handle, mode, bufferSize, TRUE, SysBase, DOSBase );
#else
file = AS_OpenAsyncFH( handle, mode, bufferSize, TRUE );
#endif
if( !file )
{
Close( handle );
}
}
return( file );
}
//-------------------------------------
// LONG CloseAsync(AsyncFile *file )
_LIBCALL LONG
CloseAsync( _REG( a0 ) AsyncFile *file )
{
LONG result;
if( file )
{
#ifdef ASIO_NOEXTERNALS
struct ExecBase *SysBase = file->af_SysBase;
struct DosLibrary *DOSBase = file->af_DOSBase;
#endif
result = AS_WaitPacket( file );
if( result >= 0 )
{
if( !file->af_ReadMode )
{
/* this will flush out any pending data in the write buffer */
if( file->af_BufferSize > file->af_BytesLeft )
{
result = Write(
file->af_File,
file->af_Buffers[ file->af_CurrentBuf ],
file->af_BufferSize - file->af_BytesLeft );
}
}
}
if( file->af_CloseFH )
{
Close( file->af_File );
}
FreeVec(file);
}
else
{
#ifndef ASIO_NOEXTERNALS
SetIoErr( ERROR_INVALID_LOCK );
#endif
result = -1;
}
return( result );
}
//-------------------------------------
// LONG WriteAsync( AsyncFile *file, APTR buffer, LONG numBytes )
_LIBCALL LONG
WriteAsync( _REG( a0 ) AsyncFile *file, _REG( a1 ) APTR buffer, _REG( d0 ) LONG numBytes )
{
#ifdef ASIO_NOEXTERNALS
struct ExecBase *SysBase = file->af_SysBase;
#endif
LONG totalBytes = 0;
/* this takes care of NIL: */
if( !file->af_Handler )
{
file->af_Offset = file->af_Buffers[ 0 ];
file->af_BytesLeft = file->af_BufferSize;
return( numBytes );
}
while( numBytes > file->af_BytesLeft )
{
if( file->af_BytesLeft )
{
CopyMem( buffer, file->af_Offset, file->af_BytesLeft );
numBytes -= file->af_BytesLeft;
buffer = ( APTR ) ( ( ULONG ) buffer + file->af_BytesLeft );
totalBytes += file->af_BytesLeft;
}
if( AS_WaitPacket( file ) < 0 )
{
return( -1 );
}
/* send the current buffer out to disk */
AS_SendPacket( file, file->af_Buffers[ file->af_CurrentBuf ] );
file->af_CurrentBuf = 1 - file->af_CurrentBuf;
file->af_Offset = file->af_Buffers[ file->af_CurrentBuf ];
file->af_BytesLeft = file->af_BufferSize;
}
CopyMem( buffer, file->af_Offset, numBytes );
file->af_BytesLeft -= numBytes;
file->af_Offset += numBytes;
return ( totalBytes + numBytes );
}
//-------------------------------------
// LONG WriteCharAsync( AsyncFile *file, UBYTE ch )
_CALL LONG
WriteCharAsync( _REG( a0 ) AsyncFile *file, _REG( d0 ) UBYTE ch )
{
if( file->af_BytesLeft )
{
/* if there's any room left in the current buffer, directly write
* the byte into it, updating counters and stuff.
*/
*file->af_Offset = ch;
--file->af_BytesLeft;
++file->af_Offset;
/* one byte written */
return( 1 );
}
/* there was no room in the current buffer, so call the main write
* routine. This will effectively send the current buffer out to disk,
* wait for the other buffer to come back, and then put the byte into
* it.
*/
{
TEXT c;
c = ch; /* SAS/C workaround... */
return( WriteAsync( file, &c, 1 ) );
}
}
//-------------------------------------
// LONG ReadAsync( AsyncFile *file, APTR buffer, LONG numBytes )
_LIBCALL LONG
ReadAsync( _REG( a0 ) AsyncFile *file, _REG( a1 ) APTR buffer, _REG( d0 ) LONG numBytes )
{
#ifdef ASIO_NOEXTERNALS
struct ExecBase *SysBase = file->af_SysBase;
#endif
LONG totalBytes = 0;
LONG bytesArrived;
/* if we need more bytes than there are in the current buffer, enter the
* read loop
*/
while( numBytes > file->af_BytesLeft )
{
/* drain buffer */
CopyMem( file->af_Offset, buffer, file->af_BytesLeft );
numBytes -= file->af_BytesLeft;
buffer = ( APTR ) ( ( ULONG ) buffer + file->af_BytesLeft );
totalBytes += file->af_BytesLeft;
file->af_BytesLeft = 0;
bytesArrived = AS_WaitPacket( file );
if( bytesArrived <= 0 )
{
if( bytesArrived == 0 )
{
return( totalBytes );
}
return( -1 );
}
/* ask that the buffer be filled */
AS_SendPacket( file, file->af_Buffers[ 1 - file->af_CurrentBuf ] );
/* in case we tried to seek past EOF */
if( file->af_SeekOffset > bytesArrived )
{
file->af_SeekOffset = bytesArrived;
}
file->af_Offset = file->af_Buffers[ file->af_CurrentBuf ] + file->af_SeekOffset;
file->af_CurrentBuf = 1 - file->af_CurrentBuf;
file->af_BytesLeft = bytesArrived - file->af_SeekOffset;
file->af_SeekOffset = 0;
}
CopyMem( file->af_Offset, buffer, numBytes );
file->af_BytesLeft -= numBytes;
file->af_Offset += numBytes;
return( totalBytes + numBytes );
}
//-------------------------------------
+87
View File
@@ -0,0 +1,87 @@
#ifndef _ASYNC_H_
#define _ASYNC_H_
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <clib/asyncio_protos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>
/*****************************************************************************/
#ifdef _DCC
#ifdef ASIO_SHARED_LIB
#define _LIBCALL __geta4 _ASM _ARGS
#else
#define _LIBCALL _ASM _ARGS
#endif
#else
#ifdef __GNUC__
#define _LIBCALL
#else
#ifdef __MAXON__
#define _LIBCALL
#else /* __SASC__ */
#ifdef ASIO_SHARED_LIB
#define _LIBCALL __saveds _ASM _ARGS
#else
#define _LIBCALL _ASM _ARGS
#endif
#endif
#endif /* _ GNUC_ */
#endif /* _DCC */
#define _CALL _ASM _ARGS
/*****************************************************************************/
#ifndef ASIO_NOEXTERNALS
extern struct DosLibrary *DOSBase;
extern struct ExecBase *SysBase;
#endif
#ifdef ASIO_SHARED_LIB
extern struct ExecBase *SysBase;
extern struct Library *UtilityBase;
extern struct DosLibrary *DOSBase;
#endif
/*****************************************************************************/
/* this macro lets us long-align structures on the stack */
#define D_S(type,name) char a_##name[ sizeof( type ) + 3 ]; \
type *name = ( type * ) ( ( LONG ) ( a_##name + 3 ) & ~3 );
#ifndef MIN
#define MIN(a,b) ( ( a ) < ( b ) ? ( a ) : ( b ) )
#endif
/*****************************************************************************/
#ifdef ASIO_NOEXTERNALS
AsyncFile *
AS_OpenAsyncFH( BPTR handle, OpenModes mode, LONG bufferSize, BOOL closeIt, struct ExecBase *SysBase, struct DosLibrary *DOSBase );
#else
AsyncFile *
AS_OpenAsyncFH( BPTR handle, OpenModes mode, LONG bufferSize, BOOL closeIt );
#endif
VOID AS_SendPacket( AsyncFile *file, APTR arg2 );
LONG AS_WaitPacket( AsyncFile *file );
VOID AS_RequeuePacket( AsyncFile *file );
VOID AS_RecordSyncFailure( AsyncFile *file );
#endif /* _ASYNC_H_ */
+428
View File
@@ -0,0 +1,428 @@
#ifndef CONFIG_H
#define CONFIG_H
/* Define to use back slash as directory separator. */
#undef BACK_SLASH
/* Target: standard I/O. */
#undef BASIC
/* Define to use buffered debug output. */
#undef BUFFERED_LOG
/* Define to allow sound clipping. */
#undef CLIP_SOUND
/* Define to 1 if the `closedir' function returns void instead of `int'. */
#undef CLOSEDIR_VOID
/* Define to allow console sound (keyboard clicks). */
#define CONSOLE_SOUND 1
/* Define to activate crash menu after CIM instruction. */
#define CRASH_MENU 1
/* Define to disable bitmap graphics emulation in CURSES target. */
#undef CURSES_BASIC
/* Alternate config filename due to 8+3 fs limit. */
#define DEFAULT_CFG_NAME "PROGDIR:Atari800.cfg"
/* Target: Windows with DirectX. */
#undef DIRECTX
/* Target: DOS VGA. */
#undef DOSVGA
/* Define to enable DOS style drives support. */
#undef DOS_DRIVES
/* Target: Atari Falcon system. */
#undef FALCON
/* Define to use m68k assembler CPU core for Falcon target. */
#undef FALCON_CPUASM
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
/* Define to 1 if you have the `atexit' function. */
#define HAVE_ATEXIT 1
/* Define to 1 if you have the `chmod' function. */
#define HAVE_CHMOD 1
/* Define to 1 if you have the `clock' function. */
#define HAVE_CLOCK 1
/* Define to 1 if you have the <direct.h> header file. */
#undef HAVE_DIRECT_H
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
#define HAVE_DIRENT_H 1
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
#undef HAVE_DOPRNT
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `fdopen' function. */
#define HAVE_FDOPEN 1
/* Define to 1 if you have the `fflush' function. */
#define HAVE_FFLUSH 1
/* Define to 1 if you have the <file.h> header file. */
#undef HAVE_FILE_H
/* Define to 1 if you have the `floor' function. */
#define HAVE_FLOOR 1
/* Define to 1 if you have the `fstat' function. */
#define HAVE_FSTAT 1
/* Define to 1 if you have the `getcwd' function. */
#define HAVE_GETCWD 1
/* Define to 1 if you have the `gethostbyaddr' function. */
#undef HAVE_GETHOSTBYADDR
/* Define to 1 if you have the `gethostbyname' function. */
#undef HAVE_GETHOSTBYNAME
/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the `inet_ntoa' function. */
#undef HAVE_INET_NTOA
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `png' library (-lpng). */
/*#define HAVE_LIBPNG 1*/
/* Define to 1 if you have the `z' library (-lz). */
/*#define HAVE_LIBZ 1*/
/* Define to 1 if you have the `localtime' function. */
#define HAVE_LOCALTIME 1
/* Define to 1 if you have the `memmove' function. */
#define HAVE_MEMMOVE 1
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the `mkdir' function. */
#define HAVE_MKDIR 1
/* Define to 1 if you have the `mkstemp' function. */
#define HAVE_MKSTEMP 1
/* Define to 1 if you have the `mktemp' function. */
#define HAVE_MKTEMP 1
/* Define to 1 if you have the `modf' function. */
#define HAVE_MODF 1
/* Define to 1 if you have the `nanosleep' function. */
#undef HAVE_NANOSLEEP
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H
/* Define to 1 if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H
/* Define to 1 if you have the <netinet/in.h> header file. */
#undef HAVE_NETINET_IN_H
/* Define to 1 if you have the `opendir' function. */
#define HAVE_OPENDIR 1
/* Define to 1 if you have the `rename' function. */
#define HAVE_RENAME 1
/* Define to 1 if you have the `rewind' function. */
#define HAVE_REWIND 1
/* Define to 1 if you have the `rmdir' function. */
#define HAVE_RMDIR 1
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if you have the `signal' function. */
#define HAVE_SIGNAL 1
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the `snprintf' function. */
#define HAVE_SNPRINTF 1
/* Define to 1 if you have the `socket' function. */
#undef HAVE_SOCKET
/* Define to 1 if you have the `stat' function. */
#define HAVE_STAT 1
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
#undef HAVE_STAT_EMPTY_STRING_BUG
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strcasecmp' function. */
#define HAVE_STRCASECMP 1
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strrchr' function. */
#define HAVE_STRRCHR 1
/* Define to 1 if you have the `strstr' function. */
#define HAVE_STRSTR 1
/* Define to 1 if you have the `strtol' function. */
#define HAVE_STRTOL 1
/* Define to 1 if you have the `system' function. */
//#define HAVE_SYSTEM 1
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_DIR_H
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_NDIR_H
/* Define to 1 if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <sys/soundcard.h> header file. */
#undef HAVE_SYS_SOUNDCARD_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <termios.h> header file. */
#define HAVE_TERMIOS_H 1
/* Define to 1 if you have the `time' function. */
#define HAVE_TIME 1
/* Define to 1 if you have the <time.h> header file. */
#define HAVE_TIME_H 1
/* Define to 1 if you have the `tmpfile' function. */
#define HAVE_TMPFILE 1
/* Define to 1 if you have the `tmpnam' function. */
#define HAVE_TMPNAM 1
/* Define to 1 if you have the `uclock' function. */
#define HAVE_UCLOCK 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <unixio.h> header file. */
#undef HAVE_UNIXIO_H
/* Define to 1 if you have the `unlink' function. */
#define HAVE_UNLINK 1
/* Define to 1 if you have the `usleep' function. */
#define HAVE_USLEEP 1
/* Define to 1 if you have the `vprintf' function. */
#define HAVE_VPRINTF 1
/* Define to 1 if you have the `vsnprintf' function. */
#define HAVE_VSNPRINTF 1
/* define to enable sound interpolation */
#define INTERPOLATE_SOUND 1
/* Define to use LINUX joystick. */
#undef LINUX_JOYSTICK
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
/* Define to activate assembler in monitor. */
#define MONITOR_ASSEMBLER 1
/* Define to activate BREAK command in monitor. */
#undef MONITOR_BREAK
/* Define to activate user-defined breakpoints. */
#undef MONITOR_BREAKPOINTS
/* Define to activate hints in disassembler. */
#define MONITOR_HINTS 1
/* Target: X11 with Motif. */
#undef MOTIF
/* Define to allow color changes inside a scanline. */
#define NEW_CYCLE_EXACT 1
/* Define to use page-based attribute array. */
#undef PAGED_ATTRIB
/* Target: Sony PlayStation 2. */
#undef PS2
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* Define to use R: device. */
#undef R_IO_DEVICE
/* Target: SDL library. */
#undef SDL
/* Define to the type of arg 1 for `select'. */
#undef SELECT_TYPE_ARG1
/* Define to the type of args 2, 3 and 4 for `select'. */
#undef SELECT_TYPE_ARG234
/* Define to the type of arg 5 for `select'. */
#undef SELECT_TYPE_ARG5
/* Define to allow serial in/out sound. */
#define SERIO_SOUND 1
/* Target: X11 with shared memory extensions. */
#undef SHM
/* Define to activate sound support. */
#define SOUND 1
#define SOUND_GAIN 2
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to allow stereo sound. */
#define STEREO 1
#define STEREO_SOUND 1
/* Save additional config file options. */
#define SUPPORTS_ATARI_CONFIGSAVE 1
/* Additional config file options. */
#define SUPPORTS_ATARI_CONFIGURE 1
/* Target: Linux with SVGALib. */
#undef SVGALIB
/* Define to use Toshiba Joystick Mouse support. */
#undef SVGA_JOYMOUSE
/* Define for drawing every 1/50 sec only 1/refresh of screen. */
#undef SVGA_SPEEDUP
/* Alternate system-wide config file for non-Unix OS. */
#undef SYSTEM_WIDE_CFG_FILE
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
/* Define to use clock() instead of gettimeofday(). */
#undef USE_CLOCK
/* Target: Curses-compatible library. */
#undef USE_CURSES
/* Define for using cursor/ctrl keys for keyboard joystick. */
#undef USE_CURSORBLOCK
/* Target: Ncurses library. */
#undef USE_NCURSES
/* Define to use very slow computer support (faster -refresh). */
#undef VERY_SLOW
/* Define to allow volume only sound. */
#undef VOL_ONLY_SOUND
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
#define WORDS_BIGENDIAN 1
/* Define if unaligned word access is ok. */
#undef WORDS_UNALIGNED_OK
/* Target: Standard X11. */
#undef X11
/* Target: X11 with XView. */
#undef XVIEW
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define as `__inline' if that's what the C compiler calls it, or to nothing
if it is not supported. */
#undef inline
/* Define to `unsigned' if <sys/types.h> does not define. */
#undef size_t
/* Define to empty if the keyword `volatile' does not work. Warning: valid
code using `volatile' can become incorrect without. Disable with care. */
#undef volatile
#endif
/* Use Signed Samples in POKEY emulation */
#define SIGNED_SAMPLES 1
/* Define two screen arrays used for switching */
#define BITPL_SCR 1
+322
View File
@@ -0,0 +1,322 @@
/*
* amiga.c - Amiga specific port code
*
* Copyright (c) 2000 Sebastian Bauer
* Copyright (c) 2000-2003 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include <stdio.h>
#include <exec/types.h>
#define ALL_REACTION_CLASSES
#include <reaction/reaction.h>
#include <reaction/reaction_macros.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include "gui.h"
#include "support.h"
struct Library *WindowBase;
struct Library *LayoutBase;
struct Library *ButtonBase;
struct Library *ListBrowserBase;
struct Library *TextEditorBase;
struct Library *LabelBase;
struct Library *StringBase;
struct Library *ScrollerBase;
struct Library *GetFileBase;
struct Library *ChooserBase;
struct Library *ClickTabBase;
struct Library *CheckBoxBase;
struct Library *GetScreenModeBase;
struct WindowIFace *IWindow;
struct LayoutIFace *ILayout;
struct ButtonIFace *IButton;
struct ListBrowserIFace *IListBrowser;
struct TextEditorIFace *ITextEditor;
struct LabelIFace *ILabel;
struct StringIFace *IString;
struct ScrollerIFace *IScroller;
struct GetFileIFace *IGetFile;
struct ChooserIFace *IChooser;
struct ClickTabIFace *IClickTab;
struct CheckBoxIFace *ICheckBox;
struct GetScreenModeIFace *IGetScreenMode;
#define LIBENTRY(name,version,base,iface) {name,version,(struct Library**)base,(struct Interface**) iface}
static struct
{
STRPTR Name;
ULONG Version;
struct Library **Base;
struct Interface **IFace;
} libraries[] =
{
LIBENTRY("window.class",44,&WindowBase,&IWindow),
LIBENTRY("gadgets/getfile.gadget",44,&GetFileBase, &IGetFile),
LIBENTRY("gadgets/layout.gadget",44,&LayoutBase, &ILayout),
LIBENTRY("gadgets/chooser.gadget",45,&ChooserBase, &IChooser),
LIBENTRY("gadgets/clicktab.gadget",44,&ClickTabBase, &IClickTab),
LIBENTRY("gadgets/button.gadget",44,&ButtonBase,&IButton),
LIBENTRY("gadgets/listbrowser.gadget",44,&ListBrowserBase,&IListBrowser),
LIBENTRY("gadgets/texteditor.gadget",50,&TextEditorBase,&ITextEditor),
LIBENTRY("gadgets/string.gadget",44,&StringBase,&IString),
LIBENTRY("gadgets/scroller.gadget",44,&ScrollerBase,&IScroller),
LIBENTRY("gadgets/checkbox.gadget",44,&CheckBoxBase, &ICheckBox),
LIBENTRY("gadgets/getscreenmode.gadget",44,&GetScreenModeBase, &IGetScreenMode),
LIBENTRY("images/label.image",44,&LabelBase,&ILabel),
};
/****************************************
Close libraries
*****************************************/
static void CloseGUILibs(void)
{
int i;
for (i=0;i<sizeof(libraries)/sizeof(libraries[0]);i++)
{
CloseLibraryInterface(*libraries[i].Base,*libraries[i].IFace);
*libraries[i].Base = NULL;
*libraries[i].IFace = NULL;
}
}
/****************************************
Open needed Libraries
*****************************************/
static int OpenGUILibs(void)
{
int i;
for (i=0;i<sizeof(libraries)/sizeof(libraries[0]);i++)
{
if (!(*libraries[i].Base = OpenLibraryInterface(libraries[i].Name,
libraries[i].Version,
libraries[i].IFace)))
{
printf("Unable to open %s version %ld\n",libraries[i].Name,libraries[i].Version);
goto out;
}
}
return 1;
out:
CloseGUILibs();
return 0;
}
/**********************************************************************
Get Attribute easily
***********************************************************************/
static ULONG xget(Object * obj, ULONG attribute)
{
ULONG x;
IIntuition->GetAttr(attribute, obj, (ULONG*)&x);
return (x);
}
/**********************************************************************
Set attributes of a given object.
Difference to RefreshSetGadgetAttrs() is that the parameters are all
Objects.
***********************************************************************/
void RefreshSetObjectAttrsA(Object *o, Object *wo, struct TagItem *tags)
{
struct Gadget *g = (struct Gadget*)o;
struct Window *w = (struct Window*)xget(wo,WINDOW_Window);
if (!o) return;
IIntuition->RefreshSetGadgetAttrsA(g,w,NULL,tags);
}
void VARARGS68K RefreshSetObjectAttrs(Object *o, Object *wo, ...)
{
ULONG *tags;
va_list args;
va_startlinear(args,wo);
tags = va_getlinearva(args,ULONG*);
RefreshSetObjectAttrsA(o,wo,(struct TagItem *)tags);
va_end(args);
}
/****** GUI ********/
static Object *main_wnd;
static Object *displaytype_chooser;
static Object *screenmode_getscreenmode;
//static Object *bestscreenmode_checkbox;
static int quitting;
enum
{
GID_QUIT = 1,
GID_SAVE,
GID_USE
};
/**********************************************************************
Handle
***********************************************************************/
static int Handle(struct AtariConfig *config)
{
int rc = 0;
ULONG result;
UWORD code;
while ((result = RA_HandleInput(main_wnd, &code) ) != WMHI_LASTMSG )
{
switch (result & WMHI_CLASSMASK)
{
case WMHI_CLOSEWINDOW:
rc = 1;
break;
case WMHI_GADGETUP:
switch (result & WMHI_GADGETMASK)
{
case GID_QUIT: rc = 1; quitting = 1; break;
case GID_SAVE: rc = 1; break;
case GID_USE: rc = 1; break;
}
}
}
return rc;
}
/*******************************
Eventlloop
********************************/
static void Loop(struct AtariConfig *config)
{
int ready = 0;
ULONG mainMask;
while (!ready)
{
ULONG mask;
IIntuition->GetAttr(WINDOW_SigMask, main_wnd, &mainMask);
mask = IExec->Wait(SIGBREAKF_CTRL_C | mainMask);
if (mask & mainMask)
ready = Handle(config);
if (mask & SIGBREAKF_CTRL_C) ready = 1;
}
}
/**********************************************************************
Configure atari
***********************************************************************/
BOOL Configure(struct AtariConfig *config)
{
static char * const tabLabels[] = {"General","Graphics","Sound","Paths",NULL};
static char * const screenTypeLabels[] = {"Custom","Window", "Sizeable Window", NULL};
if (!OpenGUILibs()) goto out;
main_wnd = (Object*)WindowObject,
WA_Title, "Atari800",
WA_Activate, TRUE,
WA_DepthGadget, TRUE,
WA_DragBar, TRUE,
WA_CloseGadget, TRUE,
WA_SizeGadget, TRUE,
WA_IDCMP, IDCMP_INTUITICKS,
// WINDOW_IDCMPHook, &idcmpHook,
WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE,
WINDOW_Position, WPOS_CENTERSCREEN,
WINDOW_ParentGroup, VGroupObject,
LAYOUT_SpaceOuter, TRUE,
LAYOUT_DeferLayout, TRUE,
LAYOUT_AddChild, ClickTabObject,
GA_Text, &tabLabels,
CLICKTAB_PageGroup, PageObject,
PAGE_Add, VGroupObject,
EndGroup,
PAGE_Add, VGroupObject, /* Graphics */
LAYOUT_AddChild, displaytype_chooser = ChooserObject,
CHOOSER_LabelArray, screenTypeLabels,
CHOOSER_Selected, 0,
End,
MemberLabel("Displaytype"),
LAYOUT_AddChild, screenmode_getscreenmode = GetScreenModeObject,
End,
MemberLabel("Screenmode"),
CHILD_WeightedHeight, 0,
LAYOUT_AddChild, CheckBoxObject,
CHECKBOX_Checked, config->UseBestID,
End,
MemberLabel("Use best screen mode"),
EndGroup,
CHILD_WeightedHeight, 0,
PAGE_Add, VGroupObject,
LAYOUT_AddChild, CheckBoxObject,
End,
MemberLabel("Enable Sound"),
EndGroup,
PAGE_Add, VGroupObject, /* Sound */
EndGroup,
End, /* Page */
End, /* Clicktab */
LAYOUT_AddChild, HGroupObject,
LAYOUT_AddChild, Button("Start & Save",GID_SAVE),
LAYOUT_AddChild, Button("Start & Use",GID_USE),
LAYOUT_AddChild, Button("Quit",GID_QUIT),
EndGroup,
CHILD_WeightedHeight, 0,
EndGroup,
EndWindow;
if (!main_wnd) goto out;
RA_OpenWindow(main_wnd);
Loop(config);
IIntuition->DisposeObject(main_wnd);
CloseGUILibs();
return quitting?FALSE:TRUE;
out:
IIntuition->DisposeObject(main_wnd);
CloseGUILibs();
return FALSE;
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef _GUI_H
#define _GUI_H
#ifndef EXEC_TYPES_H
#include <exec/types.h>
#endif
struct AtariConfig
{
/* Amiga */
ULONG DisplayType;
ULONG DisplayID;
BOOL UseBestID;
};
BOOL Configure(struct AtariConfig *config);
#endif
+107
View File
@@ -0,0 +1,107 @@
# If Kickstart isn't defined, we don't run on AmigaOS
ifndef Kickstart
CROSS_COMPILE = ppc-amigaos-
RM = rm -R
MKDIR = mkdir -p
else
RM = delete all
MKDIR = makedir
endif
CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
RANLIB = $(CROSS_COMPILE)ranlib
STRIP = $(CROSS_COMPILE)strip
# -------------------------------------------------------------
TARGET = Atari800
VERSION = 2
#CFLAGS = -O3 -I$(AHI_INCLUDE) -I. -I.. -Wall -use-dynld -DSUPPORTS_PLATFORM_CONFIGURE -DSUPPORTS_PLATFORM_CONFIGSAVE
CFLAGS = -O3 -I$(AHI_INCLUDE) -I. -I.. -Wall -DSUPPORTS_PLATFORM_CONFIGURE -DSUPPORTS_PLATFORM_CONFIGSAVE
#LIBS = -lm -lz -lpng -lAuto
LIBS = -lm -lauto
AMIGASRCS=\
amiga.c \
gui.c \
support.c
EMUSRCS= \
afile.c \
antic.c \
artifact.c \
atari.c \
binload.c \
cartridge.c \
cassette.c \
compfile.c \
cfg.c \
colours.c \
colours_external.c \
colours_pal.c \
colours_ntsc.c \
cpu.c \
devices.c \
esc.c \
gtia.c \
log.c \
memory.c \
monitor.c \
pia.c \
pokey.c \
rtime.c \
sio.c \
util.c \
pbi_proto80.c \
input.c \
statesav.c \
ui_basic.c \
ui.c \
screen.c \
cycle_map.c \
pbi_mio.c \
pbi_bb.c \
pbi_scsi.c \
pokeysnd.c \
mzpokeysnd.c \
remez.c \
sndsave.c \
pbi_xld.c \
votrax.c \
votraxsnd.c \
xep80.c \
xep80_fonts.c \
pbi.c
SRCS = $(AMIGASRCS) $(addprefix ../,$(EMUSRCS))
# -------------------------------------------------------------
OBJS = $(SRCS:%.c=ppc-amigaos-objs/amiga/%.o)
AOBJS = $(ASRCS:%.S=ppc-amigaos-objs/amiga/%.o)
all: dirs $(TARGET)
dirs:
-$(MKDIR) ppc-amigaos-objs ppc-amigaos-objs/amiga
# Rules for building
$(TARGET): $(OBJS) $(AOBJS)
$(CC) $(LINK) -o $@.debug $(OBJS) $(AOBJS) $(LIBS)
$(STRIP) -R.comment -o $@ $@.debug
ppc-amigaos-objs/amiga/%.o: %.S
$(CC) -Wa,-mregnames $(AFLAGS) -I$/home/sba/amigaos4/include -c $< -o $@
ppc-amigaos-objs/amiga/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
$(RM) $(TARGET) $(OBJS) ppc-amigaos-objs
.PHONY: revision
revision:
bumprev $(VERSION) $(TARGET)
+258
View File
@@ -0,0 +1,258 @@
/*
* support.c - user interface support code
*
* Copyright (c) 2000 Sebastian Bauer
* Copyright (c) 2000-2003 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define __USE_INLINE__
#define DoSuperMethod IDoSuperMethod
#define DoSuperMethodA IDoSuperMethodA
#define DoMethod IDoMethod
#define DoMethodA IDoMethodA
#include <string.h>
#include <cybergraphx/cybergraphics.h>
#include <libraries/gadtools.h>
#include <clib/alib_protos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/cybergraphics.h>
#include <proto/intuition.h>
/**************************************************************************
Some general supports
**************************************************************************/
LONG StrLen( const STRPTR str)
{
if(str) return (LONG)strlen(str);
return 0;
}
STRPTR StrCopy( const STRPTR str )
{
STRPTR dst;
if( !str ) return NULL;
if( !*str) return NULL;
dst = (STRPTR)AllocVec(strlen(str)+1,0);
if(dst) strcpy(dst,str);
return dst;
}
STRPTR GetFullPath( STRPTR drw, STRPTR file)
{
WORD dl = StrLen(drw);
WORD fl = StrLen( file );
LONG length = dl + fl + 6;
STRPTR fp = (STRPTR)AllocVec( length+1, 0 );
if( fp )
{
strcpy( fp, drw );
if( AddPart( fp, file, length )) return fp;
else FreeVec( fp );
}
return NULL;
}
STRPTR AddSuffix(const STRPTR name, const STRPTR suf)
{
STRPTR str;
if(!strstr(name,suf))
{
LONG len = StrLen(name)+StrLen(suf)+2;
str = (STRPTR)AllocVec(len,0);
if(str)
{
strcpy(str,name);
strcat(str,suf);
}
} else str = StrCopy(name);
return str;
}
ULONG GetBestID( ULONG width, ULONG height, ULONG depth )
{
struct Screen *defscr;
ULONG displayID;
if ((defscr = LockPubScreen(NULL)))
{
struct ViewPort *vp;
vp = &defscr->ViewPort;
displayID = BestModeID( BIDTAG_Depth,depth,
BIDTAG_NominalWidth, width,
BIDTAG_NominalHeight, height,
BIDTAG_MonitorID, GetVPModeID( vp ) & MONITOR_ID_MASK,
TAG_DONE);
if (CyberGfxBase)
{
if (IsCyberModeID(displayID))
{
struct DimensionInfo dims;
/* Get the normal dimensions of the returned displayID */
if (GetDisplayInfoData(NULL,&dims,sizeof(dims),DTAG_DIMS,displayID) > 0)
{
ULONG modeWidth = dims.Nominal.MaxX - dims.Nominal.MinX + 1;
ULONG modeHeight = dims.Nominal.MaxY - dims.Nominal.MinY + 1;
/* If dimensions differ to "much", try to get a better one via cybergfx calls */
if (modeWidth > width * 4 / 3 || modeHeight > height * 4 / 3)
{
displayID = BestCModeIDTags(
CYBRBIDTG_Depth, depth,
CYBRBIDTG_NominalWidth, width,
CYBRBIDTG_NominalHeight, height,
CYBRBIDTG_MonitorID, GetVPModeID( vp ) & MONITOR_ID_MASK,
TAG_DONE);
}
}
}
}
UnlockPubScreen( NULL, defscr );
} else displayID = INVALID_ID;
if (displayID == INVALID_ID)
{
displayID = BestModeID( BIDTAG_Depth,depth,
BIDTAG_NominalWidth, width,
BIDTAG_NominalHeight, height,
TAG_DONE);
}
return displayID;
}
STRPTR GetDisplayName(ULONG displayid)
{
STATIC struct NameInfo DisplayNameInfo;
STATIC char DisplayNameBuffer[256];
LONG i, v;
i = 0;
v = GetDisplayInfoData(NULL, (UBYTE *) &DisplayNameInfo, sizeof(DisplayNameInfo),
DTAG_NAME, displayid);
if(v > sizeof(struct QueryHeader))
{
for(; (i < sizeof(DisplayNameBuffer) - 1) && DisplayNameInfo.Name[i]; i++)
DisplayNameBuffer[i] = DisplayNameInfo.Name[i];
}
if(displayid == INVALID_ID)
strcpy(DisplayNameBuffer, "InvalidID"/*GetMessage(MSG_INVALID)*/);
else
{
if(i < sizeof(DisplayNameBuffer) - sizeof(" (0x00000000)"))
{
DisplayNameBuffer[i++] = ' ';
DisplayNameBuffer[i++] = '(';
DisplayNameBuffer[i++] = '0';
DisplayNameBuffer[i++] = 'x';
for(v = 28; (v >= 0) && (!((displayid >> v) & 0xf)); v -= 4);
if(v < 0)
DisplayNameBuffer[i++] = '0';
for(; (v >= 0); v -= 4)
{
if(((displayid >> v) & 0xf) > 9)
DisplayNameBuffer[i++] = ((displayid >> v) & 0xf) + 'a' - 10;
else
DisplayNameBuffer[i++] = ((displayid >> v) & 0xf) + '0';
}
DisplayNameBuffer[i++] = ')';
}
DisplayNameBuffer[i++] = 0;
}
return DisplayNameBuffer;
}
APTR FindUserData( struct Menu *menu, APTR userdata)
{
while(menu)
{
struct MenuItem *mi;
if(GTMENU_USERDATA( menu ) == userdata) return menu;
mi = menu->FirstItem;
while(mi)
{
struct MenuItem *smi;
if(GTMENUITEM_USERDATA( mi ) == userdata) return mi;
smi = mi->SubItem;
while(smi)
{
if(GTMENUITEM_USERDATA( smi ) == userdata) return smi;
smi = smi->NextItem;
}
mi = mi->NextItem;
}
menu = menu->NextMenu;
}
return NULL;
}
/**************************************************************************
...
**************************************************************************/
struct Library *OpenLibraryInterface(STRPTR name, int version, void *interface_ptr)
{
struct Library *lib = OpenLibrary(name,version);
struct Interface *iface;
if (!lib) return NULL;
iface = GetInterface(lib,"main",1,NULL);
if (!iface)
{
CloseLibrary(lib);
return NULL;
}
*((struct Interface**)interface_ptr) = iface;
return lib;
}
/**************************************************************************
...
**************************************************************************/
void CloseLibraryInterface(struct Library *lib, void *interface)
{
DropInterface(interface);
CloseLibrary(lib);
}
+41
View File
@@ -0,0 +1,41 @@
#ifndef _SUPPORT_H_
#define _SUPPORT_H_
#define InnerWidth(w) (w->Width - w->BorderLeft - w->BorderRight)
#define InnerHeight(w) (w->Height - w->BorderTop - w->BorderBottom)
/* Some MUI Support Functions */
#if 0
LONG xget(Object *obj,ULONG attribute);
char *getstr(Object *obj);
BOOL getbool(Object *obj);
Object *MakeLabel(STRPTR str);
Object *MakeLabel1(STRPTR str);
Object *MakeLabel2(STRPTR str);
Object *MakeLLabel(STRPTR str);
Object *MakeLLabel1(STRPTR str);
Object *MakeCheck(BOOL check);
Object *MakeButton(STRPTR str);
Object *MakeCycle(STRPTR *array);
Object *MakeString(STRPTR def, LONG maxlen);
Object *MakeImageButton(ULONG image);
Object *MakeLV(APTR pool);
ULONG DoSuperNew(struct IClass *cl,Object *obj,ULONG tag1,...);
#define nnsetstring(obj,s) nnset(obj,MUIA_String_Contents,s)
#endif
LONG StrLen( const STRPTR str);
STRPTR StrCopy( const STRPTR str );
STRPTR GetFullPath( STRPTR drw, STRPTR file);
STRPTR AddSuffix(const STRPTR name, const STRPTR suf);
ULONG GetBestID( ULONG width, ULONG height, ULONG depth );
STRPTR GetDisplayName(ULONG displayid);
APTR FindUserData( struct Menu *menu, APTR userdata);
struct Library *OpenLibraryInterface(STRPTR name, int version, void *interface_ptr);
void CloseLibraryInterface(struct Library *lib, void *interface);
#endif /* _SUPPORT_H_ */
+129
View File
@@ -0,0 +1,129 @@
/*
* unixfunc.c - only required for the Maxon compiler
*
* Copyright (c) 2000 Sebastian Bauer
* Copyright (c) 2000-2003 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef __MAXON__
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <pragma/dos_lib.h>
#include <pragma/exec_lib.h>
int __open(const char *name, int mode,...)
{
BPTR fh;
if( mode & O_RDONLY )
{
fh = Open((STRPTR)name,MODE_OLDFILE);
} else
{
if(mode & O_WRONLY)
{
fh = Open((STRPTR)name,MODE_NEWFILE);
} else fh = Open((STRPTR)name, MODE_OLDFILE);
}
if(!fh) fh = (BPTR)-1;
return (int)fh;
}
int __close(int fh)
{
if(fh && fh != -1 ) Close((BPTR)fh);
return 0;
}
int __write(int fh, const void *buffer, unsigned int length)
{
return Write((BPTR)fh,(APTR)buffer,length);
}
int __read(int fh, void *buffer, unsigned int length)
{
int count;
if (fh == -1) return 0;
count = Read((BPTR)fh,buffer,length);
/* if(!count) count = - 1;*/
return count;
}
int unlink(const char *name)
{
DeleteFile((STRPTR)name);
return 0;
}
long lseek(int fh, long rpos, int mode)
{
long origin = mode;
Seek((BPTR)fh,rpos,origin);
return Seek((BPTR)fh,0,OFFSET_CURRENT);
}
char *strdup(const char *s)
{
char *p = malloc(strlen(s)+1);
if(p)
{
strcpy(p,s);
}
return p;
}
char *getcwd(char *b, int size)
{
struct Process *p = (struct Process*)FindTask(NULL);
NameFromLock(p->pr_CurrentDir, b, size);
return b;
}
int stat()
{
return -1;
}
int readdir()
{
return -1;
}
int closedir()
{
return -1;
}
int opendir()
{
return -1;
}
#endif
+27
View File
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="name.nick.jubanka.colleen"
android:installLocation="auto"
android:versionCode="300"
android:versionName="3.0">
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="20"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:label="@string/app_name"
android:icon="@drawable/icon">
<activity
android:name="MainActivity"
android:label="@string/app_name"
android:theme="@style/MainTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".FileSelector"/>
<activity android:name=".Preferences"/>
</application>
</manifest>
+92
View File
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="colleen" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>
+47
View File
@@ -0,0 +1,47 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := atari800
A800_CORE_OBJS := \
afile.o \
antic.o \
atari.o \
binload.o \
cartridge.o \
cassette.o \
compfile.o \
cfg.o \
cpu.o \
crc32.o \
devices.o \
emuos.o \
esc.o \
gtia.o \
img_tape.o \
log.o \
memory.o \
monitor.o \
pbi.o \
pia.o \
pokey.o \
rtime.o \
sio.o \
sysrom.o \
util.o \
@OBJS@
A800_CORE_LIBS := @LIBS@
ANDROID_SRCS := platform.c \
sound.c \
graphics.c \
jni.c \
androidinput.c
ANDROID_LIBS := -llog -lGLESv1_CM
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../..
LOCAL_SRC_FILES := $(A800_CORE_OBJS:%.o=../../%.c) $(ANDROID_SRCS)
LOCAL_LDLIBS := $(A800_CORE_LIBS) $(ANDROID_LIBS)
include $(BUILD_SHARED_LIBRARY)
+1
View File
@@ -0,0 +1 @@
APP_PLATFORM := android-9
+547
View File
@@ -0,0 +1,547 @@
/*
* androidinput.c - handle touch & keyboard events from android
*
* Copyright (C) 2010 Kostas Nakos
* Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <pthread.h>
#include "input.h"
#include "akey.h"
#include "pokey.h"
#include "graphics.h"
#include "androidinput.h"
#include "keys.inc"
#define HIT_OPACITY 0.6f
#define POTLIMIT 228
#define KBD_MAXKEYS (1 << 4)
#define KBD_MASK (KBD_MAXKEYS - 1)
struct touchstate
{
int x;
int y;
int s;
};
enum
{
PTRSTL = -1,
PTRJOY = 0,
PTRTRG,
MAXPOINTERS
};
/* always: pointer 0 is joystick pointer, 1 is fire pointer */
static struct touchstate prevtc[MAXPOINTERS];
static int prevconptr;
int Android_Joyleft = TRUE;
float Android_Splitpct = 0.5f;
int Android_Split;
int Android_Paddle = FALSE;
SWORD Android_POTX = 0;
SWORD Android_POTY = 0;
int Android_PlanetaryDefense = FALSE;
UBYTE Android_ReversePddle = 0;
struct joy_overlay_state AndroidInput_JoyOvl;
struct consolekey_overlay_state AndroidInput_ConOvl;
UWORD Android_PortStatus;
UBYTE Android_TrigStatus;
static int Android_Keyboard[KBD_MAXKEYS];
static int key_head = 0, key_tail = 0;
static int Android_key_control;
static pthread_mutex_t key_mutex = PTHREAD_MUTEX_INITIALIZER;
static key_last = AKEY_NONE;
static const int derot_lut[2][4] =
{
{ KEY_RIGHT, KEY_LEFT, KEY_UP, KEY_DOWN }, /* derot left */
{ KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP } /* derot right */
};
UBYTE softjoymap[SOFTJOY_MAXKEYS + SOFTJOY_MAXACTIONS][2] =
{
{ KEY_LEFT, INPUT_STICK_LEFT },
{ KEY_RIGHT, INPUT_STICK_RIGHT },
{ KEY_UP, INPUT_STICK_FORWARD },
{ KEY_DOWN, INPUT_STICK_BACK },
{ '2', 0 },
{ ACTION_NONE, AKEY_NONE },
{ ACTION_NONE, AKEY_NONE },
{ ACTION_NONE, AKEY_NONE }
};
int Android_SoftjoyEnable = TRUE;
int Android_DerotateKeys = 0;
int Android_TouchEvent(int x1, int y1, int s1, int x2, int y2, int s2)
{
int joyptr; /* will point to joystick touch of input set */
int tmpfire; /* flag: both pointers on fire side */
int dx, dy, dx2, dy2;
struct touchstate newtc[MAXPOINTERS];
UBYTE newjoy, newtrig;
struct joy_overlay_state *jovl;
struct consolekey_overlay_state *covl;
int conptr; /* will point to stolen ptr, PTRSTL otherwise */
int i;
float a, potx, poty;
int ret = 0;
jovl = &AndroidInput_JoyOvl;
covl = &AndroidInput_ConOvl;
prevtc[PTRJOY].x = jovl->joyarea.l + ((jovl->joyarea.r - jovl->joyarea.l) >> 1);
prevtc[PTRJOY].y = jovl->joyarea.t + ((jovl->joyarea.b - jovl->joyarea.t) >> 1);
/* establish joy ptr & fire ptr for new input */
/* note: looks complicated & uses boolean magick but gets rid of a labyrinth of ifs :-) */
if ((x1 >= Android_Split) ^ (x2 >= Android_Split)) { /* pointers on opposite sides */
joyptr = (x1 < Android_Split) ^ Android_Joyleft;
} else { /* both pointers either on joystick or on fire side */
tmpfire = (x1 >= Android_Split) ^ (!Android_Joyleft); /* both pointers on fire side */
dx = (x1 - prevtc[tmpfire].x); /* figure out which is closer to previous */
dx2 = (x2 - prevtc[tmpfire].x);
dy = (y1 - prevtc[tmpfire].y);
dy2 = (y2 - prevtc[tmpfire].y);
joyptr = ((dx2*dx2 + dy2*dy2) > (dx*dx + dy*dy)) ^ !tmpfire;
s1 &= joyptr ^ (!tmpfire); /* unpress unrelated touch */
s2 &= !(joyptr ^ (!tmpfire));
}
if (joyptr) {
newtc[PTRTRG].x = x1; newtc[PTRTRG].y = y1; newtc[PTRTRG].s = s1;
newtc[PTRJOY].x = x2; newtc[PTRJOY].y = y2; newtc[PTRJOY].s = s2;
} else {
newtc[PTRJOY].x = x1; newtc[PTRJOY].y = y1; newtc[PTRJOY].s = s1;
newtc[PTRTRG].x = x2; newtc[PTRTRG].y = y2; newtc[PTRTRG].s = s2;
}
if (newtc[PTRJOY].s || newtc[PTRTRG].s)
ret = 1;
/* console keys */
conptr = PTRSTL;
covl->hitkey = CONK_NOKEY;
if (covl->ovl_visible >= COVL_READY) { /* first a quick bounding box check */
if (newtc[PTRJOY].s &&
newtc[PTRJOY].x >= covl->bbox.l &&
newtc[PTRJOY].x < covl->bbox.r &&
newtc[PTRJOY].y >= covl->bbox.t &&
newtc[PTRJOY].y < covl->bbox.b)
conptr = PTRJOY; /* implicit: mask fire by joy pointer */
else if (newtc[PTRTRG].s &&
newtc[PTRTRG].x >= covl->bbox.l &&
newtc[PTRTRG].x < covl->bbox.r &&
newtc[PTRTRG].y >= covl->bbox.t &&
newtc[PTRTRG].y < covl->bbox.b)
conptr = PTRTRG;
if (conptr != PTRSTL) { /* if bb is exact on top & bottom => check only horiz/lly */
dy = covl->keycoo[i + 1] - newtc[conptr].y;
for (i = 0; i < CONK_VERT_MAX; i += 8) {
a = ((float) covl->keycoo[i + 6] - covl->keycoo[i ]) /
((float) covl->keycoo[i + 1] - covl->keycoo[i + 7]);
dx = covl->keycoo[i] + a * dy;
if (newtc[conptr].x < dx) continue; /* off left edge */
a = ((float) covl->keycoo[i + 4] - covl->keycoo[i + 2]) /
((float) covl->keycoo[i + 3] - covl->keycoo[i + 5]);
dx = covl->keycoo[i + 2] + a * dy;
if (newtc[conptr].x > dx) continue; /* off right edge */
covl->hitkey = i / 8; /* hit inside */
break;
}
if (covl->hitkey != CONK_NOKEY) {
covl->opacity = COVL_MAX_OPACITY;
covl->statecnt = COVL_HOLD_TIME;
covl->ovl_visible = COVL_READY;
switch (covl->hitkey) {
case CONK_START:
INPUT_key_consol = INPUT_CONSOL_NONE ^ INPUT_CONSOL_START;
break;
case CONK_SELECT:
INPUT_key_consol = INPUT_CONSOL_NONE ^ INPUT_CONSOL_SELECT;
break;
case CONK_OPTION:
INPUT_key_consol = INPUT_CONSOL_NONE ^ INPUT_CONSOL_OPTION;
break;
case CONK_HELP:
Keyboard_Enqueue(AKEY_HELP);
break;
/* RESET is handled at the overlay update */
}
} else {
conptr = PTRSTL; /* didn't hit - let others handle it */
}
}
if (prevconptr != PTRSTL && conptr == PTRSTL) { /* unpressed overlay key */
if (Keyboard_Peek() == AKEY_HELP)
Keyboard_Enqueue(AKEY_NONE);
INPUT_key_consol = INPUT_CONSOL_NONE;
covl->resetcnt = 0;
}
} else if (newtc[PTRJOY].s && newtc[PTRJOY].x > Android_ScreenW - covl->hotlen
&& newtc[PTRJOY].y < covl->hotlen) {
covl->ovl_visible = COVL_FADEIN; /* touched overlay hotspot */
conptr = PTRJOY;
} else if (newtc[PTRTRG].s && newtc[PTRTRG].x > Android_ScreenW - covl->hotlen
&& newtc[PTRTRG].y < covl->hotlen) {
covl->ovl_visible = COVL_FADEIN;
conptr = PTRTRG;
}
if (conptr == PTRSTL)
if (newtc[PTRJOY].s &&
( (!prevtc[PTRJOY].s && newtc[PTRJOY].y < covl->hotlen) || /* menu area */
prevconptr != PTRSTL) && /* still held */
!(covl->ovl_visible != COVL_HIDDEN &&
newtc[PTRJOY].x >= covl->bbox.l - COVL_SHADOW_OFF && /* outside bbox */
newtc[PTRJOY].y <= covl->bbox.b + COVL_SHADOW_OFF) ) {
conptr = PTRJOY; /* touched menu area */
ret = 2;
} else if (newtc[PTRTRG].s &&
( (!prevtc[PTRTRG].s && newtc[PTRTRG].y < covl->hotlen) ||
prevconptr != PTRSTL) &&
!(covl->ovl_visible != COVL_HIDDEN &&
newtc[PTRTRG].x >= covl->bbox.l - COVL_SHADOW_OFF &&
newtc[PTRTRG].y <= covl->bbox.b + COVL_SHADOW_OFF) ) {
conptr = PTRTRG;
ret = 2;
}
/* joystick */
newjoy = INPUT_STICK_CENTRE;
if (newtc[PTRJOY].s && conptr != PTRJOY) {
if (!Android_Paddle) {
dx2 = (jovl->joyarea.r - jovl->joyarea.l) >> 1;
dy2 = (jovl->joyarea.b - jovl->joyarea.t) >> 1;
dx = dx2 - dx2 * jovl->deadarea;
dy = dy2 - dy2 * jovl->deadarea;
dx2 = (jovl->joyarea.r - jovl->joyarea.l) * jovl->gracearea;
}
if (Android_Paddle) {
potx = ((float) (newtc[PTRJOY].x - jovl->joyarea.l)) /
((float) (jovl->joyarea.r - jovl->joyarea.l));
poty = (float) newtc[PTRJOY].y / (float) Android_ScreenH;
Android_POTX = POTLIMIT - (UBYTE) (potx * ((float) POTLIMIT) + 0.5f);
Android_POTY = POTLIMIT - (UBYTE) (poty * ((float) POTLIMIT) + 0.5f);
if (Android_ReversePddle & 1)
Android_POTX = POTLIMIT - Android_POTX;
if (Android_ReversePddle & 2)
Android_POTY = POTLIMIT - Android_POTY;
if (Android_POTX < 0) Android_POTX = 0;
if (Android_POTY < 0) Android_POTY = 0;
if (Android_POTX > POTLIMIT) Android_POTX = POTLIMIT;
if (Android_POTY > POTLIMIT) Android_POTY = POTLIMIT;
jovl->joystick.x = newtc[PTRJOY].x;
jovl->joystick.y = newtc[PTRJOY].y;
jovl->stickopacity = HIT_OPACITY;
if (!jovl->anchor) {
dy = (jovl->joyarea.b - jovl->joyarea.t) >> 1;
if (newtc[PTRJOY].y - dy < 0) newtc[PTRJOY].y -= newtc[PTRJOY].y - dy;
if (newtc[PTRJOY].y + dy > Android_ScreenH)
newtc[PTRJOY].y -= newtc[PTRJOY].y + dy - Android_ScreenH;
jovl->joyarea.t = newtc[PTRJOY].y - dy;
jovl->joyarea.b = newtc[PTRJOY].y + dy;
jovl->areaopacitycur = jovl->areaopacityset;
jovl->areaopacityfrm = 0;
}
} else if ( (newtc[PTRJOY].x >= jovl->joyarea.l - dx2 &&
newtc[PTRJOY].x <= jovl->joyarea.r + dx2 &&
newtc[PTRJOY].y >= jovl->joyarea.t - dx2 &&
newtc[PTRJOY].y <= jovl->joyarea.b + dx2) ||
jovl->anchor ) {
if (newtc[PTRJOY].x <= jovl->joyarea.l + dx) {
newjoy &= INPUT_STICK_LEFT;
} else if (newtc[PTRJOY].x >= jovl->joyarea.r - dx) {
newjoy &= INPUT_STICK_RIGHT;
}
if (newtc[PTRJOY].y <= jovl->joyarea.t + dy) {
newjoy &= INPUT_STICK_FORWARD;
} else if (newtc[PTRJOY].y >= jovl->joyarea.b - dy) {
newjoy &= INPUT_STICK_BACK;
}
if (!jovl->anchor) {
if (newtc[PTRJOY].x > jovl->joyarea.r) { /* grace area */
dx = newtc[PTRJOY].x - jovl->joyarea.r;
jovl->joyarea.l += dx;
jovl->joyarea.r += dx;
} else if (newtc[PTRJOY].x < jovl->joyarea.l) {
dx = jovl->joyarea.l - newtc[PTRJOY].x;
jovl->joyarea.r -= dx;
jovl->joyarea.l -= dx;
}
if (newtc[PTRJOY].y > jovl->joyarea.b) {
dy = newtc[PTRJOY].y - jovl->joyarea.b;
jovl->joyarea.t += dy;
jovl->joyarea.b += dy;
} else if (newtc[PTRJOY].y < jovl->joyarea.t) {
dy = jovl->joyarea.t - newtc[PTRJOY].y;
jovl->joyarea.b -= dy;
jovl->joyarea.t -= dy;
}
}
jovl->joystick.x = newtc[PTRJOY].x;
jovl->joystick.y = newtc[PTRJOY].y;
jovl->stickopacity = HIT_OPACITY;
jovl->areaopacitycur = jovl->areaopacityset;
jovl->areaopacityfrm = 0;
} else {
if (prevtc[PTRJOY].s) { /* drag area along */
if (newtc[PTRJOY].x > jovl->joyarea.r) {
dx = newtc[PTRJOY].x - jovl->joyarea.r;
jovl->joyarea.l += dx;
jovl->joyarea.r += dx;
newjoy &= INPUT_STICK_RIGHT;
} else if (newtc[PTRJOY].x < jovl->joyarea.l) {
dx = jovl->joyarea.l - newtc[PTRJOY].x;
jovl->joyarea.r -= dx;
jovl->joyarea.l -= dx;
newjoy &= INPUT_STICK_LEFT;
} else if (newtc[PTRJOY].x <= jovl->joyarea.l + dx) {
newjoy &= INPUT_STICK_LEFT;
} else if (newtc[PTRJOY].x >= jovl->joyarea.r - dx) {
newjoy &= INPUT_STICK_RIGHT;
}
if (newtc[PTRJOY].y > jovl->joyarea.b) {
dy = newtc[PTRJOY].y - jovl->joyarea.b;
jovl->joyarea.t += dy;
jovl->joyarea.b += dy;
newjoy &= INPUT_STICK_BACK;
} else if (newtc[PTRJOY].y < jovl->joyarea.t) {
dy = jovl->joyarea.t - newtc[PTRJOY].y;
jovl->joyarea.b -= dy;
jovl->joyarea.t -= dy;
newjoy &= INPUT_STICK_FORWARD;
} else if (newtc[PTRJOY].y <= jovl->joyarea.t + dy) {
newjoy &= INPUT_STICK_FORWARD;
} else if (newtc[PTRJOY].y >= jovl->joyarea.b - dy) {
newjoy &= INPUT_STICK_BACK;
}
jovl->joystick.x = newtc[PTRJOY].x;
jovl->joystick.y = newtc[PTRJOY].y;
jovl->stickopacity = HIT_OPACITY;
} else { /* recenter area */
dx = (jovl->joyarea.r - jovl->joyarea.l) >> 1;
dy = (jovl->joyarea.b - jovl->joyarea.t) >> 1;
if (Android_Joyleft) {
if (newtc[PTRJOY].x + dx > Android_Split)
newtc[PTRJOY].x = Android_Split - dx;
} else {
if (newtc[PTRJOY].x - dx < Android_Split)
newtc[PTRJOY].x = Android_Split + dx;
}
if (newtc[PTRJOY].x - dx < 0) newtc[PTRJOY].x -= newtc[PTRJOY].x - dx;
if (newtc[PTRJOY].y - dy < 0) newtc[PTRJOY].y -= newtc[PTRJOY].y - dy;
if (newtc[PTRJOY].y + dy > Android_ScreenH)
newtc[PTRJOY].y -= newtc[PTRJOY].y + dy - Android_ScreenH;
jovl->joyarea.l = newtc[PTRJOY].x - dx;
jovl->joyarea.r = newtc[PTRJOY].x + dx;
jovl->joyarea.t = newtc[PTRJOY].y - dy;
jovl->joyarea.b = newtc[PTRJOY].y + dy;
}
jovl->areaopacitycur = jovl->areaopacityset;
jovl->areaopacityfrm = 0;
}
}
/* trigger */
newtrig = 1;
if ( (newtc[PTRTRG].s && conptr != PTRTRG) || /* normal trigger */
(newtc[PTRJOY].s && conptr != PTRJOY && Android_PlanetaryDefense) ) {
newtrig = 0;
jovl->fire.x = newtc[PTRTRG].x;
jovl->fire.y = newtc[PTRTRG].y;
jovl->fireopacity = HIT_OPACITY;
}
/* thread unsafe => "no" problem */
if (!Android_Paddle){
Android_PortStatus = 0xFFF0 | newjoy;
Android_TrigStatus = 0xE | newtrig;
} else {
POKEY_POT_input[INPUT_mouse_port << 1] = Android_POTX;
POKEY_POT_input[(INPUT_mouse_port << 1) + 1] = Android_POTY;
INPUT_mouse_buttons = !newtrig;
}
memcpy(prevtc, newtc, sizeof(struct touchstate) * MAXPOINTERS);
prevconptr = conptr;
return ret;
}
void Android_KeyEvent(int k, int s)
{
int i, shft;
if (Android_SoftjoyEnable) {
for (i = 0; i < 4; i++)
if (softjoymap[i][0] == k) {
if (s)
Android_PortStatus &= 0xFFF0 | softjoymap[i][1];
else
Android_PortStatus |= ~softjoymap[i][1];
return;
}
if (softjoymap[SOFTJOY_FIRE][0] == k) {
Android_TrigStatus = Android_TrigStatus & (~(s != 0)) | (s == 0);
return;
}
for (i = SOFTJOY_ACTIONBASE; i < SOFTJOY_MAXKEYS + SOFTJOY_MAXACTIONS; i++)
if (softjoymap[i][0] == k && softjoymap[i][1] != AKEY_NONE) {
k = softjoymap[i][1];
break;
}
}
if (Android_DerotateKeys && k <= KEY_UP && k >= KEY_RIGHT)
k = derot_lut[Android_DerotateKeys - 1][KEY_UP - k];
switch (k) {
case KEY_SHIFT:
INPUT_key_shift = (s) ? AKEY_SHFT : 0;
break;
case KEY_CONTROL:
Android_key_control = (s) ? AKEY_CTRL : 0;
break;
case KEY_FIRE:
Android_TrigStatus = Android_TrigStatus & (~(s != 0)) | (s == 0);
break;
default:
if (k >= STATIC_MAXKEYS)
Log_print("Unmappable key %d", k);
else {
if (k == '+' || k == '<' || k == '>' || k == '*')
shft = 0;
else
shft == INPUT_key_shift;
Keyboard_Enqueue( (s) ? (skeyxlat[k] | Android_key_control | shft) : AKEY_NONE );
}
}
}
void Input_Initialize(void)
{
int i;
memset(prevtc, 0, 2 * sizeof(struct touchstate));
prevconptr = PTRSTL;
memset(&AndroidInput_JoyOvl, 0, sizeof(struct joy_overlay_state));
AndroidInput_JoyOvl.ovl_visible = 1;
AndroidInput_JoyOvl.areaopacitycur = AndroidInput_JoyOvl.areaopacityset = 0.25f;
AndroidInput_JoyOvl.deadarea = 0.3f;
AndroidInput_JoyOvl.gracearea = 0.3f;
AndroidInput_JoyOvl.joyarea.t = AndroidInput_JoyOvl.joyarea.l = 10;
AndroidInput_JoyOvl.joyarea.b = AndroidInput_JoyOvl.joyarea.r = 74;
AndroidInput_JoyOvl.anchor = 0;
memset(&AndroidInput_ConOvl, 0, sizeof(struct consolekey_overlay_state));
AndroidInput_ConOvl.hitkey = CONK_NOKEY;
AndroidInput_ConOvl.opacity = COVL_MAX_OPACITY;
AndroidInput_ConOvl.ovl_visible = COVL_READY;
AndroidInput_ConOvl.statecnt = COVL_HOLD_TIME >> 1;
Android_PortStatus = 0xFFFF;
Android_TrigStatus = 0xF;
for (i = 0; i < KBD_MAXKEYS; Android_Keyboard[i] = AKEY_NONE, i++);
INPUT_key_consol = INPUT_CONSOL_NONE;
INPUT_key_shift = FALSE;
Android_key_control = 0;
}
void Joy_Reposition(void)
{
int dx = 0, dy = 0;
if (Android_ScreenW == 0) return; /* we're going to get called again @ initgraphics() */
if (Android_Joyleft) {
if (AndroidInput_JoyOvl.joyarea.r > Android_Split)
dx = -(AndroidInput_JoyOvl.joyarea.r - Android_Split);
} else {
if (AndroidInput_JoyOvl.joyarea.l < Android_Split)
dx = Android_Split - AndroidInput_JoyOvl.joyarea.l;
}
if (AndroidInput_JoyOvl.joyarea.l < 0)
dx = -AndroidInput_JoyOvl.joyarea.l;
else if (AndroidInput_JoyOvl.joyarea.r > Android_ScreenW)
dx = -(AndroidInput_JoyOvl.joyarea.r - Android_ScreenW);
if (AndroidInput_JoyOvl.joyarea.t < 0)
dy = -AndroidInput_JoyOvl.joyarea.t;
else if (AndroidInput_JoyOvl.joyarea.b > Android_ScreenH)
dy = -(AndroidInput_JoyOvl.joyarea.b - Android_ScreenH);
AndroidInput_JoyOvl.joyarea.l += dx;
AndroidInput_JoyOvl.joyarea.r += dx;
AndroidInput_JoyOvl.joyarea.t += dy;
AndroidInput_JoyOvl.joyarea.b += dy;
}
void Android_SplitCalc(void)
{
if (Android_Joyleft)
Android_Split = Android_Splitpct * Android_ScreenW;
else
Android_Split = (1.0f - Android_Splitpct) * Android_ScreenW;
}
void Keyboard_Enqueue(int key)
{
pthread_mutex_lock(&key_mutex);
if ((key_head + 1) & KBD_MASK == key_tail)
key_head = key_tail; /* on overflow, discard previous keys */
Android_Keyboard[key_head++] = key;
key_head &= KBD_MASK;
pthread_mutex_unlock(&key_mutex);
}
int Keyboard_Dequeue(void)
{
pthread_mutex_lock(&key_mutex);
if (key_head != key_tail) {
key_last = Android_Keyboard[key_tail++];
key_tail &= KBD_MASK;
}
pthread_mutex_unlock(&key_mutex);
return key_last;
}
int Keyboard_Peek(void)
{
int tmp_key;
tmp_key = key_last;
if (key_head != key_tail)
tmp_key = Android_Keyboard[key_tail];
return tmp_key;
}
+111
View File
@@ -0,0 +1,111 @@
#include "atari.h"
struct RECT
{
int l;
int t;
union {
int r;
int w;
};
union {
int b;
int h;
};
};
struct POINT
{
int x;
int y;
};
struct joy_overlay_state
{
int ovl_visible;
struct RECT joyarea;
float areaopacitycur;
float areaopacityset;
int areaopacityfrm;
int anchor;
float deadarea;
float gracearea;
struct POINT joystick;
float stickopacity;
struct POINT fire;
float fireopacity;
int firewid;
};
enum con_vst {
COVL_HIDDEN = 0,
COVL_FADEIN,
COVL_READY,
COVL_FADEOUT
};
enum con_key {
CONK_NOKEY = -1,
CONK_HELP = 0,
CONK_START,
CONK_SELECT,
CONK_OPTION,
CONK_RESET
};
struct consolekey_overlay_state
{
enum con_vst ovl_visible;
UWORD *keycoo;
struct RECT bbox;
float opacity;
enum con_key hitkey;
int statecnt;
int resetcnt;
int hotlen;
#define COVL_MAX_OPACITY 0.5f
#define COVL_HOLD_TIME 150
#define RESET_SOFT 30
#define RESET_HARD 60
};
extern struct joy_overlay_state AndroidInput_JoyOvl;
extern struct consolekey_overlay_state AndroidInput_ConOvl;
extern UWORD Android_PortStatus;
extern UBYTE Android_TrigStatus;
enum
{
SOFTJOY_LEFT = 0,
SOFTJOY_RIGHT,
SOFTJOY_UP,
SOFTJOY_DOWN,
SOFTJOY_FIRE,
SOFTJOY_MAXKEYS
};
#define SOFTJOY_MAXACTIONS 3
#define SOFTJOY_ACTIONBASE SOFTJOY_MAXKEYS
#define ACTION_NONE 0xFF
extern UBYTE softjoymap[SOFTJOY_MAXKEYS + SOFTJOY_MAXACTIONS][2];
extern int Android_SoftjoyEnable;
extern int Android_Joyleft;
extern float Android_Splitpct;
extern int Android_Split;
extern int Android_DerotateKeys;
extern int Android_Paddle;
extern int Android_PlanetaryDefense;
extern SWORD Android_POTX;
extern SWORD Android_POTY;
extern UBYTE Android_ReversePddle;
int Android_TouchEvent(int x1, int y1, int s1, int x2, int y2, int s2);
void Android_KeyEvent(int k, int s);
void Input_Initialize(void);
void Keyboard_Enqueue(int key);
int Keyboard_Dequeue(void);
int Keyboard_Peek(void);
void Android_SplitCalc(void);
+480
View File
@@ -0,0 +1,480 @@
/*
* graphics.c - android drawing
*
* Copyright (C) 2010 Kostas Nakos
* Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <malloc.h>
#include <string.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include "atari.h"
#include "screen.h"
#include "colours.h"
#include "akey.h"
#include "cpu.h"
#include "androidinput.h"
#include "graphics.h"
#define TEXTURE_WIDTH 512
#define TEXTURE_HEIGHT 256
#define OPACITY_CUTOFF 0.05f
#define OPACITY_STEP 0.02f
#define OPACITY_FRMSTR 75
#define BORDER_PCT 0.05f
int Android_ScreenW = 0;
int Android_ScreenH = 0;
int Android_Aspect;
int Android_CropScreen[] = {0, SCREEN_HEIGHT, SCANLINE_LEN, -SCREEN_HEIGHT};
static struct RECT screenrect;
static int screenclear;
int Android_Bilinear;
float Android_Joyscale = 0.15f;
extern int *ovl_texpix;
extern int ovl_texw;
extern int ovl_texh;
/* graphics conversion */
static UWORD *palette = NULL;
static UWORD *hicolor_screen = NULL;
/* standard gl textures */
enum {
TEX_SCREEN = 0,
TEX_OVL,
TEX_MAXNAMES
};
static GLuint texture[TEX_MAXNAMES];
static UWORD conkey_vrt[CONK_VERT_MAX];
static int conkey_lbl[CONK_VERT_MAX >> 2];
static UWORD conkey_shadow[2 * 4];
void Android_PaletteUpdate(void)
{
int i;
if (!palette) {
if ( !(palette = malloc(256 * sizeof(UWORD))) ) {
Log_print("Cannot allocate memory for palette conversion.");
return;
}
}
memset(palette, 0, 256 * sizeof(UWORD));
for (i = 0; i < 256; i++)
palette[i] = ( (Colours_GetR(i) & 0xf8) << 8 ) |
( (Colours_GetG(i) & 0xfc) << 3 ) |
( (Colours_GetB(i) & 0xf8) >> 3 );
/* force full redraw */
Screen_EntireDirty();
}
int Android_InitGraphics(void)
{
const UWORD poly[] = { 0,16, 24,16, 32,0, 8,0 };
int i, tmp, w, h;
float tmp2, tmp3;
struct RECT *r;
/* Allocate stuff */
if (!hicolor_screen) {
if ( !(hicolor_screen = malloc(TEXTURE_WIDTH * TEXTURE_HEIGHT * sizeof(UWORD))) ) {
Log_print("Cannot allocate memory for hicolor screen.");
return FALSE;
}
}
memset(hicolor_screen, 0, TEXTURE_WIDTH * TEXTURE_HEIGHT * sizeof(UWORD));
/* Setup GL */
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glGenTextures(TEX_MAXNAMES, texture);
glPixelStorei(GL_PACK_ALIGNMENT, 8);
/* overlays texture */
glBindTexture(GL_TEXTURE_2D, texture[TEX_OVL]);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ovl_texw, ovl_texh, 0, GL_RGBA,
GL_UNSIGNED_BYTE, ovl_texpix);
/* playfield texture */
glBindTexture(GL_TEXTURE_2D, texture[TEX_SCREEN]);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
Android_Bilinear ? GL_LINEAR : GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
Android_Bilinear ? GL_LINEAR : GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, Android_CropScreen);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, hicolor_screen);
/* Setup view for console key polygons */
glLoadIdentity();
glOrthof(0, Android_ScreenW, Android_ScreenH, 0, 0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glClear(GL_COLOR_BUFFER_BIT);
/* Finsh GL init with an error check */
if (glGetError() != GL_NO_ERROR) {
Log_print("Cannot initialize OpenGL");
return FALSE;
}
/* Console keys' polygons */
tmp2 = ((float) (Android_ScreenW >> 1)) / ((float) 4.5f * poly[4]);
tmp3 = ((float) Android_ScreenH) / ((float) 14 * poly[1]);
if (tmp2 > tmp3)
tmp2 = tmp3;
if (tmp2 < 2.0f)
tmp2 = 2.0f;
for (i = 0; i < CONK_VERT_MAX; i += 2) {
/* generate & scale */
conkey_vrt[i ] = poly[i % 8] * tmp2 +
((i > 7) ? (conkey_vrt[(i / 8 - 1) * 8 + 2] + 4) : 0);
conkey_vrt[i + 1] = poly[(i + 1) % 8] * tmp2;
}
tmp = Android_ScreenW - conkey_vrt[CONK_VERT_MAX - 4];
for (i = 0; i < CONK_VERT_MAX; i += 2) {
/* translate */
conkey_vrt[i ] += tmp;
conkey_vrt[i + 1] += 4;
}
for (i = 0; i < CONK_VERT_MAX; i += 8) {
conkey_lbl[i >> 2] = conkey_vrt[i] + 6;
conkey_lbl[(i >> 2) + 1] = Android_ScreenH - (conkey_vrt[i + 1] - 1);
}
AndroidInput_ConOvl.keycoo = conkey_vrt;
AndroidInput_ConOvl.bbox.l = conkey_vrt[0];
AndroidInput_ConOvl.bbox.b = conkey_vrt[1];
AndroidInput_ConOvl.bbox.r = conkey_vrt[CONK_VERT_MAX - 4];
AndroidInput_ConOvl.bbox.t = conkey_vrt[CONK_VERT_MAX - 3];
AndroidInput_ConOvl.hotlen = 0.1f *
(Android_ScreenW < Android_ScreenH ? Android_ScreenW : Android_ScreenH);
r = &(AndroidInput_ConOvl.bbox);
conkey_shadow[0] = r->l - COVL_SHADOW_OFF;
conkey_shadow[1] = r->b + COVL_SHADOW_OFF;
conkey_shadow[2] = r->r;
conkey_shadow[3] = r->b + COVL_SHADOW_OFF;
conkey_shadow[4] = r->r;
conkey_shadow[5] = r->t - COVL_SHADOW_OFF;
conkey_shadow[6] = r->l - COVL_SHADOW_OFF;
conkey_shadow[7] = r->t - COVL_SHADOW_OFF;
/* Scale joystick overlays */
Joyovl_Scale();
Joy_Reposition();
/* Aspect correct scaling */
memset(&screenrect, 0, sizeof(struct RECT));
if ( ((Android_ScreenW > Android_ScreenH) + 1) & Android_Aspect) {
w = Android_CropScreen[2];
h = -Android_CropScreen[3];
/* fit horizontally */
tmp2 = ((float) Android_ScreenW) / ((float) w);
screenrect.h = tmp2 * h;
if (screenrect.h > Android_ScreenH) {
/* fit vertically */
tmp2 = ((float) Android_ScreenH) / ((float) h);
screenrect.h = Android_ScreenH;
}
screenrect.w = tmp2 * w;
/* center */
tmp = (Android_ScreenW - screenrect.r + 1) / 2;
screenrect.l += tmp;
h = Android_ScreenH;
if (Android_ScreenH > Android_ScreenW)
h >>= 1; /* assume keyboard takes up half the height in portrait */
tmp = (h - screenrect.b + 1) / 2;
if (tmp < 0)
tmp = 0;
tmp = (Android_ScreenH - h) + tmp;
screenrect.t += tmp;
screenclear = TRUE;
} else {
screenrect.t = screenrect.l = 0;
screenrect.w = Android_ScreenW;
screenrect.h = Android_ScreenH;
screenclear = FALSE;
}
/* Initialize palette */
Android_PaletteUpdate();
return TRUE;
}
void Joyovl_Scale(void)
{
int tmp;
tmp = ( (Android_ScreenW > Android_ScreenH) ?
Android_ScreenW : Android_ScreenH ) * Android_Joyscale;
if (!Android_Paddle) {
AndroidInput_JoyOvl.joyarea.r = AndroidInput_JoyOvl.joyarea.l + tmp;
AndroidInput_JoyOvl.joyarea.b = AndroidInput_JoyOvl.joyarea.t + tmp;
} else {
if (!Android_PlanetaryDefense) {
AndroidInput_JoyOvl.joyarea.l = Android_Joyleft ? BORDER_PCT * Android_ScreenW : Android_Split;
AndroidInput_JoyOvl.joyarea.r = Android_Joyleft ? Android_Split : (1.0f - BORDER_PCT) * Android_ScreenW;
AndroidInput_JoyOvl.joyarea.b = AndroidInput_JoyOvl.joyarea.t + 8 + (tmp >> 3);
} else {
AndroidInput_JoyOvl.joyarea.l = AndroidInput_JoyOvl.joyarea.t = 0;
AndroidInput_JoyOvl.joyarea.r = Android_ScreenW;
AndroidInput_JoyOvl.joyarea.b = Android_ScreenH;
}
}
AndroidInput_JoyOvl.firewid = tmp >> 3;
}
void Android_ConvertScreen(void)
{
int x, y;
UBYTE *src, *src_line;
UWORD *dst, *dst_line;
#ifdef DIRTYRECT
UBYTE *dirty, *dirty_line;
#endif
#ifdef DIRTYRECT
dirty_line = Screen_dirty + SCANLINE_START / 8;
#endif
src_line = ((UBYTE *) Screen_atari) + SCANLINE_START;
dst_line = hicolor_screen;
for (y = 0; y < SCREEN_HEIGHT; y++) {
#ifdef DIRTYRECT
dirty = dirty_line;
#else
src = src_line;
dst = dst_line;
#endif
for (x = 0; x < SCANLINE_LEN; x += 8) {
#ifdef DIRTYRECT
if (*dirty) {
src = src_line + x;
dst = dst_line + x;
do {
#endif
*dst++ = palette[*src++]; *dst++ = palette[*src++];
*dst++ = palette[*src++]; *dst++ = palette[*src++];
*dst++ = palette[*src++]; *dst++ = palette[*src++];
*dst++ = palette[*src++]; *dst++ = palette[*src++];
#ifdef DIRTYRECT
*dirty++ = 0;
x += 8;
} while (*dirty && x < SCANLINE_LEN);
}
dirty++;
#endif
}
#ifdef DIRTYRECT
dirty_line += SCREEN_WIDTH / 8;
#endif
src_line += SCREEN_WIDTH;
dst_line += SCANLINE_LEN;
}
}
void Android_Render(void)
{
const static int crop_joy[] = {0, 0, 64, 64};
const static int crop_fire[] = {65, 0, 16, 15};
const static int crop_lbl[][4] = { {65, 64, 40, -9},
{65, 24, 40, -9},
{65, 34, 40, -9},
{65, 44, 40, -9},
{65, 54, 40, -9} };
const static int crop_all[] = {0, 64, 128, -64};
const struct RECT *r;
const struct POINT *p;
int i;
if (screenclear)
glClear(GL_COLOR_BUFFER_BIT);
/* --------------------- playfield --------------------- */
glBindTexture(GL_TEXTURE_2D, texture[TEX_SCREEN]);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, SCANLINE_LEN, SCREEN_HEIGHT, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, hicolor_screen);
r = &screenrect;
glDrawTexiOES(r->l, r->t, 0, r->w, r->h);
if (glGetError() != GL_NO_ERROR) Log_print("OpenGL error at playfield");
/* --------------------- overlays --------------------- */
glEnable(GL_BLEND); /* enable blending */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
glBindTexture(GL_TEXTURE_2D, texture[TEX_OVL]);
if (!AndroidInput_JoyOvl.ovl_visible) goto ck; /*!*/
/* joystick area */
glColor4f(1.0f, 1.0f, 1.0f, AndroidInput_JoyOvl.areaopacitycur);
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop_joy);
r = &AndroidInput_JoyOvl.joyarea;
glDrawTexiOES(r->l, Android_ScreenH - r->b, 0, r->r - r->l, r->b - r->t);
if (glGetError() != GL_NO_ERROR) Log_print("OpenGL error at joy area");
/* stick */
if (AndroidInput_JoyOvl.stickopacity >= OPACITY_CUTOFF) {
glColor4f(1.0f, 1.0f, 1.0f, AndroidInput_JoyOvl.stickopacity);
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop_fire);
p = &AndroidInput_JoyOvl.joystick;
i = AndroidInput_JoyOvl.firewid;
glDrawTexiOES(p->x - i, Android_ScreenH - (p->y + i), 0, i << 1, i << 1);
if (glGetError() != GL_NO_ERROR) Log_print("OpenGL error at stick");
}
/* fire */
if (AndroidInput_JoyOvl.fireopacity >= OPACITY_CUTOFF) {
glColor4f(1.0f, 1.0f, 1.0f, AndroidInput_JoyOvl.fireopacity);
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop_fire);
p = &AndroidInput_JoyOvl.fire;
i = AndroidInput_JoyOvl.firewid;
glDrawTexiOES(p->x - i, Android_ScreenH - (p->y + i), 0, i << 1, i << 1);
if (glGetError() != GL_NO_ERROR) Log_print("OpenGL error at fire");
}
/* glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop_all);
glDrawTexiOES(0, 0, 0, 128, 64);
*/
/* console keys */
ck: if (AndroidInput_ConOvl.ovl_visible) {
glDisable(GL_TEXTURE_2D); /* disable texturing */
glColor4f(0.0f, 0.0f, 0.0f, AndroidInput_ConOvl.opacity * 0.7);
glVertexPointer(2, GL_SHORT, 0, conkey_shadow);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glColor4f(0.5f, 0.9f, 1.0f, AndroidInput_ConOvl.opacity);
glVertexPointer(2, GL_SHORT, 0, conkey_vrt);
for (i = 0; i < (CONK_VERT_MAX >> 1); i += 4)
glDrawArrays(GL_LINE_LOOP, i, 4);
if (AndroidInput_ConOvl.hitkey >= 0) {
glColor4f(0.34f, 0.67f, 1.0f, AndroidInput_ConOvl.opacity);
glDrawArrays(GL_TRIANGLE_FAN, AndroidInput_ConOvl.hitkey << 2, 4);
}
glEnable(GL_TEXTURE_2D); /* enable texturing */
glColor4f(1.0f, 1.0f, 1.0f, AndroidInput_ConOvl.opacity);
for (i = 0; i < CONK_VERT_MAX >> 2; i += 2) {
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop_lbl[i >> 1]);
glDrawTexiOES(conkey_lbl[i], conkey_lbl[i + 1], 0, 40, 9);
}
if (glGetError() != GL_NO_ERROR) Log_print("OpenGL error at console overlay");
}
glDisable(GL_BLEND); /* disable blending */
}
void Update_Overlays(void)
{
struct joy_overlay_state *s;
struct consolekey_overlay_state *c;
s = &AndroidInput_JoyOvl;
c = &AndroidInput_ConOvl;
/* joy et co. */
if (s->fireopacity > OPACITY_CUTOFF)
s->fireopacity -= 0.05f;
else
s->fireopacity = 0.0f;
if (s->stickopacity > OPACITY_CUTOFF) {
s->stickopacity -= 0.05f;
s->areaopacityfrm = 0;
s->areaopacitycur = s->areaopacityset;
} else {
s->stickopacity = 0.0f;
s->areaopacityfrm++;
if (s->areaopacityfrm > OPACITY_FRMSTR) {
if (s->areaopacitycur > OPACITY_CUTOFF)
s->areaopacitycur -= OPACITY_STEP;
else {
s->areaopacitycur = OPACITY_CUTOFF;
s->areaopacityfrm--;
}
}
}
/* console keys */
switch (c->ovl_visible) {
case COVL_READY:
if (c->hitkey == CONK_NOKEY)
if (!c->statecnt--)
c->ovl_visible = COVL_FADEOUT;
break;
case COVL_FADEOUT:
if (c->opacity > OPACITY_CUTOFF)
c->opacity -= 2 * OPACITY_STEP;
else {
c->ovl_visible = COVL_HIDDEN;
c->opacity = 0.0f;
}
break;
case COVL_FADEIN:
if (c->opacity < COVL_MAX_OPACITY)
c->opacity += 4 * OPACITY_STEP;
else {
c->ovl_visible = COVL_READY;
c->opacity = COVL_MAX_OPACITY;
c->statecnt = COVL_HOLD_TIME;
}
break;
}
if (c->hitkey == CONK_RESET) {
if (c->resetcnt >= RESET_HARD) {
Atari800_Coldstart();
} else if (c->resetcnt >= RESET_SOFT) {
Atari800_Warmstart();
CPU_cim_encountered = FALSE;
}
c->resetcnt++;
} else {
c->resetcnt = 0;
}
}
void Android_ExitGraphics(void)
{
if (hicolor_screen)
free(hicolor_screen);
hicolor_screen = NULL;
if (palette)
free(palette);
palette = NULL;
glDeleteTextures(TEX_MAXNAMES, texture);
}
+25
View File
@@ -0,0 +1,25 @@
#define CONK_VERT_MAX (2 * 4 * 5)
#define COVL_SHADOW_OFF 10
#define SCREEN_WIDTH 384
#define SCREEN_HEIGHT 240
#define DEAD_WIDTH 48
#define SCANLINE_START (DEAD_WIDTH / 2)
#define SCANLINE_END (SCREEN_WIDTH - DEAD_WIDTH / 2)
#define SCANLINE_LEN (SCREEN_WIDTH - DEAD_WIDTH)
extern int Android_ScreenW;
extern int Android_ScreenH;
extern int Android_Aspect;
extern int Android_Bilinear;
extern int Android_CropScreen[];
extern float Android_Joyscale;
int Android_InitGraphics(void);
void Android_ExitGraphics(void);
void Android_ConvertScreen(void);
void Android_PaletteUpdate(void);
void Android_Render(void);
void Update_Overlays(void);
void Joyovl_Scale(void);
+722
View File
@@ -0,0 +1,722 @@
/*
* jni.c - native functions exported to java
*
* Copyright (C) 2014 Kostas Nakos
* Copyright (C) 2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stddef.h>
#include <pthread.h>
#include <jni.h>
#include <string.h>
#include "log.h"
#include "atari.h"
#include "input.h"
#include "afile.h"
#include "screen.h"
#include "cpu.h"
#include "antic.h"
#include "../../memory.h" /* override system header */
#include "sio.h"
#include "sysrom.h"
#include "akey.h"
#include "devices.h"
#include "cartridge.h"
#include "graphics.h"
#include "androidinput.h"
#define PD2012_FNAME "PD2012.com"
/* exports/imports */
int *ovl_texpix;
int ovl_texw;
int ovl_texh;
extern void SoundThread_Update(void *buf, int offs, int len);
extern void Android_SoundInit(int rate, int sizems, int bit16, int hq, int disableOSL);
extern void Sound_Exit(void);
extern void Sound_Pause(void);
extern void Sound_Continue(void);
extern int Android_osl_sound;
struct audiothread {
UBYTE *sndbuf;
jbyteArray sndarray;
};
static pthread_key_t audiothread_data;
static char devb_url[512];
static void JNICALL NativeGetOverlays(JNIEnv *env, jobject this)
{
jclass cls;
jfieldID fid;
jintArray arr;
jboolean cp;
cls = (*env)->GetObjectClass(env, this);
fid = (*env)->GetFieldID(env, cls, "OVL_TEXW", "I");
ovl_texw = (*env)->GetIntField(env, this, fid);
fid = (*env)->GetFieldID(env, cls, "OVL_TEXH", "I");
ovl_texh = (*env)->GetIntField(env, this, fid);
ovl_texpix = malloc(ovl_texw * ovl_texh * sizeof(int));
if (ovl_texpix == NULL) Log_print("Cannot allocate memory for overlays");
fid = (*env)->GetFieldID(env, cls, "_pix", "[I");
arr = (*env)->GetObjectField(env, this, fid);
(*env)->GetIntArrayRegion(env, arr, 0, ovl_texw * ovl_texh, ovl_texpix);
Log_print("Overlays texture initialized: %dx%d", ovl_texw, ovl_texh);
}
static void JNICALL NativeResize(JNIEnv *env, jobject this, jint w, jint h)
{
Log_print("Screen resize: %dx%d", w, h);
Android_ScreenW = w;
Android_ScreenH = h;
Android_SplitCalc();
Android_InitGraphics();
}
static void JNICALL NativeClearDevB(JNIEnv *env, jobject this)
{
dev_b_status.ready = FALSE;
memset(devb_url, 0, sizeof(devb_url));
}
static jstring JNICALL NativeInit(JNIEnv *env, jobject this)
{
int ac = 1;
char av = '\0';
char *avp = &av;
pthread_key_create(&audiothread_data, NULL);
pthread_setspecific(audiothread_data, NULL);
NativeClearDevB(env, this);
Atari800_Initialise(&ac, &avp);
return (*env)->NewStringUTF(env, Atari800_TITLE);
}
static jobjectArray JNICALL NativeGetDrvFnames(JNIEnv *env, jobject this)
{
jobjectArray arr;
int i;
char tmp[FILENAME_MAX + 3], fname[FILENAME_MAX];
jstring str;
arr = (*env)->NewObjectArray(env, 4, (*env)->FindClass(env, "java/lang/String"), NULL);
for (i = 0; i < 4; i++) {
Util_splitpath(SIO_filename[i], NULL, fname);
sprintf(tmp, "D%d:%s", i + 1, fname);
str = (*env)->NewStringUTF(env, tmp);
(*env)->SetObjectArrayElement(env, arr, i, str);
(*env)->DeleteLocalRef(env, str);
}
return arr;
}
static void JNICALL NativeUnmountAll(JNIEnv *env, jobject this)
{
int i;
for (i = 1; i <= 4; i++)
SIO_DisableDrive(i);
}
static jboolean JNICALL NativeIsDisk(JNIEnv *env, jobject this, jstring img)
{
const jbyte *img_utf = NULL;
int type;
img_utf = (*env)->GetStringUTFChars(env, img, NULL);
type = AFILE_DetectFileType(img_utf);
(*env)->ReleaseStringUTFChars(env, img, img_utf);
switch (type) {
case AFILE_ATR:
case AFILE_ATX:
case AFILE_XFD:
case AFILE_ATR_GZ:
case AFILE_XFD_GZ:
case AFILE_DCM:
case AFILE_PRO:
return JNI_TRUE;
default:
return JNI_FALSE;
}
}
static jboolean JNICALL NativeSaveState(JNIEnv *env, jobject this, jstring fname)
{
const jbyte *fname_utf = NULL;
int ret;
fname_utf = (*env)->GetStringUTFChars(env, fname, NULL);
ret = StateSav_SaveAtariState(fname_utf, "wb", TRUE);
Log_print("Saved state %s with return %d", fname_utf, ret);
(*env)->ReleaseStringUTFChars(env, fname, fname_utf);
return ret;
}
static jint JNICALL NativeRunAtariProgram(JNIEnv *env, jobject this,
jstring img, jint drv, jint reboot)
{
static char const * const cart_descriptions[CARTRIDGE_LAST_SUPPORTED + 1] = {
NULL,
CARTRIDGE_STD_8_DESC,
CARTRIDGE_STD_16_DESC,
CARTRIDGE_OSS_034M_16_DESC,
CARTRIDGE_5200_32_DESC,
CARTRIDGE_DB_32_DESC,
CARTRIDGE_5200_EE_16_DESC,
CARTRIDGE_5200_40_DESC,
CARTRIDGE_WILL_64_DESC,
CARTRIDGE_EXP_64_DESC,
CARTRIDGE_DIAMOND_64_DESC,
CARTRIDGE_SDX_64_DESC,
CARTRIDGE_XEGS_32_DESC,
CARTRIDGE_XEGS_07_64_DESC,
CARTRIDGE_XEGS_128_DESC,
CARTRIDGE_OSS_M091_16_DESC,
CARTRIDGE_5200_NS_16_DESC,
CARTRIDGE_ATRAX_128_DESC,
CARTRIDGE_BBSB_40_DESC,
CARTRIDGE_5200_8_DESC,
CARTRIDGE_5200_4_DESC,
CARTRIDGE_RIGHT_8_DESC,
CARTRIDGE_WILL_32_DESC,
CARTRIDGE_XEGS_256_DESC,
CARTRIDGE_XEGS_512_DESC,
CARTRIDGE_XEGS_1024_DESC,
CARTRIDGE_MEGA_16_DESC,
CARTRIDGE_MEGA_32_DESC,
CARTRIDGE_MEGA_64_DESC,
CARTRIDGE_MEGA_128_DESC,
CARTRIDGE_MEGA_256_DESC,
CARTRIDGE_MEGA_512_DESC,
CARTRIDGE_MEGA_1024_DESC,
CARTRIDGE_SWXEGS_32_DESC,
CARTRIDGE_SWXEGS_64_DESC,
CARTRIDGE_SWXEGS_128_DESC,
CARTRIDGE_SWXEGS_256_DESC,
CARTRIDGE_SWXEGS_512_DESC,
CARTRIDGE_SWXEGS_1024_DESC,
CARTRIDGE_PHOENIX_8_DESC,
CARTRIDGE_BLIZZARD_16_DESC,
CARTRIDGE_ATMAX_128_DESC,
CARTRIDGE_ATMAX_1024_DESC,
CARTRIDGE_SDX_128_DESC,
CARTRIDGE_OSS_8_DESC,
CARTRIDGE_OSS_043M_16_DESC,
CARTRIDGE_BLIZZARD_4_DESC,
CARTRIDGE_AST_32_DESC,
CARTRIDGE_ATRAX_SDX_64_DESC,
CARTRIDGE_ATRAX_SDX_128_DESC,
CARTRIDGE_TURBOSOFT_64_DESC,
CARTRIDGE_TURBOSOFT_128_DESC,
CARTRIDGE_ULTRACART_32_DESC,
CARTRIDGE_LOW_BANK_8_DESC,
CARTRIDGE_SIC_128_DESC,
CARTRIDGE_SIC_256_DESC,
CARTRIDGE_SIC_512_DESC,
CARTRIDGE_STD_2_DESC,
CARTRIDGE_STD_4_DESC,
CARTRIDGE_RIGHT_4_DESC,
CARTRIDGE_BLIZZARD_32_DESC,
CARTRIDGE_MEGAMAX_2048_DESC,
CARTRIDGE_THECART_128M_DESC,
CARTRIDGE_MEGA_4096_DESC,
CARTRIDGE_MEGA_2048_DESC,
CARTRIDGE_THECART_32M_DESC,
CARTRIDGE_THECART_64M_DESC,
CARTRIDGE_XEGS_8F_64_DESC
};
const jbyte *img_utf = NULL;
int ret = 0, r, kb, i, cnt = 0;
jclass cls, scls;
jfieldID fid;
jobjectArray arr, xarr;
jstring str;
char tmp[128];
if (reboot) {
NativeUnmountAll(env, this);
CARTRIDGE_Remove();
}
img_utf = (*env)->GetStringUTFChars(env, img, NULL);
r = AFILE_OpenFile(img_utf, reboot, drv, FALSE);
if ((r & 0xFF) == AFILE_ROM && (r >> 8) != 0) {
kb = r >> 8;
scls = (*env)->FindClass(env, "java/lang/String");
cls = (*env)->GetObjectClass(env, this);
fid = (*env)->GetFieldID(env, cls, "_cartTypes", "[[Ljava/lang/String;");
for (i = 1; i <= CARTRIDGE_LAST_SUPPORTED; i++)
if (CARTRIDGE_kb[i] == kb) cnt++;
xarr = (*env)->NewObjectArray(env, 2, scls, NULL);
arr = (*env)->NewObjectArray(env, cnt, (*env)->GetObjectClass(env, xarr), NULL);
for (cnt = 0, i = 1; i <= CARTRIDGE_LAST_SUPPORTED; i++)
if (CARTRIDGE_kb[i] == kb) {
sprintf(tmp, "%d", i);
str = (*env)->NewStringUTF(env, tmp);
(*env)->SetObjectArrayElement(env, xarr, 0, str);
(*env)->DeleteLocalRef(env, str);
str = (*env)->NewStringUTF(env, cart_descriptions[i]);
(*env)->SetObjectArrayElement(env, xarr, 1, str);
(*env)->DeleteLocalRef(env, str);
(*env)->SetObjectArrayElement(env, arr, cnt++, xarr);
(*env)->DeleteLocalRef(env, xarr);
xarr = (*env)->NewObjectArray(env, 2, scls, NULL);
}
(*env)->SetObjectField(env, this, fid, arr);
ret = -2;
} else if (r == AFILE_ERROR) {
Log_print("Cannot start image: %s", img_utf);
ret = -1;
} else
CPU_cim_encountered = FALSE;
(*env)->ReleaseStringUTFChars(env, img, img_utf);
return ret;
}
static void JNICALL NativeBootCartType(JNIEnv *env, jobject this, jint kb)
{
CARTRIDGE_SetTypeAutoReboot(&CARTRIDGE_main, kb);
Atari800_Coldstart();
}
static void JNICALL NativeExit(JNIEnv *env, jobject this)
{
Atari800_Exit(FALSE);
}
static jint JNICALL NativeRunFrame(JNIEnv *env, jobject this)
{
static int old_cim = FALSE;
int ret = 0;
do {
INPUT_key_code = PLATFORM_Keyboard();
if (!CPU_cim_encountered)
Atari800_Frame();
else
Atari800_display_screen = TRUE;
if (Atari800_display_screen || CPU_cim_encountered)
PLATFORM_DisplayScreen();
if (!old_cim && CPU_cim_encountered)
ret = 1;
old_cim = CPU_cim_encountered;
} while (!Atari800_display_screen);
if (dev_b_status.ready && devb_url[0] == '\0')
if (strlen(dev_b_status.url)) {
strncpy(devb_url, dev_b_status.url, sizeof(devb_url));
Log_print("Received b: device URL: %s", devb_url);
ret |= 2;
} else
Log_print("Device b: signalled with zero-length url");
return ret;
}
static void JNICALL NativeSoundInit(JNIEnv *env, jobject this, jint size)
{
jclass cls;
jfieldID fid;
jintArray arr;
struct audiothread *at;
Log_print("Audio init with buffer size %d", size);
if (pthread_getspecific(audiothread_data))
Log_print("Audiothread data already allocated for current thread");
at = (struct audiothread *) malloc(sizeof(struct audiothread));
cls = (*env)->GetObjectClass(env, this);
fid = (*env)->GetFieldID(env, cls, "_buffer", "[B");
arr = (*env)->GetObjectField(env, this, fid);
at->sndarray = (*env)->NewGlobalRef(env, arr);
at->sndbuf = malloc(size);
if (!at->sndbuf) Log_print("Cannot allocate memory for sound buffer");
pthread_setspecific(audiothread_data, at);
}
static void JNICALL NativeSoundUpdate(JNIEnv *env, jobject this, jint offset, jint length)
{
struct audiothread *at;
if ( !(at = (struct audiothread *) pthread_getspecific(audiothread_data)) )
return;
SoundThread_Update(at->sndbuf, offset, length);
(*env)->SetByteArrayRegion(env, at->sndarray, offset, length, at->sndbuf + offset);
}
static void JNICALL NativeSoundExit(JNIEnv *env, jobject this)
{
struct audiothread *at;
Log_print("Audio exit");
if ( !(at = (struct audiothread *) pthread_getspecific(audiothread_data)) )
return;
(*env)->DeleteGlobalRef(env, at->sndarray);
if (at->sndbuf)
free(at->sndbuf);
free(at);
pthread_setspecific(audiothread_data, NULL);
}
static void JNICALL NativeKey(JNIEnv *env, jobject this, int k, int s)
{
Android_KeyEvent(k, s);
}
static int JNICALL NativeTouch(JNIEnv *env, jobject this, int x1, int y1, int s1,
int x2, int y2, int s2)
{
return Android_TouchEvent(x1, y1, s1, x2, y2, s2);
}
static void JNICALL NativePrefGfx(JNIEnv *env, jobject this, int aspect, jboolean bilinear,
int artifact, int frameskip, jboolean collisions, int crophoriz,
int cropvert)
{
Android_Aspect = aspect;
Android_Bilinear = bilinear;
ANTIC_artif_mode = artifact;
ANTIC_UpdateArtifacting();
if (frameskip == 0) {
Atari800_refresh_rate = 1;
Atari800_auto_frameskip = TRUE;
} else {
Atari800_auto_frameskip = FALSE;
Atari800_refresh_rate = frameskip;
}
Atari800_collisions_in_skipped_frames = collisions;
Android_CropScreen[0] = (SCANLINE_LEN - crophoriz) / 2;
Android_CropScreen[2] = crophoriz;
Android_CropScreen[1] = SCREEN_HEIGHT - (SCREEN_HEIGHT - cropvert) / 2;
Android_CropScreen[3] = -cropvert;
Screen_visible_x1 = SCANLINE_START + Android_CropScreen[0];
Screen_visible_x2 = Screen_visible_x1 + crophoriz;
Screen_visible_y1 = SCREEN_HEIGHT - Android_CropScreen[1];
Screen_visible_y2 = Screen_visible_y1 + cropvert;
}
static jboolean JNICALL NativePrefMachine(JNIEnv *env, jobject this, int nummac, jboolean ntsc)
{
struct tSysConfig {
int type;
int ram;
};
static const struct tSysConfig machine[] = {
{ Atari800_MACHINE_800, 16 },
{ Atari800_MACHINE_800, 48 },
{ Atari800_MACHINE_800, 52 },
{ Atari800_MACHINE_800, 16 },
{ Atari800_MACHINE_800, 48 },
{ Atari800_MACHINE_800, 52 },
{ Atari800_MACHINE_XLXE, 16 },
{ Atari800_MACHINE_XLXE, 64 },
{ Atari800_MACHINE_XLXE, 128 },
{ Atari800_MACHINE_XLXE, 192 },
{ Atari800_MACHINE_XLXE, MEMORY_RAM_320_RAMBO },
{ Atari800_MACHINE_XLXE, MEMORY_RAM_320_COMPY_SHOP },
{ Atari800_MACHINE_XLXE, 576 },
{ Atari800_MACHINE_XLXE, 1088 },
{ Atari800_MACHINE_5200, 16 }
};
Atari800_SetMachineType(machine[nummac].type);
MEMORY_ram_size = machine[nummac].ram;
/* Temporary hack to allow choosing OS rev. A/B and XL/XE features.
Delete after adding proper support for choosing system settings. */
if (nummac < 3)
SYSROM_os_versions[Atari800_MACHINE_800] = ntsc ? SYSROM_A_NTSC : SYSROM_A_PAL;
else if (nummac >= 3 && nummac < 6)
/* If no OSB NTSC ROM present, try the "custom" 400/800 ROM. */
SYSROM_os_versions[Atari800_MACHINE_800] =
SYSROM_roms[SYSROM_B_NTSC].filename[0] == '\0' ?
SYSROM_800_CUSTOM :
SYSROM_B_NTSC;
else if (Atari800_machine_type == Atari800_MACHINE_XLXE) {
Atari800_builtin_basic = TRUE;
Atari800_keyboard_leds = FALSE;
Atari800_f_keys = FALSE;
Atari800_jumper = FALSE;
Atari800_builtin_game = FALSE;
Atari800_keyboard_detached = FALSE;
}
/* End of hack */
Atari800_SetTVMode(ntsc ? Atari800_TV_NTSC : Atari800_TV_PAL);
CPU_cim_encountered = FALSE;
return Atari800_InitialiseMachine();
}
static void JNICALL NativePrefEmulation(JNIEnv *env, jobject this, jboolean basic, jboolean speed,
jboolean disk, jboolean sector, jboolean browser)
{
Atari800_disable_basic = basic;
Screen_show_atari_speed = speed;
Screen_show_disk_led = disk;
Screen_show_sector_counter = sector;
Devices_enable_b_patch = browser;
Devices_UpdatePatches();
}
static void JNICALL NativePrefSoftjoy(JNIEnv *env, jobject this, jboolean softjoy, int up, int down,
int left, int right, int fire, int derotkeys, jobjectArray actions)
{
int i;
jobject obj;
const char *str;
char *sep;
UBYTE act, akey;
Android_SoftjoyEnable = softjoy;
softjoymap[SOFTJOY_UP][0] = up;
softjoymap[SOFTJOY_DOWN][0] = down;
softjoymap[SOFTJOY_LEFT][0] = left;
softjoymap[SOFTJOY_RIGHT][0] = right;
softjoymap[SOFTJOY_FIRE][0] = fire;
Android_DerotateKeys = derotkeys;
for (i = 0; i < SOFTJOY_MAXACTIONS; i++) {
obj = (*env)->GetObjectArrayElement(env, actions, i);
str = (*env)->GetStringUTFChars(env, obj, NULL);
sep = strchr(str, ',');
act = ACTION_NONE;
akey = AKEY_NONE;
if (sep) {
act = atoi(str);
akey = atoi(sep + 1);
}
softjoymap[SOFTJOY_ACTIONBASE + i][0] = act;
softjoymap[SOFTJOY_ACTIONBASE + i][1] = akey;
(*env)->ReleaseStringUTFChars(env, obj, str);
(*env)->DeleteLocalRef(env, obj);
}
}
static void config_PD(void)
{
INPUT_mouse_mode = INPUT_MOUSE_PAD;
Android_Splitpct = 1.0f;
AndroidInput_JoyOvl.ovl_visible = FALSE;
Android_PlanetaryDefense = TRUE;
Android_Paddle = TRUE;
Android_ReversePddle = 3;
}
static void JNICALL NativePrefJoy(JNIEnv *env, jobject this, jboolean visible, int size, int opacity,
jboolean righth, int deadband, jboolean midx, int anchor, int anchorx,
int anchory, int grace, jboolean paddle, jboolean plandef)
{
AndroidInput_JoyOvl.ovl_visible = visible;
AndroidInput_JoyOvl.areaopacityset = 0.01f * opacity;
Android_Joyscale = 0.01f * size;
Android_Joyleft = !righth;
Android_Splitpct = 0.01f * midx;
AndroidInput_JoyOvl.deadarea = 0.01f * deadband;
AndroidInput_JoyOvl.gracearea = 0.02f * grace;
AndroidInput_JoyOvl.anchor = anchor;
if (anchor) {
AndroidInput_JoyOvl.joyarea.l = anchorx;
AndroidInput_JoyOvl.joyarea.t = anchory;
}
Android_Paddle = paddle;
INPUT_mouse_mode = paddle ? INPUT_MOUSE_PAD : INPUT_MOUSE_OFF;
Android_PlanetaryDefense = FALSE;
Android_ReversePddle = 0;
if (plandef)
config_PD();
Android_SplitCalc();
Joyovl_Scale();
Joy_Reposition();
}
static void JNICALL NativePrefSound(JNIEnv *env, jobject this, int mixrate, int bufsizems,
jboolean sound16bit, jboolean hqpokey, jboolean disableOSL)
{
Android_SoundInit(mixrate, bufsizems, sound16bit, hqpokey, disableOSL);
}
static jboolean JNICALL NativeSetROMPath(JNIEnv *env, jobject this, jstring path)
{
const jbyte *utf = NULL;
jboolean ret = JNI_FALSE;
utf = (*env)->GetStringUTFChars(env, path, NULL);
SYSROM_FindInDir(utf, FALSE);
Log_print("sysrom %s %d", utf, SYSROM_FindInDir(utf, FALSE));
ret |= chdir(utf);
Log_print("sysrom %s %d", utf, SYSROM_FindInDir(utf, FALSE));
ret |= Atari800_InitialiseMachine();
(*env)->ReleaseStringUTFChars(env, path, utf);
return ret;
}
static jstring JNICALL NativeGetJoypos(JNIEnv *env, jobject this)
{
char tmp[16];
sprintf(tmp, "%d %d", AndroidInput_JoyOvl.joyarea.l, AndroidInput_JoyOvl.joyarea.t);
return (*env)->NewStringUTF(env, tmp);
}
static jstring JNICALL NativeGetURL(JNIEnv *env, jobject this)
{
return (*env)->NewStringUTF(env, dev_b_status.url);
}
static jboolean JNICALL NativeBootPD(JNIEnv *env, jobject this, jobjectArray img, jint sz)
{
FILE *fp;
void *src;
fp = fopen(PD2012_FNAME, "wb");
if (!fp) {
Log_print("ERROR: Cannot open PD2012 for write");
return FALSE;
}
src = (*env)->GetByteArrayElements(env, img, NULL);
fwrite(src, 1, sz, fp);
fclose(fp);
(*env)->ReleaseByteArrayElements(env, img, src, JNI_ABORT);
config_PD();
NativeUnmountAll(env, this);
CARTRIDGE_Remove();
return AFILE_OpenFile(PD2012_FNAME, TRUE, 1, FALSE);
}
static jboolean JNICALL NativeOSLSound(JNIEnv *env, jobject this)
{
return Android_osl_sound;
}
static jboolean JNICALL NativeOSLSoundPause(JNIEnv *env, jobject this, jboolean pause)
{
if (pause)
Sound_Pause();
else
Sound_Continue();
}
static void JNICALL NativeOSLSoundInit(JNIEnv *env, jobject this)
{
Sound_Initialise(0, NULL);
}
static void JNICALL NativeOSLSoundExit(JNIEnv *env, jobject this)
{
Sound_Exit();
}
jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNINativeMethod main_methods[] = {
{ "NativeExit", "()V", NativeExit },
{ "NativeRunAtariProgram", "(Ljava/lang/String;II)I", NativeRunAtariProgram },
{ "NativePrefGfx", "(IZIIZII)V", NativePrefGfx },
{ "NativePrefMachine", "(IZ)Z", NativePrefMachine },
{ "NativePrefEmulation", "(ZZZZZ)V", NativePrefEmulation },
{ "NativePrefSoftjoy", "(ZIIIIII[Ljava/lang/String;)V", NativePrefSoftjoy },
{ "NativePrefJoy", "(ZIIZIIZIIIZZ)V", NativePrefJoy },
{ "NativePrefSound", "(IIZZZ)V", NativePrefSound },
{ "NativeSetROMPath", "(Ljava/lang/String;)Z", NativeSetROMPath },
{ "NativeGetJoypos", "()Ljava/lang/String;", NativeGetJoypos },
{ "NativeInit", "()Ljava/lang/String;", NativeInit },
{ "NativeGetURL", "()Ljava/lang/String;", NativeGetURL },
{ "NativeClearDevB", "()V", NativeClearDevB },
{ "NativeBootCartType", "(I)V", NativeBootCartType },
};
JNINativeMethod view_methods[] = {
{ "NativeTouch", "(IIIIII)I", NativeTouch },
{ "NativeKey", "(II)V", NativeKey },
};
JNINativeMethod snd_methods[] = {
{ "NativeSoundInit", "(I)V", NativeSoundInit },
{ "NativeSoundUpdate", "(II)V", NativeSoundUpdate },
{ "NativeSoundExit", "()V", NativeSoundExit },
{ "NativeOSLSound", "()Z", NativeOSLSound },
{ "NativeOSLSoundInit", "()V", NativeOSLSoundInit },
{ "NativeOSLSoundExit", "()V", NativeOSLSoundExit },
{ "NativeOSLSoundPause", "(Z)V", NativeOSLSoundPause },
};
JNINativeMethod render_methods[] = {
{ "NativeRunFrame", "()I", NativeRunFrame },
{ "NativeGetOverlays", "()V", NativeGetOverlays },
{ "NativeResize", "(II)V", NativeResize },
};
JNINativeMethod fsel_methods[] = {
{ "NativeIsDisk", "(Ljava/lang/String;)Z", NativeIsDisk },
{ "NativeRunAtariProgram", "(Ljava/lang/String;II)I", NativeRunAtariProgram },
{ "NativeGetDrvFnames", "()[Ljava/lang/String;", NativeGetDrvFnames },
{ "NativeUnmountAll", "()V", NativeUnmountAll },
};
JNINativeMethod pref_methods[] = {
{ "NativeSaveState", "(Ljava/lang/String;)Z", NativeSaveState },
{ "NativeBootPD", "([BI)Z", NativeBootPD },
{ "NativeOSLSound", "()Z", NativeOSLSound },
};
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2))
return JNI_ERR;
cls = (*env)->FindClass(env, "name/nick/jubanka/colleen/MainActivity");
(*env)->RegisterNatives(env, cls, main_methods, sizeof(main_methods)/sizeof(JNINativeMethod));
cls = (*env)->FindClass(env, "name/nick/jubanka/colleen/A800view");
(*env)->RegisterNatives(env, cls, view_methods, sizeof(view_methods)/sizeof(JNINativeMethod));
cls = (*env)->FindClass(env, "name/nick/jubanka/colleen/AudioThread");
(*env)->RegisterNatives(env, cls, snd_methods, sizeof(snd_methods)/sizeof(JNINativeMethod));
cls = (*env)->FindClass(env, "name/nick/jubanka/colleen/A800Renderer");
(*env)->RegisterNatives(env, cls, render_methods, sizeof(render_methods)/sizeof(JNINativeMethod));
cls = (*env)->FindClass(env, "name/nick/jubanka/colleen/FileSelector");
(*env)->RegisterNatives(env, cls, fsel_methods, sizeof(fsel_methods)/sizeof(JNINativeMethod));
cls = (*env)->FindClass(env, "name/nick/jubanka/colleen/Preferences");
(*env)->RegisterNatives(env, cls, pref_methods, sizeof(pref_methods)/sizeof(JNINativeMethod));
return JNI_VERSION_1_2;
}
+139
View File
@@ -0,0 +1,139 @@
#define STATIC_MAXKEYS 256
#define KEY_SHIFT 256
#define KEY_CONTROL 257
#define KEY_BACKSPACE 255
#define KEY_UP 254
#define KEY_DOWN 253
#define KEY_LEFT 252
#define KEY_RIGHT 251
#define KEY_FIRE 250
#define KEY_ENTER 249
#define KEY_ESCAPE 248
#define KEY_BREAK 242
static const SWORD skeyxlat[STATIC_MAXKEYS] = {
[0 ... (STATIC_MAXKEYS - 1)] = AKEY_NONE,
['0'] = AKEY_0,
['1'] = AKEY_1,
['2'] = AKEY_2,
['3'] = AKEY_3,
['4'] = AKEY_4,
['5'] = AKEY_5,
['6'] = AKEY_6,
['7'] = AKEY_7,
['8'] = AKEY_8,
['9'] = AKEY_9,
['a'] = AKEY_a,
['b'] = AKEY_b,
['c'] = AKEY_c,
['d'] = AKEY_d,
['e'] = AKEY_e,
['f'] = AKEY_f,
['g'] = AKEY_g,
['h'] = AKEY_h,
['i'] = AKEY_i,
['j'] = AKEY_j,
['k'] = AKEY_k,
['l'] = AKEY_l,
['m'] = AKEY_m,
['n'] = AKEY_n,
['o'] = AKEY_o,
['p'] = AKEY_p,
['q'] = AKEY_q,
['r'] = AKEY_r,
['s'] = AKEY_s,
['t'] = AKEY_t,
['u'] = AKEY_u,
['v'] = AKEY_v,
['w'] = AKEY_w,
['x'] = AKEY_x,
['y'] = AKEY_y,
['z'] = AKEY_z,
['A'] = AKEY_A,
['B'] = AKEY_B,
['C'] = AKEY_C,
['D'] = AKEY_D,
['E'] = AKEY_E,
['F'] = AKEY_F,
['G'] = AKEY_G,
['H'] = AKEY_H,
['I'] = AKEY_I,
['J'] = AKEY_J,
['K'] = AKEY_K,
['L'] = AKEY_L,
['M'] = AKEY_M,
['N'] = AKEY_N,
['O'] = AKEY_O,
['P'] = AKEY_P,
['Q'] = AKEY_Q,
['R'] = AKEY_R,
['S'] = AKEY_S,
['T'] = AKEY_T,
['U'] = AKEY_U,
['V'] = AKEY_V,
['W'] = AKEY_W,
['X'] = AKEY_X,
['Y'] = AKEY_Y,
['Z'] = AKEY_Z,
['\e'] = AKEY_ESCAPE,
['~'] = AKEY_ESCAPE,
['\t'] = AKEY_TAB,
['\n'] = AKEY_RETURN,
[' '] = AKEY_SPACE,
['!'] = AKEY_EXCLAMATION,
['\"'] = AKEY_DBLQUOTE,
['#'] = AKEY_HASH,
['$'] = AKEY_DOLLAR,
['%'] = AKEY_PERCENT,
['&'] = AKEY_AMPERSAND,
['\''] = AKEY_QUOTE,
['@'] = AKEY_AT,
['('] = AKEY_PARENLEFT,
[')'] = AKEY_PARENRIGHT,
['<'] = AKEY_LESS,
['>'] = AKEY_GREATER,
['='] = AKEY_EQUAL,
['?'] = AKEY_QUESTION,
['-'] = AKEY_MINUS,
['+'] = AKEY_PLUS,
['*'] = AKEY_ASTERISK,
['/'] = AKEY_SLASH,
[':'] = AKEY_COLON,
[';'] = AKEY_SEMICOLON,
[','] = AKEY_COMMA,
['.'] = AKEY_FULLSTOP,
['_'] = AKEY_UNDERSCORE,
['['] = AKEY_BRACKETLEFT,
[']'] = AKEY_BRACKETRIGHT,
['^'] = AKEY_CIRCUMFLEX,
['\\'] = AKEY_BACKSLASH,
['|'] = AKEY_BAR,
['`'] = AKEY_CAPSTOGGLE,
['{'] = AKEY_ATARI,
[KEY_BACKSPACE] = AKEY_BACKSPACE,
[KEY_UP ] = AKEY_UP,
[KEY_DOWN ] = AKEY_DOWN,
[KEY_LEFT ] = AKEY_LEFT,
[KEY_RIGHT ] = AKEY_RIGHT,
[KEY_ENTER ] = AKEY_RETURN,
[KEY_ESCAPE ] = AKEY_ESCAPE,
[KEY_BREAK ] = AKEY_BREAK,
/* unmapped codes
#define AKEY_HELP 0x11
#define AKEY_DELETE_CHAR 0xb4
#define AKEY_DELETE_LINE 0x74
#define AKEY_INSERT_CHAR 0xb7
#define AKEY_INSERT_LINE 0x77
#define AKEY_SETTAB 0x6c
#define AKEY_CLRTAB 0xac
*/
};
+86
View File
@@ -0,0 +1,86 @@
/*
* platform.c - platform interface implementation for android
*
* Copyright (C) 2010 Kostas Nakos
* Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "atari.h"
#include "cpu.h"
#include "input.h"
#include "devices.h"
#include "graphics.h"
#include "androidinput.h"
int PLATFORM_Initialise(int *argc, char *argv[])
{
/* Android_InitGraphics() is deferred until GL surface is created */
/* Sound_Initialise() not needed */
Log_print("Core init");
Input_Initialize();
Devices_enable_h_patch = FALSE;
INPUT_direct_mouse = TRUE;
return TRUE;
}
int PLATFORM_Exit(int run_monitor)
{
if (CPU_cim_encountered) {
Log_print("CIM encountered");
return TRUE;
}
Log_print("Core_exit");
Android_ExitGraphics();
return FALSE;
}
int PLATFORM_Keyboard(void)
{
return Keyboard_Dequeue();
}
void PLATFORM_DisplayScreen(void)
{
Android_ConvertScreen();
Android_Render();
Update_Overlays();
}
void PLATFORM_PaletteUpdate(void)
{
Android_PaletteUpdate();
}
int PLATFORM_PORT(int num)
{
return (Android_PortStatus >> (num << 3)) & 0xFF;
}
int PLATFORM_TRIG(int num)
{
return (Android_TrigStatus >> num) & 0x1;
}
+381
View File
@@ -0,0 +1,381 @@
/*
* sound.c - android sound
*
* Copyright (C) 2014 Kostas Nakos
* Copyright (C) 2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <dlfcn.h>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include "pokeysnd.h"
#include "log.h"
static int at_sixteenbit = 0;
static int snd_bufsizems = 0;
static int snd_mixrate = 0;
#define OSL_BUFSIZE_MS 10
static void *osl_handle;
int Android_osl_sound;
static int osl_disable = 0;
static int osl_bufnum = 0;
static int osl_bufszbytes = 0;
static UBYTE *osl_soundbuf = NULL;
static UBYTE **osl_soundbufptr = NULL;
static ULONG osl_lastplayedindex = 0;
static volatile ULONG osl_lastindex = 0;
static int osl_nextbufindex = 0;
static SLObjectItf osl_engine = NULL,
osl_mixer = NULL,
osl_player = NULL;
static SLEngineItf osl_engineif = NULL;
static SLPlayItf osl_playif = NULL;
static SLAndroidSimpleBufferQueueItf osl_bufqif = NULL;
static SLresult SLAPIENTRY (*osl_slCreateEngine) (
SLObjectItf *pEngine,
SLuint32 numOptions,
const SLEngineOption *pEngineOptions,
SLuint32 numInterfaces,
const SLInterfaceID *pInterfaceIds,
const SLboolean * pInterfaceRequired
) = NULL;
static SLAPIENTRY const SLInterfaceID *osl_SL_IID_VOLUME;
static SLAPIENTRY const SLInterfaceID *osl_SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
static SLAPIENTRY const SLInterfaceID *osl_SL_IID_ENGINE;
static SLAPIENTRY const SLInterfaceID *osl_SL_IID_PLAY;
#define CHECK_OSL(command, errmsg) \
if ( (res = command) != SL_RESULT_SUCCESS ) { \
Log_print("ERROR: OSL: Cannot " errmsg " (%08X)", res); \
return FALSE; \
} else \
(void) 0
#define GET_SYMBOL(var, sname) \
var = dlsym(osl_handle, sname); \
errstr = dlerror(); \
if (errstr) { \
Log_print("ERROR: Cannot resolve " sname ": %s", errstr); \
return FALSE; \
} else \
(void) 0
void Sound_Continue(void);
/* Legacy AudioThread functions */
void Android_SoundInit(int rate, int bufsizems, int bit16, int hq, int disableOSL)
{
Log_print("SoundInit for android initializing with %dHz, %d bufsize, OSL %s",
rate, bufsizems, (disableOSL) ? "off" : "on");
POKEYSND_bienias_fix = 0;
POKEYSND_enable_new_pokey = hq;
at_sixteenbit = bit16;
snd_bufsizems = bufsizems;
snd_mixrate = rate;
osl_bufnum = snd_bufsizems / OSL_BUFSIZE_MS;
osl_bufszbytes = OSL_BUFSIZE_MS * (at_sixteenbit ? 2 : 1) * snd_mixrate / 1000;
osl_disable = disableOSL;
if (disableOSL)
Android_osl_sound = FALSE;
Log_print("Initializing POKEY");
POKEYSND_Init(POKEYSND_FREQ_17_EXACT, rate, 1, bit16 ? POKEYSND_BIT16 : 0);
Log_print("POKEY init done");
}
void SoundThread_Update(void *buf, int offs, int len)
{
POKEYSND_Process(buf + offs, len >> at_sixteenbit);
}
/* Native sound helpers */
static int OSL_grab_functions(void)
{
const char *errstr;
dlerror();
GET_SYMBOL(osl_slCreateEngine, "slCreateEngine");
GET_SYMBOL(osl_SL_IID_VOLUME, "SL_IID_VOLUME");
GET_SYMBOL(osl_SL_IID_ANDROIDSIMPLEBUFFERQUEUE, "SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
GET_SYMBOL(osl_SL_IID_ENGINE, "SL_IID_ENGINE");
GET_SYMBOL(osl_SL_IID_PLAY, "SL_IID_PLAY");
return TRUE;
}
static int OSL_load(void)
{
osl_handle = dlopen("libOpenSLES.so", RTLD_LAZY);
if (! osl_handle) {
Log_print("Cannot dlopen OSL");
return FALSE;
}
if ( OSL_grab_functions() ) {
Log_print("Open SL ES found and bound");
return TRUE;
}
return FALSE;
}
void OSL_process(SLAndroidSimpleBufferQueueItf bufqif, void *ctx)
{
SLAndroidSimpleBufferQueueState st;
if ( (*bufqif)->GetState(bufqif, &st) != SL_RESULT_SUCCESS ) {
Log_print("ERROR: Cannot get queue state");
return;
}
osl_lastindex = st.index;
}
static int OSL_init(void)
{
SLresult res;
const SLInterfaceID mixids[] = { *osl_SL_IID_VOLUME };
const SLboolean mixreq[] = { SL_BOOLEAN_FALSE };
SLDataLocator_AndroidSimpleBufferQueue dlsbq = {
.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
.numBuffers = osl_bufnum
};
SLDataFormat_PCM dfpcm = {
.formatType = SL_DATAFORMAT_PCM,
.numChannels = 1,
.samplesPerSec = (snd_mixrate == 44100) ? SL_SAMPLINGRATE_44_1 :
(snd_mixrate == 22050) ? SL_SAMPLINGRATE_22_05 :
(snd_mixrate == 11025) ? SL_SAMPLINGRATE_11_025:
0,
.bitsPerSample = (at_sixteenbit) ? SL_PCMSAMPLEFORMAT_FIXED_16 : SL_PCMSAMPLEFORMAT_FIXED_8,
.containerSize = (at_sixteenbit) ? SL_PCMSAMPLEFORMAT_FIXED_16 : SL_PCMSAMPLEFORMAT_FIXED_8,
.channelMask = SL_SPEAKER_FRONT_CENTER,
.endianness = SL_BYTEORDER_LITTLEENDIAN
};
SLDataSource dsrc = {
.pLocator = &dlsbq,
.pFormat = &dfpcm
};
SLDataLocator_OutputMix dlmix = {
.locatorType = SL_DATALOCATOR_OUTPUTMIX,
.outputMix = NULL
};
SLDataSink dsnk = {
.pLocator = &dlmix,
.pFormat = NULL
};
const SLInterfaceID apids[] = { *osl_SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean apreq[] = { SL_BOOLEAN_TRUE };
if (dfpcm.samplesPerSec == 0) {
Log_print("ERROR: Incorrect mixrate %d", snd_mixrate);
return FALSE;
}
/* engine */
CHECK_OSL( osl_slCreateEngine(&osl_engine, 0, NULL, 0, NULL, NULL), "create engine");
CHECK_OSL( (*osl_engine)->Realize(osl_engine, SL_BOOLEAN_FALSE), "realize engine");
CHECK_OSL( (*osl_engine)->GetInterface(osl_engine, *osl_SL_IID_ENGINE, &osl_engineif), "get engine i/f");
/* mixer */
CHECK_OSL( (*osl_engineif)->CreateOutputMix(osl_engineif, &osl_mixer, 1, mixids, mixreq), "create mixer");
CHECK_OSL( (*osl_mixer)->Realize(osl_mixer, SL_BOOLEAN_FALSE), "realize mixer");
dlmix.outputMix = osl_mixer;
/* player */
CHECK_OSL( (*osl_engineif)->CreateAudioPlayer(osl_engineif, &osl_player, &dsrc, &dsnk, 1, apids, apreq), "create player");
CHECK_OSL( (*osl_player)->Realize(osl_player, SL_BOOLEAN_FALSE), "realize player");
CHECK_OSL( (*osl_player)->GetInterface(osl_player, *osl_SL_IID_PLAY, &osl_playif), "get player i/f");
CHECK_OSL( (*osl_player)->GetInterface(osl_player, *osl_SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &osl_bufqif), "get buffer queue i/f");
/* register callback */
CHECK_OSL( (*osl_bufqif)->RegisterCallback(osl_bufqif, OSL_process, NULL), "register callback");
Log_print("OpenSL ES initialized successfully");
return TRUE;
}
static void OSL_stop_playback(void)
{
SLuint32 playstate;
(*osl_playif)->SetPlayState(osl_playif, SL_PLAYSTATE_STOPPED);
Log_print("Waiting for OSL player to finish");
do {
usleep(50000);
(*osl_playif)->GetPlayState(osl_playif, &playstate);
} while (playstate != SL_PLAYSTATE_STOPPED);
Log_print("Playback finished");
}
static void OSL_teardown(void)
{
if (osl_playif) {
OSL_stop_playback();
(*osl_player)->Destroy(osl_player);
osl_player = NULL;
osl_playif = NULL;
osl_bufqif = NULL;
}
if (osl_mixer) {
(*osl_mixer)->Destroy(osl_mixer);
osl_mixer = NULL;
}
if (osl_engine) {
(*osl_engine)->Destroy(osl_engine);
osl_engine = NULL;
osl_engineif = NULL;
}
Log_print("OpenSL teardown complete");
}
static void OSL_buf_free(void)
{
if (osl_soundbufptr) {
free(osl_soundbufptr);
osl_soundbufptr = NULL;
}
if (osl_soundbuf) {
free(osl_soundbuf);
osl_soundbuf = NULL;
}
}
static int OSL_buf_alloc(void)
{
UBYTE *ptr;
int i;
if (osl_soundbuf || osl_soundbufptr) {
Log_print("WARNING: Sound buffers already allocated. Freeing.");
OSL_buf_free();
}
if (! ( osl_soundbufptr = (UBYTE **) malloc(osl_bufnum * sizeof(void *)) ) ) {
Log_print("ERROR: Cannot allocate sound buffer pointers (%d)", osl_bufnum);
return FALSE;
}
if (! ( osl_soundbuf = (UBYTE *) malloc(osl_bufnum * osl_bufszbytes) ) ) {
Log_print("ERROR: Cannot allocate sound buffer for %d buffers of %d bytes each", osl_bufnum, osl_bufszbytes);
return FALSE;
}
memset(osl_soundbuf, 0, osl_bufnum * osl_bufszbytes);
for (ptr = osl_soundbuf, i = 0; i < osl_bufnum; i++, ptr += osl_bufszbytes)
osl_soundbufptr[i] = ptr;
Log_print("Allocated OK sound buffer for %d buffers %dms each, %d bits at %dHz",
osl_bufnum, OSL_BUFSIZE_MS, (at_sixteenbit) ? 16 : 8, snd_mixrate);
return TRUE;
}
static int OSL_start_playback(void)
{
SLresult res;
int i;
Sound_Continue();
for (i = 0; i < osl_bufnum; i++) {
if (! osl_bufqif) return FALSE;
CHECK_OSL( (*osl_bufqif)->Enqueue(osl_bufqif, osl_soundbufptr[i], osl_bufszbytes), "enqueue init buffer");
}
osl_nextbufindex = 0;
osl_lastindex = osl_lastplayedindex = 0;
Log_print("Buffer queue bootstrap OK");
return TRUE;
}
/* Platform interface. Used only with SL sound */
void Sound_Exit(void)
{
Log_print("Sound exit");
OSL_teardown();
OSL_buf_free();
if (osl_handle) {
dlclose(osl_handle);
osl_handle = NULL;
}
Android_osl_sound = FALSE;
}
int Sound_Initialise(int *argc, char *argv[])
{
Android_osl_sound = TRUE;
if (
osl_disable ||
! OSL_load() ||
! OSL_init() ||
! OSL_buf_alloc() ||
! OSL_start_playback()
)
{
Android_osl_sound = FALSE;
Sound_Exit();
Log_print("Using legacy AudioThread");
} else
Log_print("Using OpenSL ES sound");
return 1;
}
void Sound_Update(void)
{
SLresult res;
while (osl_lastplayedindex < osl_lastindex) {
if (! osl_soundbufptr) return;
POKEYSND_Process(osl_soundbufptr[osl_nextbufindex], osl_bufszbytes >> at_sixteenbit);
if (! osl_bufqif) return;
res = (*osl_bufqif)->Enqueue(osl_bufqif, osl_soundbufptr[osl_nextbufindex], osl_bufszbytes);
if (res != SL_RESULT_SUCCESS) {
Log_print("Cannot enqueue buffer #%d (%08X)", osl_nextbufindex, res);
return;
}
osl_nextbufindex = (osl_nextbufindex + 1) % osl_bufnum;
osl_lastplayedindex++;
}
}
void Sound_Pause(void)
{
Log_print("OSL pausing sound");
if (! osl_playif) return;
(*osl_playif)->SetPlayState(osl_playif, SL_PLAYSTATE_PAUSED);
}
void Sound_Continue(void)
{
Log_print("OSL resuming sound");
if (! osl_playif) return;
(*osl_playif)->SetPlayState(osl_playif, SL_PLAYSTATE_PLAYING);
}
+14
View File
@@ -0,0 +1,14 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-20
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#BB000000" />
</shape>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

@@ -0,0 +1,36 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:padding="10dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/header"
android:text="@string/pref_keymapmsg2"
android:textAppearance="@android:style/TextAppearance.Medium"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/keyinput"
android:hint="@string/pref_typeatarikey"
android:lines="1"
android:maxLines="1"
android:maxLength="1"
android:inputType="textNoSuggestions"
android:imeOptions="actionDone"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/note"
android:text="@string/pref_keymapmsg2note"
android:textAppearance="@android:style/TextAppearance.Small"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@id/android:list"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_above="@+id/footer"/>
<LinearLayout
android:id="@+id/footer"
android:background="@android:color/darker_gray"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:padding="5dp">
<Button
android:id="@+id/fsel_ok"
android:text="@string/selectdir"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/fsel_cancel"
android:text="@string/cancel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
</RelativeLayout>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/fsel_image"
android:layout_height="30dp"
android:layout_width="40dp"
android:paddingLeft="10dp"/>
<TextView
android:id="@+id/fsel_text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="10dp"
android:gravity="center_vertical"
android:textSize="14sp"
android:singleLine="true"
android:ellipsize="end"/>
</LinearLayout>
@@ -0,0 +1,20 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:padding="10dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<SeekBar
android:id="@+id/slider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:max="99"/>
<TextView
android:id="@+id/setting"
android:text="99%"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="fill_parent"/>
</LinearLayout>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_search"
android:title="@string/fselmenu_search"
android:icon="@drawable/ic_menu_search"
android:showAsAction="ifRoom|collapseActionView"
android:actionViewClass="android.widget.SearchView" />
</menu>
+20
View File
@@ -0,0 +1,20 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_open"
android:title="@string/menu_open"
android:icon="@drawable/ic_menu_archive"
android:showAsAction="ifRoom"/>
<item android:id="@+id/menu_nextdisk"
android:title="@string/menu_nextdisk"
android:icon="@drawable/ic_menu_rotate"
android:showAsAction="ifRoom"/>
<item android:id="@+id/menu_softkbd"
android:title="@string/menu_softkbd"
android:icon="@drawable/keyboard"
android:showAsAction="ifRoom"/>
<item android:id="@+id/menu_preferences"
android:title="@string/menu_preferences"
android:icon="@drawable/ic_menu_preferences"/>
<item android:id="@+id/menu_quit"
android:title="@string/menu_quit"
android:icon="@drawable/ic_menu_close_clear_cancel"/>
</menu>
@@ -0,0 +1,5 @@
<resources>
<style name="MainTheme" parent="@android:style/Theme.Holo">
<item name="android:windowActionBarOverlay">true</item>
</style>
</resources>
+122
View File
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="aspect">
<item>@string/none</item>
<item>@string/asp_portrait</item>
<item>@string/asp_landscape</item>
<item>@string/asp_both</item>
</string-array>
<string-array name="aspect_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="artifact">
<item>@string/none</item>
<item>@string/art_bluebrown1</item>
<item>@string/art_bluebrown2</item>
<item>@string/art_gtia</item>
<item>@string/art_ctia</item>
</string-array>
<string-array name="artifact_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</string-array>
<string-array name="machine">
<item>Atari OS/A (16 KB)</item>
<item>Atari OS/A (48 KB)</item>
<item>Atari OS/A (52 KB)</item>
<item>Atari OS/B (16 KB)</item>
<item>Atari OS/B (48 KB)</item>
<item>Atari OS/B (52 KB)</item>
<item>Atari 600XL (16 KB)</item>
<item>Atari 800XL (64 KB)</item>
<item>Atari 130XE (128 KB)</item>
<item>Atari XL/XE (192 KB)</item>
<item>Atari XL/XE (320 KB RAMBO)</item>
<item>Atari XL/XE (320 KB COMPY SHOP)</item>
<item>Atari XL/XE (576 KB)</item>
<item>Atari XL/XE (1088 KB)</item>
<item>Atari 5200 (16 KB)</item>
</string-array>
<string-array name="machine_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
</string-array>
<string-array name="frameskip">
<item>@string/skipauto</item>
<item>@string/skip0</item>
<item>@string/skip1</item>
<item>@string/skip2</item>
<item>@string/skip3</item>
<item>@string/skip4</item>
<item>@string/skip5</item>
</string-array>
<string-array name="frameskip_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
</string-array>
<string-array name="mixrate">
<item>44100 Hz</item>
<item>22050 Hz</item>
<item>11025 Hz</item>
</string-array>
<string-array name="mixrate_values">
<item>44100</item>
<item>22050</item>
<item>11025</item>
</string-array>
<string-array name="derotkeys">
<item>@string/none</item>
<item>@string/left</item>
<item>@string/right</item>
</string-array>
<string-array name="derotkeys_values">
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
<string-array name="changes_strings">
<item>@string/changesv1_1a</item>
<item>@string/changesv1_2</item>
<item>@string/changesv1_3</item>
<item>@string/changesv2_0</item>
<item>@string/changesv3_0</item>
</string-array>
<integer-array name="changes_versions">
<item>3</item>
<item>10</item>
<item>20</item>
<item>200</item>
<item>300</item>
</integer-array>
</resources>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SliderPreference">
<attr name="min" format="string"/>
<attr name="max" format="string"/>
<attr name="suffix" format="string"/>
</declare-styleable>
<declare-styleable name="KeymapPreference">
<attr name="ext" format="string"/>
</declare-styleable>
</resources>
+289
View File
@@ -0,0 +1,289 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Colleen</string>
<string name="menu_quit">Quit</string>
<string name="menu_softkbd">Keyboard</string>
<string name="menu_open">Open</string>
<string name="menu_nextdisk">Next Side</string>
<string name="fsel_openfile">Open File:</string>
<string name="fsel_opendir">Open Dir:</string>
<string name="fselmenu_search">Search</string>
<string name="warning">Warning</string>
<string name="mountnodisk">File %s is not a disk image.\nContinue?</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="mountdisk">Mount Image to Drive</string>
<string name="unmountall">Unmount all drives</string>
<string name="mountnextdisk">Image %s inserted</string>
<string name="mountnextdiskerror">Cannot insert image %s</string>
<string name="mountinsertdisk">Image %1$s inserted into drive D%2$d:</string>
<string name="savestateoverwrite">Save state file \'%s\' already exists. OK to overwrite?</string>
<string name="savestateerror">Error: Cannot save state</string>
<string name="savestateok">State saved</string>
<string name="mountnonextdisk">No next disk image found</string>
<string name="diskboot">Booting image %s</string>
<string name="errorboot">Cannot boot image %s</string>
<string name="none">None</string>
<string name="left">Left</string>
<string name="right">Right</string>
<string name="menu_preferences">Preferences</string>
<string name="cancel">Cancel</string>
<string name="ok">OK</string>
<string name="save">Save</string>
<string name="cimcrash">The Atari computer has crashed.\n
\nReset the machine or boot another image.</string>
<string name="noromfoundrevert">Failed to initialize machine. Required ROM not found.\n
\nYour machine change has been reverted.</string>
<string name="noromfound">Failed to initialize machine. Required ROM not found.</string>
<string name="pressback">Press \'Back\' once more to exit</string>
<string name="welcome">Welcome to Colleen!</string>
<string name="welcomenote">Hello,\n
\nJust a few tips to get you going:
\n1) Left hand joystick, right hand trigger (or search button).
\n2) Tap the top-right corner for console keys.
\n3) On Honeycomb (3.0)+ devices, tap near the screen\'s top for menu.
\n4) On earlier devices, hit \'Menu\' for preferences and more.
\n5) Long-press in the file selector to insert an image and not boot it.
\n6) Use the WiiController or the keyboard for accuracy.\n
\nFirst though, setup the Atari ROM path in the next dialog.\n
\nHave fun! </string>
<string name="pathsetup">Atari ROM Path</string>
<string name="pathsetupmsg"><![CDATA[
The emulator requires the original Atari ROM images.<br><br>
Touch <b>OK</b> to use the file selector to point to the folder containing
the ROM images.<br>
Touch <b>Cancel</b> to quit to the OS.<br><br>
Try the
<a href="http://atari800.sourceforge.net/download.html">Atari800 site</a>
for the XL ROMs.<br>
Valid ROM filenames are:<br>
atariosa.rom - OS/A,
atariosb.rom - OS/B,
atarixl.rom - XL,
ataribas.rom - XL Basic,
5200.rom - 5200
]]></string>
<string name="loadingdir">Loading directory. Please wait...</string>
<string name="selectdir">Select directory</string>
<string name="rompatherror">Failed to initialize machine.\n
\nRequired ROM not found or path not accessible.</string>
<string name="about">Colleen</string>
<string name="aboutmsg"><![CDATA[
<html><head></head><body>
<p align="right"><font size="-1"><b>Package version: </b>%1$s<br>
<b>Core version:</b>%2$s</font></p>
<p align="center">Android port by <i>Kostas Nakos</i><br>
<a href="http://pocketatari.atari.org/android">
http://pocketatari.atari.org/android</a><br>
Copyright &copy; 1995-1998 <i>David Firth</i><br>
Copyright &copy; 1998-2014 <i>Atari800 Development Team</i><br>
<a href="http://atari800.atari.org">http://atari800.atari.org</a></p>
<p align="justify"><font size="-1">This program is not affiliated with Atari Inc.
Atari and the Atari logo are trademarks owned by Atari Interactive, Inc.
All other trademarks are the property of their respective owners.</font></p>
<p align="justify"><font size="-1">This program is free software; you can
redistribute it and/or modify it under the terms of the GNU General
Public License as published by the Free Software Foundation; either
version 2, or (at your option) any later version.</font></p>
<p align="center">New Features? Translations? Bugs?<br>
<a href="mailto:knakos@gmail.com>Email me</a></p>
</body></html>
]]></string>
<string name="changesv1_1a"><![CDATA[
<i>Changes for version 1.1a:</i>
<br>This version is a quick fix for a regression to the <i>Anchor Joystick</i>
preference, introduced in v1.1.<br><br>
<i>Version 1.1 changelog follows:</i>
<br><b>*</b> Fix a crash when sound was switched off
<br><b>*</b> Added support for .com and .exe files
<br><b>*</b> Added the auto frameskip option
<br><b>*</b> Added the new <i>Joystick Grace Area</i> preference
<br>Thanks to the bug/feature reporters!
]]></string>
<string name="changesv1_2"><![CDATA[
<i>Changes for version 1.2:</i><br>
<br><b>*</b> New disk management menu (long press in the file selector)
<br><b>*</b> New screen cropping preferences
<br><b>*</b> New arrow key derotation preference for external keyboards
<br><b>*</b> DPAD-CENTER and tilde (~) now map to Escape key
<br><b>*</b> Atari800 core version 2.2.0
<br><b>*</b> Fix rare sound-related crashes
<br><b>*</b> Various fixes and improvements
<br><br>Thanks to the bug/feature reporters!
]]></string>
<string name="changesv1_3"><![CDATA[
<i>Changes for version 1.3:</i><br>
<br><b>*</b> New NTSC/PAL preference
<br><b>*</b> New keyboard action mapping preferences
<br><b>*</b> Added support for Xperia Play fire buttons
<br><b>*</b> DPAD-CENTER now mapped to Break key
<br><b>*</b> Atari800 core version 2.2.1
<br><b>*</b> Several bug fixes and improvements
<br><br>Thank you for your continued support and bug/feature reports :-)
]]></string>
<string name="changesv2_0"><![CDATA[
<i>Changes for version 2.0:</i><br>
<br><b>*</b> Free game included: Planetary Defense 2012. Find it in the Preferences.
<br><b>*</b> UI overhaul for Honeycomb+ devices
<br><b>*</b> When aspect correction is portrait, make room for the soft keyboard
<br><b>*</b> Bugfix: Crashes while loading ROMs
<br><b>*</b> Bugfix: Won\'t load OSB ROMs
<br><b>*</b> Bugfix: Crashes in keyboard-joystick remapping
<br><b>*</b> Warning: State saves from previous version are incompatible (sorry)
<br><b>*</b> Numerous bug fixes and improvements
<br><br>Thank you for your continued support and bug/feature reports
]]></string>
<string name="changesv3_0"><![CDATA[
<i>Changes for version 3.0:</i><br>
<br><b>*</b> Native Open SL ES sound for perfect playback for > 2.3 devices.
<br><b>*</b> Fix for no sound for NTSC machines under certain circumstances.
<br><b>*</b> Various other bugfixes.
<br><b>*</b> Upgrade to atari800 core v. 3.1.0.
<br><br>Thank you for your continued support and bug/feature reports
]]></string>
<string name="atariupdate">Colleen Update</string>
<string name="confirmurl">The current Atari program is requesting browser access to the
following URL:\n%s\nAllow access?</string>
<string name="browserreqdenied">Denied Atari program browser request (malformed URL)</string>
<string name="actionbarhelptoast">Touch near the top of the screen for menu\nTouch
top-right for console keys</string>
<string name="noactionbarhelptoast">Touch top-right for console keys</string>
<string name="selectcarttype">Select cartridge type</string>
<string name="pdbooterror">Cannot prepare Planetary Defense 2012 for boot :-(</string>
<string name="pdreminder">Reminder: \"Touchscreen Mode\" enabled. Please remember to uncheck
the \"Touchscreen Mode\" preference when done playing</string>
<!-- Preferences -->
<string name="preftitle_graphics">Graphics</string>
<string name="preftitle_emulation">Emulation</string>
<string name="preftitle_input">Input</string>
<string name="preftitle_sound">Sound</string>
<string name="preftitle_about">About</string>
<string name="preftitle_extras">Extras</string>
<string name="pref_aspect">Aspect</string>
<string name="pref_aspect_sum">Maintain aspect for scaling the screen</string>
<string name="asp_portrait">Portrait</string>
<string name="asp_landscape">Landscape</string>
<string name="asp_both">Both</string>
<string name="pref_bilinear">Bilinear Scaling</string>
<string name="pref_bilinear_sum">Filter scaled screen</string>
<string name="pref_artifact">Artifacting</string>
<string name="pref_artifact_sum">Emulate TV artifacts</string>
<string name="art_brownblue">Brown/Blue</string>
<string name="art_bluebrown1">Blue/Brown 1</string>
<string name="art_bluebrown2">Blue/Brown 2</string>
<string name="art_gtia">GTIA</string>
<string name="art_ctia">CTIA</string>
<string name="pref_machine">Machine Type</string>
<string name="pref_machine_sum">Select machine to emulate</string>
<string name="pref_speed">Show Atari Speed</string>
<string name="pref_speed_sum">Percentage of real Atari speed</string>
<string name="pref_disk">Show Drive Access</string>
<string name="pref_disk_sum">Display disk drive number for ongoing accesses</string>
<string name="pref_sector">Show Sector Access</string>
<string name="pref_sector_sum">Display disk sector number for ongoing accesses</string>
<string name="pref_frameskip">Frameskip</string>
<string name="pref_frameskip_sum">Screen repaint frequency</string>
<string name="skipauto">Auto</string>
<string name="skip0">Each frame (Skip 0)</string>
<string name="skip1">Alternate frames (Skip 1)</string>
<string name="skip2">Skip 2 frames</string>
<string name="skip3">Skip 3 frames</string>
<string name="skip4">Skip 4 frames</string>
<string name="skip5">Skip 5 frames</string>
<string name="pref_collisions">Accurate Collisions</string>
<string name="pref_collisions_sum">Calculate collisions in skipped frames</string>
<string name="pref_basic">Disable BASIC</string>
<string name="pref_basic_sum">Simulate holding OPTION key down when booting</string>
<string name="pref_softjoy">Keyboard Joystick</string>
<string name="pref_softjoy_sum">Emulate joystick w/ hardware keyboard/Wii Remote</string>
<string name="pref_keydefscr">Configure Keyboard</string>
<string name="pref_keydefscr_sum">Define keyboard joystick keys</string>
<string name="pref_up">Up</string>
<string name="pref_down">Down</string>
<string name="pref_left">Left</string>
<string name="pref_right">Right</string>
<string name="pref_fire">Fire</string>
<string name="pref_actiona">Action A</string>
<string name="pref_actionb">Action B</string>
<string name="pref_actionc">Action C</string>
<string name="preftitle_keymap_joystick">Joystick Keymap</string>
<string name="preftitle_keymap_actions">Generic Mappable Keys</string>
<string name="pref_joysize">Joystick Area Size</string>
<string name="pref_joysize_sum">Enlarge/Shrink on-screen joystick</string>
<string name="pref_joyvisible">Joystick Visible</string>
<string name="pref_joyvisible_sum">Show the on-screen joystick</string>
<string name="pref_joyrighth">Right-Handed Joystick</string>
<string name="pref_joyrighth_sum">Exchange on-screen joystick/fire button areas</string>
<string name="pref_joydeadband">Joystick Deadband</string>
<string name="pref_joydeadband_sum">Joystick deflections lower than this will not register</string>
<string name="pref_joymidx">Joystick Screen Split</string>
<string name="pref_joymidx_sum">Horizontal percentage of screen allocated to on-screen joystick</string>
<string name="pref_joyopacity">Joystick Opacity</string>
<string name="pref_joyopacity_sum">Alpha blend factor for the on-screen joystick</string>
<string name="pref_sound">Sound</string>
<string name="pref_sound_sum">Enable sound emulation</string>
<string name="pref_mixrate">Mix Rate</string>
<string name="pref_mixrate_sum">Sound generation frequency</string>
<string name="pref_sound16bit">16bit Sound</string>
<string name="pref_sound16bit_sum">Toggle between 8bit/16bit sound generation</string>
<string name="pref_hqpokey">High Quality Sound</string>
<string name="pref_hqpokey_sum">Use high quality POKEY emulation</string>
<string name="pref_romdir">ROMs directory</string>
<string name="pref_romdir_sum">Set directory where Atari ROMs reside</string>
<string name="pref_keymapdupmsg">This key is already used for another action.\n\nWould you like to swap
the mapping between these two keys? (\'No\' will keep current
assignments)</string>
<string name="pref_warnresetactions">Are you sure you want to clear the current action mappings?</string>
<string name="pref_keymapmsg">Press the key on the controller to assign to this action</string>
<string name="pref_keymapmsg1">Step 1:\nPress the key on the CONTROLLER to assign to this action</string>
<string name="pref_keymapmsg2">Step 2:\nType the key of the Atari to assign to this action in
the next box (1 character only)</string>
<string name="pref_keymapmsg2note">NOTE:\nUse the hardware keyboard to type in the box. If you have
enabled the Wiicontroller IME, please temporarily disable it by long
pressing in the box and select the standard IME. The virtual keyboard
subsequently will show up when you select the text box above. Please
remember to re-set the WiiController IME when finished.</string>
<string name="pref_typeatarikey">Type Atari key</string>
<string name="pref_keymap_current">Current:</string>
<string name="pref_keymap_controller">Controller:</string>
<string name="pref_keymap_mappedto">is mapped to:</string>
<string name="pref_resetactions">Reset Action Mappings</string>
<string name="pref_resetactions_sum">Clear current action mappings</string>
<string name="pref_mixbufsize">Sound Buffer Size</string>
<string name="pref_mixbufsize_sum">Lower for lower latency, higher to get rid of clicks</string>
<string name="pref_rompath">Atari ROM Path</string>
<string name="pref_rompath_sum">Set directory containing the ROM images</string>
<string name="pref_about">About</string>
<string name="pref_about_sum">Colleen credits</string>
<string name="pref_help">Help</string>
<string name="pref_help_sum">Android port instructions</string>
<string name="pref_anchor">Anchor Joystick</string>
<string name="pref_anchor_sum">Fix on-screen joystick to current position</string>
<string name="pref_joygrace">Joystick Grace Area</string>
<string name="pref_joygrace_sum">Area extension around the joystick which results in no recentering</string>
<string name="pref_crophoriz">Crop Horizontally</string>
<string name="pref_crophoriz_sum">Width in pixels of original screen to show</string>
<string name="pref_cropvert">Crop Vertically</string>
<string name="pref_cropvert_sum">Height in pixels of original screen to show</string>
<string name="pref_derotkeys">Derotate Arrow Keys</string>
<string name="pref_derotkeys_sum">Fix external keyboard arrow keys when display is rotated</string>
<string name="pref_ntsc">NTSC TV Mode</string>
<string name="pref_ntsc_sum">Toggle between NTSC (60fps) and PAL (50fps) tv modes</string>
<string name="pref_paddle">Paddle Mode</string>
<string name="pref_paddle_sum">Enable paddle emulation instead of joystick</string>
<string name="pref_savestate">Save Current State</string>
<string name="pref_savestate_sum_dis">Disabled! Set a state save path first!</string>
<string name="pref_savestate_sum_ena">Save current machine state</string>
<string name="pref_savestate_msg">Enter the file name:</string>
<string name="pref_statepath">State Save Path</string>
<string name="pref_statepath_sum">Where atari states will be saved</string>
<string name="pref_plandef">Touchscreen Mode</string>
<string name="pref_plandef_sum">A Koala Pad-like input mode for games like Planetary Defense</string>
<string name="pref_browser">Allow Web Browser</string>
<string name="pref_browser_sum">Provide the B: device to the emulated Atari</string>
<string name="pref_launchpd">Planetary Defense 2012</string>
<string name="pref_launchpd_sum">A game revamped for touchscreen and Colleen by Tom Hudson</string>
<string name="pref_forceAT">Force Legacy Playback</string>
<string name="pref_forceAT_sum">Disable OpenSL ES sound if checked</string>
</resources>
@@ -0,0 +1,4 @@
<resources>
<style name="MainTheme" parent="@android:style/Theme.NoTitleBar.Fullscreen">
</style>
</resources>
@@ -0,0 +1,322 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:jub="http://schemas.android.com/apk/res/name.nick.jubanka.colleen">
<PreferenceCategory android:title="@string/preftitle_graphics">
<CheckBoxPreference
android:key="ntsc"
android:title="@string/pref_ntsc"
android:summary="@string/pref_ntsc_sum"
android:defaultValue="false"/>
<ListPreference
android:key="aspect"
android:title="@string/pref_aspect"
android:summary="@string/pref_aspect_sum"
android:entries="@array/aspect"
android:entryValues="@array/aspect_values"
android:defaultValue="0"/>
<CheckBoxPreference
android:key="bilinear"
android:title="@string/pref_bilinear"
android:summary="@string/pref_bilinear_sum"
android:defaultValue="false"/>
<ListPreference
android:key="artifact"
android:title="@string/pref_artifact"
android:summary="@string/pref_artifact_sum"
android:entries="@array/artifact"
android:entryValues="@array/artifact_values"
android:defaultValue="0"/>
<ListPreference
android:key="frameskip"
android:title="@string/pref_frameskip"
android:summary="@string/pref_frameskip_sum"
android:entries="@array/frameskip"
android:entryValues="@array/frameskip_values"
android:defaultValue="0"/>
<CheckBoxPreference
android:key="collisions"
android:title="@string/pref_collisions"
android:summary="@string/pref_collisions_sum"
android:defaultValue="true"/>
<name.nick.jubanka.colleen.SliderPreference
android:key="crophoriz"
android:title="@string/pref_crophoriz"
android:summary="@string/pref_crophoriz_sum"
android:defaultValue="336"
jub:suffix=""
jub:min="320"
jub:max="336"/>
<name.nick.jubanka.colleen.SliderPreference
android:key="cropvert"
android:title="@string/pref_cropvert"
android:summary="@string/pref_cropvert_sum"
android:defaultValue="240"
jub:suffix=""
jub:min="192"
jub:max="240"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/preftitle_emulation">
<ListPreference
android:key="machine"
android:title="@string/pref_machine"
android:summary="@string/pref_machine_sum"
android:entries="@array/machine"
android:entryValues="@array/machine_values"
android:defaultValue="7"/>
<Preference
android:key="rompath"
android:title="@string/pref_rompath"
android:summary="@string/pref_rompath_sum"/>
<Preference
android:key="statepath"
android:title="@string/pref_statepath"
android:summary="@string/pref_statepath_sum"/>
<EditTextPreference
android:key="savestate"
android:title="@string/pref_savestate"
android:summary="@string/pref_savestate_sum_dis"
android:dialogMessage="@string/pref_savestate_msg"
android:positiveButtonText="@string/save"
android:negativeButtonText="@string/cancel"
android:lines="1"
android:maxLines="1"
android:inputType="textNoSuggestions"
android:imeOptions="actionDone"
android:enabled="false"/>
<CheckBoxPreference
android:key="basic"
android:title="@string/pref_basic"
android:summary="@string/pref_basic_sum"
android:defaultValue="true"/>
<CheckBoxPreference
android:key="speed"
android:title="@string/pref_speed"
android:summary="@string/pref_speed_sum"
android:defaultValue="false"/>
<CheckBoxPreference
android:key="disk"
android:title="@string/pref_disk"
android:summary="@string/pref_disk_sum"
android:defaultValue="true"/>
<CheckBoxPreference
android:key="sector"
android:title="@string/pref_sector"
android:summary="@string/pref_sector_sum"
android:defaultValue="false"/>
<CheckBoxPreference
android:key="browser"
android:title="@string/pref_browser"
android:summary="@string/pref_browser_sum"
android:defaultValue="true"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/preftitle_input">
<CheckBoxPreference
android:key="softjoy"
android:title="@string/pref_softjoy"
android:summary="@string/pref_softjoy_sum"
android:defaultValue="false"/>
<PreferenceScreen
android:key="keydefscr"
android:title="@string/pref_keydefscr"
android:summary="@string/pref_keydefscr_sum"
android:dependency="softjoy">
<PreferenceCategory android:title="@string/preftitle_keymap_joystick">
<name.nick.jubanka.colleen.KeymapPreference
android:key="up"
android:title="@string/pref_up"
android:defaultValue="254"
jub:ext="false"/>
<name.nick.jubanka.colleen.KeymapPreference
android:key="down"
android:title="@string/pref_down"
android:defaultValue="253"
jub:ext="false"/>
<name.nick.jubanka.colleen.KeymapPreference
android:key="left"
android:title="@string/pref_left"
android:defaultValue="252"
jub:ext="false"/>
<name.nick.jubanka.colleen.KeymapPreference
android:key="right"
android:title="@string/pref_right"
android:defaultValue="251"
jub:ext="false"/>
<name.nick.jubanka.colleen.KeymapPreference
android:key="fire"
android:title="@string/pref_fire"
android:defaultValue="50"
jub:ext="false"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/preftitle_keymap_actions">
<name.nick.jubanka.colleen.KeymapPreference
android:key="actiona"
android:title="@string/pref_actiona"
android:defaultValue="-1,-1"
jub:ext="true"/>
<name.nick.jubanka.colleen.KeymapPreference
android:key="actionb"
android:title="@string/pref_actionb"
android:defaultValue="-1,-1"
jub:ext="true"/>
<name.nick.jubanka.colleen.KeymapPreference
android:key="actionc"
android:title="@string/pref_actionc"
android:defaultValue="-1,-1"
jub:ext="true"/>
<Preference
android:key="resetactions"
android:title="@string/pref_resetactions"
android:summary="@string/pref_resetactions_sum"/>
</PreferenceCategory>
</PreferenceScreen>
<ListPreference
android:key="derotkeys"
android:title="@string/pref_derotkeys"
android:summary="@string/pref_derotkeys_sum"
android:entries="@array/derotkeys"
android:entryValues="@array/derotkeys_values"
android:defaultValue="0"/>
<CheckBoxPreference
android:key="joyvisible"
android:title="@string/pref_joyvisible"
android:summary="@string/pref_joyvisible_sum"
android:dependency="plandef"
android:defaultValue="true"/>
<name.nick.jubanka.colleen.SliderPreference
android:key="joyopacity"
android:title="@string/pref_joyopacity"
android:summary="@string/pref_joyopacity_sum"
android:dependency="joyvisible"
android:defaultValue="25"
jub:min="10"
jub:max="90"/>
<name.nick.jubanka.colleen.SliderPreference
android:key="joysize"
android:title="@string/pref_joysize"
android:summary="@string/pref_joysize_sum"
android:dependency="plandef"
android:defaultValue="15"
jub:min="10"
jub:max="32"/>
<CheckBoxPreference
android:key="joyrighth"
android:title="@string/pref_joyrighth"
android:summary="@string/pref_joyrighth_sum"
android:dependency="plandef"
android:defaultValue="false"/>
<CheckBoxPreference
android:key="anchor"
android:title="@string/pref_anchor"
android:summary="@string/pref_anchor_sum"
android:dependency="plandef"
android:defaultValue="false"/>
<name.nick.jubanka.colleen.SliderPreference
android:key="joymidx"
android:title="@string/pref_joymidx"
android:summary="@string/pref_joymidx_sum"
android:dependency="plandef"
android:defaultValue="65"
jub:min="50"
jub:max="80"/>
<name.nick.jubanka.colleen.SliderPreference
android:key="joydeadband"
android:title="@string/pref_joydeadband"
android:summary="@string/pref_joydeadband_sum"
android:dependency="plandef"
android:defaultValue="35"
jub:min="20"
jub:max="60"/>
<name.nick.jubanka.colleen.SliderPreference
android:key="joygrace"
android:title="@string/pref_joygrace"
android:summary="@string/pref_joygrace_sum"
android:dependency="plandef"
android:defaultValue="50"
jub:min="10"
jub:max="99"/>
<CheckBoxPreference
android:key="paddle"
android:title="@string/pref_paddle"
android:summary="@string/pref_paddle_sum"
android:disableDependentsState="true"
android:dependency="plandef"
android:defaultValue="false"/>
<CheckBoxPreference
android:key="plandef"
android:title="@string/pref_plandef"
android:summary="@string/pref_plandef_sum"
android:disableDependentsState="true"
android:defaultValue="false"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/preftitle_sound">
<CheckBoxPreference
android:key="sound"
android:title="@string/pref_sound"
android:summary="@string/pref_sound_sum"
android:defaultValue="true"/>
<ListPreference
android:key="mixrate"
android:title="@string/pref_mixrate"
android:summary="@string/pref_mixrate_sum"
android:entries="@array/mixrate"
android:entryValues="@array/mixrate_values"
android:defaultValue="44100"
android:dependency="sound"/>
<name.nick.jubanka.colleen.SliderPreference
android:key="mixbufsize"
android:title="@string/pref_mixbufsize"
android:summary="@string/pref_mixbufsize_sum"
android:defaultValue="10"
jub:suffix="0ms"
jub:min="10"
jub:max="40"/>
<CheckBoxPreference
android:key="sound16bit"
android:title="@string/pref_sound16bit"
android:summary="@string/pref_sound16bit_sum"
android:defaultValue="true"
android:dependency="sound"/>
<CheckBoxPreference
android:key="hqpokey"
android:title="@string/pref_hqpokey"
android:summary="@string/pref_hqpokey_sum"
android:defaultValue="false"
android:dependency="sound"/>
<CheckBoxPreference
android:key="forceAT"
android:title="@string/pref_forceAT"
android:summary="@string/pref_forceAT_sum"
android:defaultValue="false"
android:dependency="sound"
android:enabled="false"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/preftitle_extras">
<Preference
android:key="launchpd"
android:title="@string/pref_launchpd"
android:summary="@string/pref_launchpd_sum"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/preftitle_about">
<Preference
android:key="about"
android:title="@string/pref_about"
android:summary="@string/pref_about_sum"/>
<Preference
android:key="help"
android:title="@string/pref_help"
android:summary="@string/pref_help_sum"/>
</PreferenceCategory>
<!--
reset to default?
save state on exit (state/disk/none)?
mouse?
-->
</PreferenceScreen>
+133
View File
@@ -0,0 +1,133 @@
/*
* A800Renderer.java - opengl graphics frontend to android
*
* Copyright (C) 2010 Kostas Nakos
* Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package name.nick.jubanka.colleen;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.Log;
import android.widget.Toast;
import android.content.Context;
import android.os.Message;
import android.os.Handler;
public final class A800Renderer implements GLSurfaceView.Renderer
{
public static final int REQ_BROWSER = 1;
private static final String TAG = "A800Renderer";
private final int OVL_TEXW = 128;
private final int OVL_TEXH = 64;
private int[] _pix;
private Toast _crashtoast;
private int _frameret;
private Handler _handler = null;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
_pix = new int[OVL_TEXW * OVL_TEXH];
generateOverlays();
NativeGetOverlays();
}
@Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
NativeResize(w, h);
}
@Override
public void onDrawFrame(GL10 gl) {
_frameret = NativeRunFrame();
if ((_frameret & 1) != 0)
_crashtoast.show();
else if ((_frameret & 2) != 0) {
Log.d(TAG, "Browser request");
if (_handler != null)
_handler.dispatchMessage(Message.obtain(_handler, REQ_BROWSER));
}
}
public void prepareToast(Context c) {
_crashtoast = Toast.makeText(c, R.string.cimcrash, Toast.LENGTH_LONG);
}
public void setHandler(Handler h) {
_handler = h;
}
private void generateOverlays() {
RectF r;
Paint fill = new Paint(0);
fill.setStyle(Paint.Style.FILL);
fill.setColor(0xFF0054A8);
Paint stroke = new Paint(0);
stroke.setStyle(Paint.Style.STROKE);
stroke.setStrokeWidth(1);
stroke.setColor(0xFF001976);
Bitmap bmp = Bitmap.createBitmap(OVL_TEXW, OVL_TEXH, Bitmap.Config.ARGB_8888);
bmp.eraseColor(0);
Canvas can = new Canvas(bmp);
// Joystick area
r = new RectF(0, 0, 63, 63);
can.clipRect(0, 0, 64, 64, Region.Op.REPLACE);
can.drawRoundRect(r, 6, 6, fill);
can.drawRoundRect(r, 6, 6, stroke);
// Fire/Joy point
r = new RectF(67, 3, 77, 13);
can.clipRect(64, 0, 79, 15, Region.Op.REPLACE);
can.drawOval(r, fill);
// El texto
can.clipRect(64, 16, 128, 64, Region.Op.REPLACE);
Paint t = new Paint(Paint.ANTI_ALIAS_FLAG);
t.setColor(0xFF001976);
t.setTextSize(10);
can.drawColor(0x00ffffff);
can.drawText("START", 65, 24, t);
can.drawText("SELECT", 65, 34, t);
can.drawText("OPTION", 65, 44, t);
can.drawText("RESET", 65, 54, t);
can.drawText("HELP", 65, 64, t);
bmp.getPixels(_pix, 0, OVL_TEXW, 0, 0, OVL_TEXW, OVL_TEXH);
bmp.recycle();
}
// Native function declarations
private native void NativeGetOverlays();
private native int NativeRunFrame();
private native void NativeResize(int w, int h);
}
+265
View File
@@ -0,0 +1,265 @@
/*
* A800view.java - atari screen view
*
* Copyright (C) 2014 Kostas Nakos
* Copyright (C) 2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package name.nick.jubanka.colleen;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;
import android.view.KeyEvent;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.os.Build;
import android.widget.Toast;
import android.view.View;
import android.util.SparseArray;
import android.os.Handler;
import android.os.Message;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import static android.view.KeyEvent.*;
public final class A800view extends GLSurfaceView
{
public static final int KEY_SHIFT = 256;
public static final int KEY_CONTROL = 257;
public static final int KEY_BACKSPACE = 255;
public static final int KEY_UP = 254;
public static final int KEY_DOWN = 253;
public static final int KEY_LEFT = 252;
public static final int KEY_RIGHT = 251;
public static final int KEY_FIRE = 250;
public static final int KEY_ENTER = 249;
public static final int KEY_ESCAPE = 248;
public static final int KEY_CENTER = 247;
public static final int KEY_BT_X = 246;
public static final int KEY_BT_Y = 245;
public static final int KEY_BT_L1 = 244;
public static final int KEY_BT_R1 = 243;
public static final int KEY_BREAK = 242;
// keycodes from newer sdks
public static final int KC_BUTTON_X = 307;
public static final int KC_BUTTON_Y = 308;
public static final int KC_BUTTON_L1 = 310;
public static final int KC_BUTTON_R1 = 311;
private static final String TAG = "A800View";
private A800Renderer _renderer;
private KeyCharacterMap _keymap;
private int _key, _meta, _hit;
private TouchFactory _touchHandler = null;
private Toast _toastquit;
private Integer _xkey;
public A800view(Context context) {
super(context);
_renderer = new A800Renderer();
setRenderer(_renderer);
_renderer.prepareToast(context);
_renderer.setHandler(new Handler() {
@Override
public void handleMessage(Message msg) {
((MainActivity) getContext()).message(msg.what);
}
});
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
_keymap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.ECLAIR)
_touchHandler = new SingleTouch();
else
_touchHandler = new MultiTouch();
_toastquit = Toast.makeText(context, R.string.pressback, Toast.LENGTH_SHORT);
}
public void pause(boolean p) {
setRenderMode(p ? GLSurfaceView.RENDERMODE_WHEN_DIRTY :
GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
// Touch input
@Override
public boolean onTouchEvent(final MotionEvent ev) {
int ret = _touchHandler.onTouchEvent(ev);
if (Integer.parseInt(Build.VERSION.SDK) >= Build.VERSION_CODES.HONEYCOMB) {
MainActivity m = (MainActivity) getContext();
if (ret == 2)
m._aBar.show(m);
else if (ret == 1)
m._aBar.hide(m);
}
return true;
}
abstract static class TouchFactory {
public abstract int onTouchEvent(MotionEvent ev);
};
private static final class SingleTouch extends TouchFactory {
private int _x1, _y1, _s1;
private int _action, _actioncode;
@Override
public int onTouchEvent(final MotionEvent ev) {
_action = ev.getAction();
_actioncode = _action & MotionEvent.ACTION_MASK;
_x1 = (int) ev.getX();
_y1 = (int) ev.getY();
_s1 = 1;
if (_actioncode == MotionEvent.ACTION_UP)
_s1 = 0;
return NativeTouch(_x1, _y1, _s1, -1000, -1000, 0);
}
}
private static final class MultiTouch extends TouchFactory {
private int _x1, _y1, _s1, _x2, _y2, _s2;
private int _action, _actioncode, _ptrcnt;
@Override
public int onTouchEvent(final MotionEvent ev) {
_action = ev.getAction();
_actioncode = _action & MotionEvent.ACTION_MASK;
_ptrcnt = ev.getPointerCount();
_x1 = (int) ev.getX(0);
_y1 = (int) ev.getY(0);
_s1 = 1;
if (_ptrcnt > 1) {
_x2 = (int) ev.getX(1);
_y2 = (int) ev.getY(1);
_s2 = 1;
} else {
_x2 = -1000;
_y2 = -1000;
_s2 = 0;
}
if (_actioncode == MotionEvent.ACTION_UP) {
_s1 = _s2 = 0;
} else if (_actioncode == MotionEvent.ACTION_POINTER_UP) {
if ( (_action >> MotionEvent.ACTION_POINTER_ID_SHIFT) == 0)
_s1 = 0;
else
_s2 = 0;
}
return NativeTouch(_x1, _y1, _s1, _x2, _y2, _s2);
}
}
// Key input
@Override
public boolean onKeyDown(int kc, final KeyEvent ev) {
return doKey(kc, ev);
}
@Override
public boolean onKeyUp(int kc, final KeyEvent ev) {
return doKey(kc, ev);
}
@Override
public boolean onCheckIsTextEditor() {
return true;
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
return new BaseInputConnection(this, false) {
@Override
public boolean deleteSurroundingText(int leftLength, int rightLength) {
//Log.d(TAG, "Synthetic del");
this.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
this.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
return true;
}
};
}
private boolean doKey(int kc, final KeyEvent ev) {
_hit =(ev.getAction() == ACTION_DOWN) ? 1 : 0;
if (kc == KEYCODE_BACK && _hit == 1) {
MainActivity m = (MainActivity) getContext();
if (_toastquit.getView().getWindowVisibility() == View.VISIBLE) {
_toastquit.cancel();
m.finish();
} else if (m._aBar.isShowing(m))
m._aBar.hide(m);
else
_toastquit.show();
return true;
}
_xkey = XLATKEYS.get(kc);
if (_xkey != null)
_key = _xkey.intValue();
else {
_meta = ev.getMetaState();
if ((_meta & KeyEvent.META_SHIFT_RIGHT_ON) == KeyEvent.META_SHIFT_RIGHT_ON)
_meta &= ~(KeyEvent.META_SHIFT_RIGHT_ON | KeyEvent.META_SHIFT_ON);
_key = _keymap.get(kc, _meta);
if (_key == 0)
return false;
}
//Log.d(TAG, String.format("key %d %d -> %d", ev.getAction(), kc, _key));
NativeKey(_key, _hit);
return true;
}
private native static int NativeTouch(int x1, int y1, int s1, int x2, int y2, int s2);
private native void NativeKey(int keycode, int status);
public static final SparseArray<Integer> XLATKEYS = new SparseArray<Integer>(14);
static {
XLATKEYS.put(KEYCODE_DPAD_UP, KEY_UP);
XLATKEYS.put(KEYCODE_DPAD_DOWN, KEY_DOWN);
XLATKEYS.put(KEYCODE_DPAD_LEFT, KEY_LEFT);
XLATKEYS.put(KEYCODE_DPAD_RIGHT, KEY_RIGHT);
XLATKEYS.put(KEYCODE_DPAD_CENTER, KEY_BREAK);
XLATKEYS.put(KEYCODE_SEARCH, KEY_FIRE);
XLATKEYS.put(KEYCODE_SHIFT_LEFT, KEY_SHIFT);
XLATKEYS.put(KEYCODE_SHIFT_RIGHT, KEY_CONTROL);
XLATKEYS.put(KEYCODE_DEL, KEY_BACKSPACE);
XLATKEYS.put(KEYCODE_ENTER, KEY_ENTER);
XLATKEYS.put(KC_BUTTON_X, KEY_BT_X);
XLATKEYS.put(KC_BUTTON_Y, KEY_BT_Y);
XLATKEYS.put(KC_BUTTON_L1, KEY_BT_L1);
XLATKEYS.put(KC_BUTTON_R1, KEY_BT_R1);
}
}
+159
View File
@@ -0,0 +1,159 @@
/*
* AudioThread.java - pushes audio to android
*
* Copyright (C) 2014 Kostas Nakos
* Copyright (C) 2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package name.nick.jubanka.colleen;
import android.media.AudioTrack;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.util.Log;
public final class AudioThread extends Thread
{
private static final String TAG = "A800AudioThread";
private AudioTrack _at;
private int _bufsize;
private byte[] _buffer;
private boolean _quit;
private int _chunk;
private boolean _initok;
private boolean _pause;
private boolean _useOSL;
public AudioThread(int rate, int bytes, int bufsizems, boolean ntsc) {
NativeOSLSoundInit();
_useOSL = NativeOSLSound();
if (_useOSL) {
Log.d(TAG, "Disabling AudioThread. Using OSL instead");
return;
}
int format = bytes == 1 ? AudioFormat.ENCODING_PCM_8BIT : AudioFormat.ENCODING_PCM_16BIT;
int minbuf = AudioTrack.getMinBufferSize(rate, AudioFormat.CHANNEL_OUT_MONO, format);
int hardmin = (int) ( ((float) rate * bytes) / ((float) (1000.0f / bufsizems)) );
_chunk = (rate * bytes / (ntsc ? 60 : 50) + 3) / 4 * 4;
_bufsize = (hardmin > minbuf) ? hardmin : minbuf;
_bufsize = ((_bufsize + _chunk - 1) / _chunk * _chunk + 3) / 4 * 4;
_at = new AudioTrack(AudioManager.STREAM_MUSIC, rate, AudioFormat.CHANNEL_CONFIGURATION_MONO,
format, _bufsize, AudioTrack.MODE_STREAM);
_buffer = new byte[_bufsize];
Log.d( TAG, String.format(
"Mixing audio at %dHz, %dbit, buffer size %d (%d ms) [requested=%d(%dms), minbuf=%d(%dms)], chunk %d",
rate, 8 * bytes, _bufsize, (int) (((float) _bufsize)/((float) rate * bytes) * 1000),
hardmin, (int) (((float) hardmin)/((float) rate * bytes) * 1000),
minbuf, (int) (((float) minbuf)/((float) rate * bytes) * 1000),
_chunk
) );
_quit = false;
_pause = false;
this.setDaemon(true);
if (_at.getState() != AudioTrack.STATE_INITIALIZED) {
Log.e(TAG, "Cannot initialize audio");
_initok = false;
} else
_initok = true;
}
public void pause(boolean p) {
if (_useOSL) {
NativeOSLSoundPause(p);
return;
}
_pause = p;
if (!_initok) return;
if (p) {
_at.pause();
Log.d(TAG, "Audio paused");
} else {
_at.play();
Log.d(TAG, "Audio resumed");
}
}
public void run() {
int offset = 0;
int len, w, chunk;
if (_useOSL) {
NativeOSLSoundPause(false);
return;
}
if (!_initok) return;
Log.d(TAG, "Running");
NativeSoundInit(_bufsize);
_at.play();
chunk = _chunk / 2;
try {
while (!_quit) {
if (_pause) {
sleep(100);
continue;
}
len = _bufsize - offset;
if (len > chunk)
len = chunk;
else if (len <= 0) {
len = chunk;
offset = 0;
}
NativeSoundUpdate(offset, len);
w = 0;
while (w < len)
w += _at.write(_buffer, offset + w, len - w);
offset += w;
}
} catch (InterruptedException ex) {
}
Log.d(TAG, "Exit");
NativeSoundExit();
_at.stop();
_at.release();
}
public void interrupt() {
if (_useOSL) {
NativeOSLSoundExit();
return;
}
Log.d(TAG, "Audio thread exit via interrupt");
_quit = true;
}
// Native function declarations
private native void NativeSoundInit(int size);
private native void NativeSoundUpdate(int offset, int length);
private native void NativeSoundExit();
private native boolean NativeOSLSound();
private native void NativeOSLSoundInit();
private native void NativeOSLSoundExit();
private native void NativeOSLSoundPause(boolean paused);
}
+449
View File
@@ -0,0 +1,449 @@
/*
* FileSelector.java - the file selector activity
*
* Copyright (C) 2010 Kostas Nakos
* Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package name.nick.jubanka.colleen;
import java.io.File;
import java.io.FileFilter;
import java.util.Comparator;
import java.util.Set;
import java.util.HashSet;
import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.os.Environment;
import android.view.View;
import android.widget.ListView;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.content.Context;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.ImageView;
import android.content.SharedPreferences;
import android.widget.AdapterView;
import android.content.DialogInterface;
import android.app.AlertDialog;
import android.util.Log;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.app.Dialog;
import android.widget.Toast;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.SearchView;
import android.text.TextUtils;
import android.os.Build;
public final class FileSelector extends ListActivity implements AdapterView.OnItemLongClickListener,
View.OnClickListener
{
public static final String ACTION_OPEN_FILE = "jubanka.intent.OPENFILE";
public static final String ACTION_OPEN_PATH = "jubanka.intent.OPENPATH";
private static final String TAG = "FileSelector";
private static final String SAVED_PATH = "SavedPath";
private static final String SAVED_POS = "SavedPos";
private static final int DLG_MOUNT = 0;
private static final int DLG_WARNING = 1;
private IconArrayAdapter _ad = null;
private File _curdir;
private ListDirTask _task = null;
private boolean _pathsel = false;
private static String _mntfname = null;
private static String _drive1fname = null;
private SearchNull _srchView;
private final class IconArrayAdapter extends ArrayAdapter<String> {
LayoutInflater _inf = null;
public IconArrayAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
_inf = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int pos, View view, ViewGroup par) {
if (view == null)
view = _inf.inflate(R.layout.file_selector_row, null);
String itm = getItem(pos);
((TextView) view.findViewById(R.id.fsel_text)).setText(itm);
((ImageView) view.findViewById(R.id.fsel_image)).setImageResource(
itm.endsWith("/") ? R.drawable.folder : 0 );
return view;
}
}
private static class SearchNull {
public boolean onCreateOptionsMenu(Menu menu, ListActivity a) { return false; };
public void reset(ListActivity a) {};
}
private static final class SearchHelp extends SearchNull implements SearchView.OnQueryTextListener {
ListActivity _actv;
private MenuItem _msrch = null;
@Override
public boolean onCreateOptionsMenu(Menu menu, ListActivity a) {
_actv = a;
MenuInflater inf = a.getMenuInflater();
inf.inflate(R.menu.fsel_menu, menu);
_msrch = menu.findItem(R.id.menu_search);
((SearchView) _msrch.getActionView()).setOnQueryTextListener(this);
return true;
};
@Override
public boolean onQueryTextChange(String newText) {
if (TextUtils.isEmpty(newText))
_actv.getListView().clearTextFilter();
else
_actv.getListView().setFilterText(newText.toString());
return true;
}
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public void reset(ListActivity a) {
a.getListView().clearTextFilter();
if (_msrch != null)
if (Integer.parseInt(Build.VERSION.SDK) >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
_msrch.collapseActionView();
else
((SearchView) _msrch.getActionView()).setIconified(true);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Integer.parseInt(Build.VERSION.SDK) >= Build.VERSION_CODES.HONEYCOMB)
_srchView = new SearchHelp();
else
_srchView = new SearchNull();
ListView lv = getListView();
_pathsel = getIntent().getAction().equals(ACTION_OPEN_PATH);
if (_pathsel) {
LayoutInflater inf = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inf.inflate(R.layout.file_selector_footer, null);
setContentView(v);
findViewById(R.id.fsel_ok).setOnClickListener(this);
findViewById(R.id.fsel_cancel).setOnClickListener(this);
} else
lv.setOnItemLongClickListener(this);
lv.setTextFilterEnabled(true);
lv.setFastScrollEnabled(true);
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
String oldpath = _pathsel ? (getIntent().getData() != null ? getIntent().getData().getPath() : null)
: prefs.getString(SAVED_PATH, null);
listDirectory((oldpath != null) ? new File(oldpath) : Environment.getExternalStorageDirectory(),
_pathsel ? 0 : prefs.getInt(SAVED_POS, 0), getLastNonConfigurationInstance());
}
@Override
protected void onPause() {
if (!_pathsel) {
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
edit.putString(SAVED_PATH, _curdir.getAbsolutePath());
edit.putInt(SAVED_POS, getListView().getFirstVisiblePosition());
edit.commit();
}
super.onPause();
}
@Override
protected void onDestroy() {
if (_task != null) _task.cancel(true); // you rotate, you lose
_task = null;
super.onDestroy();
}
@Override
public Object onRetainNonConfigurationInstance() {
String[] ret = null;
if (_task == null && _ad != null && _ad.getCount() > 0) {
int cnt = _ad.getCount();
ret = new String[cnt];
for (int i = 0; i < cnt; i++)
ret[i] = _ad.getItem(i);
}
return (Object) ret;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.fsel_ok:
setResult(Activity.RESULT_OK, new Intent(MainActivity.ACTION_SET_ROMPATH,
Uri.fromFile(_curdir)));
finish();
break;
case R.id.fsel_cancel:
setResult(Activity.RESULT_CANCELED);
finish();
break;
}
}
@Override
protected void onListItemClick(ListView l, View v, int pos, long id) {
String fname = _ad.getItem(pos);
if (fname.startsWith("../"))
listDirectory(_curdir.getParentFile(), 0, null);
else if (fname.endsWith("/"))
listDirectory(new File(_curdir, fname), 0, null);
else if (!_pathsel) {
_drive1fname = null;
setResult(Activity.RESULT_OK, new Intent(MainActivity.ACTION_INSERT_REBOOT,
Uri.fromFile(new File(_curdir, fname))));
finish();
return;
}
}
@Override
public boolean onItemLongClick(AdapterView<?> l, View v, final int pos, long id) {
_mntfname = _ad.getItem(pos);
if (_mntfname.endsWith("/"))
return true;
if (!NativeIsDisk(_curdir + "/" + _mntfname)) {
showDialog(DLG_WARNING);
return true;
}
showDialog(DLG_MOUNT);
return true;
}
@Override
protected Dialog onCreateDialog(int id) {
Dialog d;
switch (id) {
case DLG_MOUNT:
CharSequence[] items = new CharSequence[5];
String[] drives = NativeGetDrvFnames();
for (int i = 0; i < 4; i++)
items[i] = new StringBuilder(drives[i]);
items[4] = getString(R.string.unmountall);
d = new AlertDialog.Builder(this)
.setTitle(R.string.mountdisk)
.setCancelable(true)
.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
if (i < 4) {
NativeRunAtariProgram(_curdir + "/" + _mntfname, i + 1, 0);
if (i == 0)
_drive1fname = _curdir + "/" + _mntfname;
Toast.makeText(FileSelector.this,
String.format(getString(R.string.mountinsertdisk), _mntfname, i + 1),
Toast.LENGTH_SHORT)
.show();
} else {
NativeUnmountAll();
_drive1fname = null;
}
_mntfname = null;
dismissDialog(DLG_MOUNT);
}
})
.create();
break;
case DLG_WARNING:
d = new AlertDialog.Builder(FileSelector.this)
.setTitle(R.string.warning)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
dismissDialog(DLG_WARNING);
showDialog(DLG_MOUNT);
}
})
.setNegativeButton(R.string.no, null)
.setMessage(String.format(getString(R.string.mountnodisk), _mntfname))
.create();
break;
default:
d = null;
}
return d;
}
@Override
protected void onPrepareDialog(int id, Dialog d) {
switch (id) {
case DLG_MOUNT:
String[] drives = NativeGetDrvFnames();
StringBuilder itemtxt;
for (int i = 0; i < 4; i++) {
itemtxt = (StringBuilder) ((AlertDialog) d).getListView().getAdapter().getItem(i);
itemtxt.delete(0, itemtxt.length());
itemtxt.append(drives[i]);
}
((AlertDialog) d).getListView().invalidateViews();
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return _srchView.onCreateOptionsMenu(menu, this);
}
@Override
public void finish() {
if (!_pathsel) {
if (_drive1fname != null) {
setResult(Activity.RESULT_OK, new Intent(MainActivity.ACTION_INSERT_ONLY,
Uri.fromFile(new File(_drive1fname))));
}
}
super.finish();
}
private void listDirectory(File dir, int pos, Object retain) {
if (_ad != null) _ad.clear();
_srchView.reset(this);
setTitle(getString(_pathsel ? R.string.fsel_opendir : R.string.fsel_openfile)
+ " " + dir.getAbsolutePath());
_curdir = dir;
if (retain == null)
_task = (ListDirTask) new ListDirTask(pos).execute(dir);
else {
_ad = new IconArrayAdapter(this, R.layout.file_selector_row);
for (String str: (String[]) retain)
_ad.add(str);
setListAdapter(_ad);
if (pos > _ad.getCount()) pos = _ad.getCount();
setSelection(pos);
}
}
private final class ListDirTask extends AsyncTask<File, Void, IconArrayAdapter>
{
ProgressDialog _pdlg;
int _position;
public ListDirTask(int pos) {
_position = pos;
}
@Override
protected void onPreExecute() {
_pdlg = ProgressDialog.show(FileSelector.this, "", getString(R.string.loadingdir), true);
}
@Override
protected void onPostExecute(IconArrayAdapter res) {
_ad = res;
setListAdapter(_ad);
if (_position > res.getCount()) _position = res.getCount();
setSelection(_position);
try {
_pdlg.dismiss();
} catch (Exception e) {
Log.d(TAG, "Leaked pdialog handle");
}
_task = null;
}
@Override
protected IconArrayAdapter doInBackground(File... files) {
IconArrayAdapter flst = new IconArrayAdapter(FileSelector.this, R.layout.file_selector_row);
File dir = files[0];
if (!dir.toString().equals("/"))
flst.add("../");
File[] lst = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
String f = file.getName().toLowerCase();
int l = f.length();
return file.isDirectory() || (l > 3 && EXTENSIONS.contains(f.substring(l - 3)));
}
});
if (lst == null) return flst;
for (File f: lst) {
if (f.isDirectory())
flst.add(f.getName() + "/");
else
flst.add(f.getName());
}
flst.sort(new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
boolean s1b = s1.endsWith("/");
boolean s2b = s2.endsWith("/");
if (s1b && !s2b) return -1;
if (s2b && !s1b) return 1;
return s1.compareToIgnoreCase(s2);
}
});
return flst;
}
}
private native boolean NativeIsDisk(String img);
private native int NativeRunAtariProgram(String img, int drive, int reboot);
private native String[] NativeGetDrvFnames();
private native void NativeUnmountAll();
private static final Set<String> EXTENSIONS = new HashSet<String>(13);
static {
EXTENSIONS.add("atr"); EXTENSIONS.add("atz"); EXTENSIONS.add("xfd");
EXTENSIONS.add("dcm"); EXTENSIONS.add("xfz"); EXTENSIONS.add("xex");
EXTENSIONS.add("cas"); EXTENSIONS.add("rom"); EXTENSIONS.add("bin");
EXTENSIONS.add("car"); EXTENSIONS.add("a8s"); EXTENSIONS.add("com");
EXTENSIONS.add("exe");
}
}
@@ -0,0 +1,308 @@
/*
* KeymapPreference.java - Even simpler preference for mapping keys
*
* Copyright (C) 2010 Kostas Nakos
* Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package name.nick.jubanka.colleen;
import android.preference.DialogPreference;
import android.content.Context;
import android.view.KeyCharacterMap;
import android.view.View;
import android.view.ViewGroup;
import android.view.KeyEvent;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.content.DialogInterface;
import android.os.Bundle;
import android.app.Dialog;
import android.app.AlertDialog;
import android.util.SparseArray;
import android.widget.TextView;
import android.R.style;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import static android.view.KeyEvent.*;
import static name.nick.jubanka.colleen.A800view.*;
public final class KeymapPreference extends DialogPreference
{
private static final String TAG = "KeyPreference";
private static final int DEFKEY = 'a';
private static final String DEFKEYEXT = "-1,-1";
private static final int EXTSTR_ACTION = 0;
private static final int EXTSTR_KEY = 1;
private KeyCharacterMap _keymap;
private int _def;
private String _defext = null;
private boolean _extended = false;
public KeymapPreference(Context c, AttributeSet a) {
super(c, a);
_keymap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
_extended = Boolean.parseBoolean( c.obtainStyledAttributes(a, R.styleable.KeymapPreference)
.getString(R.styleable.KeymapPreference_ext) );
setNegativeButtonText(R.string.cancel);
setDialogTitle(getTitle());
}
@Override
protected Object onGetDefaultValue(TypedArray a, int i) {
try {
_def = a.getInt(i, DEFKEY);
return _def;
} catch (NumberFormatException e) {
_defext = a.getString(i);
if (_defext == null)
_defext = DEFKEYEXT;
return _defext;
}
}
@Override
protected void onSetInitialValue(boolean restore, Object def) {
if (!restore)
if (!_extended)
persistInt((Integer) def);
else
persistString((String) def);
}
@Override
protected void showDialog(Bundle state) {
super.showDialog(state);
Dialog d = getDialog();
d.takeKeyEvents(true);
((AlertDialog) d).getButton(DialogInterface.BUTTON_POSITIVE).setVisibility(View.GONE);
}
@Override
protected View onCreateDialogView() {
View v = new SnoopTextView(getContext());
return v;
}
private final class SnoopTextView extends TextView
{
public SnoopTextView(Context c) {
super(c);
setText( (!_extended) ? R.string.pref_keymapmsg : R.string.pref_keymapmsg1);
setCursorVisible(false);
int pad = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) 10,
c.getResources().getDisplayMetrics());
setPadding(pad, pad, pad, pad);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
}
@Override
public boolean onCheckIsTextEditor() {
return true;
}
@Override
public InputConnection onCreateInputConnection (EditorInfo outAttrs) {
return new BaseInputConnection(this, false);
}
@Override
public boolean onKeyDown(int kc, KeyEvent ev) {
Log.d(TAG, "key " + kc);
for (int res: RESKEYS)
if (res == kc)
return false;
final int k = xlatKey(kc);
if (k == 0)
return false;
if (k == getKeymap() && !_extended) {
getDialog().dismiss();
return true;
}
if (callChangeListener(new Integer(k)) == false) {
new AlertDialog.Builder(getContext())
.setTitle(R.string.warning)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.pref_keymapdupmsg)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int i) {
callChangeListener(new Integer(-k));
setKeymap(k);
d.dismiss();
if (!_extended) {
Dialog d1 = getDialog();
if (d1 != null)
d1.dismiss();
} else
showExtDialog();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int i) {
Dialog d1 = getDialog();
if (d1 != null)
d1.dismiss();
}
})
.show();
return true;
}
setKeymap(k);
if (!_extended)
getDialog().dismiss();
else
showExtDialog();
return true;
}
}
private void showExtDialog()
{
LayoutInflater inf = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
new AlertDialog.Builder(getContext())
.setTitle(getTitle())
.setView(inf.inflate(R.layout.extended_keymap, null))
.setCancelable(false)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int i) {
CharSequence txt = ((TextView) ((Dialog) d).findViewById(R.id.keyinput)).getText();
if (txt == null || txt.length() != 1) {
getDialog().dismiss();
return;
}
persistString( buildExtPref(parseExtPref(EXTSTR_ACTION), (int) txt.charAt(0)) );
updateSum();
d.dismiss();
getDialog().dismiss();
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int i) {
getDialog().dismiss();
}
})
.show();
}
public void updateSum() {
StringBuilder str = new StringBuilder();
str.append( getContext()
.getString(_extended ? R.string.pref_keymap_controller : R.string.pref_keymap_current) );
str.append(" ");
str.append( getKeyname(getKeymap()) );
if (_extended) {
str.append(" ");
str.append( getContext().getString(R.string.pref_keymap_mappedto) );
str.append(" ");
str.append( getKeyname(parseExtPref(EXTSTR_KEY)) );
}
setSummary(str);
}
private int xlatKey(int kc) {
int k;
Integer xlat = A800view.XLATKEYS.get(kc);
if (xlat != null)
k = xlat.intValue();
else
k = _keymap.get(kc, 0);
return k;
}
public void setKeymap(int k) {
if (!_extended)
persistInt(k);
else
persistString( buildExtPref(k, parseExtPref(EXTSTR_KEY)) );
updateSum();
}
public void setDefaultKeymap() {
if (!_extended) return;
persistString(DEFKEYEXT);
updateSum();
}
public int getKeymap() {
if (!_extended)
return getPersistedInt(-128) == -128 ? _def : getPersistedInt(-1);
else
return parseExtPref(EXTSTR_ACTION);
}
private int parseExtPref(int part) {
String str = getPersistedString(null);
return Integer.parseInt( ((str != null) ? str : _defext).split(",")[part] );
}
private String buildExtPref(int k1, int k2) {
return Integer.toString(k1) + "," + Integer.toString(k2);
}
private String getKeyname(int k) {
String name = null;
name = KEYNAMES.get(k);
if (name != null) return name;
if (k > 31 && k < 127) return Character.toString((char) k);
return "ASCII " + k;
}
// Real programmers *hate* data entry ;-)
private static final SparseArray<String> KEYNAMES = new SparseArray<String>(13);
static {
KEYNAMES.put(-1, "None");
KEYNAMES.put(' ', "Space");
KEYNAMES.put(KEY_DOWN, "Down arrow");
KEYNAMES.put(KEY_LEFT, "Left arrow");
KEYNAMES.put(KEY_RIGHT, "Right arrow");
KEYNAMES.put(KEY_UP, "Up arrow");
KEYNAMES.put(KEY_ENTER, "Enter");
KEYNAMES.put(KEY_BACKSPACE, "Del");
KEYNAMES.put(KEY_BT_X, "Button X");
KEYNAMES.put(KEY_BT_Y, "Button Y");
KEYNAMES.put(KEY_BT_L1, "Button L1");
KEYNAMES.put(KEY_BT_R1, "Button R1");
KEYNAMES.put(KEY_BREAK, "DPAD Enter");
}
private static final int[] RESKEYS = {
KEYCODE_SHIFT_LEFT, KEYCODE_SHIFT_RIGHT, KEYCODE_VOLUME_UP, KEYCODE_VOLUME_DOWN,
KEYCODE_MENU, KEYCODE_SEARCH, KEYCODE_BACK, KEYCODE_HOME, KEYCODE_POWER,
KEYCODE_CALL, KEYCODE_ENDCALL
};
}
+870
View File
@@ -0,0 +1,870 @@
/*
* MainActivity.java - activity entry point for atari800
*
* Copyright (C) 2014 Kostas Nakos
* Copyright (C) 2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package name.nick.jubanka.colleen;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.io.File;
import java.util.Map;
import java.util.EnumMap;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuInflater;
import android.view.inputmethod.InputMethodManager;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.app.Dialog;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.widget.TextView;
import android.R.style;
import android.widget.ScrollView;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.app.ActionBar;
import android.view.Window;
import android.view.WindowManager;
import android.os.Build;
import android.view.View;
public final class MainActivity extends Activity
{
public static final String ACTION_INSERT_REBOOT = "name.nick.jubanka.colleen.FileSelector.INSERTREBOOT";
public static final String ACTION_INSERT_ONLY = "name.nick.jubanka.colleen.FileSelector.INSERTONLY";
public static final String ACTION_SET_ROMPATH = "name.nick.jubanka.colleen.FileSelector.SETROMPATH";
private static final String TAG = "MainActivity";
private static final int ACTIVITY_FSEL = 1;
private static final int ACTIVITY_PREFS = 2;
private static final int DLG_WELCOME = 0;
private static final int DLG_PATHSETUP = 1;
private static final int DLG_CHANGES = 2;
private static final int DLG_BRWSCONFRM = 3;
private static final int DLG_SELCARTTYPE = 4;
public static String _pkgversion;
public static String _coreversion;
public ActionBarNull _aBar = null;
private static boolean _initialized = false;
private static String _curDiskFname = null;
private A800view _view = null;
private AudioThread _audio = null;
private InputMethodManager _imng;
private Settings _settings = null;
private boolean _bootupconfig = false;
private String _cartTypes[][] = null;
public static class ActionBarNull {
public ActionBarNull(Activity a) {};
public void hide(Activity a) {};
public void hide(Activity a, boolean p) {};
public void hide(Activity a, boolean p, boolean f) {};
public void show(Activity a) {};
public boolean isShowing(Activity a) { return false; }
public boolean isReal() { return false; }
public void init(Activity a) {};
}
public static final class ActionBarHelp extends ActionBarNull {
public ActionBarHelp(Activity a) {
super(a);
}
@Override
public void hide(Activity a) {
hide(a, true);
}
@Override
public void hide(Activity a, boolean p) {
hide(a, p, false);
}
@Override
public void hide(Activity a, boolean p, boolean f) {
ActionBar ab = a.getActionBar();
View v = ((MainActivity) a)._view;
if ( !f && !ab.isShowing() &&
(v.getSystemUiVisibility() & View.STATUS_BAR_HIDDEN) == View.STATUS_BAR_HIDDEN )
return;
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.JELLY_BEAN) {
a.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
a.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
if (v != null) {
int flags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.STATUS_BAR_HIDDEN;
if (p == true)
flags |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
v.setSystemUiVisibility(flags);
}
ab.hide();
((MainActivity) a).pauseEmulation(false);
}
@Override
public void show(Activity a) {
ActionBar ab = a.getActionBar();
if (ab.isShowing()) return;
((MainActivity) a).pauseEmulation(true);
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.JELLY_BEAN) {
a.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
a.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
View v = ((MainActivity) a)._view;
if (v != null) v.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.STATUS_BAR_VISIBLE);
ab.show();
}
@Override
public boolean isShowing(Activity a) {
return a.getActionBar().isShowing();
}
@Override
public boolean isReal() {
return true;
}
@Override
public void init(Activity a) {
a.getActionBar().setBackgroundDrawable(a.getResources().getDrawable(R.drawable.actionbar_bg));
}
}
static {
System.loadLibrary("atari800");
_coreversion = NativeInit();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Integer.parseInt(Build.VERSION.SDK) >= Build.VERSION_CODES.HONEYCOMB)
_aBar = new ActionBarHelp(this);
else
_aBar = new ActionBarNull(this);
_view = new A800view(this);
setContentView(_view);
_view.setKeepScreenOn(true);
_aBar.init(this);
_aBar.hide(this);
_imng = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
PreferenceManager.setDefaultValues(this, R.xml.preferences, true);
Object obj = getLastNonConfigurationInstance();
_settings = new Settings(PreferenceManager.getDefaultSharedPreferences(this), this, obj);
_pkgversion = getPInfo().versionName;
if (!_initialized) {
_settings.putBoolean("plandef", false);
_settings.fetchApplySettings();
_initialized = true;
bootupMsgs();
} else {
_settings.fetch();
if (obj != null) _settings.testApply();
_settings.commit();
soundInit(false);
}
}
@Override
public Object onRetainNonConfigurationInstance() {
return (Object) _settings.serialize();
}
private void bootupMsgs() {
String instver = _settings.get(false, "version");
if (instver == null || instver.equals("false")) {
_bootupconfig = true;
pauseEmulation(true);
showDialog(DLG_WELCOME);
return;
}
String rompath = _settings.get(false, "rompath");
if (rompath == null || rompath.equals("false")) {
pauseEmulation(true);
_bootupconfig = true;
showDialog(DLG_PATHSETUP);
return;
}
if (Integer.parseInt(instver) != getPInfo().versionCode) {
_bootupconfig = true;
pauseEmulation(true);
showDialog(DLG_CHANGES);
return;
}
Toast.makeText(this,
_aBar.isReal() ? R.string.actionbarhelptoast : R.string.noactionbarhelptoast,
Toast.LENGTH_SHORT).show();
}
public void message(int msg) {
switch (msg) {
case A800Renderer.REQ_BROWSER:
runOnUiThread(new Runnable() {
@Override
public void run() {
showDialog(DLG_BRWSCONFRM);
}
});
break;
};
}
@Override
protected Dialog onCreateDialog(int id) {
Dialog d;
TextView t;
ScrollView s;
switch (id) {
case DLG_WELCOME:
t = new TextView(this);
t.setText(R.string.welcomenote);
t.setTextAppearance(this, android.R.style.TextAppearance_Small_Inverse);
t.setBackgroundResource(android.R.color.background_light);
s = new ScrollView(this);
s.addView(t);
d = new AlertDialog.Builder(this)
.setTitle(R.string.welcome)
.setView(s)
.setInverseBackgroundForced(true)
.setCancelable(false)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
dismissDialog(DLG_WELCOME);
_settings.putInt("version", getPInfo().versionCode);
showDialog(DLG_PATHSETUP);
}
})
.create();
break;
case DLG_PATHSETUP:
t = new TextView(this);
t.setText(Html.fromHtml(getString(R.string.pathsetupmsg)));
t.setTextAppearance(this, android.R.style.TextAppearance_Small_Inverse);
t.setBackgroundResource(android.R.color.background_light);
t.setMovementMethod(LinkMovementMethod.getInstance());
s = new ScrollView(this);
s.addView(t);
d = new AlertDialog.Builder(this)
.setTitle(R.string.pathsetup)
.setView(s)
.setInverseBackgroundForced(true)
.setCancelable(false)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
dismissDialog(DLG_PATHSETUP);
startActivityForResult(new Intent(FileSelector.ACTION_OPEN_PATH,
null, MainActivity.this, FileSelector.class), ACTIVITY_FSEL);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
dismissDialog(DLG_PATHSETUP);
finish();
}
})
.create();
break;
case DLG_CHANGES:
t = new TextView(this);
int[] vs = getResources().getIntArray(R.array.changes_versions);
int instver = getPInfo().versionCode;
for (int i = 0; i < vs.length; i++)
if (vs[i] == instver) {
t.setText(Html.fromHtml(getResources().getStringArray(R.array.changes_strings)[i]));
break;
}
t.setTextAppearance(this, android.R.style.TextAppearance_Small_Inverse);
t.setBackgroundResource(android.R.color.background_light);
t.setMovementMethod(LinkMovementMethod.getInstance());
s = new ScrollView(this);
s.addView(t);
d = new AlertDialog.Builder(this)
.setTitle(R.string.atariupdate)
.setView(s)
.setInverseBackgroundForced(true)
.setCancelable(false)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
_settings.putInt("version", getPInfo().versionCode);
_bootupconfig = false;
pauseEmulation(false);
dismissDialog(DLG_CHANGES);
Toast.makeText(MainActivity.this, _aBar.isReal() ?
R.string.actionbarhelptoast :
R.string.noactionbarhelptoast,
Toast.LENGTH_SHORT).show();
}
})
.create();
break;
case DLG_BRWSCONFRM:
String url = NativeGetURL();
if (url.length() == 0) {
d = null;
break;
}
if (! validateURL(url)) {
Log.d(TAG, "Browser request denied for improper url " + url);
d = null;
NativeClearDevB();
Toast.makeText(this, R.string.browserreqdenied, Toast.LENGTH_SHORT).show();
break;
}
pauseEmulation(true);
d = new AlertDialog.Builder(this)
.setTitle(R.string.warning)
.setIcon(android.R.drawable.ic_dialog_alert)
.setCancelable(false)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
String u = NativeGetURL().trim();
Log.d(TAG, "Spawning browser for " + u);
pauseEmulation(false);
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(u)));
} catch (Exception e1) {
Log.d(TAG, "Exception, trying with lower case");
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(u.toLowerCase())));
} catch (Exception e2) {
Log.d(TAG, "Exception, failed, giving up");
}
}
NativeClearDevB();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
pauseEmulation(false);
NativeClearDevB();
}
})
.setMessage("")
.create();
break;
case DLG_SELCARTTYPE:
if (_cartTypes == null || _cartTypes.length == 0) {
Log.d(TAG, "0 cart types passed");
d = null;
break;
}
pauseEmulation(true);
String itm[] = new String[_cartTypes.length];
for (int i = 0; i < _cartTypes.length; itm[i] = _cartTypes[i][1], i++);
d = new AlertDialog.Builder(this)
.setTitle(R.string.selectcarttype)
.setCancelable(false)
.setItems(itm, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
NativeBootCartType(Integer.parseInt(_cartTypes[i][0]));
pauseEmulation(false);
removeDialog(DLG_SELCARTTYPE);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int i) {
pauseEmulation(false);
removeDialog(DLG_SELCARTTYPE);
}
})
.create();
break;
default:
d = null;
}
return d;
}
@Override
protected void onPrepareDialog(int id, Dialog d) {
switch (id) {
case DLG_BRWSCONFRM:
((AlertDialog) d).setMessage(String.format(getString(R.string.confirmurl), NativeGetURL().trim()));
break;
}
}
private boolean validateURL(String u) {
if (u.trim().toLowerCase().startsWith("http://"))
return true;
return false;
}
private PackageInfo getPInfo() {
PackageInfo p;
try {
p = getPackageManager().getPackageInfo("name.nick.jubanka.colleen", 0);
} catch (Exception e) {
Log.d(TAG, "Package not found");
p = null;
}
return p;
}
private void soundInit(boolean n) {
if (Boolean.parseBoolean(_settings.get(n, "sound"))) {
if (_audio != null) _audio.interrupt();
_audio = new AudioThread(Integer.parseInt(_settings.get(n, "mixrate")),
Boolean.parseBoolean(_settings.get(n, "sound16bit")) ? 2 : 1,
Integer.parseInt(_settings.get(n, "mixbufsize")) * 10,
Boolean.parseBoolean(_settings.get(n, "ntsc")));
_audio.start();
} else {
if (_audio != null) _audio.interrupt();
_audio = null;
}
}
public void pauseEmulation(boolean pause) {
if (pause) {
if (_audio != null) _audio.pause(pause);
if (_view != null) _view.pause(pause);
} else {
if (_view != null) _view.pause(pause);
if (_audio != null) _audio.pause(pause);
}
}
@Override
public void onPause() {
_imng.hideSoftInputFromWindow(_view.getWindowToken(), 0);
pauseEmulation(true);
super.onPause();
}
@Override
public void onResume() {
_aBar.hide(this, true, true);
if (!_bootupconfig) pauseEmulation(false);
super.onResume();
}
@Override
public void onDestroy() {
if(_audio != null) _audio.interrupt();
super.onDestroy();
if (isFinishing()) {
Log.d(TAG, "Exiting with finishing flag up");
NativeExit();
android.os.Process.killProcess(android.os.Process.myPid());
}
}
// Menu stuff
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inf = getMenuInflater();
inf.inflate(R.menu.menu, menu);
return true;
}
@Override
public void onOptionsMenuClosed(Menu m) {
_aBar.hide(this);
pauseEmulation(false);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (!_aBar.isReal())
pauseEmulation(true); // menu is always shown on > honeycomb
_imng.hideSoftInputFromWindow(_view.getWindowToken(), 0);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_quit:
finish();
return true;
case R.id.menu_softkbd:
_imng.showSoftInput(_view, InputMethodManager.SHOW_FORCED);
_aBar.hide(this, false);
return true;
case R.id.menu_open:
startActivityForResult(new Intent(FileSelector.ACTION_OPEN_FILE, null, this, FileSelector.class),
ACTIVITY_FSEL);
return true;
case R.id.menu_nextdisk:
insertNextDisk();
_aBar.hide(this);
return true;
case R.id.menu_preferences:
startActivityForResult(new Intent(this, Preferences.class), ACTIVITY_PREFS);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onActivityResult(int reqc, int resc, Intent data) {
_aBar.hide(this);
switch (reqc) {
case ACTIVITY_FSEL:
if (resc != RESULT_OK) {
if (_bootupconfig) finish();
break;
}
if (data.getAction().equals(ACTION_SET_ROMPATH)) {
String p = data.getData().getPath();
_settings.putString("rompath", p);
_settings.simulateChanged("rompath");
_bootupconfig = false;
pauseEmulation(false);
break;
}
_curDiskFname = data.getData().getPath();
if (data.getAction().equals(ACTION_INSERT_REBOOT)) {
int r = NativeRunAtariProgram(_curDiskFname, 1, 1);
if (r == -2)
showDialog(DLG_SELCARTTYPE);
else
Toast.makeText(this, String.format(getString(r < 0 ? R.string.errorboot : R.string.diskboot),
_curDiskFname.substring(_curDiskFname.lastIndexOf("/") + 1)),
Toast.LENGTH_SHORT)
.show();
}
break;
case ACTIVITY_PREFS:
_settings.fetchApplySettings();
break;
}
}
private void insertNextDisk() {
final String[] pats = { "[\\s(,_]+s\\d" };
Pattern p;
Matcher m;
File f;
if (_curDiskFname == null)
return;
String path = _curDiskFname.substring(0, _curDiskFname.lastIndexOf("/") + 1);
String fname = _curDiskFname.substring(_curDiskFname.lastIndexOf("/") + 1,
_curDiskFname.lastIndexOf("."));
String ext = _curDiskFname.substring(_curDiskFname.lastIndexOf("."));
Log.d(TAG, "Enter **" + path + "**" + fname + "**" + ext + "**");
for (String s: pats) {
p = Pattern.compile(s);
m = p.matcher(fname);
if (m.find()) {
Log.d(TAG, "Match **" + m.group() + "**");
char side = (char)(fname.charAt(m.end() - 1) + 1);
char end = side;
do {
f = new File(path + fname.substring(0, m.end() - 1) + side +
fname.substring(m.end()) + ext);
Log.d(TAG, "Trying loop " + f.getName());
if (f.exists()) {
_curDiskFname = f.getPath();
int r = NativeRunAtariProgram(_curDiskFname, 1, 0);
Toast.makeText(this,
String.format(getString(
r >= 0 ? R.string.mountnextdisk : R.string.mountnextdiskerror),
f.getName()),
Toast.LENGTH_SHORT)
.show();
return;
}
if (side != '9')
side++;
else
side = '0';
} while (side != end);
}
}
Toast.makeText(this, R.string.mountnonextdisk, Toast.LENGTH_SHORT).show();
}
private native int NativeRunAtariProgram(String img, int drive, int reboot);
private native void NativeBootCartType(int kb);
private native void NativeExit();
private static native String NativeInit();
// ----------------- Preferences -------------------
private final static class Settings
{
enum PreferenceName {
aspect, bilinear, artifact, frameskip, collisions, machine, basic, speed,
disk, sector, softjoy, up, down, left, right, fire, joyvisible, joysize,
joyopacity, joyrighth, joydeadband, joymidx, sound, mixrate, sound16bit,
hqpokey, mixbufsize, version, rompath, anchor, anchorstr, joygrace,
crophoriz, cropvert, derotkeys, actiona, actionb, actionc, ntsc, paddle,
plandef, browser, forceAT
};
private SharedPreferences _sharedprefs;
private Map<PreferenceName, String> _values, _newvalues;
private Context _context;
@SuppressWarnings("unchecked")
public Settings(SharedPreferences s, Context c, Object retain) {
_sharedprefs = s;
_context = c;
if (retain == null)
_values = new EnumMap<PreferenceName, String>(PreferenceName.class);
else
_values = (EnumMap<PreferenceName, String>) retain;
_newvalues = new EnumMap<PreferenceName, String>(PreferenceName.class);
}
public void fetch() {
String v = null;
for (PreferenceName n: PreferenceName.values()) {
// nice, efficient coerce to string follows
try { v = Boolean.toString(_sharedprefs.getBoolean(n.toString(), false)); } catch(Exception e1) {
try { v = Integer.toString(_sharedprefs.getInt(n.toString(), -1)); } catch(Exception e2) {
try { v = _sharedprefs.getString(n.toString(), null); } catch(Exception e3) {
throw new ClassCastException(); }}};
_newvalues.put(n, v);
}
}
private void apply() {
NativePrefGfx( Integer.parseInt(_newvalues.get(PreferenceName.aspect)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.bilinear)),
Integer.parseInt(_newvalues.get(PreferenceName.artifact)),
Integer.parseInt(_newvalues.get(PreferenceName.frameskip)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.collisions)),
Integer.parseInt(_newvalues.get(PreferenceName.crophoriz)),
Integer.parseInt(_newvalues.get(PreferenceName.cropvert)) );
if ( changed(PreferenceName.machine) || changed(PreferenceName.ntsc) ) {
if ( !NativePrefMachine(Integer.parseInt(_newvalues.get(PreferenceName.machine)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.ntsc))) ) {
Log.d(TAG, "OS rom not found");
if ( _values.get(PreferenceName.machine) != null &&
!_values.get(PreferenceName.machine).equals("false") ) {
Toast.makeText(_context, R.string.noromfoundrevert, Toast.LENGTH_LONG).show();
revertString(PreferenceName.machine);
NativePrefMachine(Integer.parseInt(_newvalues.get(PreferenceName.machine)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.ntsc)));
} else {
Toast.makeText(_context, R.string.noromfound, Toast.LENGTH_LONG).show();
}
}
}
NativePrefEmulation( Boolean.parseBoolean(_newvalues.get(PreferenceName.basic)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.speed)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.disk)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.sector)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.browser)) );
NativePrefSoftjoy( Boolean.parseBoolean(_newvalues.get(PreferenceName.softjoy)),
Integer.parseInt(_newvalues.get(PreferenceName.up)),
Integer.parseInt(_newvalues.get(PreferenceName.down)),
Integer.parseInt(_newvalues.get(PreferenceName.left)),
Integer.parseInt(_newvalues.get(PreferenceName.right)),
Integer.parseInt(_newvalues.get(PreferenceName.fire)),
Integer.parseInt(_newvalues.get(PreferenceName.derotkeys)),
new String[] { _newvalues.get(PreferenceName.actiona),
_newvalues.get(PreferenceName.actionb),
_newvalues.get(PreferenceName.actionc) } );
int x = 0, y = 0;
if (Boolean.parseBoolean(_newvalues.get(PreferenceName.anchor))) {
String astr = _newvalues.get(PreferenceName.anchorstr);
if (astr == null || astr.equals("false")) {
astr = NativeGetJoypos();
putString("anchorstr", astr);
_newvalues.put(PreferenceName.anchorstr, astr);
}
String[] tok = astr.split(" ");
x = Integer.parseInt(tok[0]);
y = Integer.parseInt(tok[1]);
} else
putString("anchorstr", "false");
NativePrefJoy( Boolean.parseBoolean(_newvalues.get(PreferenceName.joyvisible)),
Integer.parseInt(_newvalues.get(PreferenceName.joysize)),
Integer.parseInt(_newvalues.get(PreferenceName.joyopacity)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.joyrighth)),
Integer.parseInt(_newvalues.get(PreferenceName.joydeadband)),
Integer.parseInt(_newvalues.get(PreferenceName.joymidx)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.anchor)),
x, y,
Integer.parseInt(_newvalues.get(PreferenceName.joygrace)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.paddle)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.plandef)) );
if ( changed(PreferenceName.mixrate) || changed(PreferenceName.sound16bit) ||
changed(PreferenceName.hqpokey) || changed(PreferenceName.mixbufsize) ||
changed(PreferenceName.forceAT) )
NativePrefSound( Integer.parseInt(_newvalues.get(PreferenceName.mixrate)),
Integer.parseInt(_newvalues.get(PreferenceName.mixbufsize)) * 10,
Boolean.parseBoolean(_newvalues.get(PreferenceName.sound16bit)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.hqpokey)),
Boolean.parseBoolean(_newvalues.get(PreferenceName.forceAT)) );
if ( changed(PreferenceName.sound) || changed(PreferenceName.mixrate) ||
changed(PreferenceName.sound16bit) || changed(PreferenceName.mixbufsize) ||
changed(PreferenceName.forceAT) )
((MainActivity) _context).soundInit(true);
if (changed(PreferenceName.rompath))
if (!NativeSetROMPath(_newvalues.get(PreferenceName.rompath)))
Toast.makeText(_context, R.string.rompatherror, Toast.LENGTH_LONG).show();
}
public void simulateChanged(String key) {
for (PreferenceName n: PreferenceName.values())
_newvalues.put(n, _values.get(n));
_values.put(PreferenceName.valueOf(key), null);
apply();
commit();
}
public String get(boolean newval, String what) {
return (newval ? _newvalues : _values).get(PreferenceName.valueOf(what));
}
public void putInt(String key, int val) {
_values.put(PreferenceName.valueOf(key), Integer.toString(val));
SharedPreferences.Editor e = _sharedprefs.edit();
e.putInt(key, val);
e.commit();
}
public void putString(String key, String val) {
_values.put(PreferenceName.valueOf(key), val);
SharedPreferences.Editor e = _sharedprefs.edit();
e.putString(key, val);
e.commit();
}
public void putBoolean(String key, boolean val) {
_values.put(PreferenceName.valueOf(key), Boolean.toString(val));
SharedPreferences.Editor e = _sharedprefs.edit();
e.putBoolean(key, val);
e.commit();
}
private void revertString(PreferenceName p) {
String oldval = _values.get(p);
_newvalues.put(p, oldval);
SharedPreferences.Editor e = _sharedprefs.edit();
e.putString(p.toString(), oldval);
e.commit();
}
public void fetchApplySettings() {
fetch();
apply();
commit();
}
public void testApply() {
boolean changed = false;
for (PreferenceName n: PreferenceName.values())
changed |= changed(n);
if (changed)
apply();
}
private boolean changed(PreferenceName p) {
String s1 = _values.get(p);
String s2 = _newvalues.get(p);
if (s1 == null || s2 == null) return true;
return !s1.equals(s2);
}
public void commit() {
for (PreferenceName n: PreferenceName.values()) {
_values.put(n, _newvalues.get(n));
_newvalues.put(n, null);
}
}
public void print() {
for (PreferenceName n: PreferenceName.values())
Log.d(TAG, n.toString() + "=" + _values.get(n));
}
public Map<PreferenceName, String> serialize() {
return _values;
}
}
private static native void NativePrefGfx(int aspect, boolean bilinear, int artifact,
int frameskip, boolean collisions, int crophoriz, int cropvert);
private static native boolean NativePrefMachine(int machine, boolean ntsc);
private static native void NativePrefEmulation(boolean basic, boolean speed, boolean disk,
boolean sector, boolean browser);
private static native void NativePrefSoftjoy(boolean softjoy, int up, int down, int left, int right,
int fire, int derotkeys, String[] actions);
private static native void NativePrefJoy(boolean visible, int size, int opacity, boolean righth,
int deadband, int midx, boolean anchor, int anchorx, int anchory,
int grace, boolean paddle, boolean plandef);
private static native void NativePrefSound(int mixrate, int mixbufsizems, boolean sound16bit, boolean hqpokey,
boolean disableOSL);
private static native boolean NativeSetROMPath(String path);
private static native String NativeGetJoypos();
private static native String NativeGetURL();
private static native void NativeClearDevB();
}
+291
View File
@@ -0,0 +1,291 @@
/*
* Preferences.java - Preference activity for the emulator
*
* Copyright (C) 2014 Kostas Nakos
* Copyright (C) 2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package name.nick.jubanka.colleen;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import android.preference.PreferenceActivity;
import android.os.Bundle;
import android.preference.Preference;
import android.util.Log;
import android.content.SharedPreferences;
import android.preference.Preference.OnPreferenceClickListener;
import android.net.Uri;
import android.content.Intent;
import android.app.AlertDialog;
import android.webkit.WebView;
import android.app.Dialog;
import android.content.DialogInterface;
import android.preference.EditTextPreference;
import android.widget.Toast;
import android.content.res.Resources;
import android.preference.CheckBoxPreference;
public final class Preferences extends PreferenceActivity implements Preference.OnPreferenceChangeListener
{
private static final String TAG = "Preferences";
private static final String[] PREF_KEYS = { "up", "down", "left", "right", "fire",
"actiona", "actionb", "actionc" };
private static final String PD_RESNAME = "pd2012";
private static final int ACTIVITY_FSEL_ROMPATH = 1;
private static final int ACTIVITY_FSEL_STATEPATH = 2;
private static final int DLG_ABOUT = 1;
private static final int DLG_RESET = 2;
private static final int DLG_OVRWR = 3;
private SharedPreferences _sp;
private String _svstfname = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
KeymapPreference kp;
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
_sp = getPreferenceManager().getSharedPreferences();
for (String s: PREF_KEYS) {
kp = (KeymapPreference) findPreference(s);
kp.setOnPreferenceChangeListener(this);
kp.updateSum();
}
for (final String pref: new String[] {"rompath", "statepath"}) {
findPreference(pref).setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference p) {
String val = _sp.getString(pref, null);
Uri u = (val == null) ? null : Uri.fromFile(new File(val));
startActivityForResult(new Intent(FileSelector.ACTION_OPEN_PATH, u,
Preferences.this, FileSelector.class),
pref.equals("rompath") ? ACTIVITY_FSEL_ROMPATH :
ACTIVITY_FSEL_STATEPATH);
return true;
}
});
}
findPreference("about").setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference p) {
showDialog(DLG_ABOUT);
return true;
}
});
findPreference("help").setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference p) {
startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse("http://pocketatari.atari.org/android/index.html#manual")));
return true;
}
});
findPreference("resetactions").setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference p) {
showDialog(DLG_RESET);
return true;
}
});
if (_sp.getString("statepath", null) != null)
enableStateSave();
findPreference("savestate").setOnPreferenceChangeListener(this);
Preference p = findPreference("launchpd");
if (p != null) {
p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference p) {
Resources res = Preferences.this.getResources();
int id = res.getIdentifier(PD_RESNAME, "raw", Preferences.this.getPackageName());
if (id != 0) {
InputStream is = res.openRawResource(id);
byte pddata[];
try {
pddata = new byte[is.available()];
is.read(pddata);
is.close();
} catch (IOException e) {
Log.d(TAG, "IO exception while reading resouce");
return true;
}
if (! NativeBootPD(pddata, pddata.length))
Toast.makeText(Preferences.this, R.string.pdbooterror, Toast.LENGTH_LONG).show();
else {
((CheckBoxPreference) Preferences.this.findPreference("plandef")).setChecked(true);
Toast.makeText(Preferences.this, R.string.pdreminder, Toast.LENGTH_LONG).show();
Preferences.this.finish();
}
} else {
Log.d(TAG, "PD2012 resource not found");
}
return true;
}
});
if (getResources().getIdentifier(PD_RESNAME, "raw", getPackageName()) == 0)
p.setEnabled(false);
}
findPreference("forceAT").setEnabled(NativeOSLSound() || ((CheckBoxPreference) findPreference("forceAT")).isChecked());
}
private void enableStateSave() {
Preference p = findPreference("savestate");
p.setEnabled(true);
p.setSummary(getString(R.string.pref_savestate_sum_ena));
}
private boolean saveState(boolean force) {
String path = _sp.getString("statepath", null);
if (path == null) {
Log.d(TAG, "state save path is null");
Toast.makeText(this, R.string.savestateerror, Toast.LENGTH_LONG).show();
return true;
}
if (!force && new File(path, _svstfname).exists())
return false;
if (!NativeSaveState(path + '/' + _svstfname)) {
Toast.makeText(this, R.string.savestateerror, Toast.LENGTH_LONG).show();
return true;
}
Toast.makeText(this, R.string.savestateok, Toast.LENGTH_LONG).show();
return true;
}
@Override
public boolean onPreferenceChange(Preference p, Object v) {
if (p.getKey().equals("savestate")) {
_svstfname = (String) v + ".a8s";
if (!saveState(false))
showDialog(DLG_OVRWR);
return true;
} else {
int k = (Integer) v;
KeymapPreference pref;
Log.d(TAG, "Change " + k);
for (String key: PREF_KEYS) {
if (key.equals(p.getKey())) continue;
pref = (KeymapPreference) findPreference(key);
if (k >= 0) { // check mappings
if (pref.getKeymap() == k)
return false;
} else { // swap mappings
if (pref.getKeymap() == -k) {
pref.setKeymap( ((KeymapPreference) p).getKeymap() );
return true;
}
}
}
return true;
}
}
@Override
protected void onActivityResult(int reqc, int resc, Intent data) {
String pref = "rompath";
if (resc != RESULT_OK) return;
switch (reqc) {
case ACTIVITY_FSEL_STATEPATH:
pref = "statepath";
enableStateSave();
// fallthrough
case ACTIVITY_FSEL_ROMPATH:
SharedPreferences.Editor e = _sp.edit();
e.putString(pref, data.getData().getPath());
e.commit();
break;
}
}
@Override
protected Dialog onCreateDialog(int id) {
Dialog d;
switch (id) {
case DLG_ABOUT:
WebView v = new WebView(this);
v.loadData(String.format(getString(R.string.aboutmsg),
MainActivity._pkgversion, MainActivity._coreversion), "text/html", "utf-8");
v.setVerticalScrollBarEnabled(true);
d = new AlertDialog.Builder(this)
.setTitle(R.string.about)
.setIcon(R.drawable.icon)
.setView(v)
.setInverseBackgroundForced(true)
.setPositiveButton(R.string.ok, null)
.create();
break;
case DLG_RESET:
d = new AlertDialog.Builder(this)
.setTitle(R.string.warning)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.pref_warnresetactions)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int i) {
for (String str: new String[] {"actiona", "actionb", "actionc"})
((KeymapPreference) findPreference(str)).setDefaultKeymap();
}
})
.setNegativeButton(R.string.cancel, null)
.create();
break;
case DLG_OVRWR:
d = new AlertDialog.Builder(this)
.setTitle(R.string.warning)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(String.format(getString(R.string.savestateoverwrite), _svstfname))
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int i) {
saveState(true);
}
})
.setNegativeButton(R.string.cancel, null)
.create();
break;
default:
d = null;
}
return d;
}
private native boolean NativeSaveState(String fname);
private native boolean NativeBootPD(byte data[], int len);
private native boolean NativeOSLSound();
}
@@ -0,0 +1,101 @@
/*
* SliderPreference.java - Simple custom preference dialog with a slider
*
* Copyright (C) 2010 Kostas Nakos
* Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package name.nick.jubanka.colleen;
import android.preference.DialogPreference;
import android.content.Context;
import android.util.AttributeSet;
import android.content.res.TypedArray;
import android.widget.SeekBar;
import android.view.LayoutInflater;
import android.widget.TextView;
import android.view.View;
import android.content.DialogInterface;
import android.util.Log;
public final class SliderPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener
{
private int _min, _max, _def;
private String _suffix;
private TextView _txtSetting = null;
private int _sliderValue;
public SliderPreference(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SliderPreference);
_min = a.getInt(R.styleable.SliderPreference_min, 10);
_max = a.getInt(R.styleable.SliderPreference_max, 99);
_suffix = a.getString(R.styleable.SliderPreference_suffix);
if (_suffix == null) _suffix = "%";
a.recycle();
setPositiveButtonText(R.string.ok);
setNegativeButtonText(R.string.cancel);
setDialogTitle(getTitle());
}
@Override
protected Object onGetDefaultValue(TypedArray a, int i) {
_def = a.getInt(i, 10);
return _def;
}
@Override
protected void onSetInitialValue(boolean restore, Object def) {
if (restore == false)
persistInt((Integer) def);
}
@Override
protected View onCreateDialogView() {
LayoutInflater inf = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inf.inflate(R.layout.slider_dialog, null);
_txtSetting = (TextView) v.findViewById(R.id.setting);
SeekBar s = (SeekBar) v.findViewById(R.id.slider);
s.setOnSeekBarChangeListener(this);
s.setMax(_max - _min);
s.setProgress(getPersistedInt(_def) - _min);
onProgressChanged(s, getPersistedInt(_def) - _min, false);
return v;
}
@Override
public void onClick(DialogInterface d, int w) {
if (w == DialogInterface.BUTTON_POSITIVE && callChangeListener(_sliderValue))
persistInt(_sliderValue);
_txtSetting = null;
}
@Override
public void onProgressChanged(SeekBar s, int p, boolean u) {
_sliderValue = p + _min;
_txtSetting.setText(_sliderValue + _suffix);
}
@Override public void onStartTrackingTouch(SeekBar seekBar) {}
@Override public void onStopTrackingTouch(SeekBar seekBar) {}
}
+4143
View File
File diff suppressed because it is too large Load Diff
+137
View File
@@ -0,0 +1,137 @@
#ifndef ANTIC_H_
#define ANTIC_H_
#include "atari.h"
/*
* Offset to registers in custom relative to start of antic memory addresses.
*/
#define ANTIC_OFFSET_DMACTL 0x00
#define ANTIC_OFFSET_CHACTL 0x01
#define ANTIC_OFFSET_DLISTL 0x02
#define ANTIC_OFFSET_DLISTH 0x03
#define ANTIC_OFFSET_HSCROL 0x04
#define ANTIC_OFFSET_VSCROL 0x05
#define ANTIC_OFFSET_PMBASE 0x07
#define ANTIC_OFFSET_CHBASE 0x09
#define ANTIC_OFFSET_WSYNC 0x0a
#define ANTIC_OFFSET_VCOUNT 0x0b
#define ANTIC_OFFSET_PENH 0x0c
#define ANTIC_OFFSET_PENV 0x0d
#define ANTIC_OFFSET_NMIEN 0x0e
#define ANTIC_OFFSET_NMIRES 0x0f
#define ANTIC_OFFSET_NMIST 0x0f
extern UBYTE ANTIC_CHACTL;
extern UBYTE ANTIC_CHBASE;
extern UWORD ANTIC_dlist;
extern UBYTE ANTIC_DMACTL;
extern UBYTE ANTIC_HSCROL;
extern UBYTE ANTIC_NMIEN;
extern UBYTE ANTIC_NMIST;
extern UBYTE ANTIC_PMBASE;
extern UBYTE ANTIC_VSCROL;
extern int ANTIC_break_ypos;
extern int ANTIC_ypos;
extern int ANTIC_wsync_halt;
/* Current clock cycle in a scanline.
Normally 0 <= ANTIC_xpos && ANTIC_xpos < ANTIC_LINE_C, but in some cases ANTIC_xpos >= ANTIC_LINE_C,
which means that we are already in line (ypos + 1). */
extern int ANTIC_xpos;
/* ANTIC_xpos limit for the currently running 6502 emulation. */
extern int ANTIC_xpos_limit;
/* Main clock value at the beginning of the current scanline. */
extern unsigned int ANTIC_screenline_cpu_clock;
/* Current main clock value. */
#define ANTIC_CPU_CLOCK (ANTIC_screenline_cpu_clock + ANTIC_XPOS)
#define ANTIC_NMIST_C 6
#define ANTIC_NMI_C 12
/* Number of cycles per scanline. */
#define ANTIC_LINE_C 114
/* STA WSYNC resumes here. */
#define ANTIC_WSYNC_C 106
/* Number of memory refresh cycles per scanline.
In the first scanline of a font mode there are actually less than ANTIC_DMAR
memory refresh cycles. */
#define ANTIC_DMAR 9
extern int ANTIC_artif_mode;
extern int ANTIC_artif_new;
extern UBYTE ANTIC_PENH_input;
extern UBYTE ANTIC_PENV_input;
int ANTIC_Initialise(int *argc, char *argv[]);
void ANTIC_Reset(void);
void ANTIC_Frame(int draw_display);
UBYTE ANTIC_GetByte(UWORD addr, int no_side_effects);
void ANTIC_PutByte(UWORD addr, UBYTE byte);
UBYTE ANTIC_GetDLByte(UWORD *paddr);
UWORD ANTIC_GetDLWord(UWORD *paddr);
/* always call ANTIC_UpdateArtifacting after changing ANTIC_artif_mode */
void ANTIC_UpdateArtifacting(void);
/* Video memory access */
void ANTIC_VideoMemset(UBYTE *ptr, UBYTE val, ULONG size);
void ANTIC_VideoPutByte(UBYTE *ptr, UBYTE val);
/* GTIA calls it on a write to PRIOR */
void ANTIC_SetPrior(UBYTE prior);
/* Saved states */
void ANTIC_StateSave(void);
void ANTIC_StateRead(void);
/* Pointer to 16 KB seen by ANTIC in 0x4000-0x7fff.
If it's the same what the CPU sees (and what's in memory[0x4000..0x7fff],
then NULL. */
extern const UBYTE *ANTIC_xe_ptr;
/* PM graphics for GTIA */
extern int ANTIC_player_dma_enabled;
extern int ANTIC_missile_dma_enabled;
extern int ANTIC_player_gra_enabled;
extern int ANTIC_missile_gra_enabled;
extern int ANTIC_player_flickering;
extern int ANTIC_missile_flickering;
/* ANTIC colour lookup tables, used by GTIA */
extern UWORD ANTIC_cl[128];
extern ULONG ANTIC_lookup_gtia9[16];
extern ULONG ANTIC_lookup_gtia11[16];
extern UWORD ANTIC_hires_lookup_l[128];
#ifdef NEW_CYCLE_EXACT
#define ANTIC_NOT_DRAWING -999
#define ANTIC_DRAWING_SCREEN (ANTIC_cur_screen_pos!=ANTIC_NOT_DRAWING)
extern int ANTIC_delayed_wsync;
extern int ANTIC_cur_screen_pos;
extern const int *ANTIC_cpu2antic_ptr;
extern const int *ANTIC_antic2cpu_ptr;
void ANTIC_UpdateScanline(void);
void ANTIC_UpdateScanlinePrior(UBYTE byte);
#define ANTIC_XPOS ( ANTIC_DRAWING_SCREEN ? ANTIC_cpu2antic_ptr[ANTIC_xpos] : ANTIC_xpos )
#else
#define ANTIC_XPOS ANTIC_xpos
#endif /* NEW_CYCLE_EXACT */
#ifndef NO_SIMPLE_PAL_BLENDING
/* Set to 1 to enable simplified emulation of PAL blending, that uses only
the standard 8-bit palette. */
extern int ANTIC_pal_blending;
#endif /* NO_SIMPLE_PAL_BLENDING */
#endif /* ANTIC_H_ */
+217
View File
@@ -0,0 +1,217 @@
/*
* artifact.c - management of video artifacting settings
*
* Copyright (C) 2013 Tomasz Krasuski
* Copyright (C) 2013 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with Atari800; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <string.h>
#include "artifact.h"
#include "antic.h"
#include "atari.h"
#include "cfg.h"
#include "log.h"
#ifdef PAL_BLENDING
#include "pal_blending.h"
#endif /* PAL_BLENDING */
#include "util.h"
#if SUPPORTS_CHANGE_VIDEOMODE
#include "videomode.h"
#endif /* SUPPORTS_CHANGE_VIDEOMODE */
ARTIFACT_t ARTIFACT_mode = ARTIFACT_NONE;
static ARTIFACT_t mode_ntsc = ARTIFACT_NONE;
static ARTIFACT_t mode_pal = ARTIFACT_NONE;
static char const * const mode_cfg_strings[ARTIFACT_SIZE] = {
"NONE",
"NTSC-OLD",
"NTSC-NEW",
#if NTSC_FILTER
"NTSC-FULL",
#endif /* NTSC_FILTER */
#ifndef NO_SIMPLE_PAL_BLENDING
"PAL-SIMPLE",
#endif /* NO_SIMPLE_PAL_BLENDING */
#ifdef PAL_BLENDING
"PAL-BLEND"
#endif /* PAL_BLENDING */
};
static void UpdateMode(ARTIFACT_t old_mode, int reinit)
{
#if (NTSC_FILTER && SUPPORTS_CHANGE_VIDEOMODE) || defined(PAL_BLENDING)
int need_reinit = FALSE;
#endif /* (NTSC_FILTER && SUPPORTS_CHANGE_VIDEOMODE) || defined(PAL_BLENDING) */
if (ARTIFACT_mode == old_mode)
return;
/* TV effect has changed. */
#if NTSC_FILTER && SUPPORTS_CHANGE_VIDEOMODE
/* If switched between non-filter and NTSC filter, video mode needs update. */
if (ARTIFACT_mode == ARTIFACT_NTSC_FULL ||
old_mode == ARTIFACT_NTSC_FULL)
need_reinit = TRUE;
#endif /* NTSC_FILTER && SUPPORTS_CHANGE_VIDEOMODE */
#ifdef PAL_BLENDING
/* If PAL blending was enabled/disabled, video mode needs update. */
if (ARTIFACT_mode == ARTIFACT_PAL_BLEND ||
old_mode == ARTIFACT_PAL_BLEND)
need_reinit = TRUE;
#endif /* PAL_BLENDING */
#ifndef NO_SIMPLE_PAL_BLENDING
ANTIC_pal_blending = ARTIFACT_mode == ARTIFACT_PAL_SIMPLE;
#endif /* NO_SIMPLE_PAL_BLENDING */
if (ARTIFACT_mode != ARTIFACT_NTSC_OLD &&
ARTIFACT_mode != ARTIFACT_NTSC_NEW) {
ANTIC_artif_new = ANTIC_artif_mode = 0;
} else {
if (ANTIC_artif_mode == 0)
/* ANTIC new or old artifacting is being enabled */
ANTIC_artif_mode = 1;
ANTIC_artif_new = ARTIFACT_mode == ARTIFACT_NTSC_NEW;
}
ANTIC_UpdateArtifacting();
#if SUPPORTS_CHANGE_VIDEOMODE
if (need_reinit && reinit) {
if (!VIDEOMODE_Update()) {
ARTIFACT_t tmp = ARTIFACT_mode;
/* Updating display failed, restore previous setting. */
ARTIFACT_mode = old_mode;
UpdateMode(tmp, FALSE);
}
}
#endif /* SUPPORTS_CHANGE_VIDEOMODE */
}
static void UpdateFromTVMode(int tv_mode)
{
if (tv_mode == Atari800_TV_NTSC)
ARTIFACT_mode = mode_ntsc;
else /* tv_mode == Atari800_TV_PAL */
ARTIFACT_mode = mode_pal;
}
void ARTIFACT_Set(ARTIFACT_t mode)
{
ARTIFACT_t old_effect = ARTIFACT_mode;
ARTIFACT_mode = mode;
if (Atari800_tv_mode == Atari800_TV_NTSC)
mode_ntsc = mode;
else /* Atari800_tv_mode == Atari800_TV_PAL */
mode_pal = mode;
UpdateMode(old_effect, TRUE);
}
void ARTIFACT_SetTVMode(int tv_mode)
{
ARTIFACT_t old_mode = ARTIFACT_mode;
UpdateFromTVMode(tv_mode);
UpdateMode(old_mode, TRUE);
}
int ARTIFACT_ReadConfig(char *option, char *ptr)
{
if (strcmp(option, "ARTIFACT_NTSC") == 0) {
int i = CFG_MatchTextParameter(ptr, mode_cfg_strings, ARTIFACT_SIZE);
if (i < 0)
return FALSE;
mode_ntsc = (ARTIFACT_t)i;
}
else if (strcmp(option, "ARTIFACT_PAL") == 0) {
int i = CFG_MatchTextParameter(ptr, mode_cfg_strings, ARTIFACT_SIZE);
if (i < 0)
return FALSE;
mode_pal = (ARTIFACT_t)i;
}
else if (strcmp(option, "ARTIFACT_NTSC_MODE") == 0) {
int i = Util_sscandec(ptr);
if (i < 0 || i > 4)
return FALSE;
ANTIC_artif_mode = i;
}
else
return FALSE;
return TRUE;
}
void ARTIFACT_WriteConfig(FILE *fp)
{
fprintf(fp, "ARTIFACT_NTSC=%s\n", mode_cfg_strings[mode_ntsc]);
fprintf(fp, "ARTIFACT_PAL=%s\n", mode_cfg_strings[mode_pal]);
fprintf(fp, "ARTIFACT_NTSC_MODE=%i\n", ANTIC_artif_mode);
}
int ARTIFACT_Initialise(int *argc, char *argv[])
{
int i;
int j;
for (i = j = 1; i < *argc; i++) {
int i_a = (i + 1 < *argc); /* is argument available? */
int a_m = FALSE; /* error, argument missing! */
if (strcmp(argv[i], "-ntsc-artif") == 0) {
if (i_a) {
int idx = CFG_MatchTextParameter(argv[++i], mode_cfg_strings, ARTIFACT_SIZE);
if (idx < 0) {
Log_print("Invalid value for -ntsc-artif");
return FALSE;
}
mode_ntsc = (ARTIFACT_t)idx;
} else a_m = TRUE;
}
else if (strcmp(argv[i], "-pal-artif") == 0) {
if (i_a) {
int idx = CFG_MatchTextParameter(argv[++i], mode_cfg_strings, ARTIFACT_SIZE);
if (idx < 0) {
Log_print("Invalid value for -pal-artif");
return FALSE;
}
mode_pal = (ARTIFACT_t)idx;
} else a_m = TRUE;
}
else {
if (strcmp(argv[i], "-help") == 0) {
Log_print("\t-ntsc-artif none|ntsc-old|ntsc-new|ntsc-full");
Log_print("\t Select video artifacts for NTSC");
Log_print("\t-pal-artif none|pal-simple|pal-accu");
Log_print("\t Select video artifacts for PAL");
}
argv[j++] = argv[i];
}
if (a_m) {
Log_print("Missing argument for '%s'", argv[i]);
return FALSE;
}
}
*argc = j;
/* Assume that Atari800_tv_mode has been already initialised. */
UpdateFromTVMode(Atari800_tv_mode);
UpdateMode(ARTIFACT_NONE, FALSE);
return TRUE;
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef ARTIFACT_H_
#define ARTIFACT_H_
#include <stdio.h>
#include "config.h"
typedef enum ARTIFACT_t {
ARTIFACT_NONE, /* Artifacting disabled */
ARTIFACT_NTSC_OLD, /* Original NTSC artifacting */
ARTIFACT_NTSC_NEW, /* New NTSC artifacting */
#if NTSC_FILTER
ARTIFACT_NTSC_FULL, /* NTSC filter */
#endif /* NTSC_FILTER */
#ifndef NO_SIMPLE_PAL_BLENDING
ARTIFACT_PAL_SIMPLE, /* ANTIC-level simple PAL blending */
#endif /* NO_SIMPLE_PAL_BLENDING */
#ifdef PAL_BLENDING
ARTIFACT_PAL_BLEND, /* Accurate PAL blending */
#endif /* PAL_BLENDING */
ARTIFACT_SIZE
} ARTIFACT_t;
/* The currently used artifact emulation mode. Use ARTIFACT_Set to change this value. */
extern ARTIFACT_t ARTIFACT_mode;
/* Set artifacting mode for the current TV system. */
void ARTIFACT_Set(ARTIFACT_t mode);
/* Call after updating Atari800_tv_mode to update the artifacting mode accordingly. */
void ARTIFACT_SetTVMode(int tv_mode);
/* Read/write to configuration file. */
void ARTIFACT_WriteConfig(FILE *fp);
int ARTIFACT_ReadConfig(char *option, char *ptr);
/* Module initialisation and processing of command-line arguments. */
int ARTIFACT_Initialise(int *argc, char *argv[]);
#endif /* ARTIFACT_H_ */
+1500
View File
File diff suppressed because it is too large Load Diff
+190
View File
@@ -0,0 +1,190 @@
#ifndef ATARI_H_
#define ATARI_H_
#include "config.h"
#include <stdio.h> /* FILENAME_MAX */
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
/* Fundamental declarations ---------------------------------------------- */
#define Atari800_TITLE "Atari 800 Emulator, Version 3.1.0"
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
/* SBYTE and UBYTE must be exactly 1 byte long. */
/* SWORD and UWORD must be exactly 2 bytes long. */
/* SLONG and ULONG must be exactly 4 bytes long. */
#define SBYTE signed char
#define SWORD signed short
#define SLONG signed int
#define UBYTE unsigned char
#define UWORD unsigned short
#ifndef HAVE_WINDOWS_H
/* Windows headers typedef ULONG */
#define ULONG unsigned int
#endif
/* Note: in various parts of the emulator we assume that char is 1 byte
and int is 4 bytes. */
/* Public interface ------------------------------------------------------ */
/* Machine type. */
enum {
Atari800_MACHINE_800,
Atari800_MACHINE_XLXE,
Atari800_MACHINE_5200,
/* Number of values in the emumerator */
Atari800_MACHINE_SIZE
};
/* Don't change this variable directly; use Atari800_SetMachineType() instead. */
extern int Atari800_machine_type;
void Atari800_SetMachineType(int type);
/* Always call Atari800_InitialiseMachine() after changing Atari800_machine_type
or MEMORY_ram_size! */
/* Indicates if machine has BASIC built in. */
extern int Atari800_builtin_basic;
/* Indicates existence of 1200XL's two keyboard LEDs.
Used only for Atari800_MACHINE_XLXE. */
extern int Atari800_keyboard_leds;
/* Indicates existence of F1-F4 keys.
Used only for Atari800_MACHINE_XLXE. */
extern int Atari800_f_keys;
/* State of the J1 jumper on the 1200XL board.
Used only for Atari800_MACHINE_XLXE. Always call
Atari800_UpdateJumper() after changing this variable. */
extern int Atari800_jumper;
void Atari800_UpdateJumper(void);
/* Indicates existence of XEGS' built-in game.
Used only for Atari800_MACHINE_XLXE. */
extern int Atari800_builtin_game;
/* TRUE if the XEGS keyboard is detached.
Used only for Atari800_MACHINE_XLXE. Always call
Atari800_UpdateKeyboardDetached() after changing this variable. */
extern int Atari800_keyboard_detached;
void Atari800_UpdateKeyboardDetached(void);
/* Video system. */
#define Atari800_TV_UNSET 0
#define Atari800_TV_PAL 312
#define Atari800_TV_NTSC 262
#define Atari800_FPS_PAL 49.8607597
/*49.8607597 = (4.43361875*(4/5)*1000000)/(312*228)*/
#define Atari800_FPS_NTSC 59.9227434
/*59.9227434 = (3.579545*1000000)/(262*228)*/
/* Video system / Number of scanlines per frame. Do not set this variable
directly; instead use Atari800_SetTVMode(). */
extern int Atari800_tv_mode;
/* TRUE to disable Atari BASIC when booting Atari (hold Option in XL/XE). */
extern int Atari800_disable_basic;
/* OS ROM version currently used by the emulator. Can be -1 for emuos/missing
ROM, or a value from the SYSROM enumerator. */
extern int Atari800_os_version;
/* If Atari800_Frame() sets it to TRUE, then the current contents
of Screen_atari should be displayed. */
extern int Atari800_display_screen;
/* Simply incremented by Atari800_Frame(). */
extern int Atari800_nframes;
/* How often the screen is updated (1 = every Atari frame). */
extern int Atari800_refresh_rate;
/* If TRUE, will try to maintain the emulation speed to 100% */
extern int Atari800_auto_frameskip;
/* Set to TRUE for faster emulation with Atari800_refresh_rate > 1.
Set to FALSE for accurate emulation with Atari800_refresh_rate > 1. */
extern int Atari800_collisions_in_skipped_frames;
/* Set to TRUE to run emulated Atari as fast as possible */
extern int Atari800_turbo;
/* Initializes Atari800 emulation core. */
int Atari800_Initialise(int *argc, char *argv[]);
/* Emulates one frame (1/50sec for PAL, 1/60sec for NTSC). */
void Atari800_Frame(void);
/* Reboots the emulated Atari. */
void Atari800_Coldstart(void);
/* Presses the Reset key in the emulated Atari. */
void Atari800_Warmstart(void);
/* Reinitializes after Atari800_machine_type or ram_size change.
You should call Atari800_Coldstart() after it. */
int Atari800_InitialiseMachine(void);
/* Shuts down Atari800 emulation core and saves the config file if needed.
* Use it when a user requested exiting/entering a monitor. */
int Atari800_Exit(int run_monitor);
/* Shuts down Atari800 emulation core. Use it for emergency-exiting
such as on failure. */
void Atari800_ErrExit(void);
/* Private interface ----------------------------------------------------- */
/* Don't use outside the emulation core! */
/* STAT_UNALIGNED_WORDS is solely for benchmarking purposes.
8-element arrays (stat_arr) represent number of accesses with the given
value of 3 least significant bits of address. This gives us information
about the ratio of aligned vs unaligned accesses. */
#ifdef STAT_UNALIGNED_WORDS
#define UNALIGNED_STAT_DEF(stat_arr) unsigned int stat_arr[8];
#define UNALIGNED_STAT_DECL(stat_arr) extern unsigned int stat_arr[8];
#define UNALIGNED_GET_WORD(ptr, stat_arr) (stat_arr[(unsigned int) (ptr) & 7]++, *(const UWORD *) (ptr))
#define UNALIGNED_PUT_WORD(ptr, value, stat_arr) (stat_arr[(unsigned int) (ptr) & 7]++, *(UWORD *) (ptr) = (value))
#define UNALIGNED_GET_LONG(ptr, stat_arr) (stat_arr[(unsigned int) (ptr) & 7]++, *(const ULONG *) (ptr))
#define UNALIGNED_PUT_LONG(ptr, value, stat_arr) (stat_arr[(unsigned int) (ptr) & 7]++, *(ULONG *) (ptr) = (value))
UNALIGNED_STAT_DECL(Screen_atari_write_long_stat)
UNALIGNED_STAT_DECL(pm_scanline_read_long_stat)
UNALIGNED_STAT_DECL(memory_read_word_stat)
UNALIGNED_STAT_DECL(memory_write_word_stat)
UNALIGNED_STAT_DECL(memory_read_aligned_word_stat)
UNALIGNED_STAT_DECL(memory_write_aligned_word_stat)
#else
#define UNALIGNED_STAT_DEF(stat_arr)
#define UNALIGNED_STAT_DECL(stat_arr)
#define UNALIGNED_GET_WORD(ptr, stat_arr) (*(const UWORD *) (ptr))
#define UNALIGNED_PUT_WORD(ptr, value, stat_arr) (*(UWORD *) (ptr) = (value))
#define UNALIGNED_GET_LONG(ptr, stat_arr) (*(const ULONG *) (ptr))
#define UNALIGNED_PUT_LONG(ptr, value, stat_arr) (*(ULONG *) (ptr) = (value))
#endif
/* Sleeps until it's time to emulate next Atari frame. */
void Atari800_Sync(void);
/* Load a ROM image filename of size nbytes into buffer */
int Atari800_LoadImage(const char *filename, UBYTE *buffer, int nbytes);
/* Save State */
void Atari800_StateSave(void);
/* Read State */
void Atari800_StateRead(UBYTE version);
/* Change TV mode. */
void Atari800_SetTVMode(int mode);
#endif /* ATARI_H_ */
File diff suppressed because it is too large Load Diff
+64
View File
@@ -0,0 +1,64 @@
/*
* atari_basic.c - Text-only specific port code
*
* Copyright (c) 1995-1998 David Firth
* Copyright (c) 1998-2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "atari.h"
#include "config.h"
#include "monitor.h"
#include "log.h"
#include "platform.h"
#ifdef SOUND
#include "sound.h"
#endif
int PLATFORM_Initialise(int *argc, char *argv[])
{
#ifdef SOUND
if (!Sound_Initialise(argc, argv))
return FALSE;
#endif
return TRUE;
}
int PLATFORM_Exit(int run_monitor)
{
Log_flushlog();
if (run_monitor && MONITOR_Run())
return TRUE;
return FALSE;
}
int main(int argc, char **argv)
{
/* initialise Atari800 core */
if (!Atari800_Initialise(&argc, argv))
return 3;
/* main loop */
while (TRUE) {
Atari800_Frame();
}
}
+868
View File
@@ -0,0 +1,868 @@
/*
* atari_curses.c - Curses based port code
*
* Copyright (c) 1995-1998 David Firth
* Copyright (c) 1998-2014 Atari800 development team (see DOC/CREDITS)
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <string.h>
#ifdef USE_NCURSES
#include <ncurses.h>
#else
#include <curses.h>
#endif
#include "antic.h" /* ypos */
#include "atari.h"
#include "binload.h"
#include "gtia.h" /* GTIA_COLPFx */
#include "input.h"
#include "akey.h"
#include "log.h"
#include "monitor.h"
#include "platform.h"
#include "ui.h" /* UI_alt_function */
#ifdef SOUND
#include "sound.h"
#endif
#define CURSES_LEFT 0
#define CURSES_CENTRAL 1
#define CURSES_RIGHT 2
#define CURSES_WIDE_1 3
#define CURSES_WIDE_2 4
static int curses_mode = CURSES_LEFT;
static int curses_screen[24][40];
int PLATFORM_Initialise(int *argc, char *argv[])
{
int i;
int j;
for (i = j = 1; i < *argc; i++) {
if (strcmp(argv[i], "-left") == 0)
curses_mode = CURSES_LEFT;
else if (strcmp(argv[i], "-central") == 0)
curses_mode = CURSES_CENTRAL;
else if (strcmp(argv[i], "-right") == 0)
curses_mode = CURSES_RIGHT;
else if (strcmp(argv[i], "-wide1") == 0)
curses_mode = CURSES_WIDE_1;
else if (strcmp(argv[i], "-wide2") == 0)
curses_mode = CURSES_WIDE_2;
else {
if (strcmp(argv[i], "-help") == 0) {
Log_print("\t-central Center emulated screen\n"
"\t-left Align left\n"
"\t-right Align right (on 80 columns)\n"
"\t-wide1 Use 80 columns\n"
"\t-wide2 Use 80 columns, display twice"
);
}
argv[j++] = argv[i];
}
}
*argc = j;
initscr();
noecho();
cbreak(); /* Don't wait for carriage return */
keypad(stdscr, TRUE);
curs_set(0); /* Disable Cursor */
nodelay(stdscr, 1); /* Don't block for keypress */
#ifdef SOUND
if (!Sound_Initialise(argc, argv))
return FALSE;
#endif
return TRUE;
}
int PLATFORM_Exit(int run_monitor)
{
curs_set(1);
endwin();
Log_flushlog();
if (run_monitor && MONITOR_Run()) {
curs_set(0);
return TRUE;
}
return FALSE;
}
void curses_clear_screen(void)
{
int x;
int y;
for (y = 0; y < 24; y++)
for (x = 0; x < 40; x++)
curses_screen[y][x] = ' ';
}
void curses_clear_rectangle(int x1, int y1, int x2, int y2)
{
int x;
int y;
for (y = y1; y <= y2; y++)
for (x = x1; x <= x2; x++)
curses_screen[y][x] = ' ';
}
void curses_putch(int x, int y, int ascii, UBYTE fg, UBYTE bg)
{
/* handle line drawing chars */
switch (ascii) {
case 18:
ascii = '-';
break;
case 17:
case 3:
ascii = '/';
break;
case 26:
case 5:
ascii = '\\';
break;
case 124:
ascii = '|';
break;
default:
break;
}
if ((bg & 0xf) > (fg & 0xf))
curses_screen[y][x] = ascii + A_REVERSE;
else
curses_screen[y][x] = ascii;
}
void curses_display_line(int anticmode, const UBYTE *screendata)
{
int y;
int *p;
int w;
if (ANTIC_ypos < 32 || ANTIC_ypos >= 224)
return;
y = (ANTIC_ypos >> 3) - 4;
p = &(curses_screen[y][0]);
switch (anticmode) {
case 2:
case 3:
case 4:
case 5:
switch (ANTIC_DMACTL & 3) {
case 1:
p += 4;
w = 32;
break;
case 2:
w = 40;
break;
case 3:
screendata += 4;
w = 40;
break;
default:
return;
}
do {
static const int offset[8] = {
0x20, /* 0x00-0x1f: Numbers + !"$% etc. */
0x20, /* 0x20-0x3f: Upper Case Characters */
A_BOLD, /* 0x40-0x5f: Control Characters */
0, /* 0x60-0x7f: Lower Case Characters */
-0x80 + 0x20 + A_REVERSE, /* 0x80-0x9f: Numbers + !"$% etc. */
-0x80 + 0x20 + A_REVERSE, /* 0xa0-0xbf: Upper Case Characters */
-0x80 + A_BOLD + A_REVERSE, /* 0xc0-0xdf: Control Characters */
-0x80 + A_REVERSE /* 0xe0-0xff: Lower Case Characters */
};
UBYTE c = *screendata++;
/* PDCurses prints '\x7f' as "^?".
This causes problems if this is the last character in line.
Use bold '>' for Atari's Tab symbol (filled right-pointing triangle). */
if (c == 0x7f)
*p = '>' + A_BOLD;
else if (c == 0xff)
*p = '>' + A_BOLD + A_REVERSE;
else
*p = c + offset[c >> 5];
p++;
} while (--w);
break;
case 6:
case 7:
switch (ANTIC_DMACTL & 3) {
case 1:
p += 12;
w = 16;
break;
case 2:
p += 10;
w = 20;
break;
case 3:
p += 8;
w = 24;
break;
default:
return;
}
{
#define LIGHT_THRESHOLD 0x0c
int light[4];
light[0] = (GTIA_COLPF0 & 0x0e) >= LIGHT_THRESHOLD ? 0x20 + A_BOLD : 0x20;
light[1] = (GTIA_COLPF1 & 0x0e) >= LIGHT_THRESHOLD ? -0x40 + 0x20 + A_BOLD : -0x40 + 0x20;
light[2] = (GTIA_COLPF2 & 0x0e) >= LIGHT_THRESHOLD ? -0x80 + 0x20 + A_BOLD : -0x80 + 0x20;
light[3] = (GTIA_COLPF3 & 0x0e) >= LIGHT_THRESHOLD ? -0xc0 + 0x20 + A_BOLD : -0xc0 + 0x20;
do {
*p++ = *screendata + light[*screendata >> 6];
screendata++;
} while (--w);
}
break;
default:
break;
}
}
void PLATFORM_DisplayScreen(void)
{
int x;
int y;
for (y = 0; y < 24; y++) {
for (x = 0; x < 40; x++) {
int ch = curses_screen[y][x];
switch (curses_mode) {
default:
case CURSES_LEFT:
move(y, x);
break;
case CURSES_CENTRAL:
move(y, 20 + x);
break;
case CURSES_RIGHT:
move(y, 40 + x);
break;
case CURSES_WIDE_1:
move(y, x + x);
break;
case CURSES_WIDE_2:
move(y, x + x);
addch(ch);
ch = ' ' + (ch & A_REVERSE);
break;
}
addch(ch);
}
}
refresh();
}
int PLATFORM_Keyboard(void)
{
int keycode = getch();
#if 0
/* for debugging */
if (keycode > 0) {
Atari800_ErrExit();
printf("keycode == %d (0x%x)\n", keycode, keycode);
exit(1);
}
#endif
BINLOAD_pause_loading = FALSE;
INPUT_key_consol = INPUT_CONSOL_NONE;
switch (keycode) {
case 0x01:
keycode = AKEY_CTRL_a;
break;
case 0x02:
keycode = AKEY_CTRL_b;
break;
case 0x03 :
keycode = AKEY_CTRL_c;
break;
case 0x04:
keycode = AKEY_CTRL_d;
break;
case 0x05:
keycode = AKEY_CTRL_e;
break;
case 0x06:
keycode = AKEY_CTRL_f;
break;
case 0x07:
keycode = AKEY_CTRL_g;
break;
/*
case 0x08:
keycode = AKEY_CTRL_h;
break;
*/
case 0x09:
keycode = AKEY_TAB;
break;
/*
case 0x0a:
keycode = AKEY_CTRL_j;
break;
*/
case 0x0b:
keycode = AKEY_CTRL_k;
break;
case 0x0c:
keycode = AKEY_CTRL_l;
break;
/*
case 0x0d:
keycode = AKEY_CTRL_m;
break;
*/
case 0x0e:
keycode = AKEY_CTRL_n;
break;
case 0x0f:
keycode = AKEY_CTRL_o;
break;
case 0x10:
keycode = AKEY_CTRL_p;
break;
case 0x11:
keycode = AKEY_CTRL_q;
break;
case 0x12:
keycode = AKEY_CTRL_r;
break;
case 0x13:
keycode = AKEY_CTRL_s;
break;
case 0x14:
keycode = AKEY_CTRL_t;
break;
case 0x15:
keycode = AKEY_CTRL_u;
break;
case 0x16:
keycode = AKEY_CTRL_v;
break;
case 0x17:
keycode = AKEY_CTRL_w;
break;
case 0x18:
keycode = AKEY_CTRL_x;
break;
case 0x19:
keycode = AKEY_CTRL_y;
break;
case 0x1a:
keycode = AKEY_CTRL_z;
break;
case '`':
keycode = AKEY_CAPSTOGGLE;
break;
case '!':
keycode = AKEY_EXCLAMATION;
break;
case '"':
keycode = AKEY_DBLQUOTE;
break;
case '#':
keycode = AKEY_HASH;
break;
case '$':
keycode = AKEY_DOLLAR;
break;
case '%':
keycode = AKEY_PERCENT;
break;
case '&':
keycode = AKEY_AMPERSAND;
break;
case '\'':
keycode = AKEY_QUOTE;
break;
case '@':
keycode = AKEY_AT;
break;
case '(':
keycode = AKEY_PARENLEFT;
break;
case ')':
keycode = AKEY_PARENRIGHT;
break;
case '[':
keycode = AKEY_BRACKETLEFT;
break;
case ']':
keycode = AKEY_BRACKETRIGHT;
break;
case '<':
keycode = AKEY_LESS;
break;
case '>':
keycode = AKEY_GREATER;
break;
case '=':
keycode = AKEY_EQUAL;
break;
case '?':
keycode = AKEY_QUESTION;
break;
#ifdef PADMINUS
case PADMINUS:
#endif
case '-':
keycode = AKEY_MINUS;
break;
#ifdef PADPLUS
case PADPLUS:
#endif
case '+':
keycode = AKEY_PLUS;
break;
#ifdef PADSTAR
case PADSTAR:
#endif
case '*':
keycode = AKEY_ASTERISK;
break;
#ifdef PADSLASH
case PADSLASH:
#endif
case '/':
keycode = AKEY_SLASH;
break;
case ':':
keycode = AKEY_COLON;
break;
case ';':
keycode = AKEY_SEMICOLON;
break;
case ',':
keycode = AKEY_COMMA;
break;
case '.':
keycode = AKEY_FULLSTOP;
break;
case '_':
keycode = AKEY_UNDERSCORE;
break;
case '^':
keycode = AKEY_CIRCUMFLEX;
break;
case '\\':
keycode = AKEY_BACKSLASH;
break;
case '|':
keycode = AKEY_BAR;
break;
case ' ':
keycode = AKEY_SPACE;
break;
case '0':
keycode = AKEY_0;
break;
case '1':
keycode = AKEY_1;
break;
case '2':
keycode = AKEY_2;
break;
case '3':
keycode = AKEY_3;
break;
case '4':
keycode = AKEY_4;
break;
case '5':
keycode = AKEY_5;
break;
case '6':
keycode = AKEY_6;
break;
case '7':
keycode = AKEY_7;
break;
case '8':
keycode = AKEY_8;
break;
case '9':
keycode = AKEY_9;
break;
case 'a':
keycode = AKEY_a;
break;
case 'b':
keycode = AKEY_b;
break;
case 'c':
keycode = AKEY_c;
break;
case 'd':
keycode = AKEY_d;
break;
case 'e':
keycode = AKEY_e;
break;
case 'f':
keycode = AKEY_f;
break;
case 'g':
keycode = AKEY_g;
break;
case 'h':
keycode = AKEY_h;
break;
case 'i':
keycode = AKEY_i;
break;
case 'j':
keycode = AKEY_j;
break;
case 'k':
keycode = AKEY_k;
break;
case 'l':
keycode = AKEY_l;
break;
case 'm':
keycode = AKEY_m;
break;
case 'n':
keycode = AKEY_n;
break;
case 'o':
keycode = AKEY_o;
break;
case 'p':
keycode = AKEY_p;
break;
case 'q':
keycode = AKEY_q;
break;
case 'r':
keycode = AKEY_r;
break;
case 's':
keycode = AKEY_s;
break;
case 't':
keycode = AKEY_t;
break;
case 'u':
keycode = AKEY_u;
break;
case 'v':
keycode = AKEY_v;
break;
case 'w':
keycode = AKEY_w;
break;
case 'x':
keycode = AKEY_x;
break;
case 'y':
keycode = AKEY_y;
break;
case 'z':
keycode = AKEY_z;
break;
case 'A':
keycode = AKEY_A;
break;
case 'B':
keycode = AKEY_B;
break;
case 'C':
keycode = AKEY_C;
break;
case 'D':
keycode = AKEY_D;
break;
case 'E':
keycode = AKEY_E;
break;
case 'F':
keycode = AKEY_F;
break;
case 'G':
keycode = AKEY_G;
break;
case 'H':
keycode = AKEY_H;
break;
case 'I':
keycode = AKEY_I;
break;
case 'J':
keycode = AKEY_J;
break;
case 'K':
keycode = AKEY_K;
break;
case 'L':
keycode = AKEY_L;
break;
case 'M':
keycode = AKEY_M;
break;
case 'N':
keycode = AKEY_N;
break;
case 'O':
keycode = AKEY_O;
break;
case 'P':
keycode = AKEY_P;
break;
case 'Q':
keycode = AKEY_Q;
break;
case 'R':
keycode = AKEY_R;
break;
case 'S':
keycode = AKEY_S;
break;
case 'T':
keycode = AKEY_T;
break;
case 'U':
keycode = AKEY_U;
break;
case 'V':
keycode = AKEY_V;
break;
case 'W':
keycode = AKEY_W;
break;
case 'X':
keycode = AKEY_X;
break;
case 'Y':
keycode = AKEY_Y;
break;
case 'Z':
keycode = AKEY_Z;
break;
case 0x1b:
keycode = AKEY_ESCAPE;
break;
case KEY_F0 + 1:
keycode = AKEY_UI;
break;
case KEY_F0 + 2:
INPUT_key_consol &= ~INPUT_CONSOL_OPTION;
keycode = AKEY_NONE;
break;
case KEY_F0 + 3:
INPUT_key_consol &= ~INPUT_CONSOL_SELECT;
keycode = AKEY_NONE;
break;
case KEY_F0 + 4:
INPUT_key_consol &= ~INPUT_CONSOL_START;
keycode = AKEY_NONE;
break;
case KEY_F0 + 5:
keycode = AKEY_WARMSTART;
break;
#ifdef KEY_HELP
case KEY_HELP:
#endif
#ifdef KEY_SHELP
case KEY_SHELP:
#endif
#ifdef KEY_LHELP
case KEY_LHELP:
#endif
case KEY_F0 + 6:
keycode = AKEY_HELP;
break;
#ifdef KEY_BREAK
case KEY_BREAK:
#endif
case KEY_F0 + 7:
if (BINLOAD_wait_active) {
BINLOAD_pause_loading = TRUE;
keycode = AKEY_NONE;
}
else
keycode = AKEY_BREAK;
break;
case KEY_F0 + 8:
keycode = PLATFORM_Exit(TRUE) ? AKEY_NONE : AKEY_EXIT;
break;
case KEY_F0 + 9:
keycode = AKEY_EXIT;
break;
case KEY_F0 + 10:
keycode = AKEY_SCREENSHOT;
break;
case KEY_DOWN:
keycode = AKEY_DOWN;
break;
case KEY_LEFT:
keycode = AKEY_LEFT;
break;
case KEY_RIGHT:
keycode = AKEY_RIGHT;
break;
case KEY_UP:
keycode = AKEY_UP;
break;
case 8:
case 127:
#ifdef KEY_BACKSPACE
# if KEY_BACKSPACE != 8 && KEY_BACKSPACE != 127
case KEY_BACKSPACE:
# endif
#endif
keycode = AKEY_BACKSPACE;
break;
#ifdef PADENTER
case PADENTER:
#endif
case KEY_ENTER:
case '\n':
keycode = AKEY_RETURN;
break;
#ifdef KEY_HOME
case KEY_HOME:
keycode = AKEY_CLEAR;
break;
#endif
#ifdef KEY_CLEAR
case KEY_CLEAR:
keycode = AKEY_CLEAR;
break;
#endif
#ifdef KEY_IC
case KEY_IC:
keycode = AKEY_INSERT_CHAR;
break;
#endif
#ifdef KEY_IL
case KEY_IL:
keycode = AKEY_INSERT_LINE;
break;
#endif
#ifdef KEY_DC
case KEY_DC:
keycode = AKEY_DELETE_CHAR;
break;
#endif
#ifdef KEY_DL
case KEY_DL:
keycode = AKEY_DELETE_LINE;
break;
#endif
#ifdef KEY_STAB
case KEY_STAB:
keycode = AKEY_SETTAB;
break;
#endif
#ifdef KEY_CTAB
case KEY_CTAB:
keycode = AKEY_CLRTAB;
break;
#endif
#ifdef ALT_A
/* PDCurses specific */
case ALT_A:
UI_alt_function = UI_MENU_ABOUT;
keycode = AKEY_UI;
break;
case ALT_C:
UI_alt_function = UI_MENU_CARTRIDGE;
keycode = AKEY_UI;
break;
case ALT_D:
UI_alt_function = UI_MENU_DISK;
keycode = AKEY_UI;
break;
case ALT_L:
UI_alt_function = UI_MENU_LOADSTATE;
keycode = AKEY_UI;
break;
case ALT_O:
UI_alt_function = UI_MENU_SOUND;
keycode = AKEY_UI;
break;
case ALT_R:
UI_alt_function = UI_MENU_RUN;
keycode = AKEY_UI;
break;
case ALT_S:
UI_alt_function = UI_MENU_SAVESTATE;
keycode = AKEY_UI;
break;
case ALT_T:
UI_alt_function = UI_MENU_CASSETTE;
keycode = AKEY_UI;
break;
case ALT_W:
UI_alt_function = UI_MENU_SOUND_RECORDING;
keycode = AKEY_UI;
break;
case ALT_Y:
UI_alt_function = UI_MENU_SYSTEM;
keycode = AKEY_UI;
break;
#endif
default:
keycode = AKEY_NONE;
break;
}
return keycode;
}
int PLATFORM_PORT(int num)
{
return 0xff;
}
int PLATFORM_TRIG(int num)
{
return 1;
}
int main(int argc, char **argv)
{
/* initialise Atari800 core */
if (!Atari800_Initialise(&argc, argv))
return 3;
/* main loop */
for (;;) {
INPUT_key_code = PLATFORM_Keyboard();
Atari800_Frame();
if (Atari800_display_screen)
PLATFORM_DisplayScreen();
}
}
File diff suppressed because it is too large Load Diff
+392
View File
@@ -0,0 +1,392 @@
/* Based on nes_ntsc 0.2.2. http://www.slack.net/~ant/ */
#include "colours.h"
#include "atari_ntsc.h"
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
/* Atari change: removal and addition of structure fields.
Values of resolution and sharpness adjusted to make NTSC artifacts look better. */
atari_ntsc_setup_t const atari_ntsc_monochrome = { 0, -1, 0, 0, -.3, .3, .2, -.2, -.2, -1, 0, 0, 0, 0. };
atari_ntsc_setup_t const atari_ntsc_composite = { 0, 0, 0, 0, -.5, .3, -.1, 0, 0, 0, 0, 0, 0, 0. };
atari_ntsc_setup_t const atari_ntsc_svideo = { 0, 0, 0, 0, -.3, .3, .2, -1, -1, 0, 0, 0, 0, 0. };
atari_ntsc_setup_t const atari_ntsc_rgb = { 0, 0, 0, 0, -.3, .3, .7, -1, -1, -1, 0, 0, 0, 0. };
#define alignment_count 4
#define burst_count 1
#define rescale_in 8
#define rescale_out 7
#define artifacts_mid 1.0f
#define fringing_mid 1.0f
/* Atari change: default palette is already at correct hue.
#define std_decoder_hue -15 */
#define std_decoder_hue 0
/* Atari change: only one palette - remove base_palete field. */
#define STD_HUE_CONDITION( setup ) !(setup->palette)
#include "atari_ntsc_impl.h"
/* Atari change: adapted to 4/7 pixel ratio. */
/* 4 input pixels -> 8 composite samples */
pixel_info_t const atari_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -6, -6 ), { 0, 0, 1, 1 } },
{ PIXEL_OFFSET( -4, -4 ), { 0, 0, 1, 1 } },
{ PIXEL_OFFSET( -2, -2 ), { 0, 0, 1, 1 } },
{ PIXEL_OFFSET( 0, 0 ), { 0, 0, 1, 1 } },
};
/* Atari change: no alternating burst phases - removed merge_kernel_fields function. */
static void correct_errors( atari_ntsc_rgb_t color, atari_ntsc_rgb_t* out )
{
int n;
for ( n = burst_count; n; --n )
{
unsigned i;
for ( i = 0; i < rgb_kernel_size / 2; i++ )
{
/* Atari change: adapted to 4/7 pixel ratio */
atari_ntsc_rgb_t error = color -
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] - out[(i+8)%14+42] -
out [i + 7] - out [i + 5 +14] - out [i + 3 +28] - out [ i+1 +42];
DISTRIBUTE_ERROR( i+1+42, i+3+28, i+5+14, i+7 );
}
out += alignment_count * rgb_kernel_size;
}
}
void atari_ntsc_init( atari_ntsc_t* ntsc, atari_ntsc_setup_t const* setup )
{
/* Atari change: no alternating burst phases - remove merge_fields variable. */
int entry;
init_t impl;
/* Atari change: NES palette generation and reading removed.
Atari palette generation is located in colours_ntsc.c, and colours are read
from setup->yiq_palette. */
if ( !setup )
setup = &atari_ntsc_composite;
init( &impl, setup );
/* Atari change: no alternating burst phases - remove code for merge_fields. */
for ( entry = 0; entry < atari_ntsc_palette_size; entry++ )
{
/* Atari change: Instead of palette generation, load colours
from setup->yiq_palette. */
double y;
double i;
double q;
{
double *yiq_ptr = setup->yiq_palette + 3 * entry;
y = *yiq_ptr++;
i = *yiq_ptr++;
q = *yiq_ptr++;
}
/* Atari change: Convert from CRT TV gamma correction to the sRGB
gamma correction. */
if (setup->gamma >= 0.0)
{
double r, g, b = YIQ_TO_RGB( y, i, q, default_decoder, double, r, g );
r = Colours_Gamma2Linear(r, setup->gamma);
g = Colours_Gamma2Linear(g, setup->gamma);
b = Colours_Gamma2Linear(b, setup->gamma);
r = Colours_Linear2sRGB(r);
g = Colours_Linear2sRGB(g);
b = Colours_Linear2sRGB(b);
q = RGB_TO_YIQ( r, g, b, y, i );
}
i *= rgb_unit;
q *= rgb_unit;
y *= rgb_unit;
y += rgb_offset;
/* Generate kernel */
{
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
/* blue tends to overflow, so clamp it */
atari_ntsc_rgb_t rgb = PACK_RGB( r, g, (b < 0x3E0 ? b: 0x3E0) );
if ( setup->palette_out )
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
if ( ntsc )
{
atari_ntsc_rgb_t* kernel = ntsc->table [entry];
gen_kernel( &impl, y, i, q, kernel );
/* Atari change: no alternating burst phases - remove code for merge_fields. */
correct_errors( rgb, kernel );
}
}
}
}
#ifndef ATARI_NTSC_NO_BLITTERS
/* Atari change: no alternating burst phases - remove burst_phase parameter.
Also removed the atari_ntsc_blit function and added specific blitters for various
pixel formats. */
#include <limits.h>
#if USHRT_MAX == 0xFFFF
typedef unsigned short atari_ntsc_out16_t;
#else
#error "Need 16-bit int type"
#endif
#if UINT_MAX == 0xFFFFFFFF
typedef unsigned int atari_ntsc_out32_t;
#elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long atari_ntsc_out32_t;
#else
#error "Need 32-bit int type"
#endif
void atari_ntsc_blit_rgb16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* input, long in_row_width,
int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
ATARI_NTSC_IN_T const* line_in = input;
/* Atari change: no alternating burst phases - remove burst_phase parameter; adjust to 4/7 pixel ratio. */
ATARI_NTSC_BEGIN_ROW( ntsc,
atari_ntsc_black, atari_ntsc_black, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *line_in ) );
atari_ntsc_out16_t* restrict line_out = (atari_ntsc_out16_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
ATARI_NTSC_COLOR_IN( 0, ATARI_NTSC_ADJ_IN( line_in [0] ) );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 1, ATARI_NTSC_ADJ_IN( line_in [1] ) );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 2, ATARI_NTSC_ADJ_IN( line_in [2] ) );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 3, ATARI_NTSC_ADJ_IN( line_in [3] ) );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_RGB16 );
line_in += 4;
line_out += 7;
}
/* finish final pixels */
ATARI_NTSC_COLOR_IN( 0, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 1, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 2, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_RGB16 );
ATARI_NTSC_COLOR_IN( 3, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_RGB16 );
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void atari_ntsc_blit_bgr16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* input, long in_row_width,
int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
ATARI_NTSC_IN_T const* line_in = input;
/* Atari change: no alternating burst phases - remove burst_phase parameter; adjust to 4/7 pixel ratio. */
ATARI_NTSC_BEGIN_ROW( ntsc,
atari_ntsc_black, atari_ntsc_black, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *line_in ) );
atari_ntsc_out16_t* restrict line_out = (atari_ntsc_out16_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
ATARI_NTSC_COLOR_IN( 0, ATARI_NTSC_ADJ_IN( line_in [0] ) );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 1, ATARI_NTSC_ADJ_IN( line_in [1] ) );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 2, ATARI_NTSC_ADJ_IN( line_in [2] ) );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 3, ATARI_NTSC_ADJ_IN( line_in [3] ) );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_BGR16 );
line_in += 4;
line_out += 7;
}
/* finish final pixels */
ATARI_NTSC_COLOR_IN( 0, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 1, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 2, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_BGR16 );
ATARI_NTSC_COLOR_IN( 3, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_BGR16 );
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void atari_ntsc_blit_argb32( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* input, long in_row_width,
int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
ATARI_NTSC_IN_T const* line_in = input;
/* Atari change: no alternating burst phases - remove burst_phase parameter; adjust to 4/7 pixel ratio. */
ATARI_NTSC_BEGIN_ROW( ntsc,
atari_ntsc_black, atari_ntsc_black, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *line_in ) );
atari_ntsc_out32_t* restrict line_out = (atari_ntsc_out32_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
ATARI_NTSC_COLOR_IN( 0, ATARI_NTSC_ADJ_IN( line_in [0] ) );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 1, ATARI_NTSC_ADJ_IN( line_in [1] ) );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 2, ATARI_NTSC_ADJ_IN( line_in [2] ) );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 3, ATARI_NTSC_ADJ_IN( line_in [3] ) );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_ARGB32 );
line_in += 4;
line_out += 7;
}
/* finish final pixels */
ATARI_NTSC_COLOR_IN( 0, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 1, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 2, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_ARGB32 );
ATARI_NTSC_COLOR_IN( 3, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_ARGB32 );
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void atari_ntsc_blit_bgra32( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* input, long in_row_width,
int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
ATARI_NTSC_IN_T const* line_in = input;
/* Atari change: no alternating burst phases - remove burst_phase parameter; adjust to 4/7 pixel ratio. */
ATARI_NTSC_BEGIN_ROW( ntsc,
atari_ntsc_black, atari_ntsc_black, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *line_in ) );
atari_ntsc_out32_t* restrict line_out = (atari_ntsc_out32_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
ATARI_NTSC_COLOR_IN( 0, ATARI_NTSC_ADJ_IN( line_in [0] ) );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 1, ATARI_NTSC_ADJ_IN( line_in [1] ) );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 2, ATARI_NTSC_ADJ_IN( line_in [2] ) );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 3, ATARI_NTSC_ADJ_IN( line_in [3] ) );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_BGRA32 );
line_in += 4;
line_out += 7;
}
/* finish final pixels */
ATARI_NTSC_COLOR_IN( 0, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 0, line_out [0], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 1, line_out [1], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 1, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 2, line_out [2], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 3, line_out [3], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 2, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 4, line_out [4], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_RGB_OUT( 5, line_out [5], ATARI_NTSC_RGB_FORMAT_BGRA32 );
ATARI_NTSC_COLOR_IN( 3, atari_ntsc_black );
ATARI_NTSC_RGB_OUT( 6, line_out [6], ATARI_NTSC_RGB_FORMAT_BGRA32 );
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
#endif
+229
View File
@@ -0,0 +1,229 @@
/* Atari TIA, CTIA, GTIA and MARIA NTSC video filter */
/* based on nes_ntsc 0.2.2 */
#ifndef ATARI_NTSC_H
#define ATARI_NTSC_H
#include "atari_ntsc_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
in parenthesis and should remain fairly stable in future versions. */
typedef struct atari_ntsc_setup_t
{
/* Basic parameters */
double hue; /* -1 = -180 degrees +1 = +180 degrees */
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
double sharpness; /* edge contrast enhancement/blurring */
/* Advanced parameters */
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
double resolution; /* image resolution */
double artifacts; /* artifacts caused by color changes */
double fringing; /* color artifacts caused by brightness changes */
double bleed; /* color bleed (color resolution reduction) */
/* Atari change: no alternating burst phases - remove merge_fields field. */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
/* You can replace the standard NES color generation with an RGB palette. The
first replaces all color generation, while the second replaces only the core
64-color generation and does standard color emphasis calculations on it. */
unsigned char const* palette;/* optional 256-entry RGB palette in, 3 bytes per color */
/* Atari change: only one palette - remove base_palette field. */
/* Atari change: additional setup fields */
double burst_phase; /* Phase at which colorburst signal is turned on;
this defines colors of artifacts.
In radians; -1.0 = -180 degrees, 1.0 = +180 degrees */
double *yiq_palette;
} atari_ntsc_setup_t;
/* Video format presets */
extern atari_ntsc_setup_t const atari_ntsc_composite; /* color bleeding + artifacts */
extern atari_ntsc_setup_t const atari_ntsc_svideo; /* color bleeding only */
extern atari_ntsc_setup_t const atari_ntsc_rgb; /* crisp image */
extern atari_ntsc_setup_t const atari_ntsc_monochrome;/* desaturated + artifacts */
enum { atari_ntsc_palette_size = 256 };
/* Initializes and adjusts parameters. Can be called multiple times on the same
atari_ntsc_t object. Can pass NULL for either parameter. */
typedef struct atari_ntsc_t atari_ntsc_t;
void atari_ntsc_init( atari_ntsc_t* ntsc, atari_ntsc_setup_t const* setup );
/* Filters one or more rows of pixels. Input pixels are 6/9-bit palette indicies.
In_row_width is the number of pixels to get to the next input row. Out_pitch
is the number of *bytes* to get to the next output row. Output pixel format
is set by ATARI_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */
/* Atari change: no alternating burst phases - remove burst_phase parameter.
Also removed the atari_ntsc_blit function and added specific blitters for various
pixel formats. */
void atari_ntsc_blit_rgb16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
long in_row_width, int in_width, int in_height,
void* rgb_out, long out_pitch );
void atari_ntsc_blit_bgr16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
long in_row_width, int in_width, int in_height,
void* rgb_out, long out_pitch );
void atari_ntsc_blit_argb32( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
long in_row_width, int in_width, int in_height,
void* rgb_out, long out_pitch );
void atari_ntsc_blit_bgra32( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
long in_row_width, int in_width, int in_height,
void* rgb_out, long out_pitch );
/* Number of output pixels written by blitter for given input width. Width might
be rounded down slightly; use ATARI_NTSC_IN_WIDTH() on result to find rounded
value. Guaranteed not to round 256 down at all. */
#define ATARI_NTSC_OUT_WIDTH( in_width ) \
((((in_width) - 1) / atari_ntsc_in_chunk + 1)* atari_ntsc_out_chunk)
/* Number of input pixels that will fit within given output width. Might be
rounded down slightly; use ATARI_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define ATARI_NTSC_IN_WIDTH( out_width ) \
(((out_width) / atari_ntsc_out_chunk - 1) * atari_ntsc_in_chunk + 1)
/* Interface for user-defined custom blitters. */
enum { atari_ntsc_in_chunk = 4 }; /* number of input pixels read per chunk */
enum { atari_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
enum { atari_ntsc_black = 0 }; /* palette index for black */
enum { atari_ntsc_burst_count = 1 }; /* burst phase cycles through 0, 1, and 2 */
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
Use nes_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */
/* Atari change: no alternating burst phases; adapted to 4/7 pixel ratio. */
#define ATARI_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1, pixel2, pixel3 ) \
char const* const ktable = \
(char const*) (ntsc)->table [0];\
ATARI_NTSC_BEGIN_ROW_8_( pixel0, pixel1, pixel2, pixel3, ATARI_NTSC_ENTRY_, ktable )
/* Begins input pixel */
#define ATARI_NTSC_COLOR_IN( in_index, color_in ) \
ATARI_NTSC_COLOR_IN_( in_index, color_in, ATARI_NTSC_ENTRY_, ktable )
/* Generates output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0:
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define ATARI_NTSC_RGB_OUT( index, rgb_out, bits ) \
ATARI_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 )
/* private */
enum { atari_ntsc_entry_size = 56 };
typedef unsigned long atari_ntsc_rgb_t;
struct atari_ntsc_t {
atari_ntsc_rgb_t table [atari_ntsc_palette_size] [atari_ntsc_entry_size];
};
enum { atari_ntsc_burst_size = atari_ntsc_entry_size / atari_ntsc_burst_count };
#define ATARI_NTSC_ENTRY_( ktable, n ) \
(atari_ntsc_rgb_t const*) (ktable + (n) * (atari_ntsc_entry_size * sizeof (atari_ntsc_rgb_t)))
/* deprecated */
#define ATARI_NTSC_RGB24_OUT( x, out ) ATARI_NTSC_RGB_OUT( x, out, 24 )
#define ATARI_NTSC_RGB16_OUT( x, out ) ATARI_NTSC_RGB_OUT( x, out, 16 )
#define ATARI_NTSC_RGB15_OUT( x, out ) ATARI_NTSC_RGB_OUT( x, out, 15 )
#define ATARI_NTSC_RAW_OUT( x, out ) ATARI_NTSC_RGB_OUT( x, out, 0 )
enum { atari_ntsc_min_in_width = 320 }; /* minimum width that doesn't cut off active area */
enum { atari_ntsc_min_out_width = ATARI_NTSC_OUT_WIDTH( atari_ntsc_min_in_width ) };
enum { atari_ntsc_640_in_width = 336 }; /* room for 8-pixel left & right overscan borders */
enum { atari_ntsc_640_out_width = ATARI_NTSC_OUT_WIDTH( atari_ntsc_640_in_width ) };
enum { atari_ntsc_640_overscan_left = 8 };
enum { atari_ntsc_640_overscan_right = atari_ntsc_640_in_width - atari_ntsc_min_in_width - atari_ntsc_640_overscan_left };
enum { atari_ntsc_full_in_width = 384 }; /* room for full overscan */
enum { atari_ntsc_full_out_width = ATARI_NTSC_OUT_WIDTH( atari_ntsc_full_in_width ) };
enum { atari_ntsc_full_overscan_left = 32 };
enum { atari_ntsc_full_overscan_right = atari_ntsc_full_in_width - atari_ntsc_min_in_width - atari_ntsc_full_overscan_left };
/* common 4->7 ntsc macros */
/* Atari change: adapted to 4/7 pixel ratio. */
#define ATARI_NTSC_BEGIN_ROW_8_( pixel0, pixel1, pixel2, pixel3, ENTRY, table ) \
unsigned const atari_ntsc_pixel0_ = (pixel0);\
atari_ntsc_rgb_t const* kernel0 = ENTRY( table, atari_ntsc_pixel0_ );\
unsigned const atari_ntsc_pixel1_ = (pixel1);\
atari_ntsc_rgb_t const* kernel1 = ENTRY( table, atari_ntsc_pixel1_ );\
unsigned const atari_ntsc_pixel2_ = (pixel2);\
atari_ntsc_rgb_t const* kernel2 = ENTRY( table, atari_ntsc_pixel2_ );\
unsigned const atari_ntsc_pixel3_ = (pixel3);\
atari_ntsc_rgb_t const* kernel3 = ENTRY( table, atari_ntsc_pixel3_ );\
atari_ntsc_rgb_t const* kernelx0;\
atari_ntsc_rgb_t const* kernelx1 = kernel0;\
atari_ntsc_rgb_t const* kernelx2 = kernel0;\
atari_ntsc_rgb_t const* kernelx3 = kernel0
/* Atari change: adapted to 4/7 pixel ratio. */
#define ATARI_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
atari_ntsc_rgb_t raw_ =\
kernel0 [x ] + kernel1 [(x+5)%7+14] + kernel2 [(x+3)%7+28] + kernel3 [(x+1)%7+42] +\
kernelx0 [(x+7)%14] + kernelx1 [(x+5)%7+21] + kernelx2 [(x+3)%7+35] + kernelx3 [(x+1)%7+49];\
ATARI_NTSC_CLAMP_( raw_, shift );\
ATARI_NTSC_RGB_OUT_( rgb_out, bits, shift );\
}
/* common ntsc macros */
#define atari_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define atari_ntsc_clamp_mask (atari_ntsc_rgb_builder * 3 / 2)
#define atari_ntsc_clamp_add (atari_ntsc_rgb_builder * 0x101)
#define ATARI_NTSC_CLAMP_( io, shift ) {\
atari_ntsc_rgb_t sub = (io) >> (9-(shift)) & atari_ntsc_clamp_mask;\
atari_ntsc_rgb_t clamp = atari_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define ATARI_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\
kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
}
/* Atari change: modified ATARI_NTSC_RGB_OUT_ so its BITS parameter is
no longer a straight number of bits, but an enumerated value. Then
added a few additional bit formats. Also added the ATARI_NTSC_RGB_FORMAT
enumerated values. */
enum {
ATARI_NTSC_RGB_FORMAT_RGB16,
ATARI_NTSC_RGB_FORMAT_BGR16,
ATARI_NTSC_RGB_FORMAT_ARGB32,
ATARI_NTSC_RGB_FORMAT_BGRA32,
ATARI_NTSC_RGB_FORMAT_RGB15
};
/* x is always zero except in snes_ntsc library */
#define ATARI_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == ATARI_NTSC_RGB_FORMAT_RGB16 )\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
else if ( bits == ATARI_NTSC_RGB_FORMAT_BGR16 )\
rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(8-x)&0x07E0)|(raw_<<(7+x)&0xF800);\
else if ( bits == ATARI_NTSC_RGB_FORMAT_ARGB32 )\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF) | 0xFF000000;\
else if ( bits == ATARI_NTSC_RGB_FORMAT_BGRA32 )\
rgb_out = (raw_>>(13-x)&0xFF00)|(raw_<<(5+x)&0xFF0000)|(raw_<<(23+x)&0xFF000000) | 0xFF;\
else if ( bits == ATARI_NTSC_RGB_FORMAT_RGB15 )\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
else if ( bits == 0 )\
rgb_out = raw_ << x;\
}
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,25 @@
/* Configure library by modifying this file */
#ifndef ATARI_NTSC_CONFIG_H
#define ATARI_NTSC_CONFIG_H
/* Atari change: remove NES-specific emphasis support */
/* The following affect the built-in blitter only; a custom blitter can
handle things however it wants. */
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
#define ATARI_NTSC_OUT_DEPTH 16
/* Type of input pixel values. You'll probably use unsigned short
if you enable emphasis above. */
#define ATARI_NTSC_IN_T unsigned char
/* Each raw pixel input value is passed through this. You might want to mask
the pixel index if you use the high bits as flags, etc. */
#define ATARI_NTSC_ADJ_IN( in ) in
/* For each pixel, this is the basic operation:
output_color = color_palette [ATARI_NTSC_ADJ_IN( ATARI_NTSC_IN_T )] */
#endif
+455
View File
@@ -0,0 +1,455 @@
/* Based on nes_ntsc 0.2.2. http://www.slack.net/~ant/ */
/* Common implementation of NTSC filters */
#include <assert.h>
#include <math.h>
/* Copyright (C) 2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define DISABLE_CORRECTION 0
#undef PI
#define PI 3.14159265358979323846f
#ifndef LUMA_CUTOFF
#define LUMA_CUTOFF 0.20
#endif
#ifndef gamma_size
#define gamma_size 1
#endif
#ifndef rgb_bits
#define rgb_bits 8
#endif
#ifndef artifacts_max
#define artifacts_max (artifacts_mid * 1.5f)
#endif
#ifndef fringing_max
#define fringing_max (fringing_mid * 2)
#endif
#ifndef STD_HUE_CONDITION
#define STD_HUE_CONDITION( setup ) 1
#endif
#define ext_decoder_hue (std_decoder_hue + 15)
#define rgb_unit (1 << rgb_bits)
#define rgb_offset (rgb_unit * 2 + 0.5f)
enum { burst_size = atari_ntsc_entry_size / burst_count };
enum { kernel_half = 16 };
enum { kernel_size = kernel_half * 2 + 1 };
typedef struct init_t
{
float to_rgb [burst_count * 6];
float to_float [gamma_size];
float contrast;
float brightness;
float artifacts;
float fringing;
float kernel [rescale_out * kernel_size * 2];
} init_t;
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
float t;\
t = i * cos_b - q * sin_b;\
q = i * sin_b + q * cos_b;\
i = t;\
}
static void init_filters( init_t* impl, atari_ntsc_setup_t const* setup )
{
#if rescale_out > 1
float kernels [kernel_size * 2];
#else
float* const kernels = impl->kernel;
#endif
/* generate luma (y) filter using sinc kernel */
{
/* sinc with rolloff (dsf) */
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
float const maxh = 32;
float const pow_a_n = (float) pow( rolloff, maxh );
float sum;
int i;
/* quadratic mapping to reduce negative (blurring) range */
float to_angle = (float) setup->resolution + 1;
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = i - kernel_half;
float angle = x * to_angle;
/* instability occurs at center point with rolloff very close to 1.0 */
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
{
float rolloff_cos_a = rolloff * (float) cos( angle );
float num = 1 - rolloff_cos_a -
pow_a_n * (float) cos( maxh * angle ) +
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
float dsf = num / den;
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
}
}
/* apply blackman window and find sum */
sum = 0;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
float x = PI * 2 / (kernel_half * 2) * i;
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
}
/* normalize kernel */
sum = 1.0f / sum;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = kernel_size * 3 / 2 - kernel_half + i;
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
/* generate chroma (iq) filter using gaussian kernel */
{
float const cutoff_factor = -0.03125f;
float cutoff = (float) setup->bleed;
int i;
if ( cutoff < 0 )
{
/* keep extreme value accessible only near upper end of scale (1.0) */
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= -30.0f / 0.65f;
}
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
for ( i = -kernel_half; i <= kernel_half; i++ )
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
/* normalize even and odd phases separately */
for ( i = 0; i < 2; i++ )
{
float sum = 0;
int x;
for ( x = i; x < kernel_size; x += 2 )
sum += kernels [x];
sum = 1.0f / sum;
for ( x = i; x < kernel_size; x += 2 )
{
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
}
/*
printf( "luma:\n" );
for ( i = kernel_size; i < kernel_size * 2; i++ )
printf( "%f\n", kernels [i] );
printf( "chroma:\n" );
for ( i = 0; i < kernel_size; i++ )
printf( "%f\n", kernels [i] );
*/
/* generate linear rescale kernels */
#if rescale_out > 1
{
float weight = 1.0f;
float* out = impl->kernel;
int n = rescale_out;
do
{
float remain = 0;
int i;
weight -= 1.0f / rescale_in;
for ( i = 0; i < kernel_size * 2; i++ )
{
float cur = kernels [i];
float m = cur * weight;
*out++ = m + remain;
remain = cur - m;
}
}
while ( --n );
}
#endif
}
/* Atari change: more accurate values taken from
http://en.wikipedia.org/wiki/YIQ */
static float const default_decoder [6] =
{ 0.9563f, 0.6210f, -0.2721f, -0.6474f, -1.1070f, 1.7046f };
static void init( init_t* impl, atari_ntsc_setup_t const* setup )
{
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
#ifdef default_palette_contrast
if ( !setup->palette )
impl->contrast *= default_palette_contrast;
#endif
impl->artifacts = (float) setup->artifacts;
if ( impl->artifacts > 0 )
impl->artifacts *= artifacts_max - artifacts_mid;
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
impl->fringing = (float) setup->fringing;
if ( impl->fringing > 0 )
impl->fringing *= fringing_max - fringing_mid;
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
init_filters( impl, setup );
/* generate gamma table */
if ( gamma_size > 1 )
{
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
int i;
for ( i = 0; i < gamma_size; i++ )
impl->to_float [i] =
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
}
/* setup decoder matricies */
{
/* Atari change:
NTSC colorburst angle in YIQ colorspace. Colorburst is at
180 degrees in YUV - that is, a gold color. In YIQ, gold is at
different angle. However, YIQ is actually YUV turned
33 degrees. So by looking at screenshots at Wikipedia we can
conclude that the colorburst angle is 270+33 in YIQ.
(See http://en.wikipedia.org/wiki/YUV and
http://en.wikipedia.org/wiki/YIQ) */
static float const colorburst_angle = (303.0f) * PI / 180.0f;
float hue = (float) -setup->hue * PI + PI / 180 * ext_decoder_hue + PI * setup->burst_phase - colorburst_angle;
float sat = (float) setup->saturation + 1;
float const* decoder = setup->decoder_matrix;
if ( !decoder )
{
decoder = default_decoder;
if ( STD_HUE_CONDITION( setup ) )
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
}
{
float s = (float) sin( hue ) * sat;
float c = (float) cos( hue ) * sat;
float* out = impl->to_rgb;
int n;
n = burst_count;
do
{
float const* in = decoder;
int n = 3;
do
{
float i = *in++;
float q = *in++;
*out++ = i * c - q * s;
*out++ = i * s + q * c;
}
while ( --n );
if ( burst_count <= 1 )
break;
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
}
while ( --n );
}
}
}
/* kernel generation */
/* Atari change: more accurate values taken from
http://en.wikipedia.org/wiki/YIQ */
#define RGB_TO_YIQ( r, g, b, y, i ) (\
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
(i = (r) * 0.595716f - (g) * 0.274453f - (b) * 0.321263f),\
((r) * 0.211456f - (g) * 0.522591f + (b) * 0.311135f)\
)
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
)
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
enum { rgb_kernel_size = burst_size / alignment_count };
enum { rgb_bias = rgb_unit * 2 * atari_ntsc_rgb_builder };
typedef struct pixel_info_t
{
int offset;
float negate;
float kernel [4];
} pixel_info_t;
#if rescale_in > 1
#define PIXEL_OFFSET_( ntsc, scaled ) \
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
(kernel_size * 2 * scaled))
#define PIXEL_OFFSET( ntsc, scaled ) \
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
(((scaled) + rescale_out * 10) % rescale_out) ),\
(1.0f - (((ntsc) + 100) & 2))
#else
#define PIXEL_OFFSET( ntsc, scaled ) \
(kernel_size / 2 + (ntsc) - (scaled)),\
(1.0f - (((ntsc) + 100) & 2))
#endif
extern pixel_info_t const atari_ntsc_pixels [alignment_count];
/* Generate pixel at all burst phases and column alignments */
static void gen_kernel( init_t* impl, float y, float i, float q, atari_ntsc_rgb_t* out )
{
/* generate for each scanline burst phase */
float const* to_rgb = impl->to_rgb;
int burst_remain = burst_count;
y -= rgb_offset;
do
{
/* Encode yiq into *two* composite signals (to allow control over artifacting).
Convolve these with kernels which: filter respective components, apply
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
into integer. Based on algorithm by NewRisingSun. */
pixel_info_t const* pixel = atari_ntsc_pixels;
int alignment_remain = alignment_count;
do
{
/* negate is -1 when composite starts at odd multiple of 2 */
float const yy = y * impl->fringing * pixel->negate;
float const ic0 = (i + yy) * pixel->kernel [0];
float const qc1 = (q + yy) * pixel->kernel [1];
float const ic2 = (i - yy) * pixel->kernel [2];
float const qc3 = (q - yy) * pixel->kernel [3];
float const factor = impl->artifacts * pixel->negate;
float const ii = i * factor;
float const yc0 = (y + ii) * pixel->kernel [0];
float const yc2 = (y - ii) * pixel->kernel [2];
float const qq = q * factor;
float const yc1 = (y + qq) * pixel->kernel [1];
float const yc3 = (y - qq) * pixel->kernel [3];
float const* k = &impl->kernel [pixel->offset];
int n;
++pixel;
for ( n = rgb_kernel_size; n; --n )
{
float i = k[0]*ic0 + k[2]*ic2;
float q = k[1]*qc1 + k[3]*qc3;
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
if ( rescale_out <= 1 )
k--;
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
k += kernel_size * 2 - 1;
else
k -= kernel_size * 2 * (rescale_out - 1) + 2;
{
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
}
}
}
while ( alignment_count > 1 && --alignment_remain );
if ( burst_count <= 1 )
break;
to_rgb += 6;
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
}
while ( --burst_remain );
}
static void correct_errors( atari_ntsc_rgb_t color, atari_ntsc_rgb_t* out );
/* Atari change: adjust DISTRIBUTE_ERROR to 4/7 pixel ratio. */
#if DISABLE_CORRECTION
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
#define DISTRIBUTE_ERROR( a, b, c, d ) { out [i] += rgb_bias; }
#else
#define CORRECT_ERROR( a ) { out [a] += error; }
#define DISTRIBUTE_ERROR( a, b, c, d ) {\
atari_ntsc_rgb_t fourth = (error + 2 * atari_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - atari_ntsc_rgb_builder;\
fourth -= rgb_bias >> 2;\
out [a] += fourth;\
out [b] += fourth;\
out [c] += fourth;\
out [d] += fourth;\
out [i] += error - (fourth * 4);\
}
#endif
#define RGB_PALETTE_OUT( rgb, out_ )\
{\
unsigned char* out = (out_);\
atari_ntsc_rgb_t clamped = (rgb);\
ATARI_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
out [0] = (unsigned char) (clamped >> 21);\
out [1] = (unsigned char) (clamped >> 11);\
out [2] = (unsigned char) (clamped >> 1);\
}
/* blitter related */
#ifndef restrict
#if defined (__GNUC__)
#define restrict __restrict__
#elif defined (_MSC_VER) && _MSC_VER > 1300
#define restrict __restrict
#else
/* no support for restricted pointers */
#define restrict
#endif
#endif
#include <limits.h>
#if ATARI_NTSC_OUT_DEPTH <= 16
#if USHRT_MAX == 0xFFFF
typedef unsigned short atari_ntsc_out_t;
#else
#error "Need 16-bit int type"
#endif
#else
#if UINT_MAX == 0xFFFFFFFF
typedef unsigned int atari_ntsc_out_t;
#elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long atari_ntsc_out_t;
#else
#error "Need 32-bit int type"
#endif
#endif
File diff suppressed because it is too large Load Diff
+209
View File
@@ -0,0 +1,209 @@
/*
* atari_rpi.c - Raspberry Pi support by djdron
*
* Copyright (c) 2013 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* This file is based on Portable ZX-Spectrum emulator.
* Copyright (C) 2001-2012 SMT, Dexus, Alone Coder, deathsoft, djdron, scor
*
* Atari800 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <bcm_host.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <SDL.h>
#include <assert.h>
#include "config.h"
#include "atari.h"
#include "atari_ntsc/atari_ntsc.h"
#include "util.h"
void gles2_create();
void gles2_destroy();
void gles2_draw(int width, int height);
void gles2_palette_changed();
static uint32_t screen_width = 0;
static uint32_t screen_height = 0;
static EGLDisplay display = NULL;
static EGLSurface surface = NULL;
static EGLContext context = NULL;
static EGL_DISPMANX_WINDOW_T nativewindow;
static SDL_Surface* screen = NULL;
extern int op_filtering;
extern float op_zoom;
int SDL_VIDEO_ReadConfig(char *option, char *parameters)
{
if(strcmp(option, "VIDEO_FILTERING") == 0)
{
int v = Util_sscanbool(parameters);
if(v >= 0)
{
op_filtering = v;
return TRUE;
}
}
else if(strcmp(option, "VIDEO_ZOOM") == 0)
{
double z = 1.0f;
if(Util_sscandouble(parameters, &z))
{
op_zoom = z;
return TRUE;
}
}
return FALSE;
}
void SDL_VIDEO_WriteConfig(FILE *fp)
{
fprintf(fp, "VIDEO_FILTERING=%d\n", op_filtering);
fprintf(fp, "VIDEO_ZOOM=%.2f\n", op_zoom);
}
// some dummies (unresolved externals from sdl/video.c, sdl/input.c)
int VIDEOMODE_Update() { return TRUE; }
int VIDEOMODE_SetWindowSize(unsigned int width, unsigned int height) { return TRUE; }
int VIDEOMODE_ToggleWindowed() { return TRUE; }
int VIDEOMODE_ToggleHorizontalArea() { return TRUE; }
int VIDEOMODE_Toggle80Column() { return TRUE; }
void SDL_VIDEO_SetScanlinesPercentage(int value) {}
int SDL_VIDEO_scanlines_percentage = 5;
int SDL_VIDEO_width = 1;
int SDL_VIDEO_height = 1;
atari_ntsc_t *FILTER_NTSC_emu = NULL;
atari_ntsc_setup_t FILTER_NTSC_setup;
void FILTER_NTSC_Update(atari_ntsc_t *filter) {}
void FILTER_NTSC_NextPreset() {}
void PLATFORM_PaletteUpdate() { gles2_palette_changed(); }
void SDL_VIDEO_InitSDL();
int SDL_VIDEO_Initialise(int *argc, char *argv[])
{
bcm_host_init();
SDL_VIDEO_InitSDL();
return 1;
}
void SDL_VIDEO_InitSDL()
{
SDL_InitSubSystem(SDL_INIT_VIDEO);
SDL_WM_SetCaption(Atari800_TITLE, "Atari800");
SDL_EnableUNICODE(1);
SDL_ShowCursor(SDL_DISABLE); /* hide mouse cursor */
screen = SDL_SetVideoMode(0,0, 32, SDL_SWSURFACE); // hack to make keyboard events work
// get an EGL display connection
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
assert(display != EGL_NO_DISPLAY);
// initialize the EGL display connection
EGLBoolean result = eglInitialize(display, NULL, NULL);
assert(EGL_FALSE != result);
// get an appropriate EGL frame buffer configuration
EGLint num_config;
EGLConfig config;
static const EGLint attribute_list[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
result = eglChooseConfig(display, attribute_list, &config, 1, &num_config);
assert(EGL_FALSE != result);
result = eglBindAPI(EGL_OPENGL_ES_API);
assert(EGL_FALSE != result);
// create an EGL rendering context
static const EGLint context_attributes[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
assert(context != EGL_NO_CONTEXT);
// create an EGL window surface
int32_t success = graphics_get_display_size(0, &screen_width, &screen_height);
assert(success >= 0);
VC_RECT_T dst_rect;
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = screen_width;
dst_rect.height = screen_height;
VC_RECT_T src_rect;
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = screen_width << 16;
src_rect.height = screen_height << 16;
DISPMANX_DISPLAY_HANDLE_T dispman_display = vc_dispmanx_display_open(0);
DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start(0);
DISPMANX_ELEMENT_HANDLE_T dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display,
0, &dst_rect, 0, &src_rect, DISPMANX_PROTECTION_NONE, NULL, NULL, DISPMANX_NO_ROTATE);
nativewindow.element = dispman_element;
nativewindow.width = screen_width;
nativewindow.height = screen_height;
vc_dispmanx_update_submit_sync(dispman_update);
surface = eglCreateWindowSurface(display, config, &nativewindow, NULL);
assert(surface != EGL_NO_SURFACE);
// connect the context to the surface
result = eglMakeCurrent(display, surface, surface, context);
assert(EGL_FALSE != result);
gles2_create();
}
void SDL_VIDEO_Exit()
{
if(screen)
{
SDL_FreeSurface(screen);
screen = NULL;
}
SDL_QuitSubSystem(SDL_INIT_VIDEO);
gles2_destroy();
// Release OpenGL resources
eglMakeCurrent( display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
eglDestroySurface( display, surface );
eglDestroyContext( display, context );
eglTerminate( display );
bcm_host_deinit();
}
void PLATFORM_DisplayScreen()
{
gles2_draw(screen_width, screen_height);
eglSwapBuffers(display, surface);
}
File diff suppressed because it is too large Load Diff
+14
View File
@@ -0,0 +1,14 @@
#! /bin/sh
autoheader
autoconf
echo
echo "Now you need to run the configure script. The configure script may take the"
echo "\"--target=TARGET\" option and various \"--enable-FEATURE\" and \"--with-PACKAGE\""
echo "options."
echo
echo "Run \"./configure --help\" to see all available options."
echo "Run \"./configure --help=short\" just to see the Atari800 FEATURE options."
echo "Run \"./configure --target=help\" without a parameter to see the valid targets."
echo
+221
View File
@@ -0,0 +1,221 @@
/*
* binload.c - load a binary executable file
*
* Copyright (C) 1995-1998 David Firth
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <stdio.h>
#include "atari.h"
#include "binload.h"
#include "cpu.h"
#include "devices.h"
#include "esc.h"
#include "log.h"
#include "memory.h"
#include "sio.h"
int BINLOAD_start_binloading = FALSE;
int BINLOAD_loading_basic = 0;
int BINLOAD_slow_xex_loading = FALSE;
FILE *BINLOAD_bin_file = NULL;
/* These variables are for slow XEX loading only. */
/* Number of CPU instructions elapsed since last loaded byte. */
static unsigned int instr_elapsed = 0;
int BINLOAD_wait_active=FALSE;
/* Start and end address of the currently loaded segment. */
static UWORD from = 0;
static UWORD to = 0;
/* Inticates that the next call to loader_cont will overwrite INITAD. */
static int init2e3 = FALSE;
/* Indicates that we are currently not during loading of a segment. */
static int segfinished = TRUE;
int BINLOAD_pause_loading;
/* Read a word from file */
static int read_word(void)
{
UBYTE buf[2];
if (fread(buf, 1, 2, BINLOAD_bin_file) != 2) {
fclose(BINLOAD_bin_file);
BINLOAD_bin_file = NULL;
if (BINLOAD_start_binloading) {
BINLOAD_start_binloading = FALSE;
Log_print("binload: not valid BIN file");
return -1;
}
CPU_regPC = MEMORY_dGetWordAligned(0x2e0);
return -1;
}
return buf[0] + (buf[1] << 8);
}
/* Start or continue loading */
static void loader_cont(void)
{
if (BINLOAD_bin_file == NULL)
return;
if (BINLOAD_start_binloading) {
MEMORY_dPutByte(0x244, 0);
MEMORY_dPutByte(0x09, 1);
}
else
CPU_regS += 2; /* pop ESC code */
if (init2e3)
MEMORY_dPutByte(0x2e3, 0xd7);
init2e3=FALSE;
do {
if((!BINLOAD_wait_active || !BINLOAD_slow_xex_loading) && segfinished){
int temp;
do
temp = read_word();
while (temp == 0xffff);
if (temp < 0)
return;
from = (UWORD) temp;
temp = read_word();
if (temp < 0)
return;
to = (UWORD) temp;
if (BINLOAD_start_binloading) {
MEMORY_dPutWordAligned(0x2e0, from);
BINLOAD_start_binloading = FALSE;
}
to++;
segfinished = FALSE;
}
do {
int byte;
if (BINLOAD_slow_xex_loading) {
instr_elapsed++;
if ((instr_elapsed < 300) || BINLOAD_pause_loading) {
CPU_regS--;
ESC_Add((UWORD) (0x100 + CPU_regS), ESC_BINLOADER_CONT, loader_cont);
CPU_regS--;
CPU_regPC = CPU_regS + 1 + 0x100;
BINLOAD_wait_active = TRUE;
return;
}
instr_elapsed = 0;
BINLOAD_wait_active = FALSE;
}
byte = fgetc(BINLOAD_bin_file);
if (byte == EOF) {
fclose(BINLOAD_bin_file);
BINLOAD_bin_file = NULL;
CPU_regPC = MEMORY_dGetWordAligned(0x2e0);
if (MEMORY_dGetByte(0x2e3) != 0xd7) {
/* run INIT routine which RTSes directly to RUN routine */
CPU_regPC--;
MEMORY_dPutByte(0x0100 + CPU_regS--, CPU_regPC >> 8); /* high */
MEMORY_dPutByte(0x0100 + CPU_regS--, CPU_regPC & 0xff); /* low */
CPU_regPC = MEMORY_dGetWordAligned(0x2e2);
}
return;
}
MEMORY_PutByte(from, (UBYTE) byte);
from++;
} while (from != to);
segfinished = TRUE;
} while (MEMORY_dGetByte(0x2e3) == 0xd7);
CPU_regS--;
ESC_Add((UWORD) (0x100 + CPU_regS), ESC_BINLOADER_CONT, loader_cont);
CPU_regS--;
MEMORY_dPutByte(0x0100 + CPU_regS--, 0x01); /* high */
MEMORY_dPutByte(0x0100 + CPU_regS, CPU_regS + 1); /* low */
CPU_regS--;
CPU_regPC = MEMORY_dGetWordAligned(0x2e2);
CPU_SetC;
MEMORY_dPutByte(0x0300, 0x31); /* for "Studio Dream" */
init2e3 = TRUE;
}
/* Fake boot sector to call loader_cont at boot time */
int BINLOAD_LoaderStart(UBYTE *buffer)
{
buffer[0] = 0x00; /* ignored */
buffer[1] = 0x01; /* one boot sector */
buffer[2] = 0x00; /* start at memory location 0x0700 */
buffer[3] = 0x07;
buffer[4] = 0x77; /* reset reboots (0xe477 = Atari OS Coldstart) */
buffer[5] = 0xe4;
buffer[6] = 0xf2; /* ESC */
buffer[7] = ESC_BINLOADER_CONT;
ESC_Add(0x706, ESC_BINLOADER_CONT, loader_cont);
BINLOAD_wait_active = FALSE;
init2e3 = TRUE;
segfinished = TRUE;
return 'C';
}
/* Load BIN file, returns TRUE if ok */
int BINLOAD_Loader(const char *filename)
{
UBYTE buf[2];
if (BINLOAD_bin_file != NULL) { /* close previously open file */
fclose(BINLOAD_bin_file);
BINLOAD_bin_file = NULL;
BINLOAD_loading_basic = 0;
}
if (Atari800_machine_type == Atari800_MACHINE_5200) {
Log_print("binload: can't run Atari programs directly on the 5200");
return FALSE;
}
BINLOAD_bin_file = fopen(filename, "rb");
if (BINLOAD_bin_file == NULL) { /* open */
Log_print("binload: can't open \"%s\"", filename);
return FALSE;
}
/* Avoid "BOOT ERROR" when loading a BASIC program */
if (SIO_drive_status[0] == SIO_NO_DISK)
SIO_DisableDrive(1);
if (fread(buf, 1, 2, BINLOAD_bin_file) == 2) {
if (buf[0] == 0xff && buf[1] == 0xff) {
BINLOAD_start_binloading = TRUE; /* force SIO to call BINLOAD_LoaderStart at boot */
Atari800_Coldstart(); /* reboot */
return TRUE;
}
else if (buf[0] == 0 && buf[1] == 0) {
BINLOAD_loading_basic = BINLOAD_LOADING_BASIC_SAVED;
ESC_UpdatePatches();
Atari800_Coldstart();
return TRUE;
}
else if (buf[0] >= '0' && buf[0] <= '9') {
BINLOAD_loading_basic = BINLOAD_LOADING_BASIC_LISTED;
ESC_UpdatePatches();
Atari800_Coldstart();
return TRUE;
}
}
fclose(BINLOAD_bin_file);
BINLOAD_bin_file = NULL;
Log_print("binload: \"%s\" not recognized as a DOS or BASIC program", filename);
return FALSE;
}
+32
View File
@@ -0,0 +1,32 @@
#ifndef BINLOAD_H_
#define BINLOAD_H_
#include <stdio.h> /* FILE */
#include "atari.h" /* UBYTE */
extern FILE *BINLOAD_bin_file;
int BINLOAD_Loader(const char *filename);
extern int BINLOAD_start_binloading;
extern int BINLOAD_loading_basic;
/* Set to TRUE to enable loading of XEX with approximate disk speed */
extern int BINLOAD_slow_xex_loading;
/* Indicates that a DOS file is being currently slowly loaded. */
extern int BINLOAD_wait_active;
/* Set it to TRUE to pause the current loading of a DOS file. */
extern int BINLOAD_pause_loading;
#define BINLOAD_LOADING_BASIC_SAVED 1
#define BINLOAD_LOADING_BASIC_LISTED 2
#define BINLOAD_LOADING_BASIC_LISTED_ATARI 3
#define BINLOAD_LOADING_BASIC_LISTED_CR 4
#define BINLOAD_LOADING_BASIC_LISTED_LF 5
#define BINLOAD_LOADING_BASIC_LISTED_CRLF 6
#define BINLOAD_LOADING_BASIC_LISTED_CR_OR_CRLF 7
#define BINLOAD_LOADING_BASIC_RUN 8
int BINLOAD_LoaderStart(UBYTE *buffer);
#endif /* BINLOAD_H_ */
+261
View File
@@ -0,0 +1,261 @@
/*
* bit3.c - Emulation of the Bit3 Full View 80 column card.
*
* Copyright (C) 2009 Perry McFarlane
* Copyright (C) 2009 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "bit3.h"
#include "atari.h"
#include "util.h"
#include "log.h"
#include "memory.h"
#include "cpu.h"
#include "videomode.h"
#include <stdlib.h>
static UBYTE *bit3_rom = NULL;
static char bit3_rom_filename[FILENAME_MAX];
static UBYTE *bit3_charset = NULL;
static char bit3_charset_filename[FILENAME_MAX];
static UBYTE *bit3_screen = NULL;
int BIT3_enabled = FALSE;
static int video_latch = 0;
static int rom_bank_select; /* bits 5 and 0-2 of d508, $0-$f 16 banks */
static UBYTE crtreg[0x40];
int BIT3_palette[2] = {
0x000000, /* black */
0xFFFFFF /* white (high intensity) */
};
#ifdef BIT3_DEBUG
#define D(a) a
#else
#define D(a) do{}while(0)
#endif
static void update_d6(void)
{
memcpy(MEMORY_mem + 0xd600, bit3_rom + (rom_bank_select<<8), 0x100);
}
int BIT3_Initialise(int *argc, char *argv[])
{
int i, j;
int help_only = FALSE;
for (i = j = 1; i < *argc; i++) {
if (strcmp(argv[i], "-bit3") == 0) {
BIT3_enabled = TRUE;
}
else {
if (strcmp(argv[i], "-help") == 0) {
help_only = TRUE;
Log_print("\t-bit3 Emulate the Bit3 Full View 80 column board");
}
argv[j++] = argv[i];
}
}
*argc = j;
if (help_only)
return TRUE;
if (BIT3_enabled) {
Log_print("Bit 3 Full View enabled");
bit3_rom = (UBYTE *)Util_malloc(0x1000);
if (!Atari800_LoadImage(bit3_rom_filename, bit3_rom, 0x1000)) {
free(bit3_rom);
bit3_rom = NULL;
BIT3_enabled = FALSE;
Log_print("Couldn't load Bit3 Full View ROM image");
return FALSE;
}
else {
Log_print("loaded Bit3 Full View ROM image");
}
bit3_charset = (UBYTE *)Util_malloc(0x1000);
if (!Atari800_LoadImage(bit3_charset_filename, bit3_charset, 0x1000)) {
free(bit3_charset);
free(bit3_rom);
bit3_charset = bit3_rom = NULL;
BIT3_enabled = FALSE;
Log_print("Couldn't load Bit3 Full View charset image");
return FALSE;
}
else {
Log_print("loaded Bit3 Full View charset image");
}
bit3_screen = (UBYTE *)Util_malloc(0x800);
VIDEOMODE_80_column = 0; /* Disable 80 column mode if set in .cfg, Bit3 uses software control for this */
BIT3_Reset(); /* With VIDEOMODE_80_column = 0, VIDEOMODE_Set80Column(0) will not change modes */
}
return TRUE;
}
void BIT3_Exit(void)
{
free(bit3_screen);
free(bit3_charset);
free(bit3_rom);
bit3_screen = bit3_charset = bit3_rom = NULL;
}
int BIT3_ReadConfig(char *string, char *ptr)
{
if (strcmp(string, "BIT3_ROM") == 0)
Util_strlcpy(bit3_rom_filename, ptr, sizeof(bit3_rom_filename));
else if (strcmp(string, "BIT3_CHARSET") == 0)
Util_strlcpy(bit3_charset_filename, ptr, sizeof(bit3_charset_filename));
else return FALSE; /* no match */
return TRUE; /* matched something */
}
void BIT3_WriteConfig(FILE *fp)
{
fprintf(fp, "BIT3_ROM=%s\n", bit3_rom_filename);
fprintf(fp, "BIT3_CHARSET=%s\n", bit3_charset_filename);
}
int BIT3_D6GetByte(UWORD addr, int no_side_effects)
{
int result = MEMORY_dGetByte(addr);
return result;
}
void BIT3_D6PutByte(UWORD addr, UBYTE byte)
{
return;
}
int BIT3_D5GetByte(UWORD addr, int no_side_effects)
{
int result=0xff;
if (addr == 0xd508) {
}
else if (addr == 0xd580) {
/* crtc status TODO */
}
else if (addr == 0xd581) {
result = crtreg[crtreg[0x00]&0x3f];
}
else if (addr == 0xd583 || addr == 0xd585) {
/* d583 is used for reading screen ram, d585 for writing, in the ROM.
* This code supports both since the manual only mentions using
* d583 for read/write */
result = bit3_screen[(((crtreg[0x12]&0x07)<<8)|crtreg[0x13])];
if(crtreg[0x13] == 0) {
crtreg[0x12] = ((crtreg[0x12]+1)&0x3f);
}
}
else {
result = MEMORY_dGetByte(addr);
}
return result;
}
void BIT3_D5PutByte(UWORD addr, UBYTE byte)
{
if (addr == 0xd508) {
/* ROM bank bits 0-2 and bit 5 */
/* The manual says bit 3 unblanks the 80x24 display and bit 4 turns the video switch to 80 x 24 (from 40 col)*/
if (rom_bank_select != (((byte & 0x20)>>2)|(byte & 0x07))) {
rom_bank_select = (((byte & 0x20)>>2)|(byte & 0x07));
update_d6();
};
if (video_latch != !!(byte & 0x10)){
video_latch = !!(byte & 0x10);
VIDEOMODE_Set80Column(video_latch);
}
}
else if (addr == 0xd580) {
/* select crtc register */
crtreg[0] = byte;
}
else if (addr == 0xd581) {
/* write selected crtc register */
crtreg[crtreg[0]&0x3f] = byte;
}
else if (addr == 0xd583 || addr == 0xd585) {
/* d583 is used for reading screen ram, d585 for writing, in the ROM.
* This code supports both since the manual only mentions using
* d583 for read/write */
bit3_screen[(((crtreg[0x12]&0x07)<<8)|crtreg[0x13])] = byte;
crtreg[0x13]++;
if(crtreg[0x13] == 0) {
crtreg[0x12] = ((crtreg[0x12]+1)&0x3f);
}
}
}
UBYTE BIT3_GetPixels(int scanline, int column, int *colour, int blink)
{
#define BIT3_ROWS 24
#define BIT3_CELL_HEIGHT 10
UBYTE character;
UBYTE font_data;
int table_start = crtreg[0x0d] + ((crtreg[0x0c]&0x3f)<<8);
int row = scanline / BIT3_CELL_HEIGHT;
int line = scanline % BIT3_CELL_HEIGHT;
int screen_pos;
if (row >= BIT3_ROWS) {
return 0;
}
screen_pos = ((row*80+column + table_start)&0x3fff);
character = bit3_screen[screen_pos&0x7ff];
font_data = bit3_charset[(character&0x7f)*16 + line];
if (character & 0x80) {
font_data ^= 0xff; /* invert */
}
if (screen_pos == (((crtreg[0x0e]&0x3f)<<8)|crtreg[0x0f]) && !blink) {
if (line >= (crtreg[0x0a]&0x1f) && line <= (crtreg[0x0b]&0x1f)){
if ((crtreg[0x0a]&0x60) == 0x00 ||
((crtreg[0x0a]&0x60) == 0x40 && !blink) ||
((crtreg[0x0a]&0x60) == 0x60 && !blink)) {
/* 0x00: no blinking */
/* 0x20: no cursor */
/* 0x40: blink at 1/16 field rate */
/* 0x60: blink at 1/32 field rate TODO */
font_data ^= 0xff; /* cursor */
}
}
}
*colour = 1; /* set number of palette entry for foreground pixels */
return font_data;
}
void BIT3_Reset(void)
{
memset(bit3_screen, 0, 0x800);
rom_bank_select = 0;
memset(crtreg, 0, 0x40);
update_d6();
video_latch = 0;
VIDEOMODE_Set80Column(video_latch);
}
/*
vim:ts=4:sw=4:
*/
+21
View File
@@ -0,0 +1,21 @@
#ifndef BIT3_H_
#define BIT3_H_
#include "atari.h"
#include <stdio.h>
extern int BIT3_palette[2];
int BIT3_Initialise(int *argc, char *argv[]);
void BIT3_Exit(void);
void BIT3_InsertRightCartridge(void);
int BIT3_ReadConfig(char *string, char *ptr);
void BIT3_WriteConfig(FILE *fp);
int BIT3_D5GetByte(UWORD addr, int no_side_effects);
void BIT3_D5PutByte(UWORD addr, UBYTE byte);
int BIT3_D6GetByte(UWORD addr, int no_side_effects);
void BIT3_D6PutByte(UWORD addr, UBYTE byte);
UBYTE BIT3_GetPixels(int scanline, int column, int *colour, int blink);
extern int BIT3_enabled;
void BIT3_Reset(void);
#endif /* BIT3_H_ */
File diff suppressed because it is too large Load Diff
+213
View File
@@ -0,0 +1,213 @@
#ifndef CARTRIDGE_H_
#define CARTRIDGE_H_
#include "config.h"
#include "atari.h"
enum {
CARTRIDGE_UNKNOWN = -1,
CARTRIDGE_NONE = 0,
CARTRIDGE_STD_8 = 1,
CARTRIDGE_STD_16 = 2,
CARTRIDGE_OSS_034M_16 = 3,
CARTRIDGE_5200_32 = 4,
CARTRIDGE_DB_32 = 5,
CARTRIDGE_5200_EE_16 = 6,
CARTRIDGE_5200_40 = 7,
CARTRIDGE_WILL_64 = 8,
CARTRIDGE_EXP_64 = 9,
CARTRIDGE_DIAMOND_64 = 10,
CARTRIDGE_SDX_64 = 11,
CARTRIDGE_XEGS_32 = 12,
CARTRIDGE_XEGS_07_64 = 13,
CARTRIDGE_XEGS_128 = 14,
CARTRIDGE_OSS_M091_16 = 15,
CARTRIDGE_5200_NS_16 = 16,
CARTRIDGE_ATRAX_128 = 17,
CARTRIDGE_BBSB_40 = 18,
CARTRIDGE_5200_8 = 19,
CARTRIDGE_5200_4 = 20,
CARTRIDGE_RIGHT_8 = 21,
CARTRIDGE_WILL_32 = 22,
CARTRIDGE_XEGS_256 = 23,
CARTRIDGE_XEGS_512 = 24,
CARTRIDGE_XEGS_1024 = 25,
CARTRIDGE_MEGA_16 = 26,
CARTRIDGE_MEGA_32 = 27,
CARTRIDGE_MEGA_64 = 28,
CARTRIDGE_MEGA_128 = 29,
CARTRIDGE_MEGA_256 = 30,
CARTRIDGE_MEGA_512 = 31,
CARTRIDGE_MEGA_1024 = 32,
CARTRIDGE_SWXEGS_32 = 33,
CARTRIDGE_SWXEGS_64 = 34,
CARTRIDGE_SWXEGS_128 = 35,
CARTRIDGE_SWXEGS_256 = 36,
CARTRIDGE_SWXEGS_512 = 37,
CARTRIDGE_SWXEGS_1024 = 38,
CARTRIDGE_PHOENIX_8 = 39,
CARTRIDGE_BLIZZARD_16 = 40,
CARTRIDGE_ATMAX_128 = 41,
CARTRIDGE_ATMAX_1024 = 42,
CARTRIDGE_SDX_128 = 43,
CARTRIDGE_OSS_8 = 44,
CARTRIDGE_OSS_043M_16 = 45,
CARTRIDGE_BLIZZARD_4 = 46,
CARTRIDGE_AST_32 = 47,
CARTRIDGE_ATRAX_SDX_64 = 48,
CARTRIDGE_ATRAX_SDX_128 = 49,
CARTRIDGE_TURBOSOFT_64 = 50,
CARTRIDGE_TURBOSOFT_128 = 51,
CARTRIDGE_ULTRACART_32 = 52,
CARTRIDGE_LOW_BANK_8 = 53,
CARTRIDGE_SIC_128 = 54,
CARTRIDGE_SIC_256 = 55,
CARTRIDGE_SIC_512 = 56,
CARTRIDGE_STD_2 = 57,
CARTRIDGE_STD_4 = 58,
CARTRIDGE_RIGHT_4 = 59,
CARTRIDGE_BLIZZARD_32 = 60,
CARTRIDGE_MEGAMAX_2048 = 61,
CARTRIDGE_THECART_128M = 62,
CARTRIDGE_MEGA_4096 = 63,
CARTRIDGE_MEGA_2048 = 64,
CARTRIDGE_THECART_32M = 65,
CARTRIDGE_THECART_64M = 66,
CARTRIDGE_XEGS_8F_64 = 67,
CARTRIDGE_LAST_SUPPORTED = 67
};
#define CARTRIDGE_MAX_SIZE (128 * 1024 * 1024)
extern int const CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1];
#define CARTRIDGE_STD_8_DESC "Standard 8 KB cartridge"
#define CARTRIDGE_STD_16_DESC "Standard 16 KB cartridge"
#define CARTRIDGE_OSS_034M_16_DESC "OSS two chip 16 KB cartridge (034M)"
#define CARTRIDGE_5200_32_DESC "Standard 32 KB 5200 cartridge"
#define CARTRIDGE_DB_32_DESC "DB 32 KB cartridge"
#define CARTRIDGE_5200_EE_16_DESC "Two chip 16 KB 5200 cartridge"
#define CARTRIDGE_5200_40_DESC "Bounty Bob 40 KB 5200 cartridge"
#define CARTRIDGE_WILL_64_DESC "64 KB Williams cartridge"
#define CARTRIDGE_EXP_64_DESC "Express 64 KB cartridge"
#define CARTRIDGE_DIAMOND_64_DESC "Diamond 64 KB cartridge"
#define CARTRIDGE_SDX_64_DESC "SpartaDOS X 64 KB cartridge"
#define CARTRIDGE_XEGS_32_DESC "XEGS 32 KB cartridge"
#define CARTRIDGE_XEGS_07_64_DESC "XEGS 64 KB cartridge (banks 0-7)"
#define CARTRIDGE_XEGS_128_DESC "XEGS 128 KB cartridge"
#define CARTRIDGE_OSS_M091_16_DESC "OSS one chip 16 KB cartridge"
#define CARTRIDGE_5200_NS_16_DESC "One chip 16 KB 5200 cartridge"
#define CARTRIDGE_ATRAX_128_DESC "Atrax 128 KB cartridge"
#define CARTRIDGE_BBSB_40_DESC "Bounty Bob 40 KB cartridge"
#define CARTRIDGE_5200_8_DESC "Standard 8 KB 5200 cartridge"
#define CARTRIDGE_5200_4_DESC "Standard 4 KB 5200 cartridge"
#define CARTRIDGE_RIGHT_8_DESC "Right slot 8 KB cartridge"
#define CARTRIDGE_WILL_32_DESC "32 KB Williams cartridge"
#define CARTRIDGE_XEGS_256_DESC "XEGS 256 KB cartridge"
#define CARTRIDGE_XEGS_512_DESC "XEGS 512 KB cartridge"
#define CARTRIDGE_XEGS_1024_DESC "XEGS 1 MB cartridge"
#define CARTRIDGE_MEGA_16_DESC "MegaCart 16 KB cartridge"
#define CARTRIDGE_MEGA_32_DESC "MegaCart 32 KB cartridge"
#define CARTRIDGE_MEGA_64_DESC "MegaCart 64 KB cartridge"
#define CARTRIDGE_MEGA_128_DESC "MegaCart 128 KB cartridge"
#define CARTRIDGE_MEGA_256_DESC "MegaCart 256 KB cartridge"
#define CARTRIDGE_MEGA_512_DESC "MegaCart 512 KB cartridge"
#define CARTRIDGE_MEGA_1024_DESC "MegaCart 1 MB cartridge"
#define CARTRIDGE_SWXEGS_32_DESC "Switchable XEGS 32 KB cartridge"
#define CARTRIDGE_SWXEGS_64_DESC "Switchable XEGS 64 KB cartridge"
#define CARTRIDGE_SWXEGS_128_DESC "Switchable XEGS 128 KB cartridge"
#define CARTRIDGE_SWXEGS_256_DESC "Switchable XEGS 256 KB cartridge"
#define CARTRIDGE_SWXEGS_512_DESC "Switchable XEGS 512 KB cartridge"
#define CARTRIDGE_SWXEGS_1024_DESC "Switchable XEGS 1 MB cartridge"
#define CARTRIDGE_PHOENIX_8_DESC "Phoenix 8 KB cartridge"
#define CARTRIDGE_BLIZZARD_16_DESC "Blizzard 16 KB cartridge"
#define CARTRIDGE_ATMAX_128_DESC "Atarimax 128 KB Flash cartridge"
#define CARTRIDGE_ATMAX_1024_DESC "Atarimax 1 MB Flash cartridge"
#define CARTRIDGE_SDX_128_DESC "SpartaDOS X 128 KB cartridge"
#define CARTRIDGE_OSS_8_DESC "OSS 8 KB cartridge"
#define CARTRIDGE_OSS_043M_16_DESC "OSS two chip 16 KB cartridge (043M)"
#define CARTRIDGE_BLIZZARD_4_DESC "Blizzard 4 KB cartridge"
#define CARTRIDGE_AST_32_DESC "AST 32 KB cartridge"
#define CARTRIDGE_ATRAX_SDX_64_DESC "Atrax SDX 64 KB cartridge"
#define CARTRIDGE_ATRAX_SDX_128_DESC "Atrax SDX 128 KB cartridge"
#define CARTRIDGE_TURBOSOFT_64_DESC "Turbosoft 64 KB cartridge"
#define CARTRIDGE_TURBOSOFT_128_DESC "Turbosoft 128 KB cartridge"
#define CARTRIDGE_ULTRACART_32_DESC "Ultracart 32 KB cartridge"
#define CARTRIDGE_LOW_BANK_8_DESC "Low bank 8 KB cartridge"
#define CARTRIDGE_SIC_128_DESC "SIC! 128 KB cartridge"
#define CARTRIDGE_SIC_256_DESC "SIC! 256 KB cartridge"
#define CARTRIDGE_SIC_512_DESC "SIC! 512 KB cartridge"
#define CARTRIDGE_STD_2_DESC "Standard 2 KB cartridge"
#define CARTRIDGE_STD_4_DESC "Standard 4 KB cartridge"
#define CARTRIDGE_RIGHT_4_DESC "Right slot 4 KB cartridge"
#define CARTRIDGE_BLIZZARD_32_DESC "Blizzard 32 KB cartridge"
#define CARTRIDGE_MEGAMAX_2048_DESC "MegaMax 2 MB cartridge"
#define CARTRIDGE_THECART_128M_DESC "The!Cart 128 MB cartridge"
#define CARTRIDGE_MEGA_4096_DESC "Flash MegaCart 4 MB cartridge"
#define CARTRIDGE_MEGA_2048_DESC "MegaCart 2 MB cartridge"
#define CARTRIDGE_THECART_32M_DESC "The!Cart 32 MB cartridge"
#define CARTRIDGE_THECART_64M_DESC "The!Cart 64 MB cartridge"
#define CARTRIDGE_XEGS_8F_64_DESC "XEGS 64 KB cartridge (banks 8-15)"
/* Indicates whether the emulator should automatically reboot (coldstart)
after inserting/removing a cartridge. (Doesn't affect the piggyback
cartridge - in this case system will never autoreboot.) */
extern int CARTRIDGE_autoreboot;
typedef struct CARTRIDGE_image_t {
int type;
int state; /* Cartridge's state, such as selected bank or switch on/off. */
int size; /* Size of the image, in kilobytes */
UBYTE *image;
char filename[FILENAME_MAX];
} CARTRIDGE_image_t;
extern CARTRIDGE_image_t CARTRIDGE_main;
extern CARTRIDGE_image_t CARTRIDGE_piggyback;
int CARTRIDGE_Checksum(const UBYTE *image, int nbytes);
int CARTRIDGE_ReadConfig(char *string, char *ptr);
void CARTRIDGE_WriteConfig(FILE *fp);
int CARTRIDGE_Initialise(int *argc, char *argv[]);
void CARTRIDGE_Exit(void);
#define CARTRIDGE_CANT_OPEN -1 /* Can't open cartridge image file */
#define CARTRIDGE_BAD_FORMAT -2 /* Unknown cartridge format */
#define CARTRIDGE_BAD_CHECKSUM -3 /* Warning: bad CART checksum */
/* Inserts the left cartrifge. */
int CARTRIDGE_Insert(const char *filename);
/* Inserts the left cartridge and reboots the system if needed. */
int CARTRIDGE_InsertAutoReboot(const char *filename);
/* Inserts the piggyback cartridge. */
int CARTRIDGE_Insert_Second(const char *filename);
/* When the cartridge type is CARTRIDGE_UNKNOWN after a call to
CARTRIDGE_Insert(), this function should be called to set the
cartridge's type manually to a value chosen by user. */
void CARTRIDGE_SetType(CARTRIDGE_image_t *cart, int type);
/* Sets type of the cartridge and reboots the system if needed. */
void CARTRIDGE_SetTypeAutoReboot(CARTRIDGE_image_t *cart, int type);
/* Removes the left cartridge. */
void CARTRIDGE_Remove(void);
/* Removes the left cartridge and reboots the system if needed. */
void CARTRIDGE_RemoveAutoReboot(void);
/* Removed the piggyback cartridge. */
void CARTRIDGE_Remove_Second(void);
/* Called on system coldstart. Resets the states of mounted cartridges. */
void CARTRIDGE_ColdStart(void);
UBYTE CARTRIDGE_GetByte(UWORD addr, int no_side_effects);
void CARTRIDGE_PutByte(UWORD addr, UBYTE byte);
void CARTRIDGE_BountyBob1(UWORD addr);
void CARTRIDGE_BountyBob2(UWORD addr);
void CARTRIDGE_StateSave(void);
void CARTRIDGE_StateRead(UBYTE version);
#ifdef PAGED_ATTRIB
UBYTE CARTRIDGE_BountyBob1GetByte(UWORD addr, int no_side_effects);
UBYTE CARTRIDGE_BountyBob2GetByte(UWORD addr, int no_side_effects);
void CARTRIDGE_BountyBob1PutByte(UWORD addr, UBYTE value);
void CARTRIDGE_BountyBob2PutByte(UWORD addr, UBYTE value);
#endif
#endif /* CARTRIDGE_H_ */
+479
View File
@@ -0,0 +1,479 @@
/*
* cassette.c - cassette emulation
*
* Copyright (C) 2001 Piotr Fusik
* Copyright (C) 2001-2011 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "atari.h"
#include "cpu.h"
#include "cassette.h"
#include "esc.h"
#include "img_tape.h"
#include "log.h"
#include "util.h"
#include "pokey.h"
static IMG_TAPE_t *cassette_file = NULL;
/* Time till the end of the current tape event (byte or gap), in CPU ticks. */
static SLONG event_time_left = 0;
/* Indicates that there is a SERIN transmission in progress and when it ends,
the current byte should be copied to POKEY_SERIN. This can be reset by
rewinding/removing the tape or by resetting POKEY.
Note that this variable has any meaning when PASSING_GAP is FALSE,
so it doesn't have to be reset during PASSING_IRG. */
static int pending_serin = FALSE;
/* Indicates that an Inter-Record-Gap is currently being passed. It's set to TRUE
at the beginning of each block. */
static int passing_gap = FALSE;
/* if penting_serin == TRUE, this holds the byte that is currently loaded from
tape. It might be later copied to serin_byte. */
static UBYTE pending_serin_byte = 0xff;
/* Byte most recently loaded from tape; will be accessed by SIO_GetByte(). */
static UBYTE serin_byte = 0xff;
char CASSETTE_filename[FILENAME_MAX];
CASSETTE_status_t CASSETTE_status = CASSETTE_STATUS_NONE;
int CASSETTE_write_protect = FALSE;
int CASSETTE_record = FALSE;
int CASSETTE_writable = FALSE;
int CASSETTE_readable = FALSE;
char CASSETTE_description[CASSETTE_DESCRIPTION_MAX];
static int cassette_gapdelay = 0; /* in ms, includes leader and all gaps */
static int cassette_motor = 0;
int CASSETTE_hold_start_on_reboot = 0;
int CASSETTE_hold_start = 0;
int CASSETTE_press_space = 0;
/* Indicates whether the tape has ended. During saving the value is always 0;
during loading it is equal to (CASSETTE_GetPosition() >= CASSETTE_GetSize()). */
static int eof_of_tape = 0;
/* Call this function after each change of
cassette_motor, CASSETTE_status or eof_of_tape. */
static void UpdateFlags(void)
{
CASSETTE_readable = cassette_motor &&
(CASSETTE_status == CASSETTE_STATUS_READ_WRITE ||
CASSETTE_status == CASSETTE_STATUS_READ_ONLY) &&
!eof_of_tape;
CASSETTE_writable = cassette_motor &&
CASSETTE_status == CASSETTE_STATUS_READ_WRITE &&
!CASSETTE_write_protect;
}
int CASSETTE_ReadConfig(char *string, char *ptr)
{
if (strcmp(string, "CASSETTE_FILENAME") == 0)
Util_strlcpy(CASSETTE_filename, ptr, sizeof(CASSETTE_filename));
else if (strcmp(string, "CASSETTE_LOADED") == 0) {
int value = Util_sscanbool(ptr);
if (value == -1)
return FALSE;
CASSETTE_status = (value ? CASSETTE_STATUS_READ_WRITE : CASSETTE_STATUS_NONE);
}
else if (strcmp(string, "CASSETTE_WRITE_PROTECT") == 0) {
int value = Util_sscanbool(ptr);
if (value == -1)
return FALSE;
CASSETTE_write_protect = value;
}
else return FALSE;
return TRUE;
}
void CASSETTE_WriteConfig(FILE *fp)
{
fprintf(fp, "CASSETTE_FILENAME=%s\n", CASSETTE_filename);
fprintf(fp, "CASSETTE_LOADED=%d\n", CASSETTE_status != CASSETTE_STATUS_NONE);
fprintf(fp, "CASSETTE_WRITE_PROTECT=%d\n", CASSETTE_write_protect);
}
int CASSETTE_Initialise(int *argc, char *argv[])
{
int i;
int j;
int protect = FALSE; /* Is write-protect requested in command line? */
for (i = j = 1; i < *argc; i++) {
int i_a = (i + 1 < *argc); /* is argument available? */
int a_m = FALSE; /* error, argument missing! */
if (strcmp(argv[i], "-tape") == 0) {
if (i_a) {
Util_strlcpy(CASSETTE_filename, argv[++i], sizeof(CASSETTE_filename));
CASSETTE_status = CASSETTE_STATUS_READ_WRITE;
/* Reset any write-protection read from config file. */
CASSETTE_write_protect = FALSE;
}
else a_m = TRUE;
}
else if (strcmp(argv[i], "-boottape") == 0) {
if (i_a) {
Util_strlcpy(CASSETTE_filename, argv[++i], sizeof(CASSETTE_filename));
CASSETTE_status = CASSETTE_STATUS_READ_WRITE;
/* Reset any write-protection read from config file. */
CASSETTE_write_protect = FALSE;
CASSETTE_hold_start = 1;
}
else a_m = TRUE;
}
else if (strcmp(argv[i], "-tape-readonly") == 0)
protect = TRUE;
else {
if (strcmp(argv[i], "-help") == 0) {
Log_print("\t-tape <file> Insert cassette image");
Log_print("\t-boottape <file> Insert cassette image and boot it");
Log_print("\t-tape-readonly Mark the attached cassette image as read-only");
}
argv[j++] = argv[i];
}
if (a_m) {
Log_print("Missing argument for '%s'", argv[i]);
return FALSE;
}
}
*argc = j;
/* If CASSETTE_status was set in this function or in CASSETTE_ReadConfig(),
then tape is to be mounted. */
if (CASSETTE_status != CASSETTE_STATUS_NONE && CASSETTE_filename[0] != '\0') {
/* Tape is mounted unprotected by default - overrun it if needed. */
protect = protect || CASSETTE_write_protect;
if (!CASSETTE_Insert(CASSETTE_filename)) {
CASSETTE_status = CASSETTE_STATUS_NONE;
Log_print("Cannot open cassette image %s", CASSETTE_filename);
}
else if (protect)
CASSETTE_ToggleWriteProtect();
}
return TRUE;
}
void CASSETTE_Exit(void)
{
CASSETTE_Remove();
}
int CASSETTE_Insert(const char *filename)
{
int writable;
char const *description;
IMG_TAPE_t *file = IMG_TAPE_Open(filename, &writable, &description);
if (file == NULL)
return FALSE;
CASSETTE_Remove();
cassette_file = file;
/* Guard against providing CASSETTE_filename as parameter. */
if (CASSETTE_filename != filename)
strcpy(CASSETTE_filename, filename);
eof_of_tape = 0;
CASSETTE_status = (writable ? CASSETTE_STATUS_READ_WRITE : CASSETTE_STATUS_READ_ONLY);
event_time_left = 0;
pending_serin = FALSE;
passing_gap = FALSE;
if (description != NULL)
Util_strlcpy(CASSETTE_description, description, sizeof(CASSETTE_description));
CASSETTE_write_protect = FALSE;
CASSETTE_record = FALSE;
UpdateFlags();
cassette_gapdelay = 0;
return TRUE;
}
void CASSETTE_Remove(void)
{
if (cassette_file != NULL) {
IMG_TAPE_Close(cassette_file);
cassette_file = NULL;
}
CASSETTE_status = CASSETTE_STATUS_NONE;
CASSETTE_description[0] = '\0';
UpdateFlags();
}
int CASSETTE_CreateCAS(const char *filename, const char *description) {
IMG_TAPE_t *file = IMG_TAPE_Create(filename, description);
if (file == NULL)
return FALSE;
CASSETTE_Remove(); /* Unmount any previous tape image. */
cassette_file = file;
Util_strlcpy(CASSETTE_filename, filename, sizeof(CASSETTE_filename));
if (description != NULL)
Util_strlcpy(CASSETTE_description, description, sizeof(CASSETTE_description));
CASSETTE_status = CASSETTE_STATUS_READ_WRITE;
event_time_left = 0;
pending_serin = FALSE;
passing_gap = FALSE;
cassette_gapdelay = 0;
eof_of_tape = 0;
CASSETTE_record = TRUE;
CASSETTE_write_protect = FALSE;
UpdateFlags();
return TRUE;
}
unsigned int CASSETTE_GetPosition(void)
{
if (cassette_file == NULL)
return 0;
return IMG_TAPE_GetPosition(cassette_file) + 1;
}
unsigned int CASSETTE_GetSize(void)
{
if (cassette_file == NULL)
return 0;
return IMG_TAPE_GetSize(cassette_file);
}
void CASSETTE_Seek(unsigned int position)
{
if (cassette_file != NULL) {
if (position > 0)
position --;
IMG_TAPE_Seek(cassette_file, position);
event_time_left = 0;
pending_serin = FALSE;
passing_gap = FALSE;
eof_of_tape = 0;
CASSETTE_record = FALSE;
UpdateFlags();
}
}
int CASSETTE_GetByte(void)
{
return serin_byte;
}
int CASSETTE_IOLineStatus(void)
{
/* if motor off and EOF return always 1 (equivalent the mark tone) */
if (!CASSETTE_readable || CASSETTE_record) {
return 1;
}
return IMG_TAPE_SerinStatus(cassette_file, event_time_left);
}
void CASSETTE_PutByte(int byte)
{
if (!ESC_enable_sio_patch && CASSETTE_writable && CASSETTE_record)
IMG_TAPE_WriteByte(cassette_file, byte, POKEY_AUDF[POKEY_CHAN3] + POKEY_AUDF[POKEY_CHAN4]*0x100);
}
void CASSETTE_TapeMotor(int onoff)
{
if (cassette_motor != onoff) {
if (CASSETTE_record && CASSETTE_writable)
/* Recording disabled, flush the tape */
IMG_TAPE_Flush(cassette_file);
cassette_motor = onoff;
UpdateFlags();
}
}
int CASSETTE_ToggleWriteProtect(void)
{
if (CASSETTE_status != CASSETTE_STATUS_READ_WRITE)
return FALSE;
CASSETTE_write_protect = !CASSETTE_write_protect;
UpdateFlags();
return TRUE;
}
int CASSETTE_ToggleRecord(void)
{
if (CASSETTE_status == CASSETTE_STATUS_NONE)
return FALSE;
CASSETTE_record = !CASSETTE_record;
if (CASSETTE_record)
eof_of_tape = FALSE;
else if (CASSETTE_writable)
/* Recording disabled, flush the tape */
IMG_TAPE_Flush(cassette_file);
event_time_left = 0;
pending_serin = FALSE;
passing_gap = FALSE;
UpdateFlags();
/* Return FALSE to indicate that recording will not work. */
return !CASSETTE_record || (CASSETTE_status == CASSETTE_STATUS_READ_WRITE && !CASSETTE_write_protect);
}
static void CassetteWrite(int num_ticks)
{
if (CASSETTE_writable)
IMG_TAPE_WriteAdvance(cassette_file, num_ticks);
}
/* Sets the stamp of next SERIN IRQ event and loads new record if necessary.
Returns TRUE if a new byte was loaded and POKEY_SERIN should be updated.
The function assumes that current_block <= max_block. */
static int CassetteRead(int num_ticks)
{
if (CASSETTE_readable) {
int loaded = FALSE; /* Function's return value */
event_time_left -= num_ticks;
while (event_time_left < 0) {
unsigned int length;
if (!passing_gap && pending_serin) {
serin_byte = pending_serin_byte;
/* A byte is loaded, return TRUE so it gets stored in POKEY_SERIN. */
loaded = TRUE;
}
/* If POKEY is in reset state, no serial I/O occurs. */
pending_serin = (POKEY_SKCTL & 0x03) != 0;
if (!IMG_TAPE_Read(cassette_file, &length, &passing_gap, &pending_serin_byte)) {
eof_of_tape = 1;
UpdateFlags();
return loaded;
}
event_time_left += length;
}
return loaded;
}
return FALSE;
}
int CASSETTE_AddScanLine(void)
{
/* increment elapsed cassette time */
if (CASSETTE_record) {
CassetteWrite(114);
return FALSE;
} else
return CassetteRead(114);
}
void CASSETTE_ResetPOKEY(void)
{
/* Resetting POKEY stops any serial transmission. */
pending_serin = FALSE;
pending_serin_byte = 0xff;
}
/* --- Functions for loading/saving with SIO patch --- */
int CASSETTE_AddGap(int gaptime)
{
cassette_gapdelay += gaptime;
if (cassette_gapdelay < 0)
cassette_gapdelay = 0;
return cassette_gapdelay;
}
/* Indicates that a loading leader is expected by the OS */
void CASSETTE_LeaderLoad(void)
{
if (CASSETTE_record)
CASSETTE_ToggleRecord();
CASSETTE_TapeMotor(TRUE);
cassette_gapdelay = 9600;
/* registers for SETVBV: third system timer, ~0.1 sec */
CPU_regA = 3;
CPU_regX = 0;
CPU_regY = 5;
}
/* indicates that a save leader is written by the OS */
void CASSETTE_LeaderSave(void)
{
if (!CASSETTE_record)
CASSETTE_ToggleRecord();
CASSETTE_TapeMotor(TRUE);
cassette_gapdelay = 19200;
/* registers for SETVBV: third system timer, ~0.1 sec */
CPU_regA = 3;
CPU_regX = 0;
CPU_regY = 5;
}
int CASSETTE_ReadToMemory(UWORD dest_addr, int length)
{
CASSETTE_TapeMotor(1);
if (!CASSETTE_readable)
return 0;
/* Convert wait_time to ms ( wait_time * 1000 / 1789790 ) and subtract. */
cassette_gapdelay -= event_time_left / 1789; /* better accuracy not needed */
if (!IMG_TAPE_SkipToData(cassette_file, cassette_gapdelay)) {
/* Ignore the eventual error, assume it is the end of file */
cassette_gapdelay = 0;
eof_of_tape = 1;
UpdateFlags();
return 0;
}
cassette_gapdelay = 0;
/* Load bytes */
switch (IMG_TAPE_ReadToMemory(cassette_file, dest_addr, length)) {
case TRUE:
return TRUE;
case -1: /* Read error/EOF */
eof_of_tape = 1;
UpdateFlags();
/* FALLTHROUGH */
default: /* case FALSE */
return FALSE;
}
}
int CASSETTE_WriteFromMemory(UWORD src_addr, int length)
{
int result;
CASSETTE_TapeMotor(1);
if (!CASSETTE_writable)
return 0;
result = IMG_TAPE_WriteFromMemory(cassette_file, src_addr, length, cassette_gapdelay);
cassette_gapdelay = 0;
return result;
}
/*
vim:ts=4:sw=4:
*/
+95
View File
@@ -0,0 +1,95 @@
#ifndef CASSETTE_H_
#define CASSETTE_H_
#include <stdio.h> /* for FILE and FILENAME_MAX */
#include "atari.h" /* for UBYTE */
#define CASSETTE_DESCRIPTION_MAX 256
extern char CASSETTE_filename[FILENAME_MAX];
extern char CASSETTE_description[CASSETTE_DESCRIPTION_MAX];
typedef enum {
CASSETTE_STATUS_NONE,
CASSETTE_STATUS_READ_ONLY,
CASSETTE_STATUS_READ_WRITE
} CASSETTE_status_t;
extern CASSETTE_status_t CASSETTE_status;
/* Used in Atari800_Initialise during emulator initialisation */
int CASSETTE_Initialise(int *argc, char *argv[]);
void CASSETTE_Exit(void);
/* Config file read/write */
int CASSETTE_ReadConfig(char *string, char *ptr);
void CASSETTE_WriteConfig(FILE *fp);
/* Attaches a tape image. Also resets CASSETTE_write_protect to FALSE.
Returns TRUE on success, FALSE otherwise. */
int CASSETTE_Insert(const char *filename);
void CASSETTE_Remove(void);
/* Creates a new file in CAS format. DESCRIPTION can be NULL.
Returns TRUE on success, FALSE otherwise. */
int CASSETTE_CreateCAS(char const *filename, char const *description);
extern int CASSETTE_hold_start;
extern int CASSETTE_hold_start_on_reboot; /* preserve hold_start after reboot */
extern int CASSETTE_press_space;
/* Is cassette file write-protected? Don't change directly, use CASSETTE_ToggleWriteProtect(). */
extern int CASSETTE_write_protect;
/* Switches RO/RW. Fails with FALSE if the tape cannot be switched to RW. */
int CASSETTE_ToggleWriteProtect(void);
/* Is cassette record button pressed? Don't change directly, use CASSETTE_ToggleRecord(). */
extern int CASSETTE_record;
/* If tape is mounted, switches recording on/off (otherwise return FALSE).
Recording operations would fail if the tape is read-only. In such
situation, when switching recording on the function returns FALSE. */
int CASSETTE_ToggleRecord(void);
void CASSETTE_Seek(unsigned int position);
/* Returns status of the DATA IN line. */
int CASSETTE_IOLineStatus(void);
/* Get the byte which was recently loaded from tape. */
int CASSETTE_GetByte(void);
/* Put a byte into the cas file.
The block is being written at first putbyte of the subsequent block */
void CASSETTE_PutByte(int byte);
/* Set motor status: 1 - on, 0 - off */
void CASSETTE_TapeMotor(int onoff);
/* Advance the tape by a scanline. Return TRUE if a new byte has been loaded
and POKEY_SERIN must be updated. */
int CASSETTE_AddScanLine(void);
/* Reset cassette serial transmission; call when resseting POKEY by SKCTL. */
void CASSETTE_ResetPOKEY(void);
/* Return size in blocks of the currently-mounted tape file. */
unsigned int CASSETTE_GetSize(void);
/* Return current position (block number) of the mounted tape (counted from 1). */
unsigned int CASSETTE_GetPosition(void);
/* --- Functions used by patched SIO --- */
/* -- SIO_Handler() -- */
int CASSETTE_AddGap(int gaptime);
/* Reads a record from tape and copies its contents (max. LENGTH bytes,
excluding the trailing checksum) to memory starting at address DEST_ADDR.
Returns FALSE if number of bytes in record doesn't equal LENGTH, or
checksum is incorrect, or there was a read error/end of file; otherwise
returns TRUE. */
int CASSETTE_ReadToMemory(UWORD dest_addr, int length);
/* Reads LENGTH bytes from memory starting at SRC_ADDR and writes them as
a record (with added checksum) to tape. Returns FALSE if there was a write
error, TRUE otherwise. */
int CASSETTE_WriteFromMemory(UWORD src_addr, int length);
/* -- Other -- */
void CASSETTE_LeaderLoad(void);
void CASSETTE_LeaderSave(void);
/* Indicates whether the tape can be read from, ie. it's mounted and not on its
end. */
extern int CASSETTE_readable;
/* Indicates whether the tape can be written to, ie. it's mounted and not
read-only. */
extern int CASSETTE_writable;
#endif /* CASSETTE_H_ */
+488
View File
@@ -0,0 +1,488 @@
/*
* cfg.c - Emulator Configuration
*
* Copyright (c) 1995-1998 David Firth
* Copyright (c) 1998-2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "artifact.h"
#include "atari.h"
#include <stdlib.h>
#include "cartridge.h"
#include "cassette.h"
#include "binload.h"
#include "cfg.h"
#include "devices.h"
#include "esc.h"
#include "log.h"
#include "memory.h"
#include "pbi.h"
#include "rtime.h"
#include "sysrom.h"
#ifdef XEP80_EMULATION
#include "xep80.h"
#endif
#ifdef AF80
#include "af80.h"
#endif
#ifdef BIT3
#include "bit3.h"
#endif
#include "platform.h"
#include "pokeysnd.h"
#include "ui.h"
#include "util.h"
#if !defined(BASIC) && !defined(CURSES_BASIC)
#include "colours.h"
#include "screen.h"
#endif
#ifdef NTSC_FILTER
#include "filter_ntsc.h"
#endif
#if SUPPORTS_CHANGE_VIDEOMODE
#include "videomode.h"
#endif
#ifdef SOUND
#include "sound.h"
#endif
int CFG_save_on_exit = FALSE;
/* If another default path config path is defined use it
otherwise use the default one */
#ifndef DEFAULT_CFG_NAME
#define DEFAULT_CFG_NAME ".atari800.cfg"
#endif
#ifndef SYSTEM_WIDE_CFG_FILE
#define SYSTEM_WIDE_CFG_FILE "/etc/atari800.cfg"
#endif
static char rtconfig_filename[FILENAME_MAX];
int CFG_LoadConfig(const char *alternate_config_filename)
{
FILE *fp;
const char *fname = rtconfig_filename;
char string[256];
#ifndef BASIC
int was_obsolete_dir = FALSE;
#endif
#ifdef SUPPORTS_PLATFORM_CONFIGINIT
PLATFORM_ConfigInit();
#endif
/* if alternate config filename is passed then use it */
if (alternate_config_filename != NULL && *alternate_config_filename > 0) {
Util_strlcpy(rtconfig_filename, alternate_config_filename, FILENAME_MAX);
}
/* else use the default config name under the HOME folder */
else {
char *home = getenv("HOME");
if (home != NULL)
Util_catpath(rtconfig_filename, home, DEFAULT_CFG_NAME);
else
strcpy(rtconfig_filename, DEFAULT_CFG_NAME);
}
fp = fopen(fname, "r");
if (fp == NULL) {
Log_print("User config file '%s' not found.", rtconfig_filename);
#ifdef SYSTEM_WIDE_CFG_FILE
/* try system wide config file */
fname = SYSTEM_WIDE_CFG_FILE;
Log_print("Trying system wide config file: %s", fname);
fp = fopen(fname, "r");
#endif
if (fp == NULL) {
Log_print("No configuration file found, will create fresh one from scratch:");
return FALSE;
}
}
if (fgets(string, sizeof(string), fp) != NULL) {
Log_print("Using Atari800 config file: %s\nCreated by %s", fname, string);
}
while (fgets(string, sizeof(string), fp)) {
char *ptr;
Util_chomp(string);
ptr = strchr(string, '=');
if (ptr != NULL) {
*ptr++ = '\0';
Util_trim(string);
Util_trim(ptr);
if (SYSROM_ReadConfig(string, ptr)) {
}
#ifdef BASIC
else if (strcmp(string, "ATARI_FILES_DIR") == 0
|| strcmp(string, "SAVED_FILES_DIR") == 0
|| strcmp(string, "DISK_DIR") == 0 || strcmp(string, "ROM_DIR") == 0
|| strcmp(string, "EXE_DIR") == 0 || strcmp(string, "STATE_DIR") == 0)
/* do nothing */;
#else
else if (strcmp(string, "ATARI_FILES_DIR") == 0) {
if (UI_n_atari_files_dir >= UI_MAX_DIRECTORIES)
Log_print("All ATARI_FILES_DIR slots used!");
else
Util_strlcpy(UI_atari_files_dir[UI_n_atari_files_dir++], ptr, FILENAME_MAX);
}
else if (strcmp(string, "SAVED_FILES_DIR") == 0) {
if (UI_n_saved_files_dir >= UI_MAX_DIRECTORIES)
Log_print("All SAVED_FILES_DIR slots used!");
else
Util_strlcpy(UI_saved_files_dir[UI_n_saved_files_dir++], ptr, FILENAME_MAX);
}
else if (strcmp(string, "DISK_DIR") == 0 || strcmp(string, "ROM_DIR") == 0
|| strcmp(string, "EXE_DIR") == 0 || strcmp(string, "STATE_DIR") == 0) {
/* ignore blank and "." values */
if (ptr[0] != '\0' && (ptr[0] != '.' || ptr[1] != '\0'))
was_obsolete_dir = TRUE;
}
#endif
else if (strcmp(string, "H1_DIR") == 0)
Util_strlcpy(Devices_atari_h_dir[0], ptr, FILENAME_MAX);
else if (strcmp(string, "H2_DIR") == 0)
Util_strlcpy(Devices_atari_h_dir[1], ptr, FILENAME_MAX);
else if (strcmp(string, "H3_DIR") == 0)
Util_strlcpy(Devices_atari_h_dir[2], ptr, FILENAME_MAX);
else if (strcmp(string, "H4_DIR") == 0)
Util_strlcpy(Devices_atari_h_dir[3], ptr, FILENAME_MAX);
else if (strcmp(string, "HD_READ_ONLY") == 0)
Devices_h_read_only = Util_sscandec(ptr);
else if (strcmp(string, "PRINT_COMMAND") == 0) {
if (!Devices_SetPrintCommand(ptr))
Log_print("Unsafe PRINT_COMMAND ignored");
}
else if (strcmp(string, "SCREEN_REFRESH_RATIO") == 0)
Atari800_refresh_rate = Util_sscandec(ptr);
else if (strcmp(string, "DISABLE_BASIC") == 0)
Atari800_disable_basic = Util_sscanbool(ptr);
else if (strcmp(string, "ENABLE_SIO_PATCH") == 0) {
ESC_enable_sio_patch = Util_sscanbool(ptr);
}
else if (strcmp(string, "ENABLE_SLOW_XEX_LOADING") == 0) {
BINLOAD_slow_xex_loading = Util_sscanbool(ptr);
}
else if (strcmp(string, "ENABLE_H_PATCH") == 0) {
Devices_enable_h_patch = Util_sscanbool(ptr);
}
else if (strcmp(string, "ENABLE_P_PATCH") == 0) {
Devices_enable_p_patch = Util_sscanbool(ptr);
}
else if (strcmp(string, "ENABLE_R_PATCH") == 0) {
Devices_enable_r_patch = Util_sscanbool(ptr);
}
else if (strcmp(string, "ENABLE_NEW_POKEY") == 0) {
#ifdef SOUND
POKEYSND_enable_new_pokey = Util_sscanbool(ptr);
#endif /* SOUND */
}
else if (strcmp(string, "STEREO_POKEY") == 0) {
#ifdef STEREO_SOUND
POKEYSND_stereo_enabled = Util_sscanbool(ptr);
#ifdef SOUND_THIN_API
Sound_desired.channels = POKEYSND_stereo_enabled ? 2 : 1;
#endif /* SOUND_THIN_API */
#endif /* STEREO_SOUND */
}
else if (strcmp(string, "SPEAKER_SOUND") == 0) {
#ifdef CONSOLE_SOUND
POKEYSND_console_sound_enabled = Util_sscanbool(ptr);
#endif
}
else if (strcmp(string, "SERIO_SOUND") == 0) {
#ifdef SERIO_SOUND
POKEYSND_serio_sound_enabled = Util_sscanbool(ptr);
#endif
}
else if (strcmp(string, "MACHINE_TYPE") == 0) {
if (strcmp(ptr, "Atari 400/800") == 0 ||
/* Also recognise legacy values of this parameter */
strcmp(ptr, "Atari OS/A") == 0 ||
strcmp(ptr, "Atari OS/B") == 0)
Atari800_machine_type = Atari800_MACHINE_800;
else if (strcmp(ptr, "Atari XL/XE") == 0)
Atari800_machine_type = Atari800_MACHINE_XLXE;
else if (strcmp(ptr, "Atari 5200") == 0)
Atari800_machine_type = Atari800_MACHINE_5200;
else
Log_print("Invalid machine type: %s", ptr);
}
else if (strcmp(string, "RAM_SIZE") == 0) {
if (strcmp(ptr, "320 (RAMBO)") == 0)
MEMORY_ram_size = MEMORY_RAM_320_RAMBO;
else if (strcmp(ptr, "320 (COMPY SHOP)") == 0)
MEMORY_ram_size = MEMORY_RAM_320_COMPY_SHOP;
else {
int size = Util_sscandec(ptr);
if (MEMORY_SizeValid(size))
MEMORY_ram_size = size;
else
Log_print("Invalid RAM size: %s", ptr);
}
}
else if (strcmp(string, "DEFAULT_TV_MODE") == 0) {
if (strcmp(ptr, "PAL") == 0)
Atari800_tv_mode = Atari800_TV_PAL;
else if (strcmp(ptr, "NTSC") == 0)
Atari800_tv_mode = Atari800_TV_NTSC;
else
Log_print("Invalid TV Mode: %s", ptr);
}
else if (strcmp(string, "MOSAIC_RAM_NUM_BANKS") == 0) {
int num = Util_sscandec(ptr);
if (num >= 0 && num <= 64)
MEMORY_mosaic_num_banks = num;
else
Log_print("Invalid Mosaic RAM number of banks: %s", ptr);
}
else if (strcmp(string, "AXLON_RAM_NUM_BANKS") == 0) {
int num = Util_sscandec(ptr);
if (num == 0 || num == 8 || num == 16 || num == 32 || num == 64 || num == 128 || num == 256)
MEMORY_axlon_num_banks = num;
else
Log_print("Invalid Mosaic RAM number of banks: %s", ptr);
}
else if (strcmp(string, "ENABLE_MAPRAM") == 0)
MEMORY_enable_mapram = Util_sscanbool(ptr);
else if (strcmp(string, "BUILTIN_BASIC") == 0)
Atari800_builtin_basic = Util_sscanbool(ptr);
else if (strcmp(string, "KEYBOARD_LEDS") == 0)
Atari800_keyboard_leds = Util_sscanbool(ptr);
else if (strcmp(string, "F_KEYS") == 0)
Atari800_f_keys = Util_sscanbool(ptr);
else if (strcmp(string, "BUILTIN_GAME") == 0)
Atari800_builtin_game = Util_sscanbool(ptr);
else if (strcmp(string, "KEYBOARD_DETACHED") == 0)
Atari800_keyboard_detached = Util_sscanbool(ptr);
else if (strcmp(string, "1200XL_JUMPER") == 0)
Atari800_jumper = Util_sscanbool(ptr);
else if (strcmp(string, "CFG_SAVE_ON_EXIT") == 0) {
CFG_save_on_exit = Util_sscanbool(ptr);
}
/* Add module-specific configurations here */
else if (PBI_ReadConfig(string,ptr)) {
}
else if (CARTRIDGE_ReadConfig(string, ptr)) {
}
else if (CASSETTE_ReadConfig(string, ptr)) {
}
else if (RTIME_ReadConfig(string, ptr)) {
}
#ifdef XEP80_EMULATION
else if (XEP80_ReadConfig(string, ptr)) {
}
#endif
#ifdef AF80
else if (AF80_ReadConfig(string,ptr)) {
}
#endif
#ifdef BIT3
else if (BIT3_ReadConfig(string,ptr)) {
}
#endif
#if !defined(BASIC) && !defined(CURSES_BASIC)
else if (Colours_ReadConfig(string, ptr)) {
}
else if (ARTIFACT_ReadConfig(string, ptr)) {
}
else if (Screen_ReadConfig(string, ptr)) {
}
#endif
#ifdef NTSC_FILTER
else if (FILTER_NTSC_ReadConfig(string, ptr)) {
}
#endif
#if SUPPORTS_CHANGE_VIDEOMODE
else if (VIDEOMODE_ReadConfig(string, ptr)) {
}
#endif
#if defined(SOUND) && defined(SOUND_THIN_API)
else if (Sound_ReadConfig(string, ptr)) {
}
#endif /* defined(SOUND) && defined(SOUND_THIN_API) */
else {
#ifdef SUPPORTS_PLATFORM_CONFIGURE
if (!PLATFORM_Configure(string, ptr)) {
Log_print("Unrecognized variable or bad parameters: '%s=%s'", string, ptr);
}
#else
Log_print("Unrecognized variable: %s", string);
#endif
}
}
else {
Log_print("Ignored config line: %s", string);
}
}
fclose(fp);
#ifndef BASIC
if (was_obsolete_dir) {
Log_print(
"DISK_DIR, ROM_DIR, EXE_DIR and STATE_DIR configuration options\n"
"are no longer supported. Please use ATARI_FILES_DIR\n"
"and SAVED_FILES_DIR in your Atari800 configuration file.");
}
#endif
return TRUE;
}
int CFG_WriteConfig(void)
{
FILE *fp;
int i;
static const char * const machine_type_string[Atari800_MACHINE_SIZE] = {
"400/800", "XL/XE", "5200"
};
fp = fopen(rtconfig_filename, "w");
if (fp == NULL) {
perror(rtconfig_filename);
Log_print("Cannot write to config file: %s", rtconfig_filename);
return FALSE;
}
Log_print("Writing config file: %s", rtconfig_filename);
fprintf(fp, "%s\n", Atari800_TITLE);
SYSROM_WriteConfig(fp);
#ifndef BASIC
for (i = 0; i < UI_n_atari_files_dir; i++)
fprintf(fp, "ATARI_FILES_DIR=%s\n", UI_atari_files_dir[i]);
for (i = 0; i < UI_n_saved_files_dir; i++)
fprintf(fp, "SAVED_FILES_DIR=%s\n", UI_saved_files_dir[i]);
#endif
for (i = 0; i < 4; i++)
fprintf(fp, "H%c_DIR=%s\n", '1' + i, Devices_atari_h_dir[i]);
fprintf(fp, "HD_READ_ONLY=%d\n", Devices_h_read_only);
#ifdef HAVE_SYSTEM
fprintf(fp, "PRINT_COMMAND=%s\n", Devices_print_command);
#endif
#ifndef BASIC
fprintf(fp, "SCREEN_REFRESH_RATIO=%d\n", Atari800_refresh_rate);
#endif
fprintf(fp, "MACHINE_TYPE=Atari %s\n", machine_type_string[Atari800_machine_type]);
fprintf(fp, "RAM_SIZE=");
switch (MEMORY_ram_size) {
case MEMORY_RAM_320_RAMBO:
fprintf(fp, "320 (RAMBO)\n");
break;
case MEMORY_RAM_320_COMPY_SHOP:
fprintf(fp, "320 (COMPY SHOP)\n");
break;
default:
fprintf(fp, "%d\n", MEMORY_ram_size);
break;
}
fprintf(fp, (Atari800_tv_mode == Atari800_TV_PAL) ? "DEFAULT_TV_MODE=PAL\n" : "DEFAULT_TV_MODE=NTSC\n");
fprintf(fp, "MOSAIC_RAM_NUM_BANKS=%d\n", MEMORY_mosaic_num_banks);
fprintf(fp, "AXLON_RAM_NUM_BANKS=%d\n", MEMORY_axlon_num_banks);
fprintf(fp, "ENABLE_MAPRAM=%d\n", MEMORY_enable_mapram);
fprintf(fp, "DISABLE_BASIC=%d\n", Atari800_disable_basic);
fprintf(fp, "ENABLE_SIO_PATCH=%d\n", ESC_enable_sio_patch);
fprintf(fp, "ENABLE_SLOW_XEX_LOADING=%d\n", BINLOAD_slow_xex_loading);
fprintf(fp, "ENABLE_H_PATCH=%d\n", Devices_enable_h_patch);
fprintf(fp, "ENABLE_P_PATCH=%d\n", Devices_enable_p_patch);
#ifdef R_IO_DEVICE
fprintf(fp, "ENABLE_R_PATCH=%d\n", Devices_enable_r_patch);
#endif
#ifdef SOUND
fprintf(fp, "ENABLE_NEW_POKEY=%d\n", POKEYSND_enable_new_pokey);
#ifdef STEREO_SOUND
fprintf(fp, "STEREO_POKEY=%d\n", POKEYSND_stereo_enabled);
#endif
#ifdef CONSOLE_SOUND
fprintf(fp, "SPEAKER_SOUND=%d\n", POKEYSND_console_sound_enabled);
#endif
#ifdef SERIO_SOUND
fprintf(fp, "SERIO_SOUND=%d\n", POKEYSND_serio_sound_enabled);
#endif
#endif /* SOUND */
fprintf(fp, "BUILTIN_BASIC=%d\n", Atari800_builtin_basic);
fprintf(fp, "KEYBOARD_LEDS=%d\n", Atari800_keyboard_leds);
fprintf(fp, "F_KEYS=%d\n", Atari800_f_keys);
fprintf(fp, "BUILTIN_GAME=%d\n", Atari800_builtin_game);
fprintf(fp, "KEYBOARD_DETACHED=%d\n", Atari800_keyboard_detached);
fprintf(fp, "1200XL_JUMPER=%d\n", Atari800_jumper);
fprintf(fp, "CFG_SAVE_ON_EXIT=%d\n", CFG_save_on_exit);
/* Add module-specific configurations here */
PBI_WriteConfig(fp);
CARTRIDGE_WriteConfig(fp);
CASSETTE_WriteConfig(fp);
RTIME_WriteConfig(fp);
#ifdef XEP80_EMULATION
XEP80_WriteConfig(fp);
#endif
#ifdef AF80
AF80_WriteConfig(fp);
#endif
#ifdef BIT3
BIT3_WriteConfig(fp);
#endif
#if !defined(BASIC) && !defined(CURSES_BASIC)
Colours_WriteConfig(fp);
ARTIFACT_WriteConfig(fp);
Screen_WriteConfig(fp);
#endif
#ifdef NTSC_FILTER
FILTER_NTSC_WriteConfig(fp);
#endif
#if SUPPORTS_CHANGE_VIDEOMODE
VIDEOMODE_WriteConfig(fp);
#endif
#if defined(SOUND) && defined(SOUND_THIN_API)
Sound_WriteConfig(fp);
#endif /* defined(SOUND) && defined(SOUND_THIN_API) */
#ifdef SUPPORTS_PLATFORM_CONFIGSAVE
PLATFORM_ConfigSave(fp);
#endif
fclose(fp);
return TRUE;
}
int CFG_MatchTextParameter(char const *param, char const * const cfg_strings[], int cfg_strings_size)
{
int i;
for (i = 0; i < cfg_strings_size; i ++) {
if (Util_stricmp(param, cfg_strings[i]) == 0)
return i;
}
/* Unrecognised value */
return -1;
}
/*
vim:ts=4:sw=4:
*/
+19
View File
@@ -0,0 +1,19 @@
#ifndef CFG_H_
#define CFG_H_
/* Load Atari800 text configuration file. */
int CFG_LoadConfig(const char *alternate_config_filename);
/* Writes Atari800 text configuration file. */
int CFG_WriteConfig(void);
/* Controls whether the configuration file will be saved on emulator exit. */
extern int CFG_save_on_exit;
/* Compares the string PARAM with each entry in the CFG_STRINGS array
(of size CFG_STRINGS_SIZE), and returns index under which PARAM is found.
If PARAM does not exist in CFG_STRINGS, returns value lower than 0.
String comparison is case-insensitive. */
int CFG_MatchTextParameter(char const *param, char const * const cfg_strings[], int cfg_strings_size);
#endif /* CFG_H_ */

Some files were not shown because too many files have changed in this diff Show More