From: Shamus Hammons Date: Sat, 7 May 2016 00:07:36 +0000 (-0500) Subject: Initial commit for the Legend of A... project! X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=legend;a=commitdiff_plain;h=c1aa58c0845550983d27e9cc6faa8aaf68d7c4d2 Initial commit for the Legend of A... project! --- c1aa58c0845550983d27e9cc6faa8aaf68d7c4d2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5c06376 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +obj/ +pix/ +gmon.out +legend +legend.log diff --git a/makefile b/makefile new file mode 100644 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 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 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 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 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 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 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 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 index 0000000..bd68357 --- /dev/null +++ b/res/test1.tmx @@ -0,0 +1,11 @@ + + + + + + + + eJzV0ssKABAQheFxCW/g/d/USkmcuZWy+BcWPtMkEFFQlg13pF5b+tGLhzgPvT2NBLyq9NDZur8i3J9kzrJ087rCQ/PlLc7j9mfx0H+pW15POx/XzfP00hxa8gKT + + + diff --git a/res/test2.tmx b/res/test2.tmx new file mode 100644 index 0000000..5baa182 --- /dev/null +++ b/res/test2.tmx @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + 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= + + + + + + eJzt2E0KgzAQBlAHCv2xPU57/6N15cJg0FKlzeS9zYCryJcJkwwDrHvGr1dwsC//7xTLFVqSvs8PVvb9LZYr/+28U05yz+mxMU+5t8G81jf5923v/O8xr7Sttj/Gynf507JXzOtW2d8PrpX7PblcYl4nU/7lPgD6VZ4T9KGc/2v3AXJZ63fzQU6f9rfzIAf93Ce598m7DgAAAAAALXsDk5UCeA== + + + diff --git a/res/tilemap1.png b/res/tilemap1.png new file mode 100644 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 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 index 0000000..49d053c --- /dev/null +++ b/src/data.cpp @@ -0,0 +1,133 @@ +// +// Game data +// +// by James Hammons +// (C) 2014 Underground Software +// +// JLH = James Hammons +// +// 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 index 0000000..209901c --- /dev/null +++ b/src/data.h @@ -0,0 +1,29 @@ +#ifndef __DATA_H__ +#define __DATA_H__ + +#include + +// 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 index 0000000..11925b2 --- /dev/null +++ b/src/legend.cpp @@ -0,0 +1,372 @@ +// +// Legend of ? +// +// by James Hammons +// © 2014 Underground Software +// +// A simple action RPG; a crass appeal to sentimentalism ;-) +// +// JLH = James Hammons +// +// WHO WHEN WHAT +// --- ---------- ------------------------------------------------------------ +// JLH 08/13/2014 Created this file +// + +// STILL TO DO: +// +// + +#include "legend.h" + +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000..17a1ad3 --- /dev/null +++ b/src/legend.h @@ -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 + +// 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 index 0000000..6994cc5 --- /dev/null +++ b/src/log.cpp @@ -0,0 +1,69 @@ +// +// Log handler +// +// by James Hammons +// (C) 2006 Underground Software +// +// JLH = James Hammons +// +// WHO WHEN WHAT +// --- ---------- ------------------------------------------------------------ +// JLH 01/03/2006 Moved includes out of header file for faster compilation +// + +#include "log.h" + +#include +#include +#include +#include + +// 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 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 index 0000000..d57ac97 --- /dev/null +++ b/src/sound.cpp @@ -0,0 +1,253 @@ +// +// Sound Interface +// +// by James Hammons +// (C) 2014 Underground Software +// +// JLH = James Hammons +// +// 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 // For memset, memcpy +#include +#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= (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 index 0000000..0cea590 --- /dev/null +++ b/src/sound.h @@ -0,0 +1,29 @@ +// +// SOUND.H +// +// by James Hammons +// (C) 2014 Underground Software +// + +#ifndef __SOUND_H__ +#define __SOUND_H__ + +#include + +// 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 index 0000000..8bfe98f --- /dev/null +++ b/src/sprite.cpp @@ -0,0 +1,194 @@ +// +// Sprite handler +// +// by James Hammons +// (C) 2014 Underground Software +// +// JLH = James Hammons +// +// WHO WHEN WHAT +// --- ---------- ------------------------------------------------------------ +// JLH 08/19/2014 Created this file +// + +#include "sprite.h" +#include +#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 index 0000000..7d3492a --- /dev/null +++ b/src/sprite.h @@ -0,0 +1,20 @@ +#ifndef __SPRITE_H__ +#define __SPRITE_H__ + +#include +#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 index 0000000..e721bcc --- /dev/null +++ b/src/tile.cpp @@ -0,0 +1,170 @@ +// +// Tile handler +// +// by James Hammons +// (C) 2014 Underground Software +// +// JLH = James Hammons +// +// WHO WHEN WHAT +// --- ---------- ------------------------------------------------------------ +// JLH 08/19/2014 Created this file +// + +#include "tile.h" +#include +#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; yheight; y++) + { + for(int x=0; xwidth; 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 index 0000000..78bacce --- /dev/null +++ b/src/tile.h @@ -0,0 +1,19 @@ +#ifndef __TILE_H__ +#define __TILE_H__ + +#include +#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 index 0000000..2e00561 --- /dev/null +++ b/src/video.cpp @@ -0,0 +1,113 @@ +// +// VIDEO.CPP: SDL/local hardware specific video routines +// +// by James Hammons +// +// JLH = James Hammons +// +// WHO WHEN WHAT +// --- ---------- ------------------------------------------------------------ +// + +#include "video.h" +#include // Why??? (for memset, etc... Lazy!) Dunno why, but this just strikes me as wrong... +#include +#include +#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 index 0000000..98c71de --- /dev/null +++ b/src/video.h @@ -0,0 +1,28 @@ +// +// VIDEO.H: Header file +// + +#ifndef __VIDEO_H__ +#define __VIDEO_H__ + +#include +#include // 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__ +