]> Shamusworld >> Repos - legend/commitdiff
Initial commit for the Legend of A... project! master
authorShamus Hammons <jlhamm@acm.org>
Sat, 7 May 2016 00:07:36 +0000 (19:07 -0500)
committerShamus Hammons <jlhamm@acm.org>
Sat, 7 May 2016 00:07:36 +0000 (19:07 -0500)
27 files changed:
.gitignore [new file with mode: 0644]
makefile [new file with mode: 0644]
res/g2-sprites1.png [new file with mode: 0644]
res/g2-sprites1.xcf [new file with mode: 0644]
res/g2-tiles1.png [new file with mode: 0644]
res/g2-tiles1.xcf [new file with mode: 0644]
res/g2-wizard.png [new file with mode: 0644]
res/spritemap1.png [new file with mode: 0644]
res/spritemap1.xcf [new file with mode: 0644]
res/test1.tmx [new file with mode: 0644]
res/test2.tmx [new file with mode: 0644]
res/tilemap1.png [new file with mode: 0644]
res/tilemap1.xcf [new file with mode: 0644]
src/data.cpp [new file with mode: 0644]
src/data.h [new file with mode: 0644]
src/legend.cpp [new file with mode: 0644]
src/legend.h [new file with mode: 0644]
src/log.cpp [new file with mode: 0644]
src/log.h [new file with mode: 0644]
src/sound.cpp [new file with mode: 0644]
src/sound.h [new file with mode: 0644]
src/sprite.cpp [new file with mode: 0644]
src/sprite.h [new file with mode: 0644]
src/tile.cpp [new file with mode: 0644]
src/tile.h [new file with mode: 0644]
src/video.cpp [new file with mode: 0644]
src/video.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..5c06376
--- /dev/null
@@ -0,0 +1,5 @@
+obj/
+pix/
+gmon.out
+legend
+legend.log
diff --git a/makefile b/makefile
new file mode 100644 (file)
index 0000000..ff9dfcd
--- /dev/null
+++ b/makefile
@@ -0,0 +1,189 @@
+#
+# 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
+
diff --git a/res/g2-sprites1.png b/res/g2-sprites1.png
new file mode 100644 (file)
index 0000000..af3c511
Binary files /dev/null and b/res/g2-sprites1.png differ
diff --git a/res/g2-sprites1.xcf b/res/g2-sprites1.xcf
new file mode 100644 (file)
index 0000000..534d787
Binary files /dev/null and b/res/g2-sprites1.xcf differ
diff --git a/res/g2-tiles1.png b/res/g2-tiles1.png
new file mode 100644 (file)
index 0000000..140b12d
Binary files /dev/null and b/res/g2-tiles1.png differ
diff --git a/res/g2-tiles1.xcf b/res/g2-tiles1.xcf
new file mode 100644 (file)
index 0000000..70ee6aa
Binary files /dev/null and b/res/g2-tiles1.xcf differ
diff --git a/res/g2-wizard.png b/res/g2-wizard.png
new file mode 100644 (file)
index 0000000..eece130
Binary files /dev/null and b/res/g2-wizard.png differ
diff --git a/res/spritemap1.png b/res/spritemap1.png
new file mode 100644 (file)
index 0000000..312513d
Binary files /dev/null and b/res/spritemap1.png differ
diff --git a/res/spritemap1.xcf b/res/spritemap1.xcf
new file mode 100644 (file)
index 0000000..cc1260a
Binary files /dev/null and b/res/spritemap1.xcf differ
diff --git a/res/test1.tmx b/res/test1.tmx
new file mode 100644 (file)
index 0000000..bd68357
--- /dev/null
@@ -0,0 +1,11 @@
+<?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>
diff --git a/res/test2.tmx b/res/test2.tmx
new file mode 100644 (file)
index 0000000..5baa182
--- /dev/null
@@ -0,0 +1,25 @@
+<?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>
diff --git a/res/tilemap1.png b/res/tilemap1.png
new file mode 100644 (file)
index 0000000..24d556b
Binary files /dev/null and b/res/tilemap1.png differ
diff --git a/res/tilemap1.xcf b/res/tilemap1.xcf
new file mode 100644 (file)
index 0000000..bd273c3
Binary files /dev/null and b/res/tilemap1.xcf differ
diff --git a/src/data.cpp b/src/data.cpp
new file mode 100644 (file)
index 0000000..49d053c
--- /dev/null
@@ -0,0 +1,133 @@
+//
+// 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;
+
diff --git a/src/data.h b/src/data.h
new file mode 100644 (file)
index 0000000..209901c
--- /dev/null
@@ -0,0 +1,29 @@
+#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__
+
diff --git a/src/legend.cpp b/src/legend.cpp
new file mode 100644 (file)
index 0000000..11925b2
--- /dev/null
@@ -0,0 +1,372 @@
+//
+// 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);
+}
+
+
diff --git a/src/legend.h b/src/legend.h
new file mode 100644 (file)
index 0000000..17a1ad3
--- /dev/null
@@ -0,0 +1,42 @@
+#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__
+
diff --git a/src/log.cpp b/src/log.cpp
new file mode 100644 (file)
index 0000000..6994cc5
--- /dev/null
@@ -0,0 +1,69 @@
+//
+// 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;
+       }
+}
+
diff --git a/src/log.h b/src/log.h
new file mode 100644 (file)
index 0000000..f72795e
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,22 @@
+//
+// 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__
diff --git a/src/sound.cpp b/src/sound.cpp
new file mode 100644 (file)
index 0000000..d57ac97
--- /dev/null
@@ -0,0 +1,253 @@
+//
+// 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;
+}
+
diff --git a/src/sound.h b/src/sound.h
new file mode 100644 (file)
index 0000000..0cea590
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// 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__
+
diff --git a/src/sprite.cpp b/src/sprite.cpp
new file mode 100644 (file)
index 0000000..8bfe98f
--- /dev/null
@@ -0,0 +1,194 @@
+//
+// 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);
+}
+
diff --git a/src/sprite.h b/src/sprite.h
new file mode 100644 (file)
index 0000000..7d3492a
--- /dev/null
@@ -0,0 +1,20 @@
+#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__
+
diff --git a/src/tile.cpp b/src/tile.cpp
new file mode 100644 (file)
index 0000000..e721bcc
--- /dev/null
@@ -0,0 +1,170 @@
+//
+// 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)];
+}
+
+
diff --git a/src/tile.h b/src/tile.h
new file mode 100644 (file)
index 0000000..78bacce
--- /dev/null
@@ -0,0 +1,19 @@
+#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__
+
diff --git a/src/video.cpp b/src/video.cpp
new file mode 100644 (file)
index 0000000..2e00561
--- /dev/null
@@ -0,0 +1,113 @@
+//
+// 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());
+}
+
+
diff --git a/src/video.h b/src/video.h
new file mode 100644 (file)
index 0000000..98c71de
--- /dev/null
@@ -0,0 +1,28 @@
+//
+// 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__
+