initial commit
@@ -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
|
||||
@@ -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)
|
||||
@@ -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, µ) != 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
|
||||
])
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -0,0 +1,3 @@
|
||||
ppc-amigaos-objs
|
||||
Atari800
|
||||
Atari800.debug
|
||||
@@ -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
|
||||
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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
|
||||
@@ -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...
|
||||
\ \/ /
|
||||
\__/
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
//-------------------------------------
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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)
|
||||
@@ -0,0 +1 @@
|
||||
APP_PLATFORM := android-9
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
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>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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 © 1995-1998 <i>David Firth</i><br>
|
||||
Copyright © 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>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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_ */
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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_ */
|
||||