From a11adeea4ad1fe38cd2f267ca62de32ce9c5d629 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Wed, 3 May 2017 13:06:10 +0200 Subject: [PATCH 01/36] Fix luasocket compatibility with luajit 2.1.0 beta 3 (fix #1277) Note that luasocket 3.0 (in minor) targets lua 5.1, so it does not rely on a 5.0 compatibility feature, and does not require this patch. Since a 0.10.3 release seems unlikely at this point, this commit is mostly targeted at future packagers of older love versions. --- changes.txt | 1 + src/libraries/luasocket/libluasocket/lua.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/changes.txt b/changes.txt index 849ef40b8..66c6b9a35 100644 --- a/changes.txt +++ b/changes.txt @@ -8,6 +8,7 @@ Released: N/A * Fixed Shader:send and Shader:sendColor ignoring the last argument for an array. * Fixed a crash when love.graphics.pop is called after a love.window.setMode while the transformation stack was not empty. * Fixed BezierCurves to error instead of hanging in some situations. + * Fixed compilation of luasocket with newer luajit 2.1.0 beta versions. * Improved command line argument handling. * Improved seeking support, especially for short video files. diff --git a/src/libraries/luasocket/libluasocket/lua.h b/src/libraries/luasocket/libluasocket/lua.h index a280df842..c4215ecb7 100644 --- a/src/libraries/luasocket/libluasocket/lua.h +++ b/src/libraries/luasocket/libluasocket/lua.h @@ -6,9 +6,12 @@ #include #include -#if LUA_VERSION_NUM > 501 +#if LUA_VERSION_NUM >= 501 +# undef luaL_reg # define luaL_reg luaL_Reg +# undef luaL_putchar # define luaL_putchar(B, c) luaL_addchar(B, c) +# undef luaL_typerror # define luaL_typerror(L, n, t) luax_typerror(L, n, t) extern int luax_typerror(lua_State *L, int narg, const char *type); From 4c145e8c130c68662c6f35d55953e582dcf898c8 Mon Sep 17 00:00:00 2001 From: Tiago Koji Castro Shibata Date: Fri, 2 Jun 2017 19:35:58 -0300 Subject: [PATCH 02/36] Support audio mix modes --- .../xcode/liblove.xcodeproj/project.pbxproj | 4 +++ src/common/ios.h | 10 ++++++ src/common/ios.mm | 34 +++++++++++++++++++ src/modules/audio/wrap_Audio.cpp | 12 +++++++ src/modules/love/love.cpp | 14 ++++++++ src/scripts/boot.lua | 8 +++++ src/scripts/boot.lua.h | 12 +++++++ 7 files changed, 94 insertions(+) diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index d21bd683c..f958de2d3 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + CEEB36EA1EE21DB90085BD77 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEEB36E91EE21DB90085BD77 /* AVFoundation.framework */; }; FA0B791B1A958E3B000E1D17 /* b64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B78F71A958E3B000E1D17 /* b64.cpp */; }; FA0B791C1A958E3B000E1D17 /* b64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B78F71A958E3B000E1D17 /* b64.cpp */; }; FA0B791D1A958E3B000E1D17 /* b64.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B78F81A958E3B000E1D17 /* b64.h */; }; @@ -918,6 +919,7 @@ /* Begin PBXFileReference section */ 503971A86B7167A91B670FBA /* boot.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = boot.lua.h; sourceTree = ""; }; + CEEB36E91EE21DB90085BD77 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; FA08F5AE16C7525600F007B5 /* liblove-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "liblove-macosx.plist"; path = "macosx/liblove-macosx.plist"; sourceTree = ""; }; FA0B78DD1A958B90000E1D17 /* liblove.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblove.a; sourceTree = BUILT_PRODUCTS_DIR; }; FA0B78F71A958E3B000E1D17 /* b64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b64.cpp; sourceTree = ""; }; @@ -1597,6 +1599,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CEEB36EA1EE21DB90085BD77 /* AVFoundation.framework in Frameworks */, FA27B3C91B498623008A9DCE /* Theora.framework in Frameworks */, FA317EBA18F28B6D00B0BCD7 /* libz.dylib in Frameworks */, FAA627CE18E7E1560080752D /* CoreServices.framework in Frameworks */, @@ -2824,6 +2827,7 @@ FA577A6616C7199700860150 /* Frameworks */ = { isa = PBXGroup; children = ( + CEEB36E91EE21DB90085BD77 /* AVFoundation.framework */, FA0B7EEB1A959125000E1D17 /* macosx */, ); name = Frameworks; diff --git a/src/common/ios.h b/src/common/ios.h index 43a4c7c7c..1b74a6a1e 100644 --- a/src/common/ios.h +++ b/src/common/ios.h @@ -64,6 +64,16 @@ std::string getExecutablePath(); **/ void vibrate(); +/** + * Enable mix mode (e.g. with background music apps) and playback with a muted device. + **/ +void setAudioMixWithOthers(bool mixMode, bool playMuted); + +/** + * Returns whether another application is playing audio. + **/ +bool audioShouldBeSilenced(); + } // ios } // love diff --git a/src/common/ios.mm b/src/common/ios.mm index c17c17bde..70a7f35ce 100644 --- a/src/common/ios.mm +++ b/src/common/ios.mm @@ -26,6 +26,7 @@ #import #import +#import #include @@ -344,6 +345,39 @@ void vibrate() } } +void setAudioMixWithOthers(bool mixMode, bool playMuted) +{ + @autoreleasepool + { + NSError* err; + if (mixMode) + { + if (playMuted) + { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&err]; + } + else + { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&err]; + } + } + else + { + if (playMuted) + { + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&err]; + } + } + if (err != nil) + NSLog(@"Error in AVAudioSession setCategory: %@", [err localizedDescription]); + } +} + +bool audioShouldBeSilenced() +{ + return [[AVAudioSession sharedInstance] secondaryAudioShouldBeSilencedHint]; +} + } // ios } // love diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 0e617ff76..956f8da23 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -25,6 +25,7 @@ #include "null/Audio.h" #include "common/runtime.h" +#include "common/ios.h" // C++ #include @@ -293,6 +294,16 @@ int w_getDistanceModel(lua_State *L) return 1; } +int w_getShouldBeSilenced(lua_State *L) +{ +#ifdef LOVE_IOS + lua_pushboolean(L, love::ios::audioShouldBeSilenced()); +#else + lua_pushboolean(L, 0); +#endif + return 1; +} + // List of functions to wrap. static const luaL_Reg functions[] = { @@ -318,6 +329,7 @@ static const luaL_Reg functions[] = { "stopRecording", w_stopRecording },*/ { "setDistanceModel", w_setDistanceModel }, { "getDistanceModel", w_getDistanceModel }, + { "getShouldBeSilenced", w_getShouldBeSilenced }, { 0, 0 } }; diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 64d3d4586..f56bd7eee 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -23,6 +23,7 @@ #include "common/version.h" #include "common/runtime.h" #include "common/wrap_Data.h" +#include "common/ios.h" #include "love.h" @@ -258,6 +259,14 @@ static int w__setGammaCorrect(lua_State *L) return 0; } +#ifdef LOVE_IOS +static int w__setAudioMixMode(lua_State *L) +{ + love::ios::setAudioMixWithOthers(lua_toboolean(L, 1), lua_toboolean(L, 2)); + return 0; +} +#endif + int luaopen_love(lua_State *L) { love::luax_insistpinnedthread(L); @@ -291,6 +300,11 @@ int luaopen_love(lua_State *L) lua_pushcfunction(L, w__setGammaCorrect); lua_setfield(L, -2, "_setGammaCorrect"); +#ifdef LOVE_IOS + lua_pushcfunction(L, w__setAudioMixMode); + lua_setfield(L, -2, "_setAudioMixMode"); +#endif + lua_newtable(L); for (int i = 0; love::VERSION_COMPATIBILITY[i] != nullptr; i++) diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index ed903a61a..418c557d3 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -373,6 +373,10 @@ function love.init() window = true, video = true, }, + audio = { + mixmode = true, + playmuted = false, + }, console = false, -- Only relevant for windows. identity = false, appendidentity = false, @@ -416,6 +420,10 @@ function love.init() love._setGammaCorrect(c.gammacorrect) end + if love._setAudioMixMode then + love._setAudioMixMode(c.audio.mixmode, c.audio.playmuted) + end + -- Gets desired modules. for k,v in ipairs{ "thread", diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index 6d0fbadb7..e53ba39ab 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -682,6 +682,11 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x09, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x2c, 0x0a, + 0x09, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x3d, 0x20, 0x7b, 0x0a, + 0x09, 0x09, 0x09, 0x6d, 0x69, 0x78, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x70, 0x6c, 0x61, 0x79, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, + 0x73, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x7d, 0x2c, 0x0a, 0x09, 0x09, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x0a, @@ -776,6 +781,13 @@ const unsigned char boot_lua[] = 0x72, 0x72, 0x65, 0x63, 0x74, 0x28, 0x63, 0x2e, 0x67, 0x61, 0x6d, 0x6d, 0x61, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, + 0x4d, 0x69, 0x78, 0x4d, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x4d, 0x69, + 0x78, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x6d, + 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x6d, + 0x75, 0x74, 0x65, 0x64, 0x29, 0x0a, + 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x73, 0x20, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, From 74c35358bb849d529fdb910eef02f3acc2fcba9b Mon Sep 17 00:00:00 2001 From: Tiago Koji Castro Shibata Date: Sat, 10 Jun 2017 00:07:39 -0300 Subject: [PATCH 03/36] Move setMixMode to love.audio --- .../xcode/liblove.xcodeproj/project.pbxproj | 4 ---- platform/xcode/love.xcodeproj/project.pbxproj | 4 ++++ src/common/ios.mm | 22 +++++++++---------- src/modules/audio/wrap_Audio.cpp | 14 ++++++++++++ src/modules/love/love.cpp | 14 ------------ src/scripts/boot.lua | 8 +++---- src/scripts/boot.lua.h | 14 ++++++------ 7 files changed, 39 insertions(+), 41 deletions(-) diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index f958de2d3..d21bd683c 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - CEEB36EA1EE21DB90085BD77 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEEB36E91EE21DB90085BD77 /* AVFoundation.framework */; }; FA0B791B1A958E3B000E1D17 /* b64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B78F71A958E3B000E1D17 /* b64.cpp */; }; FA0B791C1A958E3B000E1D17 /* b64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B78F71A958E3B000E1D17 /* b64.cpp */; }; FA0B791D1A958E3B000E1D17 /* b64.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B78F81A958E3B000E1D17 /* b64.h */; }; @@ -919,7 +918,6 @@ /* Begin PBXFileReference section */ 503971A86B7167A91B670FBA /* boot.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = boot.lua.h; sourceTree = ""; }; - CEEB36E91EE21DB90085BD77 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; FA08F5AE16C7525600F007B5 /* liblove-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "liblove-macosx.plist"; path = "macosx/liblove-macosx.plist"; sourceTree = ""; }; FA0B78DD1A958B90000E1D17 /* liblove.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblove.a; sourceTree = BUILT_PRODUCTS_DIR; }; FA0B78F71A958E3B000E1D17 /* b64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b64.cpp; sourceTree = ""; }; @@ -1599,7 +1597,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CEEB36EA1EE21DB90085BD77 /* AVFoundation.framework in Frameworks */, FA27B3C91B498623008A9DCE /* Theora.framework in Frameworks */, FA317EBA18F28B6D00B0BCD7 /* libz.dylib in Frameworks */, FAA627CE18E7E1560080752D /* CoreServices.framework in Frameworks */, @@ -2827,7 +2824,6 @@ FA577A6616C7199700860150 /* Frameworks */ = { isa = PBXGroup; children = ( - CEEB36E91EE21DB90085BD77 /* AVFoundation.framework */, FA0B7EEB1A959125000E1D17 /* macosx */, ); name = Frameworks; diff --git a/platform/xcode/love.xcodeproj/project.pbxproj b/platform/xcode/love.xcodeproj/project.pbxproj index 3c46db730..4a0425ef5 100644 --- a/platform/xcode/love.xcodeproj/project.pbxproj +++ b/platform/xcode/love.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ A9D307F2106635D3004FEDF8 /* physfs.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9D307E9106635C3004FEDF8 /* physfs.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; A9F169AC109E825000FC83D1 /* mpg123.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9F169A6109E824900FC83D1 /* mpg123.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; A9F169AD109E825000FC83D1 /* libmodplug.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9F16926109E7BAD00FC83D1 /* libmodplug.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + CE73F8001EEB64150052DAB3 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */; }; FA0797991BF480A200034B7C /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA0797981BF480A200034B7C /* GameController.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; FA08F69616C766E000F007B5 /* love.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; }; FA08F69716C766E700F007B5 /* love.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; @@ -110,6 +111,7 @@ A9D307E9106635C3004FEDF8 /* physfs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = physfs.framework; path = /Library/Frameworks/physfs.framework; sourceTree = ""; }; A9F16926109E7BAD00FC83D1 /* libmodplug.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libmodplug.framework; path = /Library/Frameworks/libmodplug.framework; sourceTree = ""; }; A9F169A6109E824900FC83D1 /* mpg123.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = mpg123.framework; path = /Library/Frameworks/mpg123.framework; sourceTree = ""; }; + CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; }; FA0797981BF480A200034B7C /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; }; FA08F69116C765A200F007B5 /* love.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FA0B7F061A95AAF3000E1D17 /* love.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = love.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -149,6 +151,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CE73F8001EEB64150052DAB3 /* AVFoundation.framework in Frameworks */, FA5D24D11A96E73300C6FC8F /* liblove.a in Frameworks */, FA5D24C21A96D78000C6FC8F /* Foundation.framework in Frameworks */, FA5D24961A96CAC200C6FC8F /* CoreMotion.framework in Frameworks */, @@ -169,6 +172,7 @@ 1058C7A0FEA54F0111CA2CBB /* Frameworks */ = { isa = PBXGroup; children = ( + CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */, FA5D24801A96C97900C6FC8F /* ios */, FA0B7EEC1A959249000E1D17 /* macosx */, ); diff --git a/src/common/ios.mm b/src/common/ios.mm index 70a7f35ce..e34d8f362 100644 --- a/src/common/ios.mm +++ b/src/common/ios.mm @@ -349,25 +349,23 @@ void setAudioMixWithOthers(bool mixMode, bool playMuted) { @autoreleasepool { - NSError* err; + NSString *category = AVAudioSessionCategoryPlayback; + AVAudioSessionCategoryOptions options = 0; + NSError *err = nil; + if (mixMode) { if (playMuted) - { - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&err]; - } + options = AVAudioSessionCategoryOptionMixWithOthers; else - { - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&err]; - } + category = AVAudioSessionCategoryAmbient; } - else + else if (!playMuted) { - if (playMuted) - { - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&err]; - } + category = AVAudioSessionCategorySoloAmbient; } + + [[AVAudioSession sharedInstance] setCategory:category withOptions:options error:&err]; if (err != nil) NSLog(@"Error in AVAudioSession setCategory: %@", [err localizedDescription]); } diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 956f8da23..e00b0eb4a 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -25,7 +25,9 @@ #include "null/Audio.h" #include "common/runtime.h" +#ifdef LOVE_IOS #include "common/ios.h" +#endif // C++ #include @@ -294,6 +296,17 @@ int w_getDistanceModel(lua_State *L) return 1; } +#ifdef LOVE_IOS +int w_setMixMode(lua_State *L) +{ + love::ios::setAudioMixWithOthers(lua_toboolean(L, 1), lua_toboolean(L, 2)); +#else +int w_setMixMode(lua_State *) +{ +#endif + return 0; +} + int w_getShouldBeSilenced(lua_State *L) { #ifdef LOVE_IOS @@ -329,6 +342,7 @@ static const luaL_Reg functions[] = { "stopRecording", w_stopRecording },*/ { "setDistanceModel", w_setDistanceModel }, { "getDistanceModel", w_getDistanceModel }, + { "setMixMode", w_setMixMode }, { "getShouldBeSilenced", w_getShouldBeSilenced }, { 0, 0 } }; diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index f56bd7eee..64d3d4586 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -23,7 +23,6 @@ #include "common/version.h" #include "common/runtime.h" #include "common/wrap_Data.h" -#include "common/ios.h" #include "love.h" @@ -259,14 +258,6 @@ static int w__setGammaCorrect(lua_State *L) return 0; } -#ifdef LOVE_IOS -static int w__setAudioMixMode(lua_State *L) -{ - love::ios::setAudioMixWithOthers(lua_toboolean(L, 1), lua_toboolean(L, 2)); - return 0; -} -#endif - int luaopen_love(lua_State *L) { love::luax_insistpinnedthread(L); @@ -300,11 +291,6 @@ int luaopen_love(lua_State *L) lua_pushcfunction(L, w__setGammaCorrect); lua_setfield(L, -2, "_setGammaCorrect"); -#ifdef LOVE_IOS - lua_pushcfunction(L, w__setAudioMixMode); - lua_setfield(L, -2, "_setAudioMixMode"); -#endif - lua_newtable(L); for (int i = 0; love::VERSION_COMPATIBILITY[i] != nullptr; i++) diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index 418c557d3..3c6676879 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -420,10 +420,6 @@ function love.init() love._setGammaCorrect(c.gammacorrect) end - if love._setAudioMixMode then - love._setAudioMixMode(c.audio.mixmode, c.audio.playmuted) - end - -- Gets desired modules. for k,v in ipairs{ "thread", @@ -498,6 +494,10 @@ function love.init() end end + if love.audio then + love.audio.setMixMode(c.audio.mixmode, c.audio.playmuted) + end + -- Our first timestep, because window creation can take some time if love.timer then love.timer.step() diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index e53ba39ab..f6d4c8f67 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -781,13 +781,6 @@ const unsigned char boot_lua[] = 0x72, 0x72, 0x65, 0x63, 0x74, 0x28, 0x63, 0x2e, 0x67, 0x61, 0x6d, 0x6d, 0x61, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, - 0x4d, 0x69, 0x78, 0x4d, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x4d, 0x69, - 0x78, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x6d, - 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x6d, - 0x75, 0x74, 0x65, 0x64, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x73, 0x20, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, @@ -918,6 +911,13 @@ const unsigned char boot_lua[] = 0x77, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x29, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, + 0x6e, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x69, + 0x78, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x6d, + 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x6d, + 0x75, 0x74, 0x65, 0x64, 0x29, 0x0a, + 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x4f, 0x75, 0x72, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x70, 0x2c, 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x74, 0x61, From 130ee7e1d93efb6cc57470cf5b6d37568a6f0152 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 11 Jul 2017 20:38:47 -0300 Subject: [PATCH 04/36] Consolidated Image and Canvas dimension validation code. --HG-- branch : minor --- src/modules/graphics/Canvas.cpp | 38 +----------------- src/modules/graphics/Texture.cpp | 57 +++++++++++++++++++++++++++ src/modules/graphics/Texture.h | 2 + src/modules/graphics/opengl/Image.cpp | 16 +------- 4 files changed, 61 insertions(+), 52 deletions(-) diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index df5194ed2..a0626112f 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -97,43 +97,7 @@ Canvas::Canvas(const Settings &settings) throw love::Exception("%s textures are not supported on this system!", textypestr); } - int maxsize = 0; - switch (texType) - { - case TEXTURE_2D: - maxsize = (int) caps.limits[Graphics::LIMIT_TEXTURE_SIZE]; - if (pixelWidth > maxsize) - throw TextureTooLargeException("width", pixelWidth); - else if (pixelHeight > maxsize) - throw TextureTooLargeException("height", pixelHeight); - break; - case TEXTURE_VOLUME: - maxsize = (int) caps.limits[Graphics::LIMIT_VOLUME_TEXTURE_SIZE]; - if (pixelWidth > maxsize) - throw TextureTooLargeException("width", pixelWidth); - else if (pixelHeight > maxsize) - throw TextureTooLargeException("height", pixelHeight); - else if (depth > maxsize) - throw TextureTooLargeException("depth", depth); - break; - case TEXTURE_2D_ARRAY: - maxsize = (int) caps.limits[Graphics::LIMIT_TEXTURE_SIZE]; - if (pixelWidth > maxsize) - throw TextureTooLargeException("width", pixelWidth); - else if (pixelHeight > maxsize) - throw TextureTooLargeException("height", pixelHeight); - else if (layers > (int) caps.limits[Graphics::LIMIT_TEXTURE_LAYERS]) - throw TextureTooLargeException("array layer count", layers); - break; - case TEXTURE_CUBE: - if (pixelWidth != pixelHeight) - throw love::Exception("Cubemap textures must have equal width and height."); - else if (pixelWidth > (int) caps.limits[Graphics::LIMIT_CUBE_TEXTURE_SIZE]) - throw TextureTooLargeException("width", pixelWidth); - break; - default: - break; - } + validateDimensions(true); canvasCount++; } diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 80c951d32..57f6546fd 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -317,6 +317,63 @@ int Texture::getMipmapCount(int w, int h, int d) return (int) log2(std::max(std::max(w, h), d)) + 1; } +bool Texture::validateDimensions(bool throwException) const +{ + bool success = true; + + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx == nullptr) + return false; + + const Graphics::Capabilities &caps = gfx->getCapabilities(); + + int max2Dsize = (int) caps.limits[Graphics::LIMIT_TEXTURE_SIZE]; + int max3Dsize = (int) caps.limits[Graphics::LIMIT_VOLUME_TEXTURE_SIZE]; + int maxcubesize = (int) caps.limits[Graphics::LIMIT_CUBE_TEXTURE_SIZE]; + int maxlayers = (int) caps.limits[Graphics::LIMIT_TEXTURE_LAYERS]; + + int largestdim = 0; + const char *largestname = nullptr; + + if ((texType == TEXTURE_2D || texType == TEXTURE_2D_ARRAY) && (pixelWidth > max2Dsize || pixelHeight > max2Dsize)) + { + success = false; + largestdim = std::max(pixelWidth, pixelHeight); + largestname = pixelWidth > pixelHeight ? "pixel width" : "pixel height"; + } + else if (texType == TEXTURE_2D_ARRAY && layers > maxlayers) + { + success = false; + largestdim = layers; + largestname = "array layer count"; + } + else if (texType == TEXTURE_CUBE && (pixelWidth > maxcubesize || pixelWidth != pixelHeight)) + { + success = false; + largestdim = std::max(pixelWidth, pixelHeight); + largestname = pixelWidth > pixelHeight ? "pixel width" : "pixel height"; + + if (throwException && pixelWidth != pixelHeight) + throw love::Exception("Cubemap textures must have equal width and height."); + } + else if (texType == TEXTURE_VOLUME && (pixelWidth > max3Dsize || pixelHeight > max3Dsize || depth > max3Dsize)) + { + success = false; + largestdim = std::max(std::max(pixelWidth, pixelHeight), depth); + if (largestdim == pixelWidth) + largestname = "pixel width"; + else if (largestdim == pixelHeight) + largestname = "pixel height"; + else + largestname = "pixel depth"; + } + + if (throwException && largestname != nullptr) + throw love::Exception("Cannot create texture: %s of %d is too large for this system.", largestname, largestdim); + + return success; +} + bool Texture::getConstant(const char *in, TextureType &out) { return texTypes.find(in, out); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 7d5b20180..9bf3dea43 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -174,6 +174,8 @@ protected: void initQuad(); void setGraphicsMemorySize(int64 size); + bool validateDimensions(bool throwException) const; + TextureType texType; PixelFormat format; diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 42c940e18..d04e4ff2b 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -221,22 +221,8 @@ bool Image::loadVolatile() glGenTextures(1, &texture); gl.bindTextureToUnit(this, 0, false); - bool loaddefault = false; - - int max2Dsize = gl.getMax2DTextureSize(); - int max3Dsize = gl.getMax3DTextureSize(); - - if ((texType == TEXTURE_2D || texType == TEXTURE_2D_ARRAY) && (pixelWidth > max2Dsize || pixelHeight > max2Dsize)) - loaddefault = true; - else if (texType == TEXTURE_2D_ARRAY && layers > gl.getMaxTextureLayers()) - loaddefault = true; - else if (texType == TEXTURE_CUBE && (pixelWidth > gl.getMaxCubeTextureSize() || pixelWidth != pixelHeight)) - loaddefault = true; - else if (texType == TEXTURE_VOLUME && (pixelWidth > max3Dsize || pixelHeight > max3Dsize || depth > max3Dsize)) - loaddefault = true; - // Use a default texture if the size is too big for the system. - if (loaddefault) + if (!validateDimensions(false)) { loadDefaultTexture(); return true; From 4e9212b152046b247a270619495a57486f5e02f2 Mon Sep 17 00:00:00 2001 From: Tiago Koji Castro Shibata Date: Thu, 13 Jul 2017 23:54:37 -0300 Subject: [PATCH 05/36] Add Android support to hasBackgroundMusic --- src/common/android.cpp | 16 ++++++++++++++++ src/common/android.h | 2 ++ src/modules/audio/wrap_Audio.cpp | 11 ----------- src/modules/system/System.cpp | 11 +++++++++++ src/modules/system/System.h | 8 ++++++++ src/modules/system/wrap_System.cpp | 14 ++++++++++++++ 6 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/common/android.cpp b/src/common/android.cpp index 872ec2d42..638162647 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -225,6 +225,22 @@ bool createStorageDirectories() return true; } +bool hasBackgroundMusic() +{ + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + jobject activity = (jobject) SDL_AndroidGetActivity(); + + jclass clazz(env->GetObjectClass(activity)); + jmethodID method_id = env->GetMethodID(clazz, "hasBackgroundMusic", "()Z"); + + jboolean result = env->CallBooleanMethod(activity, method_id); + + env->DeleteLocalRef(activity); + env->DeleteLocalRef(clazz); + + return result; +} + } // android } // love diff --git a/src/common/android.h b/src/common/android.h index 1e4e62a39..7a7f33dd0 100644 --- a/src/common/android.h +++ b/src/common/android.h @@ -66,6 +66,8 @@ bool mkdir(const char *path); bool createStorageDirectories(); +bool hasBackgroundMusic(); + } // android } // love diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index e00b0eb4a..2869b3adc 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -307,16 +307,6 @@ int w_setMixMode(lua_State *) return 0; } -int w_getShouldBeSilenced(lua_State *L) -{ -#ifdef LOVE_IOS - lua_pushboolean(L, love::ios::audioShouldBeSilenced()); -#else - lua_pushboolean(L, 0); -#endif - return 1; -} - // List of functions to wrap. static const luaL_Reg functions[] = { @@ -343,7 +333,6 @@ static const luaL_Reg functions[] = { "setDistanceModel", w_setDistanceModel }, { "getDistanceModel", w_getDistanceModel }, { "setMixMode", w_setMixMode }, - { "getShouldBeSilenced", w_getShouldBeSilenced }, { 0, 0 } }; diff --git a/src/modules/system/System.cpp b/src/modules/system/System.cpp index 5ad391188..5951449f6 100644 --- a/src/modules/system/System.cpp +++ b/src/modules/system/System.cpp @@ -184,6 +184,17 @@ void System::vibrate(double seconds) const #endif } +bool System::hasBackgroundMusic() const +{ +#if defined(LOVE_ANDROID) + return love::android::hasBackgroundMusic(); +#elif defined(LOVE_IOS) + return love::ios::audioShouldBeSilenced(); +#else + throw love::Exception("Unsupported platform."); +#endif +} + bool System::getConstant(const char *in, System::PowerState &out) { return powerStates.find(in, out); diff --git a/src/modules/system/System.h b/src/modules/system/System.h index 42bbc077f..5efa3abc9 100644 --- a/src/modules/system/System.h +++ b/src/modules/system/System.h @@ -106,6 +106,14 @@ public: */ virtual void vibrate(double seconds) const; + /** + * Gets if the user is playing music on background. + * Throws an exception on unsupported platforms. + * + * @return Whether a music is playing on background. + **/ + bool hasBackgroundMusic() const; + static bool getConstant(const char *in, PowerState &out); static bool getConstant(PowerState in, const char *&out); diff --git a/src/modules/system/wrap_System.cpp b/src/modules/system/wrap_System.cpp index a299583f8..fd2cee7aa 100644 --- a/src/modules/system/wrap_System.cpp +++ b/src/modules/system/wrap_System.cpp @@ -93,6 +93,19 @@ int w_vibrate(lua_State *L) return 0; } +int w_hasBackgroundMusic(lua_State *L) +{ + try + { + lua_pushboolean(L, instance()->hasBackgroundMusic()); + } + catch (love::Exception &) + { + lua_pushnil(L); + } + return 1; +} + static const luaL_Reg functions[] = { { "getOS", w_getOS }, @@ -102,6 +115,7 @@ static const luaL_Reg functions[] = { "getPowerInfo", w_getPowerInfo }, { "openURL", w_openURL }, { "vibrate", w_vibrate }, + { "hasBackgroundMusic", w_hasBackgroundMusic }, { 0, 0 } }; From abcade9421cea3858f2ef46af538733d69d09ef3 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 14 Jul 2017 23:34:06 -0300 Subject: [PATCH 06/36] Updated the changelog --HG-- branch : minor --- changes.txt | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/changes.txt b/changes.txt index 104f9214e..9df6acc12 100644 --- a/changes.txt +++ b/changes.txt @@ -3,54 +3,80 @@ LOVE 0.11.0 [] Released: N/A + * Added Object:release. + * Added Data:clone. + * Added queueable audio sources. + * Added audio input support. + * Added Source filters: low gain, high gain and band pass. + * Added audio effect APIs (reverb, echo, etc.) * Added a variant to World:update, which accepts the number of iterations to run. The defaults are now 8 and 3. * Added a click count argument to love.mousepressed and love.mousereleased. * Added love.filesystem.get/setCRequirePath, and use that to find c libraries for require. * Added Channel:hasRead, which checks if a message has been read. Takes an id, which Channel:push will now return. * Added love.math.encode/decode, which support hex and base64. * Added love.math.hash, which supports MD5, SHA-1 and the SHA-2 family. + * Added Transform objects to love.math. * Added support for different ImageData formats, including RGBA8 (the default), RGBA16, RGBA16F, and RGBA32F. * Added the ability to load Radiance HDR, OpenEXR, and 16 bit PNG images. * Added love.graphics.getImageFormats (replaces love.graphics.getCompressedImageFormats). * Added the ability to specify a per-object pixel density scale factor when creating Images, Canvases, Fonts, and Videos. Affects drawing. * Added Texture:getPixelWidth/Height and love.graphics.getPixelWidth/Height. * Added Texture:getPixelDensity, love.graphics.getPixelDensity, and Font:getPixelDensity. + * Added Array, Cubemap, and Volume texture types and corresponding Image and Canvas APIs. + * Added love.graphics.getTextureTypes, returns a table with fields indicating support for each texture type. + * Added mipmapping support to Canvases, including both auto-generated mipmaps and manually rendering to a specific mipmap level. + * Added 'stencil8', 'depth24stencil8', 'depth32fstencil8', 'depth16', 'depth24', and 'depth32f' pixel formats for Canvases. + * Added optional 'readable' boolean field to the table passed into love.graphics.newCanvas. + * Added optional 'depthstencil' field to the table passed into love.graphics.setCanvas, for using a depth/stencil Canvas. + * Added optional 'depth' and 'stencil' boolean fields to the table passed into setCanvas, for enabling depth and stencil buffers if 'depthstencil' isn't used. + * Added shadow sampler support for Canvases. + * Added variant of love.graphics.getCanvasFormats which takes a 'readable' boolean. + * Added love.graphics.drawLayer and SpriteBatch:add/setLayer for easily drawing layers of Array Textures. + * Added variants of love.graphics.print and printf which take a Font argument. + * Added variants of love.graphics.clear to control how the active depth and stencil buffers are cleared. + * Added love.graphics.flushBatch for manually flushing automatically batched draws. * Added SpriteBatch:setDrawRange. * Added per-shader opt in support for the GLSL 3.30 and GLSL ES 3.00 shading languages. + * Added 'void effect()' pixel shader entry point. * Added love.graphics.validateShader. * Added Shader:hasUniform. * Added support for non-square shader uniform matrices on desktop platforms and on mobile GLSL 3. * Added Shader:send(matrixname, is_column_major, matrix, ...) which specifies how to interpret the matrix table arguments. + * Added 'borderellipse' and 'borderrectangle' ParticleSystem distributions. + * Added ParticleSystem:set/getAreaSpreadAngle and set/getAreaSpreadIsRelativeDirection. * Added love.graphics.captureScreenshot (replaces love.graphics.newScreenshot). - * Added love.window.updateMode. - * Added the ability to prevent love from creating a stencil buffer for the window. - * Added Object:release. - * Added queueable audio sources. - * Added audio input support. - * Added Transform objects to love.math. - * Added 'glsl3', 'instancing', 'fullnpot', and 'pixelshaderhighp' graphics features. + * Added 'glsl3', 'instancing', 'fullnpot','pixelshaderhighp', and 'shaderderivatives' graphics features. * Added 'anisotropy' graphics limit. - * Added Mesh instancing support. + * Added Mesh instancing support via love.graphics.drawInstanced and Mesh:attachAttribute. * Added a Mesh:attachAttribute variant that takes a different target attribute name. * Added Mesh:detachAttribute. * Added a variant of Mesh:setVertexMap which accepts a Data object. - * Added Source filters: low gain, high gain and band pass. + * Added love.window.updateMode. + * Added the ability to prevent love from creating a stencil buffer for the window. * Changed all color values to be in the range 0-1, rather than 0-255. * Changed high-dpi functionality to require much less code (often none at all) for things to appear at the correct sizes and positions. * Changed love.graphics.print and friends to ignore carriage returns. * Changed the 'multiply' blend mode to error if not used with the 'premultiplied' blend alpha mode, since the formula only works with that anyway. * Changed some love.graphics, love.window, and love.event APIs to cause an error if a Canvas is active. + * Changed stenciling functionality with a Canvas active to require stencil=true (or a custom stencil-formatted Canvas) to be set in setCanvas. * Changed Mesh:setDrawRange to take 'start' and 'count' parameters instead of 'min' and 'max'. * Changed the 'vsync' field of love.window.setMode and t.window in love.conf. It's now an integer with 0 disabling vsync. * Changed the audio playback APIs drastically. * Changed enet to no longer set the 'enet' global, again matching luasocket. * Changed Source seeking behaviour, all kinds of Sources now behave similarly when seeking past the boundaries. + * Fixed a memory leak when sending love objects to threads which never load that object's module. + * Fixed os.execute always returning -1 in Linux. + * Fixed the default reference angle for WeldJoint, PrismaticJoint, and RevoluteJoint. + * Fixed love.graphics.set/getClipboard text to error instead of crashing, when a window hasn't been created. * Fixed Joystick:getGamepadMapping to work with xinput controllers. + * Fixed baseline calculation when rendering text. + * Fixed VaryingTexCoords and love_ScreenSize in shaders to be 'highp' in OpenGL ES, when supported. * Improved performance when drawing textures, shapes, lines, and points by automatically batching their draw calls together when possible. * Improved performance of Shader:send when the Shader is not active. + * Improved performance of love.math.randomNormal when LuaJIT's JIT compiler is enabled. * Renamed love.window.getPixelScale to love.window.getPixelDensity. @@ -58,6 +84,7 @@ Released: N/A * Removed variant of love.filesystem.newFileData which takes base64 data, use love.math.decode instead. * Removed the no-argument variant of Text:set, use Text:clear instead. * Removed love.graphics.getCompressedImageFormats, use love.graphics.getImageFormats instead. + * Removed the 'void effects(...)' pixel shader entry point. Use the new 'void effect()' instead. * Removed Shader:getExternVariable, use Shader:hasUniform instead. * Removed love.graphics.newScreenshot, use love.graphics.captureScreenshot instead. * Removed deprecated enet function host:socket_get_address. @@ -66,9 +93,12 @@ Released: N/A * Removed love.window.isCreated (use love.window.isOpen instead). * Updated Source:seek to work if the Source isn't playing. + * Updated love.event.poll to stop allocating memory unnecessarily. * Updated love.math.random to have improved numeric distribution. * Updated love.graphics to support Core Profile OpenGL 3.3+ when available. + * Updated shaders to always expose derivative functions (dFdx, dFdy, fwidth) when available in OpenGL ES. * Updated love.graphics.circle/ellipse/arc/rectangle to take transformation scale into account when determining the number of segments to use. + * Updated Font glyph generation to improve antialiasing. * Updated Canvas:newImageData to return an ImageData with a format that matches the Canvas' as closely as possible. * Updated love.graphics.newImage to treat file names ending with "@2x", "@3x", etc. as a pixel density scale factor if none is explicitly supplied. * Updated luasocket to version 3.0rc1. From 34ebe18f14d31d0fe7935de6a78fdafbb6189e0b Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 16 Jul 2017 12:17:50 -0300 Subject: [PATCH 07/36] Use luaL_check/optinteger instead of luaL_check/optnumber when getting integer arguments to functions. Resolves issue #1251. --HG-- branch : minor --- src/modules/audio/wrap_Audio.cpp | 2 +- src/modules/font/wrap_Font.cpp | 6 +-- src/modules/graphics/opengl/Mesh.cpp | 2 +- src/modules/graphics/wrap_Canvas.cpp | 2 +- src/modules/graphics/wrap_Graphics.cpp | 50 +++++++++---------- src/modules/graphics/wrap_Image.cpp | 6 +-- src/modules/graphics/wrap_Mesh.cpp | 6 +-- src/modules/graphics/wrap_ParticleSystem.cpp | 2 +- src/modules/graphics/wrap_Quad.cpp | 2 +- src/modules/graphics/wrap_SpriteBatch.cpp | 10 ++-- src/modules/graphics/wrap_Text.cpp | 6 +-- .../image/wrap_CompressedImageData.cpp | 6 +-- src/modules/image/wrap_Image.cpp | 4 +- src/modules/image/wrap_ImageData.cpp | 20 ++++---- src/modules/joystick/wrap_Joystick.cpp | 8 +-- src/modules/joystick/wrap_JoystickModule.cpp | 6 +-- src/modules/love/love.cpp | 6 +-- src/modules/math/wrap_BezierCurve.cpp | 12 ++--- src/modules/math/wrap_Math.cpp | 2 +- src/modules/mouse/wrap_Mouse.cpp | 8 +-- src/modules/physics/box2d/Fixture.cpp | 4 +- src/modules/physics/box2d/Physics.cpp | 18 +++---- src/modules/physics/box2d/Physics.h | 6 +-- src/modules/physics/box2d/Shape.cpp | 4 +- src/modules/physics/box2d/wrap_ChainShape.cpp | 4 +- src/modules/physics/box2d/wrap_Fixture.cpp | 8 +-- src/modules/physics/box2d/wrap_Physics.cpp | 2 +- src/modules/physics/box2d/wrap_World.cpp | 4 +- src/modules/sound/wrap_Sound.cpp | 10 ++-- src/modules/window/wrap_Window.cpp | 28 +++++------ 30 files changed, 127 insertions(+), 127 deletions(-) diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 434079753..d3c985b50 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -84,7 +84,7 @@ int w_newQueueableSource(lua_State *L) Source *t = nullptr; luax_catchexcept(L, [&]() { - t = instance()->newSource((int)luaL_checknumber(L, 1), (int)luaL_checknumber(L, 2), (int)luaL_checknumber(L, 3), (int)luaL_optnumber(L, 4, 0)); + t = instance()->newSource((int)luaL_checkinteger(L, 1), (int)luaL_checkinteger(L, 2), (int)luaL_checkinteger(L, 3), (int)luaL_optinteger(L, 4, 0)); }); if (t != nullptr) diff --git a/src/modules/font/wrap_Font.cpp b/src/modules/font/wrap_Font.cpp index d11a7511d..7972f8a5b 100644 --- a/src/modules/font/wrap_Font.cpp +++ b/src/modules/font/wrap_Font.cpp @@ -72,7 +72,7 @@ int w_newTrueTypeRasterizer(lua_State *L) if (lua_type(L, 1) == LUA_TNUMBER || lua_isnone(L, 1)) { // First argument is a number: use the default TrueType font. - int size = (int) luaL_optnumber(L, 1, 12); + int size = (int) luaL_optinteger(L, 1, 12); const char *hintstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2); if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting)) @@ -98,7 +98,7 @@ int w_newTrueTypeRasterizer(lua_State *L) else d = filesystem::luax_getfiledata(L, 1); - int size = (int) luaL_optnumber(L, 2, 12); + int size = (int) luaL_optinteger(L, 2, 12); const char *hintstr = lua_isnoneornil(L, 3) ? nullptr : luaL_checkstring(L, 3); if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting)) @@ -180,7 +180,7 @@ int w_newImageRasterizer(lua_State *L) image::ImageData *d = luax_checktype(L, 1); std::string glyphs = luax_checkstring(L, 2); - int extraspacing = (int) luaL_optnumber(L, 3, 0); + int extraspacing = (int) luaL_optinteger(L, 3, 0); float pixeldensity = (float) luaL_optnumber(L, 4, 1.0); luax_catchexcept(L, [&](){ t = instance()->newImageRasterizer(d, glyphs, extraspacing, pixeldensity); }); diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index f84a779b8..d9b0207f6 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -96,7 +96,7 @@ void Mesh::drawInstanced(love::graphics::Graphics *gfx, const love::Matrix4 &m, if (vertexCount <= 0 || instancecount <= 0) return; - if (instancecount > 1 && !gl.isInstancingSupported()) + if (instancecount > 1 && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING]) throw love::Exception("Instancing is not supported on this system."); gfx->flushStreamDraws(); diff --git a/src/modules/graphics/wrap_Canvas.cpp b/src/modules/graphics/wrap_Canvas.cpp index 808f361ae..178c94d4b 100644 --- a/src/modules/graphics/wrap_Canvas.cpp +++ b/src/modules/graphics/wrap_Canvas.cpp @@ -46,7 +46,7 @@ int w_Canvas_renderTo(lua_State *L) if (rt.canvas->getTextureType() != TEXTURE_2D) { - rt.slice = (int) luaL_checknumber(L, 2) - 1; + rt.slice = (int) luaL_checkinteger(L, 2) - 1; startidx++; } diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index c6b4ce142..e6e870813 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -321,7 +321,7 @@ int w_setCanvas(lua_State *L) if (i == 1 && type != TEXTURE_2D) { - target.slice = (int) luaL_checknumber(L, i + 1) - 1; + target.slice = (int) luaL_checkinteger(L, i + 1) - 1; target.mipmap = (int) luaL_optinteger(L, i + 2, 1) - 1; targets.colors.push_back(target); break; @@ -470,10 +470,10 @@ int w_setScissor(lua_State *L) } Rect rect; - rect.x = (int) luaL_checknumber(L, 1); - rect.y = (int) luaL_checknumber(L, 2); - rect.w = (int) luaL_checknumber(L, 3); - rect.h = (int) luaL_checknumber(L, 4); + rect.x = (int) luaL_checkinteger(L, 1); + rect.y = (int) luaL_checkinteger(L, 2); + rect.w = (int) luaL_checkinteger(L, 3); + rect.h = (int) luaL_checkinteger(L, 4); if (rect.w < 0 || rect.h < 0) return luaL_error(L, "Can't set scissor with negative width and/or height."); @@ -485,10 +485,10 @@ int w_setScissor(lua_State *L) int w_intersectScissor(lua_State *L) { Rect rect; - rect.x = (int) luaL_checknumber(L, 1); - rect.y = (int) luaL_checknumber(L, 2); - rect.w = (int) luaL_checknumber(L, 3); - rect.h = (int) luaL_checknumber(L, 4); + rect.x = (int) luaL_checkinteger(L, 1); + rect.y = (int) luaL_checkinteger(L, 2); + rect.w = (int) luaL_checkinteger(L, 3); + rect.h = (int) luaL_checkinteger(L, 4); if (rect.w < 0 || rect.h < 0) return luaL_error(L, "Can't set scissor with negative width and/or height."); @@ -524,7 +524,7 @@ int w_stencil(lua_State *L) return luaL_error(L, "Invalid stencil draw action: %s", actionstr); } - int stencilvalue = (int) luaL_optnumber(L, 3, 1); + int stencilvalue = (int) luaL_optinteger(L, 3, 1); // Fourth argument: whether to keep the contents of the stencil buffer. OptionalInt stencilclear; @@ -561,7 +561,7 @@ int w_setStencilTest(lua_State *L) if (!getConstant(comparestr, compare)) return luaL_error(L, "Invalid compare mode: %s", comparestr); - comparevalue = (int) luaL_checknumber(L, 2); + comparevalue = (int) luaL_checkinteger(L, 2); } luax_catchexcept(L, [&](){ instance()->setStencilTest(compare, comparevalue); }); @@ -942,14 +942,14 @@ int w_newQuad(lua_State *L) } else if (luax_istype(L, 6, Texture::type)) { - layer = (int) luaL_checknumber(L, 5) - 1; + layer = (int) luaL_checkinteger(L, 5) - 1; Texture *texture = luax_checktexture(L, 6); sw = texture->getWidth(); sh = texture->getHeight(); } else if (!lua_isnoneornil(L, 7)) { - layer = (int) luaL_checknumber(L, 5) - 1; + layer = (int) luaL_checkinteger(L, 5) - 1; sw = luaL_checknumber(L, 6); sh = luaL_checknumber(L, 7); } @@ -1030,7 +1030,7 @@ int w_newSpriteBatch(lua_State *L) luax_checkgraphicscreated(L); Texture *texture = luax_checktexture(L, 1); - int size = (int) luaL_optnumber(L, 2, 1000); + int size = (int) luaL_optinteger(L, 2, 1000); vertex::Usage usage = vertex::USAGE_DYNAMIC; if (lua_gettop(L) > 2) { @@ -1075,8 +1075,8 @@ int w_newCanvas(lua_State *L) Canvas::Settings settings; // check if width and height are given. else default to screen dimensions. - settings.width = (int) luaL_optnumber(L, 1, instance()->getWidth()); - settings.height = (int) luaL_optnumber(L, 2, instance()->getHeight()); + settings.width = (int) luaL_optinteger(L, 1, instance()->getWidth()); + settings.height = (int) luaL_optinteger(L, 2, instance()->getHeight()); // Default to the screen's current pixel density scale. settings.pixeldensity = instance()->getScreenPixelDensity(); @@ -1085,7 +1085,7 @@ int w_newCanvas(lua_State *L) if (lua_isnumber(L, 3)) { - settings.layers = (int) luaL_checknumber(L, 3); + settings.layers = (int) luaL_checkinteger(L, 3); settings.type = TEXTURE_2D_ARRAY; startidx = 4; } @@ -1352,7 +1352,7 @@ static Mesh *newStandardMesh(lua_State *L) } else { - int count = (int) luaL_checknumber(L, 1); + int count = (int) luaL_checkinteger(L, 1); luax_catchexcept(L, [&](){ t = instance()->newMesh(count, drawmode, usage); }); } @@ -1397,7 +1397,7 @@ static Mesh *newCustomMesh(lua_State *L) return nullptr; } - format.components = (int) luaL_checknumber(L, -1); + format.components = (int) luaL_checkinteger(L, -1); if (format.components <= 0 || format.components > 4) { luaL_error(L, "Number of vertex attribute components must be between 1 and 4 (got %d)", format.components); @@ -1410,7 +1410,7 @@ static Mesh *newCustomMesh(lua_State *L) if (lua_isnumber(L, 2)) { - int vertexcount = (int) luaL_checknumber(L, 2); + int vertexcount = (int) luaL_checkinteger(L, 2); luax_catchexcept(L, [&](){ t = instance()->newMesh(vertexformat, vertexcount, drawmode, usage); }); } else if (luax_istype(L, 2, Data::type)) @@ -2135,7 +2135,7 @@ int w_drawLayer(lua_State *L) { Texture *texture = luax_checktexture(L, 1); Quad *quad = nullptr; - int layer = (int) luaL_checknumber(L, 2) - 1; + int layer = (int) luaL_checkinteger(L, 2) - 1; int startidx = 3; if (luax_istype(L, startidx, Quad::type)) @@ -2403,7 +2403,7 @@ int w_rectangle(lua_State *L) luax_catchexcept(L, [&](){ instance()->rectangle(mode, x, y, w, h, rx, ry); }); else { - int points = (int) luaL_checknumber(L, 8); + int points = (int) luaL_checkinteger(L, 8); luax_catchexcept(L, [&](){ instance()->rectangle(mode, x, y, w, h, rx, ry, points); }); } @@ -2425,7 +2425,7 @@ int w_circle(lua_State *L) luax_catchexcept(L, [&](){ instance()->circle(mode, x, y, radius); }); else { - int points = (int) luaL_checknumber(L, 5); + int points = (int) luaL_checkinteger(L, 5); luax_catchexcept(L, [&](){ instance()->circle(mode, x, y, radius, points); }); } @@ -2448,7 +2448,7 @@ int w_ellipse(lua_State *L) luax_catchexcept(L, [&](){ instance()->ellipse(mode, x, y, a, b); }); else { - int points = (int) luaL_checknumber(L, 6); + int points = (int) luaL_checkinteger(L, 6); luax_catchexcept(L, [&](){ instance()->ellipse(mode, x, y, a, b, points); }); } @@ -2485,7 +2485,7 @@ int w_arc(lua_State *L) luax_catchexcept(L, [&](){ instance()->arc(drawmode, arcmode, x, y, radius, angle1, angle2); }); else { - int points = (int) luaL_checknumber(L, startidx + 5); + int points = (int) luaL_checkinteger(L, startidx + 5); luax_catchexcept(L, [&](){ instance()->arc(drawmode, arcmode, x, y, radius, angle1, angle2, points); }); } diff --git a/src/modules/graphics/wrap_Image.cpp b/src/modules/graphics/wrap_Image.cpp index b25f7b2ff..5a8b3a4b5 100644 --- a/src/modules/graphics/wrap_Image.cpp +++ b/src/modules/graphics/wrap_Image.cpp @@ -56,12 +56,12 @@ int w_Image_replacePixels(lua_State *L) if (i->getTextureType() != TEXTURE_2D) { - slice = (int) luaL_checknumber(L, 3) - 1; + slice = (int) luaL_checkinteger(L, 3) - 1; if (!reloadmipmaps) - mipmap = (int) luaL_optnumber(L, 4, 1) - 1; + mipmap = (int) luaL_optinteger(L, 4, 1) - 1; } else if (!reloadmipmaps) - mipmap = (int) luaL_optnumber(L, 3, 1) - 1; + mipmap = (int) luaL_optinteger(L, 3, 1) - 1; luax_catchexcept(L, [&](){ i->replacePixels(id, slice, mipmap, reloadmipmaps); }); return 0; diff --git a/src/modules/graphics/wrap_Mesh.cpp b/src/modules/graphics/wrap_Mesh.cpp index a5326c24e..6f6b37f14 100644 --- a/src/modules/graphics/wrap_Mesh.cpp +++ b/src/modules/graphics/wrap_Mesh.cpp @@ -386,7 +386,7 @@ int w_Mesh_setVertexMap(lua_State *L) size_t datatypesize = vertex::getIndexDataSize(indextype); - int indexcount = (int) luaL_optnumber(L, 4, d->getSize() / datatypesize); + int indexcount = (int) luaL_optinteger(L, 4, d->getSize() / datatypesize); if (indexcount < 1 || indexcount * datatypesize > d->getSize()) return luaL_error(L, "Invalid index count: %d", indexcount); @@ -515,8 +515,8 @@ int w_Mesh_setDrawRange(lua_State *L) t->setDrawRange(); else { - int start = (int) luaL_checknumber(L, 2) - 1; - int count = (int) luaL_checknumber(L, 3); + int start = (int) luaL_checkinteger(L, 2) - 1; + int count = (int) luaL_checkinteger(L, 3); luax_catchexcept(L, [&](){ t->setDrawRange(start, count); }); } diff --git a/src/modules/graphics/wrap_ParticleSystem.cpp b/src/modules/graphics/wrap_ParticleSystem.cpp index 4958063c3..0f0e7642e 100644 --- a/src/modules/graphics/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/wrap_ParticleSystem.cpp @@ -699,7 +699,7 @@ int w_ParticleSystem_reset(lua_State *L) int w_ParticleSystem_emit(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); - int num = (int) luaL_checknumber(L, 2); + int num = (int) luaL_checkinteger(L, 2); t->emit(num); return 0; } diff --git a/src/modules/graphics/wrap_Quad.cpp b/src/modules/graphics/wrap_Quad.cpp index db2584ba3..00b728368 100644 --- a/src/modules/graphics/wrap_Quad.cpp +++ b/src/modules/graphics/wrap_Quad.cpp @@ -77,7 +77,7 @@ int w_Quad_getTextureDimensions(lua_State *L) int w_Quad_setLayer(lua_State *L) { Quad *quad = luax_checkquad(L, 1); - int layer = (int) luaL_checknumber(L, 2) - 1; + int layer = (int) luaL_checkinteger(L, 2) - 1; quad->setLayer(layer); return 0; } diff --git a/src/modules/graphics/wrap_SpriteBatch.cpp b/src/modules/graphics/wrap_SpriteBatch.cpp index 544d2c936..e7040bdf5 100644 --- a/src/modules/graphics/wrap_SpriteBatch.cpp +++ b/src/modules/graphics/wrap_SpriteBatch.cpp @@ -63,7 +63,7 @@ static inline int w_SpriteBatch_add_or_set(lua_State *L, SpriteBatch *t, int sta static int w_SpriteBatch_addLayer_or_setLayer(lua_State *L, SpriteBatch *t, int startidx, int index) { Quad *quad = nullptr; - int layer = (int) luaL_checknumber(L, startidx) - 1; + int layer = (int) luaL_checkinteger(L, startidx) - 1; startidx++; if (luax_istype(L, startidx, Quad::type)) @@ -101,7 +101,7 @@ int w_SpriteBatch_add(lua_State *L) int w_SpriteBatch_set(lua_State *L) { SpriteBatch *t = luax_checkspritebatch(L, 1); - int index = (int) luaL_checknumber(L, 2) - 1; + int index = (int) luaL_checkinteger(L, 2) - 1; w_SpriteBatch_add_or_set(L, t, 3, index); @@ -121,7 +121,7 @@ int w_SpriteBatch_addLayer(lua_State *L) int w_SpriteBatch_setLayer(lua_State *L) { SpriteBatch *t = luax_checkspritebatch(L, 1); - int index = (int) luaL_checknumber(L, 2) - 1; + int index = (int) luaL_checkinteger(L, 2) - 1; w_SpriteBatch_addLayer_or_setLayer(L, t, 3, index); @@ -251,8 +251,8 @@ int w_SpriteBatch_setDrawRange(lua_State *L) t->setDrawRange(); else { - int start = (int) luaL_checknumber(L, 2) - 1; - int count = (int) luaL_checknumber(L, 3); + int start = (int) luaL_checkinteger(L, 2) - 1; + int count = (int) luaL_checkinteger(L, 3); luax_catchexcept(L, [&](){ t->setDrawRange(start, count); }); } diff --git a/src/modules/graphics/wrap_Text.cpp b/src/modules/graphics/wrap_Text.cpp index 499c845d9..f003778fc 100644 --- a/src/modules/graphics/wrap_Text.cpp +++ b/src/modules/graphics/wrap_Text.cpp @@ -183,7 +183,7 @@ int w_Text_getFont(lua_State *L) int w_Text_getWidth(lua_State *L) { Text *t = luax_checktext(L, 1); - int index = (int) luaL_optnumber(L, 2, 0) - 1; + int index = (int) luaL_optinteger(L, 2, 0) - 1; lua_pushnumber(L, t->getWidth(index)); return 1; } @@ -191,7 +191,7 @@ int w_Text_getWidth(lua_State *L) int w_Text_getHeight(lua_State *L) { Text *t = luax_checktext(L, 1); - int index = (int) luaL_optnumber(L, 2, 0) - 1; + int index = (int) luaL_optinteger(L, 2, 0) - 1; lua_pushnumber(L, t->getHeight(index)); return 1; } @@ -199,7 +199,7 @@ int w_Text_getHeight(lua_State *L) int w_Text_getDimensions(lua_State *L) { Text *t = luax_checktext(L, 1); - int index = (int) luaL_optnumber(L, 2, 0) - 1; + int index = (int) luaL_optinteger(L, 2, 0) - 1; lua_pushnumber(L, t->getWidth(index)); lua_pushnumber(L, t->getHeight(index)); return 2; diff --git a/src/modules/image/wrap_CompressedImageData.cpp b/src/modules/image/wrap_CompressedImageData.cpp index 191e44c82..490394a2c 100644 --- a/src/modules/image/wrap_CompressedImageData.cpp +++ b/src/modules/image/wrap_CompressedImageData.cpp @@ -43,7 +43,7 @@ int w_CompressedImageData_clone(lua_State *L) int w_CompressedImageData_getWidth(lua_State *L) { CompressedImageData *t = luax_checkcompressedimagedata(L, 1); - int miplevel = (int) luaL_optnumber(L, 2, 1); + int miplevel = (int) luaL_optinteger(L, 2, 1); int width = 0; luax_catchexcept(L, [&](){ width = t->getWidth(miplevel - 1); }); @@ -55,7 +55,7 @@ int w_CompressedImageData_getWidth(lua_State *L) int w_CompressedImageData_getHeight(lua_State *L) { CompressedImageData *t = luax_checkcompressedimagedata(L, 1); - int miplevel = (int) luaL_optnumber(L, 2, 1); + int miplevel = (int) luaL_optinteger(L, 2, 1); int height = 0; luax_catchexcept(L, [&](){ height = t->getHeight(miplevel - 1); }); @@ -67,7 +67,7 @@ int w_CompressedImageData_getHeight(lua_State *L) int w_CompressedImageData_getDimensions(lua_State *L) { CompressedImageData *t = luax_checkcompressedimagedata(L, 1); - int miplevel = (int) luaL_optnumber(L, 2, 1); + int miplevel = (int) luaL_optinteger(L, 2, 1); int width = 0, height = 0; luax_catchexcept(L, [&]() diff --git a/src/modules/image/wrap_Image.cpp b/src/modules/image/wrap_Image.cpp index ace0db780..3456fe76f 100644 --- a/src/modules/image/wrap_Image.cpp +++ b/src/modules/image/wrap_Image.cpp @@ -39,8 +39,8 @@ int w_newImageData(lua_State *L) // Case 1: width & height. if (lua_isnumber(L, 1)) { - int w = (int) luaL_checknumber(L, 1); - int h = (int) luaL_checknumber(L, 2); + int w = (int) luaL_checkinteger(L, 1); + int h = (int) luaL_checkinteger(L, 2); if (w <= 0 || h <= 0) return luaL_error(L, "Invalid image size."); diff --git a/src/modules/image/wrap_ImageData.cpp b/src/modules/image/wrap_ImageData.cpp index f65d960c9..3f411e2fe 100644 --- a/src/modules/image/wrap_ImageData.cpp +++ b/src/modules/image/wrap_ImageData.cpp @@ -158,8 +158,8 @@ static pushpixel pushFormats[PIXELFORMAT_MAX_ENUM] = {}; int w_ImageData_getPixel(lua_State *L) { ImageData *t = luax_checkimagedata(L, 1); - int x = (int) luaL_checknumber(L, 2); - int y = (int) luaL_checknumber(L, 3); + int x = (int) luaL_checkinteger(L, 2); + int y = (int) luaL_checkinteger(L, 3); PixelFormat format = t->getFormat(); @@ -172,8 +172,8 @@ int w_ImageData_getPixel(lua_State *L) int w_ImageData_setPixel(lua_State *L) { ImageData *t = luax_checkimagedata(L, 1); - int x = (int) luaL_checknumber(L, 2); - int y = (int) luaL_checknumber(L, 3); + int x = (int) luaL_checkinteger(L, 2); + int y = (int) luaL_checkinteger(L, 3); PixelFormat format = t->getFormat(); @@ -247,12 +247,12 @@ int w_ImageData_paste(lua_State *L) { ImageData *t = luax_checkimagedata(L, 1); ImageData *src = luax_checkimagedata(L, 2); - int dx = (int) luaL_checknumber(L, 3); - int dy = (int) luaL_checknumber(L, 4); - int sx = (int) luaL_optnumber(L, 5, 0); - int sy = (int) luaL_optnumber(L, 6, 0); - int sw = (int) luaL_optnumber(L, 7, src->getWidth()); - int sh = (int) luaL_optnumber(L, 8, src->getHeight()); + int dx = (int) luaL_checkinteger(L, 3); + int dy = (int) luaL_checkinteger(L, 4); + int sx = (int) luaL_optinteger(L, 5, 0); + int sy = (int) luaL_optinteger(L, 6, 0); + int sw = (int) luaL_optinteger(L, 7, src->getWidth()); + int sh = (int) luaL_optinteger(L, 8, src->getHeight()); t->paste((love::image::ImageData *)src, dx, dy, sx, sy, sw, sh); return 0; } diff --git a/src/modules/joystick/wrap_Joystick.cpp b/src/modules/joystick/wrap_Joystick.cpp index 444601304..45ecc81bf 100644 --- a/src/modules/joystick/wrap_Joystick.cpp +++ b/src/modules/joystick/wrap_Joystick.cpp @@ -95,7 +95,7 @@ int w_Joystick_getHatCount(lua_State *L) int w_Joystick_getAxis(lua_State *L) { Joystick *j = luax_checkjoystick(L, 1); - int axisindex = (int) luaL_checknumber(L, 2) - 1; + int axisindex = (int) luaL_checkinteger(L, 2) - 1; lua_pushnumber(L, j->getAxis(axisindex)); return 1; } @@ -114,7 +114,7 @@ int w_Joystick_getAxes(lua_State *L) int w_Joystick_getHat(lua_State *L) { Joystick *j = luax_checkjoystick(L, 1); - int hatindex = (int) luaL_checknumber(L, 2) - 1; + int hatindex = (int) luaL_checkinteger(L, 2) - 1; Joystick::Hat h = j->getHat(hatindex); @@ -143,14 +143,14 @@ int w_Joystick_isDown(lua_State *L) for (int i = 0; i < num; i++) { lua_rawgeti(L, 2, i + 1); - buttons.push_back((int) luaL_checknumber(L, -1) - 1); + buttons.push_back((int) luaL_checkinteger(L, -1) - 1); lua_pop(L, 1); } } else { for (int i = 0; i < num; i++) - buttons.push_back((int) luaL_checknumber(L, i + 2) - 1); + buttons.push_back((int) luaL_checkinteger(L, i + 2) - 1); } luax_pushboolean(L, j->isDown(buttons)); diff --git a/src/modules/joystick/wrap_JoystickModule.cpp b/src/modules/joystick/wrap_JoystickModule.cpp index 16c34a9ed..d982297a5 100644 --- a/src/modules/joystick/wrap_JoystickModule.cpp +++ b/src/modules/joystick/wrap_JoystickModule.cpp @@ -91,14 +91,14 @@ int w_setGamepadMapping(lua_State *L) switch (jinput.type) { case Joystick::INPUT_TYPE_AXIS: - jinput.axis = (int) luaL_checknumber(L, 4) - 1; + jinput.axis = (int) luaL_checkinteger(L, 4) - 1; break; case Joystick::INPUT_TYPE_BUTTON: - jinput.button = (int) luaL_checknumber(L, 4) - 1; + jinput.button = (int) luaL_checkinteger(L, 4) - 1; break; case Joystick::INPUT_TYPE_HAT: // Hats need both a hat index and a hat value. - jinput.hat.index = (int) luaL_checknumber(L, 4) - 1; + jinput.hat.index = (int) luaL_checkinteger(L, 4) - 1; hatstr = luaL_checkstring(L, 5); if (!Joystick::getConstant(hatstr, jinput.hat.value)) return luaL_error(L, "Invalid joystick hat: %s", hatstr); diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 1cecb42a9..2cd4f8007 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -225,9 +225,9 @@ static int w_love_isVersionCompatible(lua_State *L) version = luaL_checkstring(L, 1); else { - int major = (int) luaL_checknumber(L, 1); - int minor = (int) luaL_checknumber(L, 2); - int rev = (int) luaL_checknumber(L, 3); + int major = (int) luaL_checkinteger(L, 1); + int minor = (int) luaL_checkinteger(L, 2); + int rev = (int) luaL_checkinteger(L, 3); // Convert the numbers to a string, since VERSION_COMPATIBILITY is an // array of version strings. diff --git a/src/modules/math/wrap_BezierCurve.cpp b/src/modules/math/wrap_BezierCurve.cpp index 56953fb48..291d62988 100644 --- a/src/modules/math/wrap_BezierCurve.cpp +++ b/src/modules/math/wrap_BezierCurve.cpp @@ -52,7 +52,7 @@ int w_BezierCurve_getDerivative(lua_State *L) int w_BezierCurve_getControlPoint(lua_State *L) { BezierCurve *curve = luax_checkbeziercurve(L, 1); - int idx = (int) luaL_checknumber(L, 2); + int idx = (int) luaL_checkinteger(L, 2); if (idx > 0) // 1-indexing idx--; @@ -69,7 +69,7 @@ int w_BezierCurve_getControlPoint(lua_State *L) int w_BezierCurve_setControlPoint(lua_State *L) { BezierCurve *curve = luax_checkbeziercurve(L, 1); - int idx = (int) luaL_checknumber(L, 2); + int idx = (int) luaL_checkinteger(L, 2); float vx = (float) luaL_checknumber(L, 3); float vy = (float) luaL_checknumber(L, 4); @@ -85,7 +85,7 @@ int w_BezierCurve_insertControlPoint(lua_State *L) BezierCurve *curve = luax_checkbeziercurve(L, 1); float vx = (float) luaL_checknumber(L, 2); float vy = (float) luaL_checknumber(L, 3); - int idx = (int) luaL_optnumber(L, 4, -1); + int idx = (int) luaL_optinteger(L, 4, -1); if (idx > 0) // 1-indexing idx--; @@ -97,7 +97,7 @@ int w_BezierCurve_insertControlPoint(lua_State *L) int w_BezierCurve_removeControlPoint(lua_State *L) { BezierCurve *curve = luax_checkbeziercurve(L, 1); - int idx = (int) luaL_checknumber(L, 2); + int idx = (int) luaL_checkinteger(L, 2); if (idx > 0) // 1-indexing idx--; @@ -174,7 +174,7 @@ int w_BezierCurve_getSegment(lua_State *L) int w_BezierCurve_render(lua_State *L) { BezierCurve *curve = luax_checkbeziercurve(L, 1); - int accuracy = (int) luaL_optnumber(L, 2, 5); + int accuracy = (int) luaL_optinteger(L, 2, 5); std::vector points; luax_catchexcept(L, [&](){ points = curve->render(accuracy); }); @@ -196,7 +196,7 @@ int w_BezierCurve_renderSegment(lua_State *L) BezierCurve *curve = luax_checkbeziercurve(L, 1); double start = luaL_checknumber(L, 2); double end = luaL_checknumber(L, 3); - int accuracy = (int) luaL_optnumber(L, 4, 5); + int accuracy = (int) luaL_optinteger(L, 4, 5); std::vector points; luax_catchexcept(L, [&](){ points = curve->renderSegment(start, end, accuracy); }); diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index 5e7b8d337..6972e838e 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -354,7 +354,7 @@ int w_compress(lua_State *L) if (fstr && !Compressor::getConstant(fstr, format)) return luaL_error(L, "Invalid compressed data format: %s", fstr); - int level = (int) luaL_optnumber(L, 3, -1); + int level = (int) luaL_optinteger(L, 3, -1); CompressedData *cdata = nullptr; if (lua_isstring(L, 1)) diff --git a/src/modules/mouse/wrap_Mouse.cpp b/src/modules/mouse/wrap_Mouse.cpp index c76ee5266..c94fd2de5 100644 --- a/src/modules/mouse/wrap_Mouse.cpp +++ b/src/modules/mouse/wrap_Mouse.cpp @@ -41,8 +41,8 @@ int w_newCursor(lua_State *L) luax_convobj(L, 1, "image", "newImageData"); love::image::ImageData *data = luax_checktype(L, 1); - int hotx = (int) luaL_optnumber(L, 2, 0); - int hoty = (int) luaL_optnumber(L, 3, 0); + int hotx = (int) luaL_optinteger(L, 2, 0); + int hoty = (int) luaL_optinteger(L, 3, 0); luax_catchexcept(L, [&](){ cursor = instance()->newCursor(data, hotx, hoty); }); @@ -154,14 +154,14 @@ int w_isDown(lua_State *L) for (int i = 0; i < num; i++) { lua_rawgeti(L, 1, i + 1); - buttons.push_back((int) luaL_checknumber(L, -1)); + buttons.push_back((int) luaL_checkinteger(L, -1)); lua_pop(L, 1); } } else { for (int i = 0; i < num; i++) - buttons.push_back((int) luaL_checknumber(L, i + 1)); + buttons.push_back((int) luaL_checkinteger(L, i + 1)); } luax_pushboolean(L, instance()->isDown(buttons)); diff --git a/src/modules/physics/box2d/Fixture.cpp b/src/modules/physics/box2d/Fixture.cpp index 2fba43f25..343646b91 100644 --- a/src/modules/physics/box2d/Fixture.cpp +++ b/src/modules/physics/box2d/Fixture.cpp @@ -280,7 +280,7 @@ int Fixture::rayCast(lua_State *L) const float p2x = Physics::scaleDown((float)luaL_checknumber(L, 3)); float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4)); float maxFraction = (float)luaL_checknumber(L, 5); - int childIndex = (int) luaL_optnumber(L, 6, 1) - 1; // Convert from 1-based index + int childIndex = (int) luaL_optinteger(L, 6, 1) - 1; // Convert from 1-based index b2RayCastInput input; input.p1.Set(p1x, p1y); input.p2.Set(p2x, p2y); @@ -296,7 +296,7 @@ int Fixture::rayCast(lua_State *L) const int Fixture::getBoundingBox(lua_State *L) const { - int childIndex = (int) luaL_optnumber(L, 1, 1) - 1; // Convert from 1-based index + int childIndex = (int) luaL_optinteger(L, 1, 1) - 1; // Convert from 1-based index b2AABB box; luax_catchexcept(L, [&]() { box = fixture->GetAABB(childIndex); }); box = Physics::scaleUp(box); diff --git a/src/modules/physics/box2d/Physics.cpp b/src/modules/physics/box2d/Physics.cpp index 91d09bbd7..cddfe2eb9 100644 --- a/src/modules/physics/box2d/Physics.cpp +++ b/src/modules/physics/box2d/Physics.cpp @@ -31,7 +31,7 @@ namespace physics namespace box2d { -int Physics::meter = Physics::DEFAULT_METER; +float Physics::meter = Physics::DEFAULT_METER; const char *Physics::getName() const { @@ -323,37 +323,37 @@ int Physics::getDistance(lua_State *L) return 5; } -void Physics::setMeter(int scale) +void Physics::setMeter(float scale) { if (scale < 1) throw love::Exception("Physics error: invalid meter"); Physics::meter = scale; } -int Physics::getMeter() +float Physics::getMeter() { return meter; } void Physics::scaleDown(float &x, float &y) { - x /= (float)meter; - y /= (float)meter; + x /= meter; + y /= meter; } void Physics::scaleUp(float &x, float &y) { - x *= (float)meter; - y *= (float)meter; + x *= meter; + y *= meter; } float Physics::scaleDown(float f) { - return f/(float)meter; + return f/meter; } float Physics::scaleUp(float f) { - return f*(float)meter; + return f*meter; } b2Vec2 Physics::scaleDown(const b2Vec2 &v) diff --git a/src/modules/physics/box2d/Physics.h b/src/modules/physics/box2d/Physics.h index 996a2d8e5..62e256031 100644 --- a/src/modules/physics/box2d/Physics.h +++ b/src/modules/physics/box2d/Physics.h @@ -292,13 +292,13 @@ public: * Sets the number of pixels in one meter. * @param scale The number of pixels in one meter. (1m ~= 3.3ft). **/ - static void setMeter(int scale); + static void setMeter(float scale); /** * Gets the number of pixels in one meter. * @return The number of pixels in one meter. (1m ~= 3.3ft). **/ - static int getMeter(); + static float getMeter(); /** * Scales a value down according to the current meter in pixels. @@ -359,7 +359,7 @@ public: private: // The length of one meter in pixels. - static int meter; + static float meter; }; // Physics } // box2d diff --git a/src/modules/physics/box2d/Shape.cpp b/src/modules/physics/box2d/Shape.cpp index da6ff272a..84d41e9b4 100644 --- a/src/modules/physics/box2d/Shape.cpp +++ b/src/modules/physics/box2d/Shape.cpp @@ -105,7 +105,7 @@ int Shape::rayCast(lua_State *L) const float x = Physics::scaleDown((float)luaL_checknumber(L, 6)); float y = Physics::scaleDown((float)luaL_checknumber(L, 7)); float r = (float)luaL_checknumber(L, 8); - int childIndex = (int) luaL_optnumber(L, 9, 1) - 1; // Convert from 1-based index + int childIndex = (int) luaL_optinteger(L, 9, 1) - 1; // Convert from 1-based index b2RayCastInput input; input.p1.Set(p1x, p1y); input.p2.Set(p2x, p2y); @@ -125,7 +125,7 @@ int Shape::computeAABB(lua_State *L) const float x = Physics::scaleDown((float)luaL_checknumber(L, 1)); float y = Physics::scaleDown((float)luaL_checknumber(L, 2)); float r = (float)luaL_checknumber(L, 3); - int childIndex = (int) luaL_optnumber(L, 4, 1) - 1; // Convert from 1-based index + int childIndex = (int) luaL_optinteger(L, 4, 1) - 1; // Convert from 1-based index b2Transform transform(b2Vec2(x, y), b2Rot(r)); b2AABB box; shape->ComputeAABB(&box, transform, childIndex); diff --git a/src/modules/physics/box2d/wrap_ChainShape.cpp b/src/modules/physics/box2d/wrap_ChainShape.cpp index c4ec96497..0bfbfdba9 100644 --- a/src/modules/physics/box2d/wrap_ChainShape.cpp +++ b/src/modules/physics/box2d/wrap_ChainShape.cpp @@ -65,7 +65,7 @@ int w_ChainShape_setPreviousVertex(lua_State *L) int w_ChainShape_getChildEdge(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - int index = (int) luaL_checknumber(L, 2) - 1; // Convert from 1-based index + int index = (int) luaL_checkinteger(L, 2) - 1; // Convert from 1-based index EdgeShape *e = 0; luax_catchexcept(L, [&](){ e = c->getChildEdge(index); }); luax_pushtype(L, e); @@ -84,7 +84,7 @@ int w_ChainShape_getVertexCount(lua_State *L) int w_ChainShape_getPoint(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - int index = (int) luaL_checknumber(L, 2) - 1; // Convert from 1-based index + int index = (int) luaL_checkinteger(L, 2) - 1; // Convert from 1-based index b2Vec2 v; luax_catchexcept(L, [&](){ v = c->getPoint(index); }); lua_pushnumber(L, v.x); diff --git a/src/modules/physics/box2d/wrap_Fixture.cpp b/src/modules/physics/box2d/wrap_Fixture.cpp index 6107d36dc..bfa6efbae 100644 --- a/src/modules/physics/box2d/wrap_Fixture.cpp +++ b/src/modules/physics/box2d/wrap_Fixture.cpp @@ -164,9 +164,9 @@ int w_Fixture_setFilterData(lua_State *L) { Fixture *t = luax_checkfixture(L, 1); int v[3]; - v[0] = (int) luaL_checknumber(L, 2); - v[1] = (int) luaL_checknumber(L, 3); - v[2] = (int) luaL_checknumber(L, 4); + v[0] = (int) luaL_checkinteger(L, 2); + v[1] = (int) luaL_checkinteger(L, 3); + v[2] = (int) luaL_checkinteger(L, 4); t->setFilterData(v); return 0; } @@ -249,7 +249,7 @@ int w_Fixture_getGroupIndex(lua_State *L) int w_Fixture_setGroupIndex(lua_State *L) { Fixture *t = luax_checkfixture(L, 1); - int i = (int) luaL_checknumber(L, 2); + int i = (int) luaL_checkinteger(L, 2); t->setGroupIndex(i); return 0; } diff --git a/src/modules/physics/box2d/wrap_Physics.cpp b/src/modules/physics/box2d/wrap_Physics.cpp index 7408d1d97..0513d43fa 100644 --- a/src/modules/physics/box2d/wrap_Physics.cpp +++ b/src/modules/physics/box2d/wrap_Physics.cpp @@ -471,7 +471,7 @@ int w_getDistance(lua_State *L) int w_setMeter(lua_State *L) { - int arg1 = (int) luaL_checknumber(L, 1); + float arg1 = (float) luaL_checknumber(L, 1); luax_catchexcept(L, [&](){ Physics::setMeter(arg1); }); return 0; diff --git a/src/modules/physics/box2d/wrap_World.cpp b/src/modules/physics/box2d/wrap_World.cpp index ef0184387..ef29143a8 100644 --- a/src/modules/physics/box2d/wrap_World.cpp +++ b/src/modules/physics/box2d/wrap_World.cpp @@ -47,8 +47,8 @@ int w_World_update(lua_State *L) luax_catchexcept(L, [&](){ t->update(dt); }); else { - int velocityiterations = (int) luaL_checknumber(L, 3); - int positioniterations = (int) luaL_checknumber(L, 4); + int velocityiterations = (int) luaL_checkinteger(L, 3); + int positioniterations = (int) luaL_checkinteger(L, 4); luax_catchexcept(L, [&](){ t->update(dt, velocityiterations, positioniterations); }); } diff --git a/src/modules/sound/wrap_Sound.cpp b/src/modules/sound/wrap_Sound.cpp index 7d114f2a2..49a13e865 100644 --- a/src/modules/sound/wrap_Sound.cpp +++ b/src/modules/sound/wrap_Sound.cpp @@ -35,7 +35,7 @@ namespace sound int w_newDecoder(lua_State *L) { love::filesystem::FileData *data = love::filesystem::luax_getfiledata(L, 1); - int bufferSize = (int) luaL_optnumber(L, 2, Decoder::DEFAULT_BUFFER_SIZE); + int bufferSize = (int) luaL_optinteger(L, 2, Decoder::DEFAULT_BUFFER_SIZE); Decoder *t = nullptr; luax_catchexcept(L, @@ -57,10 +57,10 @@ int w_newSoundData(lua_State *L) if (lua_isnumber(L, 1)) { - int samples = (int) luaL_checknumber(L, 1); - int sampleRate = (int) luaL_optnumber(L, 2, Decoder::DEFAULT_SAMPLE_RATE); - int bitDepth = (int) luaL_optnumber(L, 3, Decoder::DEFAULT_BIT_DEPTH); - int channels = (int) luaL_optnumber(L, 4, Decoder::DEFAULT_CHANNELS); + int samples = (int) luaL_checkinteger(L, 1); + int sampleRate = (int) luaL_optinteger(L, 2, Decoder::DEFAULT_SAMPLE_RATE); + int bitDepth = (int) luaL_optinteger(L, 3, Decoder::DEFAULT_BIT_DEPTH); + int channels = (int) luaL_optinteger(L, 4, Decoder::DEFAULT_CHANNELS); luax_catchexcept(L, [&](){ t = instance()->newSoundData(samples, sampleRate, bitDepth, channels); }); } diff --git a/src/modules/window/wrap_Window.cpp b/src/modules/window/wrap_Window.cpp index 52d8c8165..843f512d5 100644 --- a/src/modules/window/wrap_Window.cpp +++ b/src/modules/window/wrap_Window.cpp @@ -36,7 +36,7 @@ int w_getDisplayCount(lua_State *L) int w_getDisplayName(lua_State *L) { - int index = (int) luaL_checknumber(L, 1) - 1; + int index = (int) luaL_checkinteger(L, 1) - 1; const char *name = nullptr; luax_catchexcept(L, [&](){ name = instance()->getDisplayName(index); }); @@ -105,8 +105,8 @@ static int readWindowSettings(lua_State *L, int idx, WindowSettings &settings) settings.useposition = !(lua_isnoneornil(L, -2) && lua_isnoneornil(L, -1)); if (settings.useposition) { - settings.x = (int) luaL_optnumber(L, -2, 0); - settings.y = (int) luaL_optnumber(L, -1, 0); + settings.x = (int) luaL_optinteger(L, -2, 0); + settings.y = (int) luaL_optinteger(L, -1, 0); } lua_pop(L, 2); @@ -116,8 +116,8 @@ static int readWindowSettings(lua_State *L, int idx, WindowSettings &settings) int w_setMode(lua_State *L) { - int w = (int) luaL_checknumber(L, 1); - int h = (int) luaL_checknumber(L, 2); + int w = (int) luaL_checkinteger(L, 1); + int h = (int) luaL_checkinteger(L, 2); if (lua_isnoneornil(L, 3)) { @@ -150,8 +150,8 @@ int w_updateMode(lua_State *L) if (lua_isnumber(L, 1)) { idx = 3; - w = (int) luaL_checknumber(L, 1); - h = (int) luaL_checknumber(L, 2); + w = (int) luaL_checkinteger(L, 1); + h = (int) luaL_checkinteger(L, 2); } if (!lua_isnoneornil(L, idx)) @@ -232,7 +232,7 @@ int w_getFullscreenModes(lua_State *L) { int displayindex = 0; if (!lua_isnoneornil(L, 1)) - displayindex = (int) luaL_checknumber(L, 1) - 1; + displayindex = (int) luaL_checkinteger(L, 1) - 1; else { int x, y; @@ -317,7 +317,7 @@ int w_getDesktopDimensions(lua_State *L) int width = 0, height = 0; int displayindex = 0; if (!lua_isnoneornil(L, 1)) - displayindex = (int) luaL_checknumber(L, 1) - 1; + displayindex = (int) luaL_checkinteger(L, 1) - 1; else { int x, y; @@ -331,12 +331,12 @@ int w_getDesktopDimensions(lua_State *L) int w_setPosition(lua_State *L) { - int x = (int) luaL_checknumber(L, 1); - int y = (int) luaL_checknumber(L, 2); + int x = (int) luaL_checkinteger(L, 1); + int y = (int) luaL_checkinteger(L, 2); int displayindex = 0; if (!lua_isnoneornil(L, 3)) - displayindex = (int) luaL_checknumber(L, 3) - 1; + displayindex = (int) luaL_checkinteger(L, 3) - 1; else { int x_unused, y_unused; @@ -509,7 +509,7 @@ int w_showMessageBox(lua_State *L) // Optional table entry specifying the button to use when enter is pressed. lua_getfield(L, 3, "enterbutton"); if (!lua_isnoneornil(L, -1)) - data.enterButtonIndex = (int) luaL_checknumber(L, -1) - 1; + data.enterButtonIndex = (int) luaL_checkinteger(L, -1) - 1; else data.enterButtonIndex = 0; lua_pop(L, 1); @@ -517,7 +517,7 @@ int w_showMessageBox(lua_State *L) // Optional table entry specifying the button to use when esc is pressed. lua_getfield(L, 3, "escapebutton"); if (!lua_isnoneornil(L, -1)) - data.escapeButtonIndex = (int) luaL_checknumber(L, -1) - 1; + data.escapeButtonIndex = (int) luaL_checkinteger(L, -1) - 1; else data.escapeButtonIndex = (int) data.buttons.size() - 1; lua_pop(L, 1); From 3dfe3808c645ac31b547d118e15b20922f31ee36 Mon Sep 17 00:00:00 2001 From: Tiago Koji Castro Shibata Date: Tue, 18 Jul 2017 15:15:04 -0300 Subject: [PATCH 08/36] Remove playmuted audio configuration --- src/common/ios.h | 4 ++-- src/common/ios.mm | 29 ++++++++++------------------- src/modules/audio/wrap_Audio.cpp | 2 +- src/modules/system/System.cpp | 4 ++-- src/modules/system/wrap_System.cpp | 9 +-------- src/scripts/boot.lua | 5 ++--- src/scripts/boot.lua.h | 12 ++++++------ 7 files changed, 24 insertions(+), 41 deletions(-) diff --git a/src/common/ios.h b/src/common/ios.h index 1b74a6a1e..1d93aa4b1 100644 --- a/src/common/ios.h +++ b/src/common/ios.h @@ -67,12 +67,12 @@ void vibrate(); /** * Enable mix mode (e.g. with background music apps) and playback with a muted device. **/ -void setAudioMixWithOthers(bool mixMode, bool playMuted); +void setAudioMixWithOthers(bool mixEnabled); /** * Returns whether another application is playing audio. **/ -bool audioShouldBeSilenced(); +bool hasBackgroundMusic(); } // ios } // love diff --git a/src/common/ios.mm b/src/common/ios.mm index e34d8f362..d7685873b 100644 --- a/src/common/ios.mm +++ b/src/common/ios.mm @@ -345,35 +345,26 @@ void vibrate() } } -void setAudioMixWithOthers(bool mixMode, bool playMuted) +void setAudioMixWithOthers(bool mixEnabled) { @autoreleasepool { - NSString *category = AVAudioSessionCategoryPlayback; - AVAudioSessionCategoryOptions options = 0; - NSError *err = nil; + NSString *category = AVAudioSessionCategorySoloAmbient; + NSError *err; - if (mixMode) - { - if (playMuted) - options = AVAudioSessionCategoryOptionMixWithOthers; - else - category = AVAudioSessionCategoryAmbient; - } - else if (!playMuted) - { - category = AVAudioSessionCategorySoloAmbient; - } + if (mixEnabled) + category = AVAudioSessionCategoryAmbient; - [[AVAudioSession sharedInstance] setCategory:category withOptions:options error:&err]; - if (err != nil) + if (![[AVAudioSession sharedInstance] setCategory:category error:&err]) NSLog(@"Error in AVAudioSession setCategory: %@", [err localizedDescription]); } } -bool audioShouldBeSilenced() +bool hasBackgroundMusic() { - return [[AVAudioSession sharedInstance] secondaryAudioShouldBeSilencedHint]; + if ([[AVAudioSession sharedInstance] respondsToSelector:@selector(secondaryAudioShouldBeSilencedHint)]) + return [[AVAudioSession sharedInstance] secondaryAudioShouldBeSilencedHint]; + return false; } } // ios diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 2869b3adc..66e38f23d 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -299,7 +299,7 @@ int w_getDistanceModel(lua_State *L) #ifdef LOVE_IOS int w_setMixMode(lua_State *L) { - love::ios::setAudioMixWithOthers(lua_toboolean(L, 1), lua_toboolean(L, 2)); + love::ios::setAudioMixWithOthers(lua_toboolean(L, 1)); #else int w_setMixMode(lua_State *) { diff --git a/src/modules/system/System.cpp b/src/modules/system/System.cpp index 5951449f6..3d8ebd3fa 100644 --- a/src/modules/system/System.cpp +++ b/src/modules/system/System.cpp @@ -189,9 +189,9 @@ bool System::hasBackgroundMusic() const #if defined(LOVE_ANDROID) return love::android::hasBackgroundMusic(); #elif defined(LOVE_IOS) - return love::ios::audioShouldBeSilenced(); + return love::ios::hasBackgroundMusic(); #else - throw love::Exception("Unsupported platform."); + return false; #endif } diff --git a/src/modules/system/wrap_System.cpp b/src/modules/system/wrap_System.cpp index fd2cee7aa..925befba0 100644 --- a/src/modules/system/wrap_System.cpp +++ b/src/modules/system/wrap_System.cpp @@ -95,14 +95,7 @@ int w_vibrate(lua_State *L) int w_hasBackgroundMusic(lua_State *L) { - try - { - lua_pushboolean(L, instance()->hasBackgroundMusic()); - } - catch (love::Exception &) - { - lua_pushnil(L); - } + lua_pushboolean(L, instance()->hasBackgroundMusic()); return 1; } diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index 3c6676879..13ed3a891 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -374,8 +374,7 @@ function love.init() video = true, }, audio = { - mixmode = true, - playmuted = false, + mixwithsystem = true, -- Only relevant for Android / iOS. }, console = false, -- Only relevant for windows. identity = false, @@ -495,7 +494,7 @@ function love.init() end if love.audio then - love.audio.setMixMode(c.audio.mixmode, c.audio.playmuted) + love.audio.setMixMode(c.audio.mixwithsystem) end -- Our first timestep, because window creation can take some time diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index f6d4c8f67..4684661ab 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -683,9 +683,10 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x09, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x2c, 0x0a, 0x09, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x3d, 0x20, 0x7b, 0x0a, - 0x09, 0x09, 0x09, 0x6d, 0x69, 0x78, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x70, 0x6c, 0x61, 0x79, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, - 0x73, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x6d, 0x69, 0x78, 0x77, 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x3d, + 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, + 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, + 0x2f, 0x20, 0x69, 0x4f, 0x53, 0x2e, 0x0a, 0x09, 0x09, 0x7d, 0x2c, 0x0a, 0x09, 0x09, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, @@ -914,9 +915,8 @@ const unsigned char boot_lua[] = 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x69, - 0x78, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x6d, - 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x6d, - 0x75, 0x74, 0x65, 0x64, 0x29, 0x0a, + 0x78, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x77, + 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x4f, 0x75, 0x72, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x70, 0x2c, 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x77, 0x69, 0x6e, 0x64, From 518ed6f524ee3930ba5f7a28fc48c031e05668ea Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 21 Jul 2017 21:17:55 -0300 Subject: [PATCH 09/36] Small code style cleanup --HG-- branch : minor --- src/modules/filesystem/physfs/File.cpp | 2 +- src/modules/window/sdl/Window.cpp | 8 +++----- src/modules/window/sdl/Window.h | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/modules/filesystem/physfs/File.cpp b/src/modules/filesystem/physfs/File.cpp index 0717bed60..5d7670b73 100644 --- a/src/modules/filesystem/physfs/File.cpp +++ b/src/modules/filesystem/physfs/File.cpp @@ -65,7 +65,7 @@ bool File::open(Mode mode) throw love::Exception("Could not open file %s. Does not exist.", filename.c_str()); // Check whether the write directory is set. - if ((mode == MODE_APPEND || mode == MODE_WRITE) && (PHYSFS_getWriteDir() == 0) && !hack_setupWriteDirectory()) + if ((mode == MODE_APPEND || mode == MODE_WRITE) && (PHYSFS_getWriteDir() == nullptr) && !hack_setupWriteDirectory()) throw love::Exception("Could not set write directory."); // File already open? diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index e759fbb0b..4abc9ea84 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -448,7 +448,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) else { sdlflags |= SDL_WINDOW_FULLSCREEN; - SDL_DisplayMode mode = {0, width, height, 0, 0}; + SDL_DisplayMode mode = {0, width, height, 0, nullptr}; // Fullscreen window creation will bug out if no mode can be used. if (SDL_GetClosestDisplayMode(f.display, &mode, &mode) == nullptr) @@ -738,9 +738,7 @@ const char *Window::getDisplayName(int displayindex) const return name; } -typedef Window::WindowSize WindowSize; - -std::vector Window::getFullscreenSizes(int displayindex) const +std::vector Window::getFullscreenSizes(int displayindex) const { std::vector sizes; @@ -866,7 +864,7 @@ bool Window::setIcon(love::image::ImageData *imgd) int h = imgd->getHeight(); int pitch = imgd->getWidth() * 4; - SDL_Surface *sdlicon = 0; + SDL_Surface *sdlicon = nullptr; { // We don't want another thread modifying the ImageData mid-copy. diff --git a/src/modules/window/sdl/Window.h b/src/modules/window/sdl/Window.h index ebf9e660a..f734deee2 100644 --- a/src/modules/window/sdl/Window.h +++ b/src/modules/window/sdl/Window.h @@ -34,7 +34,7 @@ namespace window namespace sdl { -class Window : public love::window::Window +class Window final : public love::window::Window { public: From b568e267eb0c2d3d542ec04deb7221d52d16ec1c Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 21 Jul 2017 21:37:48 -0300 Subject: [PATCH 10/36] Reorganized the ImageData decoding/encoding implementation slightly. --HG-- branch : minor --- src/modules/image/magpie/Image.cpp | 11 ++++-- src/modules/image/magpie/Image.h | 16 +++++---- src/modules/image/magpie/ImageData.cpp | 46 ++++++++++---------------- src/modules/image/magpie/ImageData.h | 11 +++--- 4 files changed, 38 insertions(+), 46 deletions(-) diff --git a/src/modules/image/magpie/Image.cpp b/src/modules/image/magpie/Image.cpp index f98c56026..98b34ebfe 100644 --- a/src/modules/image/magpie/Image.cpp +++ b/src/modules/image/magpie/Image.cpp @@ -79,17 +79,17 @@ const char *Image::getName() const love::image::ImageData *Image::newImageData(love::filesystem::FileData *data) { - return new ImageData(formatHandlers, data); + return new ImageData(data); } love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format) { - return new ImageData(formatHandlers, width, height, format); + return new ImageData(width, height, format); } love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format, void *data, bool own) { - return new ImageData(formatHandlers, width, height, format, data, own); + return new ImageData(width, height, format, data, own); } love::image::CompressedImageData *Image::newCompressedData(love::filesystem::FileData *data) @@ -108,6 +108,11 @@ bool Image::isCompressed(love::filesystem::FileData *data) return false; } +const std::list &Image::getFormatHandlers() const +{ + return formatHandlers; +} + } // magpie } // image } // love diff --git a/src/modules/image/magpie/Image.h b/src/modules/image/magpie/Image.h index 7ebe4efd7..b34923c01 100644 --- a/src/modules/image/magpie/Image.h +++ b/src/modules/image/magpie/Image.h @@ -41,7 +41,7 @@ namespace magpie * multiple image libraries and determines the correct one to use on a * per-image basis at runtime. **/ -class Image : public love::image::Image +class Image final : public love::image::Image { public: @@ -49,15 +49,17 @@ public: ~Image(); // Implements Module. - const char *getName() const; + const char *getName() const override; - love::image::ImageData *newImageData(love::filesystem::FileData *data); - love::image::ImageData *newImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8); - love::image::ImageData *newImageData(int width, int height, PixelFormat format, void *data, bool own = false); + love::image::ImageData *newImageData(love::filesystem::FileData *data) override; + love::image::ImageData *newImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8) override; + love::image::ImageData *newImageData(int width, int height, PixelFormat format, void *data, bool own = false) override; - love::image::CompressedImageData *newCompressedData(love::filesystem::FileData *data); + love::image::CompressedImageData *newCompressedData(love::filesystem::FileData *data) override; - bool isCompressed(love::filesystem::FileData *data); + bool isCompressed(love::filesystem::FileData *data) override; + + const std::list &getFormatHandlers() const; private: diff --git a/src/modules/image/magpie/ImageData.cpp b/src/modules/image/magpie/ImageData.cpp index 1dc6bd0da..23f32d363 100644 --- a/src/modules/image/magpie/ImageData.cpp +++ b/src/modules/image/magpie/ImageData.cpp @@ -20,6 +20,7 @@ // LOVE #include "ImageData.h" +#include "Image.h" namespace love { @@ -28,19 +29,12 @@ namespace image namespace magpie { -ImageData::ImageData(std::list formatHandlers, love::filesystem::FileData *data) - : formatHandlers(formatHandlers) - , decodeHandler(nullptr) +ImageData::ImageData(love::filesystem::FileData *data) { - for (FormatHandler *handler : formatHandlers) - handler->retain(); - decode(data); } -ImageData::ImageData(std::list formatHandlers, int width, int height, PixelFormat format) - : formatHandlers(formatHandlers) - , decodeHandler(nullptr) +ImageData::ImageData(int width, int height, PixelFormat format) { if (!validPixelFormat(format)) throw love::Exception("Unsupported pixel format for ImageData"); @@ -53,14 +47,9 @@ ImageData::ImageData(std::list formatHandlers, int width, int h // Set to black/transparency. memset(data, 0, getSize()); - - for (FormatHandler *handler : formatHandlers) - handler->retain(); } -ImageData::ImageData(std::list formatHandlers, int width, int height, PixelFormat format, void *data, bool own) - : formatHandlers(formatHandlers) - , decodeHandler(nullptr) +ImageData::ImageData(int width, int height, PixelFormat format, void *data, bool own) { if (!validPixelFormat(format)) throw love::Exception("Unsupported pixel format for ImageData"); @@ -73,34 +62,23 @@ ImageData::ImageData(std::list formatHandlers, int width, int h this->data = (unsigned char *) data; else create(width, height, format, data); - - for (FormatHandler *handler : formatHandlers) - handler->retain(); } ImageData::ImageData(const ImageData &c) - : formatHandlers(c.formatHandlers) - , decodeHandler(nullptr) { width = c.width; height = c.height; format = c.format; - for (FormatHandler *handler : formatHandlers) - handler->retain(); - create(width, height, format, c.getData()); } ImageData::~ImageData() { - if (decodeHandler) + if (decodeHandler.get()) decodeHandler->free(data); else delete[] data; - - for (FormatHandler *handler : formatHandlers) - handler->release(); } love::image::ImageData *ImageData::clone() const @@ -133,7 +111,12 @@ void ImageData::decode(love::filesystem::FileData *data) FormatHandler *decoder = nullptr; FormatHandler::DecodedImage decodedimage; - for (FormatHandler *handler : formatHandlers) + auto module = dynamic_cast(Module::getInstance(Module::M_IMAGE)); + + if (module == nullptr) + throw love::Exception("love.image must be loaded in order to decode an ImageData."); + + for (FormatHandler *handler : module->getFormatHandlers()) { if (handler->canDecode(data)) { @@ -183,7 +166,12 @@ love::filesystem::FileData *ImageData::encode(EncodedFormat encodedFormat, const rawimage.data = data; rawimage.format = format; - for (FormatHandler *handler : formatHandlers) + auto module = dynamic_cast(Module::getInstance(Module::M_IMAGE)); + + if (module == nullptr) + throw love::Exception("love.image must be loaded in order to encode an ImageData."); + + for (FormatHandler *handler : module->getFormatHandlers()) { if (handler->canEncode(format, encodedFormat)) { diff --git a/src/modules/image/magpie/ImageData.h b/src/modules/image/magpie/ImageData.h index 0c053cd05..97bbe59a9 100644 --- a/src/modules/image/magpie/ImageData.h +++ b/src/modules/image/magpie/ImageData.h @@ -39,9 +39,9 @@ class ImageData : public love::image::ImageData { public: - ImageData(std::list formatHandlers, love::filesystem::FileData *data); - ImageData(std::list formatHandlers, int width, int height, PixelFormat format = PIXELFORMAT_RGBA8); - ImageData(std::list formatHandlers, int width, int height, PixelFormat format, void *data, bool own); + ImageData(love::filesystem::FileData *data); + ImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8); + ImageData(int width, int height, PixelFormat format, void *data, bool own); ImageData(const ImageData &c); virtual ~ImageData(); @@ -57,12 +57,9 @@ private: // Decode and load an encoded format. void decode(love::filesystem::FileData *data); - // Image format handlers we can use for decoding and encoding. - std::list formatHandlers; - // The format handler that was used to decode the ImageData. We need to know // this so we can properly delete memory allocated by the decoder. - FormatHandler *decodeHandler; + StrongRef decodeHandler; }; // ImageData From 864147c38c3105d1755061afa7145a977d83562a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 22 Jul 2017 23:34:39 -0300 Subject: [PATCH 11/36] love.graphics: move more platform-independent code out of the opengl backend --HG-- branch : minor --- src/modules/graphics/Buffer.cpp | 2 +- src/modules/graphics/Buffer.h | 2 +- src/modules/graphics/Graphics.cpp | 122 +++++++++++++++++ src/modules/graphics/Graphics.h | 4 +- src/modules/graphics/Mesh.cpp | 79 ++++++++++- src/modules/graphics/Mesh.h | 6 +- src/modules/graphics/ParticleSystem.cpp | 13 +- src/modules/graphics/ParticleSystem.h | 5 +- src/modules/graphics/SpriteBatch.cpp | 70 ++++++++-- src/modules/graphics/SpriteBatch.h | 8 +- src/modules/graphics/Text.cpp | 31 +++++ src/modules/graphics/Text.h | 5 + src/modules/graphics/opengl/Graphics.cpp | 123 +----------------- src/modules/graphics/opengl/Graphics.h | 2 +- src/modules/graphics/opengl/Mesh.cpp | 82 ++---------- src/modules/graphics/opengl/Mesh.h | 5 +- .../graphics/opengl/ParticleSystem.cpp | 13 +- src/modules/graphics/opengl/ParticleSystem.h | 5 +- src/modules/graphics/opengl/SpriteBatch.cpp | 65 ++------- src/modules/graphics/opengl/SpriteBatch.h | 5 +- src/modules/graphics/opengl/Text.cpp | 32 +---- src/modules/graphics/opengl/Text.h | 5 +- 22 files changed, 368 insertions(+), 316 deletions(-) diff --git a/src/modules/graphics/Buffer.cpp b/src/modules/graphics/Buffer.cpp index eeddcfde2..a1d5c292f 100644 --- a/src/modules/graphics/Buffer.cpp +++ b/src/modules/graphics/Buffer.cpp @@ -151,7 +151,7 @@ IndexDataType QuadIndices::getType(size_t s) const return vertex::getIndexDataTypeFromMax(getIndexCount(s)); } -size_t QuadIndices::getElementSize() +size_t QuadIndices::getElementSize() const { return elementSize; } diff --git a/src/modules/graphics/Buffer.h b/src/modules/graphics/Buffer.h index 38493b2be..8df71bda5 100644 --- a/src/modules/graphics/Buffer.h +++ b/src/modules/graphics/Buffer.h @@ -238,7 +238,7 @@ public: * Can be used with getPointer to calculate an offset into the array based * on a number of elements. **/ - size_t getElementSize(); + size_t getElementSize() const; /** * Returns the pointer to the Buffer. diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 0efc39735..394513871 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -430,6 +430,128 @@ void Graphics::setCanvas(const RenderTargetsStrongRef &rts) return setCanvas(targets); } +void Graphics::setCanvas(const RenderTargets &rts) +{ + DisplayState &state = states.back(); + int ncanvases = (int) rts.colors.size(); + + if (ncanvases == 0 && rts.depthStencil.canvas == nullptr) + return setCanvas(); + else if (ncanvases == 0) + throw love::Exception("At least one color render target is required when using a custom depth/stencil buffer."); + + const auto &prevRTs = state.renderTargets; + + if (ncanvases == (int) prevRTs.colors.size()) + { + bool modified = false; + + for (int i = 0; i < ncanvases; i++) + { + if (rts.colors[i].canvas != prevRTs.colors[i].canvas.get() + || rts.colors[i].slice != prevRTs.colors[i].slice + || rts.colors[i].mipmap != prevRTs.colors[i].mipmap) + { + modified = true; + break; + } + } + + if (!modified && (rts.depthStencil.canvas != prevRTs.depthStencil.canvas + || rts.depthStencil.slice != prevRTs.depthStencil.slice + || rts.depthStencil.mipmap != prevRTs.depthStencil.mipmap)) + { + modified = true; + } + + if (rts.temporaryRTFlags != prevRTs.temporaryRTFlags) + modified = true; + + if (!modified) + return; + } + + if (ncanvases > capabilities.limits[LIMIT_MULTI_CANVAS]) + throw love::Exception("This system can't simultaneously render to %d canvases.", ncanvases); + + love::graphics::Canvas *firstcanvas = rts.colors[0].canvas; + + bool multiformatsupported = capabilities.features[FEATURE_MULTI_CANVAS_FORMATS]; + PixelFormat firstformat = firstcanvas->getPixelFormat(); + + if (isPixelFormatDepthStencil(firstformat)) + throw love::Exception("Depth/stencil format Canvases must be used with the 'depthstencil' field of the table passed into setCanvas."); + + if (rts.colors[0].mipmap < 0 || rts.colors[0].mipmap >= firstcanvas->getMipmapCount()) + throw love::Exception("Invalid mipmap level %d.", rts.colors[0].mipmap + 1); + + bool hasSRGBcanvas = firstformat == PIXELFORMAT_sRGBA8; + int pixelw = firstcanvas->getPixelWidth(rts.colors[0].mipmap); + int pixelh = firstcanvas->getPixelHeight(rts.colors[0].mipmap); + + for (int i = 1; i < ncanvases; i++) + { + love::graphics::Canvas *c = rts.colors[i].canvas; + PixelFormat format = c->getPixelFormat(); + int mip = rts.colors[i].mipmap; + + if (mip < 0 || mip >= c->getMipmapCount()) + throw love::Exception("Invalid mipmap level %d.", mip + 1); + + if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh) + throw love::Exception("All canvases must have the same pixel dimensions."); + + if (!multiformatsupported && format != firstformat) + throw love::Exception("This system doesn't support multi-canvas rendering with different canvas formats."); + + if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA()) + throw love::Exception("All Canvases must have the same MSAA value."); + + if (isPixelFormatDepthStencil(format)) + throw love::Exception("Depth/stencil format Canvases must be used with the 'depthstencil' field of the table passed into setCanvas."); + + if (format == PIXELFORMAT_sRGBA8) + hasSRGBcanvas = true; + } + + if (rts.depthStencil.canvas != nullptr) + { + love::graphics::Canvas *c = rts.depthStencil.canvas; + int mip = rts.depthStencil.mipmap; + + if (!isPixelFormatDepthStencil(c->getPixelFormat())) + throw love::Exception("Only depth/stencil format Canvases can be used with the 'depthstencil' field of the table passed into setCanvas."); + + if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh) + throw love::Exception("All canvases must have the same pixel dimensions."); + + if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA()) + throw love::Exception("All Canvases must have the same MSAA value."); + + if (mip < 0 || mip >= c->getMipmapCount()) + throw love::Exception("Invalid mipmap level %d.", mip + 1); + } + + int w = firstcanvas->getWidth(rts.colors[0].mipmap); + int h = firstcanvas->getHeight(rts.colors[0].mipmap); + + flushStreamDraws(); + setCanvasInternal(rts, w, h, pixelw, pixelh, hasSRGBcanvas); + + RenderTargetsStrongRef refs; + refs.colors.reserve(rts.colors.size()); + + for (auto c : rts.colors) + refs.colors.emplace_back(c.canvas, c.slice); + + refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.canvas, rts.depthStencil.slice); + refs.temporaryRTFlags = rts.temporaryRTFlags; + + std::swap(state.renderTargets, refs); + + canvasSwitchCount++; +} + Graphics::RenderTargets Graphics::getCanvas() const { const auto &curRTs = states.back().renderTargets; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 6a6fc38e6..a515a1d21 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -478,7 +478,7 @@ public: Shader *getShader() const; void setCanvas(RenderTarget rt, uint32 temporaryRTFlags); - virtual void setCanvas(const RenderTargets &rts) = 0; + void setCanvas(const RenderTargets &rts); void setCanvas(const RenderTargetsStrongRef &rts); virtual void setCanvas() = 0; @@ -861,6 +861,8 @@ protected: virtual StreamBuffer *newStreamBuffer(BufferType type, size_t size) = 0; + virtual void setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) = 0; + virtual void initCapabilities() = 0; virtual void getAPIStats(int &drawcalls, int &shaderswitches) const = 0; diff --git a/src/modules/graphics/Mesh.cpp b/src/modules/graphics/Mesh.cpp index 45f8a5c24..2b200c127 100644 --- a/src/modules/graphics/Mesh.cpp +++ b/src/modules/graphics/Mesh.cpp @@ -564,11 +564,88 @@ bool Mesh::getDrawRange(int &start, int &count) const return true; } -void Mesh::draw(love::graphics::Graphics *gfx, const love::Matrix4 &m) +void Mesh::draw(Graphics *gfx, const love::Matrix4 &m) { drawInstanced(gfx, m, 1); } +void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount) +{ + if (vertexCount <= 0 || instancecount <= 0) + return; + + if (instancecount > 1 && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING]) + throw love::Exception("Instancing is not supported on this system."); + + gfx->flushStreamDraws(); + + if (Shader::isDefaultActive()) + Shader::attachDefault(Shader::STANDARD_DEFAULT); + + if (Shader::current && texture.get()) + Shader::current->checkMainTexture(texture); + + uint32 enabledattribs = 0; + uint32 instancedattribs = 0; + + for (const auto &attrib : attachedAttributes) + { + if (!attrib.second.enabled) + continue; + + love::graphics::Mesh *mesh = attrib.second.mesh; + int location = mesh->bindAttributeToShaderInput(attrib.second.index, attrib.first); + + if (location >= 0) + { + uint32 bit = 1u << (uint32) location; + + enabledattribs |= bit; + + if (attrib.second.step == STEP_PER_INSTANCE) + instancedattribs |= bit; + } + } + + // Not supported on all platforms or GL versions, I believe. + if (!(enabledattribs & ATTRIBFLAG_POS)) + throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn."); + + bool useindexbuffer = useIndexBuffer && ibo != nullptr && elementCount > 0; + + int start = 0; + int count = 0; + + if (useindexbuffer) + { + // Make sure the index buffer isn't mapped (sends data to GPU if needed.) + ibo->unmap(); + + start = std::min(std::max(0, rangeStart), (int) elementCount - 1); + + count = (int) elementCount; + if (rangeCount > 0) + count = std::min(count, rangeCount); + + count = std::min(count, (int) elementCount - start); + } + else + { + start = std::min(std::max(0, rangeStart), (int) vertexCount - 1); + + count = (int) vertexCount; + if (rangeCount > 0) + count = std::min(count, rangeCount); + + count = std::min(count, (int) vertexCount - start); + } + + Graphics::TempTransform transform(gfx, m); + + if (count > 0) + drawInternal(start, count, instancecount, useindexbuffer, enabledattribs, instancedattribs); +} + size_t Mesh::getAttribFormatSize(const AttribFormat &format) { switch (format.type) diff --git a/src/modules/graphics/Mesh.h b/src/modules/graphics/Mesh.h index 583e2d36f..7fe7445c6 100644 --- a/src/modules/graphics/Mesh.h +++ b/src/modules/graphics/Mesh.h @@ -195,11 +195,11 @@ public: virtual int bindAttributeToShaderInput(int attributeindex, const std::string &inputname) = 0; - virtual void drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount) = 0; - // Implements Drawable. void draw(Graphics *gfx, const Matrix4 &m) override; + void drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount); + static bool getConstant(const char *in, DrawMode &out); static bool getConstant(DrawMode in, const char *&out); @@ -223,6 +223,8 @@ protected: void calculateAttributeSizes(); size_t getAttributeOffset(size_t attribindex) const; + virtual void drawInternal(int start, int count, int instancecount, bool useindexbuffer, uint32 attribflags, uint32 instancedattribflags) const = 0; + static size_t getAttribFormatSize(const AttribFormat &format); static std::vector getDefaultVertexFormat(); diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index e049fabee..b619b9341 100644 --- a/src/modules/graphics/ParticleSystem.cpp +++ b/src/modules/graphics/ParticleSystem.cpp @@ -1048,15 +1048,21 @@ void ParticleSystem::update(float dt) prevPosition = position; } -bool ParticleSystem::prepareDraw(Graphics *gfx) +void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m) { uint32 pCount = getCount(); if (pCount == 0 || texture.get() == nullptr || pMem == nullptr || buffer == nullptr) - return false; + return; gfx->flushStreamDraws(); + if (Shader::isDefaultActive()) + Shader::attachDefault(Shader::STANDARD_DEFAULT); + + if (Shader::current && texture.get()) + Shader::current->checkMainTexture(texture); + const Vector2 *positions = texture->getQuad()->getVertexPositions(); const Vector2 *texcoords = texture->getQuad()->getVertexTexCoords(); @@ -1098,7 +1104,8 @@ bool ParticleSystem::prepareDraw(Graphics *gfx) buffer->unmap(); - return true; + Graphics::TempTransform transform(gfx, m); + drawInternal(); } bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out) diff --git a/src/modules/graphics/ParticleSystem.h b/src/modules/graphics/ParticleSystem.h index 9278c9ca2..547fe54eb 100644 --- a/src/modules/graphics/ParticleSystem.h +++ b/src/modules/graphics/ParticleSystem.h @@ -569,6 +569,9 @@ public: **/ void update(float dt); + // Implements Drawable. + void draw(Graphics *gfx, const Matrix4 &m) override; + static bool getConstant(const char *in, AreaSpreadDistribution &out); static bool getConstant(AreaSpreadDistribution in, const char *&out); @@ -612,7 +615,7 @@ protected: int quadIndex; }; - bool prepareDraw(Graphics *gfx); + virtual void drawInternal() const = 0; // Pointer to the beginning of the allocated memory. Particle *pMem; diff --git a/src/modules/graphics/SpriteBatch.cpp b/src/modules/graphics/SpriteBatch.cpp index 780d46650..79b851741 100644 --- a/src/modules/graphics/SpriteBatch.cpp +++ b/src/modules/graphics/SpriteBatch.cpp @@ -62,9 +62,9 @@ SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, vertex::Usag else vertex_format = vertex::CommonFormat::XYf_STf_RGBAub; - format_stride = vertex::getFormatStride(vertex_format); + vertex_stride = vertex::getFormatStride(vertex_format); - size_t vertex_size = format_stride * 4 * size; + size_t vertex_size = vertex_stride * 4 * size; array_buf = gfx->newBuffer(vertex_size, nullptr, BUFFER_VERTEX, usage, Buffer::MAP_EXPLICIT_RANGE_MODIFY); } @@ -95,7 +95,7 @@ int SpriteBatch::add(Quad *quad, const Matrix4 &m, int index /*= -1*/) const Vector2 *quadtexcoords = quad->getVertexTexCoords(); // Always keep the VBO mapped when adding data (it'll be unmapped on draw.) - size_t offset = (index == -1 ? next : index) * format_stride * 4; + size_t offset = (index == -1 ? next : index) * vertex_stride * 4; auto verts = (XYf_STf_RGBAub *) ((uint8 *) array_buf->map() + offset); m.transformXY(verts, quadpositions, 4); @@ -107,7 +107,7 @@ int SpriteBatch::add(Quad *quad, const Matrix4 &m, int index /*= -1*/) verts[i].color = color; } - array_buf->setMappedRangeModified(offset, format_stride * 4); + array_buf->setMappedRangeModified(offset, vertex_stride * 4); // Increment counter. if (index == -1) @@ -141,7 +141,7 @@ int SpriteBatch::addLayer(int layer, Quad *quad, const Matrix4 &m, int index) const Vector2 *quadtexcoords = quad->getVertexTexCoords(); // Always keep the VBO mapped when adding data (it'll be unmapped on draw.) - size_t offset = (index == -1 ? next : index) * format_stride * 4; + size_t offset = (index == -1 ? next : index) * vertex_stride * 4; auto verts = (XYf_STPf_RGBAub *) ((uint8 *) array_buf->map() + offset); m.transformXY(verts, quadpositions, 4); @@ -154,7 +154,7 @@ int SpriteBatch::addLayer(int layer, Quad *quad, const Matrix4 &m, int index) verts[i].color = color; } - array_buf->setMappedRangeModified(offset, format_stride * 4); + array_buf->setMappedRangeModified(offset, vertex_stride * 4); // Increment counter. if (index == -1) @@ -225,7 +225,7 @@ void SpriteBatch::setBufferSize(int newsize) if (newsize == size) return; - size_t vertex_size = format_stride * 4 * newsize; + size_t vertex_size = vertex_stride * 4 * newsize; love::graphics::Buffer *new_array_buf = nullptr; int new_next = std::min(next, newsize); @@ -236,7 +236,7 @@ void SpriteBatch::setBufferSize(int newsize) new_array_buf = gfx->newBuffer(vertex_size, nullptr, array_buf->getType(), array_buf->getUsage(), array_buf->getMapFlags()); // Copy as much of the old data into the new GLBuffer as can fit. - size_t copy_size = format_stride * 4 * new_next; + size_t copy_size = vertex_stride * 4 * new_next; array_buf->copyTo(0, copy_size, new_array_buf, 0); quad_indices = QuadIndices(gfx, newsize); @@ -307,5 +307,59 @@ bool SpriteBatch::getDrawRange(int &start, int &count) const return true; } +void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) +{ + using namespace vertex; + + if (next == 0) + return; + + gfx->flushStreamDraws(); + + if (texture.get()) + { + if (Shader::isDefaultActive()) + { + Shader::StandardShader defaultshader = Shader::STANDARD_DEFAULT; + if (texture->getTextureType() == TEXTURE_2D_ARRAY) + defaultshader = Shader::STANDARD_ARRAY; + + Shader::attachDefault(defaultshader); + } + + if (Shader::current) + Shader::current->checkMainTexture(texture); + } + + // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.) + array_buf->unmap(); + + CommonFormat format = vertex_format; + + if (!color_active) + { + if (format == CommonFormat::XYf_STPf_RGBAub) + format = CommonFormat::XYf_STPf; + else + format = CommonFormat::XYf_STf; + } + + int start = std::min(std::max(0, range_start), next - 1); + + int count = next; + if (range_count > 0) + count = std::min(count, range_count); + + count = std::min(count, next - start); + + size_t indexbytestart = quad_indices.getIndexCount(start) * quad_indices.getElementSize(); + size_t indexcount = quad_indices.getIndexCount(count); + + Graphics::TempTransform transform(gfx, m); + + if (count > 0) + drawInternal(format, indexbytestart, indexcount); +} + } // graphics } // love diff --git a/src/modules/graphics/SpriteBatch.h b/src/modules/graphics/SpriteBatch.h index d2e1709e8..bf1d3f82a 100644 --- a/src/modules/graphics/SpriteBatch.h +++ b/src/modules/graphics/SpriteBatch.h @@ -32,6 +32,7 @@ #include "Drawable.h" #include "Color.h" #include "Mesh.h" +#include "vertex.h" namespace love { @@ -105,6 +106,9 @@ public: void setDrawRange(); bool getDrawRange(int &start, int &count) const; + // Implements Drawable. + void draw(Graphics *gfx, const Matrix4 &m) override; + protected: struct AttachedAttribute @@ -119,6 +123,8 @@ protected: **/ void setBufferSize(int newsize); + virtual void drawInternal(vertex::CommonFormat format, size_t indexbytestart, size_t indexcount) = 0; + StrongRef texture; // Max number of sprites in the batch. @@ -133,7 +139,7 @@ protected: bool color_active; vertex::CommonFormat vertex_format; - size_t format_stride; + size_t vertex_stride; love::graphics::Buffer *array_buf; QuadIndices quad_indices; diff --git a/src/modules/graphics/Text.cpp b/src/modules/graphics/Text.cpp index ee9228054..1c851d248 100644 --- a/src/modules/graphics/Text.cpp +++ b/src/modules/graphics/Text.cpp @@ -235,5 +235,36 @@ int Text::getHeight(int index) const return text_data[index].text_info.height; } +void Text::draw(Graphics *gfx, const Matrix4 &m) +{ + if (vbo == nullptr || draw_commands.empty()) + return; + + gfx->flushStreamDraws(); + + if (Shader::isDefaultActive()) + Shader::attachDefault(Shader::STANDARD_DEFAULT); + + if (Shader::current) + Shader::current->checkMainTextureType(TEXTURE_2D, false); + + // Re-generate the text if the Font's texture cache was invalidated. + if (font->getTextureCacheID() != texture_cache_id) + regenerateVertices(); + + int totalverts = 0; + for (const Font::DrawCommand &cmd : draw_commands) + totalverts = std::max(cmd.startvertex + cmd.vertexcount, totalverts); + + if ((size_t) totalverts / 4 > quadIndices.getSize()) + quadIndices = QuadIndices(gfx, (size_t) totalverts / 4); + + vbo->unmap(); // Make sure all pending data is flushed to the GPU. + + Graphics::TempTransform transform(gfx, m); + + drawInternal(draw_commands); +} + } // graphics } // love diff --git a/src/modules/graphics/Text.h b/src/modules/graphics/Text.h index cd3af048c..7beeb553c 100644 --- a/src/modules/graphics/Text.h +++ b/src/modules/graphics/Text.h @@ -63,6 +63,9 @@ public: **/ int getHeight(int index = 0) const; + // Implements Drawable. + void draw(love::graphics::Graphics *gfx, const Matrix4 &m) override; + protected: struct TextData @@ -80,6 +83,8 @@ protected: void regenerateVertices(); void addTextData(const TextData &s); + virtual void drawInternal(const std::vector &commands) const = 0; + StrongRef font; Buffer *vbo; QuadIndices quadIndices; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index ab9afa30c..bd5415e1b 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -492,107 +492,9 @@ void Graphics::setDebug(bool enable) ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n"); } -void Graphics::setCanvas(const RenderTargets &rts) +void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) { - DisplayState &state = states.back(); - int ncanvases = (int) rts.colors.size(); - - if (ncanvases == 0 && rts.depthStencil.canvas == nullptr) - return setCanvas(); - else if (ncanvases == 0) - throw love::Exception("At least one color render target is required when using a custom depth/stencil buffer."); - - const auto &prevRTs = state.renderTargets; - - if (ncanvases == (int) prevRTs.colors.size()) - { - bool modified = false; - - for (int i = 0; i < ncanvases; i++) - { - if (rts.colors[i].canvas != prevRTs.colors[i].canvas.get() - || rts.colors[i].slice != prevRTs.colors[i].slice - || rts.colors[i].mipmap != prevRTs.colors[i].mipmap) - { - modified = true; - break; - } - } - - if (!modified && (rts.depthStencil.canvas != prevRTs.depthStencil.canvas - || rts.depthStencil.slice != prevRTs.depthStencil.slice - || rts.depthStencil.mipmap != prevRTs.depthStencil.mipmap)) - { - modified = true; - } - - if (rts.temporaryRTFlags != prevRTs.temporaryRTFlags) - modified = true; - - if (!modified) - return; - } - - if (ncanvases > gl.getMaxRenderTargets()) - throw love::Exception("This system can't simultaneously render to %d canvases.", ncanvases); - - love::graphics::Canvas *firstcanvas = rts.colors[0].canvas; - - bool multiformatsupported = Canvas::isMultiFormatMultiCanvasSupported(); - PixelFormat firstformat = firstcanvas->getPixelFormat(); - - if (isPixelFormatDepthStencil(firstformat)) - throw love::Exception("Depth/stencil format Canvases must be used with the 'depthstencil' field of the table passed into setCanvas."); - - if (rts.colors[0].mipmap < 0 || rts.colors[0].mipmap >= firstcanvas->getMipmapCount()) - throw love::Exception("Invalid mipmap level %d.", rts.colors[0].mipmap + 1); - - bool hasSRGBcanvas = firstformat == PIXELFORMAT_sRGBA8; - int pixelwidth = firstcanvas->getPixelWidth(rts.colors[0].mipmap); - int pixelheight = firstcanvas->getPixelHeight(rts.colors[0].mipmap); - - for (int i = 1; i < ncanvases; i++) - { - love::graphics::Canvas *c = rts.colors[i].canvas; - PixelFormat format = c->getPixelFormat(); - int mip = rts.colors[i].mipmap; - - if (mip < 0 || mip >= c->getMipmapCount()) - throw love::Exception("Invalid mipmap level %d.", mip + 1); - - if (c->getPixelWidth(mip) != pixelwidth || c->getPixelHeight(mip) != pixelheight) - throw love::Exception("All canvases must have the same pixel dimensions."); - - if (!multiformatsupported && format != firstformat) - throw love::Exception("This system doesn't support multi-canvas rendering with different canvas formats."); - - if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA()) - throw love::Exception("All Canvases must have the same MSAA value."); - - if (isPixelFormatDepthStencil(format)) - throw love::Exception("Depth/stencil format Canvases must be used with the 'depthstencil' field of the table passed into setCanvas."); - - if (format == PIXELFORMAT_sRGBA8) - hasSRGBcanvas = true; - } - - if (rts.depthStencil.canvas != nullptr) - { - love::graphics::Canvas *c = rts.depthStencil.canvas; - int mip = rts.depthStencil.mipmap; - - if (!isPixelFormatDepthStencil(c->getPixelFormat())) - throw love::Exception("Only depth/stencil format Canvases can be used with the 'depthstencil' field of the table passed into setCanvas."); - - if (c->getPixelWidth(mip) != pixelwidth || c->getPixelHeight(mip) != pixelheight) - throw love::Exception("All canvases must have the same pixel dimensions."); - - if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA()) - throw love::Exception("All Canvases must have the same MSAA value."); - - if (mip < 0 || mip >= c->getMipmapCount()) - throw love::Exception("Invalid mipmap level %d.", mip + 1); - } + const DisplayState &state = states.back(); OpenGL::TempDebugGroup debuggroup("setCanvas(...)"); @@ -600,15 +502,13 @@ void Graphics::setCanvas(const RenderTargets &rts) bindCachedFBO(rts); - gl.setViewport({0, 0, pixelwidth, pixelheight}); + gl.setViewport({0, 0, pixelw, pixelh}); // Re-apply the scissor if it was active, since the rectangle passed to // glScissor is affected by the viewport dimensions. if (state.scissor) setScissor(state.scissorRect); - int w = firstcanvas->getWidth(rts.colors[0].mipmap); - int h = firstcanvas->getHeight(rts.colors[0].mipmap); projectionMatrix = Matrix4::ortho(0.0, (float) w, 0.0, (float) h); // Make sure the correct sRGB setting is used when drawing to the canvases. @@ -619,19 +519,6 @@ void Graphics::setCanvas(const RenderTargets &rts) else if (!hasSRGBcanvas && gl.hasFramebufferSRGB()) gl.setFramebufferSRGB(false); } - - RenderTargetsStrongRef refs; - refs.colors.reserve(rts.colors.size()); - - for (auto c : rts.colors) - refs.colors.emplace_back(c.canvas, c.slice); - - refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.canvas, rts.depthStencil.slice); - refs.temporaryRTFlags = rts.temporaryRTFlags; - - std::swap(state.renderTargets, refs); - - canvasSwitchCount++; } void Graphics::setCanvas() @@ -643,6 +530,7 @@ void Graphics::setCanvas() OpenGL::TempDebugGroup debuggroup("setCanvas()"); + flushStreamDraws(); endPass(); state.renderTargets = RenderTargetsStrongRef(); @@ -673,8 +561,6 @@ void Graphics::setCanvas() void Graphics::endPass() { - flushStreamDraws(); - auto &rts = states.back().renderTargets; love::graphics::Canvas *depthstencil = rts.depthStencil.canvas.get(); @@ -1013,6 +899,7 @@ void Graphics::present(void *screenshotCallbackData) if (isCanvasActive()) throw love::Exception("present cannot be called while a Canvas is active."); + flushStreamDraws(); endPass(); gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO()); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 0c7bfc17e..02ca81bb9 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -97,7 +97,6 @@ public: void setColor(Colorf c) override; - void setCanvas(const RenderTargets &rts) override; void setCanvas() override; void setScissor(const Rect &rect) override; @@ -128,6 +127,7 @@ public: private: love::graphics::StreamBuffer *newStreamBuffer(BufferType type, size_t size) override; + void setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) override; void initCapabilities() override; void getAPIStats(int &drawcalls, int &shaderswitches) const override; diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index d9b0207f6..a80bc96c5 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -91,94 +91,28 @@ int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inpu return attriblocation; } -void Mesh::drawInstanced(love::graphics::Graphics *gfx, const love::Matrix4 &m, int instancecount) +void Mesh::drawInternal(int start, int count, int instancecount, bool useindexbuffer, uint32 attribflags, uint32 instancedattribflags) const { - if (vertexCount <= 0 || instancecount <= 0) - return; - - if (instancecount > 1 && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING]) - throw love::Exception("Instancing is not supported on this system."); - - gfx->flushStreamDraws(); - - if (Shader::isDefaultActive()) - Shader::attachDefault(Shader::STANDARD_DEFAULT); - - if (Shader::current && texture.get()) - Shader::current->checkMainTexture(texture); - OpenGL::TempDebugGroup debuggroup("Mesh draw"); - uint32 enabledattribs = 0; - uint32 instancedattribs = 0; - - for (const auto &attrib : attachedAttributes) - { - if (!attrib.second.enabled) - continue; - - love::graphics::Mesh *mesh = attrib.second.mesh; - int location = mesh->bindAttributeToShaderInput(attrib.second.index, attrib.first); - - if (location >= 0) - { - uint32 bit = 1u << (uint32) location; - - enabledattribs |= bit; - - if (attrib.second.step == STEP_PER_INSTANCE) - instancedattribs |= bit; - } - } - - // Not supported on all platforms or GL versions, I believe. - if (!(enabledattribs & ATTRIBFLAG_POS)) - throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn."); - - gl.useVertexAttribArrays(enabledattribs, instancedattribs); - + gl.useVertexAttribArrays(attribflags, instancedattribflags); gl.bindTextureToUnit(texture, 0, false); - - Graphics::TempTransform transform(gfx, m); - gl.prepareDraw(); - if (useIndexBuffer && ibo && elementCount > 0) + GLenum gldrawmode = getGLDrawMode(drawMode); + + if (useindexbuffer) { - // Use the custom vertex map (index buffer) to draw the vertices. - gl.bindBuffer(BUFFER_INDEX, (GLuint) ibo->getHandle()); - - // Make sure the index buffer isn't mapped (sends data to GPU if needed.) - ibo->unmap(); - - int start = std::min(std::max(0, rangeStart), (int) elementCount - 1); - - int count = (int) elementCount; - if (rangeCount > 0) - count = std::min(count, rangeCount); - - count = std::min(count, (int) elementCount - start); - size_t elementsize = vertex::getIndexDataSize(elementDataType); const void *indices = BUFFER_OFFSET(start * elementsize); GLenum type = OpenGL::getGLIndexDataType(elementDataType); - if (count > 0) - gl.drawElements(getGLDrawMode(drawMode), count, type, indices, instancecount); + gl.bindBuffer(BUFFER_INDEX, (GLuint) ibo->getHandle()); + gl.drawElements(gldrawmode, count, type, indices, instancecount); } else { - int start = std::min(std::max(0, rangeStart), (int) vertexCount - 1); - - int count = (int) vertexCount; - if (rangeCount > 0) - count = std::min(count, rangeCount); - - count = std::min(count, (int) vertexCount - start); - - // Normal non-indexed drawing (no custom vertex map.) - if (count > 0) - gl.drawArrays(getGLDrawMode(drawMode), start, count, instancecount); + gl.drawArrays(gldrawmode, start, count, instancecount); } } diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 01f16e9ec..ec1395193 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -44,7 +44,10 @@ public: virtual ~Mesh(); int bindAttributeToShaderInput(int attributeindex, const std::string &inputname) override; - void drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount) override; + +protected: + + void drawInternal(int start, int count, int instancecount, bool useindexbuffer, uint32 attribflags, uint32 instancedattribflags) const override; private: diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 36a465ae7..8d65d8221 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -50,21 +50,10 @@ ParticleSystem *ParticleSystem::clone() return new ParticleSystem(*this); } -void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m) +void ParticleSystem::drawInternal() const { using namespace vertex; - if (!prepareDraw(gfx)) - return; - - Graphics::TempTransform transform(gfx, m); - - if (Shader::isDefaultActive()) - Shader::attachDefault(Shader::STANDARD_DEFAULT); - - if (Shader::current && texture.get()) - Shader::current->checkMainTexture(texture); - OpenGL::TempDebugGroup debuggroup("ParticleSystem draw"); gl.bindTextureToUnit(texture, 0, false); diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 04d385995..eafdbc310 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -44,7 +44,10 @@ public: virtual ~ParticleSystem(); ParticleSystem *clone() override; - void draw(Graphics *gfx, const Matrix4 &m) override; + +private: + + void drawInternal() const override; }; // ParticleSystem diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index 2e5eaa10d..14accb645 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -51,52 +51,15 @@ SpriteBatch::~SpriteBatch() { } -void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) +void SpriteBatch::drawInternal(vertex::CommonFormat format, size_t indexbytestart, size_t indexcount) { - using namespace vertex; - - if (next == 0) - return; - - gfx->flushStreamDraws(); - - if (texture.get()) - { - if (Shader::isDefaultActive()) - { - Shader::StandardShader defaultshader = Shader::STANDARD_DEFAULT; - if (texture->getTextureType() == TEXTURE_2D_ARRAY) - defaultshader = Shader::STANDARD_ARRAY; - - Shader::attachDefault(defaultshader); - } - - if (Shader::current) - Shader::current->checkMainTexture(texture); - } - OpenGL::TempDebugGroup debuggroup("SpriteBatch draw"); - Graphics::TempTransform transform(gfx, m); - - gl.bindTextureToUnit(texture, 0, false); - - // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.) - array_buf->unmap(); - - CommonFormat format = vertex_format; - - if (!color_active) - { - if (format == CommonFormat::XYf_STPf_RGBAub) - format = CommonFormat::XYf_STPf; - else - format = CommonFormat::XYf_STf; - } - uint32 enabledattribs = getFormatFlags(format); - gl.setVertexPointers(format, array_buf, format_stride, 0); + // We want attached attributes to override local attributes, so we should + // call this before binding attached attributes. + gl.setVertexPointers(format, array_buf, vertex_stride, 0); for (const auto &it : attached_attributes) { @@ -114,26 +77,16 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) } gl.useVertexAttribArrays(enabledattribs); + gl.bindTextureToUnit(texture, 0, false); gl.prepareDraw(); - int start = std::min(std::max(0, range_start), next - 1); + gl.bindBuffer(BUFFER_INDEX, (GLuint) quad_indices.getBuffer()->getHandle()); - int count = next; - if (range_count > 0) - count = std::min(count, range_count); + const void *indices = BUFFER_OFFSET(indexbytestart); + GLenum gltype = OpenGL::getGLIndexDataType(quad_indices.getType()); - count = std::min(count, next - start); - - if (count > 0) - { - gl.bindBuffer(BUFFER_INDEX, (GLuint) quad_indices.getBuffer()->getHandle()); - - const void *indices = BUFFER_OFFSET(start * quad_indices.getElementSize()); - GLenum gltype = OpenGL::getGLIndexDataType(quad_indices.getType()); - - gl.drawElements(GL_TRIANGLES, (GLsizei) quad_indices.getIndexCount(count), gltype, indices); - } + gl.drawElements(GL_TRIANGLES, (GLsizei) indexcount, gltype, indices); } } // opengl diff --git a/src/modules/graphics/opengl/SpriteBatch.h b/src/modules/graphics/opengl/SpriteBatch.h index d4a2c5832..35e7bb8a6 100644 --- a/src/modules/graphics/opengl/SpriteBatch.h +++ b/src/modules/graphics/opengl/SpriteBatch.h @@ -37,8 +37,9 @@ public: SpriteBatch(Graphics *gfx, Texture *texture, int size, vertex::Usage usage); virtual ~SpriteBatch(); - // Implements Drawable. - void draw(Graphics *gfx, const Matrix4 &m) override; +protected: + + void drawInternal(vertex::CommonFormat format, size_t indexbytestart, size_t indexcount) override; }; // SpriteBatch diff --git a/src/modules/graphics/opengl/Text.cpp b/src/modules/graphics/opengl/Text.cpp index f91f8f368..9f6f2b1dd 100644 --- a/src/modules/graphics/opengl/Text.cpp +++ b/src/modules/graphics/opengl/Text.cpp @@ -40,36 +40,10 @@ Text::~Text() { } -void Text::draw(Graphics *gfx, const Matrix4 &m) +void Text::drawInternal(const std::vector &commands) const { - if (vbo == nullptr || draw_commands.empty()) - return; - - gfx->flushStreamDraws(); - - if (Shader::isDefaultActive()) - Shader::attachDefault(Shader::STANDARD_DEFAULT); - - if (Shader::current) - Shader::current->checkMainTextureType(TEXTURE_2D, false); - OpenGL::TempDebugGroup debuggroup("Text object draw"); - // Re-generate the text if the Font's texture cache was invalidated. - if (font->getTextureCacheID() != texture_cache_id) - regenerateVertices(); - - int totalverts = 0; - for (const Font::DrawCommand &cmd : draw_commands) - totalverts = std::max(cmd.startvertex + cmd.vertexcount, totalverts); - - if ((size_t) totalverts / 4 > quadIndices.getSize()) - quadIndices = QuadIndices(gfx, (size_t) totalverts / 4); - - vbo->unmap(); // Make sure all pending data is flushed to the GPU. - - Graphics::TempTransform transform(gfx, m); - gl.prepareDraw(); gl.setVertexPointers(Font::vertexFormat, vbo, 0); @@ -82,14 +56,12 @@ void Text::draw(Graphics *gfx, const Matrix4 &m) // We need a separate draw call for every section of the text which uses a // different texture than the previous section. - for (const Font::DrawCommand &cmd : draw_commands) + for (const Font::DrawCommand &cmd : commands) { GLsizei count = (cmd.vertexcount / 4) * 6; size_t offset = (cmd.startvertex / 4) * 6 * elemsize; - // TODO: Use glDrawElementsBaseVertex when supported? gl.bindTextureToUnit(cmd.texture, 0, false); - gl.drawElements(GL_TRIANGLES, count, gltype, BUFFER_OFFSET(offset)); } } diff --git a/src/modules/graphics/opengl/Text.h b/src/modules/graphics/opengl/Text.h index 8cefaca6b..e91a84bd5 100644 --- a/src/modules/graphics/opengl/Text.h +++ b/src/modules/graphics/opengl/Text.h @@ -38,8 +38,9 @@ public: Text(love::graphics::Graphics *gfx, love::graphics::Font *font, const std::vector &text = {}); virtual ~Text(); - // Implements Drawable. - void draw(love::graphics::Graphics *gfx, const Matrix4 &m) override; +protected: + + void drawInternal(const std::vector &commands) const override; }; // Text From 72ba5080fbc34828214c0c2c6af581663aa860e9 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 23 Jul 2017 00:28:25 -0300 Subject: [PATCH 12/36] Update license.txt and relicense my .dds file parser code --HG-- branch : minor --- license.txt | 222 +++++++++++++++++++--------- src/libraries/ddsparse/ddsinfo.h | 30 ++-- src/libraries/ddsparse/ddsparse.cpp | 30 ++-- src/libraries/ddsparse/ddsparse.h | 30 ++-- 4 files changed, 191 insertions(+), 121 deletions(-) diff --git a/license.txt b/license.txt index ffadfb869..25b6b5069 100644 --- a/license.txt +++ b/license.txt @@ -23,9 +23,9 @@ distribution. --------- -This software uses LuaJIT: +This software uses ENet: -LuaJIT is Copyright (c) 2005-2016 Mike Pall +Copyright (c) 2002-2016 Lee Salzman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -47,6 +47,31 @@ THE SOFTWARE. --------- +This software uses GLAD: + + The MIT License (MIT) + + Copyright (c) 2013 David Herberth, modified by Alex Szpakowski + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--------- + This software uses glslang: Copyright (C) 2002-2005 3Dlabs Inc. Ltd. @@ -85,30 +110,6 @@ POSSIBILITY OF SUCH DAMAGE. --------- -This software uses ENet: - -Copyright (c) 2002-2016 Lee Salzman - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---------- - This software uses lua-enet: Copyright (C) 2011 by Leaf Corcoran @@ -133,30 +134,76 @@ THE SOFTWARE. --------- -This software uses UTF8-CPP: +This software uses LuaJIT: -Copyright 2006 Nemanja Trifunovic +LuaJIT is Copyright (c) 2005-2016 Mike Pall -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +--------- + +This software uses Lua's UTF-8 module: + +Copyright (C) 1994-2015 Lua.org, PUC-Rio, 2015 LOVE Development Team. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--------- + +This software uses luasocket: + +LuaSocket 3.0 license +Copyright (C) 2004-2013 Diego Nehab + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------- @@ -197,6 +244,63 @@ You can contact the author at : --------- +This software uses TinyEXR: + +Copyright (c) 2014 - 2016, Syoyo Fujita +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--------- + +This software uses UTF8-CPP: + +Copyright 2006 Nemanja Trifunovic + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +--------- + This software uses xxHash: xxHash - Extremely Fast Hash algorithm @@ -232,41 +336,13 @@ You can contact the author at : --------- -This software uses TinyEXR: - -Copyright (c) 2014 - 2016, Syoyo Fujita -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---------- - This software uses the following LGPL libraries on Windows, Mac OS X, Linux, and Android: - libmpg123 Website: http://www.mpg123.de/ Source download: http://sourceforge.net/projects/mpg123/files/latest/download + - OpenAL Soft Website: http://kcat.strangesoft.net/openal.html Source download: http://kcat.strangesoft.net/openal.html#download diff --git a/src/libraries/ddsparse/ddsinfo.h b/src/libraries/ddsparse/ddsinfo.h index 59760d0fe..f653b31e2 100644 --- a/src/libraries/ddsparse/ddsinfo.h +++ b/src/libraries/ddsparse/ddsinfo.h @@ -1,25 +1,23 @@ /** * Simple DDS data parser for compressed 2D textures. * - * Copyright (c) 2013 Alexander Szpakowski. + * Copyright (c) 2013-2017 Alex Szpakowski * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. * * * Enums and structs copied from Microsoft. diff --git a/src/libraries/ddsparse/ddsparse.cpp b/src/libraries/ddsparse/ddsparse.cpp index 4fbdd16a9..d583ff3af 100644 --- a/src/libraries/ddsparse/ddsparse.cpp +++ b/src/libraries/ddsparse/ddsparse.cpp @@ -1,25 +1,23 @@ /** * Simple DDS data parser for compressed 2D textures. * - * Copyright (c) 2013 Alexander Szpakowski. + * Copyright (c) 2013-2017 Alex Szpakowski * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. **/ #include "ddsparse.h" diff --git a/src/libraries/ddsparse/ddsparse.h b/src/libraries/ddsparse/ddsparse.h index 425919ba0..d63875744 100644 --- a/src/libraries/ddsparse/ddsparse.h +++ b/src/libraries/ddsparse/ddsparse.h @@ -1,25 +1,23 @@ /** * Simple DDS data parser for compressed 2D textures. * - * Copyright (c) 2013 Alexander Szpakowski. + * Copyright (c) 2013-2017 Alex Szpakowski * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. **/ #ifndef DDS_PARSE_H From c37e9ed6bf4b60f4bce6e884f5079cdddede8708 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 23 Jul 2017 01:49:27 -0300 Subject: [PATCH 13/36] Use vector2 arrays instead of raw float arrays for graphics primitives. Simplifies the code a bit. --HG-- branch : minor --- src/modules/graphics/Graphics.cpp | 95 ++++++++++++-------------- src/modules/graphics/Graphics.h | 18 +++-- src/modules/graphics/Polyline.cpp | 16 ++--- src/modules/graphics/Polyline.h | 16 ++--- src/modules/graphics/wrap_Graphics.cpp | 94 ++++++++++++++----------- 5 files changed, 124 insertions(+), 115 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 394513871..16f1b2841 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -951,7 +951,7 @@ void Graphics::printf(const std::vector &str, Font *font, f * Primitives (points, shapes, lines). **/ -void Graphics::points(const float *coords, const Colorf *colors, size_t numpoints) +void Graphics::points(const Vector2 *positions, const Colorf *colors, size_t numpoints) { const Matrix4 &t = getTransform(); bool is2D = t.isAffine2DTransform(); @@ -965,9 +965,9 @@ void Graphics::points(const float *coords, const Colorf *colors, size_t numpoint StreamVertexData data = requestStreamDraw(req); if (is2D) - t.transformXY((Vector2 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); + t.transformXY((Vector2 *) data.stream[0], positions, req.vertexCount); else - t.transformXY0((Vector3 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); + t.transformXY0((Vector3 *) data.stream[0], positions, req.vertexCount); Color *colordata = (Color *) data.stream[1]; @@ -1008,7 +1008,7 @@ int Graphics::calculateEllipsePoints(float rx, float ry) const return std::max(points, 8); } -void Graphics::polyline(const float *coords, size_t count) +void Graphics::polyline(const Vector2 *vertices, size_t count) { float halfwidth = getLineWidth() * 0.5f; LineJoin linejoin = getLineJoin(); @@ -1019,27 +1019,27 @@ void Graphics::polyline(const float *coords, size_t count) if (linejoin == LINE_JOIN_NONE) { NoneJoinPolyline line; - line.render(coords, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH); + line.render(vertices, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH); line.draw(this); } else if (linejoin == LINE_JOIN_BEVEL) { BevelJoinPolyline line; - line.render(coords, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH); + line.render(vertices, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH); line.draw(this); } else if (linejoin == LINE_JOIN_MITER) { MiterJoinPolyline line; - line.render(coords, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH); + line.render(vertices, count, halfwidth, pixelsize, linestyle == LINE_SMOOTH); line.draw(this); } } void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h) { - float coords[] = {x,y, x,y+h, x+w,y+h, x+w,y, x,y}; - polygon(mode, coords, 5 * 2); + Vector2 coords[] = {Vector2(x,y), Vector2(x,y+h), Vector2(x+w,y+h), Vector2(x+w,y), Vector2(x,y)}; + polygon(mode, coords, 5); } void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry, int points) @@ -1062,44 +1062,43 @@ void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, floa const float half_pi = static_cast(LOVE_M_PI / 2); float angle_shift = half_pi / ((float) points + 1.0f); - int num_coords = (points + 2) * 8; - float *coords = getScratchBuffer(num_coords + 2); + int num_coords = (points + 2) * 4; + Vector2 *coords = getScratchBuffer(num_coords + 1); float phi = .0f; for (int i = 0; i <= points + 2; ++i, phi += angle_shift) { - coords[2 * i + 0] = x + rx * (1 - cosf(phi)); - coords[2 * i + 1] = y + ry * (1 - sinf(phi)); + coords[i].x = x + rx * (1 - cosf(phi)); + coords[i].y = y + ry * (1 - sinf(phi)); } phi = half_pi; for (int i = points + 2; i <= 2 * (points + 2); ++i, phi += angle_shift) { - coords[2 * i + 0] = x + w - rx * (1 + cosf(phi)); - coords[2 * i + 1] = y + ry * (1 - sinf(phi)); + coords[i].x = x + w - rx * (1 + cosf(phi)); + coords[i].y = y + ry * (1 - sinf(phi)); } phi = 2 * half_pi; for (int i = 2 * (points + 2); i <= 3 * (points + 2); ++i, phi += angle_shift) { - coords[2 * i + 0] = x + w - rx * (1 + cosf(phi)); - coords[2 * i + 1] = y + h - ry * (1 + sinf(phi)); + coords[i].x = x + w - rx * (1 + cosf(phi)); + coords[i].y = y + h - ry * (1 + sinf(phi)); } - phi = 3 * half_pi; + phi = 3 * half_pi; for (int i = 3 * (points + 2); i <= 4 * (points + 2); ++i, phi += angle_shift) { - coords[2 * i + 0] = x + rx * (1 - cosf(phi)); - coords[2 * i + 1] = y + h - ry * (1 + sinf(phi)); + coords[i].x = x + rx * (1 - cosf(phi)); + coords[i].y = y + h - ry * (1 + sinf(phi)); } - coords[num_coords + 0] = coords[0]; - coords[num_coords + 1] = coords[1]; + coords[num_coords] = coords[0]; - polygon(mode, coords, num_coords + 2); + polygon(mode, coords, num_coords + 1); } void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry) @@ -1124,15 +1123,14 @@ void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b, int po float angle_shift = (two_pi / points); float phi = .0f; - float *coords = getScratchBuffer(2 * (points + 1)); + Vector2 *coords = getScratchBuffer(points + 1); for (int i = 0; i < points; ++i, phi += angle_shift) { - coords[2*i+0] = x + a * cosf(phi); - coords[2*i+1] = y + b * sinf(phi); + coords[i].x = x + a * cosf(phi); + coords[i].y = y + b * sinf(phi); } - coords[2*points+0] = coords[0]; - coords[2*points+1] = coords[1]; + coords[points] = coords[0]; polygon(mode, coords, (points + 1) * 2); } @@ -1173,45 +1171,43 @@ void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float r float phi = angle1; - float *coords = nullptr; + Vector2 *coords = nullptr; int num_coords = 0; - const auto createPoints = [&](float *coordinates) + const auto createPoints = [&](Vector2 *coordinates) { for (int i = 0; i <= points; ++i, phi += angle_shift) { - coordinates[2 * i + 0] = x + radius * cosf(phi); - coordinates[2 * i + 1] = y + radius * sinf(phi); + coordinates[i].x = x + radius * cosf(phi); + coordinates[i].y = y + radius * sinf(phi); } }; if (arcmode == ARC_PIE) { - num_coords = (points + 3) * 2; - coords = getScratchBuffer(num_coords); + num_coords = points + 3; + coords = getScratchBuffer(num_coords); - coords[0] = coords[num_coords - 2] = x; - coords[1] = coords[num_coords - 1] = y; + coords[0] = coords[num_coords - 1] = Vector2(x, y); - createPoints(coords + 2); + createPoints(coords + 1); } else if (arcmode == ARC_OPEN) { - num_coords = (points + 1) * 2; - coords = getScratchBuffer(num_coords); + num_coords = points + 1; + coords = getScratchBuffer(num_coords); createPoints(coords); } else // ARC_CLOSED { - num_coords = (points + 2) * 2; - coords = getScratchBuffer(num_coords); + num_coords = points + 2; + coords = getScratchBuffer(num_coords); createPoints(coords); // Connect the ends of the arc. - coords[num_coords - 2] = coords[0]; - coords[num_coords - 1] = coords[1]; + coords[num_coords - 1] = coords[0]; } polygon(drawmode, coords, num_coords); @@ -1229,13 +1225,10 @@ void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float r arc(drawmode, arcmode, x, y, radius, angle1, angle2, (int) (points + 0.5f)); } -/// @param mode the draw mode -/// @param coords the coordinate array -/// @param count the number of coordinates/size of the array -void Graphics::polygon(DrawMode mode, const float *coords, size_t count) +void Graphics::polygon(DrawMode mode, const Vector2 *coords, size_t count) { // coords is an array of a closed loop of vertices, i.e. - // coords[count-2] = coords[0], coords[count-1] = coords[1] + // coords[count-1] == coords[0] if (mode == DRAW_LINE) { polyline(coords, count); @@ -1249,14 +1242,14 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count) req.formats[0] = vertex::getSinglePositionFormat(is2D); req.formats[1] = vertex::CommonFormat::RGBAub; req.indexMode = vertex::TriangleIndexMode::FAN; - req.vertexCount = (int)count/2 - 1; + req.vertexCount = (int)count - 1; StreamVertexData data = requestStreamDraw(req); if (is2D) - t.transformXY((Vector2 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); + t.transformXY((Vector2 *) data.stream[0], coords, req.vertexCount); else - t.transformXY0((Vector3 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); + t.transformXY0((Vector3 *) data.stream[0], coords, req.vertexCount); Color c = toColor(getColor()); Color *colordata = (Color *) data.stream[1]; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index a515a1d21..7fda77ae4 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -620,18 +620,16 @@ public: void printf(const std::vector &str, Font *font, float wrap, Font::AlignMode align, const Matrix4 &m); /** - * Draws a point at (x,y). - * @param x Point along x-axis. - * @param y Point along y-axis. + * Draws a series of points at the specified positions. **/ - void points(const float *coords, const Colorf *colors, size_t numpoints); + void points(const Vector2 *positions, const Colorf *colors, size_t numpoints); /** * Draws a series of lines connecting the given vertices. - * @param coords Vertex components (x1, y1, ..., xn, yn). If x1,y1 == xn,yn the line will be drawn closed. - * @param count Number of items in the array, i.e. count = 2 * n + * @param coords Vertex positions (v1, ..., vn). If v1 == vn the line will be drawn closed. + * @param count Number of vertices. **/ - void polyline(const float *coords, size_t count); + void polyline(const Vector2 *vertices, size_t count); /** * Draws a rectangle. @@ -696,10 +694,10 @@ public: /** * Draws a polygon with an arbitrary number of vertices. * @param mode The type of drawing (line/filled). - * @param coords Vertex components (x1, y1, x2, y2, etc.) - * @param count Coord array size + * @param coords Vertex positions. + * @param count Vertex array size. **/ - void polygon(DrawMode mode, const float *coords, size_t count); + void polygon(DrawMode mode, const Vector2 *vertices, size_t count); /** * Gets the graphics capabilities (feature support, limit values, and diff --git a/src/modules/graphics/Polyline.cpp b/src/modules/graphics/Polyline.cpp index ebf651ef5..060a01da4 100644 --- a/src/modules/graphics/Polyline.cpp +++ b/src/modules/graphics/Polyline.cpp @@ -33,7 +33,7 @@ namespace love namespace graphics { -void Polyline::render(const float *coords, size_t count, size_t size_hint, float halfwidth, float pixel_size, bool draw_overdraw) +void Polyline::render(const Vector2 *coords, size_t count, size_t size_hint, float halfwidth, float pixel_size, bool draw_overdraw) { static std::vector anchors; anchors.clear(); @@ -48,26 +48,26 @@ void Polyline::render(const float *coords, size_t count, size_t size_hint, float halfwidth -= pixel_size * 0.3f; // compute sleeve - bool is_looping = (coords[0] == coords[count - 2]) && (coords[1] == coords[count - 1]); + bool is_looping = (coords[0] == coords[count - 1]); Vector2 s; if (!is_looping) // virtual starting point at second point mirrored on first point - s = Vector2(coords[2] - coords[0], coords[3] - coords[1]); + s = coords[1] - coords[0]; else // virtual starting point at last vertex - s = Vector2(coords[0] - coords[count - 4], coords[1] - coords[count - 3]); + s = coords[0] - coords[count - 2]; float len_s = s.getLength(); Vector2 ns = s.getNormal(halfwidth / len_s); - Vector2 q, r(coords[0], coords[1]); - for (size_t i = 0; i + 3 < count; i += 2) + Vector2 q, r(coords[0]); + for (size_t i = 0; i + 1 < count; i++) { q = r; - r = Vector2(coords[i + 2], coords[i + 3]); + r = coords[i + 1]; renderEdge(anchors, normals, s, len_s, ns, q, r, halfwidth); } q = r; - r = is_looping ? Vector2(coords[2], coords[3]) : r + s; + r = is_looping ? coords[1] : r + s; renderEdge(anchors, normals, s, len_s, ns, q, r, halfwidth); vertex_count = normals.size(); diff --git a/src/modules/graphics/Polyline.h b/src/modules/graphics/Polyline.h index 9bdc2ab6a..773f06147 100644 --- a/src/modules/graphics/Polyline.h +++ b/src/modules/graphics/Polyline.h @@ -57,13 +57,13 @@ public: /** * @param vertices Vertices defining the core line segments - * @param count Number of coordinates (= size of the array vertices) + * @param count Number of vertices * @param size_hint Expected number of vertices of the rendering sleeve around the core line. * @param halfwidth linewidth / 2. * @param pixel_size Dimension of one pixel on the screen in world coordinates. * @param draw_overdraw Fake antialias the line. */ - void render(const float *vertices, size_t count, size_t size_hint, float halfwidth, float pixel_size, bool draw_overdraw); + void render(const Vector2 *vertices, size_t count, size_t size_hint, float halfwidth, float pixel_size, bool draw_overdraw); /** Draws the line on the screen */ @@ -112,9 +112,9 @@ public: : Polyline(vertex::TriangleIndexMode::QUADS) {} - void render(const float *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw) + void render(const Vector2 *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw) { - Polyline::render(vertices, count, 2 * count - 4, halfwidth, pixel_size, draw_overdraw); + Polyline::render(vertices, count, 4 * count - 4, halfwidth, pixel_size, draw_overdraw); // discard the first and last two vertices. (these are redundant) for (size_t i = 0; i < vertex_count - 4; ++i) @@ -149,9 +149,9 @@ class MiterJoinPolyline : public Polyline { public: - void render(const float *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw) + void render(const Vector2 *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw) { - Polyline::render(vertices, count, count, halfwidth, pixel_size, draw_overdraw); + Polyline::render(vertices, count, 2 * count, halfwidth, pixel_size, draw_overdraw); } protected: @@ -171,9 +171,9 @@ class BevelJoinPolyline : public Polyline { public: - void render(const float *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw) + void render(const Vector2 *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw) { - Polyline::render(vertices, count, 2 * count - 4, halfwidth, pixel_size, draw_overdraw); + Polyline::render(vertices, count, 4 * count - 4, halfwidth, pixel_size, draw_overdraw); } protected: diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index e6e870813..7e7cc9fba 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -2279,23 +2279,23 @@ int w_points(lua_State *L) if (args % 2 != 0 && !is_table_of_tables) return luaL_error(L, "Number of vertex components must be a multiple of two"); - int numpoints = args / 2; + int numpositions = args / 2; if (is_table_of_tables) - numpoints = args; + numpositions = args; - float *coords = nullptr; + Vector2 *positions = nullptr; Colorf *colors = nullptr; if (is_table_of_tables) { - size_t datasize = (sizeof(float) * 2 + sizeof(Colorf)) * numpoints; + size_t datasize = (sizeof(Vector2) + sizeof(Colorf)) * numpositions; uint8 *data = instance()->getScratchBuffer(datasize); - coords = (float *) data; - colors = (Colorf *) (data + sizeof(float) * numpoints * 2); + positions = (Vector2 *) data; + colors = (Colorf *) (data + sizeof(Vector2) * numpositions); } else - coords = instance()->getScratchBuffer(numpoints * 2); + positions = instance()->getScratchBuffer(numpositions); if (is_table) { @@ -2308,13 +2308,13 @@ int w_points(lua_State *L) for (int j = 1; j <= 6; j++) lua_rawgeti(L, -j, j); - coords[i * 2 + 0] = luax_tofloat(L, -6); - coords[i * 2 + 1] = luax_tofloat(L, -5); + positions[i].x = luax_tofloat(L, -6); + positions[i].y = luax_tofloat(L, -5); - colors[i].r = luaL_optnumber(L, -4, 1.0); - colors[i].g = luaL_optnumber(L, -3, 1.0); - colors[i].b = luaL_optnumber(L, -2, 1.0); - colors[i].a = luaL_optnumber(L, -1, 1.0); + colors[i].r = (float) luaL_optnumber(L, -4, 1.0); + colors[i].g = (float) luaL_optnumber(L, -3, 1.0); + colors[i].b = (float) luaL_optnumber(L, -2, 1.0); + colors[i].a = (float) luaL_optnumber(L, -1, 1.0); lua_pop(L, 7); } @@ -2322,21 +2322,26 @@ int w_points(lua_State *L) else { // points({x1, y1, x2, y2, ...}) - for (int i = 0; i < args; i++) + for (int i = 0; i < numpositions; i++) { - lua_rawgeti(L, 1, i + 1); - coords[i] = luax_tofloat(L, -1); - lua_pop(L, 1); + lua_rawgeti(L, 1, i * 2 + 1); + lua_rawgeti(L, 1, i * 2 + 2); + positions[i].x = luax_tofloat(L, -2); + positions[i].y = luax_tofloat(L, -1); + lua_pop(L, 2); } } } else { - for (int i = 0; i < args; i++) - coords[i] = luax_tofloat(L, i + 1); + for (int i = 0; i < numpositions; i++) + { + positions[i].x = luax_tofloat(L, i * 2 + 1); + positions[i].y = luax_tofloat(L, i * 2 + 2); + } } - luax_catchexcept(L, [&](){ instance()->points(coords, colors, numpoints); }); + luax_catchexcept(L, [&](){ instance()->points(positions, colors, numpositions); }); return 0; } @@ -2355,24 +2360,31 @@ int w_line(lua_State *L) else if (args < 4) return luaL_error(L, "Need at least two vertices to draw a line"); - float *coords = instance()->getScratchBuffer(args); + int numvertices = args / 2; + + Vector2 *coords = instance()->getScratchBuffer(numvertices); if (is_table) { - for (int i = 0; i < args; ++i) + for (int i = 0; i < numvertices; ++i) { - lua_rawgeti(L, 1, i + 1); - coords[i] = luax_tofloat(L, -1); - lua_pop(L, 1); + lua_rawgeti(L, 1, (i * 2) + 1); + lua_rawgeti(L, 1, (i * 2) + 2); + coords[i].x = luax_tofloat(L, -2); + coords[i].y = luax_tofloat(L, -1); + lua_pop(L, 2); } } else { - for (int i = 0; i < args; ++i) - coords[i] = luax_tofloat(L, i + 1); + for (int i = 0; i < numvertices; ++i) + { + coords[i].x = luax_tofloat(L, (i * 2) + 1); + coords[i].y = luax_tofloat(L, (i * 2) + 2); + } } luax_catchexcept(L, - [&](){ instance()->polyline(coords, args); } + [&](){ instance()->polyline(coords, numvertices); } ); return 0; @@ -2513,28 +2525,34 @@ int w_polygon(lua_State *L) else if (args < 6) return luaL_error(L, "Need at least three vertices to draw a polygon"); + int numvertices = args / 2; + // fetch coords - float *coords = instance()->getScratchBuffer(args + 2); + Vector2 *coords = instance()->getScratchBuffer(numvertices + 1); if (is_table) { - for (int i = 0; i < args; ++i) + for (int i = 0; i < numvertices; ++i) { - lua_rawgeti(L, 2, i + 1); - coords[i] = luax_tofloat(L, -1); - lua_pop(L, 1); + lua_rawgeti(L, 2, (i * 2) + 1); + lua_rawgeti(L, 2, (i * 2) + 2); + coords[i].x = luax_tofloat(L, -2); + coords[i].y = luax_tofloat(L, -1); + lua_pop(L, 2); } } else { - for (int i = 0; i < args; ++i) - coords[i] = luax_tofloat(L, i + 2); + for (int i = 0; i < numvertices; ++i) + { + coords[i].x = luax_tofloat(L, (i * 2) + 2); + coords[i].y = luax_tofloat(L, (i * 2) + 3); + } } // make a closed loop - coords[args] = coords[0]; - coords[args+1] = coords[1]; + coords[numvertices] = coords[0]; - luax_catchexcept(L, [&](){ instance()->polygon(mode, coords, args+2); }); + luax_catchexcept(L, [&](){ instance()->polygon(mode, coords, numvertices+1); }); return 0; } From b3d4443f9d88133b9c75d778b53955e86751d2a7 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 23 Jul 2017 01:58:25 -0300 Subject: [PATCH 14/36] Added 'drawcallsbatched' field to the table returned by love.graphics.getStats. It has the number of draw calls that were saved by auto-batching. --HG-- branch : minor --- src/modules/graphics/Graphics.cpp | 5 +++++ src/modules/graphics/Graphics.h | 2 ++ src/modules/graphics/opengl/Graphics.cpp | 1 + src/modules/graphics/wrap_Graphics.cpp | 3 +++ 4 files changed, 11 insertions(+) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 16f1b2841..d00459147 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -112,6 +112,7 @@ Graphics::Graphics() , streamBufferState() , projectionMatrix() , canvasSwitchCount(0) + , drawCallsBatched(0) , capabilities() { transformStack.reserve(16); @@ -879,6 +880,9 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest & } } + if (state.vertexCount > 0) + drawCallsBatched++; + state.vertexCount += req.vertexCount; state.indexCount += reqIndexCount; @@ -1273,6 +1277,7 @@ Graphics::Stats Graphics::getStats() const stats.drawCalls++; stats.canvasSwitches = canvasSwitchCount; + stats.drawCallsBatched = drawCallsBatched; stats.canvases = Canvas::canvasCount; stats.images = Image::imageCount; stats.fonts = Font::fontCount; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 7fda77ae4..24f5d88ca 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -216,6 +216,7 @@ public: struct Stats { int drawCalls; + int drawCallsBatched; int canvasSwitches; int shaderSwitches; int canvases; @@ -900,6 +901,7 @@ protected: std::vector temporaryCanvases; int canvasSwitchCount; + int drawCallsBatched; Capabilities capabilities; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index bd5415e1b..cce9290f8 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1010,6 +1010,7 @@ void Graphics::present(void *screenshotCallbackData) gl.stats.drawCalls = 0; gl.stats.shaderSwitches = 0; canvasSwitchCount = 0; + drawCallsBatched = 0; } void Graphics::setScissor(const Rect &rect) diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 7e7cc9fba..0d8d183a2 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -2073,6 +2073,9 @@ int w_getStats(lua_State *L) lua_pushinteger(L, stats.drawCalls); lua_setfield(L, -2, "drawcalls"); + lua_pushinteger(L, stats.drawCallsBatched); + lua_setfield(L, -2, "drawcallsbatched"); + lua_pushinteger(L, stats.canvasSwitches); lua_setfield(L, -2, "canvasswitches"); From d1d6fb6f6822644e94c497d275896fc78b6817da Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 23 Jul 2017 18:44:08 -0300 Subject: [PATCH 15/36] Update stb_image from 2.12 to 2.16. --HG-- branch : minor --- src/libraries/stb/stb_image.h | 1560 +++++++++++++++++++++------------ 1 file changed, 991 insertions(+), 569 deletions(-) diff --git a/src/libraries/stb/stb_image.h b/src/libraries/stb/stb_image.h index 13ba6c75c..a056138dd 100644 --- a/src/libraries/stb/stb_image.h +++ b/src/libraries/stb/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.12 - public domain image loader - http://nothings.org/stb_image.h +/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h no warranty implied; use at your own risk Do this: @@ -21,7 +21,7 @@ avoid problematic images and only need the trivial interface JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8-bit-per-channel (16 bpc not supported) + PNG 1/2/4/8/16-bit-per-channel TGA (not sure what subset, if a subset) BMP non-1bpp, non-RLE @@ -42,136 +42,23 @@ Full documentation under "DOCUMENTATION" below. - Revision 2.00 release notes: +LICENSE - - Progressive JPEG is now supported. + See end of file for license information. - - PPM and PGM binary formats are now supported, thanks to Ken Miller. +RECENT REVISION HISTORY: - - x86 platforms now make use of SSE2 SIMD instructions for - JPEG decoding, and ARM platforms can use NEON SIMD if requested. - This work was done by Fabian "ryg" Giesen. SSE2 is used by - default, but NEON must be enabled explicitly; see docs. - - With other JPEG optimizations included in this version, we see - 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup - on a JPEG on an ARM machine, relative to previous versions of this - library. The same results will not obtain for all JPGs and for all - x86/ARM machines. (Note that progressive JPEGs are significantly - slower to decode than regular JPEGs.) This doesn't mean that this - is the fastest JPEG decoder in the land; rather, it brings it - closer to parity with standard libraries. If you want the fastest - decode, look elsewhere. (See "Philosophy" section of docs below.) - - See final bullet items below for more info on SIMD. - - - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing - the memory allocator. Unlike other STBI libraries, these macros don't - support a context parameter, so if you need to pass a context in to - the allocator, you'll have to store it in a global or a thread-local - variable. - - - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and - STBI_NO_LINEAR. - STBI_NO_HDR: suppress implementation of .hdr reader format - STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API - - - You can suppress implementation of any of the decoders to reduce - your code footprint by #defining one or more of the following - symbols before creating the implementation. - - STBI_NO_JPEG - STBI_NO_PNG - STBI_NO_BMP - STBI_NO_PSD - STBI_NO_TGA - STBI_NO_GIF - STBI_NO_HDR - STBI_NO_PIC - STBI_NO_PNM (.ppm and .pgm) - - - You can request *only* certain decoders and suppress all other ones - (this will be more forward-compatible, as addition of new decoders - doesn't require you to disable them explicitly): - - STBI_ONLY_JPEG - STBI_ONLY_PNG - STBI_ONLY_BMP - STBI_ONLY_PSD - STBI_ONLY_TGA - STBI_ONLY_GIF - STBI_ONLY_HDR - STBI_ONLY_PIC - STBI_ONLY_PNM (.ppm and .pgm) - - Note that you can define multiples of these, and you will get all - of them ("only x" and "only y" is interpreted to mean "only x&y"). - - - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still - want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB - - - Compilation of all SIMD code can be suppressed with - #define STBI_NO_SIMD - It should not be necessary to disable SIMD unless you have issues - compiling (e.g. using an x86 compiler which doesn't support SSE - intrinsics or that doesn't support the method used to detect - SSE2 support at run-time), and even those can be reported as - bugs so I can refine the built-in compile-time checking to be - smarter. - - - The old STBI_SIMD system which allowed installing a user-defined - IDCT etc. has been removed. If you need this, don't upgrade. My - assumption is that almost nobody was doing this, and those who - were will find the built-in SIMD more satisfactory anyway. - - - RGB values computed for JPEG images are slightly different from - previous versions of stb_image. (This is due to using less - integer precision in SIMD.) The C code has been adjusted so - that the same RGB values will be computed regardless of whether - SIMD support is available, so your app should always produce - consistent results. But these results are slightly different from - previous versions. (Specifically, about 3% of available YCbCr values - will compute different RGB results from pre-1.49 versions by +-1; - most of the deviating values are one smaller in the G channel.) - - - If you must produce consistent results with previous versions of - stb_image, #define STBI_JPEG_OLD and you will get the same results - you used to; however, you will not get the SIMD speedups for - the YCbCr-to-RGB conversion step (although you should still see - significant JPEG speedup from the other changes). - - Please note that STBI_JPEG_OLD is a temporary feature; it will be - removed in future versions of the library. It is only intended for - near-term back-compatibility use. - - - Latest revision history: + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 RGB-format JPEG; remove white matting in PSD; - allocate large structures on the stack; + allocate large structures on the stack; correct channel count for PNG & BMP 2.10 (2016-01-22) avoid warning introduced in 2.09 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED - 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA - 2.07 (2015-09-13) partial animated GIF support - limited 16-bit PSD support - minor bugs, code cleanup, and compiler warnings - 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value - 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning - 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit - 2.03 (2015-04-12) additional corruption checking - stbi_set_flip_vertically_on_load - fix NEON support; fix mingw support - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD - progressive JPEG - PGM/PPM support - STBI_MALLOC,STBI_REALLOC,STBI_FREE - STBI_NO_*, STBI_ONLY_* - GIF bugfix See end of file for full revision history. @@ -186,34 +73,30 @@ Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) - urraka@github (animated gif) Junggon Kim (PNM comments) + github:urraka (animated gif) Junggon Kim (PNM comments) Daniel Gibson (16-bit TGA) - + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Fabian "ryg" Giesen Arseny Kapoulkine + John-Mark Allen Bug & warning fixes Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Martin Golini Jerry Jansson Joseph Thomson - Dave Moore Roy Eltham Hayaki Saito Phil Jordan - Won Chun Luke Graham Johan Duparc Nathan Reed - the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis - Janez Zemva John Bartholomew Michal Cichon svdijk@github - Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson - Laurent Gomila Cort Stratton Sergio Gonzalez romigrou@github - Aruelien Pocheville Thibault Reuille Cass Everitt Matthew Gregan - Ryamond Barbiero Paul Du Bois Engin Manap snagar@github - Michaelangel007@github Oriol Ferrer Mesia socks-the-fox - Blazej Dariusz Roszkowski - - -LICENSE - -This software is dual-licensed to the public domain and under the following -license: you are granted a perpetual, irrevocable license to copy, modify, -publish, and distribute this file as you see fit. - + Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan + Dave Moore Roy Eltham Hayaki Saito Nathan Reed + Won Chun Luke Graham Johan Duparc Nick Verigakis + the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson + Janez Zemva John Bartholomew Michal Cichon github:rlyeh + Jonathan Blow Ken Hamada Tero Hanninen github:romigrou + Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk + Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar + Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex + Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210 + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw + Blazej Dariusz Roszkowski Gregory Mullen github:phprus + Christian Floisand Kevin Schmidt github:poppolopoppo */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -238,10 +121,10 @@ publish, and distribute this file as you see fit. // stbi_image_free(data) // // Standard parameters: -// int *x -- outputs image width in pixels -// int *y -- outputs image height in pixels -// int *comp -- outputs # of image components in image file -// int req_comp -- if non-zero, # of image components requested in result +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result // // The return value from an image loader is an 'unsigned char *' which points // to the pixel data, or NULL on an allocation failure or if the image is @@ -249,11 +132,12 @@ publish, and distribute this file as you see fit. // with each pixel consisting of N interleaved 8-bit components; the first // pixel pointed to is top-left-most in the image. There is no padding between // image scanlines or between pixels, regardless of format. The number of -// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. -// If req_comp is non-zero, *comp has the number of components that _would_ -// have been output otherwise. E.g. if you set req_comp to 4, you will always -// get RGBA output, but you can check *comp to see if it's trivially opaque -// because e.g. there were only 3 channels in the source image. +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. // // An output image with N components has the following components interleaved // in this order in each pixel: @@ -265,10 +149,10 @@ publish, and distribute this file as you see fit. // 4 red, green, blue, alpha // // If image loading fails for any reason, the return value will be NULL, -// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() -// can be queried for an extremely brief, end-user unfriendly explanation -// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid -// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly // more user-friendly ones. // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. @@ -287,13 +171,13 @@ publish, and distribute this file as you see fit. // and for best performance I may provide less-easy-to-use APIs that give higher // performance, in addition to the easy to use ones. Nevertheless, it's important // to keep in mind that from the standpoint of you, a client of this library, -// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. // // Some secondary priorities arise directly from the first two, some of which // make more explicit reasons why performance can't be emphasized. // // - Portable ("ease of use") -// - Small footprint ("easy to maintain") +// - Small source code footprint ("easy to maintain") // - No dependencies ("ease of use") // // =========================================================================== @@ -325,13 +209,6 @@ publish, and distribute this file as you see fit. // (at least this is true for iOS and Android). Therefore, the NEON support is // toggled by a build flag: define STBI_NEON to get NEON loops. // -// The output of the JPEG decoder is slightly different from versions where -// SIMD support was introduced (that is, for versions before 1.49). The -// difference is only +-1 in the 8-bit RGB channels, and only on a small -// fraction of pixels. You can force the pre-1.49 behavior by defining -// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path -// and hence cost some performance. -// // If for some reason you do not want to use any of SIMD code, or if // you have issues compiling it, you can disable it entirely by // defining STBI_NO_SIMD. @@ -387,6 +264,41 @@ publish, and distribute this file as you see fit. // says there's premultiplied data (currently only happens in iPhone images, // and only if iPhone convert-to-rgb processing is on). // +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// #ifndef STBI_NO_STDIO @@ -397,7 +309,7 @@ publish, and distribute this file as you see fit. enum { - STBI_default = 0, // only used for req_comp + STBI_default = 0, // only used for desired_channels STBI_grey = 1, STBI_grey_alpha = 2, @@ -406,6 +318,7 @@ enum }; typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; #ifdef __cplusplus extern "C" { @@ -433,22 +346,44 @@ typedef struct int (*eof) (void *user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); // for stbi_load_from_file, file pointer is left pointing immediately after image #endif +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// #ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); #endif #endif @@ -566,6 +501,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #include // ptrdiff_t on osx #include #include +#include #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) #include // ldexp @@ -649,12 +585,14 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #define STBI__X86_TARGET #endif -#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) -// NOTE: not clear do we actually need this for the 64-bit path? +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) // gcc doesn't support sse2 intrinsics unless you compile with -msse2, -// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; -// this is just broken and gcc are jerks for not fixing it properly -// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. #define STBI_NO_SIMD #endif @@ -702,7 +640,7 @@ static int stbi__cpuid3(void) #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name -static int stbi__sse2_available() +static int stbi__sse2_available(void) { int info3 = stbi__cpuid3(); return ((info3 >> 26) & 1) != 0; @@ -710,22 +648,12 @@ static int stbi__sse2_available() #else // assume GCC-style if not VC++ #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -static int stbi__sse2_available() +static int stbi__sse2_available(void) { -#if defined(STBI__X64_TARGET) - // on x64, SSE2 can be assumed to be available. + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. return 1; -#elif defined(LOVE_STBI_SSE2_OVERRIDE) - return 1; -#else -# warning "stb_image compiled without SSE2 support, define LOVE_STBI_SSE2_OVERRIDE to force SSE2 support" - // __builtin_cpu_supports is buggy on GCC 5 and above, causing problems if - // referenced in a shared object, giving missing __cpu_model hidden symbol errors. - // To get around that, just assume that SSE2 is not available on x86. - // - // See https://github.com/nothings/stb/issues/280 for more information. - return 0; -#endif } #endif #endif @@ -833,57 +761,70 @@ static void stbi__rewind(stbi__context *s) s->img_buffer_end = s->img_buffer_original_end; } +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + #ifndef STBI_NO_JPEG static int stbi__jpeg_test(stbi__context *s); -static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNG static int stbi__png_test(stbi__context *s); -static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_BMP static int stbi__bmp_test(stbi__context *s); -static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_TGA static int stbi__tga_test(stbi__context *s); -static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PSD static int stbi__psd_test(stbi__context *s); -static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_HDR static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PIC static int stbi__pic_test(stbi__context *s); -static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_GIF static int stbi__gif_test(stbi__context *s); -static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNM static int stbi__pnm_test(stbi__context *s); -static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); #endif @@ -906,6 +847,77 @@ static void *stbi__malloc(size_t size) return STBI_MALLOC(size); } +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} + +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} + // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -941,33 +953,38 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) stbi__vertically_flip_on_load = flag_true_if_should_flip; } -static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); #endif #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); } #endif @@ -975,56 +992,123 @@ static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *com #ifndef STBI_NO_TGA // test tga last because it's a crappy test! if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp); + return stbi__tga_load(s,x,y,comp,req_comp, ri); #endif return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); } -static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) { - unsigned char *result = stbi__load_main(s, x, y, comp, req_comp); + int i; + int img_len = w * h * channels; + stbi_uc *reduced; - if (stbi__vertically_flip_on_load && result != NULL) { - int w = *x, h = *y; - int depth = req_comp ? req_comp : *comp; - int row,col,z; - stbi_uc temp; + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); - // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once - for (row = 0; row < (h>>1); row++) { - for (col = 0; col < w; col++) { - for (z = 0; z < depth; z++) { - temp = result[(row * w + col) * depth + z]; - result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; - result[((h - row - 1) * w + col) * depth + z] = temp; - } - } + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; } } +} - return result; +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; } #ifndef STBI_NO_HDR static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) { if (stbi__vertically_flip_on_load && result != NULL) { - int w = *x, h = *y; - int depth = req_comp ? req_comp : *comp; - int row,col,z; - float temp; - - // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once - for (row = 0; row < (h>>1); row++) { - for (col = 0; col < w; col++) { - for (z = 0; z < depth; z++) { - temp = result[(row * w + col) * depth + z]; - result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; - result[((h - row - 1) * w + col) * depth + z] = temp; - } - } - } + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); } } #endif @@ -1059,27 +1143,66 @@ STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req unsigned char *result; stbi__context s; stbi__start_file(&s,f); - result = stbi__load_flip(&s,x,y,comp,req_comp); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); if (result) { // need to 'unget' all the characters in the IO buffer fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); } return result; } + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + #endif //!STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_mem(&s,buffer,len); - return stbi__load_flip(&s,x,y,comp,req_comp); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); } STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__load_flip(&s,x,y,comp,req_comp); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); } #ifndef STBI_NO_LINEAR @@ -1088,13 +1211,14 @@ static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int unsigned char *data; #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) { - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp); + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); if (hdr_data) stbi__float_postprocess(hdr_data,x,y,comp,req_comp); return hdr_data; } #endif - data = stbi__load_flip(s, x, y, comp, req_comp); + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); if (data) return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); @@ -1301,15 +1425,11 @@ static int stbi__get16be(stbi__context *s) return (z << 8) + stbi__get8(s); } -#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) -// nothing -#else static stbi__uint32 stbi__get32be(stbi__context *s) { stbi__uint32 z = stbi__get16be(s); return (z << 16) + stbi__get16be(s); } -#endif #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing @@ -1356,7 +1476,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r if (req_comp == img_n) return data; STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (unsigned char *) stbi__malloc(req_comp * x * y); + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); if (good == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); @@ -1366,26 +1486,75 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r unsigned char *src = data + j * x * img_n ; unsigned char *dest = good + j * x * req_comp; - #define COMBO(a,b) ((a)*8+(b)) - #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) // convert source image with img_n components to one with req_comp components; // avoid switch per pixel, so use switch per scanline and massive macros - switch (COMBO(img_n, req_comp)) { - CASE(1,2) dest[0]=src[0], dest[1]=255; break; - CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; - CASE(2,1) dest[0]=src[0]; break; - CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; - CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; - CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; - CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; - CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; - CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; - CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; default: STBI_ASSERT(0); } - #undef CASE + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE } STBI_FREE(data); @@ -1396,7 +1565,9 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) { int i,k,n; - float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; @@ -1416,7 +1587,9 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) { int i,k,n; - stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; @@ -1481,7 +1654,7 @@ typedef struct stbi__context *s; stbi__huffman huff_dc[4]; stbi__huffman huff_ac[4]; - stbi_uc dequant[4][64]; + stbi__uint16 dequant[4][64]; stbi__int16 fast_ac[4][1 << FAST_BITS]; // sizes for components, interleaved MCUs @@ -1517,6 +1690,8 @@ typedef struct int succ_high; int succ_low; int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag int rgb; int scan_n, order[4]; @@ -1587,7 +1762,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) // magnitude code followed by receive_extend code int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); int m = 1 << (magbits - 1); - if (k < m) k += (-1 << magbits) + 1; + if (k < m) k += (~0U << magbits) + 1; // if the result is small enough, we can fit it in fast_ac table if (k >= -128 && k <= 127) fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); @@ -1602,6 +1777,7 @@ static void stbi__grow_buffer_unsafe(stbi__jpeg *j) int b = j->nomore ? 0 : stbi__get8(j->s); if (b == 0xff) { int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes if (c != 0) { j->marker = (unsigned char) c; j->nomore = 1; @@ -1726,7 +1902,7 @@ static stbi_uc stbi__jpeg_dezigzag[64+15] = }; // decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) { int diff,dc,k; int t; @@ -2435,7 +2611,7 @@ static stbi_uc stbi__get_marker(stbi__jpeg *j) x = stbi__get8(j->s); if (x != 0xff) return STBI__MARKER_none; while (x == 0xff) - x = stbi__get8(j->s); + x = stbi__get8(j->s); // consume repeated 0xff fill bytes return x; } @@ -2450,7 +2626,7 @@ static void stbi__jpeg_reset(stbi__jpeg *j) j->code_bits = 0; j->code_buffer = 0; j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; j->marker = STBI__MARKER_none; j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; j->eob_run = 0; @@ -2582,7 +2758,7 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z) } } -static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) { int i; for (i=0; i < 64; ++i) @@ -2624,13 +2800,14 @@ static int stbi__process_marker(stbi__jpeg *z, int m) L = stbi__get16be(z->s)-2; while (L > 0) { int q = stbi__get8(z->s); - int p = q >> 4; + int p = q >> 4, sixteen = (p != 0); int t = q & 15,i; - if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); - L -= 65; + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); } return L==0; @@ -2663,12 +2840,50 @@ static int stbi__process_marker(stbi__jpeg *z, int m) } return L==0; } + // check for comment block or APP blocks if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - stbi__skip(z->s, stbi__get16be(z->s)-2); + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); return 1; } - return 0; + + return stbi__err("unknown marker","Corrupt JPEG"); } // after we see SOS @@ -2711,6 +2926,28 @@ static int stbi__process_scan_header(stbi__jpeg *z) return 1; } +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + static int stbi__process_frame_header(stbi__jpeg *z, int scan) { stbi__context *s = z->s; @@ -2720,7 +2957,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires c = stbi__get8(s); - if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); s->img_n = c; for (i=0; i < c; ++i) { z->img_comp[i].data = NULL; @@ -2733,13 +2970,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) for (i=0; i < s->img_n; ++i) { static unsigned char rgb[3] = { 'R', 'G', 'B' }; z->img_comp[i].id = stbi__get8(s); - if (z->img_comp[i].id != i+1) // JFIF requires - if (z->img_comp[i].id != i) { // some version of jpegtran outputs non-JFIF-compliant files! - // somethings output this (see http://fileformats.archiveteam.org/wiki/JPEG#Color_format) - if (z->img_comp[i].id != rgb[i]) - return stbi__err("bad component ID","Corrupt JPEG"); - ++z->rgb; - } + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; q = stbi__get8(s); z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); @@ -2748,7 +2980,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) if (scan != STBI__SCAN_load) return 1; - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); for (i=0; i < s->img_n; ++i) { if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; @@ -2760,6 +2992,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) z->img_v_max = v_max; z->img_mcu_w = h_max * 8; z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; @@ -2771,28 +3004,27 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) // the bogus oversized data from using interleaved MCUs and their // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); - - if (z->img_comp[i].raw_data == NULL) { - for(--i; i >= 0; --i) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].raw_data = NULL; - } - return stbi__err("outofmem", "Out of memory"); - } + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); // align blocks for idct using mmx/sse z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - z->img_comp[i].linebuf = NULL; if (z->progressive) { - z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; - z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; - z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } else { - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; } } @@ -2811,6 +3043,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) { int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 z->marker = STBI__MARKER_none; // initialize cached marker to empty m = stbi__get_marker(z); if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); @@ -2852,12 +3086,15 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) if (x == 255) { j->marker = stbi__get8(j->s); break; - } else if (x != 0) { - return stbi__err("junk before marker", "Corrupt JPEG"); } } // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) stbi__err("bad DNL height", "Corrupt JPEG"); } else { if (!stbi__process_marker(j, m)) return 0; } @@ -3076,38 +3313,9 @@ static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_ return out; } -#ifdef STBI_JPEG_OLD -// this is the same YCbCr-to-RGB calculation that stb_image has used -// historically before the algorithm changes in 1.49 -#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 16) + 32768; // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr*float2fixed(1.40200f); - g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); - b = y_fixed + cb*float2fixed(1.77200f); - r >>= 16; - g >>= 16; - b >>= 16; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#else // this is a reduced-precision calculation of YCbCr-to-RGB introduced // to make sure the code produces the same results in both SIMD and scalar -#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) { int i; @@ -3116,9 +3324,9 @@ static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc int r,g,b; int cr = pcr[i] - 128; int cb = pcb[i] - 128; - r = y_fixed + cr* float2fixed(1.40200f); - g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* float2fixed(1.77200f); + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); r >>= 20; g >>= 20; b >>= 20; @@ -3132,7 +3340,6 @@ static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc out += step; } } -#endif #if defined(STBI_SSE2) || defined(STBI_NEON) static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) @@ -3251,9 +3458,9 @@ static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc cons int r,g,b; int cr = pcr[i] - 128; int cb = pcb[i] - 128; - r = y_fixed + cr* float2fixed(1.40200f); - g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* float2fixed(1.77200f); + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); r >>= 20; g >>= 20; b >>= 20; @@ -3279,18 +3486,14 @@ static void stbi__setup_jpeg(stbi__jpeg *j) #ifdef STBI_SSE2 if (stbi__sse2_available()) { j->idct_block_kernel = stbi__idct_simd; - #ifndef STBI_JPEG_OLD j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - #endif j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; } #endif #ifdef STBI_NEON j->idct_block_kernel = stbi__idct_simd; - #ifndef STBI_JPEG_OLD j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - #endif j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; #endif } @@ -3298,23 +3501,7 @@ static void stbi__setup_jpeg(stbi__jpeg *j) // clean up the temporary component buffers static void stbi__cleanup_jpeg(stbi__jpeg *j) { - int i; - for (i=0; i < j->s->img_n; ++i) { - if (j->img_comp[i].raw_data) { - STBI_FREE(j->img_comp[i].raw_data); - j->img_comp[i].raw_data = NULL; - j->img_comp[i].data = NULL; - } - if (j->img_comp[i].raw_coeff) { - STBI_FREE(j->img_comp[i].raw_coeff); - j->img_comp[i].raw_coeff = 0; - j->img_comp[i].coeff = 0; - } - if (j->img_comp[i].linebuf) { - STBI_FREE(j->img_comp[i].linebuf); - j->img_comp[i].linebuf = NULL; - } - } + stbi__free_jpeg_components(j, j->s->img_n, 0); } typedef struct @@ -3327,9 +3514,16 @@ typedef struct int ypos; // which pre-expansion row we're on } stbi__resample; +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) { - int n, decode_n; + int n, decode_n, is_rgb; z->s->img_n = 0; // make stbi__cleanup_jpeg safe // validate req_comp @@ -3339,9 +3533,11 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n; + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; - if (z->s->img_n == 3 && n < 3) + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) decode_n = 1; else decode_n = z->s->img_n; @@ -3378,7 +3574,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp } // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } // now go ahead and resample @@ -3401,7 +3597,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp if (n >= 3) { stbi_uc *y = coutput[0]; if (z->s->img_n == 3) { - if (z->rgb == 3) { + if (is_rgb) { for (i=0; i < z->s->img_x; ++i) { out[0] = y[i]; out[1] = coutput[1][i]; @@ -3412,6 +3608,28 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp } else { z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } } else for (i=0; i < z->s->img_x; ++i) { out[0] = out[1] = out[2] = y[i]; @@ -3419,25 +3637,54 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp out += n; } } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + } } } stbi__cleanup_jpeg(z); *out_x = z->s->img_x; *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n; // report original components, not output + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output return output; } } -static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); result = load_jpeg_image(j, x,y,comp,req_comp); @@ -3448,11 +3695,12 @@ static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *com static int stbi__jpeg_test(stbi__context *s) { int r; - stbi__jpeg j; - j.s = s; - stbi__setup_jpeg(&j); - r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); stbi__rewind(s); + STBI_FREE(j); return r; } @@ -3464,7 +3712,7 @@ static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) } if (x) *x = j->s->img_x; if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; return 1; } @@ -3521,7 +3769,7 @@ stbi_inline static int stbi__bit_reverse(int v, int bits) return stbi__bitreverse16(v) >> (16-bits); } -static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) { int i,k=0; int code, next_code[16], sizes[17]; @@ -3731,6 +3979,7 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) int hlit = stbi__zreceive(a,5) + 257; int hdist = stbi__zreceive(a,5) + 1; int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; memset(codelength_sizes, 0, sizeof(codelength_sizes)); for (i=0; i < hclen; ++i) { @@ -3740,27 +3989,29 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; n = 0; - while (n < hlit + hdist) { + while (n < ntot) { int c = stbi__zhuffman_decode(a, &z_codelength); if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); if (c < 16) lencodes[n++] = (stbi_uc) c; - else if (c == 16) { - c = stbi__zreceive(a,2)+3; - memset(lencodes+n, lencodes[n-1], c); - n += c; - } else if (c == 17) { - c = stbi__zreceive(a,3)+3; - memset(lencodes+n, 0, c); - n += c; - } else { - STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; - memset(lencodes+n, 0, c); + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) + c = stbi__zreceive(a,3)+3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); n += c; } } - if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; return 1; @@ -3808,9 +4059,24 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) return 1; } -// @TODO: should statically initialize these for optimal thread safety -static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; -static void stbi__init_zdefaults(void) +static const stbi_uc stbi__zdefault_length[288] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: { int i; // use <= to match clearly with spec for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; @@ -3820,6 +4086,7 @@ static void stbi__init_zdefaults(void) for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; } +*/ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) { @@ -3838,7 +4105,6 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) } else { if (type == 1) { // use fixed code lengths - if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { @@ -4026,20 +4292,19 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r int width = x; STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc(x * y * output_bytes); // extra bytes to write off the end into + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into if (!a->out) return stbi__err("outofmem", "Out of memory"); img_width_bytes = (((img_n * x * depth) + 7) >> 3); img_len = (img_width_bytes + 1) * y; - if (s->img_x == x && s->img_y == y) { - if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); - } else { // interlaced: - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); - } + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); for (j=0; j < y; ++j) { stbi_uc *cur = a->out + stride*j; - stbi_uc *prior = cur - stride; + stbi_uc *prior; int filter = *raw++; if (filter > 4) @@ -4051,6 +4316,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r filter_bytes = 1; width = img_width_bytes; } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; @@ -4091,37 +4357,37 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r // this is a little gross, so that we don't switch per-pixel or per-component if (depth < 8 || img_n == out_n) { int nk = (width - 1)*filter_bytes; - #define CASE(f) \ + #define STBI__CASE(f) \ case f: \ for (k=0; k < nk; ++k) switch (filter) { // "none" filter turns into a memcpy here; make that explicit. case STBI__F_none: memcpy(cur, raw, nk); break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; } - #undef CASE + #undef STBI__CASE raw += nk; } else { STBI_ASSERT(img_n+1 == out_n); - #define CASE(f) \ + #define STBI__CASE(f) \ case f: \ for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ for (k=0; k < filter_bytes; ++k) switch (filter) { - CASE(STBI__F_none) cur[k] = raw[k]; break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); break; + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; } - #undef CASE + #undef STBI__CASE // the loop above sets the high byte of the pixels' alpha, but for // 16 bit png files we also need the low byte set. we'll do that here. @@ -4224,13 +4490,15 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) { + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; stbi_uc *final; int p; if (!interlaced) return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); // de-interlacing - final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -4250,8 +4518,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 for (i=0; i < x; ++i) { int out_y = j*yspc[p]+yorig[p]; int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, - a->out + (j*x+i)*out_n, out_n); + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); } } STBI_FREE(a->out); @@ -4319,7 +4587,7 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; stbi_uc *p, *temp_out, *orig = a->out; - p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); if (p == NULL) return stbi__err("outofmem", "Out of memory"); // between here and free(out) below, exitting would leak @@ -4351,26 +4619,6 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__reduce_png(stbi__png *p) -{ - int i; - int img_len = p->s->img_x * p->s->img_y * p->s->img_out_n; - stbi_uc *reduced; - stbi__uint16 *orig = (stbi__uint16*)p->out; - - if (p->depth != 16) return 1; // don't need to do anything if not 16-bit data - - reduced = (stbi_uc *)stbi__malloc(img_len); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); - - for (i = 0; i < img_len; ++i) reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is a decent approx of 16->8 bit scaling - - p->out = reduced; - STBI_FREE(orig); - - return 1; -} - static int stbi__unpremultiply_on_load = 0; static int stbi__de_iphone_flag = 0; @@ -4405,9 +4653,10 @@ static void stbi__de_iphone(stbi__png *z) stbi_uc a = p[3]; stbi_uc t = p[0]; if (a) { - p[0] = p[2] * 255 / a; - p[1] = p[1] * 255 / a; - p[2] = t * 255 / a; + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; } else { p[0] = p[2]; p[2] = t; @@ -4461,7 +4710,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); @@ -4510,7 +4759,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = stbi__get16be(s); // copy the values as-is + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger } @@ -4570,6 +4819,9 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (req_comp >= 3) s->img_out_n = req_comp; if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; return 1; @@ -4597,20 +4849,22 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) } } -static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) { - unsigned char *result=NULL; + void *result=NULL; if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth == 16) { - if (!stbi__reduce_png(p)) { - return result; - } - } + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { - result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); p->s->img_out_n = req_comp; if (result == NULL) return result; } @@ -4625,11 +4879,11 @@ static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req return result; } -static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi__png p; p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp); + return stbi__do_png(&p, x,y,comp,req_comp, ri); } static int stbi__png_test(stbi__context *s) @@ -4742,7 +4996,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->offset = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s); info->mr = info->mg = info->mb = info->ma = 0; - + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz == 12) { s->img_x = stbi__get16le(s); @@ -4817,7 +5071,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } -static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *out; unsigned int mr=0,mg=0,mb=0,ma=0, all_a; @@ -4825,8 +5079,9 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int int psize=0,i,j,width; int flip_vertically, pad, target; stbi__bmp_data info; + STBI_NOTUSED(ri); - info.all_a = 255; + info.all_a = 255; if (stbi__bmp_parse_header(s, &info) == NULL) return NULL; // error code already set @@ -4853,7 +5108,11 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int else target = s->img_n; // if they want monochrome, we'll post-convert - out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); if (info.bpp < 16) { int z=0; @@ -4941,7 +5200,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int stbi__skip(s, pad); } } - + // if alpha channel is all 0s, replace with all 255s if (target == 4 && all_a == 0) for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) @@ -5087,18 +5346,18 @@ errorEnd: } // read 16bit value and convert to 24bit RGB -void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) { - stbi__uint16 px = stbi__get16le(s); + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); stbi__uint16 fiveBitMask = 31; // we have 3 channels with 5bits each int r = (px >> 10) & fiveBitMask; int g = (px >> 5) & fiveBitMask; int b = px & fiveBitMask; // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later - out[0] = (r * 255)/31; - out[1] = (g * 255)/31; - out[2] = (b * 255)/31; + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); // some people claim that the most significant bit might be used for alpha // (possibly if an alpha-bit is set in the "image descriptor byte") @@ -5106,7 +5365,7 @@ void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) // so let's treat all 15 and 16bit TGAs as RGB with no alpha. } -static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { // read in the TGA header stuff int tga_offset = stbi__get8(s); @@ -5128,10 +5387,11 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int unsigned char *tga_data; unsigned char *tga_palette = NULL; int i, j; - unsigned char raw_data[4]; + unsigned char raw_data[4] = {0}; int RLE_count = 0; int RLE_repeating = 0; int read_next_pixel = 1; + STBI_NOTUSED(ri); // do a tiny bit of precessing if ( tga_image_type >= 8 ) @@ -5153,7 +5413,10 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int *y = tga_height; if (comp) *comp = tga_comp; - tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp ); + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); // skip to the data's starting position (offset usually = 0) @@ -5172,7 +5435,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int // any data to skip? (offset usually = 0) stbi__skip(s, tga_palette_start ); // load the palette - tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_comp ); + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); if (!tga_palette) { STBI_FREE(tga_data); return stbi__errpuc("outofmem", "Out of memory"); @@ -5308,14 +5571,53 @@ static int stbi__psd_test(stbi__context *s) return r; } -static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) { - int pixelCount; + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; int channelCount, compression; - int channel, i, count, len; + int channel, i; int bitdepth; int w,h; stbi_uc *out; + STBI_NOTUSED(ri); // Check identifier if (stbi__get32be(s) != 0x38425053) // "8BPS" @@ -5372,8 +5674,18 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int if (compression > 1) return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + // Create the destination image. - out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); pixelCount = w*h; @@ -5405,82 +5717,86 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int *p = (channel == 3 ? 255 : 0); } else { // Read the RLE data. - count = 0; - while (count < pixelCount) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len ^= 0x0FF; - len += 2; - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); } } } } else { // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit value for each pixel in the image. + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. // Read the data by channel. for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out + channel; if (channel >= channelCount) { // Fill this channel with default data. - stbi_uc val = channel == 3 ? 255 : 0; - for (i = 0; i < pixelCount; i++, p += 4) - *p = val; - } else { - // Read the data. - if (bitdepth == 16) { - for (i = 0; i < pixelCount; i++, p += 4) - *p = (stbi_uc) (stbi__get16be(s) >> 8); + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } } } } } + // remove weird white matte from PSD if (channelCount >= 4) { - for (i=0; i < w*h; ++i) { - unsigned char *pixel = out + 4*i; - if (pixel[3] != 0 && pixel[3] != 255) { - // remove weird white matte from PSD - float a = pixel[3] / 255.0f; - float ra = 1.0f / a; - float inv_a = 255.0f * (1 - ra); - pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); - pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); - pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } } } } + // convert to desired output format if (req_comp && req_comp != 4) { - out = stbi__convert_format(out, 4, req_comp, w, h); + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); if (out == NULL) return out; // stbi__convert_format frees input on failure } @@ -5664,10 +5980,13 @@ static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *c return result; } -static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) { stbi_uc *result; - int i, x,y; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; for (i=0; i<92; ++i) stbi__get8(s); @@ -5675,14 +5994,14 @@ static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int re x = stbi__get16be(s); y = stbi__get16be(s); if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); stbi__get32be(s); //skip `ratio' stbi__get16be(s); //skip `fields' stbi__get16be(s); //skip `pad' // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc(x*y*4); + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { @@ -5941,8 +6260,11 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0)) + return stbi__errpuc("too large", "GIF too large"); + prev_out = g->out; - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0); if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); switch ((g->eflags & 0x1C) >> 2) { @@ -6049,11 +6371,12 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i STBI_NOTUSED(req_comp); } -static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *u = 0; stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); memset(g, 0, sizeof(*g)); + STBI_NOTUSED(ri); u = stbi__gif_load_next(s, g, comp, req_comp); if (u == (stbi_uc *) s) u = 0; // end of animated gif marker @@ -6079,20 +6402,24 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) // Radiance RGBE HDR loader // originally by Nicolas Schulz #ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s) +static int stbi__hdr_test_core(stbi__context *s, const char *signature) { - const char *signature = "#?RADIANCE\n"; int i; for (i=0; signature[i]; ++i) if (stbi__get8(s) != signature[i]) - return 0; + return 0; + stbi__rewind(s); return 1; } static int stbi__hdr_test(stbi__context* s) { - int r = stbi__hdr_test_core(s); + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } return r; } @@ -6146,7 +6473,7 @@ static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) } } -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { char buffer[STBI__HDR_BUFLEN]; char *token; @@ -6157,10 +6484,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re int len; unsigned char count, value; int i, j, k, c1,c2, z; - + const char *headerToken; + STBI_NOTUSED(ri); // Check identifier - if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) return stbi__errpf("not HDR", "Corrupt HDR image"); // Parse header @@ -6189,8 +6518,13 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re if (comp) *comp = 3; if (req_comp == 0) req_comp = 3; + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + // Read data - hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); // Load image data // image data is stored as some number of sca @@ -6229,20 +6563,29 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re len <<= 8; len |= stbi__get8(s); if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } for (k = 0; k < 4; ++k) { + int nleft; i = 0; - while (i < width) { + while ((nleft = width - i) > 0) { count = stbi__get8(s); if (count > 128) { // Run value = stbi__get8(s); count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -6251,7 +6594,8 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re for (i=0; i < width; ++i) stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); } - STBI_FREE(scanline); + if (scanline) + STBI_FREE(scanline); } return hdr_data; @@ -6262,6 +6606,11 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) char buffer[STBI__HDR_BUFLEN]; char *token; int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; if (stbi__hdr_test(s) == 0) { stbi__rewind( s ); @@ -6303,14 +6652,14 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) void *p; stbi__bmp_data info; - info.all_a = 255; + info.all_a = 255; p = stbi__bmp_parse_header(s, &info); stbi__rewind( s ); if (p == NULL) return 0; - *x = s->img_x; - *y = s->img_y; - *comp = info.ma ? 4 : 3; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) *comp = info.ma ? 4 : 3; return 1; } #endif @@ -6318,7 +6667,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PSD static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { - int channelCount; + int channelCount, dummy; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; if (stbi__get32be(s) != 0x38425053) { stbi__rewind( s ); return 0; @@ -6351,9 +6703,13 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PIC static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) { - int act_comp=0,num_packets=0,chained; + int act_comp=0,num_packets=0,chained,dummy; stbi__pic_packet packets[10]; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { stbi__rewind(s); return 0; @@ -6429,16 +6785,22 @@ static int stbi__pnm_test(stbi__context *s) return 1; } -static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *out; + STBI_NOTUSED(ri); + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) return 0; + *x = s->img_x; *y = s->img_y; - *comp = s->img_n; + if (comp) *comp = s->img_n; - out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); stbi__getn(s, out, s->img_n * s->img_x * s->img_y); @@ -6487,16 +6849,20 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) { - int maxv; + int maxv, dummy; char c, p, t; - stbi__rewind( s ); + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); // Get identifier p = (char) stbi__get8(s); t = (char) stbi__get8(s); if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); + stbi__rewind(s); return 0; } @@ -6603,6 +6969,19 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int /* revision history: + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.11 (2016-04-02) allocate large structures on the stack remove white matting for transparent PSD @@ -6763,3 +7142,46 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int 0.50 (2006-11-19) first released version */ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ From ef5897b22c48c3e7dbe6188aa2d30007167c28b4 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 23 Jul 2017 19:45:49 -0300 Subject: [PATCH 16/36] Seed love.math.random when the math module is loaded, instead of in love.run. --HG-- branch : minor --- src/modules/math/MathModule.cpp | 7 +++++++ src/scripts/boot.lua | 5 ----- src/scripts/boot.lua.h | 4 ---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/modules/math/MathModule.cpp b/src/modules/math/MathModule.cpp index b153d4452..fbfd51f26 100644 --- a/src/modules/math/MathModule.cpp +++ b/src/modules/math/MathModule.cpp @@ -32,6 +32,9 @@ #include #include +// C +#include + using std::list; using love::Vector2; @@ -359,6 +362,10 @@ Math::Math() { // prevent the runtime from free()-ing this retain(); + + RandomGenerator::Seed seed; + seed.b64 = (uint64) time(nullptr); + rng.setSeed(seed); } Math::~Math() diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index 7b924eeb7..ca8156b5e 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -511,11 +511,6 @@ function love.init() end function love.run() - - if love.math then - love.math.setRandomSeed(os.time()) - end - if love.load then love.load(arg) end -- We don't want the first frame's dt to include time taken by love.load. diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index 3a4498522..daa9d6da3 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -952,10 +952,6 @@ const unsigned char boot_lua[] = 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x75, 0x6e, 0x28, 0x29, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x73, 0x65, 0x74, 0x52, 0x61, 0x6e, - 0x64, 0x6f, 0x6d, 0x53, 0x65, 0x65, 0x64, 0x28, 0x6f, 0x73, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x28, 0x29, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x61, 0x72, 0x67, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, From 2eb9b3bdcdec8485b61b1174dc2afafae7456d66 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 23 Jul 2017 19:56:48 -0300 Subject: [PATCH 17/36] love.timer.step now returns the calculated dt directly. --HG-- branch : minor --- src/modules/timer/Timer.cpp | 4 +++- src/modules/timer/Timer.h | 4 ++-- src/modules/timer/wrap_Timer.cpp | 6 +++--- src/scripts/boot.lua | 3 +-- src/scripts/boot.lua.h | 4 +--- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/modules/timer/Timer.cpp b/src/modules/timer/Timer.cpp index d98244d4a..95b511953 100644 --- a/src/modules/timer/Timer.cpp +++ b/src/modules/timer/Timer.cpp @@ -61,7 +61,7 @@ Timer::Timer() prevFpsUpdate = currTime = getTime(); } -void Timer::step() +double Timer::step() { // Frames rendered frames++; @@ -84,6 +84,8 @@ void Timer::step() prevFpsUpdate = currTime; frames = 0; } + + return dt; } void Timer::sleep(double seconds) const diff --git a/src/modules/timer/Timer.h b/src/modules/timer/Timer.h index ce05e66bd..02cfc332a 100644 --- a/src/modules/timer/Timer.h +++ b/src/modules/timer/Timer.h @@ -42,9 +42,9 @@ public: /** * Measures the time between this call and the previous call, - * and updates internal values accordinly. + * and updates internal values accordingly. **/ - void step(); + double step(); /** * Tries to sleep for the specified amount of time. The precision is diff --git a/src/modules/timer/wrap_Timer.cpp b/src/modules/timer/wrap_Timer.cpp index 71c3b6a1f..cb8cf3bef 100644 --- a/src/modules/timer/wrap_Timer.cpp +++ b/src/modules/timer/wrap_Timer.cpp @@ -30,10 +30,10 @@ namespace timer #define instance() (Module::getInstance(Module::M_TIMER)) -int w_step(lua_State *) +int w_step(lua_State *L) { - instance()->step(); - return 0; + lua_pushnumber(L, instance()->step()); + return 1; } int w_getDelta(lua_State *L) diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index ca8156b5e..c27453f0e 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -535,8 +535,7 @@ function love.run() -- Update dt, as we'll be passing it to update if love.timer then - love.timer.step() - dt = love.timer.getDelta() + dt = love.timer.step() end -- Call update and draw diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index daa9d6da3..21b960d29 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -993,10 +993,8 @@ const unsigned char boot_lua[] = 0x69, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, - 0x28, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x64, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, - 0x2e, 0x67, 0x65, 0x74, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x28, 0x29, 0x0a, + 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x72, 0x61, 0x77, 0x0a, From d578c35f4aa18e62b0b614f4a0bff060b219691f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 25 Jul 2017 08:05:46 -0300 Subject: [PATCH 18/36] Fix love.graphics.circle (thanks xenthral!) --HG-- branch : minor --- src/modules/graphics/Graphics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index d00459147..3908de5b4 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -1136,7 +1136,7 @@ void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b, int po coords[points] = coords[0]; - polygon(mode, coords, (points + 1) * 2); + polygon(mode, coords, points + 1); } void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b) From 9ee11409c549bfe137c14baad8521be7e97c90a9 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Thu, 27 Jul 2017 17:40:56 +0200 Subject: [PATCH 19/36] Add vararg versions of love.audio.play/pause/stop (fixes #1295) The table versions existed already, I guess I forgot about varargs --HG-- branch : minor --- src/modules/audio/wrap_Audio.cpp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index d3c985b50..2503b9f67 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -115,16 +115,34 @@ static std::vector readSourceList(lua_State *L, int n) return sources; } +static std::vector readSourceVararg(lua_State *L, int i) +{ + const int top = lua_gettop(L); + + if (i < 0) + i += top + 1; + + int items = top - i + 1; + std::vector sources(items); + + for (int pos = 0; i <= top; i++, pos++) + sources[pos] = luax_checksource(L, i); + + return sources; +} + int w_play(lua_State *L) { if (lua_istable(L, 1)) - { luax_pushboolean(L, instance()->play(readSourceList(L, 1))); - return 1; + else if (lua_gettop(L) > 1) + luax_pushboolean(L, instance()->play(readSourceVararg(L, 1))); + else + { + Source *s = luax_checksource(L, 1); + luax_pushboolean(L, instance()->play(s)); } - Source *s = luax_checksource(L, 1); - luax_pushboolean(L, instance()->play(s)); return 1; } @@ -134,6 +152,8 @@ int w_stop(lua_State *L) instance()->stop(); else if (lua_istable(L, 1)) instance()->stop(readSourceList(L, 1)); + else if (lua_gettop(L) > 1) + instance()->stop(readSourceVararg(L, 1)); else { Source *s = luax_checksource(L, 1); @@ -158,6 +178,8 @@ int w_pause(lua_State *L) } else if (lua_istable(L, 1)) instance()->pause(readSourceList(L, 1)); + else if (lua_gettop(L) > 1) + instance()->pause(readSourceVararg(L, 1)); else { Source *s = luax_checksource(L, 1); From 6f7fe0611be03d269155904a81b33a185e440681 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Thu, 27 Jul 2017 17:41:27 +0200 Subject: [PATCH 20/36] Fix broken audio when attempting to stop or pause multiple sources, when not all of them were playing --HG-- branch : minor --- src/modules/audio/openal/Source.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index 0bb68c287..6240b0942 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -1041,7 +1041,7 @@ void Source::stop(const std::vector &sources) sourceIds.push_back(source->source); } - alSourceStopv((ALsizei) sources.size(), &sourceIds[0]); + alSourceStopv((ALsizei) sourceIds.size(), &sourceIds[0]); for (auto &_source : sources) { @@ -1068,7 +1068,7 @@ void Source::pause(const std::vector &sources) sourceIds.push_back(source->source); } - alSourcePausev((ALsizei) sources.size(), &sourceIds[0]); + alSourcePausev((ALsizei) sourceIds.size(), &sourceIds[0]); } std::vector Source::pause(Pool *pool) From 94ce5581265d6a217be5d6451ca1d54a5fc0cc51 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 27 Jul 2017 19:54:56 -0300 Subject: [PATCH 21/36] require now looks for both .dylib and .so extensions for C dynamic libraries in macOS, instead of just .so. It also now replaces all occurrences of '??' and '?' in the path with the module filename and module name respectively, rather than just the first occurrence. --HG-- branch : minor --- src/modules/filesystem/physfs/File.cpp | 9 ++- src/modules/filesystem/wrap_Filesystem.cpp | 66 ++++++++++++++-------- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/src/modules/filesystem/physfs/File.cpp b/src/modules/filesystem/physfs/File.cpp index 5d7670b73..0b2f47a34 100644 --- a/src/modules/filesystem/physfs/File.cpp +++ b/src/modules/filesystem/physfs/File.cpp @@ -151,8 +151,6 @@ int64 File::read(void *dst, int64 size) int64 max = (int64)PHYSFS_fileLength(file); size = (size == ALL) ? max : size; size = (size > max) ? max : size; - // Sadly, we'll have to clamp to 32 bits here - size = (size > LOVE_UINT32_MAX) ? LOVE_UINT32_MAX : size; if (size < 0) throw love::Exception("Invalid read size."); @@ -160,6 +158,8 @@ int64 File::read(void *dst, int64 size) #ifdef LOVE_USE_PHYSFS_2_1 int64 read = PHYSFS_readBytes(file, dst, (PHYSFS_uint64) size); #else + // Sadly, we'll have to clamp to 32 bits here + size = (size > LOVE_UINT32_MAX) ? LOVE_UINT32_MAX : size; int64 read = (int64)PHYSFS_read(file, dst, 1, (PHYSFS_uint32) size); #endif @@ -171,9 +171,6 @@ bool File::write(const void *data, int64 size) if (!file || (mode != MODE_WRITE && mode != MODE_APPEND)) throw love::Exception("File is not opened for writing."); - // Another clamp, for the time being. - size = (size > LOVE_UINT32_MAX) ? LOVE_UINT32_MAX : size; - if (size < 0) throw love::Exception("Invalid write size."); @@ -181,6 +178,8 @@ bool File::write(const void *data, int64 size) #ifdef LOVE_USE_PHYSFS_2_1 int64 written = PHYSFS_writeBytes(file, data, (PHYSFS_uint64) size); #else + // Another clamp, for the time being. + size = (size > LOVE_UINT32_MAX) ? LOVE_UINT32_MAX : size; int64 written = (int64) PHYSFS_write(file, data, 1, (PHYSFS_uint32) size); #endif diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index f6d03870c..319bc69e8 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -634,6 +634,22 @@ int w_setCRequirePath(lua_State *L) return 0; } +static void replaceAll(std::string &str, const std::string &substr, const std::string &replacement) +{ + std::vector locations; + size_t pos = 0; + size_t sublen = substr.length(); + + while ((pos = str.find(substr, pos)) != std::string::npos) + { + locations.push_back(pos); + pos += sublen; + } + + for (int i = (int) locations.size() - 1; i >= 0; i--) + str.replace(locations[i], sublen, replacement); +} + int loader(lua_State *L) { std::string modulename = luax_tostring(L, 1); @@ -647,9 +663,7 @@ int loader(lua_State *L) auto *inst = instance(); for (std::string element : inst->getRequirePath()) { - size_t pos = 0; - while ((pos = element.find('?', pos)) != std::string::npos) - element.replace(pos, 1, modulename); + replaceAll(element, "?", modulename); if (inst->isFile(element.c_str())) { @@ -665,14 +679,16 @@ int loader(lua_State *L) return 1; } -inline const char *library_extension() +static const char *library_extensions[] = { #ifdef LOVE_WINDOWS - return ".dll"; + ".dll" +#elif defined(LOVE_MACOSX) || defined(LOVE_IOS) + ".dylib", ".so" #else - return ".so"; + ".so" #endif -} +}; int extloader(lua_State *L) { @@ -694,25 +710,31 @@ int extloader(lua_State *L) void *handle = nullptr; auto *inst = instance(); - for (std::string element : inst->getCRequirePath()) + + for (const std::string &el : inst->getCRequirePath()) { - // Replace ?? with the filename and extension - size_t pos = element.find("??"); - if (pos != std::string::npos) - element.replace(pos, 2, tokenized_name + library_extension()); - // Or ? with just the filename - pos = element.find('?'); - if (pos != std::string::npos) - element.replace(pos, 1, tokenized_name); + for (const char *ext : library_extensions) + { + std::string element = el; - if (!inst->isFile(element.c_str())) - continue; + // Replace ?? with the filename and extension + replaceAll(element, "??", tokenized_name + ext); - // Now resolve the full path, as we're bypassing physfs for the next part. - element = inst->getRealDirectory(element.c_str()) + LOVE_PATH_SEPARATOR + element; + // And ? with just the filename + replaceAll(element, "?", tokenized_name); + + if (!inst->isFile(element.c_str())) + continue; + + // Now resolve the full path, as we're bypassing physfs for the next part. + std::string filepath = inst->getRealDirectory(element.c_str()) + LOVE_PATH_SEPARATOR + element; + + handle = SDL_LoadObject(filepath.c_str()); + // Can fail, for instance if it turned out the source was a zip + if (handle) + break; + } - handle = SDL_LoadObject(element.c_str()); - // Can fail, for instance if it turned out the source was a zip if (handle) break; } From 7fa8fe75721e91bcc6449ed35542b520f89800d6 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Fri, 28 Jul 2017 14:49:35 +0200 Subject: [PATCH 22/36] Fix replacement when using love.joystick.setGamepadMapping (issue #1298) The broken find code would previously cause the (duplicate) key to be appended to the end, now it successfully replaces the previous value --HG-- branch : minor --- src/modules/joystick/sdl/JoystickModule.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/joystick/sdl/JoystickModule.cpp b/src/modules/joystick/sdl/JoystickModule.cpp index ec51ff06c..4ef7587af 100644 --- a/src/modules/joystick/sdl/JoystickModule.cpp +++ b/src/modules/joystick/sdl/JoystickModule.cpp @@ -241,15 +241,15 @@ bool JoystickModule::setGamepadMapping(const std::string &guid, Joystick::Gamepa std::string insertstr = gpinputname + ":" + joyinputstr + ","; // We should replace any existing gamepad bind. - size_t findpos = mapstr.find(std::string(", ") + gpinputname + ":"); + size_t findpos = mapstr.find("," + gpinputname + ":"); if (findpos != std::string::npos) { // The bind string ends at the next comma, or the end of the string. - size_t endpos = mapstr.find_first_of(',', findpos); + size_t endpos = mapstr.find_first_of(',', findpos + 1); if (endpos == std::string::npos) endpos = mapstr.length() - 1; - mapstr.replace(findpos, endpos - findpos + 1, insertstr); + mapstr.replace(findpos + 1, endpos - findpos + 1, insertstr); } else { From b19a8ab67ec8df4984297892f09810e817f26bc8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 28 Jul 2017 18:53:54 -0300 Subject: [PATCH 23/36] RecordingDevice:start has default arguments (resolves issue #1296). --HG-- branch : minor --- src/modules/audio/RecordingDevice.h | 12 +++++------ src/modules/audio/null/RecordingDevice.cpp | 5 ----- src/modules/audio/null/RecordingDevice.h | 1 - src/modules/audio/openal/RecordingDevice.cpp | 16 +++++---------- src/modules/audio/openal/RecordingDevice.h | 13 +++++++----- src/modules/audio/wrap_RecordingDevice.cpp | 21 +++++++++----------- 6 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/modules/audio/RecordingDevice.h b/src/modules/audio/RecordingDevice.h index 17345e7df..e56fb2043 100644 --- a/src/modules/audio/RecordingDevice.h +++ b/src/modules/audio/RecordingDevice.h @@ -37,15 +37,14 @@ public: static love::Type type; + static const int DEFAULT_SAMPLES = 8192; + static const int DEFAULT_SAMPLE_RATE = 8000; + static const int DEFAULT_BIT_DEPTH = 16; + static const int DEFAULT_CHANNELS = 1; + RecordingDevice(); virtual ~RecordingDevice(); - /** - * Begins audio input recording process. using default (previous) parameters. - * @return True if recording started successfully. - **/ - virtual bool start() = 0; - /** * Begins audio input recording process. * @param samples Number of samples to buffer. @@ -96,6 +95,7 @@ public: * @return True if currently recording. **/ virtual bool isRecording() const = 0; + }; //RecordingDevice } //audio diff --git a/src/modules/audio/null/RecordingDevice.cpp b/src/modules/audio/null/RecordingDevice.cpp index 5ca3a7280..f640993c9 100644 --- a/src/modules/audio/null/RecordingDevice.cpp +++ b/src/modules/audio/null/RecordingDevice.cpp @@ -38,11 +38,6 @@ RecordingDevice::~RecordingDevice() { } -bool RecordingDevice::start() -{ - return false; -} - bool RecordingDevice::start(int, int, int, int) { return false; diff --git a/src/modules/audio/null/RecordingDevice.h b/src/modules/audio/null/RecordingDevice.h index 67d92c1f5..85d5f2cd8 100644 --- a/src/modules/audio/null/RecordingDevice.h +++ b/src/modules/audio/null/RecordingDevice.h @@ -36,7 +36,6 @@ class RecordingDevice : public love::audio::RecordingDevice public: RecordingDevice(const char *name); virtual ~RecordingDevice(); - virtual bool start(); virtual bool start(int samples, int sampleRate, int bitDepth, int channels); virtual void stop(); virtual love::sound::SoundData *getData(); diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index b8997f41a..cdc646e4f 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -56,19 +56,8 @@ RecordingDevice::~RecordingDevice() alcCaptureCloseDevice(device); } -bool RecordingDevice::start() -{ - return start(samples, sampleRate, bitDepth, channels); -} - bool RecordingDevice::start(int samples, int sampleRate, int bitDepth, int channels) { - if (isRecording()) - { - alcCaptureStop(device); - alcCaptureCloseDevice(device); - } - ALenum format = Audio::getFormat(bitDepth, channels); if (format == AL_NONE) throw InvalidFormatException(channels, bitDepth); @@ -79,15 +68,20 @@ bool RecordingDevice::start(int samples, int sampleRate, int bitDepth, int chann if (sampleRate <= 0) throw love::Exception("Invalid sample rate."); + if (isRecording()) + stop(); + device = alcCaptureOpenDevice(name.c_str(), sampleRate, format, samples); if (device == nullptr) return false; alcCaptureStart(device); + this->samples = samples; this->sampleRate = sampleRate; this->bitDepth = bitDepth; this->channels = channels; + return true; } diff --git a/src/modules/audio/openal/RecordingDevice.h b/src/modules/audio/openal/RecordingDevice.h index 407e515b6..99a9d2137 100644 --- a/src/modules/audio/openal/RecordingDevice.h +++ b/src/modules/audio/openal/RecordingDevice.h @@ -49,9 +49,9 @@ namespace openal class RecordingDevice : public love::audio::RecordingDevice { public: + RecordingDevice(const char *name); virtual ~RecordingDevice(); - virtual bool start(); virtual bool start(int samples, int sampleRate, int bitDepth, int channels); virtual void stop(); virtual love::sound::SoundData *getData(); @@ -63,12 +63,15 @@ public: virtual bool isRecording() const; private: - int samples = 8192; - int sampleRate = 8000; - int bitDepth = 16; - int channels = 1; + + int samples = 0; + int sampleRate = 0; + int bitDepth = 0; + int channels = 0; + std::string name; ALCdevice *device = nullptr; + }; //RecordingDevice } //openal diff --git a/src/modules/audio/wrap_RecordingDevice.cpp b/src/modules/audio/wrap_RecordingDevice.cpp index e52e1e3b7..dce415cf2 100644 --- a/src/modules/audio/wrap_RecordingDevice.cpp +++ b/src/modules/audio/wrap_RecordingDevice.cpp @@ -35,18 +35,15 @@ RecordingDevice *luax_checkrecordingdevice(lua_State *L, int idx) int w_RecordingDevice_start(lua_State *L) { RecordingDevice *d = luax_checkrecordingdevice(L, 1); - if (lua_gettop(L) > 1) - { - int samples = (int) luaL_checkinteger(L, 2); - int sampleRate = (int) luaL_checkinteger(L, 3); - int bitDepth = (int) luaL_checkinteger(L, 4); - int channels = (int) luaL_checkinteger(L, 5); - luax_catchexcept(L, [&](){ - lua_pushboolean(L, d->start(samples, sampleRate, bitDepth, channels)); - }); - } - else - luax_catchexcept(L, [&](){ lua_pushboolean(L, d->start()); }); + + int samples = (int) luaL_optinteger(L, 2, RecordingDevice::DEFAULT_SAMPLES); + int sampleRate = (int) luaL_optinteger(L, 3, RecordingDevice::DEFAULT_SAMPLE_RATE); + int bitDepth = (int) luaL_optinteger(L, 4, RecordingDevice::DEFAULT_BIT_DEPTH); + int channels = (int) (int) luaL_optinteger(L, 5, RecordingDevice::DEFAULT_CHANNELS); + + luax_catchexcept(L, [&](){ + lua_pushboolean(L, d->start(samples, sampleRate, bitDepth, channels)); + }); return 1; } From 5fc2190ce42e5d9ca90fb313e5f9f8232f271aee Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 28 Jul 2017 19:28:50 -0300 Subject: [PATCH 24/36] Rename love.audio.getEffectsList and Source:getEffectsList to getActiveEffects. They now return an empty table instead of nil when there are no active effects, as well. --HG-- branch : minor --- src/modules/audio/Audio.h | 2 +- src/modules/audio/Source.h | 2 +- src/modules/audio/null/Audio.cpp | 2 +- src/modules/audio/null/Audio.h | 2 +- src/modules/audio/null/Source.cpp | 2 +- src/modules/audio/null/Source.h | 2 +- src/modules/audio/openal/Audio.cpp | 2 +- src/modules/audio/openal/Audio.h | 2 +- src/modules/audio/openal/Source.cpp | 2 +- src/modules/audio/openal/Source.h | 2 +- src/modules/audio/wrap_Audio.cpp | 11 +++++------ src/modules/audio/wrap_Source.cpp | 14 +++++++------- 12 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index 50c31412b..019908ddc 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -236,7 +236,7 @@ public: * @param list List of EFX names to fill. * @return true if effect was present, false otherwise. */ - virtual bool getEffectsList(std::vector &list) = 0; + virtual bool getActiveEffects(std::vector &list) const = 0; /** * Gets maximum number of scene EFX effects. diff --git a/src/modules/audio/Source.h b/src/modules/audio/Source.h index 593e78b91..a0ae66117 100644 --- a/src/modules/audio/Source.h +++ b/src/modules/audio/Source.h @@ -117,7 +117,7 @@ public: virtual bool setEffect(const char *effect, const std::map ¶ms) = 0; virtual bool unsetEffect(const char *effect) = 0; virtual bool getEffect(const char *effect, std::map ¶ms) = 0; - virtual bool getEffectsList(std::vector &list) = 0; + virtual bool getActiveEffects(std::vector &list) const = 0; virtual int getFreeBufferCount() const = 0; virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels) = 0; diff --git a/src/modules/audio/null/Audio.cpp b/src/modules/audio/null/Audio.cpp index 6cf33e963..afa402cb9 100644 --- a/src/modules/audio/null/Audio.cpp +++ b/src/modules/audio/null/Audio.cpp @@ -183,7 +183,7 @@ bool Audio::getEffect(const char *, std::map &) return false; } -bool Audio::getEffectsList(std::vector &list) +bool Audio::getActiveEffects(std::vector &) const { return false; } diff --git a/src/modules/audio/null/Audio.h b/src/modules/audio/null/Audio.h index 34f1f592a..41c4da8f7 100644 --- a/src/modules/audio/null/Audio.h +++ b/src/modules/audio/null/Audio.h @@ -81,7 +81,7 @@ public: bool setEffect(const char *, std::map ¶ms); bool unsetEffect(const char *); bool getEffect(const char *, std::map ¶ms); - bool getEffectsList(std::vector &list); + bool getActiveEffects(std::vector &list) const; int getMaxSceneEffects() const; int getMaxSourceEffects() const; bool isEFXsupported() const; diff --git a/src/modules/audio/null/Source.cpp b/src/modules/audio/null/Source.cpp index 1a1a8d655..ce2a99dc4 100644 --- a/src/modules/audio/null/Source.cpp +++ b/src/modules/audio/null/Source.cpp @@ -274,7 +274,7 @@ bool Source::getEffect(const char *, std::map &) return false; } -bool Source::getEffectsList(std::vector &) +bool Source::getActiveEffects(std::vector &) const { return false; } diff --git a/src/modules/audio/null/Source.h b/src/modules/audio/null/Source.h index b158f909e..20bd464e1 100644 --- a/src/modules/audio/null/Source.h +++ b/src/modules/audio/null/Source.h @@ -90,7 +90,7 @@ public: virtual bool setEffect(const char *effect, const std::map ¶ms); virtual bool unsetEffect(const char *effect); virtual bool getEffect(const char *effect, std::map ¶ms); - virtual bool getEffectsList(std::vector &list); + virtual bool getActiveEffects(std::vector &list) const; private: diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index 803da0a51..08864c311 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -543,7 +543,7 @@ bool Audio::getEffect(const char *name, std::map ¶ return true; } -bool Audio::getEffectsList(std::vector &list) +bool Audio::getActiveEffects(std::vector &list) const { if (effectmap.empty()) return false; diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index 9d9badb07..91299efc5 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -118,7 +118,7 @@ public: bool setEffect(const char *name, std::map ¶ms); bool unsetEffect(const char *name); bool getEffect(const char *name, std::map ¶ms); - bool getEffectsList(std::vector &list); + bool getActiveEffects(std::vector &list) const; int getMaxSceneEffects() const; int getMaxSourceEffects() const; bool isEFXsupported() const; diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index 6240b0942..cd89cec6f 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -1488,7 +1488,7 @@ bool Source::getEffect(const char *name, std::map &par return true; } -bool Source::getEffectsList(std::vector &list) +bool Source::getActiveEffects(std::vector &list) const { if (effectmap.empty()) return false; diff --git a/src/modules/audio/openal/Source.h b/src/modules/audio/openal/Source.h index 5d70c0ad9..ea213587d 100644 --- a/src/modules/audio/openal/Source.h +++ b/src/modules/audio/openal/Source.h @@ -152,7 +152,7 @@ public: virtual bool setEffect(const char *effect, const std::map ¶ms); virtual bool unsetEffect(const char *effect); virtual bool getEffect(const char *effect, std::map ¶ms); - virtual bool getEffectsList(std::vector &list); + virtual bool getActiveEffects(std::vector &list) const; virtual int getFreeBufferCount() const; virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels); diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 2c7d32902..1fda94516 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -488,14 +488,13 @@ int w_getEffect(lua_State *L) return 1; } -int w_getEffectsList(lua_State *L) +int w_getActiveEffects(lua_State *L) { std::vector list; - if (!instance()->getEffectsList(list)) - return 0; + instance()->getActiveEffects(list); - lua_createtable(L, 0, list.size()); - for (unsigned int i = 0; i < list.size(); i++) + lua_createtable(L, 0, (int) list.size()); + for (int i = 0; i < (int) list.size(); i++) { lua_pushnumber(L, i + 1); lua_pushstring(L, list[i].c_str()); @@ -559,7 +558,7 @@ static const luaL_Reg functions[] = { "getRecordingDevices", w_getRecordingDevices }, { "setEffect", w_setEffect }, { "getEffect", w_getEffect }, - { "getEffectsList", w_getEffectsList }, + { "getActiveEffects", w_getActiveEffects }, { "getMaxSceneEffects", w_getMaxSceneEffects }, { "getMaxSourceEffects", w_getMaxSourceEffects }, { "isEffectsSupported", w_isEffectsSupported }, diff --git a/src/modules/audio/wrap_Source.cpp b/src/modules/audio/wrap_Source.cpp index 000ba69ad..6ce02a32d 100644 --- a/src/modules/audio/wrap_Source.cpp +++ b/src/modules/audio/wrap_Source.cpp @@ -493,15 +493,15 @@ int w_Source_getEffect(lua_State *L) return 1; } -int w_Source_getEffectsList(lua_State *L) +int w_Source_getActiveEffects(lua_State *L) { Source *t = luax_checksource(L, 1); - std::vector list; - if (!t->getEffectsList(list)) - return 0; - lua_createtable(L, 0, list.size()); - for (unsigned int i = 0; i < list.size(); i++) + std::vector list; + t->getActiveEffects(list); + + lua_createtable(L, 0, (int) list.size()); + for (int i = 0; i < (int) list.size(); i++) { lua_pushnumber(L, i + 1); lua_pushstring(L, list[i].c_str()); @@ -624,7 +624,7 @@ static const luaL_Reg w_Source_functions[] = { "getFilter", w_Source_getFilter }, { "setEffect", w_Source_setEffect }, { "getEffect", w_Source_getEffect }, - { "getEffectsList", w_Source_getEffectsList }, + { "getActiveEffects", w_Source_getActiveEffects }, { "getFreeBufferCount", w_Source_getFreeBufferCount }, { "queue", w_Source_queue }, From d338f274ffbd2c91ed94bc13abaa6126a684ed59 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 29 Jul 2017 01:25:56 -0300 Subject: [PATCH 25/36] Update naming convention for builtin shader matrices. - ClipSpaceFromLocal replaces TransformProjectionMatrix - ViewSpaceFromLocal replaces TransformMatrix - ClipSpaceFromView replaces ProjectionMatrix - ViewNormalFromLocal replaces NormalMatrix --HG-- branch : minor --- src/modules/graphics/Shader.cpp | 20 ++++++++++---------- src/modules/graphics/Shader.h | 8 ++++---- src/modules/graphics/opengl/Shader.cpp | 8 ++++---- src/modules/graphics/wrap_Graphics.lua | 25 ++++++++++++++++--------- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 0e220d829..dcd50d8e8 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -351,16 +351,16 @@ StringMap Shader::stageNames(Shader StringMap::Entry Shader::builtinNameEntries[] = { - { "MainTex", BUILTIN_TEXTURE_MAIN }, - { "love_VideoYChannel", BUILTIN_TEXTURE_VIDEO_Y }, - { "love_VideoCbChannel", BUILTIN_TEXTURE_VIDEO_CB }, - { "love_VideoCrChannel", BUILTIN_TEXTURE_VIDEO_CR }, - { "TransformMatrix", BUILTIN_MATRIX_TRANSFORM }, - { "ProjectionMatrix", BUILTIN_MATRIX_PROJECTION }, - { "TransformProjectionMatrix", BUILTIN_MATRIX_TRANSFORM_PROJECTION }, - { "NormalMatrix", BUILTIN_MATRIX_NORMAL }, - { "love_PointSize", BUILTIN_POINT_SIZE }, - { "love_ScreenSize", BUILTIN_SCREEN_SIZE }, + { "MainTex", BUILTIN_TEXTURE_MAIN }, + { "love_VideoYChannel", BUILTIN_TEXTURE_VIDEO_Y }, + { "love_VideoCbChannel", BUILTIN_TEXTURE_VIDEO_CB }, + { "love_VideoCrChannel", BUILTIN_TEXTURE_VIDEO_CR }, + { "ViewSpaceFromLocal", BUILTIN_MATRIX_VIEW_FROM_LOCAL }, + { "ClipSpaceFromView", BUILTIN_MATRIX_CLIP_FROM_VIEW }, + { "ClipSpaceFromLocal", BUILTIN_MATRIX_CLIP_FROM_LOCAL }, + { "ViewNormalFromLocal", BUILTIN_MATRIX_VIEW_NORMAL_FROM_LOCAL }, + { "love_PointSize", BUILTIN_POINT_SIZE }, + { "love_ScreenSize", BUILTIN_SCREEN_SIZE }, }; StringMap Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries)); diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index 31ff693b7..c684df384 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -73,10 +73,10 @@ public: BUILTIN_TEXTURE_VIDEO_Y, BUILTIN_TEXTURE_VIDEO_CB, BUILTIN_TEXTURE_VIDEO_CR, - BUILTIN_MATRIX_TRANSFORM, - BUILTIN_MATRIX_PROJECTION, - BUILTIN_MATRIX_TRANSFORM_PROJECTION, - BUILTIN_MATRIX_NORMAL, + BUILTIN_MATRIX_VIEW_FROM_LOCAL, + BUILTIN_MATRIX_CLIP_FROM_VIEW, + BUILTIN_MATRIX_CLIP_FROM_LOCAL, + BUILTIN_MATRIX_VIEW_NORMAL_FROM_LOCAL, BUILTIN_POINT_SIZE, BUILTIN_SCREEN_SIZE, BUILTIN_MAX_ENUM diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 35636c5cd..b465d6e0e 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -855,14 +855,14 @@ void Shader::updateBuiltinUniforms() // Only upload the matrices if they've changed. if (memcmp(curxform.getElements(), lastTransformMatrix.getElements(), sizeof(float) * 16) != 0) { - GLint location = builtinUniforms[BUILTIN_MATRIX_TRANSFORM]; + GLint location = builtinUniforms[BUILTIN_MATRIX_VIEW_FROM_LOCAL]; if (location >= 0) glUniformMatrix4fv(location, 1, GL_FALSE, curxform.getElements()); // Also upload the re-calculated normal matrix, if possible. The normal // matrix is the transpose of the inverse of the rotation portion // (top-left 3x3) of the transform matrix. - location = builtinUniforms[BUILTIN_MATRIX_NORMAL]; + location = builtinUniforms[BUILTIN_MATRIX_VIEW_NORMAL_FROM_LOCAL]; if (location >= 0) { Matrix3 normalmatrix = Matrix3(curxform).transposedInverse(); @@ -875,7 +875,7 @@ void Shader::updateBuiltinUniforms() if (memcmp(curproj.getElements(), lastProjectionMatrix.getElements(), sizeof(float) * 16) != 0) { - GLint location = builtinUniforms[BUILTIN_MATRIX_PROJECTION]; + GLint location = builtinUniforms[BUILTIN_MATRIX_CLIP_FROM_VIEW]; if (location >= 0) glUniformMatrix4fv(location, 1, GL_FALSE, curproj.getElements()); @@ -885,7 +885,7 @@ void Shader::updateBuiltinUniforms() if (tpmatrixneedsupdate) { - GLint location = builtinUniforms[BUILTIN_MATRIX_TRANSFORM_PROJECTION]; + GLint location = builtinUniforms[BUILTIN_MATRIX_CLIP_FROM_LOCAL]; if (location >= 0) { Matrix4 tp_matrix(curproj, curxform); diff --git a/src/modules/graphics/wrap_Graphics.lua b/src/modules/graphics/wrap_Graphics.lua index 529e7768d..386d2e02e 100644 --- a/src/modules/graphics/wrap_Graphics.lua +++ b/src/modules/graphics/wrap_Graphics.lua @@ -72,11 +72,18 @@ GLSL.UNIFORMS = [[ // According to the GLSL ES 1.0 spec, uniform precision must match between stages, // but we can't guarantee that highp is always supported in fragment shaders... // We *really* don't want to use mediump for these in vertex shaders though. -uniform LOVE_HIGHP_OR_MEDIUMP mat4 TransformMatrix; -uniform LOVE_HIGHP_OR_MEDIUMP mat4 ProjectionMatrix; -uniform LOVE_HIGHP_OR_MEDIUMP mat4 TransformProjectionMatrix; -uniform LOVE_HIGHP_OR_MEDIUMP mat3 NormalMatrix; -uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_ScreenSize;]] +uniform LOVE_HIGHP_OR_MEDIUMP mat4 ViewSpaceFromLocal; +uniform LOVE_HIGHP_OR_MEDIUMP mat4 ClipSpaceFromView; +uniform LOVE_HIGHP_OR_MEDIUMP mat4 ClipSpaceFromLocal; +uniform LOVE_HIGHP_OR_MEDIUMP mat3 ViewNormalFromLocal; +uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_ScreenSize; + +// Compatibility +#define TransformMatrix ViewSpaceFromLocal +#define ProjectionMatrix ClipSpaceFromView +#define TransformProjectionMatrix ClipSpaceFromLocal +#define NormalMatrix ViewNormalFromLocal +]] GLSL.FUNCTIONS = [[ #ifdef GL_ES @@ -222,13 +229,13 @@ attribute vec4 ConstantColor; varying vec4 VaryingTexCoord; varying vec4 VaryingColor; -vec4 position(mat4 transform_proj, vec4 vertpos); +vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition); void main() { VaryingTexCoord = VertexTexCoord; VaryingColor = gammaCorrectColor(VertexColor) * ConstantColor; setPointSize(); - love_Position = position(TransformProjectionMatrix, VertexPosition); + love_Position = position(ClipSpaceFromLocal, VertexPosition); }]], } @@ -424,8 +431,8 @@ end local defaultcode = { vertex = [[ -vec4 position(mat4 transform_proj, vec4 vertpos) { - return transform_proj * vertpos; +vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition) { + return clipSpaceFromLocal * localPosition; }]], pixel = [[ vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) { From 68f1ab5f47c8fc7635494f27a552cab299ccebc9 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 29 Jul 2017 02:06:32 -0300 Subject: [PATCH 26/36] Check a couple more vendor strings to determine if an AMD driver is being used. --HG-- branch : minor --- src/modules/graphics/opengl/OpenGL.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 25811d96e..0df714c8b 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -261,7 +261,8 @@ void OpenGL::initVendor() // http://feedback.wildfiregames.com/report/opengl/feature/GL_VENDOR // http://stackoverflow.com/questions/2093594/opengl-extensions-available-on-different-android-devices - if (strstr(vstr, "ATI Technologies")) + // http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_VENDOR + if (strstr(vstr, "ATI Technologies") || strstr(vstr, "AMD") || strstr(vstr, "Advanced Micro Devices")) vendor = VENDOR_AMD; else if (strstr(vstr, "NVIDIA")) vendor = VENDOR_NVIDIA; From bf7f082adb54c8d3ed886d07388985a443850f72 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 29 Jul 2017 11:45:35 -0300 Subject: [PATCH 27/36] Re-added the no-argument variant of RecordingDevice:start(). It uses the samples / sample rate / bit depth / channel count previously set for the RecordingDevice, and errors if it hasn't been set before. --HG-- branch : minor --- src/modules/audio/wrap_RecordingDevice.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/modules/audio/wrap_RecordingDevice.cpp b/src/modules/audio/wrap_RecordingDevice.cpp index dce415cf2..8cd5f4ded 100644 --- a/src/modules/audio/wrap_RecordingDevice.cpp +++ b/src/modules/audio/wrap_RecordingDevice.cpp @@ -36,15 +36,23 @@ int w_RecordingDevice_start(lua_State *L) { RecordingDevice *d = luax_checkrecordingdevice(L, 1); - int samples = (int) luaL_optinteger(L, 2, RecordingDevice::DEFAULT_SAMPLES); - int sampleRate = (int) luaL_optinteger(L, 3, RecordingDevice::DEFAULT_SAMPLE_RATE); - int bitDepth = (int) luaL_optinteger(L, 4, RecordingDevice::DEFAULT_BIT_DEPTH); - int channels = (int) (int) luaL_optinteger(L, 5, RecordingDevice::DEFAULT_CHANNELS); + int samples = d->getSampleCount(); + int samplerate = d->getSampleRate(); + int bitdepth = d->getBitDepth(); + int channels = d->getChannels(); - luax_catchexcept(L, [&](){ - lua_pushboolean(L, d->start(samples, sampleRate, bitDepth, channels)); - }); + if (lua_gettop(L) > 1) + { + samples = (int) luaL_checkinteger(L, 2); + samplerate = (int) luaL_optinteger(L, 3, RecordingDevice::DEFAULT_SAMPLE_RATE); + bitdepth = (int) luaL_optinteger(L, 4, RecordingDevice::DEFAULT_BIT_DEPTH); + channels = (int) (int) luaL_optinteger(L, 5, RecordingDevice::DEFAULT_CHANNELS); + } + bool success = false; + luax_catchexcept(L, [&]() { success = d->start(samples, samplerate, bitdepth, channels); }); + + luax_pushboolean(L, success); return 1; } From 2c80cce00b94849875053af0a6182401f07c4c8c Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 29 Jul 2017 11:52:01 -0300 Subject: [PATCH 28/36] Fix RecordingDevice:start(). --HG-- branch : minor --- src/modules/audio/RecordingDevice.h | 5 +++++ src/modules/audio/null/RecordingDevice.cpp | 11 ++++++++--- src/modules/audio/null/RecordingDevice.h | 1 + src/modules/audio/openal/RecordingDevice.cpp | 11 ++++++----- src/modules/audio/openal/RecordingDevice.h | 1 + src/modules/audio/wrap_RecordingDevice.cpp | 2 +- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/modules/audio/RecordingDevice.h b/src/modules/audio/RecordingDevice.h index e56fb2043..1cf4ba180 100644 --- a/src/modules/audio/RecordingDevice.h +++ b/src/modules/audio/RecordingDevice.h @@ -76,6 +76,11 @@ public: **/ virtual int getSampleCount() const = 0; + /** + * Gets the maximum number of samples that will be buffered, as set by start(). + **/ + virtual int getMaxSamples() const = 0; + /** * @return Sample rate for recording. **/ diff --git a/src/modules/audio/null/RecordingDevice.cpp b/src/modules/audio/null/RecordingDevice.cpp index f640993c9..bee6c0cc3 100644 --- a/src/modules/audio/null/RecordingDevice.cpp +++ b/src/modules/audio/null/RecordingDevice.cpp @@ -57,19 +57,24 @@ int RecordingDevice::getSampleCount() const return 0; } +int RecordingDevice::getMaxSamples() const +{ + return 0; +} + int RecordingDevice::getSampleRate() const { - return 8000; + return 0; } int RecordingDevice::getBitDepth() const { - return 16; + return 0; } int RecordingDevice::getChannels() const { - return 1; + return 0; } const char *RecordingDevice::getName() const diff --git a/src/modules/audio/null/RecordingDevice.h b/src/modules/audio/null/RecordingDevice.h index 85d5f2cd8..c138086b6 100644 --- a/src/modules/audio/null/RecordingDevice.h +++ b/src/modules/audio/null/RecordingDevice.h @@ -40,6 +40,7 @@ public: virtual void stop(); virtual love::sound::SoundData *getData(); virtual const char *getName() const; + virtual int getMaxSamples() const; virtual int getSampleCount() const; virtual int getSampleRate() const; virtual int getBitDepth() const; diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index cdc646e4f..8482ad320 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -49,11 +49,7 @@ RecordingDevice::RecordingDevice(const char *name) RecordingDevice::~RecordingDevice() { - if (!isRecording()) - return; - - alcCaptureStop(device); - alcCaptureCloseDevice(device); + stop(); } bool RecordingDevice::start(int samples, int sampleRate, int bitDepth, int channels) @@ -121,6 +117,11 @@ int RecordingDevice::getSampleCount() const return (int)samples; } +int RecordingDevice::getMaxSamples() const +{ + return samples; +} + int RecordingDevice::getSampleRate() const { return sampleRate; diff --git a/src/modules/audio/openal/RecordingDevice.h b/src/modules/audio/openal/RecordingDevice.h index 99a9d2137..9d6e27e35 100644 --- a/src/modules/audio/openal/RecordingDevice.h +++ b/src/modules/audio/openal/RecordingDevice.h @@ -57,6 +57,7 @@ public: virtual love::sound::SoundData *getData(); virtual const char *getName() const; virtual int getSampleCount() const; + virtual int getMaxSamples() const; virtual int getSampleRate() const; virtual int getBitDepth() const; virtual int getChannels() const; diff --git a/src/modules/audio/wrap_RecordingDevice.cpp b/src/modules/audio/wrap_RecordingDevice.cpp index 8cd5f4ded..fe86cbd16 100644 --- a/src/modules/audio/wrap_RecordingDevice.cpp +++ b/src/modules/audio/wrap_RecordingDevice.cpp @@ -36,7 +36,7 @@ int w_RecordingDevice_start(lua_State *L) { RecordingDevice *d = luax_checkrecordingdevice(L, 1); - int samples = d->getSampleCount(); + int samples = d->getMaxSamples(); int samplerate = d->getSampleRate(); int bitdepth = d->getBitDepth(); int channels = d->getChannels(); From 5ef6730497c54b311b39cc3394e9f73149c6793a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 29 Jul 2017 12:54:53 -0300 Subject: [PATCH 29/36] Added a variant of love.graphics.captureScreenshot which takes a single filename parameter. Resolves issue #1293. --HG-- branch : minor --- src/modules/filesystem/wrap_Filesystem.cpp | 6 +-- src/modules/graphics/wrap_Graphics.cpp | 46 ++++++++++++++++++++++ src/modules/image/ImageData.h | 2 +- src/modules/image/magpie/ImageData.cpp | 25 +++++++++++- src/modules/image/magpie/ImageData.h | 2 +- src/modules/image/wrap_ImageData.cpp | 11 +----- 6 files changed, 76 insertions(+), 16 deletions(-) diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index 319bc69e8..3d5a9542d 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -459,11 +459,9 @@ int w_getDirectoryItems(lua_State *L) int w_lines(lua_State *L) { - File *file; - if (lua_isstring(L, 1)) { - file = instance()->newFile(lua_tostring(L, 1)); + File *file = instance()->newFile(lua_tostring(L, 1)); bool success = false; luax_catchexcept(L, [&](){ success = file->open(File::MODE_READ); }); @@ -488,7 +486,7 @@ int w_load(lua_State *L) { std::string filename = std::string(luaL_checkstring(L, 1)); - Data *data = 0; + Data *data = nullptr; try { data = instance()->read(filename.c_str()); diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 0d8d183a2..a27ee25e1 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -439,8 +439,54 @@ static void screenshotCallback(love::image::ImageData *i, Reference *ref, void * delete ref; } +static int screenshotSaveToFile(lua_State *L) +{ + image::ImageData *id = image::luax_checkimagedata(L, 1); + + const char *filename = luaL_checkstring(L, lua_upvalueindex(1)); + const char *ext = luaL_checkstring(L, lua_upvalueindex(2)); + + image::ImageData::EncodedFormat format; + if (!image::ImageData::getConstant(ext, format)) + return 0; + + try + { + id->encode(format, filename, true); + } + catch (love::Exception &e) + { + printf("Screenshot encoding or saving failed: %s", e.what()); + // Do nothing... + } + + return 0; +} + int w_captureScreenshot(lua_State *L) { + if (lua_isstring(L, 1)) + { + std::string filename = luax_checkstring(L, 1); + std::string ext; + + size_t dotpos = filename.rfind('.'); + + if (dotpos != std::string::npos) + ext = filename.substr(dotpos + 1); + + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); + + image::ImageData::EncodedFormat format; + if (!image::ImageData::getConstant(ext.c_str(), format)) + return luaL_error(L, "Invalid encoded image format: %s", ext.c_str()); + + lua_pushvalue(L, 1); + luax_pushstring(L, ext); + lua_pushcclosure(L, screenshotSaveToFile, 2); + lua_replace(L, 1); + } + luaL_checktype(L, 1, LUA_TFUNCTION); Graphics::ScreenshotInfo info; diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index 4d122fc92..c7f84bd01 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -111,7 +111,7 @@ public: * @param f The file to save the encoded image data to. * @param format The format of the encoded data. **/ - virtual love::filesystem::FileData *encode(EncodedFormat format, const char *filename) = 0; + virtual love::filesystem::FileData *encode(EncodedFormat format, const char *filename, bool writefile) = 0; love::thread::Mutex *getMutex() const; diff --git a/src/modules/image/magpie/ImageData.cpp b/src/modules/image/magpie/ImageData.cpp index 23f32d363..fc2de49b3 100644 --- a/src/modules/image/magpie/ImageData.cpp +++ b/src/modules/image/magpie/ImageData.cpp @@ -22,6 +22,8 @@ #include "ImageData.h" #include "Image.h" +#include "filesystem/Filesystem.h" + namespace love { namespace image @@ -154,7 +156,7 @@ void ImageData::decode(love::filesystem::FileData *data) decodeHandler = decoder; } -love::filesystem::FileData *ImageData::encode(EncodedFormat encodedFormat, const char *filename) +love::filesystem::FileData *ImageData::encode(EncodedFormat encodedFormat, const char *filename, bool writefile) { FormatHandler *encoder = nullptr; FormatHandler::EncodedImage encodedimage; @@ -208,6 +210,27 @@ love::filesystem::FileData *ImageData::encode(EncodedFormat encodedFormat, const memcpy(filedata->getData(), encodedimage.data, encodedimage.size); encoder->free(encodedimage.data); + if (writefile) + { + auto fs = Module::getInstance(Module::M_FILESYSTEM); + + if (fs == nullptr) + { + filedata->release(); + throw love::Exception("love.filesystem must be loaded in order to write an encoded ImageData to a file."); + } + + try + { + fs->write(filename, filedata->getData(), filedata->getSize()); + } + catch (love::Exception &) + { + filedata->release(); + throw; + } + } + return filedata; } diff --git a/src/modules/image/magpie/ImageData.h b/src/modules/image/magpie/ImageData.h index 97bbe59a9..91ec6a362 100644 --- a/src/modules/image/magpie/ImageData.h +++ b/src/modules/image/magpie/ImageData.h @@ -47,7 +47,7 @@ public: // Implements image::ImageData. virtual love::image::ImageData *clone() const; - virtual love::filesystem::FileData *encode(EncodedFormat encodedFormat, const char *filename); + virtual love::filesystem::FileData *encode(EncodedFormat encodedFormat, const char *filename, bool writefile); private: diff --git a/src/modules/image/wrap_ImageData.cpp b/src/modules/image/wrap_ImageData.cpp index 3f411e2fe..dd33d5faf 100644 --- a/src/modules/image/wrap_ImageData.cpp +++ b/src/modules/image/wrap_ImageData.cpp @@ -22,6 +22,7 @@ #include "common/wrap_Data.h" #include "filesystem/File.h" +#include "filesystem/Filesystem.h" // Shove the wrap_ImageData.lua code directly into a raw string literal. static const char imagedata_lua[] = @@ -276,19 +277,11 @@ int w_ImageData_encode(lua_State *L) } love::filesystem::FileData *filedata = nullptr; - luax_catchexcept(L, [&](){ filedata = t->encode(format, filename.c_str()); }); + luax_catchexcept(L, [&](){ filedata = t->encode(format, filename.c_str(), hasfilename); }); luax_pushtype(L, filedata); filedata->release(); - if (hasfilename) - { - luax_getfunction(L, "filesystem", "write"); - lua_pushvalue(L, 3); // filename - lua_pushvalue(L, -3); // FileData - lua_call(L, 2, 0); - } - return 1; } From 5848b8c8b62abe11b157c775db28d133c6e58f2f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 29 Jul 2017 22:53:20 -0300 Subject: [PATCH 30/36] Set non-zero default sampling parameters for RecordingDevices. This allows RecordingDevice:start() with no arguments to work if it's being started for the first time. --HG-- branch : minor --- src/modules/audio/openal/RecordingDevice.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/audio/openal/RecordingDevice.h b/src/modules/audio/openal/RecordingDevice.h index 9d6e27e35..de9f0e5d5 100644 --- a/src/modules/audio/openal/RecordingDevice.h +++ b/src/modules/audio/openal/RecordingDevice.h @@ -65,10 +65,10 @@ public: private: - int samples = 0; - int sampleRate = 0; - int bitDepth = 0; - int channels = 0; + int samples = DEFAULT_SAMPLES; + int sampleRate = DEFAULT_SAMPLE_RATE; + int bitDepth = DEFAULT_BIT_DEPTH; + int channels = DEFAULT_CHANNELS; std::string name; ALCdevice *device = nullptr; From 17cf7bba83db9df3cecf9e8a3cd80cfaf99a59d8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 29 Jul 2017 23:09:45 -0300 Subject: [PATCH 31/36] Cleaned up love.graphics.newShader's wrapper code a bit. --HG-- branch : minor --- src/modules/filesystem/physfs/File.cpp | 2 +- src/modules/filesystem/wrap_Filesystem.cpp | 6 ++--- src/modules/graphics/wrap_Graphics.cpp | 27 +++++++++++----------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/modules/filesystem/physfs/File.cpp b/src/modules/filesystem/physfs/File.cpp index 0b2f47a34..75492af83 100644 --- a/src/modules/filesystem/physfs/File.cpp +++ b/src/modules/filesystem/physfs/File.cpp @@ -190,7 +190,7 @@ bool File::write(const void *data, int64 size) // Manually flush the buffer in BUFFER_LINE mode if we find a newline. if (bufferMode == BUFFER_LINE && bufferSize > size) { - if (memchr(data, '\n', (size_t) size) != NULL) + if (memchr(data, '\n', (size_t) size) != nullptr) flush(); } diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index 3d5a9542d..d44df9943 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -366,7 +366,7 @@ 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; + Data *data = nullptr; try { data = instance()->read(filename, len); @@ -376,7 +376,7 @@ int w_read(lua_State *L) return luax_ioError(L, "%s", e.what()); } - if (data == 0) + if (data == nullptr) return luax_ioError(L, "File could not be read."); // Push the string. @@ -395,7 +395,7 @@ static int w_write_or_append(lua_State *L, File::Mode mode) { const char *filename = luaL_checkstring(L, 1); - const char *input = 0; + const char *input = nullptr; size_t len = 0; if (luax_istype(L, 2, love::Data::type)) diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index a27ee25e1..489a7925f 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -24,6 +24,7 @@ #include "image/ImageData.h" #include "image/Image.h" #include "font/Rasterizer.h" +#include "filesystem/Filesystem.h" #include "filesystem/wrap_Filesystem.h" #include "video/VideoStream.h" #include "image/wrap_Image.h" @@ -1190,34 +1191,32 @@ static int w_getShaderSource(lua_State *L, int startidx, bool gles, Shader::Shad { luax_checkgraphicscreated(L); + auto fs = Module::getInstance(Module::M_FILESYSTEM); + // read any filepath arguments for (int i = startidx; i < startidx + 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); + size_t slen = 0; + const char *str = lua_tolstring(L, i, &slen); - bool isFile = luax_toboolean(L, -1); - lua_pop(L, 1); - - if (isFile) + if (fs != nullptr && fs->isFile(str)) { - luax_getfunction(L, "filesystem", "read"); - lua_pushvalue(L, i); - lua_call(L, 1, 1); + filesystem::FileData *fd = nullptr; + luax_catchexcept(L, [&](){ fd = fs->read(str); }); + + lua_pushlstring(L, (const char *) fd->getData(), fd->getSize()); + fd->release(); + lua_replace(L, i); } else { // Check if the argument looks like a filepath - we want a nicer // error for misspelled filepath arguments. - size_t slen = 0; - const char *str = lua_tolstring(L, i, &slen); - if (slen > 0 && slen < 256 && !strchr(str, '\n')) + if (slen > 0 && slen < 64 && !strchr(str, '\n')) { const char *ext = strchr(str, '.'); if (ext != nullptr && !strchr(ext, ';') && !strchr(ext, ' ')) From 02aa7937a15fee57017a4885db66ae50cab5b0cc Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 29 Jul 2017 23:22:54 -0300 Subject: [PATCH 32/36] Rename love.audio.setMixMode to setMixWithSystem. Fix some copyright notice typos. --HG-- branch : minor --- src/modules/audio/Audio.cpp | 20 ++++++++++++++++++-- src/modules/audio/Audio.h | 8 +++++++- src/modules/audio/Effect.cpp | 2 +- src/modules/audio/Effect.h | 2 +- src/modules/audio/RecordingDevice.h | 2 +- src/modules/audio/null/RecordingDevice.cpp | 2 +- src/modules/audio/null/RecordingDevice.h | 2 +- src/modules/audio/openal/RecordingDevice.cpp | 2 +- src/modules/audio/openal/RecordingDevice.h | 2 +- src/modules/audio/wrap_Audio.cpp | 16 ++++------------ src/scripts/boot.lua | 2 +- src/scripts/boot.lua.h | 4 ++-- 12 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/modules/audio/Audio.cpp b/src/modules/audio/Audio.cpp index b3be99364..eb12a5982 100644 --- a/src/modules/audio/Audio.cpp +++ b/src/modules/audio/Audio.cpp @@ -13,18 +13,34 @@ * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. - * 2. Altered Audio versions must be plainly marked as such, and must not be + * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any Audio distribution. + * 3. This notice may not be removed or altered from any source distribution. **/ #include "Audio.h" +#include "common/config.h" + +#ifdef LOVE_IOS +#include "common/ios.h" +#endif namespace love { namespace audio { +bool Audio::setMixWithSystem(bool mix) +{ +#ifdef LOVE_IOS + love::ios::setAudioMixWithOthers(mix); + return true; +#else + LOVE_UNUSED(mix); + return false; +#endif +} + StringMap::Entry Audio::distanceModelEntries[] = { {"none", Audio::DISTANCE_NONE}, diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index 019908ddc..a20406d5f 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -9,7 +9,7 @@ * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * - * 1. The origin of this software must not be misrepresented = 0; you must not + * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. @@ -256,6 +256,12 @@ public: */ virtual bool isEFXsupported() const = 0; + /** + * Sets whether audio from other apps mixes with love.audio or is muted, + * on supported platforms. + **/ + bool setMixWithSystem(bool mix); + private: static StringMap::Entry distanceModelEntries[]; diff --git a/src/modules/audio/Effect.cpp b/src/modules/audio/Effect.cpp index 93214e074..420fc19a8 100644 --- a/src/modules/audio/Effect.cpp +++ b/src/modules/audio/Effect.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2016 LOVE Development Team + * Copyright (c) 2006-2017 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/Effect.h b/src/modules/audio/Effect.h index 6204d319f..4bc3f5e3a 100644 --- a/src/modules/audio/Effect.h +++ b/src/modules/audio/Effect.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2016 LOVE Development Team + * Copyright (c) 2006-2017 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/RecordingDevice.h b/src/modules/audio/RecordingDevice.h index 1cf4ba180..0158c4363 100644 --- a/src/modules/audio/RecordingDevice.h +++ b/src/modules/audio/RecordingDevice.h @@ -9,7 +9,7 @@ * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * - * 1. The origin of this software must not be misrepresented = 0; you must not + * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. diff --git a/src/modules/audio/null/RecordingDevice.cpp b/src/modules/audio/null/RecordingDevice.cpp index bee6c0cc3..7d86df957 100644 --- a/src/modules/audio/null/RecordingDevice.cpp +++ b/src/modules/audio/null/RecordingDevice.cpp @@ -9,7 +9,7 @@ * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * - * 1. The origin of this software must not be misrepresented = 0; you must not + * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. diff --git a/src/modules/audio/null/RecordingDevice.h b/src/modules/audio/null/RecordingDevice.h index c138086b6..9ed7759bb 100644 --- a/src/modules/audio/null/RecordingDevice.h +++ b/src/modules/audio/null/RecordingDevice.h @@ -9,7 +9,7 @@ * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * - * 1. The origin of this software must not be misrepresented = 0; you must not + * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index 8482ad320..b68754f6b 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -9,7 +9,7 @@ * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * - * 1. The origin of this software must not be misrepresented = 0; you must not + * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. diff --git a/src/modules/audio/openal/RecordingDevice.h b/src/modules/audio/openal/RecordingDevice.h index de9f0e5d5..427fd21ab 100644 --- a/src/modules/audio/openal/RecordingDevice.h +++ b/src/modules/audio/openal/RecordingDevice.h @@ -9,7 +9,7 @@ * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * - * 1. The origin of this software must not be misrepresented = 0; you must not + * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 1fda94516..395b179b1 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -25,9 +25,6 @@ #include "null/Audio.h" #include "common/runtime.h" -#ifdef LOVE_IOS -#include "common/ios.h" -#endif // C++ #include @@ -521,15 +518,10 @@ int w_isEffectsSupported(lua_State *L) return 1; } -#ifdef LOVE_IOS -int w_setMixMode(lua_State *L) +int w_setMixWithSystem(lua_State *L) { - love::ios::setAudioMixWithOthers(lua_toboolean(L, 1)); -#else -int w_setMixMode(lua_State *) -{ -#endif - return 0; + luax_pushboolean(L, instance()->setMixWithSystem(luax_toboolean(L, 1))); + return 1; } // List of functions to wrap. @@ -562,7 +554,7 @@ static const luaL_Reg functions[] = { "getMaxSceneEffects", w_getMaxSceneEffects }, { "getMaxSourceEffects", w_getMaxSourceEffects }, { "isEffectsSupported", w_isEffectsSupported }, - { "setMixMode", w_setMixMode }, + { "setMixWithSystem", w_setMixWithSystem }, { 0, 0 } }; diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index 8025cb129..f6b16cf22 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -496,7 +496,7 @@ function love.init() end if love.audio then - love.audio.setMixMode(c.audio.mixwithsystem) + love.audio.setMixWithSystem(c.audio.mixwithsystem) end -- Our first timestep, because window creation can take some time diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index b474b2156..104879a3b 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -921,8 +921,8 @@ const unsigned char boot_lua[] = 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x69, - 0x78, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x77, - 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x29, 0x0a, + 0x78, 0x57, 0x69, 0x74, 0x68, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x28, 0x63, 0x2e, 0x61, 0x75, 0x64, 0x69, + 0x6f, 0x2e, 0x6d, 0x69, 0x78, 0x77, 0x69, 0x74, 0x68, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x4f, 0x75, 0x72, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x70, 0x2c, 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x77, 0x69, 0x6e, 0x64, From 217552b5ff40db88ac563a44d545b7cd7f06f4d2 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 1 Aug 2017 18:35:35 -0300 Subject: [PATCH 33/36] love.graphics.newShader can accept File and FileData arguments (resolves issue #1308). --HG-- branch : minor --- src/modules/graphics/wrap_Graphics.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 489a7925f..5ea26ee5b 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -1189,22 +1189,36 @@ int w_newCanvas(lua_State *L) static int w_getShaderSource(lua_State *L, int startidx, bool gles, Shader::ShaderSource &source) { + using namespace love::filesystem; + luax_checkgraphicscreated(L); - auto fs = Module::getInstance(Module::M_FILESYSTEM); + auto fs = Module::getInstance(Module::M_FILESYSTEM); // read any filepath arguments for (int i = startidx; i < startidx + 2; i++) { if (!lua_isstring(L, i)) + { + if (luax_cangetfiledata(L, i)) + { + FileData *fd = luax_getfiledata(L, i); + + lua_pushlstring(L, (const char *) fd->getData(), fd->getSize()); + fd->release(); + + lua_replace(L, i); + } + continue; + } size_t slen = 0; const char *str = lua_tolstring(L, i, &slen); if (fs != nullptr && fs->isFile(str)) { - filesystem::FileData *fd = nullptr; + FileData *fd = nullptr; luax_catchexcept(L, [&](){ fd = fs->read(str); }); lua_pushlstring(L, (const char *) fd->getData(), fd->getSize()); From 84d5d8b636f1619944c502c1a9f19b5d983d7f11 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 1 Aug 2017 23:22:24 -0300 Subject: [PATCH 34/36] Move decoder-agnostic love.image code out of the magpie backend folder. --HG-- branch : minor --- CMakeLists.txt | 12 +- .../xcode/liblove.xcodeproj/project.pbxproj | 68 ++--- src/modules/graphics/wrap_Graphics.cpp | 4 +- .../{magpie => }/CompressedFormatHandler.h | 24 +- src/modules/image/CompressedImageData.cpp | 96 ++++--- src/modules/image/CompressedImageData.h | 59 +---- ...pressedImageData.h => CompressedSlice.cpp} | 66 +++-- src/modules/image/CompressedSlice.h | 72 ++++++ .../image/{magpie => }/FormatHandler.cpp | 7 +- .../image/{magpie => }/FormatHandler.h | 23 +- src/modules/image/Image.cpp | 84 ++++++ src/modules/image/Image.h | 27 +- src/modules/image/ImageData.cpp | 212 +++++++++++++++- src/modules/image/ImageData.h | 50 ++-- src/modules/image/magpie/ASTCHandler.cpp | 6 +- src/modules/image/magpie/ASTCHandler.h | 11 +- .../image/magpie/CompressedImageData.cpp | 85 ------- src/modules/image/magpie/EXRHandler.cpp | 5 +- src/modules/image/magpie/EXRHandler.h | 11 +- src/modules/image/magpie/Image.cpp | 118 --------- src/modules/image/magpie/Image.h | 78 ------ src/modules/image/magpie/ImageData.cpp | 239 ------------------ src/modules/image/magpie/ImageData.h | 70 ----- src/modules/image/magpie/KTXHandler.cpp | 8 +- src/modules/image/magpie/KTXHandler.h | 11 +- src/modules/image/magpie/PKMHandler.cpp | 8 +- src/modules/image/magpie/PKMHandler.h | 11 +- src/modules/image/magpie/PNGHandler.cpp | 6 +- src/modules/image/magpie/PNGHandler.h | 11 +- src/modules/image/magpie/PVRHandler.cpp | 8 +- src/modules/image/magpie/PVRHandler.h | 11 +- src/modules/image/magpie/STBHandler.cpp | 7 +- src/modules/image/magpie/STBHandler.h | 19 +- src/modules/image/magpie/ddsHandler.cpp | 8 +- src/modules/image/magpie/ddsHandler.h | 11 +- src/modules/image/wrap_Image.cpp | 4 +- src/modules/image/wrap_ImageData.cpp | 2 +- 37 files changed, 631 insertions(+), 921 deletions(-) rename src/modules/image/{magpie => }/CompressedFormatHandler.h (78%) rename src/modules/image/{magpie/CompressedImageData.h => CompressedSlice.cpp} (52%) create mode 100644 src/modules/image/CompressedSlice.h rename src/modules/image/{magpie => }/FormatHandler.cpp (89%) rename src/modules/image/{magpie => }/FormatHandler.h (87%) delete mode 100644 src/modules/image/magpie/CompressedImageData.cpp delete mode 100644 src/modules/image/magpie/Image.cpp delete mode 100644 src/modules/image/magpie/Image.h delete mode 100644 src/modules/image/magpie/ImageData.cpp delete mode 100644 src/modules/image/magpie/ImageData.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d32c13b28..9ad8b14b1 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -575,8 +575,13 @@ source_group("modules\\graphics\\opengl" FILES ${LOVE_SRC_MODULE_GRAPHICS_OPENGL # set(LOVE_SRC_MODULE_IMAGE_ROOT + src/modules/image/CompressedFormatHandler.h src/modules/image/CompressedImageData.cpp src/modules/image/CompressedImageData.h + src/modules/image/CompressedSlice.cpp + src/modules/image/CompressedSlice.h + src/modules/image/FormatHandler.cpp + src/modules/image/FormatHandler.h src/modules/image/Image.cpp src/modules/image/Image.h src/modules/image/ImageData.cpp @@ -594,17 +599,10 @@ set(LOVE_SRC_MODULE_IMAGE_ROOT set(LOVE_SRC_MODULE_IMAGE_MAGPIE src/modules/image/magpie/ASTCHandler.cpp src/modules/image/magpie/ASTCHandler.h - src/modules/image/magpie/CompressedImageData.cpp - src/modules/image/magpie/CompressedImageData.h - src/modules/image/magpie/CompressedFormatHandler.h src/modules/image/magpie/ddsHandler.cpp src/modules/image/magpie/ddsHandler.h src/modules/image/magpie/EXRHandler.cpp src/modules/image/magpie/EXRHandler.h - src/modules/image/magpie/FormatHandler.cpp - src/modules/image/magpie/FormatHandler.h - src/modules/image/magpie/Image.cpp - src/modules/image/magpie/Image.h src/modules/image/magpie/ImageData.cpp src/modules/image/magpie/ImageData.h src/modules/image/magpie/KTXHandler.cpp diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 772b2ab21..908b11b0f 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -469,22 +469,9 @@ FA0B7D861A95902C000E1D17 /* ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BC61A95902C000E1D17 /* ImageData.cpp */; }; FA0B7D871A95902C000E1D17 /* ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BC61A95902C000E1D17 /* ImageData.cpp */; }; FA0B7D881A95902C000E1D17 /* ImageData.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BC71A95902C000E1D17 /* ImageData.h */; }; - FA0B7D891A95902C000E1D17 /* CompressedImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BC91A95902C000E1D17 /* CompressedImageData.cpp */; }; - FA0B7D8A1A95902C000E1D17 /* CompressedImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BC91A95902C000E1D17 /* CompressedImageData.cpp */; }; - FA0B7D8B1A95902C000E1D17 /* CompressedImageData.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BCA1A95902C000E1D17 /* CompressedImageData.h */; }; - FA0B7D8C1A95902C000E1D17 /* CompressedFormatHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BCB1A95902C000E1D17 /* CompressedFormatHandler.h */; }; FA0B7D8D1A95902C000E1D17 /* ddsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BCC1A95902C000E1D17 /* ddsHandler.cpp */; }; FA0B7D8E1A95902C000E1D17 /* ddsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BCC1A95902C000E1D17 /* ddsHandler.cpp */; }; FA0B7D8F1A95902C000E1D17 /* ddsHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BCD1A95902C000E1D17 /* ddsHandler.h */; }; - FA0B7D901A95902C000E1D17 /* FormatHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BCE1A95902C000E1D17 /* FormatHandler.cpp */; }; - FA0B7D911A95902C000E1D17 /* FormatHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BCE1A95902C000E1D17 /* FormatHandler.cpp */; }; - FA0B7D921A95902C000E1D17 /* FormatHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BCF1A95902C000E1D17 /* FormatHandler.h */; }; - FA0B7D931A95902C000E1D17 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BD01A95902C000E1D17 /* Image.cpp */; }; - FA0B7D941A95902C000E1D17 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BD01A95902C000E1D17 /* Image.cpp */; }; - FA0B7D951A95902C000E1D17 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BD11A95902C000E1D17 /* Image.h */; }; - FA0B7D961A95902C000E1D17 /* ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BD21A95902C000E1D17 /* ImageData.cpp */; }; - FA0B7D971A95902C000E1D17 /* ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BD21A95902C000E1D17 /* ImageData.cpp */; }; - FA0B7D981A95902C000E1D17 /* ImageData.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BD31A95902C000E1D17 /* ImageData.h */; }; FA0B7D9F1A95902C000E1D17 /* KTXHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BD81A95902C000E1D17 /* KTXHandler.cpp */; }; FA0B7DA01A95902C000E1D17 /* KTXHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BD81A95902C000E1D17 /* KTXHandler.cpp */; }; FA0B7DA11A95902C000E1D17 /* KTXHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BD91A95902C000E1D17 /* KTXHandler.h */; }; @@ -948,6 +935,9 @@ FA91591E1CF1ED7500A7053F /* halffloat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA91591C1CF1ED7500A7053F /* halffloat.cpp */; }; FA91591F1CF1ED7500A7053F /* halffloat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA91591C1CF1ED7500A7053F /* halffloat.cpp */; }; FA9159201CF1ED7500A7053F /* halffloat.h in Headers */ = {isa = PBXBuildFile; fileRef = FA91591D1CF1ED7500A7053F /* halffloat.h */; }; + FA93C4521F315B960087CCD4 /* CompressedFormatHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA93C44F1F315B960087CCD4 /* CompressedFormatHandler.h */; }; + FA93C4531F315B960087CCD4 /* FormatHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA93C4501F315B960087CCD4 /* FormatHandler.h */; }; + FA93C4541F315B960087CCD4 /* FormatHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA93C4511F315B960087CCD4 /* FormatHandler.cpp */; }; FA9B4A0816E1578300074F42 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA9B4A0716E1578300074F42 /* SDL2.framework */; }; FA9D8DD11DEB56C3002CD881 /* pixelformat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA9D8DCF1DEB56C3002CD881 /* pixelformat.cpp */; }; FA9D8DD21DEB56C3002CD881 /* pixelformat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA9D8DCF1DEB56C3002CD881 /* pixelformat.cpp */; }; @@ -1036,6 +1026,10 @@ FADF543D1E3DAFF700012CC0 /* wrap_Graphics.h in Headers */ = {isa = PBXBuildFile; fileRef = FADF543A1E3DAFF700012CC0 /* wrap_Graphics.h */; }; FAE272521C05A15B00A67640 /* ParticleSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE272501C05A15B00A67640 /* ParticleSystem.cpp */; }; FAE272531C05A15B00A67640 /* ParticleSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE272511C05A15B00A67640 /* ParticleSystem.h */; }; + FAECA1B21F3164700095D008 /* CompressedSlice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAECA1B01F3164700095D008 /* CompressedSlice.cpp */; }; + FAECA1B31F3164700095D008 /* CompressedSlice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAECA1B01F3164700095D008 /* CompressedSlice.cpp */; }; + FAECA1B41F3164700095D008 /* CompressedSlice.h in Headers */ = {isa = PBXBuildFile; fileRef = FAECA1B11F3164700095D008 /* CompressedSlice.h */; }; + FAECA1B51F31648A0095D008 /* FormatHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA93C4511F315B960087CCD4 /* FormatHandler.cpp */; }; FAF140531E20934C00F898D2 /* CodeGen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FC21E20934C00F898D2 /* CodeGen.cpp */; }; FAF140541E20934C00F898D2 /* CodeGen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FC21E20934C00F898D2 /* CodeGen.cpp */; }; FAF140551E20934C00F898D2 /* Link.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FC31E20934C00F898D2 /* Link.cpp */; }; @@ -1482,17 +1476,8 @@ FA0B7BC51A95902C000E1D17 /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = ""; }; FA0B7BC61A95902C000E1D17 /* ImageData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageData.cpp; sourceTree = ""; }; FA0B7BC71A95902C000E1D17 /* ImageData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageData.h; sourceTree = ""; }; - FA0B7BC91A95902C000E1D17 /* CompressedImageData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompressedImageData.cpp; sourceTree = ""; }; - FA0B7BCA1A95902C000E1D17 /* CompressedImageData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompressedImageData.h; sourceTree = ""; }; - FA0B7BCB1A95902C000E1D17 /* CompressedFormatHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompressedFormatHandler.h; sourceTree = ""; }; FA0B7BCC1A95902C000E1D17 /* ddsHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ddsHandler.cpp; sourceTree = ""; }; FA0B7BCD1A95902C000E1D17 /* ddsHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsHandler.h; sourceTree = ""; }; - FA0B7BCE1A95902C000E1D17 /* FormatHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormatHandler.cpp; sourceTree = ""; }; - FA0B7BCF1A95902C000E1D17 /* FormatHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormatHandler.h; sourceTree = ""; }; - FA0B7BD01A95902C000E1D17 /* Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = ""; }; - FA0B7BD11A95902C000E1D17 /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = ""; }; - FA0B7BD21A95902C000E1D17 /* ImageData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageData.cpp; sourceTree = ""; }; - FA0B7BD31A95902C000E1D17 /* ImageData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageData.h; sourceTree = ""; }; FA0B7BD81A95902C000E1D17 /* KTXHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KTXHandler.cpp; sourceTree = ""; }; FA0B7BD91A95902C000E1D17 /* KTXHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KTXHandler.h; sourceTree = ""; }; FA0B7BDA1A95902C000E1D17 /* PKMHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PKMHandler.cpp; sourceTree = ""; }; @@ -1808,6 +1793,9 @@ FA8951A11AA2EDF300EC385A /* wrap_Event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Event.h; sourceTree = ""; }; FA91591C1CF1ED7500A7053F /* halffloat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = halffloat.cpp; sourceTree = ""; }; FA91591D1CF1ED7500A7053F /* halffloat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = halffloat.h; sourceTree = ""; }; + FA93C44F1F315B960087CCD4 /* CompressedFormatHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompressedFormatHandler.h; sourceTree = ""; }; + FA93C4501F315B960087CCD4 /* FormatHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormatHandler.h; sourceTree = ""; }; + FA93C4511F315B960087CCD4 /* FormatHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormatHandler.cpp; sourceTree = ""; }; FA9B4A0716E1578300074F42 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = ""; }; FA9D8DCF1DEB56C3002CD881 /* pixelformat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pixelformat.cpp; sourceTree = ""; }; FA9D8DD01DEB56C3002CD881 /* pixelformat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pixelformat.h; sourceTree = ""; }; @@ -1870,6 +1858,8 @@ FADF543A1E3DAFF700012CC0 /* wrap_Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Graphics.h; sourceTree = ""; }; FAE272501C05A15B00A67640 /* ParticleSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParticleSystem.cpp; sourceTree = ""; }; FAE272511C05A15B00A67640 /* ParticleSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParticleSystem.h; sourceTree = ""; }; + FAECA1B01F3164700095D008 /* CompressedSlice.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CompressedSlice.cpp; sourceTree = ""; }; + FAECA1B11F3164700095D008 /* CompressedSlice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CompressedSlice.h; sourceTree = ""; }; FAF13FC21E20934C00F898D2 /* CodeGen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGen.cpp; sourceTree = ""; }; FAF13FC31E20934C00F898D2 /* Link.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Link.cpp; sourceTree = ""; }; FAF13FC51E20934C00F898D2 /* arrays.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arrays.h; sourceTree = ""; }; @@ -2760,8 +2750,13 @@ FA0B7BC21A95902C000E1D17 /* image */ = { isa = PBXGroup; children = ( + FA93C44F1F315B960087CCD4 /* CompressedFormatHandler.h */, FA0B7BC31A95902C000E1D17 /* CompressedImageData.cpp */, FA0B7BC41A95902C000E1D17 /* CompressedImageData.h */, + FAECA1B01F3164700095D008 /* CompressedSlice.cpp */, + FAECA1B11F3164700095D008 /* CompressedSlice.h */, + FA93C4511F315B960087CCD4 /* FormatHandler.cpp */, + FA93C4501F315B960087CCD4 /* FormatHandler.h */, FA9D8DDF1DEF843D002CD881 /* Image.cpp */, FA0B7BC51A95902C000E1D17 /* Image.h */, FA0B7BC61A95902C000E1D17 /* ImageData.cpp */, @@ -2785,19 +2780,10 @@ children = ( FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */, FA41A3C71C0A1F950084430C /* ASTCHandler.h */, - FA0B7BCB1A95902C000E1D17 /* CompressedFormatHandler.h */, - FA0B7BC91A95902C000E1D17 /* CompressedImageData.cpp */, - FA0B7BCA1A95902C000E1D17 /* CompressedImageData.h */, FA0B7BCC1A95902C000E1D17 /* ddsHandler.cpp */, FA0B7BCD1A95902C000E1D17 /* ddsHandler.h */, FA1557C11CE90BD200AFF582 /* EXRHandler.cpp */, FA1557C21CE90BD200AFF582 /* EXRHandler.h */, - FA0B7BCE1A95902C000E1D17 /* FormatHandler.cpp */, - FA0B7BCF1A95902C000E1D17 /* FormatHandler.h */, - FA0B7BD01A95902C000E1D17 /* Image.cpp */, - FA0B7BD11A95902C000E1D17 /* Image.h */, - FA0B7BD21A95902C000E1D17 /* ImageData.cpp */, - FA0B7BD31A95902C000E1D17 /* ImageData.h */, FA0B7BD81A95902C000E1D17 /* KTXHandler.cpp */, FA0B7BD91A95902C000E1D17 /* KTXHandler.h */, FA0B7BDA1A95902C000E1D17 /* PKMHandler.cpp */, @@ -3550,7 +3536,6 @@ FA76344C1E28722A0066EF9E /* StreamBuffer.h in Headers */, 217DFBF31D9F6D490055D849 /* mime.h in Headers */, FA0B7B361A958EA3000E1D17 /* wuff_convert.h in Headers */, - FA0B7D981A95902C000E1D17 /* ImageData.h in Headers */, FA0B7CDE1A95902C000E1D17 /* Source.h in Headers */, FA0B7E141A95902C000E1D17 /* GearJoint.h in Headers */, FA0B7D051A95902C000E1D17 /* wrap_DroppedFile.h in Headers */, @@ -3612,6 +3597,7 @@ FA0B7CD21A95902C000E1D17 /* Audio.h in Headers */, FA0B79421A958E3B000E1D17 /* utf8.h in Headers */, FA0B7D171A95902C000E1D17 /* Font.h in Headers */, + FAECA1B41F3164700095D008 /* CompressedSlice.h in Headers */, FA0B7A6D1A958EA3000E1D17 /* b2World.h in Headers */, FA0B7EAE1A95902C000E1D17 /* wrap_SoundData.h in Headers */, FA0B7CFF1A95902C000E1D17 /* File.h in Headers */, @@ -3661,6 +3647,7 @@ FA0B7E351A95902C000E1D17 /* WeldJoint.h in Headers */, FA0B7E2F1A95902C000E1D17 /* RopeJoint.h in Headers */, FA0B7D141A95902C000E1D17 /* Font.h in Headers */, + FA93C4521F315B960087CCD4 /* CompressedFormatHandler.h in Headers */, FA0B7D411A95902C000E1D17 /* Mesh.h in Headers */, FA0B7E591A95902C000E1D17 /* wrap_Joint.h in Headers */, FA0B79351A958E3B000E1D17 /* macosx.h in Headers */, @@ -3720,6 +3707,7 @@ FA0B7ECD1A95902C000E1D17 /* wrap_Channel.h in Headers */, FAF140AF1E20934C00F898D2 /* osinclude.h in Headers */, FA0B7A431A958EA3000E1D17 /* b2CircleShape.h in Headers */, + FA93C4531F315B960087CCD4 /* FormatHandler.h in Headers */, FA0B7CD81A95902C000E1D17 /* Audio.h in Headers */, FA0B7CF61A95902C000E1D17 /* File.h in Headers */, FA0B7E961A95902C000E1D17 /* Mpg123Decoder.h in Headers */, @@ -3728,7 +3716,6 @@ FA0B7DD51A95902C000E1D17 /* BezierCurve.h in Headers */, FA0B79271A958E3B000E1D17 /* int.h in Headers */, FA27B3A21B498151008A9DCE /* VideoStream.h in Headers */, - FA0B7D8C1A95902C000E1D17 /* CompressedFormatHandler.h in Headers */, FA0B7E531A95902C000E1D17 /* wrap_FrictionJoint.h in Headers */, FA0B7EB71A95902C000E1D17 /* wrap_System.h in Headers */, FA27B3A91B498151008A9DCE /* Video.h in Headers */, @@ -3738,7 +3725,6 @@ FAB17BF21ABFB37500F9BA27 /* wrap_CompressedData.h in Headers */, FA0B7E801A95902C000E1D17 /* Joint.h in Headers */, FA0B7D2F1A95902C000E1D17 /* Drawable.h in Headers */, - FA0B7D951A95902C000E1D17 /* Image.h in Headers */, 217DFBE21D9F6D490055D849 /* ftp.lua.h in Headers */, FA0B7EC41A95902C000E1D17 /* Thread.h in Headers */, FA0B7DFF1A95902C000E1D17 /* ChainShape.h in Headers */, @@ -3794,7 +3780,6 @@ FA0B7CF91A95902C000E1D17 /* FileData.h in Headers */, FA0B7DA71A95902C000E1D17 /* PNGHandler.h in Headers */, FA0B7AC41A958EA3000E1D17 /* protocol.h in Headers */, - FA0B7D8B1A95902C000E1D17 /* CompressedImageData.h in Headers */, FAF140601E20934C00F898D2 /* revision.h in Headers */, FAF140A21E20934C00F898D2 /* RemoveTree.h in Headers */, FA0B7A8E1A958EA3000E1D17 /* b2DistanceJoint.h in Headers */, @@ -3895,7 +3880,6 @@ FADF54041E3D77B500012CC0 /* wrap_Text.h in Headers */, FA0B7ED31A95902C000E1D17 /* wrap_ThreadModule.h in Headers */, FA0B7A511A958EA3000E1D17 /* b2GrowableStack.h in Headers */, - FA0B7D921A95902C000E1D17 /* FormatHandler.h in Headers */, FAC756F61E4F99B400B91289 /* Effect.h in Headers */, FA0B7ADD1A958EA3000E1D17 /* gladfuncs.hpp in Headers */, FAF1405D1E20934C00F898D2 /* intermediate.h in Headers */, @@ -4051,7 +4035,6 @@ FA0B7ABE1A958EA3000E1D17 /* compress.c in Sources */, FA0B7CF21A95902C000E1D17 /* DroppedFile.cpp in Sources */, FA4F2C141DE936FE00CA37D7 /* usocket.c in Sources */, - FA0B7D8A1A95902C000E1D17 /* CompressedImageData.cpp in Sources */, FAF140831E20934C00F898D2 /* ParseContextBase.cpp in Sources */, FA0B7AD21A958EA3000E1D17 /* protocol.c in Sources */, FAF140A41E20934C00F898D2 /* Scan.cpp in Sources */, @@ -4190,15 +4173,14 @@ FADF54211E3DA52C00012CC0 /* wrap_ParticleSystem.cpp in Sources */, FA0B791C1A958E3B000E1D17 /* b64.cpp in Sources */, FA1E88851DF363E100E808AA /* Filter.cpp in Sources */, - FA0B7D941A95902C000E1D17 /* Image.cpp in Sources */, FA0B7DA01A95902C000E1D17 /* KTXHandler.cpp in Sources */, FA27B3A11B498151008A9DCE /* VideoStream.cpp in Sources */, FA0B7A5C1A958EA3000E1D17 /* b2Timer.cpp in Sources */, FA0B7CEC1A95902C000E1D17 /* Event.cpp in Sources */, FA27B3AB1B498151008A9DCE /* VideoStream.cpp in Sources */, FA0B7A7E1A958EA3000E1D17 /* b2ContactSolver.cpp in Sources */, - FA0B7D971A95902C000E1D17 /* ImageData.cpp in Sources */, FA0B7E581A95902C000E1D17 /* wrap_Joint.cpp in Sources */, + FAECA1B51F31648A0095D008 /* FormatHandler.cpp in Sources */, FA4F2C0A1DE936E600CA37D7 /* mime.c in Sources */, FA0B7E311A95902C000E1D17 /* Shape.cpp in Sources */, FA0B7E491A95902C000E1D17 /* wrap_DistanceJoint.cpp in Sources */, @@ -4287,13 +4269,13 @@ FA0B7DB21A95902C000E1D17 /* wrap_Image.cpp in Sources */, FA0B7E891A95902C000E1D17 /* Decoder.cpp in Sources */, FA0B7A591A958EA3000E1D17 /* b2StackAllocator.cpp in Sources */, + FAECA1B31F3164700095D008 /* CompressedSlice.cpp in Sources */, FA0B7E3D1A95902C000E1D17 /* wrap_Body.cpp in Sources */, FA0B7D7A1A95902C000E1D17 /* Quad.cpp in Sources */, FA620A3B1AA305F6005DB4C2 /* types.cpp in Sources */, FA0B7DD41A95902C000E1D17 /* BezierCurve.cpp in Sources */, FA0B7E7C1A95902C000E1D17 /* wrap_World.cpp in Sources */, FA4F2C0E1DE936FE00CA37D7 /* tcp.c in Sources */, - FA0B7D911A95902C000E1D17 /* FormatHandler.cpp in Sources */, FA0B7D431A95902C000E1D17 /* OpenGL.cpp in Sources */, FA0B7DBF1A95902C000E1D17 /* JoystickModule.cpp in Sources */, FA0B7D4F1A95902C000E1D17 /* SpriteBatch.cpp in Sources */, @@ -4410,7 +4392,6 @@ FA0B7D091A95902C000E1D17 /* wrap_FileData.cpp in Sources */, FA0B7B341A958EA3000E1D17 /* wuff_convert.c in Sources */, FA0B7CF11A95902C000E1D17 /* DroppedFile.cpp in Sources */, - FA0B7D891A95902C000E1D17 /* CompressedImageData.cpp in Sources */, FAF140821E20934C00F898D2 /* ParseContextBase.cpp in Sources */, FA0B7D1E1A95902C000E1D17 /* ImageRasterizer.cpp in Sources */, FAF140A31E20934C00F898D2 /* Scan.cpp in Sources */, @@ -4545,7 +4526,6 @@ FA0B7A4E1A958EA3000E1D17 /* b2Draw.cpp in Sources */, FAD19A171DFF8CA200D5398A /* ImageDataBase.cpp in Sources */, FA27B3C01B4985BF008A9DCE /* wrap_VideoStream.cpp in Sources */, - FA0B7D931A95902C000E1D17 /* Image.cpp in Sources */, FADF54201E3DA52C00012CC0 /* wrap_ParticleSystem.cpp in Sources */, FA0B7D9F1A95902C000E1D17 /* KTXHandler.cpp in Sources */, FA1E88831DF363DB00E808AA /* Filter.cpp in Sources */, @@ -4554,9 +4534,9 @@ FA0B7CEB1A95902C000E1D17 /* Event.cpp in Sources */, FA1557C31CE90BD200AFF582 /* EXRHandler.cpp in Sources */, FA27B3AA1B498151008A9DCE /* VideoStream.cpp in Sources */, - FA0B7D961A95902C000E1D17 /* ImageData.cpp in Sources */, FA0B7E571A95902C000E1D17 /* wrap_Joint.cpp in Sources */, FA0B7E301A95902C000E1D17 /* Shape.cpp in Sources */, + FA93C4541F315B960087CCD4 /* FormatHandler.cpp in Sources */, FA0B7E481A95902C000E1D17 /* wrap_DistanceJoint.cpp in Sources */, FA0B7A8F1A958EA3000E1D17 /* b2FrictionJoint.cpp in Sources */, FA0B792F1A958E3B000E1D17 /* Module.cpp in Sources */, @@ -4597,6 +4577,7 @@ FA0B7E8B1A95902C000E1D17 /* FLACDecoder.cpp in Sources */, FA0B7B3A1A958EA3000E1D17 /* wuff_memory.c in Sources */, FA0B7A381A958EA3000E1D17 /* b2DynamicTree.cpp in Sources */, + FAECA1B21F3164700095D008 /* CompressedSlice.cpp in Sources */, FA0B7D481A95902C000E1D17 /* Polyline.cpp in Sources */, 217DFC111D9F6D490055D849 /* usocket.c in Sources */, FAF140751E20934C00F898D2 /* IntermTraverse.cpp in Sources */, @@ -4647,7 +4628,6 @@ FA91591E1CF1ED7500A7053F /* halffloat.cpp in Sources */, FA0B7E7B1A95902C000E1D17 /* wrap_World.cpp in Sources */, FA0B7B281A958EA3000E1D17 /* simplexnoise1234.cpp in Sources */, - FA0B7D901A95902C000E1D17 /* FormatHandler.cpp in Sources */, FA0B7D421A95902C000E1D17 /* OpenGL.cpp in Sources */, FA0B7A671A958EA3000E1D17 /* b2Island.cpp in Sources */, FA0B7DBE1A95902C000E1D17 /* JoystickModule.cpp in Sources */, diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 5ea26ee5b..074c777f2 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -447,7 +447,7 @@ static int screenshotSaveToFile(lua_State *L) const char *filename = luaL_checkstring(L, lua_upvalueindex(1)); const char *ext = luaL_checkstring(L, lua_upvalueindex(2)); - image::ImageData::EncodedFormat format; + image::FormatHandler::EncodedFormat format; if (!image::ImageData::getConstant(ext, format)) return 0; @@ -478,7 +478,7 @@ int w_captureScreenshot(lua_State *L) std::transform(ext.begin(), ext.end(), ext.begin(), tolower); - image::ImageData::EncodedFormat format; + image::FormatHandler::EncodedFormat format; if (!image::ImageData::getConstant(ext.c_str(), format)) return luaL_error(L, "Invalid encoded image format: %s", ext.c_str()); diff --git a/src/modules/image/magpie/CompressedFormatHandler.h b/src/modules/image/CompressedFormatHandler.h similarity index 78% rename from src/modules/image/magpie/CompressedFormatHandler.h rename to src/modules/image/CompressedFormatHandler.h index 81328e5be..43aa54cc9 100644 --- a/src/modules/image/magpie/CompressedFormatHandler.h +++ b/src/modules/image/CompressedFormatHandler.h @@ -18,20 +18,17 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_COMPRESSED_HANDLER_H -#define LOVE_IMAGE_MAGPIE_COMPRESSED_HANDLER_H +#pragma once // LOVE -#include "filesystem/FileData.h" -#include "image/CompressedImageData.h" #include "common/Object.h" +#include "filesystem/FileData.h" +#include "CompressedSlice.h" namespace love { namespace image { -namespace magpie -{ /** * Base class for all CompressedImageData parser library interfaces. @@ -45,8 +42,8 @@ public: virtual ~CompressedFormatHandler() {} /** - * Determines whether a particular FileData can be parsed as CompressedImageData - * by this handler. + * Determines whether a particular FileData can be parsed as + * CompressedImageData by this handler. * @param data The data to parse. **/ virtual bool canParse(const filesystem::FileData *data) = 0; @@ -56,21 +53,18 @@ public: * a single block of memory containing all the images. * * @param[in] filedata The data to parse. - * @param[out] images The list of sub-images generated. Byte data is a pointer - * to the returned data. + * @param[out] images The list of sub-images generated. Byte data is a + * pointer to the returned data. * @param[out] format The format of the Compressed Data. * @param[out] sRGB Whether the texture is sRGB-encoded. * * @return The single block of memory containing the parsed images. **/ - virtual StrongRef parse(filesystem::FileData *filedata, - std::vector> &images, + virtual StrongRef parse(filesystem::FileData *filedata, + std::vector> &images, PixelFormat &format, bool &sRGB) = 0; }; // CompressedFormatHandler -} // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_COMPRESSED_HANDLER_H diff --git a/src/modules/image/CompressedImageData.cpp b/src/modules/image/CompressedImageData.cpp index 066a3b291..984c93df5 100644 --- a/src/modules/image/CompressedImageData.cpp +++ b/src/modules/image/CompressedImageData.cpp @@ -27,58 +27,54 @@ namespace image love::Type CompressedImageData::type("CompressedImageData", &Data::type); -CompressedImageData::Memory::Memory(size_t size) - : data(nullptr) - , size(size) -{ - try - { - data = new uint8[size]; - } - catch (std::exception &) - { - throw love::Exception("Out of memory."); - } -} - -CompressedImageData::Memory::~Memory() -{ - delete[] data; -} - -CompressedImageData::Slice::Slice(PixelFormat format, int width, int height, Memory *memory, size_t offset, size_t size) - : memory(memory) - , offset(offset) - , dataSize(size) -{ - this->format = format; - this->width = width; - this->height = height; -} - -CompressedImageData::Slice::Slice(const Slice &s) - : memory(s.memory) - , offset(s.offset) - , dataSize(s.dataSize) -{ - this->format = s.getFormat(); - this->width = s.getWidth(); - this->height = s.getHeight(); -} - -CompressedImageData::Slice::~Slice() -{ -} - -CompressedImageData::Slice *CompressedImageData::Slice::clone() const -{ - return new Slice(*this); -} - -CompressedImageData::CompressedImageData() +CompressedImageData::CompressedImageData(const std::list &formats, love::filesystem::FileData *filedata) : format(PIXELFORMAT_UNKNOWN) , sRGB(false) { + CompressedFormatHandler *parser = nullptr; + + for (CompressedFormatHandler *handler : formats) + { + if (handler->canParse(filedata)) + { + parser = handler; + break; + } + } + + if (parser == nullptr) + throw love::Exception("Could not parse compressed data: Unknown format."); + + memory = parser->parse(filedata, dataImages, format, sRGB); + + if (memory == nullptr) + throw love::Exception("Could not parse compressed data."); + + if (format == PIXELFORMAT_UNKNOWN) + throw love::Exception("Could not parse compressed data: Unknown format."); + + if (dataImages.size() == 0 || memory->size == 0) + throw love::Exception("Could not parse compressed data: No valid data?"); +} + +CompressedImageData::CompressedImageData(const CompressedImageData &c) + : format(c.format) + , sRGB(c.sRGB) +{ + memory.set(new CompressedMemory(c.memory->size), Acquire::NORETAIN); + memcpy(memory->data, c.memory->data, memory->size); + + for (const auto &i : c.dataImages) + { + auto slice = new CompressedSlice(i->getFormat(), i->getWidth(), i->getHeight(), memory, i->getOffset(), i->getSize()); + dataImages.push_back(slice); + slice->release(); + } +} + +CompressedImageData *CompressedImageData::clone() const +{ + return new CompressedImageData(*this); } CompressedImageData::~CompressedImageData() @@ -143,7 +139,7 @@ bool CompressedImageData::isSRGB() const return sRGB; } -CompressedImageData::Slice *CompressedImageData::getSlice(int slice, int miplevel) const +CompressedSlice *CompressedImageData::getSlice(int slice, int miplevel) const { checkSliceExists(slice, miplevel); diff --git a/src/modules/image/CompressedImageData.h b/src/modules/image/CompressedImageData.h index fef680085..5a2ecfea2 100644 --- a/src/modules/image/CompressedImageData.h +++ b/src/modules/image/CompressedImageData.h @@ -25,10 +25,13 @@ #include "common/StringMap.h" #include "common/int.h" #include "common/pixelformat.h" -#include "ImageDataBase.h" +#include "filesystem/FileData.h" +#include "CompressedSlice.h" +#include "CompressedFormatHandler.h" // STL #include +#include namespace love { @@ -44,53 +47,16 @@ class CompressedImageData : public Data { public: - class Memory : public Object - { - public: - - Memory(size_t size); - virtual ~Memory(); - - uint8 *data; - size_t size; - - }; // Memory - - // Compressed image data can have multiple mipmap levels, each represented - // by a sub-image. - class Slice : public ImageDataBase - { - public: - - Slice(PixelFormat format, int width, int height, Memory *memory, size_t offset, size_t size); - Slice(const Slice &slice); - virtual ~Slice(); - - Slice *clone() const override; - void *getData() const override { return memory->data + offset; } - size_t getSize() const override { return dataSize; } - bool isSRGB() const override { return sRGB; } - size_t getOffset() const { return offset; } - - private: - - StrongRef memory; - - size_t offset; - size_t dataSize; - bool sRGB; - - }; // Slice - static love::Type type; - CompressedImageData(); + CompressedImageData(const std::list &formats, love::filesystem::FileData *filedata); + CompressedImageData(const CompressedImageData &c); virtual ~CompressedImageData(); // Implements Data. - virtual CompressedImageData *clone() const = 0; - virtual void *getData() const; - virtual size_t getSize() const; + CompressedImageData *clone() const override; + void *getData() const override; + size_t getSize() const override; /** * Gets the number of mipmaps in this Compressed Image Data. @@ -130,19 +96,18 @@ public: bool isSRGB() const; - Slice *getSlice(int slice, int miplevel) const; + CompressedSlice *getSlice(int slice, int miplevel) const; protected: PixelFormat format; - bool sRGB; // Single block of memory containing all of the sub-images. - StrongRef memory; + StrongRef memory; // Texture info for each mipmap level. - std::vector> dataImages; + std::vector> dataImages; void checkSliceExists(int slice, int miplevel) const; diff --git a/src/modules/image/magpie/CompressedImageData.h b/src/modules/image/CompressedSlice.cpp similarity index 52% rename from src/modules/image/magpie/CompressedImageData.h rename to src/modules/image/CompressedSlice.cpp index c8fd624f5..f640c8740 100644 --- a/src/modules/image/magpie/CompressedImageData.h +++ b/src/modules/image/CompressedSlice.cpp @@ -18,37 +18,61 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_COMPRESSED_IMAGE_DATA_H -#define LOVE_IMAGE_MAGPIE_COMPRESSED_IMAGE_DATA_H - -// LOVE -#include "CompressedFormatHandler.h" -#include "filesystem/FileData.h" -#include "image/CompressedImageData.h" - -// C++ -#include +#include "CompressedSlice.h" +#include "common/Exception.h" namespace love { namespace image { -namespace magpie + +CompressedMemory::CompressedMemory(size_t size) + : data(nullptr) + , size(size) { + try + { + data = new uint8[size]; + } + catch (std::exception &) + { + throw love::Exception("Out of memory."); + } +} -class CompressedImageData : public love::image::CompressedImageData +CompressedMemory::~CompressedMemory() { -public: + delete[] data; +} - CompressedImageData(std::list formats, love::filesystem::FileData *filedata); - CompressedImageData(const CompressedImageData &c); - virtual ~CompressedImageData(); +CompressedSlice::CompressedSlice(PixelFormat format, int width, int height, CompressedMemory *memory, size_t offset, size_t size) + : memory(memory) + , offset(offset) + , dataSize(size) +{ + this->format = format; + this->width = width; + this->height = height; +} - virtual CompressedImageData *clone() const; -}; // CompressedImageData +CompressedSlice::CompressedSlice(const CompressedSlice &s) + : memory(s.memory) + , offset(s.offset) + , dataSize(s.dataSize) +{ + this->format = s.getFormat(); + this->width = s.getWidth(); + this->height = s.getHeight(); +} + +CompressedSlice::~CompressedSlice() +{ +} + +CompressedSlice *CompressedSlice::clone() const +{ + return new CompressedSlice(*this); +} -} // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_COMPRESSED_IMAGE_DATA_H diff --git a/src/modules/image/CompressedSlice.h b/src/modules/image/CompressedSlice.h new file mode 100644 index 000000000..bfe4ce946 --- /dev/null +++ b/src/modules/image/CompressedSlice.h @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2006-2017 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#pragma once + +// LOVE +#include "common/int.h" +#include "common/pixelformat.h" +#include "common/Object.h" +#include "ImageDataBase.h" + +namespace love +{ +namespace image +{ + +class CompressedMemory : public Object +{ +public: + + CompressedMemory(size_t size); + virtual ~CompressedMemory(); + + uint8 *data; + size_t size; + +}; // CompressedMemory + +// Compressed image data can have multiple mipmap levels, each represented by a +// sub-image. +class CompressedSlice : public ImageDataBase +{ +public: + + CompressedSlice(PixelFormat format, int width, int height, CompressedMemory *memory, size_t offset, size_t size); + CompressedSlice(const CompressedSlice &slice); + virtual ~CompressedSlice(); + + CompressedSlice *clone() const override; + void *getData() const override { return memory->data + offset; } + size_t getSize() const override { return dataSize; } + bool isSRGB() const override { return sRGB; } + size_t getOffset() const { return offset; } + +private: + + StrongRef memory; + size_t offset; + size_t dataSize; + bool sRGB; + +}; // CompressedSlice + +} // image +} // love diff --git a/src/modules/image/magpie/FormatHandler.cpp b/src/modules/image/FormatHandler.cpp similarity index 89% rename from src/modules/image/magpie/FormatHandler.cpp rename to src/modules/image/FormatHandler.cpp index a50562c1e..689609f56 100644 --- a/src/modules/image/magpie/FormatHandler.cpp +++ b/src/modules/image/FormatHandler.cpp @@ -26,8 +26,6 @@ namespace love { namespace image { -namespace magpie -{ FormatHandler::FormatHandler() { @@ -42,7 +40,7 @@ bool FormatHandler::canDecode(love::filesystem::FileData* /*data*/) return false; } -bool FormatHandler::canEncode(PixelFormat /*rawFormat*/, ImageData::EncodedFormat /*encodedFormat*/) +bool FormatHandler::canEncode(PixelFormat /*rawFormat*/, EncodedFormat /*encodedFormat*/) { return false; } @@ -52,7 +50,7 @@ FormatHandler::DecodedImage FormatHandler::decode(love::filesystem::FileData* /* throw love::Exception("Image decoding is not implemented for this format backend."); } -FormatHandler::EncodedImage FormatHandler::encode(const DecodedImage& /*img*/, ImageData::EncodedFormat /*format*/) +FormatHandler::EncodedImage FormatHandler::encode(const DecodedImage& /*img*/, EncodedFormat /*format*/) { throw love::Exception("Image encoding is not implemented for this format backend."); } @@ -62,6 +60,5 @@ void FormatHandler::free(unsigned char *mem) delete[] mem; } -} // magpie } // image } // love diff --git a/src/modules/image/magpie/FormatHandler.h b/src/modules/image/FormatHandler.h similarity index 87% rename from src/modules/image/magpie/FormatHandler.h rename to src/modules/image/FormatHandler.h index 1e76819b1..a29b42d95 100644 --- a/src/modules/image/magpie/FormatHandler.h +++ b/src/modules/image/FormatHandler.h @@ -18,20 +18,17 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_FORMAT_HANDLER_H -#define LOVE_IMAGE_MAGPIE_FORMAT_HANDLER_H +#pragma once // LOVE -#include "image/ImageData.h" -#include "filesystem/FileData.h" #include "common/Object.h" +#include "common/pixelformat.h" +#include "filesystem/FileData.h" namespace love { namespace image { -namespace magpie -{ /** * Base class for all ImageData encoder/decoder library interfaces. @@ -41,6 +38,13 @@ class FormatHandler : public love::Object { public: + enum EncodedFormat + { + ENCODED_TGA, + ENCODED_PNG, + ENCODED_MAX_ENUM + }; + // Raw RGBA pixel data. struct DecodedImage { @@ -76,7 +80,7 @@ public: /** * Whether this format handler can encode to a particular format. **/ - virtual bool canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat); + virtual bool canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat); /** * Decodes an image from its encoded form into raw pixel data. @@ -91,7 +95,7 @@ public: * @param format The format to encode to. * @return The encoded image data. **/ - virtual EncodedImage encode(const DecodedImage &img, ImageData::EncodedFormat format); + virtual EncodedImage encode(const DecodedImage &img, EncodedFormat format); /** * Frees memory allocated by the format handler. @@ -100,8 +104,5 @@ public: }; // FormatHandler -} // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_FORMAT_HANDLER_H diff --git a/src/modules/image/Image.cpp b/src/modules/image/Image.cpp index d50db0d50..9d69de4b8 100644 --- a/src/modules/image/Image.cpp +++ b/src/modules/image/Image.cpp @@ -20,6 +20,17 @@ // LOVE #include "Image.h" +#include "common/config.h" + +#include "magpie/PNGHandler.h" +#include "magpie/STBHandler.h" +#include "magpie/EXRHandler.h" + +#include "magpie/ddsHandler.h" +#include "magpie/PVRHandler.h" +#include "magpie/KTXHandler.h" +#include "magpie/PKMHandler.h" +#include "magpie/ASTCHandler.h" namespace love { @@ -28,6 +39,79 @@ namespace image love::Type Image::type("image", &Module::type); +Image::Image() +{ + using namespace magpie; + + halfInit(); // Makes sure half-float conversions can be used. + + formatHandlers = { + new PNGHandler, + new STBHandler, + new EXRHandler, + }; + + compressedFormatHandlers = { + new DDSHandler, + new PVRHandler, + new KTXHandler, + new PKMHandler, + new ASTCHandler, + }; +} + +Image::~Image() +{ + // ImageData objects reference the FormatHandlers in our list, so we should + // release them instead of deleting them completely here. + for (FormatHandler *handler : formatHandlers) + handler->release(); + + for (CompressedFormatHandler *handler : compressedFormatHandlers) + handler->release(); +} + +const char *Image::getName() const +{ + return "love.image.magpie"; +} + +love::image::ImageData *Image::newImageData(love::filesystem::FileData *data) +{ + return new ImageData(data); +} + +love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format) +{ + return new ImageData(width, height, format); +} + +love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format, void *data, bool own) +{ + return new ImageData(width, height, format, data, own); +} + +love::image::CompressedImageData *Image::newCompressedData(love::filesystem::FileData *data) +{ + return new CompressedImageData(compressedFormatHandlers, data); +} + +bool Image::isCompressed(love::filesystem::FileData *data) +{ + for (CompressedFormatHandler *handler : compressedFormatHandlers) + { + if (handler->canParse(data)) + return true; + } + + return false; +} + +const std::list &Image::getFormatHandlers() const +{ + return formatHandlers; +} + ImageData *Image::newPastedImageData(ImageData *src, int sx, int sy, int w, int h) { ImageData *res = newImageData(w, h, src->getFormat()); diff --git a/src/modules/image/Image.h b/src/modules/image/Image.h index 64ace18ca..a8a835439 100644 --- a/src/modules/image/Image.h +++ b/src/modules/image/Image.h @@ -28,6 +28,9 @@ #include "ImageData.h" #include "CompressedImageData.h" +// C++ +#include + namespace love { namespace image @@ -46,17 +49,19 @@ public: static love::Type type; - virtual ~Image() {} + Image(); + virtual ~Image(); // Implements Module. - virtual ModuleType getModuleType() const { return M_IMAGE; } + ModuleType getModuleType() const override { return M_IMAGE; } + const char *getName() const override; /** * Creates new ImageData from FileData. * @param data The FileData containing the encoded image data. * @return The new ImageData. **/ - virtual ImageData *newImageData(love::filesystem::FileData *data) = 0; + ImageData *newImageData(love::filesystem::FileData *data); /** * Creates empty ImageData with the given size. @@ -64,7 +69,7 @@ public: * @param height The height of the ImageData. * @return The new ImageData. **/ - virtual ImageData *newImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8) = 0; + ImageData *newImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8); /** * Creates empty ImageData with the given size. @@ -75,28 +80,36 @@ public: * copy it. * @return The new ImageData. **/ - virtual ImageData *newImageData(int width, int height, PixelFormat format, void *data, bool own = false) = 0; + ImageData *newImageData(int width, int height, PixelFormat format, void *data, bool own = false); /** * Creates new CompressedImageData from FileData. * @param data The FileData containing the compressed image data. * @return The new CompressedImageData. **/ - virtual CompressedImageData *newCompressedData(love::filesystem::FileData *data) = 0; + CompressedImageData *newCompressedData(love::filesystem::FileData *data); /** * Determines whether a FileData is Compressed image data or not. * @param data The FileData to test. **/ - virtual bool isCompressed(love::filesystem::FileData *data) = 0; + bool isCompressed(love::filesystem::FileData *data); std::vector> newCubeFaces(ImageData *src); std::vector> newVolumeLayers(ImageData *src); + const std::list &getFormatHandlers() const; + private: ImageData *newPastedImageData(ImageData *src, int sx, int sy, int w, int h); + // Image format handlers we can use for decoding and encoding ImageData. + std::list formatHandlers; + + // Compressed image format handers we can use for parsing CompressedImageData. + std::list compressedFormatHandlers; + }; // Image } // image diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index 399a08647..0313d5ae2 100644 --- a/src/modules/image/ImageData.cpp +++ b/src/modules/image/ImageData.cpp @@ -19,6 +19,8 @@ **/ #include "ImageData.h" +#include "Image.h" +#include "filesystem/Filesystem.h" using love::thread::Lock; @@ -29,13 +31,207 @@ namespace image love::Type ImageData::type("ImageData", &Data::type); -ImageData::ImageData() - : data(nullptr) +ImageData::ImageData(love::filesystem::FileData *data) { + decode(data); +} + +ImageData::ImageData(int width, int height, PixelFormat format) +{ + if (!validPixelFormat(format)) + throw love::Exception("Unsupported pixel format for ImageData"); + + this->width = width; + this->height = height; + this->format = format; + + create(width, height, format); + + // Set to black/transparency. + memset(data, 0, getSize()); +} + +ImageData::ImageData(int width, int height, PixelFormat format, void *data, bool own) +{ + if (!validPixelFormat(format)) + throw love::Exception("Unsupported pixel format for ImageData"); + + this->width = width; + this->height = height; + this->format = format; + + if (own) + this->data = (unsigned char *) data; + else + create(width, height, format, data); +} + +ImageData::ImageData(const ImageData &c) +{ + width = c.width; + height = c.height; + format = c.format; + + create(width, height, format, c.getData()); } ImageData::~ImageData() { + if (decodeHandler.get()) + decodeHandler->free(data); + else + delete[] data; +} + +love::image::ImageData *ImageData::clone() const +{ + return new ImageData(*this); +} + +void ImageData::create(int width, int height, PixelFormat format, void *data) +{ + size_t datasize = width * height * getPixelFormatSize(format); + + try + { + this->data = new unsigned char[datasize]; + } + catch(std::bad_alloc &) + { + throw love::Exception("Out of memory"); + } + + if (data) + memcpy(this->data, data, datasize); + + decodeHandler = nullptr; + this->format = format; +} + +void ImageData::decode(love::filesystem::FileData *data) +{ + FormatHandler *decoder = nullptr; + FormatHandler::DecodedImage decodedimage; + + auto module = Module::getInstance(Module::M_IMAGE); + + if (module == nullptr) + throw love::Exception("love.image must be loaded in order to decode an ImageData."); + + for (FormatHandler *handler : module->getFormatHandlers()) + { + if (handler->canDecode(data)) + { + decoder = handler; + break; + } + } + + if (decoder) + decodedimage = decoder->decode(data); + + if (decodedimage.data == nullptr) + { + const std::string &name = data->getFilename(); + throw love::Exception("Could not decode file '%s' to ImageData: unsupported file format", name.c_str()); + } + + if (decodedimage.size != decodedimage.width * decodedimage.height * getPixelFormatSize(decodedimage.format)) + { + decoder->free(decodedimage.data); + throw love::Exception("Could not convert image!"); + } + + // Clean up any old data. + if (decodeHandler) + decodeHandler->free(this->data); + else + delete[] this->data; + + this->width = decodedimage.width; + this->height = decodedimage.height; + this->data = decodedimage.data; + this->format = decodedimage.format; + + decodeHandler = decoder; +} + +love::filesystem::FileData *ImageData::encode(FormatHandler::EncodedFormat encodedFormat, const char *filename, bool writefile) const +{ + FormatHandler *encoder = nullptr; + FormatHandler::EncodedImage encodedimage; + FormatHandler::DecodedImage rawimage; + + rawimage.width = width; + rawimage.height = height; + rawimage.size = getSize(); + rawimage.data = data; + rawimage.format = format; + + auto module = Module::getInstance(Module::M_IMAGE); + + if (module == nullptr) + throw love::Exception("love.image must be loaded in order to encode an ImageData."); + + for (FormatHandler *handler : module->getFormatHandlers()) + { + if (handler->canEncode(format, encodedFormat)) + { + encoder = handler; + break; + } + } + + if (encoder != nullptr) + { + thread::Lock lock(mutex); + encodedimage = encoder->encode(rawimage, encodedFormat); + } + + if (encoder == nullptr || encodedimage.data == nullptr) + { + const char *fname = "unknown"; + love::getConstant(format, fname); + throw love::Exception("No suitable image encoder for %s format.", fname); + } + + love::filesystem::FileData *filedata = nullptr; + + try + { + filedata = new love::filesystem::FileData(encodedimage.size, filename); + } + catch (love::Exception &) + { + encoder->free(encodedimage.data); + throw; + } + + memcpy(filedata->getData(), encodedimage.data, encodedimage.size); + encoder->free(encodedimage.data); + + if (writefile) + { + auto fs = Module::getInstance(Module::M_FILESYSTEM); + + if (fs == nullptr) + { + filedata->release(); + throw love::Exception("love.filesystem must be loaded in order to write an encoded ImageData to a file."); + } + + try + { + fs->write(filename, filedata->getData(), filedata->getSize()); + } + catch (love::Exception &) + { + filedata->release(); + throw; + } + } + + return filedata; } size_t ImageData::getSize() const @@ -289,23 +485,23 @@ bool ImageData::validPixelFormat(PixelFormat format) } } -bool ImageData::getConstant(const char *in, EncodedFormat &out) +bool ImageData::getConstant(const char *in, FormatHandler::EncodedFormat &out) { return encodedFormats.find(in, out); } -bool ImageData::getConstant(EncodedFormat in, const char *&out) +bool ImageData::getConstant(FormatHandler::EncodedFormat in, const char *&out) { return encodedFormats.find(in, out); } -StringMap::Entry ImageData::encodedFormatEntries[] = +StringMap::Entry ImageData::encodedFormatEntries[] = { - {"tga", ENCODED_TGA}, - {"png", ENCODED_PNG}, + {"tga", FormatHandler::ENCODED_TGA}, + {"png", FormatHandler::ENCODED_PNG}, }; -StringMap ImageData::encodedFormats(ImageData::encodedFormatEntries, sizeof(ImageData::encodedFormatEntries)); +StringMap ImageData::encodedFormats(ImageData::encodedFormatEntries, sizeof(ImageData::encodedFormatEntries)); } // image } // love diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index c7f84bd01..21f654534 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -29,6 +29,7 @@ #include "filesystem/FileData.h" #include "thread/threads.h" #include "ImageDataBase.h" +#include "FormatHandler.h" using love::thread::Mutex; @@ -61,14 +62,10 @@ public: static love::Type type; - enum EncodedFormat - { - ENCODED_TGA, - ENCODED_PNG, - ENCODED_MAX_ENUM - }; - - ImageData(); + ImageData(love::filesystem::FileData *data); + ImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8); + ImageData(int width, int height, PixelFormat format, void *data, bool own); + ImageData(const ImageData &c); virtual ~ImageData(); /** @@ -111,12 +108,12 @@ public: * @param f The file to save the encoded image data to. * @param format The format of the encoded data. **/ - virtual love::filesystem::FileData *encode(EncodedFormat format, const char *filename, bool writefile) = 0; + love::filesystem::FileData *encode(FormatHandler::EncodedFormat format, const char *filename, bool writefile) const; love::thread::Mutex *getMutex() const; // Implements ImageDataBase. - virtual ImageData *clone() const override = 0; + ImageData *clone() const override; void *getData() const override; size_t getSize() const override; bool isSRGB() const override; @@ -125,18 +122,8 @@ public: static bool validPixelFormat(PixelFormat format); - static bool getConstant(const char *in, EncodedFormat &out); - static bool getConstant(EncodedFormat in, const char *&out); - -protected: - - // The actual data. - unsigned char *data; - - // We need to be thread-safe - // so we lock when we're accessing our - // data - love::thread::MutexRef mutex; + static bool getConstant(const char *in, FormatHandler::EncodedFormat &out); + static bool getConstant(FormatHandler::EncodedFormat in, const char *&out); private: @@ -148,6 +135,21 @@ private: float *f32; }; + // Create imagedata. Initialize with data if not null. + void create(int width, int height, PixelFormat format, void *data = nullptr); + + // Decode and load an encoded format. + void decode(love::filesystem::FileData *data); + + // The actual data. + unsigned char *data = nullptr; + + love::thread::MutexRef mutex; + + // The format handler that was used to decode the ImageData. We need to know + // this so we can properly delete memory allocated by the decoder. + StrongRef decodeHandler; + static void pasteRGBA8toRGBA16(Row src, Row dst, int w); static void pasteRGBA8toRGBA16F(Row src, Row dst, int w); static void pasteRGBA8toRGBA32F(Row src, Row dst, int w); @@ -164,8 +166,8 @@ private: static void pasteRGBA32FtoRGBA16(Row src, Row dst, int w); static void pasteRGBA32FtoRGBA16F(Row src, Row dst, int w); - static StringMap::Entry encodedFormatEntries[]; - static StringMap encodedFormats; + static StringMap::Entry encodedFormatEntries[]; + static StringMap encodedFormats; }; // ImageData diff --git a/src/modules/image/magpie/ASTCHandler.cpp b/src/modules/image/magpie/ASTCHandler.cpp index 63fb7fe95..05363fe24 100644 --- a/src/modules/image/magpie/ASTCHandler.cpp +++ b/src/modules/image/magpie/ASTCHandler.cpp @@ -104,7 +104,7 @@ bool ASTCHandler::canParse(const filesystem::FileData *data) return true; } -StrongRef ASTCHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef ASTCHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) { if (!canParse(filedata)) throw love::Exception("Could not decode compressed data (not an .astc file?)"); @@ -129,12 +129,12 @@ StrongRef ASTCHandler::parse(filesystem::FileData * if (totalsize + sizeof(header) > filedata->getSize()) throw love::Exception("Could not parse .astc file: file is too small."); - StrongRef memory(new CompressedImageData::Memory(totalsize), Acquire::NORETAIN); + StrongRef memory(new CompressedMemory(totalsize), Acquire::NORETAIN); // .astc files only store a single mipmap level. memcpy(memory->data, (uint8 *) filedata->getData() + sizeof(ASTCHeader), totalsize); - images.emplace_back(new CompressedImageData::Slice(cformat, sizeX, sizeY, memory, 0, totalsize), Acquire::NORETAIN); + images.emplace_back(new CompressedSlice(cformat, sizeX, sizeY, memory, 0, totalsize), Acquire::NORETAIN); format = cformat; sRGB = false; diff --git a/src/modules/image/magpie/ASTCHandler.h b/src/modules/image/magpie/ASTCHandler.h index 341782a52..d83fc4ce0 100644 --- a/src/modules/image/magpie/ASTCHandler.h +++ b/src/modules/image/magpie/ASTCHandler.h @@ -18,11 +18,10 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_ASTC_HANDLER_H -#define LOVE_IMAGE_MAGPIE_ASTC_HANDLER_H +#pragma once #include "common/config.h" -#include "CompressedFormatHandler.h" +#include "image/CompressedFormatHandler.h" namespace love { @@ -44,8 +43,8 @@ public: // Implements CompressedFormatHandler. bool canParse(const filesystem::FileData *data) override; - StrongRef parse(filesystem::FileData *filedata, - std::vector> &images, + StrongRef parse(filesystem::FileData *filedata, + std::vector> &images, PixelFormat &format, bool &sRGB) override; }; // ASTCHandler @@ -53,5 +52,3 @@ public: } // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_ASTC_HANDLER_H diff --git a/src/modules/image/magpie/CompressedImageData.cpp b/src/modules/image/magpie/CompressedImageData.cpp deleted file mode 100644 index 4d3df3e46..000000000 --- a/src/modules/image/magpie/CompressedImageData.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2006-2017 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "CompressedImageData.h" - -namespace love -{ -namespace image -{ -namespace magpie -{ - -CompressedImageData::CompressedImageData(std::list formats, love::filesystem::FileData *filedata) -{ - CompressedFormatHandler *parser = nullptr; - - for (CompressedFormatHandler *handler : formats) - { - if (handler->canParse(filedata)) - { - parser = handler; - break; - } - } - - if (parser == nullptr) - throw love::Exception("Could not parse compressed data: Unknown format."); - - memory = parser->parse(filedata, dataImages, format, sRGB); - - if (memory == nullptr) - throw love::Exception("Could not parse compressed data."); - - if (format == PIXELFORMAT_UNKNOWN) - throw love::Exception("Could not parse compressed data: Unknown format."); - - if (dataImages.size() == 0 || memory->size == 0) - throw love::Exception("Could not parse compressed data: No valid data?"); -} - -CompressedImageData::CompressedImageData(const CompressedImageData &c) -{ - format = c.format; - sRGB = c.sRGB; - - memory.set(new Memory(c.memory->size), Acquire::NORETAIN); - memcpy(memory->data, c.memory->data, memory->size); - - for (const auto &i : c.dataImages) - { - Slice *slice = new Slice(i->getFormat(), i->getWidth(), i->getHeight(), memory, i->getOffset(), i->getSize()); - dataImages.push_back(slice); - slice->release(); - } -} - -CompressedImageData *CompressedImageData::clone() const -{ - return new CompressedImageData(*this); -} - -CompressedImageData::~CompressedImageData() -{ -} - -} // magpie -} // image -} // love diff --git a/src/modules/image/magpie/EXRHandler.cpp b/src/modules/image/magpie/EXRHandler.cpp index 77260a78a..177ad753f 100644 --- a/src/modules/image/magpie/EXRHandler.cpp +++ b/src/modules/image/magpie/EXRHandler.cpp @@ -20,6 +20,7 @@ // LOVE #include "EXRHandler.h" +#include "common/halffloat.h" // tinyexr #define TINYEXR_IMPLEMENTATION @@ -41,7 +42,7 @@ bool EXRHandler::canDecode(love::filesystem::FileData *data) return ParseEXRVersionFromMemory(&version, (const unsigned char *) data->getData(), data->getSize()) == TINYEXR_SUCCESS; } -bool EXRHandler::canEncode(PixelFormat /*rawFormat*/, ImageData::EncodedFormat /*encodedFormat*/) +bool EXRHandler::canEncode(PixelFormat /*rawFormat*/, EncodedFormat /*encodedFormat*/) { return false; } @@ -186,7 +187,7 @@ FormatHandler::DecodedImage EXRHandler::decode(love::filesystem::FileData *data) return img; } -FormatHandler::EncodedImage EXRHandler::encode(const DecodedImage & /*img*/, ImageData::EncodedFormat /*encodedFormat*/) +FormatHandler::EncodedImage EXRHandler::encode(const DecodedImage & /*img*/, EncodedFormat /*encodedFormat*/) { throw love::Exception("Invalid format."); } diff --git a/src/modules/image/magpie/EXRHandler.h b/src/modules/image/magpie/EXRHandler.h index 187166684..ff50f2ece 100644 --- a/src/modules/image/magpie/EXRHandler.h +++ b/src/modules/image/magpie/EXRHandler.h @@ -18,10 +18,9 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_EXR_HANDLER_H -#define LOVE_IMAGE_MAGPIE_EXR_HANDLER_H +#pragma once -#include "FormatHandler.h" +#include "image/FormatHandler.h" namespace love { @@ -40,10 +39,10 @@ public: // Implements FormatHandler. virtual bool canDecode(love::filesystem::FileData *data); - virtual bool canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat); + virtual bool canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat); virtual DecodedImage decode(love::filesystem::FileData *data); - virtual EncodedImage encode(const DecodedImage &img, ImageData::EncodedFormat format); + virtual EncodedImage encode(const DecodedImage &img, EncodedFormat format); virtual void free(unsigned char *mem); @@ -52,5 +51,3 @@ public: } // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_EXR_HANDLER_H diff --git a/src/modules/image/magpie/Image.cpp b/src/modules/image/magpie/Image.cpp deleted file mode 100644 index 98b34ebfe..000000000 --- a/src/modules/image/magpie/Image.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Copyright (c) 2006-2017 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "common/config.h" - -#include "Image.h" - -#include "ImageData.h" -#include "CompressedImageData.h" - -#include "PNGHandler.h" -#include "STBHandler.h" -#include "EXRHandler.h" - -#include "ddsHandler.h" -#include "PVRHandler.h" -#include "KTXHandler.h" -#include "PKMHandler.h" -#include "ASTCHandler.h" - -namespace love -{ -namespace image -{ -namespace magpie -{ - -Image::Image() -{ - halfInit(); // Makes sure half-float conversions can be used. - - formatHandlers = { - new PNGHandler, - new STBHandler, - new EXRHandler, - }; - - compressedFormatHandlers = { - new DDSHandler, - new PVRHandler, - new KTXHandler, - new PKMHandler, - new ASTCHandler, - }; -} - -Image::~Image() -{ - // ImageData objects reference the FormatHandlers in our list, so we should - // release them instead of deleting them completely here. - for (FormatHandler *handler : formatHandlers) - handler->release(); - - for (CompressedFormatHandler *handler : compressedFormatHandlers) - handler->release(); -} - -const char *Image::getName() const -{ - return "love.image.magpie"; -} - -love::image::ImageData *Image::newImageData(love::filesystem::FileData *data) -{ - return new ImageData(data); -} - -love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format) -{ - return new ImageData(width, height, format); -} - -love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format, void *data, bool own) -{ - return new ImageData(width, height, format, data, own); -} - -love::image::CompressedImageData *Image::newCompressedData(love::filesystem::FileData *data) -{ - return new CompressedImageData(compressedFormatHandlers, data); -} - -bool Image::isCompressed(love::filesystem::FileData *data) -{ - for (CompressedFormatHandler *handler : compressedFormatHandlers) - { - if (handler->canParse(data)) - return true; - } - - return false; -} - -const std::list &Image::getFormatHandlers() const -{ - return formatHandlers; -} - -} // magpie -} // image -} // love diff --git a/src/modules/image/magpie/Image.h b/src/modules/image/magpie/Image.h deleted file mode 100644 index b34923c01..000000000 --- a/src/modules/image/magpie/Image.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2006-2017 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#ifndef LOVE_IMAGE_MAGPIE_IMAGE_H -#define LOVE_IMAGE_MAGPIE_IMAGE_H - -// LOVE -#include "image/Image.h" -#include "FormatHandler.h" -#include "CompressedFormatHandler.h" - -// C++ -#include - -namespace love -{ -namespace image -{ -namespace magpie -{ - -/** - * Similar to love.sound's Lullaby module, love.image.magpie interfaces with - * multiple image libraries and determines the correct one to use on a - * per-image basis at runtime. - **/ -class Image final : public love::image::Image -{ -public: - - Image(); - ~Image(); - - // Implements Module. - const char *getName() const override; - - love::image::ImageData *newImageData(love::filesystem::FileData *data) override; - love::image::ImageData *newImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8) override; - love::image::ImageData *newImageData(int width, int height, PixelFormat format, void *data, bool own = false) override; - - love::image::CompressedImageData *newCompressedData(love::filesystem::FileData *data) override; - - bool isCompressed(love::filesystem::FileData *data) override; - - const std::list &getFormatHandlers() const; - -private: - - // Image format handlers we can use for decoding and encoding ImageData. - std::list formatHandlers; - - // Compressed image format handers we can use for parsing CompressedImageData. - std::list compressedFormatHandlers; - -}; // Image - -} // magpie -} // image -} // love - -#endif // LOVE_IMAGE_MAGPIE_IMAGE_H diff --git a/src/modules/image/magpie/ImageData.cpp b/src/modules/image/magpie/ImageData.cpp deleted file mode 100644 index fc2de49b3..000000000 --- a/src/modules/image/magpie/ImageData.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/** - * Copyright (c) 2006-2017 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -// LOVE -#include "ImageData.h" -#include "Image.h" - -#include "filesystem/Filesystem.h" - -namespace love -{ -namespace image -{ -namespace magpie -{ - -ImageData::ImageData(love::filesystem::FileData *data) -{ - decode(data); -} - -ImageData::ImageData(int width, int height, PixelFormat format) -{ - if (!validPixelFormat(format)) - throw love::Exception("Unsupported pixel format for ImageData"); - - this->width = width; - this->height = height; - this->format = format; - - create(width, height, format); - - // Set to black/transparency. - memset(data, 0, getSize()); -} - -ImageData::ImageData(int width, int height, PixelFormat format, void *data, bool own) -{ - if (!validPixelFormat(format)) - throw love::Exception("Unsupported pixel format for ImageData"); - - this->width = width; - this->height = height; - this->format = format; - - if (own) - this->data = (unsigned char *) data; - else - create(width, height, format, data); -} - -ImageData::ImageData(const ImageData &c) -{ - width = c.width; - height = c.height; - format = c.format; - - create(width, height, format, c.getData()); -} - -ImageData::~ImageData() -{ - if (decodeHandler.get()) - decodeHandler->free(data); - else - delete[] data; -} - -love::image::ImageData *ImageData::clone() const -{ - return new ImageData(*this); -} - -void ImageData::create(int width, int height, PixelFormat format, void *data) -{ - size_t datasize = width * height * getPixelFormatSize(format); - - try - { - this->data = new unsigned char[datasize]; - } - catch(std::bad_alloc &) - { - throw love::Exception("Out of memory"); - } - - if (data) - memcpy(this->data, data, datasize); - - decodeHandler = nullptr; - this->format = format; -} - -void ImageData::decode(love::filesystem::FileData *data) -{ - FormatHandler *decoder = nullptr; - FormatHandler::DecodedImage decodedimage; - - auto module = dynamic_cast(Module::getInstance(Module::M_IMAGE)); - - if (module == nullptr) - throw love::Exception("love.image must be loaded in order to decode an ImageData."); - - for (FormatHandler *handler : module->getFormatHandlers()) - { - if (handler->canDecode(data)) - { - decoder = handler; - break; - } - } - - if (decoder) - decodedimage = decoder->decode(data); - - if (decodedimage.data == nullptr) - { - const std::string &name = data->getFilename(); - throw love::Exception("Could not decode file '%s' to ImageData: unsupported file format", name.c_str()); - } - - if (decodedimage.size != decodedimage.width * decodedimage.height * getPixelFormatSize(decodedimage.format)) - { - decoder->free(decodedimage.data); - throw love::Exception("Could not convert image!"); - } - - // Clean up any old data. - if (decodeHandler) - decodeHandler->free(this->data); - else - delete[] this->data; - - this->width = decodedimage.width; - this->height = decodedimage.height; - this->data = decodedimage.data; - this->format = decodedimage.format; - - decodeHandler = decoder; -} - -love::filesystem::FileData *ImageData::encode(EncodedFormat encodedFormat, const char *filename, bool writefile) -{ - FormatHandler *encoder = nullptr; - FormatHandler::EncodedImage encodedimage; - FormatHandler::DecodedImage rawimage; - - rawimage.width = width; - rawimage.height = height; - rawimage.size = getSize(); - rawimage.data = data; - rawimage.format = format; - - auto module = dynamic_cast(Module::getInstance(Module::M_IMAGE)); - - if (module == nullptr) - throw love::Exception("love.image must be loaded in order to encode an ImageData."); - - for (FormatHandler *handler : module->getFormatHandlers()) - { - if (handler->canEncode(format, encodedFormat)) - { - encoder = handler; - break; - } - } - - if (encoder != nullptr) - { - thread::Lock lock(mutex); - encodedimage = encoder->encode(rawimage, encodedFormat); - } - - if (encoder == nullptr || encodedimage.data == nullptr) - { - const char *fname = "unknown"; - love::getConstant(format, fname); - throw love::Exception("No suitable image encoder for %s format.", fname); - } - - love::filesystem::FileData *filedata = nullptr; - - try - { - filedata = new love::filesystem::FileData(encodedimage.size, filename); - } - catch (love::Exception &) - { - encoder->free(encodedimage.data); - throw; - } - - memcpy(filedata->getData(), encodedimage.data, encodedimage.size); - encoder->free(encodedimage.data); - - if (writefile) - { - auto fs = Module::getInstance(Module::M_FILESYSTEM); - - if (fs == nullptr) - { - filedata->release(); - throw love::Exception("love.filesystem must be loaded in order to write an encoded ImageData to a file."); - } - - try - { - fs->write(filename, filedata->getData(), filedata->getSize()); - } - catch (love::Exception &) - { - filedata->release(); - throw; - } - } - - return filedata; -} - -} // magpie -} // image -} // love diff --git a/src/modules/image/magpie/ImageData.h b/src/modules/image/magpie/ImageData.h deleted file mode 100644 index 91ec6a362..000000000 --- a/src/modules/image/magpie/ImageData.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) 2006-2017 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#ifndef LOVE_IMAGE_MAGPIE_IMAGE_DATA_H -#define LOVE_IMAGE_MAGPIE_IMAGE_DATA_H - -// LOVE -#include "FormatHandler.h" -#include "image/ImageData.h" - -// C++ -#include - -namespace love -{ -namespace image -{ -namespace magpie -{ - -class ImageData : public love::image::ImageData -{ -public: - - ImageData(love::filesystem::FileData *data); - ImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8); - ImageData(int width, int height, PixelFormat format, void *data, bool own); - ImageData(const ImageData &c); - virtual ~ImageData(); - - // Implements image::ImageData. - virtual love::image::ImageData *clone() const; - virtual love::filesystem::FileData *encode(EncodedFormat encodedFormat, const char *filename, bool writefile); - -private: - - // Create imagedata. Initialize with data if not null. - void create(int width, int height, PixelFormat format, void *data = nullptr); - - // Decode and load an encoded format. - void decode(love::filesystem::FileData *data); - - // The format handler that was used to decode the ImageData. We need to know - // this so we can properly delete memory allocated by the decoder. - StrongRef decodeHandler; - -}; // ImageData - -} // magpie -} // image -} // love - -#endif // LOVE_IMAGE_MAGPIE_IMAGE_DATA_H diff --git a/src/modules/image/magpie/KTXHandler.cpp b/src/modules/image/magpie/KTXHandler.cpp index 3d5cd7f34..da88f157e 100644 --- a/src/modules/image/magpie/KTXHandler.cpp +++ b/src/modules/image/magpie/KTXHandler.cpp @@ -297,7 +297,7 @@ bool KTXHandler::canParse(const filesystem::FileData *data) return true; } -StrongRef KTXHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef KTXHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) { if (!canParse(filedata)) throw love::Exception("Could not decode compressed data (not a KTX file?)"); @@ -353,8 +353,8 @@ StrongRef KTXHandler::parse(filesystem::FileData *f fileoffset += mipsizepadded; } - StrongRef memory; - memory.set(new CompressedImageData::Memory(totalsize), Acquire::NORETAIN); + StrongRef memory; + memory.set(new CompressedMemory(totalsize), Acquire::NORETAIN); // Reset the file offset to the start of the file's image data. fileoffset = sizeof(KTXHeader) + header.bytesOfKeyValueData; @@ -377,7 +377,7 @@ StrongRef KTXHandler::parse(filesystem::FileData *f memcpy(memory->data + dataoffset, filebytes + fileoffset, mipsize); - auto slice = new CompressedImageData::Slice(cformat, width, height, memory, dataoffset, mipsize); + auto slice = new CompressedSlice(cformat, width, height, memory, dataoffset, mipsize); images.push_back(slice); slice->release(); diff --git a/src/modules/image/magpie/KTXHandler.h b/src/modules/image/magpie/KTXHandler.h index 965c7e3c0..71d8090e7 100644 --- a/src/modules/image/magpie/KTXHandler.h +++ b/src/modules/image/magpie/KTXHandler.h @@ -18,11 +18,10 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_KTX_HANDLER_H -#define LOVE_IMAGE_MAGPIE_KTX_HANDLER_H +#pragma once #include "common/config.h" -#include "CompressedFormatHandler.h" +#include "image/CompressedFormatHandler.h" namespace love { @@ -43,8 +42,8 @@ public: // Implements CompressedFormatHandler. bool canParse(const filesystem::FileData *data) override; - StrongRef parse(filesystem::FileData *filedata, - std::vector> &images, + StrongRef parse(filesystem::FileData *filedata, + std::vector> &images, PixelFormat &format, bool &sRGB) override; }; // KTXHandler @@ -52,5 +51,3 @@ public: } // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_KTX_HANDLER_H diff --git a/src/modules/image/magpie/PKMHandler.cpp b/src/modules/image/magpie/PKMHandler.cpp index 81c799780..f78c73333 100644 --- a/src/modules/image/magpie/PKMHandler.cpp +++ b/src/modules/image/magpie/PKMHandler.cpp @@ -113,7 +113,7 @@ bool PKMHandler::canParse(const filesystem::FileData *data) return true; } -StrongRef PKMHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef PKMHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) { if (!canParse(filedata)) throw love::Exception("Could not decode compressed data (not a PKM file?)"); @@ -134,8 +134,8 @@ StrongRef PKMHandler::parse(filesystem::FileData *f // The rest of the file after the header is all texture data. size_t totalsize = filedata->getSize() - sizeof(PKMHeader); - StrongRef memory; - memory.set(new CompressedImageData::Memory(totalsize), Acquire::NORETAIN); + StrongRef memory; + memory.set(new CompressedMemory(totalsize), Acquire::NORETAIN); // PKM files only store a single mipmap level. memcpy(memory->data, (uint8 *) filedata->getData() + sizeof(PKMHeader), totalsize); @@ -145,7 +145,7 @@ StrongRef PKMHandler::parse(filesystem::FileData *f int width = header.widthBig; int height = header.heightBig; - images.emplace_back(new CompressedImageData::Slice(cformat, width, height, memory, 0, totalsize), Acquire::NORETAIN); + images.emplace_back(new CompressedSlice(cformat, width, height, memory, 0, totalsize), Acquire::NORETAIN); format = cformat; sRGB = false; diff --git a/src/modules/image/magpie/PKMHandler.h b/src/modules/image/magpie/PKMHandler.h index deb13ef1a..1da404e35 100644 --- a/src/modules/image/magpie/PKMHandler.h +++ b/src/modules/image/magpie/PKMHandler.h @@ -18,11 +18,10 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_PKM_HANDLER_H -#define LOVE_IMAGE_MAGPIE_PKM_HANDLER_H +#pragma once #include "common/config.h" -#include "CompressedFormatHandler.h" +#include "image/CompressedFormatHandler.h" namespace love { @@ -43,8 +42,8 @@ public: // Implements CompressedFormatHandler. bool canParse(const filesystem::FileData *data) override; - StrongRef parse(filesystem::FileData *filedata, - std::vector> &images, + StrongRef parse(filesystem::FileData *filedata, + std::vector> &images, PixelFormat &format, bool &sRGB) override; }; // PKMHandler @@ -52,5 +51,3 @@ public: } // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_PKM_HANDLER_H diff --git a/src/modules/image/magpie/PNGHandler.cpp b/src/modules/image/magpie/PNGHandler.cpp index fe7b9968c..b0d3265bc 100644 --- a/src/modules/image/magpie/PNGHandler.cpp +++ b/src/modules/image/magpie/PNGHandler.cpp @@ -140,9 +140,9 @@ bool PNGHandler::canDecode(love::filesystem::FileData *data) return status == 0 && width > 0 && height > 0; } -bool PNGHandler::canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat) +bool PNGHandler::canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat) { - return encodedFormat == ImageData::ENCODED_PNG + return encodedFormat == ENCODED_PNG && (rawFormat == PIXELFORMAT_RGBA8 || rawFormat == PIXELFORMAT_RGBA16); } @@ -199,7 +199,7 @@ PNGHandler::DecodedImage PNGHandler::decode(love::filesystem::FileData *fdata) return img; } -PNGHandler::EncodedImage PNGHandler::encode(const DecodedImage &img, ImageData::EncodedFormat encodedFormat) +FormatHandler::EncodedImage PNGHandler::encode(const DecodedImage &img, EncodedFormat encodedFormat) { if (!canEncode(img.format, encodedFormat)) throw love::Exception("PNG encoder cannot encode to non-PNG format."); diff --git a/src/modules/image/magpie/PNGHandler.h b/src/modules/image/magpie/PNGHandler.h index c0cee564d..071cac8ba 100644 --- a/src/modules/image/magpie/PNGHandler.h +++ b/src/modules/image/magpie/PNGHandler.h @@ -18,11 +18,10 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_PNG_HANDLER_H -#define LOVE_IMAGE_MAGPIE_PNG_HANDLER_H +#pragma once // LOVE -#include "FormatHandler.h" +#include "image/FormatHandler.h" namespace love { @@ -41,10 +40,10 @@ public: // Implements FormatHandler. virtual bool canDecode(love::filesystem::FileData *data); - virtual bool canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat); + virtual bool canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat); virtual DecodedImage decode(love::filesystem::FileData *data); - virtual EncodedImage encode(const DecodedImage &img, ImageData::EncodedFormat format); + virtual EncodedImage encode(const DecodedImage &img, EncodedFormat format); virtual void free(unsigned char *mem); @@ -53,5 +52,3 @@ public: } // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_PNG_HANDLER_H diff --git a/src/modules/image/magpie/PVRHandler.cpp b/src/modules/image/magpie/PVRHandler.cpp index ca1d74359..3afec5748 100644 --- a/src/modules/image/magpie/PVRHandler.cpp +++ b/src/modules/image/magpie/PVRHandler.cpp @@ -474,7 +474,7 @@ bool PVRHandler::canParse(const filesystem::FileData *data) return false; } -StrongRef PVRHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef PVRHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) { if (!canParse(filedata)) throw love::Exception("Could not decode compressed data (not a PVR file?)"); @@ -524,8 +524,8 @@ StrongRef PVRHandler::parse(filesystem::FileData *f if (filedata->getSize() < fileoffset + totalsize) throw love::Exception("Could not parse PVR file: invalid size calculation."); - StrongRef memory; - memory.set(new CompressedImageData::Memory(totalsize), Acquire::NORETAIN); + StrongRef memory; + memory.set(new CompressedMemory(totalsize), Acquire::NORETAIN); size_t curoffset = 0; const uint8 *filebytes = (uint8 *) filedata->getData() + fileoffset; @@ -542,7 +542,7 @@ StrongRef PVRHandler::parse(filesystem::FileData *f memcpy(memory->data + curoffset, filebytes + curoffset, mipsize); - auto slice = new CompressedImageData::Slice(cformat, width, height, memory, curoffset, mipsize); + auto slice = new CompressedSlice(cformat, width, height, memory, curoffset, mipsize); images.push_back(slice); slice->release(); diff --git a/src/modules/image/magpie/PVRHandler.h b/src/modules/image/magpie/PVRHandler.h index 7cff3c24d..de06b7f73 100644 --- a/src/modules/image/magpie/PVRHandler.h +++ b/src/modules/image/magpie/PVRHandler.h @@ -18,12 +18,11 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_PVR_HANDLER_H -#define LOVE_IMAGE_MAGPIE_PVR_HANDLER_H +#pragma once // LOVE #include "common/config.h" -#include "CompressedFormatHandler.h" +#include "image/CompressedFormatHandler.h" namespace love { @@ -41,8 +40,8 @@ public: // Implements CompressedFormatHandler. bool canParse(const filesystem::FileData *data) override; - StrongRef parse(filesystem::FileData *filedata, - std::vector> &images, + StrongRef parse(filesystem::FileData *filedata, + std::vector> &images, PixelFormat &format, bool &sRGB) override; }; // PVRHandler @@ -50,5 +49,3 @@ public: } // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_PVR_HANDLER_H diff --git a/src/modules/image/magpie/STBHandler.cpp b/src/modules/image/magpie/STBHandler.cpp index f0eac3c43..279a83ad1 100644 --- a/src/modules/image/magpie/STBHandler.cpp +++ b/src/modules/image/magpie/STBHandler.cpp @@ -20,6 +20,7 @@ // LOVE #include "STBHandler.h" +#include "image/ImageData.h" static void loveSTBIAssert(bool test, const char *teststr) { @@ -60,9 +61,9 @@ bool STBHandler::canDecode(love::filesystem::FileData *data) return status == 1 && w > 0 && h > 0; } -bool STBHandler::canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat) +bool STBHandler::canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat) { - return encodedFormat == ImageData::ENCODED_TGA && rawFormat == PIXELFORMAT_RGBA8; + return encodedFormat == ENCODED_TGA && rawFormat == PIXELFORMAT_RGBA8; } FormatHandler::DecodedImage STBHandler::decode(love::filesystem::FileData *data) @@ -97,7 +98,7 @@ FormatHandler::DecodedImage STBHandler::decode(love::filesystem::FileData *data) return img; } -FormatHandler::EncodedImage STBHandler::encode(const DecodedImage &img, ImageData::EncodedFormat encodedFormat) +FormatHandler::EncodedImage STBHandler::encode(const DecodedImage &img, EncodedFormat encodedFormat) { if (!canEncode(img.format, encodedFormat)) throw love::Exception("Invalid format."); diff --git a/src/modules/image/magpie/STBHandler.h b/src/modules/image/magpie/STBHandler.h index 3605feba6..df2740623 100644 --- a/src/modules/image/magpie/STBHandler.h +++ b/src/modules/image/magpie/STBHandler.h @@ -18,10 +18,9 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_STB_HANDLER_H -#define LOVE_IMAGE_MAGPIE_STB_HANDLER_H +#pragma once -#include "FormatHandler.h" +#include "image/FormatHandler.h" namespace love { @@ -37,24 +36,22 @@ namespace magpie * We could use stb_image to decode PNG as well, but performance and * comprehensive format support is lacking compared to some alternatives. **/ -class STBHandler : public FormatHandler +class STBHandler final : public FormatHandler { public: // Implements FormatHandler. - virtual bool canDecode(love::filesystem::FileData *data); - virtual bool canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat); + bool canDecode(love::filesystem::FileData *data) override; + bool canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat) override; - virtual DecodedImage decode(love::filesystem::FileData *data); - virtual EncodedImage encode(const DecodedImage &img, ImageData::EncodedFormat format); + DecodedImage decode(love::filesystem::FileData *data) override; + EncodedImage encode(const DecodedImage &img, EncodedFormat format) override; - virtual void free(unsigned char *mem); + void free(unsigned char *mem) override; }; // STBHandler } // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_STB_HANDLER_H diff --git a/src/modules/image/magpie/ddsHandler.cpp b/src/modules/image/magpie/ddsHandler.cpp index 400239e13..caa3896e7 100644 --- a/src/modules/image/magpie/ddsHandler.cpp +++ b/src/modules/image/magpie/ddsHandler.cpp @@ -32,7 +32,7 @@ bool DDSHandler::canParse(const filesystem::FileData *data) return dds::isCompressedDDS(data->getData(), data->getSize()); } -StrongRef DDSHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef DDSHandler::parse(filesystem::FileData *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) { if (!dds::isDDS(filedata->getData(), filedata->getSize())) throw love::Exception("Could not decode compressed data (not a DDS file?)"); @@ -40,7 +40,7 @@ StrongRef DDSHandler::parse(filesystem::FileData *f PixelFormat texformat = PIXELFORMAT_UNKNOWN; bool isSRGB = false; - StrongRef memory; + StrongRef memory; size_t dataSize = 0; images.clear(); @@ -63,7 +63,7 @@ StrongRef DDSHandler::parse(filesystem::FileData *f dataSize += img->dataSize; } - memory.set(new CompressedImageData::Memory(dataSize), Acquire::NORETAIN); + memory.set(new CompressedMemory(dataSize), Acquire::NORETAIN); size_t dataOffset = 0; @@ -76,7 +76,7 @@ StrongRef DDSHandler::parse(filesystem::FileData *f // Copy the mipmap image from the FileData to our block of memory. memcpy(memory->data + dataOffset, img->data, img->dataSize); - auto slice = new CompressedImageData::Slice(texformat, img->width, img->height, memory, dataOffset, img->dataSize); + auto slice = new CompressedSlice(texformat, img->width, img->height, memory, dataOffset, img->dataSize); images.emplace_back(slice, Acquire::NORETAIN); dataOffset += img->dataSize; diff --git a/src/modules/image/magpie/ddsHandler.h b/src/modules/image/magpie/ddsHandler.h index fde057729..a875e055f 100644 --- a/src/modules/image/magpie/ddsHandler.h +++ b/src/modules/image/magpie/ddsHandler.h @@ -18,11 +18,10 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_IMAGE_MAGPIE_DDS_HANDLER_H -#define LOVE_IMAGE_MAGPIE_DDS_HANDLER_H +#pragma once // LOVE -#include "CompressedFormatHandler.h" +#include "image/CompressedFormatHandler.h" // dds parser #include "ddsparse/ddsparse.h" @@ -49,8 +48,8 @@ public: // Implements CompressedFormatHandler. bool canParse(const filesystem::FileData *data) override; - StrongRef parse(filesystem::FileData *filedata, - std::vector> &images, + StrongRef parse(filesystem::FileData *filedata, + std::vector> &images, PixelFormat &format, bool &sRGB) override; private: @@ -62,5 +61,3 @@ private: } // magpie } // image } // love - -#endif // LOVE_IMAGE_MAGPIE_DDS_HANDLER_H diff --git a/src/modules/image/wrap_Image.cpp b/src/modules/image/wrap_Image.cpp index 3456fe76f..d42dea40c 100644 --- a/src/modules/image/wrap_Image.cpp +++ b/src/modules/image/wrap_Image.cpp @@ -23,7 +23,7 @@ #include "common/Data.h" #include "common/StringMap.h" -#include "magpie/Image.h" +#include "Image.h" #include "filesystem/wrap_Filesystem.h" @@ -154,7 +154,7 @@ extern "C" int luaopen_love_image(lua_State *L) Image *instance = instance(); if (instance == nullptr) { - luax_catchexcept(L, [&](){ instance = new love::image::magpie::Image(); }); + luax_catchexcept(L, [&](){ instance = new love::image::Image(); }); } else instance->retain(); diff --git a/src/modules/image/wrap_ImageData.cpp b/src/modules/image/wrap_ImageData.cpp index dd33d5faf..83785eba6 100644 --- a/src/modules/image/wrap_ImageData.cpp +++ b/src/modules/image/wrap_ImageData.cpp @@ -262,7 +262,7 @@ int w_ImageData_encode(lua_State *L) { ImageData *t = luax_checkimagedata(L, 1); - ImageData::EncodedFormat format; + FormatHandler::EncodedFormat format; const char *fmt = luaL_checkstring(L, 2); if (!ImageData::getConstant(fmt, format)) return luaL_error(L, "Invalid encoded image format '%s'.", fmt); From c11a4250e8b70e8ee6b3bc19188dca9eb04e95f7 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 1 Aug 2017 23:24:20 -0300 Subject: [PATCH 35/36] Fix CMakeLists.txt --HG-- branch : minor --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ad8b14b1..593e28a3a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -603,8 +603,6 @@ set(LOVE_SRC_MODULE_IMAGE_MAGPIE src/modules/image/magpie/ddsHandler.h src/modules/image/magpie/EXRHandler.cpp src/modules/image/magpie/EXRHandler.h - src/modules/image/magpie/ImageData.cpp - src/modules/image/magpie/ImageData.h src/modules/image/magpie/KTXHandler.cpp src/modules/image/magpie/KTXHandler.h src/modules/image/magpie/PKMHandler.cpp From b129d49a6c65b2ef58b65576171c10a58d197b5e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 1 Aug 2017 23:53:44 -0300 Subject: [PATCH 36/36] Move Color.h from modules/graphics/ to common/ --HG-- branch : minor --- CMakeLists.txt | 2 +- .../xcode/liblove.xcodeproj/project.pbxproj | 8 +++---- src/{modules/graphics => common}/Color.h | 9 +++----- src/modules/font/BMFontRasterizer.cpp | 20 ++++++++++-------- src/modules/font/ImageRasterizer.cpp | 21 ++++++++----------- src/modules/font/ImageRasterizer.h | 4 ++-- src/modules/graphics/Graphics.h | 2 +- src/modules/graphics/ParticleSystem.h | 2 +- src/modules/graphics/SpriteBatch.h | 2 +- src/modules/graphics/opengl/Canvas.h | 2 +- src/modules/graphics/opengl/Graphics.h | 2 +- src/modules/graphics/opengl/OpenGL.h | 2 +- src/modules/graphics/vertex.h | 2 +- src/modules/image/ImageData.h | 7 ------- src/modules/image/magpie/STBHandler.cpp | 5 ++++- 15 files changed, 41 insertions(+), 49 deletions(-) rename src/{modules/graphics => common}/Color.h (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 593e28a3a..96a108fca 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,6 +255,7 @@ endfunction() set(LOVE_SRC_COMMON src/common/b64.cpp src/common/b64.h + src/common/Color.h src/common/config.h src/common/Data.cpp src/common/Data.h @@ -474,7 +475,6 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT src/modules/graphics/Buffer.h src/modules/graphics/Canvas.cpp src/modules/graphics/Canvas.h - src/modules/graphics/Color.h src/modules/graphics/depthstencil.cpp src/modules/graphics/depthstencil.h src/modules/graphics/Drawable.cpp diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 908b11b0f..70de09544 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -415,7 +415,6 @@ FA0B7D2B1A95902C000E1D17 /* wrap_Rasterizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B851A95902C000E1D17 /* wrap_Rasterizer.cpp */; }; FA0B7D2C1A95902C000E1D17 /* wrap_Rasterizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B851A95902C000E1D17 /* wrap_Rasterizer.cpp */; }; FA0B7D2D1A95902C000E1D17 /* wrap_Rasterizer.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7B861A95902C000E1D17 /* wrap_Rasterizer.h */; }; - FA0B7D2E1A95902C000E1D17 /* Color.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7B881A95902C000E1D17 /* Color.h */; }; FA0B7D2F1A95902C000E1D17 /* Drawable.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7B891A95902C000E1D17 /* Drawable.h */; }; FA0B7D301A95902C000E1D17 /* Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */; }; FA0B7D311A95902C000E1D17 /* Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */; }; @@ -925,6 +924,7 @@ FA620A371AA2F8DB005DB4C2 /* wrap_Texture.h in Headers */ = {isa = PBXBuildFile; fileRef = FA620A311AA2F8DB005DB4C2 /* wrap_Texture.h */; }; FA620A3A1AA305F6005DB4C2 /* types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA620A391AA305F6005DB4C2 /* types.cpp */; }; FA620A3B1AA305F6005DB4C2 /* types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA620A391AA305F6005DB4C2 /* types.cpp */; }; + FA6BDE5C1F31725300786805 /* Color.h in Headers */ = {isa = PBXBuildFile; fileRef = FA6BDE5B1F31725300786805 /* Color.h */; }; FA7550A81AEBE276003E311E /* libluajit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FA7550A71AEBE276003E311E /* libluajit.a */; }; FA76344A1E28722A0066EF9E /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7634481E28722A0066EF9E /* StreamBuffer.cpp */; }; FA76344B1E28722A0066EF9E /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7634481E28722A0066EF9E /* StreamBuffer.cpp */; }; @@ -1439,7 +1439,6 @@ FA0B7B841A95902C000E1D17 /* wrap_GlyphData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_GlyphData.h; sourceTree = ""; }; FA0B7B851A95902C000E1D17 /* wrap_Rasterizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Rasterizer.cpp; sourceTree = ""; }; FA0B7B861A95902C000E1D17 /* wrap_Rasterizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Rasterizer.h; sourceTree = ""; }; - FA0B7B881A95902C000E1D17 /* Color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Color.h; sourceTree = ""; }; FA0B7B891A95902C000E1D17 /* Drawable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Drawable.h; sourceTree = ""; }; FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Graphics.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; FA0B7B8B1A95902C000E1D17 /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = ""; }; @@ -1785,6 +1784,7 @@ FA620A301AA2F8DB005DB4C2 /* wrap_Texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Texture.cpp; sourceTree = ""; }; FA620A311AA2F8DB005DB4C2 /* wrap_Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Texture.h; sourceTree = ""; }; FA620A391AA305F6005DB4C2 /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = ""; }; + FA6BDE5B1F31725300786805 /* Color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Color.h; sourceTree = ""; }; FA7550A71AEBE276003E311E /* libluajit.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libluajit.a; sourceTree = ""; }; FA7634481E28722A0066EF9E /* StreamBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StreamBuffer.cpp; sourceTree = ""; }; FA7634491E28722A0066EF9E /* StreamBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StreamBuffer.h; sourceTree = ""; }; @@ -2019,6 +2019,7 @@ FAA3A9AD1B7D465A00CED060 /* android.h */, FA0B78F71A958E3B000E1D17 /* b64.cpp */, FA0B78F81A958E3B000E1D17 /* b64.h */, + FA6BDE5B1F31725300786805 /* Color.h */, FA0B78F91A958E3B000E1D17 /* config.h */, FA9D8DD41DEF8411002CD881 /* Data.cpp */, FA0B78FA1A958E3B000E1D17 /* Data.h */, @@ -2650,7 +2651,6 @@ FADF53F71E3C7ACD00012CC0 /* Buffer.h */, FA1BA0A51E16F20600AA2803 /* Canvas.cpp */, FA1BA0A61E16F20600AA2803 /* Canvas.h */, - FA0B7B881A95902C000E1D17 /* Color.h */, FAF1889E1E9DBC4B008C1479 /* depthstencil.cpp */, FAF1889D1E9DBBC8008C1479 /* depthstencil.h */, FA9D8DDC1DEF842A002CD881 /* Drawable.cpp */, @@ -3655,6 +3655,7 @@ FA0B7E771A95902C000E1D17 /* wrap_WeldJoint.h in Headers */, FA0B7A911A958EA3000E1D17 /* b2FrictionJoint.h in Headers */, FA0B7E291A95902C000E1D17 /* PulleyJoint.h in Headers */, + FA6BDE5C1F31725300786805 /* Color.h in Headers */, FA0B7D471A95902C000E1D17 /* ParticleSystem.h in Headers */, FA0B7E231A95902C000E1D17 /* PolygonShape.h in Headers */, FA0B791E1A958E3B000E1D17 /* config.h in Headers */, @@ -3861,7 +3862,6 @@ FA9D8DD31DEB56C3002CD881 /* pixelformat.h in Headers */, FAF140A61E20934C00F898D2 /* ScanContext.h in Headers */, FA0B7E4A1A95902C000E1D17 /* wrap_DistanceJoint.h in Headers */, - FA0B7D2E1A95902C000E1D17 /* Color.h in Headers */, FA0B7A6A1A958EA3000E1D17 /* b2TimeStep.h in Headers */, FA0B7A281A958EA3000E1D17 /* Box2D.h in Headers */, FA0B7DE41A95902C000E1D17 /* wrap_RandomGenerator.h in Headers */, diff --git a/src/modules/graphics/Color.h b/src/common/Color.h similarity index 96% rename from src/modules/graphics/Color.h rename to src/common/Color.h index 16d7db990..3b827809c 100644 --- a/src/modules/graphics/Color.h +++ b/src/common/Color.h @@ -18,13 +18,11 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_GRAPHICS_COLOR_H -#define LOVE_GRAPHICS_COLOR_H +#ifndef LOVE_COLOR_H +#define LOVE_COLOR_H namespace love { -namespace graphics -{ template struct ColorT @@ -153,7 +151,6 @@ inline Colorf toColorf(Color c) return Colorf(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f, c.a / 255.0f); } -} // graphics } // love -#endif // LOVE_GRAPHICS_COLOR_H +#endif // LOVE_COLOR_H diff --git a/src/modules/font/BMFontRasterizer.cpp b/src/modules/font/BMFontRasterizer.cpp index a6b0a2940..2a66ff300 100644 --- a/src/modules/font/BMFontRasterizer.cpp +++ b/src/modules/font/BMFontRasterizer.cpp @@ -146,7 +146,12 @@ BMFontRasterizer::BMFontRasterizer(love::filesystem::FileData *fontdef, const st // The parseConfig function will try to load any missing page images. for (int i = 0; i < (int) imagelist.size(); i++) + { + if (imagelist[i]->getFormat() != PIXELFORMAT_RGBA8) + throw love::Exception("Only 32-bit RGBA images are supported in BMFonts."); + images[i] = imagelist[i]; + } std::string configtext((const char *) fontdef->getData(), fontdef->getSize()); @@ -296,29 +301,26 @@ GlyphData *BMFontRasterizer::getGlyphData(uint32 glyph) const return new GlyphData(glyph, GlyphMetrics(), PIXELFORMAT_RGBA8); const BMFontCharacter &c = it->second; - GlyphData *g = new GlyphData(glyph, c.metrics, PIXELFORMAT_RGBA8); - const auto &imagepair = images.find(c.page); if (imagepair == images.end()) - { - g->release(); return new GlyphData(glyph, GlyphMetrics(), PIXELFORMAT_RGBA8); - } image::ImageData *imagedata = imagepair->second.get(); + GlyphData *g = new GlyphData(glyph, c.metrics, PIXELFORMAT_RGBA8); size_t pixelsize = imagedata->getPixelSize(); - image::pixel *pixels = (image::pixel *) g->getData(); - const image::pixel *ipixels = (const image::pixel *) imagedata->getData(); + + uint8 *pixels = (uint8 *) g->getData(); + const uint8 *ipixels = (const uint8 *) imagedata->getData(); love::thread::Lock lock(imagedata->getMutex()); // Copy the subsection of the texture from the ImageData to the GlyphData. for (int y = 0; y < c.metrics.height; y++) { - size_t idindex = (c.y + y) * imagedata->getWidth() + c.x; - memcpy(&pixels[y * c.metrics.width], &ipixels[idindex], pixelsize * c.metrics.width); + size_t idindex = ((c.y + y) * imagedata->getWidth() + c.x) * pixelsize; + memcpy(&pixels[y * c.metrics.width * pixelsize], &ipixels[idindex], pixelsize * c.metrics.width); } return g; diff --git a/src/modules/font/ImageRasterizer.cpp b/src/modules/font/ImageRasterizer.cpp index 4211ace4c..00507a00f 100644 --- a/src/modules/font/ImageRasterizer.cpp +++ b/src/modules/font/ImageRasterizer.cpp @@ -29,10 +29,7 @@ namespace love namespace font { -inline bool equal(const love::image::pixel &a, const love::image::pixel &b) -{ - return (a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a); -} +static_assert(sizeof(Color) == 4, "sizeof(Color) must equal 4 bytes!"); ImageRasterizer::ImageRasterizer(love::image::ImageData *data, uint32 *glyphs, int numglyphs, int extraspacing, float pixeldensity) : imageData(data) @@ -79,17 +76,17 @@ GlyphData *ImageRasterizer::getGlyphData(uint32 glyph) const // We don't want another thread modifying our ImageData mid-copy. love::thread::Lock lock(imageData->getMutex()); - love::image::pixel *gdpixels = (love::image::pixel *) g->getData(); - love::image::pixel *imagepixels = (love::image::pixel *) imageData->getData(); + Color *gdpixels = (Color *) g->getData(); + const Color *imagepixels = (const Color *) imageData->getData(); // copy glyph pixels from imagedata to glyphdata for (int i = 0; i < g->getWidth() * g->getHeight(); i++) { - love::image::pixel p = imagepixels[it->second.x + (i % gm.width) + (imageData->getWidth() * (i / gm.width))]; + Color p = imagepixels[it->second.x + (i % gm.width) + (imageData->getWidth() * (i / gm.width))]; // Use transparency instead of the spacer color - if (equal(p, spacer)) - gdpixels[i].r = gdpixels[i].g = gdpixels[i].b = gdpixels[i].a = 0; + if (p == spacer) + gdpixels[i] = Color(0, 0, 0, 0); else gdpixels[i] = p; } @@ -99,7 +96,7 @@ GlyphData *ImageRasterizer::getGlyphData(uint32 glyph) const void ImageRasterizer::load() { - love::image::pixel *pixels = (love::image::pixel *) imageData->getData(); + const Color *pixels = (const Color *) imageData->getData(); int imgw = imageData->getWidth(); int imgh = imageData->getHeight(); @@ -121,13 +118,13 @@ void ImageRasterizer::load() start = end; // Finds out where the first character starts - while (start < imgw && equal(pixels[start], spacer)) + while (start < imgw && pixels[start] == spacer) ++start; end = start; // Find where glyph ends. - while (end < imgw && !equal(pixels[end], spacer)) + while (end < imgw && pixels[end] != spacer) ++end; if (start >= end) diff --git a/src/modules/font/ImageRasterizer.h b/src/modules/font/ImageRasterizer.h index 35dc0981c..8b4d5aba2 100644 --- a/src/modules/font/ImageRasterizer.h +++ b/src/modules/font/ImageRasterizer.h @@ -22,9 +22,9 @@ #define LOVE_FONT_IMAGE_RASTERIZER_H // LOVE -#include "filesystem/File.h" #include "font/Rasterizer.h" #include "image/ImageData.h" +#include "common/Color.h" #include @@ -76,7 +76,7 @@ private: std::map imageGlyphs; // Color used to identify glyph separation in the source ImageData - love::image::pixel spacer; + Color spacer; }; // ImageRasterizer diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 24f5d88ca..85c6e79a2 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -28,9 +28,9 @@ #include "common/Vector.h" #include "common/Optional.h" #include "common/int.h" +#include "common/Color.h" #include "StreamBuffer.h" #include "vertex.h" -#include "Color.h" #include "Texture.h" #include "Canvas.h" #include "Font.h" diff --git a/src/modules/graphics/ParticleSystem.h b/src/modules/graphics/ParticleSystem.h index 547fe54eb..6e9f3ec94 100644 --- a/src/modules/graphics/ParticleSystem.h +++ b/src/modules/graphics/ParticleSystem.h @@ -25,8 +25,8 @@ #include "common/int.h" #include "common/math.h" #include "common/Vector.h" +#include "common/Color.h" #include "Drawable.h" -#include "Color.h" #include "Quad.h" #include "Texture.h" #include "Buffer.h" diff --git a/src/modules/graphics/SpriteBatch.h b/src/modules/graphics/SpriteBatch.h index bf1d3f82a..3a25c264f 100644 --- a/src/modules/graphics/SpriteBatch.h +++ b/src/modules/graphics/SpriteBatch.h @@ -29,8 +29,8 @@ // LOVE #include "common/math.h" #include "common/Matrix.h" +#include "common/Color.h" #include "Drawable.h" -#include "Color.h" #include "Mesh.h" #include "vertex.h" diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 71010184d..cbb5d2b5a 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -22,7 +22,7 @@ #define LOVE_GRAPHICS_OPENGL_CANVAS_H #include "common/config.h" -#include "graphics/Color.h" +#include "common/Color.h" #include "common/int.h" #include "graphics/Canvas.h" #include "graphics/Volatile.h" diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 02ca81bb9..92efe3344 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -31,7 +31,7 @@ // LOVE #include "graphics/Graphics.h" -#include "graphics/Color.h" +#include "common/Color.h" #include "image/Image.h" #include "image/ImageData.h" diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index a5c62101b..034bbc885 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -25,7 +25,7 @@ #include "common/config.h" #include "common/int.h" #include "common/math.h" -#include "graphics/Color.h" +#include "common/Color.h" #include "graphics/Texture.h" #include "graphics/vertex.h" #include "graphics/depthstencil.h" diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index ff8e43a1e..b41300d46 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -22,7 +22,7 @@ // LOVE #include "common/int.h" -#include "Color.h" +#include "common/Color.h" // C #include diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index 21f654534..a12355b8e 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -38,13 +38,6 @@ namespace love namespace image { -// Pixel format structure. -struct pixel -{ - // Red, green, blue, alpha. - unsigned char r, g, b, a; -}; - union Pixel { uint8 rgba8[4]; diff --git a/src/modules/image/magpie/STBHandler.cpp b/src/modules/image/magpie/STBHandler.cpp index 279a83ad1..a9f782b3f 100644 --- a/src/modules/image/magpie/STBHandler.cpp +++ b/src/modules/image/magpie/STBHandler.cpp @@ -21,6 +21,7 @@ // LOVE #include "STBHandler.h" #include "image/ImageData.h" +#include "common/Color.h" static void loveSTBIAssert(bool test, const char *teststr) { @@ -49,6 +50,8 @@ namespace image namespace magpie { +static_assert(sizeof(Color) == 4, "sizeof(Color) must equal 4 bytes!"); + bool STBHandler::canDecode(love::filesystem::FileData *data) { int w = 0; @@ -144,7 +147,7 @@ FormatHandler::EncodedImage STBHandler::encode(const DecodedImage &img, EncodedF memcpy(encimg.data + headerlen, img.data, img.width * img.height * bpp); // convert the pixels from RGBA to BGRA. - pixel *encodedpixels = (pixel *) (encimg.data + headerlen); + Color *encodedpixels = (Color *) (encimg.data + headerlen); for (int y = 0; y < img.height; y++) { for (int x = 0; x < img.width; x++)