Mercurial > love-experiments
changeset 1398:5842a06169ff GLES2-compatibility
Merged default into GLES2-compatibility
| author | Alex Szpakowski <slime73@gmail.com> |
|---|---|
| date | Thu, 21 Mar 2013 17:23:45 -0300 |
| parents | 2619c2c02312 (current diff) 43f2b4936ca8 (diff) |
| children | bd104779dd89 |
| files | src/modules/graphics/Image.h src/modules/graphics/opengl/Canvas.cpp src/modules/graphics/opengl/Canvas.h src/modules/graphics/opengl/Context.cpp src/modules/graphics/opengl/Context.h src/modules/graphics/opengl/Font.cpp src/modules/graphics/opengl/Font.h src/modules/graphics/opengl/Graphics.cpp src/modules/graphics/opengl/Graphics.h src/modules/graphics/opengl/Image.cpp src/modules/graphics/opengl/Image.h src/modules/graphics/opengl/Shader.cpp src/modules/graphics/opengl/Shader.h src/modules/graphics/opengl/wrap_Font.cpp src/modules/graphics/opengl/wrap_Graphics.cpp src/modules/graphics/opengl/wrap_Graphics.h src/modules/graphics/opengl/wrap_Image.cpp src/scripts/graphics.lua src/scripts/graphics.lua.h |
| diffstat | 30 files changed, 1009 insertions(+), 766 deletions(-) [+] |
line wrap: on
line diff
--- a/changes.txt Sun Mar 17 18:00:24 2013 -0300 +++ b/changes.txt Thu Mar 21 17:23:45 2013 -0300 @@ -21,14 +21,20 @@ * Added SoundData:getDuration. * Added new Channels api for love.thread. * Added flags to setMode. - * Added support for resizable and borderless windows. + * Added support for resizable, borderless, and non-centered windows. * Added resize event. * Added love.math module. * Added a platform-independent (good) random implementation to love.math. + * Added love.math.triangulate. * Added blend mode "none". * Added SpriteBatch:isEmpty and SpriteBatch:isFull. * Added support for extern Images in Shaders when drawing graphics primitives. * Added love.timer.getAverageDelta. + * Added love.joystickaxis/ball/hat event callbacks. + * Added ParticleSystem:setQuads. + * Added love.graphics.getDimensions and Image/Canvas/ImageData:getDimensions. + * Added love.filesystem.append. + * Added love.filesystem.getSize. * OPTIONAL: Added support for GME. * Fixed crashes with font drawing on some ATI cards. @@ -52,6 +58,8 @@ * Fixed Shader:send with Images and Canvases failing sometimes. * Fixed love.graphics.getPointStyle. * Fixed line numbers in shader errors. + * Fixed line wrapping in love.graphics.printf. + * Fixed fused release mode in OS X. * Moved love's startup to modules/love. @@ -76,6 +84,8 @@ * Updated SpriteBatch code, now more performant when (un)binding. * Updated Image creation code to error when creation fails. * Updated Canvas code to support more systems. + * Updated love.timer.getFPS to be microsecond-accurate. + * Updated love.graphics.newScreenshot to create a fully opaque image by default. LOVE 0.8.0 [Rubber Piggy] -------------------------
--- a/platform/macosx/SDLMain.m Sun Mar 17 18:00:24 2013 -0300 +++ b/platform/macosx/SDLMain.m Thu Mar 21 17:23:45 2013 -0300 @@ -1,8 +1,8 @@ /* SDLMain.m - main entry point for our Cocoa-ized SDL app - Initial Version: Darrell Walisser <dwaliss1@purdue.edu> - Non-NIB-Code & other changes: Max Horn <max@quendi.de> + Initial Version: Darrell Walisser <dwaliss1@purdue.edu> + Non-NIB-Code & other changes: Max Horn <max@quendi.de> - Feel free to customize this file to suit your needs + Feel free to customize this file to suit your needs */ //#import "SDL.h" @@ -43,18 +43,18 @@ static NSString *getApplicationName(void) { - NSDictionary *dict; - NSString *appName = 0; + NSDictionary *dict; + NSString *appName = 0; - /* Determine the application name */ - dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); - if (dict) - appName = [dict objectForKey: @"CFBundleName"]; - - if (![appName length]) - appName = [[NSProcessInfo processInfo] processName]; + /* Determine the application name */ + dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); + if (dict) + appName = [dict objectForKey: @"CFBundleName"]; - return appName; + if (![appName length]) + appName = [[NSProcessInfo processInfo] processName]; + + return appName; } #if SDL_USE_NIB_FILE @@ -71,10 +71,10 @@ /* 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); + /* Post a SDL_QUIT event */ + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); } /* Hack to make Cocoa ignore keystrokes that aren't shortcuts, otherwise it beeps on every key press */ @@ -95,15 +95,15 @@ /*CHANGED to Bundle's Resource Directory. */ - (void) setupWorkingDirectory:(BOOL)shouldChdir { - if (shouldChdir) - { - /* - char parentdir[PATH_MAX]; + if (shouldChdir) + { + /* + char parentdir[PATH_MAX]; //CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFURLRef url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, PATH_MAX)) { - assert ( chdir (parentdir) == 0 ); // chdir to the binary app's parent // + assert ( chdir (parentdir) == 0 ); // chdir to the binary app's parent // } CFRelease(url); CFRelease(url2); @@ -113,7 +113,7 @@ char path[PATH_MAX]; if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX)) { - // error! + // error! } CFRelease(resourcesURL); chdir(path); @@ -126,133 +126,133 @@ /* 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; + NSRange aRange; + NSEnumerator *enumerator; + NSMenuItem *menuItem; - aRange = [[aMenu title] rangeOfString:@"SDL App"]; - if (aRange.length != 0) - [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; + 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 ]; + 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:@""]; + /* warning: this code is very odd */ + NSMenu *appleMenu; + NSMenuItem *menuItem; + NSString *title; + NSString *appName; + + appName = getApplicationName(); + appleMenu = [[NSMenu alloc] initWithTitle:@""]; - [appleMenu addItem:[NSMenuItem separatorItem]]; + /* Add menu items */ + title = [@"About " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; - title = [@"Hide " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + [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)]; + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; - [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; - [appleMenu addItem:[NSMenuItem separatorItem]]; + [appleMenu addItem:[NSMenuItem separatorItem]]; - title = [@"Quit " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + 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]; + /* 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]; + /* 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]; + /* 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; + 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]; - 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]; + /* Put menu into the menubar */ + windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; + [windowMenuItem setSubmenu:windowMenu]; + [[NSApp mainMenu] addItem:windowMenuItem]; - /* Finally give up our references to the objects */ - [windowMenu release]; - [windowMenuItem release]; + /* 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; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + SDLMain *sdlMain; - /* Ensure the application object is initialised */ - [SDLApplication sharedApplication]; - + /* 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]; - } + { + 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] autorelease]]; - setApplicationMenu(); - setupWindowMenu(); + /* Set up the menubar */ + [NSApp setMainMenu:[[[NSMenu alloc] init] autorelease]]; + 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]; + /* 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 @@ -275,60 +275,60 @@ */ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { - const char *temparg; - size_t arglen; - char *arg; - char **newargv; + const char *temparg; + size_t arglen; + char *arg; + char **newargv; - if (!gFinderLaunch) /* MacOS is passing command line args. */ - return FALSE; + if (!gFinderLaunch) /* MacOS is passing command line args. */ + return FALSE; - if (gCalledAppMainline) /* app has started, ignore this document. */ - 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; + 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; + 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; + 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; + int status; - /* Set the working directory to the .app's parent directory */ - [self setupWorkingDirectory:gFinderLaunch]; + /* 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()]; + /* Set the main menu to contain the real app name instead of "SDL App" */ + [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; #endif - + /* Set up the app to receive menu events via keyboard shortcut */ setenv("SDL_ENABLEAPPEVENTS", "1", 1); - /* Hand off to main application code */ - gCalledAppMainline = TRUE; - status = SDL_main (gArgc, gArgv); + /* Hand off to main application code */ + gCalledAppMainline = TRUE; + status = SDL_main (gArgc, gArgv); - /* We're done, thank you for playing */ - exit(status); + /* We're done, thank you for playing */ + exit(status); } @end @@ -337,37 +337,37 @@ - (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; + 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 = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); + + /* Get first part into buffer */ + localRange.location = 0; + localRange.length = aRange.location; + [self getCharacters:buffer range:localRange]; - bufferSize = selfLen + aStringLen - aRange.length; - buffer = 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; + /* 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 @@ -382,56 +382,81 @@ /* 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; - - /* check to see if there are any .love files in Resources - props to stevejohnson/diordna */ - NSArray *lovePaths = [[NSBundle mainBundle] pathsForResourcesOfType:@"love" inDirectory:nil]; - if ([lovePaths count] > 0) { /* there are, load the first one we found and run it */ - NSString *firstLovePath = [lovePaths objectAtIndex:0]; - gCalledAppMainline = YES; - //NSLog(firstLovePath); - - const char *temparg; - size_t arglen; - char *arg; - char **newargv; - - temparg = [firstLovePath 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; + /* 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; + } + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + /* check to see if there are any .love files in Resources - props to stevejohnson/diordna */ + NSArray *lovePaths = [[NSBundle mainBundle] pathsForResourcesOfType:@"love" inDirectory:nil]; + + if ([lovePaths count] > 0) /* there are, load the first one we found and run it */ + { + NSString *firstLovePath = [lovePaths objectAtIndex:0]; + gCalledAppMainline = YES; + + const char *temparg; + size_t arglen; + char *arg; + char **newargv; + + temparg = [firstLovePath UTF8String]; + arglen = SDL_strlen(temparg) + 1; + + arg = (char *)SDL_malloc(arglen); + if (arg == NULL) + return FALSE; + + const char *fusedstr = "--fused"; + size_t fusedarglen = SDL_strlen(fusedstr) + 1; + + char *fusedarg = (char *) SDL_malloc(fusedarglen); + if (fusedarg == NULL) + { + SDL_free(arg); + return FALSE; } - } 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; - } + + newargv = (char **) realloc(gArgv, sizeof(char *) * (gArgc + 3)); + if (newargv == NULL) + { + SDL_free(arg); + SDL_free(fusedarg); + return FALSE; + } + + gArgv = newargv; + SDL_strlcpy(arg, temparg, arglen); + SDL_strlcpy(fusedarg, fusedstr, fusedarglen); + gArgv[gArgc++] = arg; + gArgv[gArgc++] = fusedarg; // run in pseudo-fused mode + gArgv[gArgc] = NULL; + } + + [pool drain]; #if SDL_USE_NIB_FILE - [SDLApplication poseAsClass:[NSApplication class]]; - NSApplicationMain (argc, argv); + [SDLApplication poseAsClass:[NSApplication class]]; + NSApplicationMain (argc, argv); #else - CustomApplicationMain (argc, argv); + CustomApplicationMain (argc, argv); #endif - return 0; + return 0; }
--- a/src/modules/filesystem/physfs/Filesystem.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/filesystem/physfs/Filesystem.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -174,12 +174,12 @@ return true; } -File *Filesystem::newFile(const char *filename) +File *Filesystem::newFile(const char *filename) const { return new File(filename); } -FileData *Filesystem::newFileData(void *data, unsigned int size, const char *filename) +FileData *Filesystem::newFileData(void *data, unsigned int size, const char *filename) const { FileData *fd = new FileData(size, std::string(filename)); @@ -189,7 +189,7 @@ return fd; } -FileData *Filesystem::newFileData(const char *b64, const char *filename) +FileData *Filesystem::newFileData(const char *b64, const char *filename) const { int size = strlen(b64); int outsize = 0; @@ -270,21 +270,21 @@ return save_path_full.c_str(); } -bool Filesystem::exists(const char *file) +bool Filesystem::exists(const char *file) const { if (PHYSFS_exists(file)) return true; return false; } -bool Filesystem::isDirectory(const char *file) +bool Filesystem::isDirectory(const char *file) const { if (PHYSFS_isDirectory(file)) return true; return false; } -bool Filesystem::isFile(const char *file) +bool Filesystem::isFile(const char *file) const { return exists(file) && !isDirectory(file); } @@ -309,118 +309,36 @@ return true; } -int Filesystem::read(lua_State *L) +Data *Filesystem::read(const char *filename, int64 size) const { - // The file to read from. The file must either be created - // on-the-fly, or passed as a parameter. - File *file; - - if (lua_isstring(L, 1)) - { - // Create the file. - file = newFile(lua_tostring(L, 1)); - } - else - return luaL_error(L, "Expected filename."); - - // Optionally, the caller can specify whether to read - // the whole file, or just a part of it. - int count = luaL_optint(L, 2, (lua_Integer)file->getSize()); // FIXME + File file(filename); - // Read the data. - Data *data = file->read(count); - - // Error check. - if (data == 0) - return luaL_error(L, "File could not be read."); + file.open(File::READ); - // Close and delete the file, if we created it. - // (I.e. if the first parameter is a string). - if (lua_isstring(L, 1)) - file->release(); - - // Push the string. - lua_pushlstring(L, (char *)data->getData(), data->getSize()); - - // Push the size. - lua_pushinteger(L, data->getSize()); - - // Lua has a copy now, so we can free it. - data->release(); - - return 2; + // close() is called in the File destructor. + return file.read(size); } -int Filesystem::write(lua_State *L) +void Filesystem::write(const char *filename, const void *data, int64 size) const { - // The file to write to. The file must either be created - // on-the-fly, or passed as a parameter. - File *file; - - // We know for sure that we need a second parameter, so - // let's check that first. - if (lua_isnoneornil(L, 2)) - return luaL_error(L, "Second argument needed."); + File file(filename); - if (lua_isstring(L, 1)) - { - // Create the file. - file = newFile(lua_tostring(L, 1)); - } - else - return luaL_error(L, "Expected filename."); - - // Get the current mode of the file. - File::Mode mode = file->getMode(); - - if (mode == File::CLOSED) - { - // It should be possible to use append mode, but - // normal File::Mode::Write is the default. - int mode = luaL_optint(L, 4, File::WRITE); - - // Open the file. - if (!file->open((File::Mode)mode)) - return luaL_error(L, "Could not open file."); - } + file.open(File::WRITE); - size_t length = 0; - const char *input; - if (lua_isstring(L, 2)) - { - input = lua_tolstring(L, 2, &length); - } - else if (luax_istype(L, 2, DATA_T)) - { - love::Data *data = luax_totype<love::Data>(L, 2, "Data", DATA_T); - length = data->getSize(); - input = (char *)data->getData(); - } - else - { - return luaL_error(L, "Expected string or data for argument #2."); - } + // close() is called in the File destructor. + if (!file.write(data, size)) + throw love::Exception("Data could not be written."); +} - // Get how much we should write. Length of string default. - length = luaL_optint(L, 3, length); - - // Write the data. - bool success = file->write(input, length); +void Filesystem::append(const char *filename, const void *data, int64 size) const +{ + File file(filename); - // Close and delete the file, if we created - // it in this function. - if (lua_isstring(L, 1)) - { - // Kill the file if "we" created it. - file->close(); - file->release(); - } + file.open(File::APPEND); - if (!success) - return luaL_error(L, "Data could not be written."); - - lua_pushboolean(L, success); - return 1; + // close() is called in the File destructor. + if (!file.write(data, size)) + throw love::Exception("Data could not be written."); } int Filesystem::enumerate(lua_State *L) @@ -553,56 +471,21 @@ return 0; } -int Filesystem::load(lua_State *L) +int64 Filesystem::getLastModified(const char *filename) const { - // Need only one arg. - luax_assert_argc(L, 1, 1); - - // Must be string. - if (!lua_isstring(L, -1)) - return luaL_error(L, "The argument must be a string."); - - std::string filename = lua_tostring(L, -1); - - // The file must exist. - if (!exists(filename.c_str())) - return luaL_error(L, "File %s does not exist.", filename.c_str()); - - // Create the file. - File *file = newFile(filename.c_str()); + PHYSFS_sint64 time = PHYSFS_getLastModTime(filename); - // Get the data from the file. - Data *data = file->read(); - - int status = luaL_loadbuffer(L, (const char *)data->getData(), data->getSize(), ("@" + filename).c_str()); - - data->release(); - file->release(); + if (time == -1) + throw love::Exception("Could not determine file modification date."); - // Load the chunk, but don't run it. - switch (status) - { - case LUA_ERRMEM: - return luaL_error(L, "Memory allocation error: %s\n", lua_tostring(L, -1)); - case LUA_ERRSYNTAX: - return luaL_error(L, "Syntax error: %s\n", lua_tostring(L, -1)); - default: // success - return 1; - } + return time; } -int Filesystem::getLastModified(lua_State *L) +int64 Filesystem::getSize(const char *filename) const { - const char *filename = luaL_checkstring(L, 1); - PHYSFS_sint64 time = PHYSFS_getLastModTime(filename); - if (time == -1) - { - lua_pushnil(L); - lua_pushstring(L, "Could not determine file modification date."); - return 2; - } - lua_pushnumber(L, static_cast<lua_Number>(time)); - return 1; + File file(filename); + int64 size = file.getSize(); + return size; } } // physfs
--- a/src/modules/filesystem/physfs/Filesystem.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/filesystem/physfs/Filesystem.h Thu Mar 21 17:23:45 2013 -0300 @@ -147,7 +147,7 @@ /** * Creates a new file. **/ - File *newFile(const char *filename); + File *newFile(const char *filename) const; /** * Creates a new FileData object. Data will be copied. @@ -155,13 +155,13 @@ * @param size The size of the data. * @param filename The full filename used to file type identification. **/ - FileData *newFileData(void *data, unsigned int size, const char *filename); + FileData *newFileData(void *data, unsigned int size, const char *filename) const; /** * Creates a new FileData object from base64 data. * @param b64 The base64 data. **/ - FileData *newFileData(const char *b64, const char *filename); + FileData *newFileData(const char *b64, const char *filename) const; /** * Gets the current working directory. @@ -190,20 +190,20 @@ * or not. * @param file The filename to check. **/ - bool exists(const char *file); + bool exists(const char *file) const; /** * Checks if an existing file really is a directory. * @param file The filename to check. **/ - bool isDirectory(const char *file); + bool isDirectory(const char *file) const; /** * Checks if an existing file really is a file, * and not a directory. * @param file The filename to check. **/ - bool isFile(const char *file); + bool isFile(const char *file) const; /** * Creates a directory. Write dir must be set. @@ -232,20 +232,27 @@ bool close(File *file); /** - * Reads count bytes from an open file. - * The first parameter is either a File or - * a string. An optional second parameter specified the - * max number of bytes to read. + * Reads data from a file. + * @param filename The name of the file to read from. + * @param size The size in bytes of the data to read. **/ - int read(lua_State *L); + Data *read(const char *filename, int64 size = File::ALL) const; /** - * Write the bytes in data to the file. File - * must be opened for write. - * The first parameter is either a File or - * a string. + * Write data to a file. + * @param filename The name of the file to write to. + * @param data The data to write. + * @param size The size in bytes of the data to write. **/ - int write(lua_State *L); + void write(const char *filename, const void *data, int64 size) const; + + /** + * Append data to a file, creating it if it doesn't exist. + * @param filename The name of the file to write to. + * @param data The data to append. + * @param size The size in bytes of the data to append. + **/ + void append(const char *filename, const void *data, int64 size) const; /** * Check if end-of-file is reached. @@ -272,14 +279,17 @@ int enumerate(lua_State *L); /** - * Loads a file without running it. The loaded - * chunk is returned as a function. - * @param filename The filename of the file to load. - * @return A function. + * Gets the last modification time of a file, in seconds + * since the Unix epoch. + * @param filename The name of the file. **/ - int load(lua_State *L); + int64 getLastModified(const char *filename) const; - int getLastModified(lua_State *L); + /** + * Gets the size of a file in bytes. + * @param filename The name of the file. + **/ + int64 getSize(const char *filename) const; /** * Text file line-reading iterator function used and
--- a/src/modules/filesystem/physfs/wrap_Filesystem.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/filesystem/physfs/wrap_Filesystem.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -199,26 +199,80 @@ int w_read(lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + int64 len = (int64) luaL_optinteger(L, 2, File::ALL); + + Data *data = 0; try { - return instance->read(L); + data = instance->read(filename, len); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); } - catch(Exception e) + + if (data == 0) + return luaL_error(L, "File could not be read."); + + // Push the string. + lua_pushlstring(L, (const char *) data->getData(), data->getSize()); + + // Push the size. + lua_pushinteger(L, data->getSize()); + + // Lua has a copy now, so we can free it. + data->release(); + + return 2; +} + +static int w_write_or_append(lua_State *L, File::Mode mode) +{ + const char *filename = luaL_checkstring(L, 1); + + const char *input = 0; + size_t len = 0; + + if (luax_istype(L, 2, DATA_T)) { - return luaL_error(L, e.what()); + love::Data *data = luax_totype<love::Data>(L, 2, "Data", DATA_T); + input = (const char *) data->getData(); + len = data->getSize(); } + else if (lua_isstring(L, 2)) + input = lua_tolstring(L, 2, &len); + else + return luaL_argerror(L, 2, "string or Data expected"); + + // Get how much we should write. Length of string default. + len = luaL_optinteger(L, 3, len); + + try + { + if (mode == File::APPEND) + instance->append(filename, (const void *) input, len); + else + instance->write(filename, (const void *) input, len); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } + + luax_pushboolean(L, true); + + return 1; } int w_write(lua_State *L) { - try - { - return instance->write(L); - } - catch(Exception e) - { - return luaL_error(L, e.what()); - } + return w_write_or_append(L, File::WRITE); +} + +int w_append(lua_State *L) +{ + return w_write_or_append(L, File::APPEND); } int w_enumerate(lua_State *L) @@ -253,19 +307,78 @@ int w_load(lua_State *L) { + std::string filename = std::string(luaL_checkstring(L, 1)); + + Data *data = 0; try { - return instance->load(L); + data = instance->read(filename.c_str()); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); } - catch(love::Exception &e) + + int status = luaL_loadbuffer(L, (const char *)data->getData(), data->getSize(), ("@" + filename).c_str()); + + data->release(); + + // Load the chunk, but don't run it. + switch (status) { - return luaL_error(L, e.what()); + case LUA_ERRMEM: + return luaL_error(L, "Memory allocation error: %s\n", lua_tostring(L, -1)); + case LUA_ERRSYNTAX: + return luaL_error(L, "Syntax error: %s\n", lua_tostring(L, -1)); + default: // success + return 1; } } int w_getLastModified(lua_State *L) { - return instance->getLastModified(L); + const char *filename = luaL_checkstring(L, 1); + + int64 time = 0; + try + { + time = instance->getLastModified(filename); + } + catch (love::Exception &e) + { + lua_pushnil(L); + lua_pushstring(L, e.what()); + return 2; + } + + lua_pushnumber(L, static_cast<lua_Number>(time)); + + return 1; +} + +int w_getSize(lua_State *L) +{ + const char *filename = luaL_checkstring(L, 1); + + int64 size = -1; + try + { + size = instance->getSize(filename); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } + + // Error on failure or if size does not fit into a double precision floating-point number. + if (size == -1) + return luaL_error(L, "Could not determine file size."); + else if (size >= 0x20000000000000LL) + return luaL_error(L, "Size too large to fit into a Lua number!"); + + + lua_pushnumber(L, (lua_Number) size); + return 1; } int loader(lua_State *L) @@ -291,7 +404,7 @@ lua_pop(L, 1); lua_pushstring(L, tmp.c_str()); // Ok, load it. - return instance->load(L); + return w_load(L); } tmp = filename; @@ -312,7 +425,7 @@ lua_pop(L, 1); lua_pushstring(L, tmp.c_str()); // Ok, load it. - return instance->load(L); + return w_load(L); } } @@ -391,10 +504,12 @@ { "remove", w_remove }, { "read", w_read }, { "write", w_write }, + { "append", w_append }, { "enumerate", w_enumerate }, { "lines", w_lines }, { "load", w_load }, { "getLastModified", w_getLastModified }, + { "getSize", w_getSize }, { "newFileData", w_newFileData }, { 0, 0 } };
--- a/src/modules/filesystem/physfs/wrap_Filesystem.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/filesystem/physfs/wrap_Filesystem.h Thu Mar 21 17:23:45 2013 -0300 @@ -57,6 +57,7 @@ int w_close(lua_State *L); int w_read(lua_State *L); int w_write(lua_State *L); +int w_append(lua_State *L); int w_eof(lua_State *L); int w_tell(lua_State *L); int w_seek(lua_State *L); @@ -64,6 +65,7 @@ int w_lines(lua_State *L); int w_load(lua_State *L); int w_getLastModified(lua_State *L); +int w_getSize(lua_State *L); int loader(lua_State *L); int extloader(lua_State *L); extern "C" LOVE_EXPORT int luaopen_love_filesystem(lua_State *L);
--- a/src/modules/graphics/Image.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/Image.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -31,6 +31,7 @@ : min(FILTER_LINEAR) , mag(FILTER_LINEAR) , mipmap(FILTER_NONE) + , anisotropy(1.0f) { }
--- a/src/modules/graphics/Image.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/Image.h Thu Mar 21 17:23:45 2013 -0300 @@ -56,6 +56,7 @@ FilterMode min; FilterMode mag; FilterMode mipmap; + float anisotropy; }; struct Wrap @@ -78,7 +79,7 @@ private: - // The default image filter + // The default texture filter. static Filter defaultFilter; static StringMap<FilterMode, FILTER_MAX_ENUM>::Entry filterModeEntries[];
--- a/src/modules/graphics/opengl/Canvas.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Canvas.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -19,8 +19,10 @@ **/ #include "Canvas.h" +#include "Image.h" #include "Graphics.h" #include "common/Matrix.h" +#include "common/config.h" #include <cstring> // For memcpy
--- a/src/modules/graphics/opengl/Context.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Context.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -56,6 +56,8 @@ } Context::Context() + : shadersSupported(false) + , maxAnisotropy(1.0f) { initExtensions(); initState(); @@ -282,6 +284,12 @@ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint *) &state.defaultFramebuffer); else state.defaultFramebuffer = 0; + + // get the maximum anisotropic filtering value + if (GLEW_EXT_texture_filter_anisotropic) + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy); + else + maxAnisotropy = 1.0f; } void Context::setupRender() @@ -670,7 +678,7 @@ glDeleteTextures(1, &texture); } -void Context::setTextureFilter(const graphics::Image::Filter &f) const +float Context::setTextureFilter(const graphics::Image::Filter &f) const { GLint gmin, gmag; @@ -708,6 +716,16 @@ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag); + + float anisotropy = 1.0f; + + if (GLEW_EXT_texture_filter_anisotropic) + { + anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); + } + + return anisotropy; } graphics::Image::Filter Context::getTextureFilter() const @@ -756,6 +774,9 @@ break; } + if (GLEW_EXT_texture_filter_anisotropic) + glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &f.anisotropy); + return f; }
--- a/src/modules/graphics/opengl/Context.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Context.h Thu Mar 21 17:23:45 2013 -0300 @@ -254,8 +254,9 @@ /** * Sets the image filter mode for the currently bound texture. + * Returns the actual amount of anisotropic filtering set. */ - void setTextureFilter(const graphics::Image::Filter &f) const; + float setTextureFilter(const graphics::Image::Filter &f) const; /** * Gets the image filter mode for the currently bound texture. @@ -327,6 +328,7 @@ } state; bool shadersSupported; + float maxAnisotropy; static bool extensionsInitialized;
--- a/src/modules/graphics/opengl/Font.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Font.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -539,8 +539,8 @@ for (it = textures.begin(); it != textures.end(); ++it) { ctx->bindTexture(*it); - ctx->setTextureFilter(f); - } + filter.anisotropy = ctx->setTextureFilter(f); + } } const Image::Filter &Font::getFilter()
--- a/src/modules/graphics/opengl/Graphics.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Graphics.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -584,16 +584,28 @@ return BLEND_MAX_ENUM; // Should never be reached. } -void Graphics::setDefaultImageFilter(const Image::Filter &f) +void Graphics::setDefaultFilter(const Image::Filter &f) { Image::setDefaultFilter(f); } -const Image::Filter &Graphics::getDefaultImageFilter() const +const Image::Filter &Graphics::getDefaultFilter() const { return Image::getDefaultFilter(); } +void Graphics::setDefaultMipmapFilter(Image::FilterMode filter, float sharpness) +{ + Image::setDefaultMipmapFilter(filter); + Image::setDefaultMipmapSharpness(sharpness); +} + +void Graphics::getDefaultMipmapFilter(Image::FilterMode *filter, float *sharpness) const +{ + *filter = Image::getDefaultMipmapFilter(); + *sharpness = Image::getDefaultMipmapSharpness(); +} + void Graphics::setLineWidth(float width) { lineWidth = width; @@ -668,7 +680,7 @@ } } -void Graphics::printf(const char *str, float x, float y, float wrap, AlignMode align) +void Graphics::printf(const char *str, float x, float y, float wrap, AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { if (currentFont == 0) return; @@ -677,34 +689,55 @@ string text(str); vector<string> lines_to_draw = currentFont->getWrap(text, wrap); - // now for the actual printing - vector<string>::const_iterator line_iter, line_end = lines_to_draw.end(); - float letter_spacing = 0.0f; - for (line_iter = lines_to_draw.begin(); line_iter != line_end; ++line_iter) + Context *ctx = getContext(); + + ctx->modelViewStack.push(ctx->modelViewStack.top()); + glPushMatrix(); + + static Matrix t; + t.setTransformation(ceil(x), ceil(y), angle, sx, sy, ox, oy, kx, ky); + ctx->modelViewStack.top() *= t; + + x = y = 0.0f; + + try { - float width = static_cast<float>(currentFont->getWidth(*line_iter)); - switch (align) + // now for the actual printing + vector<string>::const_iterator line_iter, line_end = lines_to_draw.end(); + float letter_spacing = 0.0f; + for (line_iter = lines_to_draw.begin(); line_iter != line_end; ++line_iter) { - case ALIGN_RIGHT: - currentFont->print(*line_iter, ceil(x + wrap - width), ceil(y)); - break; - case ALIGN_CENTER: - currentFont->print(*line_iter, ceil(x + (wrap - width) / 2), ceil(y)); - break; - case ALIGN_JUSTIFY: - if (line_iter->length() > 1 && (line_iter+1) != line_end) - letter_spacing = (wrap - width) / float(line_iter->length() - 1); - else - letter_spacing = 0.0f; - currentFont->print(*line_iter, ceil(x), ceil(y), letter_spacing); - break; - case ALIGN_LEFT: - default: - currentFont->print(*line_iter, ceil(x), ceil(y)); - break; + float width = static_cast<float>(currentFont->getWidth(*line_iter)); + switch (align) + { + case ALIGN_RIGHT: + currentFont->print(*line_iter, ceil(x + (wrap - width)), ceil(y), 0.0f); + break; + case ALIGN_CENTER: + currentFont->print(*line_iter, ceil(x + (wrap - width) / 2), ceil(y), 0.0f); + break; + case ALIGN_JUSTIFY: + if (line_iter->length() > 1 && (line_iter+1) != line_end) + letter_spacing = (wrap - width) / float(line_iter->length() - 1); + else + letter_spacing = 0.0f; + currentFont->print(*line_iter, ceil(x), ceil(y), letter_spacing); + break; + case ALIGN_LEFT: + default: + currentFont->print(*line_iter, ceil(x), ceil(y), 0.0f); + break; + } + y += currentFont->getHeight() * currentFont->getLineHeight(); } - y += currentFont->getHeight() * currentFont->getLineHeight(); } + catch (love::Exception &) + { + ctx->modelViewStack.pop(); + throw; + } + + ctx->modelViewStack.pop(); } /**
--- a/src/modules/graphics/opengl/Graphics.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Graphics.h Thu Mar 21 17:23:45 2013 -0300 @@ -310,19 +310,25 @@ void setBlendMode(BlendMode mode); /** - * Sets the current image filter. - **/ - void setDefaultImageFilter(const Image::Filter &f); - - /** * Gets the current blend mode. **/ BlendMode getBlendMode() const; /** - * Gets the current image filter. + * Sets the default filter for images, canvases, and fonts. + **/ + void setDefaultFilter(const Image::Filter &f); + + /** + * Gets the default filter for images, canvases, and fonts. **/ - const Image::Filter &getDefaultImageFilter() const; + const Image::Filter &getDefaultFilter() const; + + /** + * Default Image mipmap filter mode and sharpness values. + **/ + void setDefaultMipmapFilter(Image::FilterMode filter, float sharpness); + void getDefaultMipmapFilter(Image::FilterMode *filter, float *sharpness) const; /** * Sets the line width. @@ -397,7 +403,7 @@ * @param kx Shear along the x-axis. * @param ky Shear along the y-axis. **/ - void print(const char *str, float x, float y , float angle, float sx, float sy, float ox, float oy, float kx, float ky); + void print(const char *str, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); /** * Draw formatted text on screen at the specified coordinates. @@ -407,8 +413,15 @@ * @param y The y-coordinate. * @param wrap The maximum width of the text area. * @param align Where to align the text. + * @param angle The amount of rotation. + * @param sx The scale factor along the x-axis. (1 = normal). + * @param sy The scale factor along the y-axis. (1 = normal). + * @param ox The origin offset along the x-axis. + * @param oy The origin offset along the y-axis. + * @param kx Shear along the x-axis. + * @param ky Shear along the y-axis. **/ - void printf(const char *str, float x, float y, float wrap, AlignMode align); + void printf(const char *str, float x, float y, float wrap, AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky); /** * Draws a point at (x,y).
--- a/src/modules/graphics/opengl/Image.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Image.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -33,11 +33,16 @@ namespace opengl { +float Image::maxMipmapSharpness = 0.0f; + +Image::FilterMode Image::defaultMipmapFilter = Image::FILTER_NONE; +float Image::defaultMipmapSharpness = 0.0f; + Image::Image(love::image::ImageData *data) : width((float)(data->getWidth())) , height((float)(data->getHeight())) , texture(0) - , mipmapSharpness(0.0f) + , mipmapSharpness(defaultMipmapSharpness) , mipmapsCreated(false) { data->retain(); @@ -69,6 +74,7 @@ vertices[3].t = 0; filter = getDefaultFilter(); + filter.mipmap = defaultMipmapFilter; } Image::~Image() @@ -205,7 +211,7 @@ filter = f; bind(); - getContext()->setTextureFilter(f); + filter.anisotropy = getContext()->setTextureFilter(f); checkMipmapsCreated(); } @@ -229,14 +235,16 @@ void Image::setMipmapSharpness(float sharpness) { - if (!hasMipmapSharpnessSupport()) - return; + if (hasMipmapSharpnessSupport()) + { + // LOD bias has the range (-maxbias, maxbias) + mipmapSharpness = std::min(std::max(sharpness, -maxMipmapSharpness + 0.01f), maxMipmapSharpness - 0.01f); - // LOD bias has the range (-maxbias, maxbias) - mipmapSharpness = std::min(std::max(sharpness, -maxMipmapSharpness + 0.01f), maxMipmapSharpness - 0.01f); - - bind(); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness); // negative bias is sharper + bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness); // negative bias is sharper + } + else + mipmapSharpness = 0.0f; } float Image::getMipmapSharpness() const @@ -264,7 +272,7 @@ bool Image::loadVolatile() { - if (hasMipmapSharpnessSupport()) + if (hasMipmapSharpnessSupport() && maxMipmapSharpness == 0.0f) glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness); if (hasNpot()) @@ -280,7 +288,7 @@ glGenTextures(1,(GLuint *)&texture); ctx->bindTexture(texture); - ctx->setTextureFilter(filter); + filter.anisotropy = ctx->setTextureFilter(filter); ctx->setTextureWrap(wrap); float p2width = next_p2(width); @@ -320,6 +328,7 @@ mipmapsCreated = false; checkMipmapsCreated(); + setMipmapSharpness(mipmapSharpness); return true; @@ -332,7 +341,7 @@ glGenTextures(1,(GLuint *)&texture); ctx->bindTexture(texture); - ctx->setTextureFilter(filter); + filter.anisotropy = ctx->setTextureFilter(filter); ctx->setTextureWrap(wrap); while (glGetError() != GL_NO_ERROR); // clear errors @@ -352,6 +361,7 @@ mipmapsCreated = false; checkMipmapsCreated(); + setMipmapSharpness(mipmapSharpness); return true; @@ -387,11 +397,36 @@ ctx->modelViewStack.pop(); } +void Image::setDefaultMipmapSharpness(float sharpness) +{ + defaultMipmapSharpness = sharpness; +} + +float Image::getDefaultMipmapSharpness() +{ + return defaultMipmapSharpness; +} + +void Image::setDefaultMipmapFilter(Image::FilterMode f) +{ + defaultMipmapFilter = f; +} + +Image::FilterMode Image::getDefaultMipmapFilter() +{ + return defaultMipmapFilter; +} + bool Image::hasNpot() { return GLEW_ES_VERSION_2_0 || GLEW_VERSION_2_0 || GLEW_ARB_texture_non_power_of_two; } +bool Image::hasAnisotropicFilteringSupport() +{ + return GLEW_EXT_texture_filter_anisotropic; +} + bool Image::hasMipmapSupport() { return GLEW_ES_VERSION_2_0 || GLEW_VERSION_1_4 || GLEW_SGIS_generate_mipmap;
--- a/src/modules/graphics/opengl/Image.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Image.h Thu Mar 21 17:23:45 2013 -0300 @@ -105,7 +105,6 @@ const Image::Wrap &getWrap() const; void setMipmapSharpness(float sharpness); - float getMipmapSharpness() const; void bind() const; @@ -117,7 +116,13 @@ bool loadVolatile(); void unloadVolatile(); + static void setDefaultMipmapSharpness(float sharpness); + static float getDefaultMipmapSharpness(); + static void setDefaultMipmapFilter(FilterMode f); + static FilterMode getDefaultMipmapFilter(); + static bool hasNpot(); + static bool hasAnisotropicFilteringSupport(); static bool hasMipmapSupport(); static bool hasMipmapSharpnessSupport(); @@ -145,9 +150,6 @@ // Mipmap texture LOD bias (sharpness) value. float mipmapSharpness; - // Implementation-dependent min/max mipmap sharpness values. - float maxMipmapSharpness; - // True if mipmaps have been created for this Image. bool mipmapsCreated; @@ -162,6 +164,11 @@ void checkMipmapsCreated(); + static float maxMipmapSharpness; + + static FilterMode defaultMipmapFilter; + static float defaultMipmapSharpness; + }; // Image } // opengl
--- a/src/modules/graphics/opengl/Shader.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Shader.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -84,7 +84,7 @@ vertexAttribNames[Context::ATTRIB_COLOR] = "VertexColor"; vertexAttribNames[Context::ATTRIB_TEXCOORD] = "VertexTexCoord"; - // Make sure we have both vertex and fragment source codes + // Make sure we have both vertex and pixel source codes checkCodeCompleteness(); // load shader source and create program object @@ -113,13 +113,13 @@ throw love::Exception("Cannot create shader: no default vertex shader code!"); } - if (shaderSources.find(TYPE_FRAGMENT) == shaderSources.end()) + if (shaderSources.find(TYPE_PIXEL) == shaderSources.end()) { - it = defaultSources.find(TYPE_FRAGMENT); + it = defaultSources.find(TYPE_PIXEL); if (it != defaultSources.end()) - shaderSources[TYPE_FRAGMENT] = it->second; + shaderSources[TYPE_PIXEL] = it->second; else - throw love::Exception("Cannot create shader: no default fragment shader code!"); + throw love::Exception("Cannot create shader: no default pixel shader code!"); } } @@ -134,9 +134,9 @@ glshadertype = GL_VERTEX_SHADER; shadertypename = "vertex"; break; - case TYPE_FRAGMENT: + case TYPE_PIXEL: glshadertype = GL_FRAGMENT_SHADER; - shadertypename = "fragment"; + shadertypename = "pixel"; break; default: throw love::Exception("Cannot create shader object: unknown shader type."); @@ -497,10 +497,10 @@ void Shader::setDefaultSources(const ShaderSources &sources) { ShaderSources::const_iterator vertsource = sources.find(TYPE_VERTEX); - ShaderSources::const_iterator fragsource = sources.find(TYPE_FRAGMENT); + ShaderSources::const_iterator fragsource = sources.find(TYPE_PIXEL); if (vertsource == sources.end() || fragsource == sources.end()) - throw love::Exception("Default shader sources need both vertex and fragment code."); + throw love::Exception("Default shader sources need both vertex and pixel code."); defaultSources = sources; }
--- a/src/modules/graphics/opengl/Shader.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/Shader.h Thu Mar 21 17:23:45 2013 -0300 @@ -49,7 +49,7 @@ enum ShaderType { TYPE_VERTEX, - TYPE_FRAGMENT, + TYPE_PIXEL, TYPE_MAX_ENUM }; @@ -58,7 +58,7 @@ /** * Creates a new Shader using a list of source codes. - * Sources must contain either vertex or fragment shader code, or both. + * Sources must contain either vertex or pixel shader code, or both. **/ Shader(const ShaderSources &sources); @@ -138,7 +138,7 @@ /** * Sets the source codes used in new Shaders that are missing vertex or - * fragment sources. + * pixel sources. **/ static void setDefaultSources(const ShaderSources &sources);
--- a/src/modules/graphics/opengl/wrap_Canvas.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -99,6 +99,8 @@ if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); + f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); + canvas->setFilter(f); return 0; @@ -117,8 +119,9 @@ lua_pushstring(L, minstr); lua_pushstring(L, magstr); + lua_pushnumber(L, f.anisotropy); - return 2; + return 3; } int w_Canvas_setWrap(lua_State *L)
--- a/src/modules/graphics/opengl/wrap_Font.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/wrap_Font.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -103,6 +103,8 @@ if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); + f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); + try { t->setFilter(f); @@ -125,7 +127,8 @@ Image::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - return 2; + lua_pushnumber(L, f.anisotropy); + return 3; } int w_Font_getAscent(lua_State *L)
--- a/src/modules/graphics/opengl/wrap_Graphics.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -376,7 +376,7 @@ try { // Create the font. - font = instance->newFont(rasterizer, instance->getDefaultImageFilter()); + font = instance->newFont(rasterizer, instance->getDefaultFilter()); } catch (love::Exception &e) { @@ -441,7 +441,7 @@ } if (!setFilter) - img_filter = instance->getDefaultImageFilter(); + img_filter = instance->getDefaultFilter(); // Create the font. Font *font = instance->newFont(rasterizer, img_filter); @@ -528,40 +528,85 @@ if (!Shader::isSupported()) return luaL_error(L, "Sorry, your graphics card does not support shaders."); + // clamp stack to 2 elements + lua_settop(L, 2); + + // read any filepath arguments + for (int i = 1; i <= 2; i++) + { + if (!lua_isstring(L, i)) + continue; + + // call love.filesystem.isFile(arg_i) + luax_getfunction(L, "filesystem", "isFile"); + lua_pushvalue(L, i); + lua_call(L, 1, 1); + + bool isFile = luax_toboolean(L, -1); + lua_pop(L, 1); + + if (isFile) + { + luax_getfunction(L, "filesystem", "read"); + lua_pushvalue(L, i); + lua_call(L, 1, 1); + lua_replace(L, i); + } + } + + bool has_arg1 = lua_isstring(L, 1); + bool has_arg2 = lua_isstring(L, 2); + + // require at least one string argument + if (!(has_arg1 || has_arg2)) + luaL_checkstring(L, 1); + + luax_getfunction(L, "graphics", "_shaderCodeToGLSL"); + + // push vertexcode and pixelcode strings to the top of the stack + lua_pushvalue(L, 1); + lua_pushvalue(L, 2); + + // call effectCodeToGLSL, returned values will be at the top of the stack + if (lua_pcall(L, 2, 2, 0) != 0) + return luaL_error(L, "%s", lua_tostring(L, -1)); + + Shader::ShaderSources sources; + + // vertex shader code + if (lua_isstring(L, -2)) + { + std::string vertexcode(luaL_checkstring(L, -2)); + sources[Shader::TYPE_VERTEX] = vertexcode; + } + else if (has_arg1 && has_arg2) + return luaL_error(L, "Could not parse vertex shader code (missing 'position' function?)"); + + // pixel shader code + if (lua_isstring(L, -1)) + { + std::string pixelcode(luaL_checkstring(L, -1)); + sources[Shader::TYPE_PIXEL] = pixelcode; + } + else if (has_arg1 && has_arg2) + return luaL_error(L, "Could not parse pixel shader code (missing 'effect' function?)"); + + if (sources.empty()) + { + // Original args had source code, but effectCodeToGLSL couldn't translate it + for (int i = 1; i <= 2; i++) + { + if (lua_isstring(L, i)) + return luaL_argerror(L, i, "missing 'position' or 'effect' function?"); + } + } + try { - // clamp stack to 2 elements - lua_settop(L, 2); - - luax_getfunction(L, "graphics", "_shaderCodeToGLSL"); - - // push code strings to the top of the stack so they become function arguments - lua_pushvalue(L, 1); - lua_pushvalue(L, 2); - - // call shaderCodeToGLSL, returned values will be at the top of the stack - lua_pcall(L, 2, 2, 0); - - Shader::ShaderSources sources; - - // vertex shader code - if (lua_isstring(L, -2)) - { - std::string vertcode(luaL_checkstring(L, -2)); - sources[Shader::TYPE_VERTEX] = vertcode; - } - - // fragment shader code - if (lua_isstring(L, -1)) - { - std::string fragcode(luaL_checkstring(L, -1)); - sources[Shader::TYPE_FRAGMENT] = fragcode; - } - Shader *shader = instance->newShader(sources); luax_newtype(L, "Shader", GRAPHICS_SHADER_T, (void *)shader); } - catch(const love::Exception &e) + catch (const love::Exception &e) { // memory is freed in Graphics::newShader luax_getfunction(L, "graphics", "_transformGLSLErrorMessages"); @@ -697,28 +742,6 @@ return 0; } -int w_setDefaultImageFilter(lua_State *L) -{ - Image::FilterMode min; - Image::FilterMode mag; - - const char *minstr = luaL_checkstring(L, 1); - const char *magstr = luaL_optstring(L, 2, minstr); - - if (!Image::getConstant(minstr, min)) - return luaL_error(L, "Invalid filter mode: %s", minstr); - if (!Image::getConstant(magstr, mag)) - return luaL_error(L, "Invalid filter mode: %s", magstr); - - Image::Filter f; - f.min = min; - f.mag = mag; - - instance->setDefaultImageFilter(f); - - return 0; -} - int w_getBlendMode(lua_State *L) { try @@ -736,17 +759,78 @@ } } -int w_getDefaultImageFilter(lua_State *L) +int w_setDefaultFilter(lua_State *L) { - const Image::Filter &f = instance->getDefaultImageFilter(); + Image::FilterMode min; + Image::FilterMode mag; + + const char *minstr = luaL_checkstring(L, 1); + const char *magstr = luaL_optstring(L, 2, minstr); + + if (!Image::getConstant(minstr, min)) + return luaL_error(L, "Invalid filter mode: %s", minstr); + if (!Image::getConstant(magstr, mag)) + return luaL_error(L, "Invalid filter mode: %s", magstr); + + float anisotropy = (float) luaL_optnumber(L, 3, 1.0); + + Image::Filter f; + f.min = min; + f.mag = mag; + f.anisotropy = anisotropy; + + instance->setDefaultFilter(f); + + return 0; +} + +int w_getDefaultFilter(lua_State *L) +{ + const Image::Filter &f = instance->getDefaultFilter(); const char *minstr; const char *magstr; if (!Image::getConstant(f.min, minstr)) - return luaL_error(L, "Unknown filter mode for argument #1"); + return luaL_error(L, "Unknown minification filter mode"); if (!Image::getConstant(f.mag, magstr)) - return luaL_error(L, "Unknown filter mode for argument #2"); + return luaL_error(L, "Unknown magnification filter mode"); lua_pushstring(L, minstr); lua_pushstring(L, magstr); + lua_pushnumber(L, f.anisotropy); + return 3; +} + +int w_setDefaultMipmapFilter(lua_State *L) +{ + Image::FilterMode filter = Image::FILTER_NONE; + if (!lua_isnoneornil(L, 1)) + { + const char *str = luaL_checkstring(L, 1); + if (!Image::getConstant(str, filter)) + return luaL_error(L, "Invalid filter mode: %s", str); + } + + float sharpness = luaL_optnumber(L, 2, 0); + + instance->setDefaultMipmapFilter(filter, sharpness); + + return 0; +} + +int w_getDefaultMipmapFilter(lua_State *L) +{ + Image::FilterMode filter; + float sharpness; + + instance->getDefaultMipmapFilter(&filter, &sharpness); + + const char *str; + if (Image::getConstant(filter, str)) + lua_pushstring(L, str); + else + lua_pushnil(L); + + lua_pushnumber(L, sharpness); + return 2; } @@ -951,11 +1035,11 @@ Shader *shader = luax_checkshader(L, 1); - // make sure the default shader will have both vertex and fragment source codes + // make sure the default shader will have both vertex and pixel source codes const Shader::ShaderSources &sources = shader->getSources(); Shader::ShaderSources::const_iterator it; - if (sources.find(Shader::TYPE_VERTEX) == sources.end() || sources.find(Shader::TYPE_FRAGMENT) == sources.end()) - return luaL_error(L, "Default shader must have both vertex and fragment source codes."); + if (sources.find(Shader::TYPE_VERTEX) == sources.end() || sources.find(Shader::TYPE_PIXEL) == sources.end()) + return luaL_error(L, "Default shader must have both vertex and pixel source codes."); Shader *prevdefault = Shader::defaultShader; @@ -1009,11 +1093,11 @@ sources[Shader::TYPE_VERTEX] = vertcode; } - // fragment shader code + // pixel shader code if (lua_isstring(L, -1)) { std::string fragcode(luaL_checkstring(L, -1)); - sources[Shader::TYPE_FRAGMENT] = fragcode; + sources[Shader::TYPE_PIXEL] = fragcode; } try @@ -1168,18 +1252,34 @@ float y = (float)luaL_checknumber(L, 3); float wrap = (float)luaL_checknumber(L, 4); + float angle = 0.0f; + float sx = 1.0f, sy = 1.0f; + float ox = 0.0f, oy = 0.0f; + float kx = 0.0f, ky = 0.0f; + Graphics::AlignMode align = Graphics::ALIGN_LEFT; if (lua_gettop(L) >= 5) { - const char *str = luaL_checkstring(L, 5); - if (!Graphics::getConstant(str, align)) - return luaL_error(L, "Incorrect alignment: %s", str); + if (!lua_isnil(L, 5)) + { + const char *str = luaL_checkstring(L, 5); + if (!Graphics::getConstant(str, align)) + return luaL_error(L, "Incorrect alignment: %s", str); + } + + angle = (float) luaL_optnumber(L, 6, 0.0f); + sx = (float) luaL_optnumber(L, 7, 1.0f); + sy = (float) luaL_optnumber(L, 8, sx); + ox = (float) luaL_optnumber(L, 9, 0.0f); + oy = (float) luaL_optnumber(L, 10, 0.0f); + kx = (float) luaL_optnumber(L, 11, 0.0f); + ky = (float) luaL_optnumber(L, 12, 0.0f); } try { - instance->printf(str, x, y, wrap, align); + instance->printf(str, x, y, wrap, align, angle, sx, sy, ox, oy, kx, ky); } catch(love::Exception e) { @@ -1434,9 +1534,11 @@ { "getFont", w_getFont }, { "setBlendMode", w_setBlendMode }, - { "setDefaultImageFilter", w_setDefaultImageFilter }, { "getBlendMode", w_getBlendMode }, - { "getDefaultImageFilter", w_getDefaultImageFilter }, + { "setDefaultFilter", w_setDefaultFilter }, + { "getDefaultFilter", w_getDefaultFilter }, + { "setDefaultMipmapFilter", w_setDefaultMipmapFilter }, + { "getDefaultMipmapFilter", w_getDefaultMipmapFilter }, { "setLineWidth", w_setLineWidth }, { "setLineStyle", w_setLineStyle }, { "setLine", w_setLine },
--- a/src/modules/graphics/opengl/wrap_Graphics.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/wrap_Graphics.h Thu Mar 21 17:23:45 2013 -0300 @@ -73,9 +73,11 @@ int w_setFont(lua_State *L); int w_getFont(lua_State *L); int w_setBlendMode(lua_State *L); -int w_setDefaultImageFilter(lua_State *L); int w_getBlendMode(lua_State *L); -int w_getDefaultImageFilter(lua_State *L); +int w_setDefaultFilter(lua_State *L); +int w_getDefaultFilter(lua_State *L); +int w_setDefaultMipmapFilter(lua_State *L); +int w_getDefaultMipmapFilter(lua_State *L); int w_setLineWidth(lua_State *L); int w_setLineStyle(lua_State *L); int w_setLine(lua_State *L);
--- a/src/modules/graphics/opengl/wrap_Image.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/wrap_Image.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -68,6 +68,8 @@ if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); + f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); + try { t->setFilter(f); @@ -90,7 +92,8 @@ Image::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - return 2; + lua_pushnumber(L, f.anisotropy); + return 3; } int w_Image_setMipmapFilter(lua_State *L) @@ -116,21 +119,28 @@ return luaL_error(L, "%s", e.what()); } + float sharpness = luaL_optnumber(L, 3, 0); + + t->setMipmapSharpness(sharpness); + return 0; } int w_Image_getMipmapFilter(lua_State *L) { Image *t = luax_checkimage(L, 1); - const Image::Filter f = t->getFilter(); + + const Image::Filter &f = t->getFilter(); const char *mipmapstr; - if (!Image::getConstant(f.mipmap, mipmapstr)) - return 0; // only return a mipmap filter if mipmapping is enabled + if (Image::getConstant(f.mipmap, mipmapstr)) + lua_pushstring(L, mipmapstr); + else + lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled - lua_pushstring(L, mipmapstr); + lua_pushnumber(L, t->getMipmapSharpness()); - return 1; + return 2; } int w_Image_setWrap(lua_State *L) @@ -165,23 +175,6 @@ return 2; } -int w_Image_setMipmapSharpness(lua_State *L) -{ - Image *i = luax_checkimage(L, 1); - - float sharpness = (float) luaL_checknumber(L, 2); - i->setMipmapSharpness(sharpness); - - return 0; -} - -int w_Image_getMipmapSharpness(lua_State *L) -{ - Image *i = luax_checkimage(L, 1); - lua_pushnumber(L, i->getMipmapSharpness()); - return 1; -} - static const luaL_Reg functions[] = { { "getWidth", w_Image_getWidth }, @@ -193,8 +186,6 @@ { "getWrap", w_Image_getWrap }, { "setMipmapFilter", w_Image_setMipmapFilter }, { "getMipmapFilter", w_Image_getMipmapFilter }, - { "setMipmapSharpness", w_Image_setMipmapSharpness }, - { "getMipmapSharpness", w_Image_getMipmapSharpness }, { 0, 0 } };
--- a/src/modules/graphics/opengl/wrap_Image.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/graphics/opengl/wrap_Image.h Thu Mar 21 17:23:45 2013 -0300 @@ -42,8 +42,6 @@ int w_Image_getMipmapFilter(lua_State *L); int w_Image_setWrap(lua_State *L); int w_Image_getWrap(lua_State *L); -int w_Image_setMipmapSharpness(lua_State *L); -int w_Image_getMipmapSharpness(lua_State *L); extern "C" int luaopen_image(lua_State *L); } // opengl
--- a/src/modules/image/ImageData.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/image/ImageData.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -168,7 +168,6 @@ { {"tga", ImageData::FORMAT_TGA}, {"bmp", ImageData::FORMAT_BMP}, - {"gif", ImageData::FORMAT_GIF}, {"jpg", ImageData::FORMAT_JPG}, {"png", ImageData::FORMAT_PNG}, };
--- a/src/modules/image/ImageData.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/image/ImageData.h Thu Mar 21 17:23:45 2013 -0300 @@ -67,7 +67,6 @@ { FORMAT_TGA = 1, FORMAT_BMP, - FORMAT_GIF, FORMAT_JPG, FORMAT_PNG, FORMAT_MAX_ENUM
--- a/src/modules/image/devil/ImageData.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/image/devil/ImageData.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -53,7 +53,15 @@ ImageData::ImageData(filesystem::File *file) { Data *data = file->read(); - load(data); + try + { + load(data); + } + catch (love::Exception &) + { + data->release(); + throw; + } data->release(); } @@ -124,10 +132,10 @@ create(width, height, ilGetData()); } - catch(std::exception &) + catch(std::exception &e) { ilDeleteImages(1, &image); - throw; + throw love::Exception("%s", e.what()); } ilDeleteImages(1, &image); @@ -186,9 +194,6 @@ case ImageData::FORMAT_TGA: ilFormat = IL_TGA; break; - case ImageData::FORMAT_GIF: - ilFormat = IL_GIF; - break; case ImageData::FORMAT_JPG: ilFormat = IL_JPG; break;
--- a/src/modules/math/MathModule.cpp Sun Mar 17 18:00:24 2013 -0300 +++ b/src/modules/math/MathModule.cpp Thu Mar 21 17:23:45 2013 -0300 @@ -144,22 +144,30 @@ else if (polygon.size() == 3) return vector<Triangle>(1, Triangle(polygon[0], polygon[1], polygon[2])); - vector<size_t> next_vertex(polygon.size()), prev_vertex(polygon.size()); - - // collect list of connections + // collect list of connections and record leftmost item to check if the polygon + // has the expected winding + vector<size_t> next_idx(polygon.size()), prev_idx(polygon.size()); + size_t idx_lm = 0; for (size_t i = 0; i < polygon.size(); ++i) { - next_vertex[i] = i+1; - prev_vertex[i] = i-1; + const vertex &lm = polygon[idx_lm], &p = polygon[i]; + if (p.x < lm.x || (p.x == lm.x && p.y < lm.y)) + idx_lm = i; + next_idx[i] = i+1; + prev_idx[i] = i-1; } - next_vertex[next_vertex.size()-1] = 0; - prev_vertex[0] = prev_vertex.size()-1; + next_idx[next_idx.size()-1] = 0; + prev_idx[0] = prev_idx.size()-1; + + // check if the polygon has the expected winding and reverse polygon if needed + if (!is_oriented_ccw(polygon[prev_idx[idx_lm]], polygon[idx_lm], polygon[next_idx[idx_lm]])) + next_idx.swap(prev_idx); // collect list of concave polygons list<const vertex *> concave_vertices; for (size_t i = 0; i < polygon.size(); ++i) { - if (!is_oriented_ccw(polygon[prev_vertex[i]], polygon[i], polygon[next_vertex[i]])) + if (!is_oriented_ccw(polygon[prev_idx[i]], polygon[i], polygon[next_idx[i]])) concave_vertices.push_back(&polygon[i]); } @@ -169,14 +177,14 @@ size_t current = 1, skipped = 0, next, prev; while (n_vertices > 3) { - next = next_vertex[current]; - prev = prev_vertex[current]; + next = next_idx[current]; + prev = prev_idx[current]; const vertex &a = polygon[prev], &b = polygon[current], &c = polygon[next]; if (is_ear(a,b,c, concave_vertices)) { triangles.push_back(Triangle(a,b,c)); - next_vertex[prev] = next; - prev_vertex[next] = prev; + next_idx[prev] = next; + prev_idx[next] = prev; concave_vertices.remove(&b); --n_vertices; skipped = 0; @@ -187,8 +195,8 @@ } current = next; } - next = next_vertex[current]; - prev = prev_vertex[current]; + next = next_idx[current]; + prev = prev_idx[current]; triangles.push_back(Triangle(polygon[prev], polygon[current], polygon[next])); return triangles;
--- a/src/scripts/graphics.lua Sun Mar 17 18:00:24 2013 -0300 +++ b/src/scripts/graphics.lua Thu Mar 21 17:23:45 2013 -0300 @@ -1333,21 +1333,21 @@ varying lowp vec4 VaryingColor; varying mediump vec2 VaryingTexCoord;]] -local GLSLES_PRECISION_FRAG = [[ +local GLSLES_PRECISION_PIXEL = [[ #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif]] - local GLSL_MAIN_VERT = [[ + local GLSL_MAIN_VERTEX = [[ void main() { VaryingColor = VertexColor; VaryingTexCoord = VertexTexCoord.st; gl_Position = position(ModelViewProjectionMatrix, VertexPosition); }]] - local GLSLES_MAIN_VERT = [[ + local GLSLES_MAIN_VERTEX = [[ void main() { VaryingColor = VertexColor; VaryingTexCoord = VertexTexCoord.st; @@ -1355,7 +1355,7 @@ gl_Position = position(ModelViewProjectionMatrix, VertexPosition); }]] - local GLSL_MAIN_FRAG = [[ + local GLSL_MAIN_PIXEL = [[ void main() { // fix crashing issue in OSX when _tex0_ is unused within effect() float dummy = texture2D(_tex0_, vec2(.5)).r; @@ -1375,12 +1375,12 @@ return code end - local function createVertCode(vertcode) + local function createVertexCode(vertexcode) local gles = love.graphics.getRenderer() == "opengl es" if not gles then - vertcode = stripPrecisionQualifiers(vertcode) + vertexcode = stripPrecisionQualifiers(vertexcode) end - local vertcodes = { + local vertexcodes = { gles and GLSLES_VERSION or GLSL_VERSION, "#define VERTEX", GLSL_SYNTAX, @@ -1388,61 +1388,61 @@ gles and GLSLES_VARYINGS or GLSL_VARYINGS, gles and GLSLES_UNIFORMS or GLSL_UNIFORMS, "#line 0", - vertcode, - gles and GLSLES_MAIN_VERT or GLSL_MAIN_VERT, + vertexcode, + gles and GLSLES_MAIN_VERTEX or GLSL_MAIN_VERTEX, } - return table_concat(vertcodes, "\n") + return table_concat(vertexcodes, "\n") end - local function createFragCode(fragcode) + local function createPixelCode(pixelcode) local gles = love.graphics.getRenderer() == "opengl es" if not gles then - fragcode = stripPrecisionQualifiers(fragcode) + pixelcode = stripPrecisionQualifiers(pixelcode) end - local fragcodes = { + local pixelcodes = { gles and GLSLES_VERSION or GLSL_VERSION, "#define PIXEL", - gles and GLSLES_PRECISION_FRAG or "", + gles and GLSLES_PRECISION_PIXEL or "", GLSL_SYNTAX, gles and GLSLES_VARYINGS or GLSL_VARYINGS, gles and GLSLES_UNIFORMS or GLSL_UNIFORMS, "#line 0", - fragcode, - GLSL_MAIN_FRAG, + pixelcode, + GLSL_MAIN_PIXEL, } - return table_concat(fragcodes, "\n") + return table_concat(pixelcodes, "\n") end - function love.graphics._shaderCodeToGLSL(vertcode, fragcode) - if vertcode then - local s = vertcode:gsub("\r\n\t", " ") - s = s:gsub("%w+(%s+)%(", "") + function love.graphics._shaderCodeToGLSL(vertexcode, pixelcode) + if vertexcode then + local s = vertexcode:gsub("\r\n\t", " ") + s = s:gsub("(%w+)(%s+)%(", "%1(") if s:match("vec4%s*effect%(") then - fragcode = vertcode -- first argument contains frag shader code + pixelcode = vertexcode -- first argument contains pixel shader code end if not s:match("vec4%s*position%(") then - vertcode = nil -- first argument doesn't contain vert shader code + vertexcode = nil -- first argument doesn't contain vertex shader code end end - if fragcode then - local s = fragcode:gsub("\r\n\t", " ") - s = s:gsub("%w+(%s+)%(", "") + if pixelcode then + local s = pixelcode:gsub("\r\n\t", " ") + s = s:gsub("(%w+)(%s+)%(", "%1(") if s:match("vec4%s*position%(") then - vertcode = fragcode -- second argument contains vert shader code + vertexcode = pixelcode -- second argument contains vertex shader code end if not s:match("vec4%s*effect%(") then - fragcode = nil -- second argument doesn't contain frag shader code + pixelcode = nil -- second argument doesn't contain pixel shader code end end - if vertcode then - vertcode = createVertCode(vertcode) + if vertexcode then + vertexcode = createVertexCode(vertexcode) end - if fragcode then - fragcode = createFragCode(fragcode) + if pixelcode then + pixelcode = createPixelCode(pixelcode) end - return vertcode, fragcode + return vertexcode, pixelcode end function love.graphics._transformGLSLErrorMessages(message) @@ -1516,43 +1516,33 @@ end local newShader = love.graphics.newShader - function love.graphics.newShader(vertcode, fragcode) - love.graphics.newShader = function(vertcode, fragcode) - if love.filesystem then - if vertcode and love.filesystem.exists(vertcode) then - vertcode = love.filesystem.read(vertcode) - end - if fragcode and love.filesystem.exists(fragcode) then - fragcode = love.filesystem.read(fragcode) - end - end - return newShader(vertcode, fragcode) - end + function love.graphics.newShader(vertexcode, pixelcode) + love.graphics.newShader = newShader - local shader = love.graphics.newShader(vertcode, fragcode) + local shader = newShader(vertexcode, pixelcode) local meta = getmetatable(shader) meta.send = shader_dispatch_send meta.sendBoolean = meta.sendFloat return shader end - local defaultvert = [[ + local defaultvertex = [[ vec4 position(mat4 mvp_matrix, vec4 vertex) { return mvp_matrix * vertex; }]] - local defaultfrag = [[ + local defaultpixel = [[ vec4 effect(vec4 vcolor, Image texture, vec2 texcoord, vec2 pixcoord) { return vcolor * Texel(texture, texcoord); }]] - love.graphics.setDefaultShaderSources(defaultvert, defaultfrag) + love.graphics.setDefaultShaderSources(defaultvertex, defaultpixel) local defaultshader local function makeDefaultShader() if not defaultshader and love.graphics.isSupported("shader") and love.graphics.getRenderer() == "opengl es" then - defaultshader = love.graphics.newShader(defaultvert, defaultfrag) + defaultshader = love.graphics.newShader(defaultvertex, defaultpixel) end return defaultshader end
--- a/src/scripts/graphics.lua.h Sun Mar 17 18:00:24 2013 -0300 +++ b/src/scripts/graphics.lua.h Thu Mar 21 17:23:45 2013 -0300 @@ -6345,7 +6345,7 @@ 0x63, 0x32, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x5d, 0x5d, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x45, 0x53, 0x5f, 0x50, 0x52, 0x45, 0x43, 0x49, - 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x52, 0x41, 0x47, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, + 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, 0x4c, 0x5f, 0x46, 0x52, 0x41, 0x47, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x52, 0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x48, 0x49, 0x47, 0x48, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x66, 0x6c, @@ -6355,7 +6355,7 @@ 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x5d, 0x5d, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x56, - 0x45, 0x52, 0x54, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, + 0x45, 0x52, 0x54, 0x45, 0x58, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, @@ -6368,7 +6368,7 @@ 0x74, 0x65, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x3b, 0x0a, 0x7d, 0x5d, 0x5d, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x45, 0x53, 0x5f, 0x4d, 0x41, 0x49, 0x4e, - 0x5f, 0x56, 0x45, 0x52, 0x54, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, + 0x5f, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, @@ -6382,8 +6382,8 @@ 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x2c, 0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x3b, 0x0a, 0x7d, 0x5d, 0x5d, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x46, - 0x52, 0x41, 0x47, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x50, + 0x49, 0x58, 0x45, 0x4c, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x2f, 0x2f, 0x20, 0x66, 0x69, 0x78, 0x20, 0x63, 0x72, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x4f, 0x53, 0x58, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x5f, @@ -6418,19 +6418,19 @@ 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, - 0x6f, 0x64, 0x65, 0x29, 0x0a, + 0x65, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x76, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x28, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6f, 0x70, 0x65, 0x6e, 0x67, 0x6c, 0x20, 0x65, 0x73, 0x22, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, - 0x70, 0x50, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, + 0x72, 0x69, 0x70, 0x50, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x66, + 0x69, 0x65, 0x72, 0x73, 0x28, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x20, - 0x3d, 0x20, 0x7b, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, + 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x09, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x45, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x20, 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x2c, 0x0a, @@ -6447,37 +6447,37 @@ 0x5f, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x20, 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x22, 0x23, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x30, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x45, 0x53, - 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x56, 0x45, 0x52, 0x54, 0x20, 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, - 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x56, 0x45, 0x52, 0x54, 0x2c, 0x0a, + 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x20, 0x6f, 0x72, 0x20, 0x47, 0x4c, + 0x53, 0x4c, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x63, 0x61, 0x74, 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x2c, 0x20, 0x22, 0x5c, 0x6e, - 0x22, 0x29, 0x0a, + 0x63, 0x61, 0x74, 0x28, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x2c, 0x20, 0x22, + 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x66, 0x72, 0x61, 0x67, 0x63, - 0x6f, 0x64, 0x65, 0x29, 0x0a, + 0x65, 0x61, 0x74, 0x65, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x70, 0x69, 0x78, 0x65, + 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x28, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6f, 0x70, 0x65, 0x6e, 0x67, 0x6c, 0x20, 0x65, 0x73, 0x22, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, - 0x70, 0x50, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x28, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, + 0x69, 0x70, 0x50, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x28, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x20, - 0x3d, 0x20, 0x7b, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x73, + 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x09, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x45, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x20, 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x22, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x45, 0x53, - 0x5f, 0x50, 0x52, 0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x52, 0x41, 0x47, 0x20, 0x6f, 0x72, - 0x20, 0x22, 0x22, 0x2c, 0x0a, + 0x5f, 0x50, 0x52, 0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x20, 0x6f, + 0x72, 0x20, 0x22, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x53, 0x59, 0x4e, 0x54, 0x41, 0x58, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x45, 0x53, 0x5f, 0x56, 0x41, 0x52, 0x59, 0x49, 0x4e, 0x47, 0x53, 0x20, 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, @@ -6486,75 +6486,82 @@ 0x5f, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x20, 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x22, 0x23, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x30, 0x22, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x46, 0x52, 0x41, 0x47, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, + 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x63, 0x61, 0x74, 0x28, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x2c, 0x20, 0x22, 0x5c, 0x6e, - 0x22, 0x29, 0x0a, + 0x63, 0x61, 0x74, 0x28, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x2c, 0x20, 0x22, 0x5c, + 0x6e, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x54, - 0x6f, 0x47, 0x4c, 0x53, 0x4c, 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x66, 0x72, - 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x72, 0x74, 0x63, - 0x6f, 0x64, 0x65, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x5c, 0x74, 0x22, 0x2c, - 0x20, 0x22, 0x20, 0x22, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x77, 0x2b, - 0x28, 0x25, 0x73, 0x2b, 0x29, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, + 0x6f, 0x47, 0x4c, 0x53, 0x4c, 0x28, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, + 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, + 0x78, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x5c, 0x74, + 0x22, 0x2c, 0x20, 0x22, 0x20, 0x22, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x28, 0x25, 0x77, + 0x2b, 0x29, 0x28, 0x25, 0x73, 0x2b, 0x29, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x25, 0x31, 0x28, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x73, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x76, 0x65, 0x63, 0x34, 0x25, 0x73, 0x2a, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x25, 0x28, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x72, - 0x74, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x72, 0x67, - 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x66, 0x72, 0x61, - 0x67, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x76, 0x65, + 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, + 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, + 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x76, 0x65, 0x63, 0x34, 0x25, 0x73, 0x2a, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x25, 0x28, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, - 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, - 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x76, - 0x65, 0x72, 0x74, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x6e, + 0x69, 0x6c, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x72, 0x61, 0x67, 0x63, - 0x6f, 0x64, 0x65, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x5c, 0x74, 0x22, 0x2c, - 0x20, 0x22, 0x20, 0x22, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x25, 0x77, 0x2b, - 0x28, 0x25, 0x73, 0x2b, 0x29, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, + 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x5c, 0x74, 0x22, + 0x2c, 0x20, 0x22, 0x20, 0x22, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x28, 0x25, 0x77, + 0x2b, 0x29, 0x28, 0x25, 0x73, 0x2b, 0x29, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x25, 0x31, 0x28, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x73, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x76, 0x65, 0x63, 0x34, 0x25, 0x73, 0x2a, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x25, 0x28, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x72, 0x61, - 0x67, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x61, 0x72, - 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x76, 0x65, - 0x72, 0x74, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x70, + 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, + 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x76, 0x65, 0x63, 0x34, 0x25, 0x73, 0x2a, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x25, 0x28, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, - 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, - 0x66, 0x72, 0x61, 0x67, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x69, + 0x6c, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, - 0x65, 0x29, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x76, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, - 0x65, 0x29, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x70, 0x69, 0x78, 0x65, 0x6c, + 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2c, - 0x20, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, + 0x65, 0x2c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x47, 0x4c, @@ -6726,38 +6733,14 @@ 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x28, 0x76, 0x65, - 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, - 0x77, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, + 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, - 0x74, 0x65, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x61, 0x6e, - 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, - 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x72, 0x65, 0x61, 0x64, - 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x61, 0x6e, - 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, - 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x28, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x72, 0x65, 0x61, 0x64, - 0x28, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x65, 0x77, 0x53, 0x68, 0x61, 0x64, 0x65, - 0x72, 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x66, 0x72, 0x61, 0x67, 0x63, 0x6f, - 0x64, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x53, 0x68, - 0x61, 0x64, 0x65, 0x72, 0x28, 0x76, 0x65, 0x72, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x66, 0x72, 0x61, - 0x67, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, + 0x77, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x53, 0x68, 0x61, 0x64, 0x65, + 0x72, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e, + 0x65, 0x77, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x28, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, + 0x65, 0x2c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x29, 0x0a, 0x09, 0x09, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61, 0x64, @@ -6767,7 +6750,7 @@ 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x76, 0x65, 0x72, 0x74, - 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, + 0x65, 0x78, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x76, 0x65, 0x63, 0x34, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x6d, 0x76, 0x70, 0x5f, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x29, 0x0a, @@ -6775,8 +6758,8 @@ 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x76, 0x70, 0x5f, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x2a, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x3b, 0x0a, 0x7d, 0x5d, 0x5d, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x66, 0x72, 0x61, 0x67, - 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x70, 0x69, 0x78, 0x65, + 0x6c, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x76, 0x65, 0x63, 0x34, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, @@ -6788,8 +6771,8 @@ 0x7d, 0x5d, 0x5d, 0x0a, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x76, 0x65, 0x72, 0x74, 0x2c, 0x20, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x66, 0x72, 0x61, 0x67, 0x29, 0x0a, + 0x65, 0x73, 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x2c, 0x20, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x61, @@ -6804,7 +6787,7 @@ 0x09, 0x09, 0x09, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x76, 0x65, 0x72, 0x74, - 0x2c, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x66, 0x72, 0x61, 0x67, 0x29, 0x0a, + 0x65, 0x78, 0x2c, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x0a,
