diff --git a/Makefile b/Makefile index 5bfdad6..841a866 100644 --- a/Makefile +++ b/Makefile @@ -6,30 +6,38 @@ VPATH = src CFLAGS = -Wall -Isrc/ -g -c LFLAGS = -Wall +SDL_OBJS = sdl_main.o ktkMap.o ktkStructure.o ktkProgram.o ktk_parse.o + +SYS := $(shell uname) +ifeq ($(SYS),Darwin) + SDL_OBJS += SDLMain.o + SDL_LFLAGS += -framework SDL -framework Cocoa + SDL_CFLAGS += -I/Library/Frameworks/SDL.framework/Headers +else + SDL_LFLAGS += -lSDL +endif + $(BINARY): $(patsubst %,$(OBJ_DIR)/%,$(OBJS)) $(CC) $(LFLAGS) $^ -o $@ +sdl: $(patsubst %,$(OBJ_DIR)/%,$(SDL_OBJS)) + $(CC) $(LFLAGS) $(SDL_LFLAGS) $^ -o $@ + tools: tools/tobmp $(MAKE) -C tools clean: - rm -f $(OBJ_DIR)/*.o && rm -f $(BINARY) + rm -f $(OBJ_DIR)/*.o && rm -f $(BINARY) && rm -f sdl cd tools && make clean main.o: main.c ktkMap.c ktkMap.h ktk_parse.h $(CC) $(CFLAGS) main.c -ktkMap.o: ktkMap.c ktkStructure.h - $(CC) $(CFLAGS) ktkMap.c - -ktkStructure.o: ktkStructure.h ktkStructure.c - $(CC) $(CFLAGS) ktkStructure.c - -ktk_parse.o: ktk_parse.h ktk_parse.c ktkProgram.h ktkStructure.h - $(CC) $(CFLAGS) ktk_parse.c - -ktkProgram.o: ktkProgram.h ktkProgram.c ktkStructure.h - $(CC) $(CFLAGS) ktkProgram.c - $(OBJ_DIR)/%.o: %.c $(CC) $(CFLAGS) $< -o $@ + +$(SDL_OBJS)/%.o: %.c + $(CC) $(CFLAGS) $< -o $@ + +$(OBJ_DIR)/SDLMain.o: SDLMain.m + $(CC) $(CFLAGS) $(SDL_CFLAGS) $< -o $@ diff --git a/README.txt b/README.txt index 3d30170..079f721 100644 --- a/README.txt +++ b/README.txt @@ -3,13 +3,22 @@ At the moment, not much is the haps. 1. terminal output make - ./main structs/smile.txt + ./main structs/smile.txt start 2. bitmap generator make tools tools/tobmp structs/smile.txt 8 +3. SDL frontend + make sdl + ./sdl structs/smile.txt start + + space/enter - regen+link structures + Z - regen structures + X - link structures + Q - quit + Current structures: castle.txt diff --git a/src/SDLMain.h b/src/SDLMain.h new file mode 100644 index 0000000..c56d90c --- /dev/null +++ b/src/SDLMain.h @@ -0,0 +1,16 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser + Non-NIB-Code & other changes: Max Horn + + Feel free to customize this file to suit your needs +*/ + +#ifndef _SDLMain_h_ +#define _SDLMain_h_ + +#import + +@interface SDLMain : NSObject +@end + +#endif /* _SDLMain_h_ */ diff --git a/src/SDLMain.m b/src/SDLMain.m new file mode 100644 index 0000000..b065a20 --- /dev/null +++ b/src/SDLMain.m @@ -0,0 +1,383 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser + Non-NIB-Code & other changes: Max Horn + + Feel free to customize this file to suit your needs +*/ + +#include "SDL.h" +#include "SDLMain.h" +#include /* for MAXPATHLEN */ +#include + +/* For some reaon, Apple removed setAppleMenu from the headers in 10.4, + but the method still is there and works. To avoid warnings, we declare + it ourselves here. */ +@interface NSApplication(SDL_Missing_Methods) +- (void)setAppleMenu:(NSMenu *)menu; +@end + +/* Use this flag to determine whether we use SDLMain.nib or not */ +#define SDL_USE_NIB_FILE 0 + +/* Use this flag to determine whether we use CPS (docking) or not */ +#define SDL_USE_CPS 1 +#ifdef SDL_USE_CPS +/* Portions of CPS.h */ +typedef struct CPSProcessSerNum +{ + UInt32 lo; + UInt32 hi; +} CPSProcessSerNum; + +extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); +extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); +extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); + +#endif /* SDL_USE_CPS */ + +static int gArgc; +static char **gArgv; +static BOOL gFinderLaunch; +static BOOL gCalledAppMainline = FALSE; + +static NSString *getApplicationName(void) +{ + const NSDictionary *dict; + NSString *appName = 0; + + /* Determine the application name */ + dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); + if (dict) + appName = [dict objectForKey: @"CFBundleName"]; + + if (![appName length]) + appName = [[NSProcessInfo processInfo] processName]; + + return appName; +} + +#if SDL_USE_NIB_FILE +/* A helper category for NSString */ +@interface NSString (ReplaceSubString) +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; +@end +#endif + +@interface SDLApplication : NSApplication +@end + +@implementation SDLApplication +/* Invoked from the Quit menu item */ +- (void)terminate:(id)sender +{ + /* Post a SDL_QUIT event */ + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); +} +@end + +/* The main class of the application, the application's delegate */ +@implementation SDLMain + +/* Set the working directory to the .app's parent directory */ +- (void) setupWorkingDirectory:(BOOL)shouldChdir +{ + if (shouldChdir) + { + char parentdir[MAXPATHLEN]; + CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); + if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) { + chdir(parentdir); /* chdir to the binary app's parent */ + } + CFRelease(url); + CFRelease(url2); + } +} + +#if SDL_USE_NIB_FILE + +/* Fix menu to contain the real app name instead of "SDL App" */ +- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName +{ + NSRange aRange; + NSEnumerator *enumerator; + NSMenuItem *menuItem; + + aRange = [[aMenu title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; + + enumerator = [[aMenu itemArray] objectEnumerator]; + while ((menuItem = [enumerator nextObject])) + { + aRange = [[menuItem title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; + if ([menuItem hasSubmenu]) + [self fixMenu:[menuItem submenu] withAppName:appName]; + } + [ aMenu sizeToFit ]; +} + +#else + +static void setApplicationMenu(void) +{ + /* warning: this code is very odd */ + NSMenu *appleMenu; + NSMenuItem *menuItem; + NSString *title; + NSString *appName; + + appName = getApplicationName(); + appleMenu = [[NSMenu alloc] initWithTitle:@""]; + + /* Add menu items */ + title = [@"About " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Hide " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Quit " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + + + /* Put menu into the menubar */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; + [menuItem setSubmenu:appleMenu]; + [[NSApp mainMenu] addItem:menuItem]; + + /* Tell the application object that this is now the application menu */ + [NSApp setAppleMenu:appleMenu]; + + /* Finally give up our references to the objects */ + [appleMenu release]; + [menuItem release]; +} + +/* Create a window menu */ +static void setupWindowMenu(void) +{ + NSMenu *windowMenu; + NSMenuItem *windowMenuItem; + NSMenuItem *menuItem; + + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + + /* "Minimize" item */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; + [windowMenu addItem:menuItem]; + [menuItem release]; + + /* Put menu into the menubar */ + windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; + [windowMenuItem setSubmenu:windowMenu]; + [[NSApp mainMenu] addItem:windowMenuItem]; + + /* Tell the application object that this is now the window menu */ + [NSApp setWindowsMenu:windowMenu]; + + /* Finally give up our references to the objects */ + [windowMenu release]; + [windowMenuItem release]; +} + +/* Replacement for NSApplicationMain */ +static void CustomApplicationMain (int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + SDLMain *sdlMain; + + /* Ensure the application object is initialised */ + [SDLApplication sharedApplication]; + +#ifdef SDL_USE_CPS + { + CPSProcessSerNum PSN; + /* Tell the dock about us */ + if (!CPSGetCurrentProcess(&PSN)) + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) + if (!CPSSetFrontProcess(&PSN)) + [SDLApplication sharedApplication]; + } +#endif /* SDL_USE_CPS */ + + /* Set up the menubar */ + [NSApp setMainMenu:[[NSMenu alloc] init]]; + setApplicationMenu(); + setupWindowMenu(); + + /* Create SDLMain and make it the app delegate */ + sdlMain = [[SDLMain alloc] init]; + [NSApp setDelegate:sdlMain]; + + /* Start the main event loop */ + [NSApp run]; + + [sdlMain release]; + [pool release]; +} + +#endif + + +/* + * Catch document open requests...this lets us notice files when the app + * was launched by double-clicking a document, or when a document was + * dragged/dropped on the app's icon. You need to have a + * CFBundleDocumentsType section in your Info.plist to get this message, + * apparently. + * + * Files are added to gArgv, so to the app, they'll look like command line + * arguments. Previously, apps launched from the finder had nothing but + * an argv[0]. + * + * This message may be received multiple times to open several docs on launch. + * + * This message is ignored once the app's mainline has been called. + */ +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename +{ + const char *temparg; + size_t arglen; + char *arg; + char **newargv; + + if (!gFinderLaunch) /* MacOS is passing command line args. */ + return FALSE; + + if (gCalledAppMainline) /* app has started, ignore this document. */ + return FALSE; + + temparg = [filename UTF8String]; + arglen = SDL_strlen(temparg) + 1; + arg = (char *) SDL_malloc(arglen); + if (arg == NULL) + return FALSE; + + newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); + if (newargv == NULL) + { + SDL_free(arg); + return FALSE; + } + gArgv = newargv; + + SDL_strlcpy(arg, temparg, arglen); + gArgv[gArgc++] = arg; + gArgv[gArgc] = NULL; + return TRUE; +} + + +/* Called when the internal event loop has just started running */ +- (void) applicationDidFinishLaunching: (NSNotification *) note +{ + int status; + + /* Set the working directory to the .app's parent directory */ + [self setupWorkingDirectory:gFinderLaunch]; + +#if SDL_USE_NIB_FILE + /* Set the main menu to contain the real app name instead of "SDL App" */ + [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; +#endif + + /* Hand off to main application code */ + gCalledAppMainline = TRUE; + status = SDL_main (gArgc, gArgv); + + /* We're done, thank you for playing */ + exit(status); +} +@end + + +@implementation NSString (ReplaceSubString) + +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString +{ + unsigned int bufferSize; + unsigned int selfLen = [self length]; + unsigned int aStringLen = [aString length]; + unichar *buffer; + NSRange localRange; + NSString *result; + + bufferSize = selfLen + aStringLen - aRange.length; + buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar)); + + /* Get first part into buffer */ + localRange.location = 0; + localRange.length = aRange.location; + [self getCharacters:buffer range:localRange]; + + /* Get middle part into buffer */ + localRange.location = 0; + localRange.length = aStringLen; + [aString getCharacters:(buffer+aRange.location) range:localRange]; + + /* Get last part into buffer */ + localRange.location = aRange.location + aRange.length; + localRange.length = selfLen - localRange.location; + [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; + + /* Build output string */ + result = [NSString stringWithCharacters:buffer length:bufferSize]; + + NSDeallocateMemoryPages(buffer, bufferSize); + + return result; +} + +@end + + + +#ifdef main +# undef main +#endif + + +/* Main entry point to executable - should *not* be SDL_main! */ +int main (int argc, char **argv) +{ + /* Copy the arguments into a global variable */ + /* This is passed if we are launched by double-clicking */ + if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { + gArgv = (char **) SDL_malloc(sizeof (char *) * 2); + gArgv[0] = argv[0]; + gArgv[1] = NULL; + gArgc = 1; + gFinderLaunch = YES; + } else { + int i; + gArgc = argc; + gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); + for (i = 0; i <= argc; i++) + gArgv[i] = argv[i]; + gFinderLaunch = NO; + } + +#if SDL_USE_NIB_FILE + [SDLApplication poseAsClass:[NSApplication class]]; + NSApplicationMain (argc, argv); +#else + CustomApplicationMain (argc, argv); +#endif + return 0; +} + diff --git a/src/sdl_main.c b/src/sdl_main.c new file mode 100644 index 0000000..e6b9385 --- /dev/null +++ b/src/sdl_main.c @@ -0,0 +1,130 @@ +#include "ktkMap.h" +#include "ktk_parse.h" +#include "ktkProgram.h" +#include +#include +#include + +SDL_Surface *screen; + +int drawMap(struct ktkMap *map) { + int x, y; + int scale_x = screen->w / (map->w); + int scale_y = screen->h / (map->h); + for (y = 0; y < screen->h; y++) { + int c_y = y / scale_y; + if (c_y >= map->h) continue; + for (x = 0; x < screen->w; x++) { + long color; + long red = 0, green = 0, blue = 0; + int c_x = x / scale_x; + if (c_x >= map->w) continue; + if (map->cell[c_x][c_y].flags & ktk_CELL_EMPTY) { + color = 128.0f; + } else { + color = lround(32.0f + map->cell[c_x][c_y].id_1 * 32.0f); + } + if (color < 0) color = 0; + if (color > 255) color = 255; + if ((color % 3) == 0) { + red = color; + blue = color/2; + green = color/4; + } else if ((color %3) == 1) { + green = color; + red = color/2; + blue = color/4; + } else { + blue = color; + green = color/2; + red = color/4; + } + + SDL_Rect rect = {x, y, scale_x, scale_y}; + SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, red, green, blue)); + } + } +} + +int SDL_main(int argc, char ** argv) { + ktk_randomizeSeed(); + if (argc < 3) { + printf("usage: %s structure_file structure_name\n", argv[0]); + return 0; + } + + struct ktkProgram my_program = ktk_PROGRAM_DEFAULT; + if (ktk_parseSFile(&my_program, argv[1]) != 0) { + printf("could not open %s for reading\n", argv[1]); + return 1; + } + + SDL_Init(SDL_INIT_VIDEO); + if ((screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_RESIZABLE)) == NULL) { + printf("could not initialize SDL screen!\n"); + return 1; + } + SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); + SDL_Flip(screen); + + struct ktkLive my_live = ktk_LIVE_DEFAULT; + + struct ktkMap my_map = ktk_MAP_DEFAULT; + my_map.flags |= ktk_MAP_RESIZE; + ktk_buildStructure(&my_program, &my_live, ktk_getStructure(&my_program, argv[2]), &my_map); + + struct ktkLive new_live = ktk_LIVE_DEFAULT; + ktk_linkStructures(&my_program, &my_live, &new_live, &my_map); + + drawMap(&my_map); + + int is_running = 1; + while(is_running) { + SDL_Event event; + if (SDL_WaitEvent(&event)) { + switch(event.type) { + case SDL_QUIT: + is_running = 0; + break; + case SDL_KEYDOWN: + printf("%d\n", event.key.keysym.sym); + if (event.key.keysym.sym == 113) { + is_running = 0; + // space/enter = roll and link structure + } else if (event.key.keysym.sym == 32 || event.key.keysym.sym == 13) { + ktk_deleteMap(&my_map); + ktk_deleteLive(&my_live); + ktk_deleteLive(&new_live); + ktk_buildStructure(&my_program, &my_live, ktk_getStructure(&my_program, argv[2]), &my_map); + ktk_linkStructures(&my_program, &my_live, &new_live, &my_map); + SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); + drawMap(&my_map); + // z = roll structure + } else if (event.key.keysym.sym == 122) { // roll structure(s) + ktk_deleteMap(&my_map); + ktk_deleteLive(&my_live); + ktk_deleteLive(&new_live); + ktk_buildStructure(&my_program, &my_live, ktk_getStructure(&my_program, argv[2]), &my_map); + SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); + drawMap(&my_map); + // x = link live structures + } else if (event.key.keysym.sym == 120) { // link structure(s) + ktk_linkStructures(&my_program, &my_live, &new_live, &my_map); + ktk_deleteLive(&my_live); + my_live = new_live; + SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); + drawMap(&my_map); + } + break; + } + } + SDL_Flip(screen); + } + + + ktk_deleteMap(&my_map); + + ktk_freeProgram(&my_program); + + return 0; +} diff --git a/structs/castle.txt b/structs/castle.txt index c73bd9f..6d3bf7f 100644 --- a/structs/castle.txt +++ b/structs/castle.txt @@ -74,7 +74,7 @@ long_walls { flags RECT|ORIGIN id_1 0 replace { - id_1 1 + id_1 1,9 } relations { long_walls_walls { diff --git a/structs/ravine.txt b/structs/ravine.txt index 78d24a1..ad14a85 100644 --- a/structs/ravine.txt +++ b/structs/ravine.txt @@ -66,7 +66,7 @@ ravine_area_ground { flags CIRCLE size_x 100% size_y 100% - id_1 2~4 + id_1 2 } ravine_area { @@ -74,7 +74,7 @@ ravine_area { size_x 7~12 size_y 7~12 replace { - id_1 3~8 + id_1 2 } relations { ravine_area_ground {