--- /dev/null
+obj/
+pix/
+gmon.out
+legend
+legend.log
--- /dev/null
+#
+# Unified Makefile for Apple 2 SDL
+#
+# by James Hammons
+# (C) 2014 Underground Software
+# This software is licensed under the GPL v3
+#
+
+FIND = find
+FINDSDL2 := $(shell which $(CROSS)sdl2-config 2> /dev/null)
+
+# Figure out which system we're compiling for, and set the appropriate variables
+
+ifeq "$(CROSS)" ""
+OSTYPE := $(shell uname -a)
+
+# Win32
+ifeq "$(findstring Msys,$(OSTYPE))" "Msys"
+
+SYSTYPE = __GCCWIN32__
+EXESUFFIX = .exe
+ICON = obj/icon.o
+SDLLIBTYPE = --libs
+MSG = Win32 on MinGW
+
+# Should catch both 'darwin' and 'darwin7.0'
+else ifeq "$(findstring Darwin,$(OSTYPE))" "Darwin"
+
+SYSTYPE = __GCCUNIX__ -D_OSX_
+EXESUFFIX =
+ICON =
+SDLLIBTYPE = --static-libs
+MSG = Mac OS X
+
+# *nix
+else ifeq "$(findstring Linux,$(OSTYPE))" "Linux"
+
+SYSTYPE = __GCCUNIX__
+EXESUFFIX =
+ICON =
+SDLLIBTYPE = --libs
+MSG = generic Unix/Linux
+
+# Throw error, unknown OS
+else
+
+$(error OS TYPE UNDETECTED)
+
+endif
+# Cross compile using MXE under Linux host
+else
+
+SYSTYPE = __GCCWIN32__
+EXESUFFIX = .exe
+ICON = obj/icon.o
+SDLLIBTYPE = --libs
+MSG = Win32 under MXE (cross compile)
+
+endif
+
+CC = $(CROSS)gcc
+LD = $(CROSS)gcc
+TARGET = legend
+
+SDL_CFLAGS = `$(CROSS)sdl2-config --cflags`
+SDL_LIBS = `$(CROSS)sdl2-config $(SDLLIBTYPE)` -lSDL2_image
+DEFINES = -D$(SYSTYPE)
+GCC_DEPS = -MMD
+
+# Note that we use optimization level 2 instead of 3--3 doesn't seem to gain much over 2
+#CFLAGS = -MMD -Wall -Wno-switch -O2 -D$(SYSTYPE) -ffast-math -fomit-frame-pointer `sdl2-config --cflags`
+#CPPFLAGS = -MMD -Wall -Wno-switch -Wno-non-virtual-dtor -O2 -D$(SYSTYPE) \
+# No optimization and w/gcov flags, so that we get an accurate picture from gcov
+#CFLAGS = -MMD -Wall -Wno-switch -D$(SYSTYPE) \
+# -ffast-math -fomit-frame-pointer `sdl2-config --cflags` -fprofile-arcs -ftest-coverage
+#CPPFLAGS = -MMD -Wall -Wno-switch -Wno-non-virtual-dtor -D$(SYSTYPE) \
+# -ffast-math -fomit-frame-pointer `sdl2-config --cflags` -fprofile-arcs -ftest-coverage
+# No optimization for profiling with gprof...
+#CFLAGS = -MMD -Wall -Wno-switch -D$(SYSTYPE) \
+# -ffast-math `sdl2-config --cflags` -pg -g
+#CPPFLAGS = -MMD -Wall -Wno-switch -Wno-non-virtual-dtor -D$(SYSTYPE) \
+# -ffast-math `sdl2-config --cflags` -pg -g
+# -fomit-frame-pointer `sdl2-config --cflags` -g
+# -fomit-frame-pointer `sdl2-config --cflags` -DLOG_UNMAPPED_MEMORY_ACCESSES
+CFLAGS = $(GCC_DEPS) -Wall -Wno-switch $(DEFINES) -ffast-math $(SDL_CFLAGS) -pg -g
+CPPFLAGS = $(GCC_DEPS) -Wall -Wno-switch -Wno-non-virtual-dtor $(DEFINES) \
+ -ffast-math $(SDL_CFLAGS) -pg -g
+
+LDFLAGS =
+
+#LIBS = -L/usr/local/lib -L/usr/lib `sdl2-config $(SDLLIBTYPE)` -lstdc++ -lz $(GLLIB)
+# Link in the gcov library (for profiling purposes)
+#LIBS = -L/usr/local/lib -L/usr/lib `sdl2-config $(SDLLIBTYPE)` -lstdc++ -lz $(GLLIB) -lgcov
+# Link in the gprof lib
+#LIBS = -L/usr/local/lib -L/usr/lib `sdl2-config $(SDLLIBTYPE)` -lstdc++ -lz $(GLLIB) -pg
+#LIBS = -L/usr/local/lib -L/usr/lib $(SDL_LIBS) -lstdc++ -lz $(GLLIB) -pg
+LIBS = $(SDL_LIBS) -lstdc++ -lz $(GLLIB) -pg
+
+#INCS = -I. -I./src -I/usr/local/include -I/usr/include
+INCS = -I. -I./src
+
+OBJS = \
+ obj/data.o \
+ obj/log.o \
+ obj/sound.o \
+ obj/sprite.o \
+ obj/tile.o \
+ obj/video.o \
+ obj/legend.o \
+ $(ICON)
+
+all: checkenv message obj $(TARGET)$(EXESUFFIX)
+ @echo
+ @echo -e "\033[01;33m***\033[00;32m Looks like it compiled OK... Give it a whirl!\033[00m"
+
+# Check the compilation environment, barf if not appropriate
+
+checkenv:
+ @echo
+ @echo -en "\033[01;33m***\033[00;32m Checking compilation environment... \033[00m"
+ifeq "$(FINDSDL2)" ""
+ @echo
+ @echo
+ @echo -e "\033[01;33mIt seems that you don't have the SDL 2 development libraries installed. If you"
+ @echo -e "have installed them, make sure that the sdl2-config file is somewhere in your"
+ @echo -e "path and is executable.\033[00m"
+ @echo
+#Is there a better way to break out of the makefile?
+ @false;
+# @break
+# YES! But ignores all the echo's above... :-/
+#$(error SDL2 MISSING)
+
+else
+ @echo -e "\033[01;37mOK\033[00m"
+endif
+
+message:
+ @echo
+ @echo -e "\033[01;33m***\033[00;32m Building Legend of Ayeron SDL2 for $(MSG)...\033[00m"
+ @echo
+
+clean:
+ @echo -en "\033[01;33m***\033[00;32m Cleaning out the garbage...\033[00m"
+ @rm -rf obj
+ @rm -f ./$(TARGET)$(EXESUFFIX)
+ @echo -e "\033[01;37mdone!\033[00m"
+
+obj:
+ @mkdir obj
+
+# This is only done for Win32 at the moment...
+
+ifneq "" "$(ICON)"
+$(ICON): res/$(TARGET).rc res/$(TARGET).ico
+ @echo -e "\033[01;33m***\033[00;32m Processing icon...\033[00m"
+ @$(CROSS)windres -i res/$(TARGET).rc -o $(ICON) --include-dir=./res
+endif
+
+obj/%.o: src/%.c
+ @echo -e "\033[01;33m***\033[00;32m Compiling $<...\033[00m"
+ @$(CC) $(CFLAGS) $(INCS) -c $< -o $@
+
+obj/%.o: src/%.cpp
+ @echo -e "\033[01;33m***\033[00;32m Compiling $<...\033[00m"
+ @$(CC) $(CPPFLAGS) $(INCS) -c $< -o $@
+
+#GUI compilation...
+obj/%.o: src/gui/%.cpp
+ @echo -e "\033[01;33m***\033[00;32m Compiling $<...\033[00m"
+ @$(CC) $(CPPFLAGS) $(INCS) -c $< -o $@
+
+$(TARGET)$(EXESUFFIX): $(OBJS)
+ @echo -e "\033[01;33m***\033[00;32m Linking it all together...\033[00m"
+ @$(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+# strip --strip-all vj$(EXESUFFIX)
+# upx -9 vj$(EXESUFFIX)
+
+statistics:
+ @echo -n "Lines in source files: "
+ @-$(FIND) ./src -name "*.cpp" | xargs cat | wc -l
+ @echo -n "Lines in header files: "
+ @-$(FIND) ./src -name "*.h" | xargs cat | wc -l
+
+# Pull in dependencies autogenerated by gcc's -MMD switch
+# The "-" in front in there just in case they haven't been created yet
+
+-include obj/*.d
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.0" orientation="orthogonal" renderorder="right-down" width="20" height="16" tilewidth="16" tileheight="16">
+ <tileset firstgid="1" name="tilemap1" tilewidth="16" tileheight="16">
+ <image source="tilemap1.png" width="256" height="256"/>
+ </tileset>
+ <layer name="Tile Layer 1" width="20" height="16">
+ <data encoding="base64" compression="zlib">
+ eJzV0ssKABAQheFxCW/g/d/USkmcuZWy+BcWPtMkEFFQlg13pF5b+tGLhzgPvT2NBLyq9NDZur8i3J9kzrJ087rCQ/PlLc7j9mfx0H+pW15POx/XzfP00hxa8gKT
+ </data>
+ </layer>
+</map>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.0" orientation="orthogonal" renderorder="right-down" width="64" height="64" tilewidth="8" tileheight="8">
+ <tileset firstgid="1" name="g2-tiles1" tilewidth="8" tileheight="8">
+ <image source="g2-tiles1.png" width="64" height="248"/>
+ </tileset>
+ <tileset firstgid="249" name="g2-sprites1" tilewidth="24" tileheight="24">
+ <tileoffset x="-4" y="0"/>
+ <image source="../../gauntlet-ng/res/g2-sprites1.png" width="72" height="480"/>
+ </tileset>
+ <tileset firstgid="309" name="g2-sprites-2x2" tilewidth="16" tileheight="16">
+ <tileoffset x="0" y="4"/>
+ <image source="../../gauntlet-ng/res/g2-sprites-2x2.png" width="72" height="480"/>
+ </tileset>
+ <layer name="Tile Layer 1" width="64" height="64">
+ <data encoding="base64" compression="zlib">
+ eJztmrmO1EAQhgtY7nM5lmuBheVmd5b7RsBCuBI3CQkkQICQCJDIAAlCXgAiIohA4nwJEu77PgMQJOT8LVxyT7lr3J6xZ3q0G/wq2W2P7f6qqsvluU5El6AN0MZ+aM9A16AL0EVoUz/TZmgLNBsaDA3ysOOs7ZFVnheK5eefDrVAQ4SdC82DZkIlaIYy3m6NL49sSVjX7zfa8vPPUeZnBbQS2gptg6Yo42ugtZZl3YHuQq1U2Q/GRvvHUtK/RhXAXfKXfIZDI6BV0GpoO9QLtUXjoyPL4+ug9Za9Al2F7kH3oYkpHMZDEyw7xLrOmAK4S/4c/0OhYTnMv29ekdeT/iDvQ/OTvPgzdzn/HOeu+GZeNjdXXrHHpZ9p/iDvQ/OTPPjbHJgLW45zXjddce2a144U7pKnvG7ReYDvc6bgwFxkHuB10+QDE9dd0EJK5o80/vy7kqe8btF5QOZ/nmfJR5u/HdBOKo/zcaTzl5zlfnl9LS/k5Q8y/nmeJR+er0XQYvq/3reI820+Wl0hOcv98vpaXsjLH2xOPnn4KHSM4jqgD9pNyfpB8ytfjvK6clvzj2r5tyvzvYDK4/s4dJviOmAftIuS64D9u674TeMo/U5ua/5RS/y74s4V37a9Ad2keB1gTrx/akYeGtd65H9X3LnqQ5vDA+gEtASaH/GeYO2fRsl1vBIPjWvR+b9D8HPVcZXWgXPQeYr9SKvz09Z13/xeVP0n46yP4ji293dGvPk86Ue+fLPmBS0f5FX/y3pM8w/mzeel1XtZ+Wn8884DMk/Lesxex0sU9wHOWvt7rG3jD92KLTmuw+8V06PjuF7Q+OedB9K4nYIuU3of7TpV7iNq/YM90F7oAHQSmkVuP0mrC/PI/654Muu9Tx8trY9o3hd6ocmO+d8PHaTK9WJaXZhX/Nc6j/w7Mk61PG/OO2Q9f6tyvDyvqPxf6zxq8avleeNfh6Ej0GmK+0RpdWFR+b/WedTeI33f6+pdDxbNn+PV972u3vUg37fMu1kt1/syv6f1c3lbyw/1Wv+1/n+aNeu36Qdwvd8VbXcrXLW8oOWHeq3/1fKX/QC5rcWx5he+fb+8839W/gsizreovB/A/YFlVN4n0vo9kqtv3y/v/J+Vv8bZdzwUm5U/9/+Y+zTlOPaDpdHxpRo5FWWz8s/KNXQ/8OUv4z3te570gyVUvi40mntW/rVyDNUPfL7/+8S7rx9Ue36j+IfKrWj+Mt5D4+bKT+Y7RXvG8zT+zcb9I/SpivuV/GW8++b5oi3XHdxPNP2qHor7in+hL/S/3lgYjVfDP1TuD6FH0FOHXlPcN2I/mFQl/1Dz9GPoCfTMoTcU/w+B/YD7jPb3S+5DV7P+h27fQu8o2ccy/sB+YvyigyrzbzRnX9tJ8fdGs/0SekXJ/G/2f4DeK+PNyp/jnOOen1/yN/t/Q8+jcfk9OnT+nPc5nzN3jnNen/j5ZXx/pjhP2HmhWfhzXHNfWcvvX6FvVPv632je0kqunyOObeK479APyl6vhM6fn7+o+wuNv6k/51H8nfln9Pz8nXlGZLX7td8D5PfnZuAv6zyTt19Qst7T4vwjJetD17ofKn9Z55l1+wP0i8rrPS3OX4rjtXU/VP61xr+sA7S6IFT+afnf93h+P/xDcf5oRv5Z13Wu9+z84ar7moV/1nXdrvfsuk87P3T+RdvQ+RdtB/gP8B/gP8C/v/K3/8fb3Q/tP5LDTPM=
+ </data>
+ </layer>
+ <objectgroup name="Object Layer 1"/>
+ <layer name="Tile Layer 2" width="64" height="64">
+ <data encoding="base64" compression="zlib">
+ eJzt2E0KgzAQBlAHCv2xPU57/6N15cJg0FKlzeS9zYCryJcJkwwDrHvGr1dwsC//7xTLFVqSvs8PVvb9LZYr/+28U05yz+mxMU+5t8G81jf5923v/O8xr7Sttj/Gynf507JXzOtW2d8PrpX7PblcYl4nU/7lPgD6VZ4T9KGc/2v3AXJZ63fzQU6f9rfzIAf93Ce598m7DgAAAAAALXsDk5UCeA==
+ </data>
+ </layer>
+</map>
--- /dev/null
+//
+// Game data
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 08/21/2014 Created this file
+//
+
+#include "data.h"
+
+
+// We use anonymous structs and cast these to Maps to be able to access them.
+
+static const struct {
+ unsigned int width, height;
+ uint16_t n, s, e, w, special;
+ unsigned char state[16 * 11 + 1];
+} map000 = { 16, 11,
+ 1, 0, 2, 3, 0,
+ "1111111100111177"
+ "1111211100111177"
+ "1111000000111117"
+ "1111000000011111"
+ "0000000000001111"
+ "0000000000000111"
+ "1111000050000000"
+ "1111000000000000"
+ "1111000000001111"
+ "1111111101111111"
+ "1111111111111111"
+};
+
+static const struct {
+ unsigned int width, height;
+ uint16_t n, s, e, w, special;
+ unsigned char state[16 * 11 + 1];
+} map001 = { 16, 11,
+ 0, 0, 0, 0, 0,
+ "1111111111111111"
+ "1111111111111111"
+ "1111000000111111"
+ "1111000000011111"
+ "1100000000001111"
+ "1100000000000111"
+ "1111000050000011"
+ "1111000000000011"
+ "1111000000001117"
+ "1111111100111177"
+ "1111111100111177"
+};
+
+static const struct {
+ unsigned int width, height;
+ uint16_t n, s, e, w, special;
+ unsigned char state[16 * 11 + 1];
+} map002 = { 16, 11,
+ 0, 0, 0, 0, 0,
+ "1111111111111111"
+ "1111111111111111"
+ "1111000000111111"
+ "1111000000011111"
+ "1100000000001111"
+ "1100000000000111"
+ "0000000000000011"
+ "0000000000000011"
+ "1111000000001111"
+ "1111111111111111"
+ "1111111111111111"
+};
+
+static const struct {
+ unsigned int width, height;
+ uint16_t n, s, e, w, special;
+ unsigned char state[16 * 11 + 1];
+} map003 = { 16, 11,
+ 0, 0, 0, 0, 0,
+ "1111111111111111"
+ "1111111111111111"
+ "1111000000111111"
+ "1111000000011111"
+ "1100005000000000"
+ "1100000000000000"
+ "1111000000000011"
+ "1111000000000011"
+ "1111000000001111"
+ "1111111111111111"
+ "1111111111111111"
+};
+
+
+static const struct {
+ unsigned int width, height;
+ uint16_t n, s, e, w, special;
+ unsigned char state[16 * 11 + 1];
+} room000 = { 16, 11,
+ 0, 0, 0, 0, 0,
+ "1111111111111111"
+ "1111111111111111"
+ "1144444444444411"
+ "1144444444444411"
+ "1144444444444411"
+ "1144444444444411"
+ "1144444444444411"
+ "1144444444444411"
+ "1144444444444411"
+ "1111111441111111"
+ "1111111441111111"
+};
+
+
+const void * maps[] = {
+ &map000, &map001, &map002, &map003
+};
+
+
+const void * rooms[] = {
+ &room000
+};
+
+
+// Misc. globals
+
+uint8_t roomState[256 * 256];
+uint16_t roomWidth, roomHeight;
+
+Map * mapSave = 0, * currentMap = 0;
+uint16_t pxSave, pySave;
+
--- /dev/null
+#ifndef __DATA_H__
+#define __DATA_H__
+
+#include <stdint.h>
+
+// Struct for casting
+struct Map
+{
+ int width;
+ int height;
+ uint16_t n, s, e, w, special;
+ unsigned char tiles[];
+};
+
+#define NUMBER_OF_MAPS 1
+extern const void * maps[];
+
+#define NUMBER_OF_ROOMS 1
+extern const void * rooms[];
+
+// Globals
+extern uint8_t roomState[];
+extern uint16_t roomWidth, roomHeight;
+
+extern Map * mapSave, * currentMap;
+extern uint16_t pxSave, pySave;
+
+#endif // __DATA_H__
+
--- /dev/null
+//
+// Legend of ?
+//
+// by James Hammons
+// © 2014 Underground Software
+//
+// A simple action RPG; a crass appeal to sentimentalism ;-)
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 08/13/2014 Created this file
+//
+
+// STILL TO DO:
+//
+//
+
+#include "legend.h"
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+#include <fstream>
+#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "log.h"
+#include "sprite.h"
+#include "tile.h"
+#include "sound.h"
+#include "video.h"
+
+// Debug and misc. defines
+
+//#define SOFT_SWITCH_DEBUGGING
+
+// Global variables
+
+//bool powerStateChangeRequested = false;
+
+// Local variables
+
+//uint8_t lastKeyPressed = 0;
+
+static bool running = true; // Machine running state flag...
+static uint32_t startTicks;
+static uint32_t frameCount;
+
+// Local functions (technically, they're global...)
+
+void DoGame(void);
+//bool LoadImg(char * filename, uint8_t * ram, int size);
+
+// Local timer callback functions
+
+//static void FrameCallback(void);
+//static void BlinkTimer(void);
+
+
+// Points of interest:
+// screen is 16 x 11, 16x16 tiles with status bar on top of screen
+// game follows main sprite's feet, main sprite can overlap background
+
+
+//
+// Main loop
+//
+int main(int /*argc*/, char * /*argv*/[])
+{
+ InitLog("./legend.log");
+ srand(time(NULL)); // Initialize RNG
+
+ WriteLog("About to initialize video...\n");
+
+ if (!InitVideo())
+ {
+ printf("Aborting!\n");
+ return -1;
+ }
+
+ if (!InitTileHandler())
+ {
+ printf("Aborting!\n");
+ VideoDone();
+ return -1;
+ }
+
+ if (!InitSpriteHandler())
+ {
+ printf("Aborting!\n");
+ VideoDone();
+ return -1;
+ }
+
+ running = true; // Set running status...
+ WriteLog("Entering main loop...\n");
+
+ DoGame();
+
+ SoundDone();
+ VideoDone();
+ LogDone();
+
+ return 0;
+}
+
+
+void DoGame(void)
+{
+ startTicks = SDL_GetTicks();
+ bool running = true;
+ SDL_Texture * map1 = CreateMapTexture();
+ SDL_Texture * screen = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888,
+ SDL_TEXTUREACCESS_TARGET, 16 * 16, 11 * 16);
+
+ bool inRoom = false;
+ Direction playerFacing = Down;
+ int playerInput = Stopped;
+ uint16_t px = (8 * 16) << 7;
+ uint16_t py = (5 * 16) << 7;
+ int currentFrame = 0;
+ int frame[] = { 1,
+ 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ };
+
+ while (running)
+ {
+ SDL_Event event;
+
+ while (SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_KEYDOWN:
+ // Use ALT+Q to exit, as well as the usual window decoration
+ // method
+// if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod & KMOD_ALT))
+ if (event.key.keysym.sym == SDLK_ESCAPE)
+ running = false;
+ else if (event.key.keysym.sym == SDLK_z)
+ playerInput |= Left;
+ else if (event.key.keysym.sym == SDLK_c)
+ playerInput |= Right;
+ else if (event.key.keysym.sym == SDLK_s)
+ playerInput |= Up;
+ else if (event.key.keysym.sym == SDLK_x)
+ playerInput |= Down;
+
+ break;
+
+ case SDL_KEYUP:
+ if (event.key.keysym.sym == SDLK_z)
+ playerInput &= ~Left;
+ else if (event.key.keysym.sym == SDLK_c)
+ playerInput &= ~Right;
+ else if (event.key.keysym.sym == SDLK_s)
+ playerInput &= ~Up;
+ else if (event.key.keysym.sym == SDLK_x)
+ playerInput &= ~Down;
+
+ break;
+ }
+ }
+
+ uint8_t tile[2], tileUnder[4];
+ int dx = 0, dy = 0;
+
+ // Handle player input
+ if (playerInput & Left)
+ {
+ playerFacing = Left;
+ dx = -1;
+ }
+ else if (playerInput & Right)
+ {
+ playerFacing = Right;
+ dx = +1;
+ }
+ else if (playerInput & Up)
+ {
+ playerFacing = Up;
+ dy = -1;
+ }
+ else if (playerInput & Down)
+ {
+ playerFacing = Down;
+ dy = +1;
+ }
+ else
+ {
+ currentFrame = 0;
+ }
+
+ // Get the tiles the player is moving towards
+ GetTiles2(px >> 7, py >> 7, playerFacing, tile);
+ bool walk1 = (tile[0] == '0' || tile[0] == '4' || tile[0] == '2' || tile[0] == '6' ? true : false);
+ bool walk2 = (tile[1] == '0' || tile[1] == '4' || tile[1] == '2' || tile[1] == '6' ? true : false);
+
+ int curPx = px >> 7, curPy = py >> 7;
+ int tileX = curPx / 16, tileY = curPy / 16;
+ int tileXRem = curPx % 16, tileYRem = curPy % 16;
+ uint16_t newPx = px + (uint16_t)(dx * (3 << 6));
+ uint16_t newPy = py + (uint16_t)(dy * (3 << 6));
+ int newTileX = (newPx >> 7) / 16;
+ int newTileY = (newPy >> 7) / 16;
+
+ // Collision detection...
+ // Check to see if we're stepping on 2 tiles in the direction we're
+ // moving. If so, check to see what distance remains between where the
+ // player is and where he wants to be. If that distance is < the move
+ // delta, see if the tile he wants to move into can be moved into. If
+ // not, truncate the move so that he moves *exactly* into the next
+ // single space.
+ if (dx != 0)
+ {
+ // Check to see if way forward is clear...
+ if (walk1
+ && ((tileYRem == 0) || ((tileYRem != 0) && walk2)))
+ px = newPx;
+ // It's blocked ahead, so see if there's still room to move forward.
+ // (only if we're standing on 2 tiles instead of 1!)
+ else if (tileXRem != 0)
+ {
+ // We didn't cross the tile boundary, so move normally.
+ if (newTileX == tileX)
+ px = newPx;
+ // We're trying to cross the boundary, so clamp it to the edge.
+ else
+ px = ((tileX + (dx == 1 ? 1 : 0)) * 16) << 7;
+ }
+ else
+ {
+ // Player is stuck at tileXRem == 0, so see if we can nudge
+ // them up or down...
+ if (walk1 && (tileYRem < 8))
+ py = (py - (1 << 7)) & 0xFF80;
+ else if (walk2 && (tileYRem > 7))
+ py = (py + (1 << 7)) & 0xFF80;
+ }
+ }
+ else if (dy != 0)
+ {
+ // Check to see if way forward is clear...
+ if (walk1
+ && ((tileXRem == 0) || ((tileXRem != 0) && walk2)))
+ py = newPy;
+ // It's blocked ahead, so see if there's still room to move forward.
+ // (only if we're standing on 2 tiles instead of 1!)
+ else if (tileYRem != 0)
+ {
+ // We didn't cross the tile boundary, so move normally.
+ if (newTileY == tileY)
+ py = newPy;
+ // We're trying to cross the boundary, so clamp it to the edge.
+ else
+ py = ((tileY + (dy == 1 ? 1 : 0)) * 16) << 7;
+ }
+ else
+ {
+ // Player is stuck at tileYRem == 0, so see if we can nudge
+ // them left or right...
+ if (walk1 && (tileXRem < 8))
+ px = (px - (1 << 7)) & 0xFF80;
+ else if (walk2 && (tileXRem > 7))
+ px = (px + (1 << 7)) & 0xFF80;
+ }
+ }
+
+ // Now that we've moved, see what we're standing on
+ // Overlap should be taken into account so we don't have the 'Touch It
+ // And Die' (TIAD) syndrome of pixel perfect collisions...
+ GetTiles(px >> 7, py >> 7, tileUnder);
+
+ // *. .* .. ..
+ // .. .. *. .*
+ // See which one of the 4 tiles the player is closest to
+ tileXRem = (px >> 7) % 16, tileYRem = (py >> 7) % 16;
+ int tileNum = 0;
+
+ if ((tileXRem < 7) && (tileYRem < 7))
+ tileNum = 0;
+ else if ((tileXRem > 9) && (tileYRem < 7))
+ tileNum = 1;
+ else if ((tileXRem < 7) && (tileYRem > 9))
+ tileNum = 2;
+ else if ((tileXRem > 9) && (tileYRem > 9))
+ tileNum = 3;
+
+ // Special tile handling
+ if ((tileUnder[tileNum] == '2') && (dy == -1))
+ {
+ mapSave = currentMap;
+ pxSave = px & 0xF800;
+ pySave = py & 0xF800;
+ uint16_t roomToEnter = currentMap->special;
+ inRoom = true;
+ RenderMap((Map *)rooms[roomToEnter], map1);
+ px = ((7 * 16) + 8) << 7;
+ py = ((10 * 16) - 0) << 7;
+ }
+
+ // Check for moving to the next map screen handling
+ if ((dy == 1) && (py >= ((10 * 16) << 7)))
+ {
+ if (inRoom)
+ {
+ inRoom = false;
+ RenderMap(mapSave, map1);
+ px = pxSave, py = pySave;
+ }
+ else
+ {
+ uint16_t dir = currentMap->s;
+ RenderMap((Map *)maps[dir], map1);
+ py = 0;
+ }
+ }
+ else if ((dy == -1) && ((py & 0xFF80) == 0))
+ {
+ uint16_t dir = currentMap->n;
+ RenderMap((Map *)maps[dir], map1);
+ py = (10 * 16) << 7;
+ }
+ else if ((dx == 1) && (px >= ((15 * 16) << 7)))
+ {
+ uint16_t dir = currentMap->e;
+ RenderMap((Map *)maps[dir], map1);
+ px = 0;
+ }
+ else if ((dx == -1) && ((px & 0xFF80) == 0))
+ {
+ uint16_t dir = currentMap->w;
+ RenderMap((Map *)maps[dir], map1);
+ px = (15 * 16) << 7;
+ }
+
+ // Do rendering...
+ SDL_SetRenderTarget(sdlRenderer, screen);
+ // This should be limited to the visible window...
+ SDL_RenderCopy(sdlRenderer, map1, NULL, NULL);
+// DrawPlayerSprite(playerFacing, px, py);
+ DrawUnderlay(px >> 7, py >> 7, playerFacing);
+ DrawPlayerSprite2(px >> 7, py >> 7, playerFacing, frame[currentFrame]);
+ // Reset main renderer to main window
+ SDL_SetRenderTarget(sdlRenderer, NULL);
+ SDL_RenderCopy(sdlRenderer, screen, NULL, NULL);
+ SDL_RenderPresent(sdlRenderer);
+
+ // Animation handling...
+ currentFrame = (currentFrame + 1) % 24;
+
+ // In order to get our delay to come out approximately 60 Hz, we need to
+ // add in an extra ms every 3 frames. So this handles that problem. :-)
+ frameCount = (frameCount + 1) % 3;
+ uint32_t interval = (frameCount == 0 ? 16 : 17);
+
+ // We'll try to keep this running at 60 Hz...
+ while ((SDL_GetTicks() - startTicks) < interval)
+ SDL_Delay(1);
+
+ startTicks = SDL_GetTicks();
+ }
+
+ SDL_DestroyTexture(map1);
+}
+
+
--- /dev/null
+#ifndef __LEGEND_H__
+#define __LEGEND_H__
+
+//
+// Legend of Alden(?) v1.0
+//
+// by James Hammons
+//
+
+enum Direction { Stopped=0, Left=1, Right=2, Up=4, Down=8 };
+
+#include <stdint.h>
+
+// Exported functions
+
+//void SetPowerState(void);
+
+// Global variables (exported)
+
+#if 0
+extern uint8_t ram[0x10000], rom[0x10000]; // RAM & ROM pointers
+extern uint8_t ram2[0x10000]; // Auxillary RAM
+extern uint8_t appleType;
+extern FloppyDrive floppyDrive;
+extern uint8_t lastKeyPressed;
+extern bool keyDown;
+extern bool openAppleDown;
+extern bool closedAppleDown;
+extern bool store80Mode;
+extern bool vbl;
+extern bool slotCXROM;
+extern bool slotC3ROM;
+extern bool ramrd;
+extern bool ramwrt;
+extern bool altzp;
+extern bool ioudis;
+extern bool dhires;
+extern uint8_t lcState;
+#endif
+
+#endif // __LEGEND_H__
+
--- /dev/null
+//
+// Log handler
+//
+// by James Hammons
+// (C) 2006 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 01/03/2006 Moved includes out of header file for faster compilation
+//
+
+#include "log.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+// Maximum size of log file (10 MB ought to be enough for anybody)
+#define MAX_LOG_SIZE 10000000
+
+static FILE * log_stream = NULL;
+static uint32_t logSize = 0;
+
+
+bool InitLog(const char * path)
+{
+ log_stream = fopen(path, "wrt");
+
+ if (log_stream == NULL)
+ return false;
+
+ return true;
+}
+
+
+void LogDone(void)
+{
+ if (log_stream)
+ fclose(log_stream);
+}
+
+
+//
+// This logger is used mainly to ensure that text gets written to the log file
+// even if the program crashes. The performance hit is acceptable in this case!
+//
+void WriteLog(const char * text, ...)
+{
+ if (!log_stream)
+ return;
+
+ va_list arg;
+
+ va_start(arg, text);
+ logSize += vfprintf(log_stream, text, arg);
+ va_end(arg);
+
+ fflush(log_stream); // Make sure that text is written!
+
+ if (logSize > MAX_LOG_SIZE)
+ {
+ fclose(log_stream);
+ log_stream = NULL;
+ }
+}
+
--- /dev/null
+//
+// LOG.H
+//
+
+#ifndef __LOG_H__
+#define __LOG_H__
+
+// Make this header work with either C or C++
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool InitLog(const char *);
+void LogDone(void);
+void WriteLog(const char * text, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LOG_H__
--- /dev/null
+//
+// Sound Interface
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 12/02/2005 Fixed a problem with sound callback thread signaling the
+// main thread
+// JLH 12/03/2005 Fixed sound callback dropping samples when the sample buffer
+// is shorter than the callback sample buffer
+//
+
+// STILL TO DO:
+//
+//
+
+#include "sound.h"
+
+#include <string.h> // For memset, memcpy
+#include <SDL2/SDL.h>
+#include "log.h"
+
+// Useful defines
+
+//#define DEBUG
+//#define WRITE_OUT_WAVE
+
+//#define SAMPLE_RATE (44100.0)
+#define SAMPLE_RATE (48000.0)
+#define SAMPLES_PER_FRAME (SAMPLE_RATE / 60.0)
+#define CYCLES_PER_SAMPLE (1024000.0 / SAMPLE_RATE)
+//#define SOUND_BUFFER_SIZE (8192)
+#define SOUND_BUFFER_SIZE (32768)
+
+// Global variables
+
+
+// Local variables
+
+static SDL_AudioSpec desired, obtained;
+static SDL_AudioDeviceID device;
+static bool soundInitialized = false;
+static bool speakerState = false;
+static int16_t soundBuffer[SOUND_BUFFER_SIZE];
+static uint32_t soundBufferPos;
+static uint64_t lastToggleCycles;
+static SDL_cond * conditional = NULL;
+static SDL_mutex * mutex = NULL;
+static SDL_mutex * mutex2 = NULL;
+static int16_t sample;
+static uint8_t ampPtr = 12; // Start with -2047 - +2047
+static int16_t amplitude[17] = { 0, 1, 2, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047,
+ 4095, 8191, 16383, 32767 };
+#ifdef WRITE_OUT_WAVE
+static FILE * fp = NULL;
+#endif
+
+// Private function prototypes
+
+static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
+
+
+//
+// Initialize the SDL sound system
+//
+void SoundInit(void)
+{
+#if 0
+// To weed out problems for now...
+return;
+#endif
+ SDL_zero(desired);
+ desired.freq = SAMPLE_RATE; // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
+ desired.format = AUDIO_S16SYS; // This uses the native endian (for portability)...
+ desired.channels = 1;
+ desired.samples = 512; // Let's try a 1/2K buffer (can always go lower)
+ desired.callback = SDLSoundCallback;
+
+ device = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
+
+ if (device == 0)
+ {
+ WriteLog("Sound: Failed to initialize SDL sound.\n");
+ return;
+ }
+
+ conditional = SDL_CreateCond();
+ mutex = SDL_CreateMutex();
+ mutex2 = SDL_CreateMutex();// Let's try real signalling...
+ soundBufferPos = 0;
+ lastToggleCycles = 0;
+ sample = desired.silence; // ? wilwok ? yes
+
+ SDL_PauseAudioDevice(device, 0); // Start playback!
+ soundInitialized = true;
+ WriteLog("Sound: Successfully initialized.\n");
+
+#ifdef WRITE_OUT_WAVE
+ fp = fopen("./apple2.wav", "wb");
+#endif
+}
+
+
+//
+// Close down the SDL sound subsystem
+//
+void SoundDone(void)
+{
+ if (soundInitialized)
+ {
+ SDL_PauseAudioDevice(device, 1);
+ SDL_CloseAudioDevice(device);
+ SDL_DestroyCond(conditional);
+ SDL_DestroyMutex(mutex);
+ SDL_DestroyMutex(mutex2);
+ WriteLog("Sound: Done.\n");
+
+#ifdef WRITE_OUT_WAVE
+ fclose(fp);
+#endif
+ }
+}
+
+
+void SoundPause(void)
+{
+ if (soundInitialized)
+ SDL_PauseAudioDevice(device, 1);
+}
+
+
+void SoundResume(void)
+{
+ if (soundInitialized)
+ SDL_PauseAudioDevice(device, 0);
+}
+
+
+//
+// Sound card callback handler
+//
+static void SDLSoundCallback(void * /*userdata*/, Uint8 * buffer8, int length8)
+{
+//WriteLog("SDLSoundCallback(): begin (soundBufferPos=%i)\n", soundBufferPos);
+ // The sound buffer should only starve when starting which will cause it to
+ // lag behind the emulation at most by around 1 frame...
+ // (Actually, this should never happen since we fill the buffer beforehand.)
+ // (But, then again, if the sound hasn't been toggled for a while, then this
+ // makes perfect sense as the buffer won't have been filled at all!)
+ // (Should NOT starve now, now that we properly handle frame edges...)
+
+ // Let's try using a mutex for shared resource consumption...
+//Actually, I think Lock/UnlockAudio() does this already...
+//WriteLog("SDLSoundCallback: soundBufferPos = %i\n", soundBufferPos);
+ SDL_mutexP(mutex2);
+
+ // Recast this as a 16-bit type...
+ int16_t * buffer = (int16_t *)buffer8;
+ uint32_t length = (uint32_t)length8 / 2;
+
+//WriteLog("SDLSoundCallback(): filling buffer...\n");
+ if (soundBufferPos < length)
+ {
+ // The sound buffer is starved...
+ for(uint32_t i=0; i<soundBufferPos; i++)
+ buffer[i] = soundBuffer[i];
+
+ // Fill buffer with last value
+ for(uint32_t i=soundBufferPos; i<length; i++)
+ buffer[i] = sample;
+
+ // Reset soundBufferPos to start of buffer...
+ soundBufferPos = 0;
+ }
+ else
+ {
+ // Fill sound buffer with frame buffered sound
+ for(uint32_t i=0; i<length; i++)
+ buffer[i] = soundBuffer[i];
+
+ soundBufferPos -= length;
+
+ // Move current buffer down to start
+ for(uint32_t i=0; i<soundBufferPos; i++)
+ soundBuffer[i] = soundBuffer[length + i];
+ }
+
+ // Free the mutex...
+//WriteLog("SDLSoundCallback(): SDL_mutexV(mutex2)\n");
+ SDL_mutexV(mutex2);
+ // Wake up any threads waiting for the buffer to drain...
+ SDL_CondSignal(conditional);
+//WriteLog("SDLSoundCallback(): end\n");
+}
+
+
+// This is called by the main CPU thread every ~21.333 cycles.
+void WriteSampleToBuffer(void)
+{
+//WriteLog("WriteSampleToBuffer(): SDL_mutexP(mutex2)\n");
+ SDL_mutexP(mutex2);
+
+ // This should almost never happen, but, if it does...
+ while (soundBufferPos >= (SOUND_BUFFER_SIZE - 1))
+ {
+//WriteLog("WriteSampleToBuffer(): Waiting for sound thread. soundBufferPos=%i, SOUNDBUFFERSIZE-1=%i\n", soundBufferPos, SOUND_BUFFER_SIZE-1);
+ SDL_mutexV(mutex2); // Release it so sound thread can get it,
+ SDL_mutexP(mutex); // Must lock the mutex for the cond to work properly...
+ SDL_CondWait(conditional, mutex); // Sleep/wait for the sound thread
+ SDL_mutexV(mutex); // Must unlock the mutex for the cond to work properly...
+ SDL_mutexP(mutex2); // Re-lock it until we're done with it...
+ }
+
+ soundBuffer[soundBufferPos++] = sample;
+//WriteLog("WriteSampleToBuffer(): SDL_mutexV(mutex2)\n");
+ SDL_mutexV(mutex2);
+}
+
+
+void ToggleSpeaker(void)
+{
+ if (!soundInitialized)
+ return;
+
+ speakerState = !speakerState;
+ sample = (speakerState ? amplitude[ampPtr] : -amplitude[ampPtr]);
+}
+
+
+void VolumeUp(void)
+{
+ // Currently set for 16-bit samples
+ if (ampPtr < 16)
+ ampPtr++;
+}
+
+
+void VolumeDown(void)
+{
+ if (ampPtr > 0)
+ ampPtr--;
+}
+
+
+uint8_t GetVolume(void)
+{
+ return ampPtr;
+}
+
--- /dev/null
+//
+// SOUND.H
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+
+#ifndef __SOUND_H__
+#define __SOUND_H__
+
+#include <stdint.h>
+
+// Global variables (exported)
+
+
+// Functions
+
+void SoundInit(void);
+void SoundDone(void);
+void SoundPause(void);
+void SoundResume(void);
+void ToggleSpeaker(void);
+void WriteSampleToBuffer(void);
+void VolumeUp(void);
+void VolumeDown(void);
+uint8_t GetVolume(void);
+
+#endif // __SOUND_H__
+
--- /dev/null
+//
+// Sprite handler
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 08/19/2014 Created this file
+//
+
+#include "sprite.h"
+#include <SDL2/SDL_image.h>
+#include "video.h"
+
+
+// Global vars
+SDL_Texture * sprite1 = 0;
+SDL_Texture * wizard1 = 0;
+SDL_Texture * underlay = 0;
+SDL_Texture * underlay2 = 0;
+
+
+bool InitSpriteHandler(void)
+{
+ SDL_Surface * surface = IMG_Load("res/spritemap1.png");
+
+ if (!surface)
+ {
+ printf("SPRITE: IMG_Load: %s\n", IMG_GetError());
+ return false;
+ }
+
+ sprite1 = SDL_CreateTextureFromSurface(sdlRenderer, surface);
+ SDL_FreeSurface(surface);
+
+ surface = IMG_Load("res/g2-wizard.png");
+
+ if (!surface)
+ {
+ printf("SPRITE: IMG_Load: %s\n", IMG_GetError());
+ return false;
+ }
+
+ wizard1 = SDL_CreateTextureFromSurface(sdlRenderer, surface);
+ SDL_FreeSurface(surface);
+
+ uint32_t ulPixels[32 * 32];
+
+ for(uint32_t i=0; i<32*32; i++)
+ ulPixels[i] = 0xFF00FF7F;
+
+ surface = SDL_CreateRGBSurfaceFrom(ulPixels, 32, 32, 32, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
+
+ if (!surface)
+ {
+ printf("SPRITE: CreateRGBSurfaceFrom: %s\n", IMG_GetError());
+ return false;
+ }
+
+ underlay = SDL_CreateTextureFromSurface(sdlRenderer, surface);
+ SDL_FreeSurface(surface);
+
+ for(uint32_t i=0; i<32*32; i++)
+ ulPixels[i] = 0xFF7F007F;
+
+ surface = SDL_CreateRGBSurfaceFrom(ulPixels, 32, 32, 32, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
+
+ if (!surface)
+ {
+ printf("SPRITE: CreateRGBSurfaceFrom: %s\n", IMG_GetError());
+ return false;
+ }
+
+ underlay2 = SDL_CreateTextureFromSurface(sdlRenderer, surface);
+ SDL_FreeSurface(surface);
+
+ return true;
+}
+
+
+void DrawPlayerSprite(Direction facing, int xpos, int ypos)
+{
+ SDL_Rect src, dst;
+#if 1
+ src.w = src.h = 16;
+ dst.x = xpos, dst.y = ypos, dst.w = dst.h = 16;
+
+ if (facing == Up)
+ {
+ src.x = 0, src.y = 0;
+ }
+ else if (facing == Down)
+ {
+ src.x = 16, src.y = 0;
+ }
+ else if (facing == Right)
+ {
+ src.x = 32, src.y = 0;
+ }
+ else if (facing == Left)
+ {
+ src.x = 48, src.y = 0;
+ }
+
+ SDL_RenderCopy(sdlRenderer, sprite1, &src, &dst);
+#else
+
+
+#endif
+
+#if 0
+ src.w = src.h = 24;
+ src.x = src.y = 0;
+ dst.x = 100, dst.y = 100, dst.w = dst.h = 24;
+
+ SDL_RenderCopy(sdlRenderer, wizard1, &src, &dst);
+#endif
+}
+
+
+void DrawPlayerSprite2(int xpos, int ypos, Direction facing, int frame)
+{
+ // Adjust x/y coords for oversize sprite
+ xpos -= 4, ypos -= 8;
+
+ int frameX[3] = { 48, 0, 24 };
+ int frameY[3] = { 0, 24, 24 };
+ SDL_Rect src, dst;
+ src.w = src.h = 24;
+ dst.x = xpos, dst.y = ypos, dst.w = dst.h = 24;
+
+ if (facing == Up)
+ {
+ src.x = frameX[frame], src.y = (6 * 24) + frameY[frame];
+ }
+ else if (facing == Down)
+ {
+ src.x = frameX[frame], src.y = (2 * 24) + frameY[frame];
+ }
+ else if (facing == Right)
+ {
+ src.x = frameX[frame], src.y = (8 * 24) + frameY[frame];
+ }
+ else if (facing == Left)
+ {
+ src.x = frameX[frame], src.y = (4 * 24) + frameY[frame];
+ }
+
+ SDL_RenderCopy(sdlRenderer, wizard1, &src, &dst);
+}
+
+
+void DrawUnderlay(int xpos, int ypos, Direction facing)
+{
+ SDL_Rect src, dest;
+ int rx = xpos % 16, ry = ypos % 16;
+ int gx = xpos / 16, gy = ypos / 16;
+
+ src.x = 0, src.y = 0;
+ dest.x = gx * 16, dest.y = gy * 16;
+
+ src.w = (rx == 0 ? 16 : 32);
+ src.h = (ry == 0 ? 16 : 32);
+ dest.w = src.w, dest.h = src.h;
+
+ SDL_RenderCopy(sdlRenderer, underlay, &src, &dest);
+
+ if (facing == Up)
+ {
+ src.h = dest.h = 16;
+ dest.y -= 16;
+ }
+ else if (facing == Down)
+ {
+ dest.y += src.h;
+ src.h = dest.h = 16;
+ }
+ else if (facing == Left)
+ {
+ src.w = dest.w = 16;
+ dest.x -= 16;
+ }
+ else if (facing == Right)
+ {
+ dest.x += src.w;
+ src.w = dest.w = 16;
+ }
+
+ SDL_RenderCopy(sdlRenderer, underlay2, &src, &dest);
+}
+
--- /dev/null
+#ifndef __SPRITE_H__
+#define __SPRITE_H__
+
+#include <SDL2/SDL.h>
+#include "legend.h"
+
+// Exported functions
+bool InitSpriteHandler(void);
+void DrawPlayerSprite(Direction, int, int);
+void DrawPlayerSprite2(int xpos, int ypos, Direction facing, int frame);
+void DrawUnderlay(int xpos, int ypos, Direction);
+
+
+// Exported vars
+extern SDL_Texture * sprite1;
+extern SDL_Texture * underlay;
+extern SDL_Texture * underlay2;
+
+#endif // __SPRITE_H__
+
--- /dev/null
+//
+// Tile handler
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 08/19/2014 Created this file
+//
+
+#include "tile.h"
+#include <SDL2/SDL_image.h>
+#include "data.h"
+#include "log.h"
+#include "video.h"
+
+
+// Global vars
+SDL_Texture * tile1 = 0;
+int mapCornerX = 0;
+int mapCornerY = 0;
+
+
+bool InitTileHandler(void)
+{
+ SDL_Surface * surface = IMG_Load("res/tilemap1.png");
+
+ if (!surface)
+ {
+ printf("TILE: IMG_Load: %s\n", IMG_GetError());
+ return false;
+ }
+
+ tile1 = SDL_CreateTextureFromSurface(sdlRenderer, surface);
+ SDL_FreeSurface(surface);
+
+ return true;
+}
+
+
+SDL_Texture * CreateMapTexture(void)
+{
+ Map * map = (Map *)maps[0];
+
+ SDL_Texture * texture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888,
+// SDL_TEXTUREACCESS_STATIC, map->width * 16, map->height * 16);
+ SDL_TEXTUREACCESS_TARGET, map->width * 16, map->height * 16);
+
+ RenderMap(map, texture);
+
+ return texture;
+}
+
+
+void RenderMap(Map * map, SDL_Texture * texture)
+{
+ // Sanity check...
+ if ((map == 0) || (texture == 0))
+ return;
+
+ if (SDL_SetRenderTarget(sdlRenderer, texture) < 0)
+ {
+ WriteLog("TILE: Could not set Render Target to map texture... (%s)\n", SDL_GetError());
+ return;
+ }
+
+ for(int y=0; y<map->height; y++)
+ {
+ for(int x=0; x<map->width; x++)
+ {
+ unsigned char tile = map->tiles[(y * map->width) + x];
+ SDL_Rect src, dst;
+ dst.x = x * 16, dst.y = y * 16, dst.w = dst.h = 16;
+ src.w = src.h = 16;
+
+ if (tile == '0')
+ src.x = 0, src.y = 0;
+ else if (tile == '1')
+ src.x = 16, src.y = 0;
+ else if (tile == '2')
+ src.x = 32, src.y = 0;
+ else if (tile == '3')
+ src.x = 48, src.y = 0;
+ else if (tile == '4')
+ src.x = 64, src.y = 0;
+ else if (tile == '5')
+ src.x = 80, src.y = 0;
+ else if (tile == '6')
+ src.x = 96, src.y = 0;
+ else if (tile == '7')
+ src.x = 112, src.y = 0;
+
+ SDL_RenderCopy(sdlRenderer, tile1, &src, &dst);
+ }
+ }
+
+ SDL_SetRenderTarget(sdlRenderer, 0);
+
+ // Set up global room state from tile map
+ memcpy(roomState, map->tiles, 16 * 11);
+ roomWidth = map->width;
+ roomHeight = map->height;
+ currentMap = map;
+}
+
+
+//
+// Get tiles the player is standing on (1x1 to 2x2)
+//
+void GetTiles(int xpos, int ypos, uint8_t * tiles)
+{
+ memset(tiles, 0, 4);
+
+ int rx = xpos % 16, ry = ypos % 16;
+ int gx = xpos / 16, gy = ypos / 16;
+
+ tiles[0] = roomState[gx + 0 + ((gy + 0) * roomWidth)];
+
+ if (rx != 0)
+ tiles[1] = roomState[gx + 1 + ((gy + 0) * roomWidth)];
+
+ if (ry != 0)
+ tiles[2] = roomState[gx + 0 + ((gy + 1) * roomWidth)];
+
+ if ((rx != 0) && (ry != 0))
+ tiles[3] = roomState[gx + 1 + ((gy + 1) * roomWidth)];
+}
+
+
+//
+// Get tiles next to the direction the player is facing (1 or 2)
+//
+void GetTiles2(int xpos, int ypos, Direction facing, uint8_t * tiles)
+{
+ tiles[0] = tiles[1] = 0;
+
+ int rx = xpos % 16, ry = ypos % 16;
+ int gx = xpos / 16, gy = ypos / 16;
+
+ int dx = 0, dy = 0, extraX = (rx != 0 ? 1 : 0), extraY = (ry != 0 ? 1 : 0);
+
+ if (facing == Left)
+ dx = -1;
+ else if (facing == Right)
+ dx = +1 + extraX;
+ else if (facing == Up)
+ dy = -1;
+ else if (facing == Down)
+ dy = +1 + extraY;
+
+ // Edge conditions...
+ if (((facing == Left) && (gx == 0))
+ || ((facing == Right) && (gx == (roomWidth - 1)))
+ || ((facing == Up) && (gy == 0))
+ || ((facing == Down) && (gy == (roomHeight - 1))))
+ return;
+
+ tiles[0] = roomState[(gx + dx) + ((gy + dy) * roomWidth)];
+
+ if (extraX && dy)
+ tiles[1] = roomState[(gx + 1) + ((gy + dy) * roomWidth)];
+
+ if (extraY && dx)
+ tiles[1] = roomState[(gx + dx) + ((gy + 1) * roomWidth)];
+}
+
+
--- /dev/null
+#ifndef __TILE_H__
+#define __TILE_H__
+
+#include <SDL2/SDL.h>
+#include "data.h"
+#include "legend.h"
+
+// Exported functions
+bool InitTileHandler(void);
+SDL_Texture * CreateMapTexture(void);
+void RenderMap(Map * map, SDL_Texture * texture);
+void GetTiles(int xpos, int ypos, uint8_t * tiles);
+void GetTiles2(int xpos, int ypos, Direction facing, uint8_t * tiles);
+
+// Exported vars
+extern SDL_Texture * tile1;
+
+#endif // __TILE_H__
+
--- /dev/null
+//
+// VIDEO.CPP: SDL/local hardware specific video routines
+//
+// by James Hammons
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+//
+
+#include "video.h"
+#include <string.h> // Why??? (for memset, etc... Lazy!) Dunno why, but this just strikes me as wrong...
+#include <malloc.h>
+#include <SDL2/SDL_image.h>
+#include "log.h"
+
+
+// Exported global variables (actually, these are LOCAL global variables, EXPORTED...)
+
+static SDL_Window * sdlWindow = NULL;
+SDL_Renderer * sdlRenderer = NULL;
+static SDL_Texture * sdlTexture = NULL;
+uint32_t scrBuffer[VIRTUAL_SCREEN_WIDTH * VIRTUAL_SCREEN_HEIGHT * sizeof(uint32_t)];
+bool fullscreen = false;
+
+
+//
+// Prime SDL and create surfaces
+//
+bool InitVideo(void)
+{
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE) != 0)
+ {
+ WriteLog("Video: Could not initialize the SDL library: %s\n", SDL_GetError());
+ return false;
+ }
+
+ int retVal = SDL_CreateWindowAndRenderer(VIRTUAL_SCREEN_WIDTH * 2, VIRTUAL_SCREEN_HEIGHT * 2, SDL_WINDOW_OPENGL, &sdlWindow, &sdlRenderer);
+
+ if (retVal != 0)
+ {
+ WriteLog("Video: Could not window and/or renderer: %s\n", SDL_GetError());
+ return false;
+ }
+
+ // Set up SDL_image
+ retVal = IMG_Init(IMG_INIT_PNG);
+
+ if (retVal != IMG_INIT_PNG)
+ {
+ WriteLog("Video: Could not init SDL_image for PNG loading!\n");
+ WriteLog("IMG_Init: %s\n", IMG_GetError());
+ }
+
+ // Make the scaled rendering look smoother.
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
+// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
+ SDL_RenderSetLogicalSize(sdlRenderer, VIRTUAL_SCREEN_WIDTH, VIRTUAL_SCREEN_HEIGHT);
+
+ // Set the application's icon & title...
+// SDL_Surface * iconSurface = SDL_CreateRGBSurfaceFrom(icon, 64, 64, 32, 64*4, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
+// SDL_SetWindowIcon(sdlWindow, iconSurface);
+// SDL_FreeSurface(iconSurface);
+ SDL_SetWindowTitle(sdlWindow, "Legend of ?");
+
+ sdlTexture = SDL_CreateTexture(sdlRenderer,
+ SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING,
+ VIRTUAL_SCREEN_WIDTH, VIRTUAL_SCREEN_HEIGHT);
+
+ WriteLog("Video: Successfully initialized.\n");
+ return true;
+}
+
+
+//
+// Free various SDL components
+//
+void VideoDone(void)
+{
+ WriteLog("Video: Shutting down SDL...\n");
+ IMG_Quit();
+ SDL_Quit();
+ WriteLog("Video: Done.\n");
+}
+
+
+//
+// Render the screen buffer to the primary screen surface
+//
+void RenderScreenBuffer(void)
+{
+ SDL_UpdateTexture(sdlTexture, NULL, scrBuffer, VIRTUAL_SCREEN_WIDTH * sizeof(Uint32));
+ SDL_RenderClear(sdlRenderer);
+ SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
+}
+
+
+//
+// Fullscreen <-> window switching
+//
+void ToggleFullScreen(void)
+{
+ fullscreen = !fullscreen;
+
+ int retVal = SDL_SetWindowFullscreen(sdlWindow, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0));
+ SDL_ShowCursor(fullscreen ? 0 : 1);
+
+ if (retVal != 0)
+ WriteLog("Video::ToggleFullScreen: SDL error = %s\n", SDL_GetError());
+}
+
+
--- /dev/null
+//
+// VIDEO.H: Header file
+//
+
+#ifndef __VIDEO_H__
+#define __VIDEO_H__
+
+#include <SDL2/SDL.h>
+#include <stdint.h> // For uint32_t
+
+//#define VIRTUAL_SCREEN_WIDTH 280
+#define VIRTUAL_SCREEN_WIDTH 16*32
+//#define VIRTUAL_SCREEN_HEIGHT 192
+#define VIRTUAL_SCREEN_HEIGHT 16*24
+
+bool InitVideo(void);
+void VideoDone(void);
+void RenderScreenBuffer(void);
+void ToggleFullScreen(void);
+
+// Exported crap
+
+extern SDL_Renderer * sdlRenderer;
+extern uint32_t scrBuffer[];
+extern uint32_t mainScrBuffer[];
+
+#endif // __VIDEO_H__
+