mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
Merge minor into dynamiccore2
--HG-- branch : dynamiccore2
This commit is contained in:
@@ -10,3 +10,4 @@ e0f98d53debb62347c6433ca0534a0f77f15f76f 0.8.0
|
||||
a5e405cdf14d030b71d09a105086797942ae91a9 0.9.2
|
||||
14717f0fb5d96d380c10fe6f41b74b7652c7d836 0.10.0
|
||||
3cb3559eebb89803c0b7fa83d51d8e48a2b20b7a 0.10.1
|
||||
afc69c4f714534c64e6f8c8660b724b5b736d7f3 0.10.2
|
||||
|
||||
@@ -309,10 +309,14 @@ set(LOVE_SRC_MODULE_AUDIO_ROOT
|
||||
src/modules/audio/Audio.h
|
||||
src/modules/audio/Source.cpp
|
||||
src/modules/audio/Source.h
|
||||
src/modules/audio/RecordingDevice.cpp
|
||||
src/modules/audio/RecordingDevice.h
|
||||
src/modules/audio/wrap_Audio.cpp
|
||||
src/modules/audio/wrap_Audio.h
|
||||
src/modules/audio/wrap_Source.cpp
|
||||
src/modules/audio/wrap_Source.h
|
||||
src/modules/audio/wrap_RecordingDevice.cpp
|
||||
src/modules/audio/wrap_RecordingDevice.h
|
||||
)
|
||||
|
||||
set(LOVE_SRC_MODULE_AUDIO_NULL
|
||||
@@ -320,6 +324,8 @@ set(LOVE_SRC_MODULE_AUDIO_NULL
|
||||
src/modules/audio/null/Audio.h
|
||||
src/modules/audio/null/Source.cpp
|
||||
src/modules/audio/null/Source.h
|
||||
src/modules/audio/null/RecordingDevice.cpp
|
||||
src/modules/audio/null/RecordingDevice.h
|
||||
)
|
||||
|
||||
set(LOVE_SRC_MODULE_AUDIO_OPENAL
|
||||
@@ -329,6 +335,8 @@ set(LOVE_SRC_MODULE_AUDIO_OPENAL
|
||||
src/modules/audio/openal/Pool.h
|
||||
src/modules/audio/openal/Source.cpp
|
||||
src/modules/audio/openal/Source.h
|
||||
src/modules/audio/openal/RecordingDevice.cpp
|
||||
src/modules/audio/openal/RecordingDevice.h
|
||||
)
|
||||
|
||||
set(LOVE_SRC_MODULE_AUDIO
|
||||
@@ -647,6 +655,8 @@ set(LOVE_SRC_MODULE_MATH
|
||||
src/modules/math/MathModule.h
|
||||
src/modules/math/RandomGenerator.cpp
|
||||
src/modules/math/RandomGenerator.h
|
||||
src/modules/math/Transform.cpp
|
||||
src/modules/math/Transform.h
|
||||
src/modules/math/wrap_BezierCurve.cpp
|
||||
src/modules/math/wrap_BezierCurve.h
|
||||
src/modules/math/wrap_CompressedData.cpp
|
||||
@@ -655,6 +665,8 @@ set(LOVE_SRC_MODULE_MATH
|
||||
src/modules/math/wrap_Math.h
|
||||
src/modules/math/wrap_RandomGenerator.cpp
|
||||
src/modules/math/wrap_RandomGenerator.h
|
||||
src/modules/math/wrap_Transform.cpp
|
||||
src/modules/math/wrap_Transform.h
|
||||
)
|
||||
|
||||
source_group("modules\\math" FILES ${LOVE_SRC_MODULE_MATH})
|
||||
@@ -1418,6 +1430,17 @@ set(LOVE_SRC_3P_WUFF
|
||||
|
||||
add_library(love_3p_wuff ${LOVE_SRC_3P_WUFF})
|
||||
|
||||
#
|
||||
# xxHash
|
||||
#
|
||||
|
||||
set(LOVE_SRC_3P_XXHASH
|
||||
src/libraries/xxHash/xxhash.c
|
||||
src/libraries/xxHash/xxhash.h
|
||||
)
|
||||
|
||||
add_library(love_3p_xxhash ${LOVE_SRC_3P_XXHASH})
|
||||
|
||||
set(LOVE_3P
|
||||
love_3p_box2d
|
||||
love_3p_ddsparse
|
||||
@@ -1429,6 +1452,7 @@ set(LOVE_3P
|
||||
love_3p_lz4
|
||||
love_3p_noise1234
|
||||
love_3p_wuff
|
||||
love_3p_xxhash
|
||||
)
|
||||
|
||||
love_disable_warnings(love_3p_box2d love_3p_enet love_3p_luasocket)
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ Released: N/A
|
||||
LOVE 0.10.2 [Super Toast]
|
||||
-------------------------
|
||||
|
||||
Released: N/A
|
||||
Released: 2016-10-31
|
||||
|
||||
* Added lovec.exe in Windows. It is the same as love.exe but built with the Console subsystem, so it always uses or provides a console.
|
||||
* Added the ability to restart the game via love.event.quit("restart").
|
||||
|
||||
@@ -880,6 +880,45 @@
|
||||
FA4943551D9DDFFE00E8D38A /* HashFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1DC2611C5D9555008F99A0 /* HashFunction.cpp */; };
|
||||
FA4B66C91ABBCF1900558F15 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4B66C81ABBCF1900558F15 /* Timer.cpp */; };
|
||||
FA4B66CA1ABBCF1900558F15 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4B66C81ABBCF1900558F15 /* Timer.cpp */; };
|
||||
FA4F2B791DE0125B00CA37D7 /* xxhash.c in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2B771DE0125B00CA37D7 /* xxhash.c */; };
|
||||
FA4F2B7A1DE0125B00CA37D7 /* xxhash.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4F2B781DE0125B00CA37D7 /* xxhash.h */; };
|
||||
FA4F2B7B1DE0181B00CA37D7 /* xxhash.c in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2B771DE0125B00CA37D7 /* xxhash.c */; };
|
||||
FA4F2BA61DE1E36400CA37D7 /* RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BA21DE1E36400CA37D7 /* RecordingDevice.cpp */; };
|
||||
FA4F2BA71DE1E36400CA37D7 /* RecordingDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4F2BA31DE1E36400CA37D7 /* RecordingDevice.h */; };
|
||||
FA4F2BA81DE1E36400CA37D7 /* wrap_RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BA41DE1E36400CA37D7 /* wrap_RecordingDevice.cpp */; };
|
||||
FA4F2BA91DE1E36400CA37D7 /* wrap_RecordingDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4F2BA51DE1E36400CA37D7 /* wrap_RecordingDevice.h */; };
|
||||
FA4F2BAC1DE1E37000CA37D7 /* RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BAA1DE1E37000CA37D7 /* RecordingDevice.cpp */; };
|
||||
FA4F2BAD1DE1E37000CA37D7 /* RecordingDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4F2BAB1DE1E37000CA37D7 /* RecordingDevice.h */; };
|
||||
FA4F2BB01DE1E37B00CA37D7 /* RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BAE1DE1E37B00CA37D7 /* RecordingDevice.cpp */; };
|
||||
FA4F2BB11DE1E37B00CA37D7 /* RecordingDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4F2BAF1DE1E37B00CA37D7 /* RecordingDevice.h */; };
|
||||
FA4F2BB21DE1E4B400CA37D7 /* RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BAE1DE1E37B00CA37D7 /* RecordingDevice.cpp */; };
|
||||
FA4F2BB31DE1E4B800CA37D7 /* RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BA21DE1E36400CA37D7 /* RecordingDevice.cpp */; };
|
||||
FA4F2BB41DE1E4BD00CA37D7 /* RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BAA1DE1E37000CA37D7 /* RecordingDevice.cpp */; };
|
||||
FA4F2BB51DE1E4C300CA37D7 /* wrap_RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BA41DE1E36400CA37D7 /* wrap_RecordingDevice.cpp */; };
|
||||
FA4F2BE31DE6650600CA37D7 /* Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BDF1DE6650600CA37D7 /* Transform.cpp */; };
|
||||
FA4F2BE41DE6650600CA37D7 /* Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4F2BE01DE6650600CA37D7 /* Transform.h */; };
|
||||
FA4F2BE51DE6650600CA37D7 /* wrap_Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BE11DE6650600CA37D7 /* wrap_Transform.cpp */; };
|
||||
FA4F2BE61DE6650600CA37D7 /* wrap_Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4F2BE21DE6650600CA37D7 /* wrap_Transform.h */; };
|
||||
FA4F2BE71DE6650D00CA37D7 /* Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BDF1DE6650600CA37D7 /* Transform.cpp */; };
|
||||
FA4F2BE81DE6651000CA37D7 /* wrap_Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BE11DE6650600CA37D7 /* wrap_Transform.cpp */; };
|
||||
FA4F2C031DE936C200CA37D7 /* auxiliar.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFB9D1D9F6D490055D849 /* auxiliar.c */; };
|
||||
FA4F2C041DE936C600CA37D7 /* buffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFB9F1D9F6D490055D849 /* buffer.c */; };
|
||||
FA4F2C051DE936C900CA37D7 /* compat.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBA11D9F6D490055D849 /* compat.c */; };
|
||||
FA4F2C061DE936CD00CA37D7 /* except.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBA31D9F6D490055D849 /* except.c */; };
|
||||
FA4F2C071DE936DA00CA37D7 /* inet.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBAB1D9F6D490055D849 /* inet.c */; };
|
||||
FA4F2C081DE936DD00CA37D7 /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBAD1D9F6D490055D849 /* io.c */; };
|
||||
FA4F2C091DE936E200CA37D7 /* luasocket.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBB11D9F6D490055D849 /* luasocket.c */; };
|
||||
FA4F2C0A1DE936E600CA37D7 /* mime.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBB61D9F6D490055D849 /* mime.c */; };
|
||||
FA4F2C0B1DE936EA00CA37D7 /* options.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBBA1D9F6D490055D849 /* options.c */; };
|
||||
FA4F2C0C1DE936ED00CA37D7 /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBBD1D9F6D490055D849 /* select.c */; };
|
||||
FA4F2C0D1DE936F100CA37D7 /* serial.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBBF1D9F6D490055D849 /* serial.c */; };
|
||||
FA4F2C0E1DE936FE00CA37D7 /* tcp.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBC51D9F6D490055D849 /* tcp.c */; };
|
||||
FA4F2C0F1DE936FE00CA37D7 /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBC71D9F6D490055D849 /* timeout.c */; };
|
||||
FA4F2C101DE936FE00CA37D7 /* udp.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBCB1D9F6D490055D849 /* udp.c */; };
|
||||
FA4F2C111DE936FE00CA37D7 /* unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBCD1D9F6D490055D849 /* unix.c */; };
|
||||
FA4F2C121DE936FE00CA37D7 /* unixtcp.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBCF1D9F6D490055D849 /* unixtcp.c */; };
|
||||
FA4F2C131DE936FE00CA37D7 /* unixudp.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBD11D9F6D490055D849 /* unixudp.c */; };
|
||||
FA4F2C141DE936FE00CA37D7 /* usocket.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBD51D9F6D490055D849 /* usocket.c */; };
|
||||
FA56D9BC1C208A0200D8D3C7 /* libmodplug.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FA56D9BA1C2089EE00D8D3C7 /* libmodplug.a */; };
|
||||
FA577AB016C7507900860150 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7916C71A1700860150 /* Cocoa.framework */; };
|
||||
FA577AC216C7512D00860150 /* FreeType.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A6716C719D900860150 /* FreeType.framework */; };
|
||||
@@ -1575,6 +1614,20 @@
|
||||
FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTCHandler.cpp; sourceTree = "<group>"; };
|
||||
FA41A3C71C0A1F950084430C /* ASTCHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTCHandler.h; sourceTree = "<group>"; };
|
||||
FA4B66C81ABBCF1900558F15 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = "<group>"; };
|
||||
FA4F2B771DE0125B00CA37D7 /* xxhash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xxhash.c; sourceTree = "<group>"; };
|
||||
FA4F2B781DE0125B00CA37D7 /* xxhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xxhash.h; sourceTree = "<group>"; };
|
||||
FA4F2BA21DE1E36400CA37D7 /* RecordingDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordingDevice.cpp; sourceTree = "<group>"; };
|
||||
FA4F2BA31DE1E36400CA37D7 /* RecordingDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingDevice.h; sourceTree = "<group>"; };
|
||||
FA4F2BA41DE1E36400CA37D7 /* wrap_RecordingDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_RecordingDevice.cpp; sourceTree = "<group>"; };
|
||||
FA4F2BA51DE1E36400CA37D7 /* wrap_RecordingDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_RecordingDevice.h; sourceTree = "<group>"; };
|
||||
FA4F2BAA1DE1E37000CA37D7 /* RecordingDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordingDevice.cpp; sourceTree = "<group>"; };
|
||||
FA4F2BAB1DE1E37000CA37D7 /* RecordingDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingDevice.h; sourceTree = "<group>"; };
|
||||
FA4F2BAE1DE1E37B00CA37D7 /* RecordingDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordingDevice.cpp; sourceTree = "<group>"; };
|
||||
FA4F2BAF1DE1E37B00CA37D7 /* RecordingDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingDevice.h; sourceTree = "<group>"; };
|
||||
FA4F2BDF1DE6650600CA37D7 /* Transform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Transform.cpp; sourceTree = "<group>"; };
|
||||
FA4F2BE01DE6650600CA37D7 /* Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Transform.h; sourceTree = "<group>"; };
|
||||
FA4F2BE11DE6650600CA37D7 /* wrap_Transform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Transform.cpp; sourceTree = "<group>"; };
|
||||
FA4F2BE21DE6650600CA37D7 /* wrap_Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Transform.h; sourceTree = "<group>"; };
|
||||
FA56D9BA1C2089EE00D8D3C7 /* libmodplug.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libmodplug.a; sourceTree = "<group>"; };
|
||||
FA577A6716C719D900860150 /* FreeType.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FreeType.framework; path = /Library/Frameworks/FreeType.framework; sourceTree = "<absolute>"; };
|
||||
FA577A6D16C719EA00860150 /* Lua.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Lua.framework; path = /Library/Frameworks/Lua.framework; sourceTree = "<absolute>"; };
|
||||
@@ -1783,6 +1836,7 @@
|
||||
FA1557BE1CE90A2C00AFF582 /* tinyexr */,
|
||||
FA0B7A191A958EA3000E1D17 /* utf8 */,
|
||||
FA0B7A1F1A958EA3000E1D17 /* Wuff */,
|
||||
FA4F2B761DE0125B00CA37D7 /* xxHash */,
|
||||
);
|
||||
name = libraries;
|
||||
path = ../../src/libraries;
|
||||
@@ -2195,10 +2249,14 @@
|
||||
FA0B7B3F1A95902C000E1D17 /* Audio.h */,
|
||||
FA0B7B401A95902C000E1D17 /* null */,
|
||||
FA0B7B451A95902C000E1D17 /* openal */,
|
||||
FA4F2BA21DE1E36400CA37D7 /* RecordingDevice.cpp */,
|
||||
FA4F2BA31DE1E36400CA37D7 /* RecordingDevice.h */,
|
||||
FA0B7B4C1A95902C000E1D17 /* Source.cpp */,
|
||||
FA0B7B4D1A95902C000E1D17 /* Source.h */,
|
||||
FA0B7B4E1A95902C000E1D17 /* wrap_Audio.cpp */,
|
||||
FA0B7B4F1A95902C000E1D17 /* wrap_Audio.h */,
|
||||
FA4F2BA41DE1E36400CA37D7 /* wrap_RecordingDevice.cpp */,
|
||||
FA4F2BA51DE1E36400CA37D7 /* wrap_RecordingDevice.h */,
|
||||
FA0B7B501A95902C000E1D17 /* wrap_Source.cpp */,
|
||||
FA0B7B511A95902C000E1D17 /* wrap_Source.h */,
|
||||
);
|
||||
@@ -2210,6 +2268,8 @@
|
||||
children = (
|
||||
FA0B7B411A95902C000E1D17 /* Audio.cpp */,
|
||||
FA0B7B421A95902C000E1D17 /* Audio.h */,
|
||||
FA4F2BAA1DE1E37000CA37D7 /* RecordingDevice.cpp */,
|
||||
FA4F2BAB1DE1E37000CA37D7 /* RecordingDevice.h */,
|
||||
FA0B7B431A95902C000E1D17 /* Source.cpp */,
|
||||
FA0B7B441A95902C000E1D17 /* Source.h */,
|
||||
);
|
||||
@@ -2223,6 +2283,8 @@
|
||||
FA0B7B471A95902C000E1D17 /* Audio.h */,
|
||||
FA0B7B481A95902C000E1D17 /* Pool.cpp */,
|
||||
FA0B7B491A95902C000E1D17 /* Pool.h */,
|
||||
FA4F2BAE1DE1E37B00CA37D7 /* RecordingDevice.cpp */,
|
||||
FA4F2BAF1DE1E37B00CA37D7 /* RecordingDevice.h */,
|
||||
FA0B7B4A1A95902C000E1D17 /* Source.cpp */,
|
||||
FA0B7B4B1A95902C000E1D17 /* Source.h */,
|
||||
);
|
||||
@@ -2525,6 +2587,8 @@
|
||||
FA0B7C041A95902C000E1D17 /* MathModule.h */,
|
||||
FA0B7C051A95902C000E1D17 /* RandomGenerator.cpp */,
|
||||
FA0B7C061A95902C000E1D17 /* RandomGenerator.h */,
|
||||
FA4F2BDF1DE6650600CA37D7 /* Transform.cpp */,
|
||||
FA4F2BE01DE6650600CA37D7 /* Transform.h */,
|
||||
FA0B7C071A95902C000E1D17 /* wrap_BezierCurve.cpp */,
|
||||
FA0B7C081A95902C000E1D17 /* wrap_BezierCurve.h */,
|
||||
FAB17BEE1ABFB37500F9BA27 /* wrap_CompressedData.cpp */,
|
||||
@@ -2535,6 +2599,8 @@
|
||||
FA0B7C0B1A95902C000E1D17 /* wrap_RandomGenerator.cpp */,
|
||||
FA0B7C0C1A95902C000E1D17 /* wrap_RandomGenerator.h */,
|
||||
FA2E9BFE1C19E00C0004A1EE /* wrap_RandomGenerator.lua */,
|
||||
FA4F2BE11DE6650600CA37D7 /* wrap_Transform.cpp */,
|
||||
FA4F2BE21DE6650600CA37D7 /* wrap_Transform.h */,
|
||||
);
|
||||
path = math;
|
||||
sourceTree = "<group>";
|
||||
@@ -2890,6 +2956,15 @@
|
||||
path = theora;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FA4F2B761DE0125B00CA37D7 /* xxHash */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FA4F2B771DE0125B00CA37D7 /* xxhash.c */,
|
||||
FA4F2B781DE0125B00CA37D7 /* xxhash.h */,
|
||||
);
|
||||
path = xxHash;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FA56D9B91C2089CE00D8D3C7 /* modplug */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -3023,6 +3098,7 @@
|
||||
FA0B7D381A95902C000E1D17 /* Font.h in Headers */,
|
||||
FA0B7EC31A95902C000E1D17 /* threads.h in Headers */,
|
||||
FA0B7AC21A958EA3000E1D17 /* enet.h in Headers */,
|
||||
FA4F2BA71DE1E36400CA37D7 /* RecordingDevice.h in Headers */,
|
||||
FA0B7E201A95902C000E1D17 /* Physics.h in Headers */,
|
||||
217DFBEA1D9F6D490055D849 /* io.h in Headers */,
|
||||
FA0B79221A958E3B000E1D17 /* delay.h in Headers */,
|
||||
@@ -3147,6 +3223,7 @@
|
||||
FA0B7E6B1A95902C000E1D17 /* wrap_PulleyJoint.h in Headers */,
|
||||
FA0B7E051A95902C000E1D17 /* Contact.h in Headers */,
|
||||
FA0B7A691A958EA3000E1D17 /* b2Island.h in Headers */,
|
||||
FA4F2BE41DE6650600CA37D7 /* Transform.h in Headers */,
|
||||
FA0B7E0E1A95902C000E1D17 /* Fixture.h in Headers */,
|
||||
FA0B7A401A958EA3000E1D17 /* b2ChainShape.h in Headers */,
|
||||
217DFBE81D9F6D490055D849 /* inet.h in Headers */,
|
||||
@@ -3174,6 +3251,7 @@
|
||||
FA0B7A341A958EA3000E1D17 /* b2Collision.h in Headers */,
|
||||
217DFBDA1D9F6D490055D849 /* auxiliar.h in Headers */,
|
||||
FA0B7EC71A95902C000E1D17 /* ThreadModule.h in Headers */,
|
||||
FA4F2BAD1DE1E37000CA37D7 /* RecordingDevice.h in Headers */,
|
||||
FA0B792B1A958E3B000E1D17 /* Matrix.h in Headers */,
|
||||
FA0B7DA41A95902C000E1D17 /* PKMHandler.h in Headers */,
|
||||
FA0B7AC81A958EA3000E1D17 /* utility.h in Headers */,
|
||||
@@ -3221,6 +3299,7 @@
|
||||
217DFBF71D9F6D490055D849 /* options.h in Headers */,
|
||||
FA0B7E3B1A95902C000E1D17 /* World.h in Headers */,
|
||||
FA0B7DC31A95902C000E1D17 /* wrap_Joystick.h in Headers */,
|
||||
FA4F2BE61DE6650600CA37D7 /* wrap_Transform.h in Headers */,
|
||||
FA0B7EE71A95902D000E1D17 /* Window.h in Headers */,
|
||||
FA0B7E651A95902C000E1D17 /* wrap_PolygonShape.h in Headers */,
|
||||
FA0B7AC91A958EA3000E1D17 /* win32.h in Headers */,
|
||||
@@ -3242,6 +3321,7 @@
|
||||
FA0B7D0B1A95902C000E1D17 /* wrap_FileData.h in Headers */,
|
||||
FA0B7DF91A95902C000E1D17 /* Body.h in Headers */,
|
||||
FA0B7DB91A95902C000E1D17 /* Joystick.h in Headers */,
|
||||
FA4F2BB11DE1E37B00CA37D7 /* RecordingDevice.h in Headers */,
|
||||
FA0B7E2C1A95902C000E1D17 /* RevoluteJoint.h in Headers */,
|
||||
FA8951A41AA2EDF300EC385A /* wrap_Event.h in Headers */,
|
||||
FA0B7B2A1A958EA3000E1D17 /* simplexnoise1234.h in Headers */,
|
||||
@@ -3284,8 +3364,10 @@
|
||||
FA0B79451A958E3B000E1D17 /* Variant.h in Headers */,
|
||||
FA0B7D691A95902C000E1D17 /* wrap_ParticleSystem.h in Headers */,
|
||||
FA0B7E5C1A95902C000E1D17 /* wrap_MotorJoint.h in Headers */,
|
||||
FA4F2BA91DE1E36400CA37D7 /* wrap_RecordingDevice.h in Headers */,
|
||||
FA0B7A7C1A958EA3000E1D17 /* b2Contact.h in Headers */,
|
||||
FA0B7A881A958EA3000E1D17 /* b2PolygonAndCircleContact.h in Headers */,
|
||||
FA4F2B7A1DE0125B00CA37D7 /* xxhash.h in Headers */,
|
||||
FA0B7DDE1A95902C000E1D17 /* wrap_BezierCurve.h in Headers */,
|
||||
FA0B7DED1A95902C000E1D17 /* Cursor.h in Headers */,
|
||||
FA0B7E501A95902C000E1D17 /* wrap_Fixture.h in Headers */,
|
||||
@@ -3452,7 +3534,9 @@
|
||||
FA0B7EE31A95902D000E1D17 /* Window.cpp in Sources */,
|
||||
FA0B7AAB1A958EA3000E1D17 /* b2WeldJoint.cpp in Sources */,
|
||||
FA0B7EC21A95902C000E1D17 /* threads.cpp in Sources */,
|
||||
FA4F2C051DE936C900CA37D7 /* compat.c in Sources */,
|
||||
FA0B79371A958E3B000E1D17 /* macosx.mm in Sources */,
|
||||
FA4F2BE81DE6651000CA37D7 /* wrap_Transform.cpp in Sources */,
|
||||
FA0B7D011A95902C000E1D17 /* Filesystem.cpp in Sources */,
|
||||
FA0B7ED91A95902D000E1D17 /* wrap_Timer.cpp in Sources */,
|
||||
FA0B7DD11A95902C000E1D17 /* love.cpp in Sources */,
|
||||
@@ -3464,6 +3548,7 @@
|
||||
FA0B7E6D1A95902C000E1D17 /* wrap_RevoluteJoint.cpp in Sources */,
|
||||
FA0B7A5F1A958EA3000E1D17 /* b2Body.cpp in Sources */,
|
||||
FA0B7E641A95902C000E1D17 /* wrap_PolygonShape.cpp in Sources */,
|
||||
FA4F2C031DE936C200CA37D7 /* auxiliar.c in Sources */,
|
||||
FA0B7E731A95902C000E1D17 /* wrap_Shape.cpp in Sources */,
|
||||
FA0B7CFE1A95902C000E1D17 /* File.cpp in Sources */,
|
||||
FA27B39E1B498151008A9DCE /* Video.cpp in Sources */,
|
||||
@@ -3481,6 +3566,7 @@
|
||||
FA0B7D0A1A95902C000E1D17 /* wrap_FileData.cpp in Sources */,
|
||||
FA0B7ABE1A958EA3000E1D17 /* compress.c in Sources */,
|
||||
FA0B7CF21A95902C000E1D17 /* DroppedFile.cpp in Sources */,
|
||||
FA4F2C141DE936FE00CA37D7 /* usocket.c in Sources */,
|
||||
FA0B7D8A1A95902C000E1D17 /* CompressedImageData.cpp in Sources */,
|
||||
FA0B7AD21A958EA3000E1D17 /* protocol.c in Sources */,
|
||||
FA0B7D1F1A95902C000E1D17 /* ImageRasterizer.cpp in Sources */,
|
||||
@@ -3498,12 +3584,15 @@
|
||||
FA0B7E191A95902C000E1D17 /* MotorJoint.cpp in Sources */,
|
||||
FA0B7E4F1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */,
|
||||
FA0B7EBF1A95902C000E1D17 /* Thread.cpp in Sources */,
|
||||
FA4F2C121DE936FE00CA37D7 /* unixtcp.c in Sources */,
|
||||
FA0B7EB91A95902C000E1D17 /* Channel.cpp in Sources */,
|
||||
FA4B66CA1ABBCF1900558F15 /* Timer.cpp in Sources */,
|
||||
FA0B7A3F1A958EA3000E1D17 /* b2ChainShape.cpp in Sources */,
|
||||
FA0B7E921A95902C000E1D17 /* ModPlugDecoder.cpp in Sources */,
|
||||
FA0B7E521A95902C000E1D17 /* wrap_FrictionJoint.cpp in Sources */,
|
||||
FA4F2BB51DE1E4C300CA37D7 /* wrap_RecordingDevice.cpp in Sources */,
|
||||
FA0B7A311A958EA3000E1D17 /* b2CollidePolygon.cpp in Sources */,
|
||||
FA4F2C111DE936FE00CA37D7 /* unix.c in Sources */,
|
||||
FA0B7A931A958EA3000E1D17 /* b2GearJoint.cpp in Sources */,
|
||||
FA0B7E0D1A95902C000E1D17 /* Fixture.cpp in Sources */,
|
||||
FA0B7D191A95902C000E1D17 /* TrueTypeRasterizer.cpp in Sources */,
|
||||
@@ -3520,6 +3609,7 @@
|
||||
FA0B7ED21A95902C000E1D17 /* wrap_ThreadModule.cpp in Sources */,
|
||||
FA0B7EE01A95902D000E1D17 /* wrap_Touch.cpp in Sources */,
|
||||
FA0B7A3C1A958EA3000E1D17 /* b2TimeOfImpact.cpp in Sources */,
|
||||
FA4F2C081DE936DD00CA37D7 /* io.c in Sources */,
|
||||
FA0B7CDD1A95902C000E1D17 /* Source.cpp in Sources */,
|
||||
FA0B7DC51A95902C000E1D17 /* wrap_JoystickModule.cpp in Sources */,
|
||||
FA0B7E701A95902C000E1D17 /* wrap_RopeJoint.cpp in Sources */,
|
||||
@@ -3534,6 +3624,7 @@
|
||||
FA0B7D681A95902C000E1D17 /* wrap_ParticleSystem.cpp in Sources */,
|
||||
FA0B7AD51A958EA3000E1D17 /* unix.c in Sources */,
|
||||
FAB17BE71ABFAA9000F9BA27 /* lz4.c in Sources */,
|
||||
FA4F2BE71DE6650D00CA37D7 /* Transform.cpp in Sources */,
|
||||
FA0B7D651A95902C000E1D17 /* wrap_Mesh.cpp in Sources */,
|
||||
FA0B7A531A958EA3000E1D17 /* b2Math.cpp in Sources */,
|
||||
FA0B7CDA1A95902C000E1D17 /* Pool.cpp in Sources */,
|
||||
@@ -3560,13 +3651,16 @@
|
||||
FA0B7A871A958EA3000E1D17 /* b2PolygonAndCircleContact.cpp in Sources */,
|
||||
FA0B7EF21A959D2C000E1D17 /* ios.mm in Sources */,
|
||||
FA0B7D3A1A95902C000E1D17 /* Graphics.cpp in Sources */,
|
||||
FA4F2BB21DE1E4B400CA37D7 /* RecordingDevice.cpp in Sources */,
|
||||
FA0B7A2D1A958EA3000E1D17 /* b2CollideCircle.cpp in Sources */,
|
||||
FA4F2C0F1DE936FE00CA37D7 /* timeout.c in Sources */,
|
||||
FA59A2D31C06481400328DBA /* ParticleSystem.cpp in Sources */,
|
||||
FA0B7E131A95902C000E1D17 /* GearJoint.cpp in Sources */,
|
||||
FA0B7DC21A95902C000E1D17 /* wrap_Joystick.cpp in Sources */,
|
||||
FA0B7CD41A95902C000E1D17 /* Source.cpp in Sources */,
|
||||
FAA3A9AF1B7D465A00CED060 /* android.cpp in Sources */,
|
||||
FA0B7CD11A95902C000E1D17 /* Audio.cpp in Sources */,
|
||||
FA4F2B7B1DE0181B00CA37D7 /* xxhash.c in Sources */,
|
||||
FA0B7D131A95902C000E1D17 /* Font.cpp in Sources */,
|
||||
FA0B7EC91A95902C000E1D17 /* threads.cpp in Sources */,
|
||||
FA0B7A781A958EA3000E1D17 /* b2CircleContact.cpp in Sources */,
|
||||
@@ -3591,13 +3685,19 @@
|
||||
FA0B7A7E1A958EA3000E1D17 /* b2ContactSolver.cpp in Sources */,
|
||||
FA0B7D971A95902C000E1D17 /* ImageData.cpp in Sources */,
|
||||
FA0B7E581A95902C000E1D17 /* wrap_Joint.cpp in Sources */,
|
||||
FA4F2C0A1DE936E600CA37D7 /* mime.c in Sources */,
|
||||
FA0B7E311A95902C000E1D17 /* Shape.cpp in Sources */,
|
||||
FA0B7E491A95902C000E1D17 /* wrap_DistanceJoint.cpp in Sources */,
|
||||
FA0B7A391A958EA3000E1D17 /* b2DynamicTree.cpp in Sources */,
|
||||
FA4F2C101DE936FE00CA37D7 /* udp.c in Sources */,
|
||||
FA0B7A681A958EA3000E1D17 /* b2Island.cpp in Sources */,
|
||||
FA0B7E2B1A95902C000E1D17 /* RevoluteJoint.cpp in Sources */,
|
||||
FA0B7B291A958EA3000E1D17 /* simplexnoise1234.cpp in Sources */,
|
||||
FA0B7D261A95902C000E1D17 /* wrap_Font.cpp in Sources */,
|
||||
FA4F2BB31DE1E4B800CA37D7 /* RecordingDevice.cpp in Sources */,
|
||||
FA4F2C071DE936DA00CA37D7 /* inet.c in Sources */,
|
||||
FA4F2C0B1DE936EA00CA37D7 /* options.c in Sources */,
|
||||
FA4F2C0D1DE936F100CA37D7 /* serial.c in Sources */,
|
||||
FA0B7E0A1A95902C000E1D17 /* EdgeShape.cpp in Sources */,
|
||||
FAB17BF11ABFB37500F9BA27 /* wrap_CompressedData.cpp in Sources */,
|
||||
FA0B7CF81A95902C000E1D17 /* FileData.cpp in Sources */,
|
||||
@@ -3605,6 +3705,7 @@
|
||||
FA0B7E981A95902C000E1D17 /* Sound.cpp in Sources */,
|
||||
FA0B7E371A95902C000E1D17 /* WheelJoint.cpp in Sources */,
|
||||
FA0B7A8A1A958EA3000E1D17 /* b2PolygonContact.cpp in Sources */,
|
||||
FA4F2C0C1DE936ED00CA37D7 /* select.c in Sources */,
|
||||
FA0B7D8E1A95902C000E1D17 /* ddsHandler.cpp in Sources */,
|
||||
FA0B7DFE1A95902C000E1D17 /* ChainShape.cpp in Sources */,
|
||||
FA0B7A451A958EA3000E1D17 /* b2EdgeShape.cpp in Sources */,
|
||||
@@ -3629,6 +3730,7 @@
|
||||
FA0B7CE31A95902C000E1D17 /* wrap_Audio.cpp in Sources */,
|
||||
FA0B7B381A958EA3000E1D17 /* wuff_internal.c in Sources */,
|
||||
FA0B7DF81A95902C000E1D17 /* Body.cpp in Sources */,
|
||||
FA4F2BB41DE1E4BD00CA37D7 /* RecordingDevice.cpp in Sources */,
|
||||
FA0B7DF51A95902C000E1D17 /* wrap_Mouse.cpp in Sources */,
|
||||
FA0B7D6E1A95902C000E1D17 /* wrap_Shader.cpp in Sources */,
|
||||
FA0B7E861A95902C000E1D17 /* CoreAudioDecoder.cpp in Sources */,
|
||||
@@ -3647,12 +3749,14 @@
|
||||
FA0B7E1C1A95902C000E1D17 /* MouseJoint.cpp in Sources */,
|
||||
FA0B7CF51A95902C000E1D17 /* File.cpp in Sources */,
|
||||
FA0B7E341A95902C000E1D17 /* WeldJoint.cpp in Sources */,
|
||||
FA4F2C091DE936E200CA37D7 /* luasocket.c in Sources */,
|
||||
FA0B7D5C1A95902C000E1D17 /* wrap_Font.cpp in Sources */,
|
||||
FA0B7B221A958EA3000E1D17 /* luasocket.cpp in Sources */,
|
||||
FA0B7D311A95902C000E1D17 /* Graphics.cpp in Sources */,
|
||||
FA0B7E9E1A95902C000E1D17 /* WaveDecoder.cpp in Sources */,
|
||||
FA0B7EB31A95902C000E1D17 /* System.cpp in Sources */,
|
||||
FA0B7D1C1A95902C000E1D17 /* GlyphData.cpp in Sources */,
|
||||
FA4F2C061DE936CD00CA37D7 /* except.c in Sources */,
|
||||
FA0B7AAE1A958EA3000E1D17 /* b2WheelJoint.cpp in Sources */,
|
||||
FA0B7E671A95902C000E1D17 /* wrap_PrismaticJoint.cpp in Sources */,
|
||||
FA0B7DCE1A95902C000E1D17 /* wrap_Keyboard.cpp in Sources */,
|
||||
@@ -3668,6 +3772,7 @@
|
||||
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 */,
|
||||
@@ -3684,6 +3789,7 @@
|
||||
FA0B7E251A95902C000E1D17 /* PrismaticJoint.cpp in Sources */,
|
||||
FA0B7A561A958EA3000E1D17 /* b2Settings.cpp in Sources */,
|
||||
FA0B7E611A95902C000E1D17 /* wrap_Physics.cpp in Sources */,
|
||||
FA4F2C041DE936C600CA37D7 /* buffer.c in Sources */,
|
||||
FA0B7DC81A95902C000E1D17 /* Keyboard.cpp in Sources */,
|
||||
FA4943551D9DDFFE00E8D38A /* HashFunction.cpp in Sources */,
|
||||
FA0B7EAD1A95902C000E1D17 /* wrap_SoundData.cpp in Sources */,
|
||||
@@ -3695,6 +3801,7 @@
|
||||
FA0B7DE61A95902C000E1D17 /* Cursor.cpp in Sources */,
|
||||
FA0B7EDC1A95902D000E1D17 /* Touch.cpp in Sources */,
|
||||
FA0B7CE91A95902C000E1D17 /* Event.cpp in Sources */,
|
||||
FA4F2C131DE936FE00CA37D7 /* unixudp.c in Sources */,
|
||||
FA0B7A961A958EA3000E1D17 /* b2Joint.cpp in Sources */,
|
||||
FA0B7A621A958EA3000E1D17 /* b2ContactManager.cpp in Sources */,
|
||||
FA0B7A2F1A958EA3000E1D17 /* b2CollideEdge.cpp in Sources */,
|
||||
@@ -3750,7 +3857,9 @@
|
||||
FA0B7E631A95902C000E1D17 /* wrap_PolygonShape.cpp in Sources */,
|
||||
FA0B7E721A95902C000E1D17 /* wrap_Shape.cpp in Sources */,
|
||||
FA0B7CFD1A95902C000E1D17 /* File.cpp in Sources */,
|
||||
FA4F2BB01DE1E37B00CA37D7 /* RecordingDevice.cpp in Sources */,
|
||||
FA27B39D1B498151008A9DCE /* Video.cpp in Sources */,
|
||||
FA4F2BAC1DE1E37000CA37D7 /* RecordingDevice.cpp in Sources */,
|
||||
FA0B7A2E1A958EA3000E1D17 /* b2CollideEdge.cpp in Sources */,
|
||||
FA0B7E691A95902C000E1D17 /* wrap_PulleyJoint.cpp in Sources */,
|
||||
FA0B7DB71A95902C000E1D17 /* Joystick.cpp in Sources */,
|
||||
@@ -3806,6 +3915,7 @@
|
||||
FA0B7EDF1A95902D000E1D17 /* wrap_Touch.cpp in Sources */,
|
||||
FA0B794A1A958E3B000E1D17 /* wrap_Data.cpp in Sources */,
|
||||
217DFBFB1D9F6D490055D849 /* serial.c in Sources */,
|
||||
FA4F2BE51DE6650600CA37D7 /* wrap_Transform.cpp in Sources */,
|
||||
217DFC0D1D9F6D490055D849 /* unixudp.c in Sources */,
|
||||
FA0B7CDC1A95902C000E1D17 /* Source.cpp in Sources */,
|
||||
FA0B7DC41A95902C000E1D17 /* wrap_JoystickModule.cpp in Sources */,
|
||||
@@ -3894,6 +4004,7 @@
|
||||
FA0B7DA51A95902C000E1D17 /* PNGHandler.cpp in Sources */,
|
||||
FA0B7B371A958EA3000E1D17 /* wuff_internal.c in Sources */,
|
||||
FA0B7E971A95902C000E1D17 /* Sound.cpp in Sources */,
|
||||
FA4F2B791DE0125B00CA37D7 /* xxhash.c in Sources */,
|
||||
FA0B7E361A95902C000E1D17 /* WheelJoint.cpp in Sources */,
|
||||
FA0B7A471A958EA3000E1D17 /* b2PolygonShape.cpp in Sources */,
|
||||
FA0B7D8D1A95902C000E1D17 /* ddsHandler.cpp in Sources */,
|
||||
@@ -3906,6 +4017,7 @@
|
||||
FA0B7A981A958EA3000E1D17 /* b2MotorJoint.cpp in Sources */,
|
||||
FA0B7E061A95902C000E1D17 /* DistanceJoint.cpp in Sources */,
|
||||
FA620A321AA2F8DB005DB4C2 /* wrap_Quad.cpp in Sources */,
|
||||
FA4F2BA61DE1E36400CA37D7 /* RecordingDevice.cpp in Sources */,
|
||||
FA0B793B1A958E3B000E1D17 /* runtime.cpp in Sources */,
|
||||
FA0B7E5D1A95902C000E1D17 /* wrap_MouseJoint.cpp in Sources */,
|
||||
FA0B7A741A958EA3000E1D17 /* b2ChainAndPolygonContact.cpp in Sources */,
|
||||
@@ -3988,6 +4100,7 @@
|
||||
FA0B7CDF1A95902C000E1D17 /* Source.cpp in Sources */,
|
||||
FA0B7ECE1A95902C000E1D17 /* wrap_LuaThread.cpp in Sources */,
|
||||
FA0B79431A958E3B000E1D17 /* Variant.cpp in Sources */,
|
||||
FA4F2BE31DE6650600CA37D7 /* Transform.cpp in Sources */,
|
||||
FA0B7EA01A95902C000E1D17 /* Sound.cpp in Sources */,
|
||||
FA0B7DE51A95902C000E1D17 /* Cursor.cpp in Sources */,
|
||||
FA0B7EDB1A95902D000E1D17 /* Touch.cpp in Sources */,
|
||||
@@ -3998,6 +4111,7 @@
|
||||
FA0B7A891A958EA3000E1D17 /* b2PolygonContact.cpp in Sources */,
|
||||
FA0B7E1E1A95902C000E1D17 /* Physics.cpp in Sources */,
|
||||
FA0B7E811A95902C000E1D17 /* Shape.cpp in Sources */,
|
||||
FA4F2BA81DE1E36400CA37D7 /* wrap_RecordingDevice.cpp in Sources */,
|
||||
FA0B7B251A958EA3000E1D17 /* lutf8lib.c in Sources */,
|
||||
FA0B7ED41A95902D000E1D17 /* Timer.cpp in Sources */,
|
||||
FA19C4C51B4B0BD50059B0B3 /* wrap_Video.cpp in Sources */,
|
||||
@@ -4323,6 +4437,7 @@
|
||||
DYLIB_CURRENT_VERSION = 9.0;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks",
|
||||
/Library/Frameworks,
|
||||
"$(LOCAL_LIBRARY_DIR)/Frameworks",
|
||||
);
|
||||
@@ -4330,6 +4445,9 @@
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/FreeType.framework/Headers",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
|
||||
/Library/Frameworks/FreeType.framework/Headers,
|
||||
/Library/Frameworks/Lua.framework/Headers,
|
||||
/Library/Frameworks/SDL2.framework/Headers,
|
||||
@@ -4357,6 +4475,7 @@
|
||||
DYLIB_CURRENT_VERSION = 9.0;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks",
|
||||
/Library/Frameworks,
|
||||
"$(LOCAL_LIBRARY_DIR)/Frameworks",
|
||||
);
|
||||
@@ -4364,6 +4483,9 @@
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/FreeType.framework/Headers",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
|
||||
/Library/Frameworks/FreeType.framework/Headers,
|
||||
/Library/Frameworks/Lua.framework/Headers,
|
||||
/Library/Frameworks/SDL2.framework/Headers,
|
||||
@@ -4392,6 +4514,7 @@
|
||||
DYLIB_CURRENT_VERSION = 9.0;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks",
|
||||
/Library/Frameworks,
|
||||
"$(LOCAL_LIBRARY_DIR)/Frameworks",
|
||||
);
|
||||
@@ -4399,6 +4522,9 @@
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/FreeType.framework/Headers",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
|
||||
/Library/Frameworks/FreeType.framework/Headers,
|
||||
/Library/Frameworks/Lua.framework/Headers,
|
||||
/Library/Frameworks/SDL2.framework/Headers,
|
||||
|
||||
@@ -430,6 +430,7 @@
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks",
|
||||
/Library/Frameworks,
|
||||
"\"$(SRCROOT)/build/Release\"",
|
||||
"\"$(SRCROOT)/build/Debug\"",
|
||||
@@ -439,6 +440,8 @@
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
|
||||
/Library/Frameworks/Lua.framework/Headers,
|
||||
/Library/Frameworks/SDL2.framework/Headers,
|
||||
);
|
||||
@@ -458,6 +461,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks",
|
||||
/Library/Frameworks,
|
||||
"\"$(SRCROOT)/build/Release\"",
|
||||
"\"$(SRCROOT)/build/Debug\"",
|
||||
@@ -465,6 +469,8 @@
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
|
||||
/Library/Frameworks/Lua.framework/Headers,
|
||||
/Library/Frameworks/SDL2.framework/Headers,
|
||||
);
|
||||
@@ -841,6 +847,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks",
|
||||
/Library/Frameworks,
|
||||
"\"$(SRCROOT)/build/Release\"",
|
||||
"\"$(SRCROOT)/build/Debug\"",
|
||||
@@ -848,6 +855,8 @@
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/Lua.framework/Headers",
|
||||
"$(PROJECT_DIR)/macosx/Frameworks/SDL2.framework/Headers",
|
||||
/Library/Frameworks/Lua.framework/Headers,
|
||||
/Library/Frameworks/SDL2.framework/Headers,
|
||||
);
|
||||
|
||||
@@ -73,6 +73,12 @@ Matrix4::Matrix4()
|
||||
{
|
||||
setIdentity();
|
||||
}
|
||||
|
||||
|
||||
Matrix4::Matrix4(const float elements[16])
|
||||
{
|
||||
memcpy(e, elements, sizeof(float) * 16);
|
||||
}
|
||||
|
||||
Matrix4::Matrix4(float t00, float t10, float t01, float t11, float x, float y)
|
||||
{
|
||||
@@ -143,6 +149,12 @@ void Matrix4::setShear(float kx, float ky)
|
||||
e[1] = ky;
|
||||
e[4] = kx;
|
||||
}
|
||||
|
||||
void Matrix4::getApproximateScale(float &sx, float &sy) const
|
||||
{
|
||||
sx = sqrtf(e[0] * e[0] + e[4] * e[4]);
|
||||
sy = sqrtf(e[1] * e[1] + e[5] * e[5]);
|
||||
}
|
||||
|
||||
void Matrix4::setRawTransformation(float t00, float t10, float t01, float t11, float x, float y)
|
||||
{
|
||||
|
||||
@@ -52,6 +52,12 @@ public:
|
||||
**/
|
||||
Matrix4(float t00, float t10, float t01, float t11, float x, float y);
|
||||
|
||||
/**
|
||||
* Creates a new matrix from the specified elements. Be sure to pass
|
||||
* exactly 16 elements in!
|
||||
**/
|
||||
Matrix4(const float elements[16]);
|
||||
|
||||
/**
|
||||
* Creates a new matrix set to a transformation.
|
||||
**/
|
||||
@@ -112,6 +118,12 @@ public:
|
||||
* @param ky Shear along y-axis.
|
||||
**/
|
||||
void setShear(float kx, float ky);
|
||||
|
||||
/**
|
||||
* Calculates the scale factors for a 2D affine transform. The output values
|
||||
* are absolute (not signed).
|
||||
**/
|
||||
void getApproximateScale(float &sx, float &sy) const;
|
||||
|
||||
/**
|
||||
* Sets a transformation's values directly. Useful if you want to modify them inplace,
|
||||
@@ -182,6 +194,9 @@ public:
|
||||
template <typename V>
|
||||
void transform(V *dst, const V *src, int size) const;
|
||||
|
||||
/**
|
||||
* Computes and returns the inverse of the matrix.
|
||||
**/
|
||||
Matrix4 inverse() const;
|
||||
|
||||
/**
|
||||
|
||||
Executable
+889
@@ -0,0 +1,889 @@
|
||||
/*
|
||||
* xxHash - Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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 THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS 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.
|
||||
*
|
||||
* You can contact the author at :
|
||||
* - xxHash homepage: http://www.xxhash.com
|
||||
* - xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Tuning parameters
|
||||
***************************************/
|
||||
/*!XXH_FORCE_MEMORY_ACCESS :
|
||||
* By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
|
||||
* Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
|
||||
* The below switch allow to select different access method for improved performance.
|
||||
* Method 0 (default) : use `memcpy()`. Safe and portable.
|
||||
* Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
|
||||
* This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
|
||||
* Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
|
||||
* It can generate buggy code on targets which do not support unaligned memory accesses.
|
||||
* But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
|
||||
* See http://stackoverflow.com/a/32095106/646947 for details.
|
||||
* Prefer these methods in priority order (0 > 1 > 2)
|
||||
*/
|
||||
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
|
||||
# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
|
||||
# define XXH_FORCE_MEMORY_ACCESS 2
|
||||
# elif defined(__INTEL_COMPILER) || \
|
||||
(defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
|
||||
# define XXH_FORCE_MEMORY_ACCESS 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*!XXH_ACCEPT_NULL_INPUT_POINTER :
|
||||
* If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
|
||||
* When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
|
||||
* By default, this option is disabled. To enable it, uncomment below define :
|
||||
*/
|
||||
/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
|
||||
|
||||
/*!XXH_FORCE_NATIVE_FORMAT :
|
||||
* By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
|
||||
* Results are therefore identical for little-endian and big-endian CPU.
|
||||
* This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
|
||||
* Should endian-independence be of no importance for your application, you may set the #define below to 1,
|
||||
* to improve speed for Big-endian CPU.
|
||||
* This option has no impact on Little_Endian CPU.
|
||||
*/
|
||||
#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */
|
||||
# define XXH_FORCE_NATIVE_FORMAT 0
|
||||
#endif
|
||||
|
||||
/*!XXH_FORCE_ALIGN_CHECK :
|
||||
* This is a minor performance trick, only useful with lots of very small keys.
|
||||
* It means : check for aligned/unaligned input.
|
||||
* The check costs one initial branch per hash; set to 0 when the input data
|
||||
* is guaranteed to be aligned.
|
||||
*/
|
||||
#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
|
||||
# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
|
||||
# define XXH_FORCE_ALIGN_CHECK 0
|
||||
# else
|
||||
# define XXH_FORCE_ALIGN_CHECK 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Includes & Memory related functions
|
||||
***************************************/
|
||||
/*! Modify the local functions below should you wish to use some other memory routines
|
||||
* for malloc(), free() */
|
||||
#include <stdlib.h>
|
||||
static void* XXH_malloc(size_t s) { return malloc(s); }
|
||||
static void XXH_free (void* p) { free(p); }
|
||||
/*! and for memcpy() */
|
||||
#include <string.h>
|
||||
static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
|
||||
|
||||
#define XXH_STATIC_LINKING_ONLY
|
||||
#include "xxhash.h"
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Compiler Specific Options
|
||||
***************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
# define FORCE_INLINE static __forceinline
|
||||
#else
|
||||
# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||
# ifdef __GNUC__
|
||||
# define FORCE_INLINE static inline __attribute__((always_inline))
|
||||
# else
|
||||
# define FORCE_INLINE static inline
|
||||
# endif
|
||||
# else
|
||||
# define FORCE_INLINE static
|
||||
# endif /* __STDC_VERSION__ */
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Basic Types
|
||||
***************************************/
|
||||
#ifndef MEM_MODULE
|
||||
# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
# else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
|
||||
|
||||
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
|
||||
static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
|
||||
|
||||
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
|
||||
|
||||
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
|
||||
/* currently only defined for gcc and icc */
|
||||
typedef union { U32 u32; } __attribute__((packed)) unalign;
|
||||
static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
|
||||
|
||||
#else
|
||||
|
||||
/* portable and safe solution. Generally efficient.
|
||||
* see : http://stackoverflow.com/a/32095106/646947
|
||||
*/
|
||||
static U32 XXH_read32(const void* memPtr)
|
||||
{
|
||||
U32 val;
|
||||
memcpy(&val, memPtr, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
|
||||
|
||||
|
||||
/* ****************************************
|
||||
* Compiler-specific Functions and Macros
|
||||
******************************************/
|
||||
#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
|
||||
/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
|
||||
#if defined(_MSC_VER)
|
||||
# define XXH_rotl32(x,r) _rotl(x,r)
|
||||
# define XXH_rotl64(x,r) _rotl64(x,r)
|
||||
#else
|
||||
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) /* Visual Studio */
|
||||
# define XXH_swap32 _byteswap_ulong
|
||||
#elif XXH_GCC_VERSION >= 403
|
||||
# define XXH_swap32 __builtin_bswap32
|
||||
#else
|
||||
static U32 XXH_swap32 (U32 x)
|
||||
{
|
||||
return ((x << 24) & 0xff000000 ) |
|
||||
((x << 8) & 0x00ff0000 ) |
|
||||
((x >> 8) & 0x0000ff00 ) |
|
||||
((x >> 24) & 0x000000ff );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Architecture Macros
|
||||
***************************************/
|
||||
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
|
||||
|
||||
/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
|
||||
#ifndef XXH_CPU_LITTLE_ENDIAN
|
||||
static const int g_one = 1;
|
||||
# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one))
|
||||
#endif
|
||||
|
||||
|
||||
/* ***************************
|
||||
* Memory reads
|
||||
*****************************/
|
||||
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
if (align==XXH_unaligned)
|
||||
return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
|
||||
else
|
||||
return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE32_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
static U32 XXH_readBE32(const void* ptr)
|
||||
{
|
||||
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
|
||||
}
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Macros
|
||||
***************************************/
|
||||
#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
|
||||
|
||||
|
||||
/* *******************************************************************
|
||||
* 32-bits hash functions
|
||||
*********************************************************************/
|
||||
static const U32 PRIME32_1 = 2654435761U;
|
||||
static const U32 PRIME32_2 = 2246822519U;
|
||||
static const U32 PRIME32_3 = 3266489917U;
|
||||
static const U32 PRIME32_4 = 668265263U;
|
||||
static const U32 PRIME32_5 = 374761393U;
|
||||
|
||||
static U32 XXH32_round(U32 seed, U32 input)
|
||||
{
|
||||
seed += input * PRIME32_2;
|
||||
seed = XXH_rotl32(seed, 13);
|
||||
seed *= PRIME32_1;
|
||||
return seed;
|
||||
}
|
||||
|
||||
FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* bEnd = p + len;
|
||||
U32 h32;
|
||||
#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (p==NULL) {
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)16;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=16) {
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
U32 v2 = seed + PRIME32_2;
|
||||
U32 v3 = seed + 0;
|
||||
U32 v4 = seed - PRIME32_1;
|
||||
|
||||
do {
|
||||
v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
|
||||
v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
|
||||
v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
|
||||
v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
|
||||
} while (p<=limit);
|
||||
|
||||
h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
|
||||
} else {
|
||||
h32 = seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (U32) len;
|
||||
|
||||
while (p+4<=bEnd) {
|
||||
h32 += XXH_get32bits(p) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH32_state_t state;
|
||||
XXH32_reset(&state, seed);
|
||||
XXH32_update(&state, input, len);
|
||||
return XXH32_digest(&state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if (XXH_FORCE_ALIGN_CHECK) {
|
||||
if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
} }
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*====== Hash streaming ======*/
|
||||
|
||||
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
|
||||
{
|
||||
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
|
||||
}
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
|
||||
{
|
||||
memcpy(dstState, srcState, sizeof(*dstState));
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
|
||||
{
|
||||
XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
|
||||
memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */
|
||||
state.v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
state.v2 = seed + PRIME32_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME32_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (input==NULL) return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len_32 += (unsigned)len;
|
||||
state->large_len |= (len>=16) | (state->total_len_32>=16);
|
||||
|
||||
if (state->memsize + len < 16) { /* fill in tmp buffer */
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
|
||||
state->memsize += (unsigned)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* some data left from previous update */
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
|
||||
{ const U32* p32 = state->mem32;
|
||||
state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
|
||||
state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
|
||||
state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
|
||||
state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++;
|
||||
}
|
||||
p += 16-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p <= bEnd-16) {
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = state->v1;
|
||||
U32 v2 = state->v2;
|
||||
U32 v3 = state->v3;
|
||||
U32 v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
|
||||
v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
|
||||
v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
|
||||
v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
|
||||
} while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd) {
|
||||
XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
|
||||
state->memsize = (unsigned)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
|
||||
{
|
||||
const BYTE * p = (const BYTE*)state->mem32;
|
||||
const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
|
||||
U32 h32;
|
||||
|
||||
if (state->large_len) {
|
||||
h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
|
||||
} else {
|
||||
h32 = state->v3 /* == seed */ + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += state->total_len_32;
|
||||
|
||||
while (p+4<=bEnd) {
|
||||
h32 += XXH_readLE32(p, endian) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
|
||||
/*! Default XXH result types are basic unsigned 32 and 64 bits.
|
||||
* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
|
||||
* These functions allow transformation of hash result into and from its canonical format.
|
||||
* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.
|
||||
*/
|
||||
|
||||
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
|
||||
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
|
||||
memcpy(dst, &hash, sizeof(*dst));
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
|
||||
{
|
||||
return XXH_readBE32(src);
|
||||
}
|
||||
|
||||
|
||||
#ifndef XXH_NO_LONG_LONG
|
||||
|
||||
/* *******************************************************************
|
||||
* 64-bits hash functions
|
||||
*********************************************************************/
|
||||
|
||||
/*====== Memory access ======*/
|
||||
|
||||
#ifndef MEM_MODULE
|
||||
# define MEM_MODULE
|
||||
# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
|
||||
# include <stdint.h>
|
||||
typedef uint64_t U64;
|
||||
# else
|
||||
typedef unsigned long long U64; /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
|
||||
|
||||
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
|
||||
static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
|
||||
|
||||
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
|
||||
|
||||
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
|
||||
/* currently only defined for gcc and icc */
|
||||
typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64;
|
||||
static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; }
|
||||
|
||||
#else
|
||||
|
||||
/* portable and safe solution. Generally efficient.
|
||||
* see : http://stackoverflow.com/a/32095106/646947
|
||||
*/
|
||||
|
||||
static U64 XXH_read64(const void* memPtr)
|
||||
{
|
||||
U64 val;
|
||||
memcpy(&val, memPtr, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
|
||||
|
||||
#if defined(_MSC_VER) /* Visual Studio */
|
||||
# define XXH_swap64 _byteswap_uint64
|
||||
#elif XXH_GCC_VERSION >= 403
|
||||
# define XXH_swap64 __builtin_bswap64
|
||||
#else
|
||||
static U64 XXH_swap64 (U64 x)
|
||||
{
|
||||
return ((x << 56) & 0xff00000000000000ULL) |
|
||||
((x << 40) & 0x00ff000000000000ULL) |
|
||||
((x << 24) & 0x0000ff0000000000ULL) |
|
||||
((x << 8) & 0x000000ff00000000ULL) |
|
||||
((x >> 8) & 0x00000000ff000000ULL) |
|
||||
((x >> 24) & 0x0000000000ff0000ULL) |
|
||||
((x >> 40) & 0x000000000000ff00ULL) |
|
||||
((x >> 56) & 0x00000000000000ffULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
if (align==XXH_unaligned)
|
||||
return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
|
||||
else
|
||||
return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE64_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
static U64 XXH_readBE64(const void* ptr)
|
||||
{
|
||||
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
|
||||
}
|
||||
|
||||
|
||||
/*====== xxh64 ======*/
|
||||
|
||||
static const U64 PRIME64_1 = 11400714785074694791ULL;
|
||||
static const U64 PRIME64_2 = 14029467366897019727ULL;
|
||||
static const U64 PRIME64_3 = 1609587929392839161ULL;
|
||||
static const U64 PRIME64_4 = 9650029242287828579ULL;
|
||||
static const U64 PRIME64_5 = 2870177450012600261ULL;
|
||||
|
||||
static U64 XXH64_round(U64 acc, U64 input)
|
||||
{
|
||||
acc += input * PRIME64_2;
|
||||
acc = XXH_rotl64(acc, 31);
|
||||
acc *= PRIME64_1;
|
||||
return acc;
|
||||
}
|
||||
|
||||
static U64 XXH64_mergeRound(U64 acc, U64 val)
|
||||
{
|
||||
val = XXH64_round(0, val);
|
||||
acc ^= val;
|
||||
acc = acc * PRIME64_1 + PRIME64_4;
|
||||
return acc;
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* bEnd = p + len;
|
||||
U64 h64;
|
||||
#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (p==NULL) {
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)32;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=32) {
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
U64 v2 = seed + PRIME64_2;
|
||||
U64 v3 = seed + 0;
|
||||
U64 v4 = seed - PRIME64_1;
|
||||
|
||||
do {
|
||||
v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
|
||||
v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
|
||||
v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
|
||||
v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
|
||||
} while (p<=limit);
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
h64 = XXH64_mergeRound(h64, v1);
|
||||
h64 = XXH64_mergeRound(h64, v2);
|
||||
h64 = XXH64_mergeRound(h64, v3);
|
||||
h64 = XXH64_mergeRound(h64, v4);
|
||||
|
||||
} else {
|
||||
h64 = seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) len;
|
||||
|
||||
while (p+8<=bEnd) {
|
||||
U64 const k1 = XXH64_round(0, XXH_get64bits(p));
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd) {
|
||||
h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH64_state_t state;
|
||||
XXH64_reset(&state, seed);
|
||||
XXH64_update(&state, input, len);
|
||||
return XXH64_digest(&state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if (XXH_FORCE_ALIGN_CHECK) {
|
||||
if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
} }
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*====== Hash Streaming ======*/
|
||||
|
||||
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
|
||||
{
|
||||
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
|
||||
}
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
|
||||
{
|
||||
memcpy(dstState, srcState, sizeof(*dstState));
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
|
||||
{
|
||||
XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
|
||||
memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */
|
||||
state.v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
state.v2 = seed + PRIME64_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME64_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (input==NULL) return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 32) { /* fill in tmp buffer */
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
|
||||
state->memsize += (U32)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* tmp buffer is full */
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
|
||||
state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
|
||||
state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
|
||||
state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
|
||||
state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
|
||||
p += 32-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p+32 <= bEnd) {
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = state->v1;
|
||||
U64 v2 = state->v2;
|
||||
U64 v3 = state->v3;
|
||||
U64 v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
|
||||
v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
|
||||
v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
|
||||
v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
|
||||
} while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd) {
|
||||
XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
|
||||
state->memsize = (unsigned)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
|
||||
{
|
||||
const BYTE * p = (const BYTE*)state->mem64;
|
||||
const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
|
||||
U64 h64;
|
||||
|
||||
if (state->total_len >= 32) {
|
||||
U64 const v1 = state->v1;
|
||||
U64 const v2 = state->v2;
|
||||
U64 const v3 = state->v3;
|
||||
U64 const v4 = state->v4;
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
h64 = XXH64_mergeRound(h64, v1);
|
||||
h64 = XXH64_mergeRound(h64, v2);
|
||||
h64 = XXH64_mergeRound(h64, v3);
|
||||
h64 = XXH64_mergeRound(h64, v4);
|
||||
} else {
|
||||
h64 = state->v3 + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) state->total_len;
|
||||
|
||||
while (p+8<=bEnd) {
|
||||
U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd) {
|
||||
h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
|
||||
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
|
||||
memcpy(dst, &hash, sizeof(*dst));
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
|
||||
{
|
||||
return XXH_readBE64(src);
|
||||
}
|
||||
|
||||
#endif /* XXH_NO_LONG_LONG */
|
||||
Executable
+293
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
xxHash - Extremely Fast Hash algorithm
|
||||
Header File
|
||||
Copyright (C) 2012-2016, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
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.
|
||||
|
||||
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 THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
||||
|
||||
You can contact the author at :
|
||||
- xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
/* Notice extracted from xxHash homepage :
|
||||
|
||||
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
It also successfully passes all tests from the SMHasher suite.
|
||||
|
||||
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
|
||||
|
||||
Name Speed Q.Score Author
|
||||
xxHash 5.4 GB/s 10
|
||||
CrapWow 3.2 GB/s 2 Andrew
|
||||
MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
SBox 1.4 GB/s 9 Bret Mulvey
|
||||
Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
CRC32 0.43 GB/s 9
|
||||
MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
SHA1-32 0.28 GB/s 10
|
||||
|
||||
Q.Score is a measure of quality of the hash function.
|
||||
It depends on successfully passing SMHasher test set.
|
||||
10 is a perfect score.
|
||||
|
||||
A 64-bits version, named XXH64, is available since r35.
|
||||
It offers much better speed, but for 64-bits applications only.
|
||||
Name Speed on 64 bits Speed on 32 bits
|
||||
XXH64 13.8 GB/s 1.9 GB/s
|
||||
XXH32 6.8 GB/s 6.0 GB/s
|
||||
*/
|
||||
|
||||
#ifndef XXHASH_H_5627135585666179
|
||||
#define XXHASH_H_5627135585666179 1
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* ****************************
|
||||
* Definitions
|
||||
******************************/
|
||||
#include <stddef.h> /* size_t */
|
||||
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
|
||||
|
||||
|
||||
/* ****************************
|
||||
* API modifier
|
||||
******************************/
|
||||
/** XXH_PRIVATE_API
|
||||
* This is useful to include xxhash functions in `static` mode
|
||||
* in order to inline them, and remove their symbol from the public list.
|
||||
* Methodology :
|
||||
* #define XXH_PRIVATE_API
|
||||
* #include "xxhash.h"
|
||||
* `xxhash.c` is automatically included.
|
||||
* It's not useful to compile and link it as a separate module.
|
||||
*/
|
||||
#ifdef XXH_PRIVATE_API
|
||||
# ifndef XXH_STATIC_LINKING_ONLY
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
# endif
|
||||
# if defined(__GNUC__)
|
||||
# define XXH_PUBLIC_API static __inline __attribute__((unused))
|
||||
# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
# define XXH_PUBLIC_API static inline
|
||||
# elif defined(_MSC_VER)
|
||||
# define XXH_PUBLIC_API static __inline
|
||||
# else
|
||||
# define XXH_PUBLIC_API static /* this version may generate warnings for unused static functions; disable the relevant warning */
|
||||
# endif
|
||||
#else
|
||||
# define XXH_PUBLIC_API /* do nothing */
|
||||
#endif /* XXH_PRIVATE_API */
|
||||
|
||||
/*!XXH_NAMESPACE, aka Namespace Emulation :
|
||||
|
||||
If you want to include _and expose_ xxHash functions from within your own library,
|
||||
but also want to avoid symbol collisions with other libraries which may also include xxHash,
|
||||
|
||||
you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
|
||||
with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values).
|
||||
|
||||
Note that no change is required within the calling program as long as it includes `xxhash.h` :
|
||||
regular symbol name will be automatically translated by this header.
|
||||
*/
|
||||
#ifdef XXH_NAMESPACE
|
||||
# define XXH_CAT(A,B) A##B
|
||||
# define XXH_NAME2(A,B) XXH_CAT(A,B)
|
||||
# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
|
||||
# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
|
||||
# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
|
||||
# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
|
||||
# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
|
||||
# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
|
||||
# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
|
||||
# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
|
||||
# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
|
||||
# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
|
||||
# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
|
||||
# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
|
||||
# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
|
||||
# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
|
||||
# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
|
||||
# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
|
||||
# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
|
||||
# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
|
||||
# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Version
|
||||
***************************************/
|
||||
#define XXH_VERSION_MAJOR 0
|
||||
#define XXH_VERSION_MINOR 6
|
||||
#define XXH_VERSION_RELEASE 2
|
||||
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
|
||||
|
||||
|
||||
/*-**********************************************************************
|
||||
* 32-bits hash
|
||||
************************************************************************/
|
||||
typedef unsigned int XXH32_hash_t;
|
||||
|
||||
/*! XXH32() :
|
||||
Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
|
||||
The memory between input & input+length must be valid (allocated and read-accessible).
|
||||
"seed" can be used to alter the result predictably.
|
||||
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
|
||||
|
||||
/*====== Streaming ======*/
|
||||
typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
|
||||
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
|
||||
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
|
||||
|
||||
/*
|
||||
These functions generate the xxHash of an input provided in multiple segments.
|
||||
Note that, for small input, they are slower than single-call functions, due to state management.
|
||||
For small input, prefer `XXH32()` and `XXH64()` .
|
||||
|
||||
XXH state must first be allocated, using XXH*_createState() .
|
||||
|
||||
Start a new hash by initializing state with a seed, using XXH*_reset().
|
||||
|
||||
Then, feed the hash state by calling XXH*_update() as many times as necessary.
|
||||
Obviously, input must be allocated and read accessible.
|
||||
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
|
||||
|
||||
Finally, a hash value can be produced anytime, by using XXH*_digest().
|
||||
This function returns the nn-bits hash as an int or long long.
|
||||
|
||||
It's still possible to continue inserting input into the hash state after a digest,
|
||||
and generate some new hashes later on, by calling again XXH*_digest().
|
||||
|
||||
When done, free XXH state space if it was allocated dynamically.
|
||||
*/
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
|
||||
typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
|
||||
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
|
||||
|
||||
/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
|
||||
* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
|
||||
* These functions allow transformation of hash result into and from its canonical format.
|
||||
* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef XXH_NO_LONG_LONG
|
||||
/*-**********************************************************************
|
||||
* 64-bits hash
|
||||
************************************************************************/
|
||||
typedef unsigned long long XXH64_hash_t;
|
||||
|
||||
/*! XXH64() :
|
||||
Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
|
||||
"seed" can be used to alter the result predictably.
|
||||
This function runs faster on 64-bits systems, but slower on 32-bits systems (see benchmark).
|
||||
*/
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
|
||||
|
||||
/*====== Streaming ======*/
|
||||
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
|
||||
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
|
||||
#endif /* XXH_NO_LONG_LONG */
|
||||
|
||||
|
||||
#ifdef XXH_STATIC_LINKING_ONLY
|
||||
|
||||
/* ================================================================================================
|
||||
This section contains definitions which are not guaranteed to remain stable.
|
||||
They may change in future versions, becoming incompatible with a different version of the library.
|
||||
They shall only be used with static linking.
|
||||
Never use these definitions in association with dynamic linking !
|
||||
=================================================================================================== */
|
||||
|
||||
/* These definitions are only meant to make possible
|
||||
static allocation of XXH state, on stack or in a struct for example.
|
||||
Never use members directly. */
|
||||
|
||||
struct XXH32_state_s {
|
||||
unsigned total_len_32;
|
||||
unsigned large_len;
|
||||
unsigned v1;
|
||||
unsigned v2;
|
||||
unsigned v3;
|
||||
unsigned v4;
|
||||
unsigned mem32[4]; /* buffer defined as U32 for alignment */
|
||||
unsigned memsize;
|
||||
unsigned reserved; /* never read nor write, will be removed in a future version */
|
||||
}; /* typedef'd to XXH32_state_t */
|
||||
|
||||
#ifndef XXH_NO_LONG_LONG /* remove 64-bits support */
|
||||
struct XXH64_state_s {
|
||||
unsigned long long total_len;
|
||||
unsigned long long v1;
|
||||
unsigned long long v2;
|
||||
unsigned long long v3;
|
||||
unsigned long long v4;
|
||||
unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
|
||||
unsigned memsize;
|
||||
unsigned reserved[2]; /* never read nor write, will be removed in a future version */
|
||||
}; /* typedef'd to XXH64_state_t */
|
||||
#endif
|
||||
|
||||
#ifdef XXH_PRIVATE_API
|
||||
# include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */
|
||||
#endif
|
||||
|
||||
#endif /* XXH_STATIC_LINKING_ONLY */
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XXHASH_H_5627135585666179 */
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "common/Module.h"
|
||||
#include "common/StringMap.h"
|
||||
#include "Source.h"
|
||||
#include "RecordingDevice.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -189,34 +190,9 @@ public:
|
||||
virtual float getDopplerScale() const = 0;
|
||||
|
||||
/**
|
||||
* Begins recording audio input from the microphone.
|
||||
* @return Reference to a vector of pointers to recording devices. May be empty.
|
||||
**/
|
||||
virtual void record() = 0;
|
||||
|
||||
/**
|
||||
* Gets a section of recorded audio.
|
||||
* Per OpenAL, the measurement begins from the start of the
|
||||
* audio data in memory, which is after the last time this function
|
||||
* was called. If this function has not been called yet this recording
|
||||
* session, it just grabs from the beginning.
|
||||
* @return All the recorded SoundData thus far.
|
||||
**/
|
||||
virtual love::sound::SoundData *getRecordedData() = 0;
|
||||
|
||||
/**
|
||||
* Stops recording and, if passed true, returns all the recorded audio
|
||||
* not already gotten by getRecordedData.
|
||||
* @param returnData Whether to return recorded audio.
|
||||
* @return if returnData, all the recorded audio yet to be gotten,
|
||||
* otherwise NULL.
|
||||
**/
|
||||
virtual love::sound::SoundData *stopRecording(bool returnData) = 0;
|
||||
|
||||
/**
|
||||
* Checks whether LOVE is able to record audio input.
|
||||
* @return hasMic Whether LOVE has a microphone enabled.
|
||||
**/
|
||||
virtual bool canRecord() = 0;
|
||||
virtual const std::vector<RecordingDevice*> &getRecordingDevices() = 0;
|
||||
|
||||
/**
|
||||
* Gets the distance model used for attenuation.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 "RecordingDevice.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
|
||||
love::Type RecordingDevice::type("RecordingDevice", &Object::type);
|
||||
|
||||
RecordingDevice::RecordingDevice()
|
||||
{
|
||||
}
|
||||
|
||||
RecordingDevice::~RecordingDevice()
|
||||
{
|
||||
}
|
||||
|
||||
} //audio
|
||||
} //love
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 = 0; 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_AUDIO_RECORDING_DEVICE_H
|
||||
#define LOVE_AUDIO_RECORDING_DEVICE_H
|
||||
|
||||
#include "common/Object.h"
|
||||
#include "sound/SoundData.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
|
||||
class RecordingDevice : public love::Object
|
||||
{
|
||||
public:
|
||||
|
||||
static love::Type type;
|
||||
|
||||
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.
|
||||
* @param sampleRate Desired sample rate.
|
||||
* @param bitDepth Desired bit depth (8 or 16).
|
||||
* @param channels Desired number of channels.
|
||||
* @return True if recording started successfully.
|
||||
**/
|
||||
virtual bool start(int samples, int sampleRate, int bitDepth, int channels) = 0;
|
||||
|
||||
/**
|
||||
* Stops audio input recording.
|
||||
**/
|
||||
virtual void stop() = 0;
|
||||
|
||||
/**
|
||||
* Retreives recorded data.
|
||||
* @return SoundData containing data obtained from recording device.
|
||||
**/
|
||||
virtual love::sound::SoundData *getData() = 0;
|
||||
|
||||
/**
|
||||
* @return C string device name.
|
||||
**/
|
||||
virtual const char *getName() const = 0;
|
||||
|
||||
/**
|
||||
* @return Number of samples currently recorded.
|
||||
**/
|
||||
virtual int getSampleCount() const = 0;
|
||||
|
||||
/**
|
||||
* @return Sample rate for recording.
|
||||
**/
|
||||
virtual int getSampleRate() const = 0;
|
||||
|
||||
/**
|
||||
* @return Bit depth for recording.
|
||||
**/
|
||||
virtual int getBitDepth() const = 0;
|
||||
|
||||
/**
|
||||
* @return Number of channels for recording.
|
||||
**/
|
||||
virtual int getChannels() const = 0;
|
||||
|
||||
/**
|
||||
* @return True if currently recording.
|
||||
**/
|
||||
virtual bool isRecording() const = 0;
|
||||
}; //RecordingDevice
|
||||
|
||||
} //audio
|
||||
} //love
|
||||
|
||||
#endif //LOVE_AUDIO_RECORDING_DEVICE_H
|
||||
@@ -144,23 +144,9 @@ float Audio::getDopplerScale() const
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void Audio::record()
|
||||
const std::vector<love::audio::RecordingDevice*> &Audio::getRecordingDevices()
|
||||
{
|
||||
}
|
||||
|
||||
love::sound::SoundData *Audio::getRecordedData()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
love::sound::SoundData *Audio::stopRecording(bool)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Audio::canRecord()
|
||||
{
|
||||
return false;
|
||||
return capture;
|
||||
}
|
||||
|
||||
Audio::DistanceModel Audio::getDistanceModel() const
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
// LOVE
|
||||
#include "audio/Audio.h"
|
||||
|
||||
#include "RecordingDevice.h"
|
||||
#include "Source.h"
|
||||
|
||||
namespace love
|
||||
@@ -70,10 +71,7 @@ public:
|
||||
void setDopplerScale(float scale);
|
||||
float getDopplerScale() const;
|
||||
|
||||
void record();
|
||||
love::sound::SoundData *getRecordedData();
|
||||
love::sound::SoundData *stopRecording(bool returnData);
|
||||
bool canRecord();
|
||||
const std::vector<love::audio::RecordingDevice*> &getRecordingDevices();
|
||||
|
||||
DistanceModel getDistanceModel() const;
|
||||
void setDistanceModel(DistanceModel distanceModel);
|
||||
@@ -81,6 +79,7 @@ public:
|
||||
private:
|
||||
float volume;
|
||||
DistanceModel distanceModel;
|
||||
std::vector<love::audio::RecordingDevice*> capture;
|
||||
|
||||
}; // Audio
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 = 0; 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 "RecordingDevice.h"
|
||||
#include "Audio.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
namespace null
|
||||
{
|
||||
|
||||
const char *RecordingDevice::name = "null";
|
||||
|
||||
RecordingDevice::RecordingDevice(const char *)
|
||||
{
|
||||
}
|
||||
|
||||
RecordingDevice::~RecordingDevice()
|
||||
{
|
||||
}
|
||||
|
||||
bool RecordingDevice::start()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RecordingDevice::start(int, int, int, int)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void RecordingDevice::stop()
|
||||
{
|
||||
}
|
||||
|
||||
love::sound::SoundData *RecordingDevice::getData()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int RecordingDevice::getSampleCount() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RecordingDevice::getSampleRate() const
|
||||
{
|
||||
return 8000;
|
||||
}
|
||||
|
||||
int RecordingDevice::getBitDepth() const
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
int RecordingDevice::getChannels() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *RecordingDevice::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
bool RecordingDevice::isRecording() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} //null
|
||||
} //audio
|
||||
} //love
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 = 0; 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_AUDIO_NULL_RECORDING_DEVICE_H
|
||||
#define LOVE_AUDIO_NULL_RECORDING_DEVICE_H
|
||||
|
||||
#include "audio/RecordingDevice.h"
|
||||
#include "sound/SoundData.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
namespace null
|
||||
{
|
||||
|
||||
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();
|
||||
virtual const char *getName() const;
|
||||
virtual int getSampleCount() const;
|
||||
virtual int getSampleRate() const;
|
||||
virtual int getBitDepth() const;
|
||||
virtual int getChannels() const;
|
||||
virtual bool isRecording() const;
|
||||
|
||||
private:
|
||||
static const char *name;
|
||||
}; //RecordingDevice
|
||||
|
||||
} //null
|
||||
} //audio
|
||||
} //love
|
||||
|
||||
#endif //LOVE_AUDIO_NULL_RECORDING_DEVICE_H
|
||||
@@ -20,10 +20,11 @@
|
||||
|
||||
#include "Audio.h"
|
||||
#include "common/delay.h"
|
||||
|
||||
#include "RecordingDevice.h"
|
||||
#include "sound/Decoder.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -67,9 +68,29 @@ void Audio::PoolThread::setFinish()
|
||||
finish = true;
|
||||
}
|
||||
|
||||
ALenum Audio::getFormat(int bitDepth, int channels)
|
||||
{
|
||||
if (bitDepth != 8 && bitDepth != 16)
|
||||
return AL_NONE;
|
||||
|
||||
if (channels == 1)
|
||||
return bitDepth == 8 ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16;
|
||||
else if (channels == 2)
|
||||
return bitDepth == 8 ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16;
|
||||
#ifdef AL_EXT_MCFORMATS
|
||||
else if (alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
||||
{
|
||||
if (channels == 6)
|
||||
return bitDepth == 8 ? AL_FORMAT_51CHN8 : AL_FORMAT_51CHN16;
|
||||
else if (channels == 8)
|
||||
return bitDepth == 8 ? AL_FORMAT_71CHN8 : AL_FORMAT_71CHN16;
|
||||
}
|
||||
#endif
|
||||
return AL_NONE;
|
||||
}
|
||||
|
||||
Audio::Audio()
|
||||
: device(nullptr)
|
||||
, capture(nullptr)
|
||||
, context(nullptr)
|
||||
, pool(nullptr)
|
||||
, poolThread(nullptr)
|
||||
@@ -89,26 +110,6 @@ Audio::Audio()
|
||||
if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR)
|
||||
throw love::Exception("Could not make context current.");
|
||||
|
||||
/*std::string captureName(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
|
||||
const ALCchar * devices = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
|
||||
while (*devices)
|
||||
{
|
||||
std::string device(devices);
|
||||
devices += device.size() + 1;
|
||||
if (device.find("Mic") != std::string::npos || device.find("mic") != std::string::npos)
|
||||
{
|
||||
captureName = device;
|
||||
}
|
||||
}
|
||||
|
||||
capture = alcCaptureOpenDevice(captureName.c_str(), 8000, AL_FORMAT_MONO16, 262144); // about 32 seconds
|
||||
|
||||
if (!capture)
|
||||
{
|
||||
// We're not going to prevent LOVE from running without a microphone, but we should warn, at least
|
||||
std::cerr << "Warning, couldn't open capture device! No audio input!" << std::endl;
|
||||
}*/
|
||||
|
||||
// pool must be allocated after AL context.
|
||||
try
|
||||
{
|
||||
@@ -118,8 +119,10 @@ Audio::Audio()
|
||||
{
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(context);
|
||||
//if (capture) alcCaptureCloseDevice(capture);
|
||||
alcCloseDevice(device);
|
||||
for (auto c : capture)
|
||||
delete c;
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -137,8 +140,9 @@ Audio::~Audio()
|
||||
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(context);
|
||||
//if (capture) alcCaptureCloseDevice(capture);
|
||||
alcCloseDevice(device);
|
||||
for (auto c : capture)
|
||||
delete c;
|
||||
}
|
||||
|
||||
|
||||
@@ -265,44 +269,6 @@ float Audio::getDopplerScale() const
|
||||
return alGetFloat(AL_DOPPLER_FACTOR);
|
||||
}
|
||||
|
||||
void Audio::record()
|
||||
{
|
||||
if (!canRecord()) return;
|
||||
alcCaptureStart(capture);
|
||||
}
|
||||
|
||||
love::sound::SoundData *Audio::getRecordedData()
|
||||
{
|
||||
if (!canRecord())
|
||||
return NULL;
|
||||
int samplerate = 8000;
|
||||
ALCint samples;
|
||||
alcGetIntegerv(capture, ALC_CAPTURE_SAMPLES, 4, &samples);
|
||||
void *data = malloc(samples * (2/sizeof(char)));
|
||||
alcCaptureSamples(capture, data, samples);
|
||||
love::sound::SoundData *sd = new love::sound::SoundData(data, samples, samplerate, 16, 1);
|
||||
free(data);
|
||||
return sd;
|
||||
}
|
||||
|
||||
love::sound::SoundData *Audio::stopRecording(bool returnData)
|
||||
{
|
||||
if (!canRecord())
|
||||
return NULL;
|
||||
love::sound::SoundData *sd = NULL;
|
||||
if (returnData)
|
||||
{
|
||||
sd = getRecordedData();
|
||||
}
|
||||
alcCaptureStop(capture);
|
||||
return sd;
|
||||
}
|
||||
|
||||
bool Audio::canRecord()
|
||||
{
|
||||
return (capture != NULL);
|
||||
}
|
||||
|
||||
Audio::DistanceModel Audio::getDistanceModel() const
|
||||
{
|
||||
return distanceModel;
|
||||
@@ -347,6 +313,76 @@ void Audio::setDistanceModel(DistanceModel distanceModel)
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<love::audio::RecordingDevice*> &Audio::getRecordingDevices()
|
||||
{
|
||||
std::vector<std::string> devnames;
|
||||
std::vector<love::audio::RecordingDevice*> devices;
|
||||
|
||||
std::string defaultname(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
|
||||
|
||||
//no device name obtained from AL, fallback to reading from device
|
||||
if (defaultname.length() == 0)
|
||||
{
|
||||
//use some safe basic parameters - 8 kHz, 8 bits, 1 channel
|
||||
ALCdevice *defaultdevice = alcCaptureOpenDevice(NULL, 8000, 8, 1);
|
||||
if (alGetError() == AL_NO_ERROR)
|
||||
{
|
||||
defaultname = alcGetString(defaultdevice, ALC_CAPTURE_DEVICE_SPECIFIER);
|
||||
alcCaptureCloseDevice(defaultdevice);
|
||||
}
|
||||
else
|
||||
{
|
||||
//failed to open default recording device - bail, return empty list
|
||||
capture.clear();
|
||||
return capture;
|
||||
}
|
||||
}
|
||||
|
||||
devnames.reserve(capture.size());
|
||||
devnames.push_back(defaultname);
|
||||
|
||||
//find devices name list
|
||||
const ALCchar *devstr = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
|
||||
size_t offset = 0;
|
||||
while (true)
|
||||
{
|
||||
if (devstr[offset] == '\0')
|
||||
break;
|
||||
std::string str((ALCchar*)&devstr[offset]);
|
||||
if (str != defaultname)
|
||||
devnames.push_back(str);
|
||||
offset += str.length() + 1;
|
||||
}
|
||||
|
||||
devices.reserve(devnames.size());
|
||||
//build ordered list of devices
|
||||
for (int i = 0; i < (int) devnames.size(); i++)
|
||||
{
|
||||
devices.push_back(nullptr);
|
||||
auto d = devices.end() - 1;
|
||||
|
||||
for (auto c : capture)
|
||||
if (devnames[i] == c->getName())
|
||||
*d = c;
|
||||
|
||||
if (*d == nullptr)
|
||||
*d = new RecordingDevice(devnames[i].c_str());
|
||||
else
|
||||
(*d)->retain();
|
||||
}
|
||||
|
||||
for (auto c : capture)
|
||||
c->release();
|
||||
capture.clear();
|
||||
capture.reserve(devices.size());
|
||||
|
||||
//this needs to be executed in specific order
|
||||
for (unsigned int i = 0; i < devnames.size(); i++)
|
||||
capture.push_back(devices[i]);
|
||||
|
||||
return capture;
|
||||
}
|
||||
|
||||
} // openal
|
||||
} // audio
|
||||
} // love
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
// LOVE
|
||||
#include "audio/Audio.h"
|
||||
#include "audio/RecordingDevice.h"
|
||||
#include "common/config.h"
|
||||
#include "sound/SoundData.h"
|
||||
|
||||
@@ -65,6 +66,15 @@ public:
|
||||
Audio();
|
||||
~Audio();
|
||||
|
||||
/**
|
||||
* Gets the OpenAL format identifier based on number of
|
||||
* channels and bits.
|
||||
* @param channels.
|
||||
* @param bitDepth Either 8-bit samples, or 16-bit samples.
|
||||
* @return One of AL_FORMAT_*, or AL_NONE if unsupported format.
|
||||
**/
|
||||
static ALenum getFormat(int bitDepth, int channels);
|
||||
|
||||
// Implements Module.
|
||||
const char *getName() const;
|
||||
|
||||
@@ -95,10 +105,7 @@ public:
|
||||
void setDopplerScale(float scale);
|
||||
float getDopplerScale() const;
|
||||
|
||||
void record();
|
||||
love::sound::SoundData *getRecordedData();
|
||||
love::sound::SoundData *stopRecording(bool returnData);
|
||||
bool canRecord();
|
||||
const std::vector<love::audio::RecordingDevice*> &getRecordingDevices();
|
||||
|
||||
DistanceModel getDistanceModel() const;
|
||||
void setDistanceModel(DistanceModel distanceModel);
|
||||
@@ -108,8 +115,8 @@ private:
|
||||
// The OpenAL device.
|
||||
ALCdevice *device;
|
||||
|
||||
// The OpenAL capture device (microphone).
|
||||
ALCdevice *capture;
|
||||
// The OpenAL capture devices.
|
||||
std::vector<love::audio::RecordingDevice*> capture;
|
||||
|
||||
// The OpenAL context.
|
||||
ALCcontext *context;
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 = 0; 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 "RecordingDevice.h"
|
||||
#include "Audio.h"
|
||||
#include "sound/Sound.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
namespace openal
|
||||
{
|
||||
|
||||
#define soundInstance() (Module::getInstance<love::sound::Sound>(Module::M_SOUND))
|
||||
|
||||
class InvalidFormatException : public love::Exception
|
||||
{
|
||||
public:
|
||||
|
||||
InvalidFormatException(int channels, int bitdepth)
|
||||
: Exception("Recording %d channels with %d bits per sample is not supported.", channels, bitdepth)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
RecordingDevice::RecordingDevice(const char *name)
|
||||
: name(name)
|
||||
{
|
||||
}
|
||||
|
||||
RecordingDevice::~RecordingDevice()
|
||||
{
|
||||
if (!isRecording())
|
||||
return;
|
||||
|
||||
alcCaptureStop(device);
|
||||
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);
|
||||
|
||||
if (samples <= 0)
|
||||
throw love::Exception("Invalid number of samples.");
|
||||
|
||||
if (sampleRate <= 0)
|
||||
throw love::Exception("Invalid sample rate.");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void RecordingDevice::stop()
|
||||
{
|
||||
if (!isRecording())
|
||||
return;
|
||||
|
||||
alcCaptureStop(device);
|
||||
alcCaptureCloseDevice(device);
|
||||
device = nullptr;
|
||||
}
|
||||
|
||||
love::sound::SoundData *RecordingDevice::getData()
|
||||
{
|
||||
if (!isRecording())
|
||||
return nullptr;
|
||||
|
||||
int samples = getSampleCount();
|
||||
if (samples == 0)
|
||||
return nullptr;
|
||||
|
||||
love::sound::SoundData *soundData = soundInstance()->newSoundData(samples, sampleRate, bitDepth, channels);
|
||||
|
||||
alcCaptureSamples(device, soundData->getData(), samples);
|
||||
|
||||
return soundData;
|
||||
}
|
||||
|
||||
int RecordingDevice::getSampleCount() const
|
||||
{
|
||||
if (!isRecording())
|
||||
return 0;
|
||||
|
||||
ALCint samples;
|
||||
alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, sizeof(ALCint), &samples);
|
||||
return (int)samples;
|
||||
}
|
||||
|
||||
int RecordingDevice::getSampleRate() const
|
||||
{
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
int RecordingDevice::getBitDepth() const
|
||||
{
|
||||
return bitDepth;
|
||||
}
|
||||
|
||||
int RecordingDevice::getChannels() const
|
||||
{
|
||||
return channels;
|
||||
}
|
||||
|
||||
const char *RecordingDevice::getName() const
|
||||
{
|
||||
return name.c_str();
|
||||
}
|
||||
|
||||
bool RecordingDevice::isRecording() const
|
||||
{
|
||||
return device != nullptr;
|
||||
}
|
||||
|
||||
} //openal
|
||||
} //audio
|
||||
} //love
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 = 0; 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_AUDIO_OPENAL_RECORDING_DEVICE_H
|
||||
#define LOVE_AUDIO_OPENAL_RECORDING_DEVICE_H
|
||||
|
||||
#include "common/config.h"
|
||||
|
||||
#ifdef LOVE_APPLE_USE_FRAMEWORKS
|
||||
#ifdef LOVE_IOS
|
||||
#include <OpenAL/alc.h>
|
||||
#include <OpenAL/al.h>
|
||||
#else
|
||||
#include <OpenAL-Soft/alc.h>
|
||||
#include <OpenAL-Soft/al.h>
|
||||
#endif
|
||||
#else
|
||||
#include <AL/alc.h>
|
||||
#include <AL/al.h>
|
||||
#endif
|
||||
|
||||
#include "audio/RecordingDevice.h"
|
||||
#include "sound/SoundData.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
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();
|
||||
virtual const char *getName() const;
|
||||
virtual int getSampleCount() const;
|
||||
virtual int getSampleRate() const;
|
||||
virtual int getBitDepth() const;
|
||||
virtual int getChannels() const;
|
||||
virtual bool isRecording() const;
|
||||
|
||||
private:
|
||||
int samples = 8192;
|
||||
int sampleRate = 8000;
|
||||
int bitDepth = 16;
|
||||
int channels = 1;
|
||||
std::string name;
|
||||
ALCdevice *device = nullptr;
|
||||
}; //RecordingDevice
|
||||
|
||||
} //openal
|
||||
} //audio
|
||||
} //love
|
||||
|
||||
#endif //LOVE_AUDIO_OPENAL_RECORDING_DEVICE_H
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Source.h"
|
||||
#include "Pool.h"
|
||||
#include "Audio.h"
|
||||
#include "common/math.h"
|
||||
|
||||
// STD
|
||||
@@ -119,8 +120,8 @@ Source::Source(Pool *pool, love::sound::SoundData *soundData)
|
||||
, channels(soundData->getChannels())
|
||||
, bitDepth(soundData->getBitDepth())
|
||||
{
|
||||
ALenum fmt = getFormat(soundData->getChannels(), soundData->getBitDepth());
|
||||
if (fmt == 0)
|
||||
ALenum fmt = Audio::getFormat(soundData->getBitDepth(), soundData->getChannels());
|
||||
if (fmt == AL_NONE)
|
||||
throw InvalidFormatException(soundData->getChannels(), soundData->getBitDepth());
|
||||
|
||||
staticBuffer.set(new StaticDataBuffer(fmt, soundData->getData(), (ALsizei) soundData->getSize(), sampleRate), Acquire::NORETAIN);
|
||||
@@ -141,7 +142,7 @@ Source::Source(Pool *pool, love::sound::Decoder *decoder)
|
||||
, decoder(decoder)
|
||||
, unusedBufferTop(MAX_BUFFERS - 1)
|
||||
{
|
||||
if (getFormat(decoder->getChannels(), decoder->getBitDepth()) == 0)
|
||||
if (Audio::getFormat(decoder->getBitDepth(), decoder->getChannels()) == AL_NONE)
|
||||
throw InvalidFormatException(decoder->getChannels(), decoder->getBitDepth());
|
||||
|
||||
alGenBuffers(MAX_BUFFERS, streamBuffers);
|
||||
@@ -162,8 +163,8 @@ Source::Source(Pool *pool, int sampleRate, int bitDepth, int channels)
|
||||
, channels(channels)
|
||||
, bitDepth(bitDepth)
|
||||
{
|
||||
ALenum fmt = getFormat(channels, bitDepth);
|
||||
if (fmt == 0)
|
||||
ALenum fmt = Audio::getFormat(bitDepth, channels);
|
||||
if (fmt == AL_NONE)
|
||||
throw InvalidFormatException(channels, bitDepth);
|
||||
|
||||
alGenBuffers(MAX_BUFFERS, streamBuffers);
|
||||
@@ -280,10 +281,12 @@ bool Source::update()
|
||||
switch (sourceType)
|
||||
{
|
||||
case TYPE_STATIC:
|
||||
{
|
||||
// Looping mode could have changed.
|
||||
// FIXME: make looping mode not change without you noticing so that this is not needed
|
||||
// FIXME: make looping mode change atomically so this is not needed
|
||||
alSourcei(source, AL_LOOPING, isLooping() ? AL_TRUE : AL_FALSE);
|
||||
return !isFinished();
|
||||
}
|
||||
case TYPE_STREAM:
|
||||
if (!isFinished())
|
||||
{
|
||||
@@ -401,24 +404,26 @@ void Source::seekAtomic(float offset, void *unit)
|
||||
break;
|
||||
}
|
||||
|
||||
bool wasPlaying = isPlaying();
|
||||
switch (sourceType)
|
||||
{
|
||||
case TYPE_STATIC:
|
||||
alSourcef(source, AL_SAMPLE_OFFSET, offsetSamples);
|
||||
offsetSamples = offsetSeconds = 0;
|
||||
if (valid)
|
||||
{
|
||||
alSourcef(source, AL_SAMPLE_OFFSET, offsetSamples);
|
||||
offsetSamples = offsetSeconds = 0;
|
||||
}
|
||||
break;
|
||||
case TYPE_STREAM:
|
||||
{
|
||||
bool wasPlaying = isPlaying();
|
||||
|
||||
// To drain all buffers
|
||||
if (valid)
|
||||
stopAtomic();
|
||||
stop();
|
||||
|
||||
decoder->seek(offsetSeconds);
|
||||
|
||||
if (wasPlaying)
|
||||
playAtomic(source);
|
||||
play();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -454,6 +459,13 @@ void Source::seekAtomic(float offset, void *unit)
|
||||
case TYPE_MAX_ENUM:
|
||||
break;
|
||||
}
|
||||
if (wasPlaying && (alGetError() == AL_INVALID_VALUE || (sourceType == TYPE_STREAM && !isPlaying())))
|
||||
{
|
||||
stop();
|
||||
if (isLooping())
|
||||
play();
|
||||
return;
|
||||
}
|
||||
this->offsetSamples = offsetSamples;
|
||||
this->offsetSeconds = offsetSeconds;
|
||||
}
|
||||
@@ -688,7 +700,7 @@ bool Source::queueAtomic(void *data, ALsizei length)
|
||||
if (buffer == AL_NONE)
|
||||
return false;
|
||||
|
||||
alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate);
|
||||
alBufferData(buffer, Audio::getFormat(bitDepth, channels), data, length, sampleRate);
|
||||
alSourceQueueBuffers(source, 1, &buffer);
|
||||
unusedBufferPop();
|
||||
}
|
||||
@@ -699,7 +711,7 @@ bool Source::queueAtomic(void *data, ALsizei length)
|
||||
return false;
|
||||
|
||||
//stack acts as queue while stopped
|
||||
alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate);
|
||||
alBufferData(buffer, Audio::getFormat(bitDepth, channels), data, length, sampleRate);
|
||||
unusedBufferQueue(buffer);
|
||||
}
|
||||
bufferedBytes += length;
|
||||
@@ -734,9 +746,6 @@ void Source::prepareAtomic()
|
||||
{
|
||||
case TYPE_STATIC:
|
||||
alSourcei(source, AL_BUFFER, staticBuffer->getBuffer());
|
||||
//source can be seeked while not valid
|
||||
if (offsetSamples >= 0)
|
||||
alSourcef(source, AL_SAMPLE_OFFSET, offsetSamples);
|
||||
break;
|
||||
case TYPE_STREAM:
|
||||
while (unusedBufferPeek() != AL_NONE)
|
||||
@@ -760,8 +769,6 @@ void Source::prepareAtomic()
|
||||
for (unsigned int i = top + 1; i < MAX_BUFFERS; i++)
|
||||
unusedBufferPush(unusedBuffers[i]);
|
||||
|
||||
if (offsetSamples >= 0)
|
||||
alSourcef(source, AL_SAMPLE_OFFSET, offsetSamples);
|
||||
break;
|
||||
}
|
||||
case TYPE_MAX_ENUM:
|
||||
@@ -774,7 +781,6 @@ void Source::teardownAtomic()
|
||||
switch (sourceType)
|
||||
{
|
||||
case TYPE_STATIC:
|
||||
alSourcef(source, AL_SAMPLE_OFFSET, 0);
|
||||
break;
|
||||
case TYPE_STREAM:
|
||||
{
|
||||
@@ -832,16 +838,32 @@ bool Source::playAtomic(ALuint source)
|
||||
|
||||
alSourcePlay(source);
|
||||
|
||||
// alSourcePlay may fail if the system has reached its limit of simultaneous
|
||||
// playing sources.
|
||||
bool success = alGetError() == AL_NO_ERROR;
|
||||
|
||||
valid = true; //if it fails it will be set to false again
|
||||
//but this prevents a horrible, horrible bug
|
||||
if (sourceType == TYPE_STREAM)
|
||||
{
|
||||
valid = true; //isPlaying() needs source to be valid
|
||||
if (!isPlaying())
|
||||
success = false;
|
||||
}
|
||||
else if (success)
|
||||
{
|
||||
alSourcef(source, AL_SAMPLE_OFFSET, offsetSamples);
|
||||
success = alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
valid = true; //stop() needs source to be valid
|
||||
stop();
|
||||
}
|
||||
if (sourceType != TYPE_STREAM)
|
||||
offsetSamples = offsetSeconds = 0;
|
||||
|
||||
//this is set to success state afterwards anyway, but setting it here
|
||||
//to true preemptively avoids race condition with update bug
|
||||
valid = true;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -862,7 +884,12 @@ void Source::pauseAtomic()
|
||||
void Source::resumeAtomic()
|
||||
{
|
||||
if (valid && !isPlaying())
|
||||
{
|
||||
alSourcePlay(source);
|
||||
|
||||
if (alGetError() == AL_INVALID_VALUE || (sourceType == TYPE_STREAM && unusedBufferTop == MAX_BUFFERS - 1))
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
bool Source::playAtomic(const std::vector<love::audio::Source*> &sources, const std::vector<ALuint> &ids, const std::vector<char> &wasPlaying)
|
||||
@@ -941,7 +968,7 @@ void Source::pauseAtomic(const std::vector<love::audio::Source*> &sources)
|
||||
|
||||
void Source::reset()
|
||||
{
|
||||
alSourcei(source, AL_BUFFER, 0);
|
||||
alSourcei(source, AL_BUFFER, AL_NONE);
|
||||
alSourcefv(source, AL_POSITION, position);
|
||||
alSourcefv(source, AL_VELOCITY, velocity);
|
||||
alSourcefv(source, AL_DIRECTION, direction);
|
||||
@@ -966,34 +993,6 @@ void Source::setFloatv(float *dst, const float *src) const
|
||||
dst[2] = src[2];
|
||||
}
|
||||
|
||||
ALenum Source::getFormat(int channels, int bitDepth) const
|
||||
{
|
||||
if (channels == 1 && bitDepth == 8)
|
||||
return AL_FORMAT_MONO8;
|
||||
else if (channels == 1 && bitDepth == 16)
|
||||
return AL_FORMAT_MONO16;
|
||||
else if (channels == 2 && bitDepth == 8)
|
||||
return AL_FORMAT_STEREO8;
|
||||
else if (channels == 2 && bitDepth == 16)
|
||||
return AL_FORMAT_STEREO16;
|
||||
|
||||
#ifdef AL_EXT_MCFORMATS
|
||||
if (alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
||||
{
|
||||
if (channels == 6 && bitDepth == 8)
|
||||
return AL_FORMAT_51CHN8;
|
||||
else if (channels == 6 && bitDepth == 16)
|
||||
return AL_FORMAT_51CHN16;
|
||||
else if (channels == 8 && bitDepth == 8)
|
||||
return AL_FORMAT_71CHN8;
|
||||
else if (channels == 8 && bitDepth == 16)
|
||||
return AL_FORMAT_71CHN16;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ALuint Source::unusedBufferPeek()
|
||||
{
|
||||
return (unusedBufferTop < 0) ? AL_NONE : unusedBuffers[unusedBufferTop];
|
||||
@@ -1029,9 +1028,9 @@ int Source::streamAtomic(ALuint buffer, love::sound::Decoder *d)
|
||||
// OpenAL implementations are allowed to ignore 0-size alBufferData calls.
|
||||
if (decoded > 0)
|
||||
{
|
||||
int fmt = getFormat(d->getChannels(), d->getBitDepth());
|
||||
int fmt = Audio::getFormat(d->getBitDepth(), d->getChannels());
|
||||
|
||||
if (fmt != 0)
|
||||
if (fmt != AL_NONE)
|
||||
alBufferData(buffer, fmt, d->getBuffer(), decoded, d->getSampleRate());
|
||||
else
|
||||
decoded = 0;
|
||||
|
||||
@@ -163,15 +163,6 @@ private:
|
||||
|
||||
void setFloatv(float *dst, const float *src) const;
|
||||
|
||||
/**
|
||||
* Gets the OpenAL format identifier based on number of
|
||||
* channels and bits.
|
||||
* @param channels Either 1 (mono) or 2 (stereo).
|
||||
* @param bitDepth Either 8-bit samples, or 16-bit samples.
|
||||
* @return One of AL_FORMAT_*, or 0 if unsupported format.
|
||||
**/
|
||||
ALenum getFormat(int channels, int bitDepth) const;
|
||||
|
||||
int streamAtomic(ALuint buffer, love::sound::Decoder *d);
|
||||
|
||||
ALuint unusedBufferPeek();
|
||||
|
||||
@@ -257,49 +257,6 @@ int w_getDopplerScale(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_record(lua_State *)
|
||||
{
|
||||
instance()->record();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getRecordedData(lua_State *L)
|
||||
{
|
||||
love::sound::SoundData *sd = instance()->getRecordedData();
|
||||
if (!sd)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
{
|
||||
luax_pushtype(L, sd);
|
||||
sd->release();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_stopRecording(lua_State *L)
|
||||
{
|
||||
if (luax_optboolean(L, 1, true))
|
||||
{
|
||||
love::sound::SoundData *sd = instance()->stopRecording(true);
|
||||
if (!sd)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
{
|
||||
luax_pushtype(L, sd);
|
||||
sd->release();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
instance()->stopRecording(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_canRecord(lua_State *L)
|
||||
{
|
||||
luax_pushboolean(L, instance()->canRecord());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_setDistanceModel(lua_State *L)
|
||||
{
|
||||
const char *modelStr = luaL_checkstring(L, 1);
|
||||
@@ -320,6 +277,21 @@ int w_getDistanceModel(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_getRecordingDevices(lua_State *L)
|
||||
{
|
||||
const std::vector<RecordingDevice*> &devices = instance()->getRecordingDevices();
|
||||
|
||||
lua_createtable(L, devices.size(), 0);
|
||||
|
||||
for (unsigned int i = 0; i < devices.size(); i++)
|
||||
{
|
||||
luax_pushtype(L, devices[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// List of functions to wrap.
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
@@ -339,17 +311,16 @@ static const luaL_Reg functions[] =
|
||||
{ "getVelocity", w_getVelocity },
|
||||
{ "setDopplerScale", w_setDopplerScale },
|
||||
{ "getDopplerScale", w_getDopplerScale },
|
||||
/*{ "record", w_record },
|
||||
{ "getRecordedData", w_getRecordedData },
|
||||
{ "stopRecording", w_stopRecording },*/
|
||||
{ "setDistanceModel", w_setDistanceModel },
|
||||
{ "getDistanceModel", w_getDistanceModel },
|
||||
{ "getRecordingDevices", w_getRecordingDevices },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static const lua_CFunction types[] =
|
||||
{
|
||||
luaopen_source,
|
||||
luaopen_recordingdevice,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "common/runtime.h"
|
||||
#include "Audio.h"
|
||||
#include "wrap_Source.h"
|
||||
#include "wrap_RecordingDevice.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 "wrap_RecordingDevice.h"
|
||||
#include "wrap_Audio.h"
|
||||
|
||||
#include "sound/SoundData.h"
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
|
||||
RecordingDevice *luax_checkrecordingdevice(lua_State *L, int idx)
|
||||
{
|
||||
return luax_checktype<RecordingDevice>(L, 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()); });
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RecordingDevice_stop(lua_State *L)
|
||||
{
|
||||
RecordingDevice *d = luax_checkrecordingdevice(L, 1);
|
||||
love::sound::SoundData *s = nullptr;
|
||||
|
||||
luax_catchexcept(L, [&](){ s = d->getData(); });
|
||||
|
||||
d->stop();
|
||||
|
||||
if (s != nullptr)
|
||||
{
|
||||
luax_pushtype(L, s);
|
||||
s->release();
|
||||
}
|
||||
else
|
||||
lua_pushnil(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RecordingDevice_getData(lua_State *L)
|
||||
{
|
||||
RecordingDevice *d = luax_checkrecordingdevice(L, 1);
|
||||
love::sound::SoundData *s = nullptr;
|
||||
|
||||
luax_catchexcept(L, [&](){ s = d->getData(); });
|
||||
|
||||
if (s != nullptr)
|
||||
{
|
||||
luax_pushtype(L, s);
|
||||
s->release();
|
||||
}
|
||||
else
|
||||
lua_pushnil(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RecordingDevice_getSampleCount(lua_State *L)
|
||||
{
|
||||
RecordingDevice *d = luax_checkrecordingdevice(L, 1);
|
||||
lua_pushnumber(L, d->getSampleCount());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RecordingDevice_getSampleRate(lua_State *L)
|
||||
{
|
||||
RecordingDevice *d = luax_checkrecordingdevice(L, 1);
|
||||
lua_pushnumber(L, d->getSampleRate());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RecordingDevice_getBitDepth(lua_State *L)
|
||||
{
|
||||
RecordingDevice *d = luax_checkrecordingdevice(L, 1);
|
||||
lua_pushnumber(L, d->getBitDepth());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RecordingDevice_getChannels(lua_State *L)
|
||||
{
|
||||
RecordingDevice *d = luax_checkrecordingdevice(L, 1);
|
||||
lua_pushnumber(L, d->getChannels());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RecordingDevice_getName(lua_State *L)
|
||||
{
|
||||
RecordingDevice *d = luax_checkrecordingdevice(L, 1);
|
||||
lua_pushstring(L, d->getName());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RecordingDevice_isRecording(lua_State *L)
|
||||
{
|
||||
RecordingDevice *d = luax_checkrecordingdevice(L, 1);
|
||||
lua_pushboolean(L, d->isRecording());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg w_RecordingDevice_functions[] =
|
||||
{
|
||||
{ "start", w_RecordingDevice_start },
|
||||
{ "stop", w_RecordingDevice_stop },
|
||||
{ "getData", w_RecordingDevice_getData },
|
||||
{ "getSampleCount", w_RecordingDevice_getSampleCount },
|
||||
{ "getSampleRate", w_RecordingDevice_getSampleRate },
|
||||
{ "getBitDepth", w_RecordingDevice_getBitDepth },
|
||||
{ "getChannels", w_RecordingDevice_getChannels },
|
||||
{ "getName", w_RecordingDevice_getName },
|
||||
{ "isRecording", w_RecordingDevice_isRecording },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
extern "C" int luaopen_recordingdevice(lua_State *L)
|
||||
{
|
||||
int ret = luax_register_type(L, &RecordingDevice::type, w_RecordingDevice_functions, nullptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} //audio
|
||||
} //love
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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_AUDIO_WRAP_RECORDING_DEVICE_H
|
||||
#define LOVE_AUDIO_WRAP_RECORDING_DEVICE_H
|
||||
|
||||
// LOVE
|
||||
#include "common/runtime.h"
|
||||
#include "RecordingDevice.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
|
||||
RecordingDevice *luax_checkrecordingdevice(lua_State *L, int idx);
|
||||
extern "C" int luaopen_recordingdevice(lua_State *L);
|
||||
|
||||
} // audio
|
||||
} // love
|
||||
|
||||
#endif //LOVE_AUDIO_WRAP_RECORDING_DEVICE_H
|
||||
|
||||
@@ -112,6 +112,8 @@ Event::~Event()
|
||||
|
||||
void Event::pump()
|
||||
{
|
||||
exceptionIfInRenderPass();
|
||||
|
||||
SDL_Event e;
|
||||
|
||||
while (SDL_PollEvent(&e))
|
||||
@@ -127,6 +129,8 @@ void Event::pump()
|
||||
|
||||
Message *Event::wait()
|
||||
{
|
||||
exceptionIfInRenderPass();
|
||||
|
||||
SDL_Event e;
|
||||
|
||||
if (SDL_WaitEvent(&e) != 1)
|
||||
@@ -137,6 +141,8 @@ Message *Event::wait()
|
||||
|
||||
void Event::clear()
|
||||
{
|
||||
exceptionIfInRenderPass();
|
||||
|
||||
SDL_Event e;
|
||||
|
||||
while (SDL_PollEvent(&e))
|
||||
@@ -147,6 +153,17 @@ void Event::clear()
|
||||
love::event::Event::clear();
|
||||
}
|
||||
|
||||
void Event::exceptionIfInRenderPass()
|
||||
{
|
||||
// Some core OS graphics functionality (e.g. swap buffers on some platforms)
|
||||
// happens inside SDL_PumpEvents - which is called by SDL_PollEvent and
|
||||
// friends. It's probably a bad idea to call those functions while we're in
|
||||
// a render pass.
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
if (gfx != nullptr && gfx->isPassActive())
|
||||
throw love::Exception("Cannot call this function while a render pass is active in love.graphics.");
|
||||
}
|
||||
|
||||
Message *Event::convert(const SDL_Event &e) const
|
||||
{
|
||||
Message *msg = nullptr;
|
||||
|
||||
@@ -68,6 +68,8 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void exceptionIfInRenderPass();
|
||||
|
||||
Message *convert(const SDL_Event &e) const;
|
||||
Message *convertJoystickEvent(const SDL_Event &e) const;
|
||||
Message *convertWindowEvent(const SDL_Event &e) const;
|
||||
|
||||
@@ -53,15 +53,16 @@ int w_poll(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_pump(lua_State *)
|
||||
int w_pump(lua_State *L)
|
||||
{
|
||||
instance()->pump();
|
||||
luax_catchexcept(L, [&]() { instance()->pump(); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_wait(lua_State *L)
|
||||
{
|
||||
Message *m = instance()->wait();
|
||||
Message *m = nullptr;
|
||||
luax_catchexcept(L, [&]() { m = instance()->wait(); });
|
||||
if (m)
|
||||
{
|
||||
int args = m->toLua(L);
|
||||
@@ -85,9 +86,9 @@ int w_push(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_clear(lua_State *)
|
||||
int w_clear(lua_State *L)
|
||||
{
|
||||
instance()->clear();
|
||||
luax_catchexcept(L, [&]() { instance()->clear(); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,6 +260,8 @@ StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM>::Entry Graphics::featur
|
||||
{ "multicanvasformats", FEATURE_MULTI_CANVAS_FORMATS },
|
||||
{ "clampzero", FEATURE_CLAMP_ZERO },
|
||||
{ "lighten", FEATURE_LIGHTEN },
|
||||
{ "fullnpot", FEATURE_FULL_NPOT },
|
||||
{ "pixelshaderhighp", FEATURE_PIXEL_SHADER_HIGHP },
|
||||
};
|
||||
|
||||
StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM> Graphics::features(Graphics::featureEntries, sizeof(Graphics::featureEntries));
|
||||
@@ -270,6 +272,7 @@ StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM>::Entry Graphics::syst
|
||||
{ "texturesize", LIMIT_TEXTURE_SIZE },
|
||||
{ "multicanvas", LIMIT_MULTI_CANVAS },
|
||||
{ "canvasmsaa", LIMIT_CANVAS_MSAA },
|
||||
{ "anisotropy", LIMIT_ANISOTROPY },
|
||||
};
|
||||
|
||||
StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM> Graphics::systemLimits(Graphics::systemLimitEntries, sizeof(Graphics::systemLimitEntries));
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace love
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
const int MAX_COLOR_RENDER_TARGETS = 16;
|
||||
|
||||
/**
|
||||
* Globally sets whether gamma correction is enabled. Ideally this should be set
|
||||
* prior to using any Graphics module function.
|
||||
@@ -59,6 +61,14 @@ void gammaCorrectColor(Colorf &c);
|
||||
**/
|
||||
void unGammaCorrectColor(Colorf &c);
|
||||
|
||||
class RenderOutsidePassException : public love::Exception
|
||||
{
|
||||
public:
|
||||
RenderOutsidePassException()
|
||||
: Exception("Cannot draw outside of a render pass!")
|
||||
{}
|
||||
};
|
||||
|
||||
class Graphics : public Module
|
||||
{
|
||||
public:
|
||||
@@ -143,6 +153,8 @@ public:
|
||||
FEATURE_MULTI_CANVAS_FORMATS,
|
||||
FEATURE_CLAMP_ZERO,
|
||||
FEATURE_LIGHTEN,
|
||||
FEATURE_FULL_NPOT,
|
||||
FEATURE_PIXEL_SHADER_HIGHP,
|
||||
FEATURE_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -159,6 +171,7 @@ public:
|
||||
LIMIT_TEXTURE_SIZE,
|
||||
LIMIT_MULTI_CANVAS,
|
||||
LIMIT_CANVAS_MSAA,
|
||||
LIMIT_ANISOTROPY,
|
||||
LIMIT_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -180,7 +193,7 @@ public:
|
||||
struct Stats
|
||||
{
|
||||
int drawCalls;
|
||||
int canvasSwitches;
|
||||
int renderPasses;
|
||||
int shaderSwitches;
|
||||
int canvases;
|
||||
int images;
|
||||
@@ -259,6 +272,8 @@ public:
|
||||
**/
|
||||
virtual bool isActive() const = 0;
|
||||
|
||||
virtual bool isPassActive() const = 0;
|
||||
|
||||
static bool getConstant(const char *in, DrawMode &out);
|
||||
static bool getConstant(DrawMode in, const char *&out);
|
||||
|
||||
|
||||
@@ -36,11 +36,10 @@ namespace opengl
|
||||
static GLenum createFBO(GLuint &framebuffer, GLuint texture)
|
||||
{
|
||||
// get currently bound fbo to reset to it later
|
||||
GLint current_fbo;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo);
|
||||
GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
|
||||
|
||||
glGenFramebuffers(1, &framebuffer);
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, framebuffer);
|
||||
|
||||
if (texture != 0)
|
||||
{
|
||||
@@ -53,14 +52,19 @@ static GLenum createFBO(GLuint &framebuffer, GLuint texture)
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
|
||||
// unbind framebuffer
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, (GLuint) current_fbo);
|
||||
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo);
|
||||
return status;
|
||||
}
|
||||
|
||||
static GLenum createMSAABuffer(int width, int height, int &samples, GLenum iformat, GLuint &buffer)
|
||||
static bool createMSAABuffer(int width, int height, int &samples, GLenum iformat, GLuint &buffer)
|
||||
{
|
||||
GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
|
||||
|
||||
// Temporary FBO used to clear the renderbuffer.
|
||||
GLuint fbo = 0;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, fbo);
|
||||
|
||||
glGenRenderbuffers(1, &buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, buffer);
|
||||
|
||||
@@ -73,7 +77,7 @@ static GLenum createMSAABuffer(int width, int height, int &samples, GLenum iform
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
|
||||
if (status == GL_FRAMEBUFFER_COMPLETE)
|
||||
if (status == GL_FRAMEBUFFER_COMPLETE && samples > 1)
|
||||
{
|
||||
// Initialize the buffer to transparent black.
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
@@ -83,23 +87,22 @@ static GLenum createMSAABuffer(int width, int height, int &samples, GLenum iform
|
||||
{
|
||||
glDeleteRenderbuffers(1, &buffer);
|
||||
buffer = 0;
|
||||
samples = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo);
|
||||
gl.deleteFramebuffer(fbo);
|
||||
|
||||
return status == GL_FRAMEBUFFER_COMPLETE && samples > 1;
|
||||
}
|
||||
|
||||
love::Type Canvas::type("Canvas", &Texture::type);
|
||||
Canvas *Canvas::current = nullptr;
|
||||
OpenGL::Viewport Canvas::systemViewport = OpenGL::Viewport();
|
||||
bool Canvas::screenHasSRGB = false;
|
||||
int Canvas::canvasCount = 0;
|
||||
|
||||
Canvas::Canvas(int width, int height, Format format, int msaa)
|
||||
: fbo(0)
|
||||
, resolve_fbo(0)
|
||||
, texture(0)
|
||||
, msaa_buffer(0)
|
||||
, depth_stencil(0)
|
||||
, format(format)
|
||||
, requested_samples(msaa)
|
||||
, actual_samples(0)
|
||||
@@ -144,65 +147,18 @@ Canvas::Canvas(int width, int height, Format format, int msaa)
|
||||
Canvas::~Canvas()
|
||||
{
|
||||
--canvasCount;
|
||||
|
||||
// reset framebuffer if still using this one
|
||||
if (current == this)
|
||||
stopGrab();
|
||||
|
||||
unloadVolatile();
|
||||
}
|
||||
|
||||
bool Canvas::createMSAAFBO(GLenum internalformat)
|
||||
{
|
||||
actual_samples = requested_samples;
|
||||
|
||||
if (actual_samples <= 1)
|
||||
{
|
||||
actual_samples = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create our FBO without a texture.
|
||||
status = createFBO(fbo, 0);
|
||||
|
||||
GLuint previous = gl.getDefaultFBO();
|
||||
if (current != this)
|
||||
{
|
||||
if (current != nullptr)
|
||||
previous = current->fbo;
|
||||
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
}
|
||||
|
||||
// Create and attach the MSAA buffer for our FBO.
|
||||
status = createMSAABuffer(width, height, actual_samples, internalformat, msaa_buffer);
|
||||
|
||||
// Create the FBO used for the MSAA resolve, and attach the texture.
|
||||
if (status == GL_FRAMEBUFFER_COMPLETE)
|
||||
status = createFBO(resolve_fbo, texture);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
// Clean up.
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
glDeleteFramebuffers(1, &resolve_fbo);
|
||||
glDeleteRenderbuffers(1, &msaa_buffer);
|
||||
fbo = msaa_buffer = resolve_fbo = 0;
|
||||
actual_samples = 0;
|
||||
}
|
||||
|
||||
if (current != this)
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, previous);
|
||||
|
||||
return status == GL_FRAMEBUFFER_COMPLETE;
|
||||
}
|
||||
|
||||
bool Canvas::loadVolatile()
|
||||
{
|
||||
if (texture != 0)
|
||||
return true;
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Canvas load");
|
||||
|
||||
fbo = depth_stencil = texture = 0;
|
||||
resolve_fbo = msaa_buffer = 0;
|
||||
fbo = texture = 0;
|
||||
msaa_buffer = 0;
|
||||
status = GL_FRAMEBUFFER_COMPLETE;
|
||||
|
||||
// glTexImage2D is guaranteed to error in this case.
|
||||
@@ -240,8 +196,8 @@ bool Canvas::loadVolatile()
|
||||
while (glGetError() != GL_NO_ERROR)
|
||||
/* Clear the error buffer. */;
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, iformat, width, height, 0,
|
||||
externalformat, textype, nullptr);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, iformat, width, height, 0, externalformat,
|
||||
textype, nullptr);
|
||||
|
||||
if (glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
@@ -251,24 +207,27 @@ bool Canvas::loadVolatile()
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to create a MSAA FBO if requested. On failure (or no requested MSAA),
|
||||
// fall back to a regular FBO.
|
||||
if (!createMSAAFBO(internalformat))
|
||||
status = createFBO(fbo, texture);
|
||||
// Create a canvas-local FBO used for glReadPixels as well as MSAA blitting.
|
||||
status = createFBO(fbo, texture);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
if (fbo != 0)
|
||||
{
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
fbo = 0;
|
||||
}
|
||||
{
|
||||
if (fbo != 0)
|
||||
{
|
||||
gl.deleteFramebuffer(fbo);
|
||||
fbo = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
actual_samples = requested_samples == 1 ? 0 : requested_samples;
|
||||
|
||||
if (actual_samples > 0 && !createMSAABuffer(width, height, actual_samples, internalformat, msaa_buffer))
|
||||
actual_samples = 0;
|
||||
|
||||
size_t prevmemsize = texture_memory;
|
||||
|
||||
texture_memory = (getFormatBitsPerPixel(format) * width * height) / 8;
|
||||
texture_memory = ((getFormatBitsPerPixel(format) * width) / 8) * height;
|
||||
if (msaa_buffer != 0)
|
||||
texture_memory += (texture_memory * actual_samples);
|
||||
|
||||
@@ -279,33 +238,35 @@ bool Canvas::loadVolatile()
|
||||
|
||||
void Canvas::unloadVolatile()
|
||||
{
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
glDeleteFramebuffers(1, &resolve_fbo);
|
||||
if (fbo != 0)
|
||||
gl.deleteFramebuffer(fbo);
|
||||
|
||||
glDeleteRenderbuffers(1, &depth_stencil);
|
||||
glDeleteRenderbuffers(1, &msaa_buffer);
|
||||
if (msaa_buffer != 0)
|
||||
glDeleteRenderbuffers(1, &msaa_buffer);
|
||||
|
||||
gl.deleteTexture(texture);
|
||||
if (texture != 0)
|
||||
gl.deleteTexture(texture);
|
||||
|
||||
fbo = 0;
|
||||
resolve_fbo = 0;
|
||||
depth_stencil = 0;
|
||||
msaa_buffer = 0;
|
||||
texture = 0;
|
||||
|
||||
attachedCanvases.clear();
|
||||
|
||||
gl.updateTextureMemorySize(texture_memory, 0);
|
||||
texture_memory = 0;
|
||||
}
|
||||
|
||||
void Canvas::drawv(const Matrix4 &t, const Vertex *v)
|
||||
{
|
||||
// FIXME: This doesn't handle cases where the Canvas is used as a texture
|
||||
// in a SpriteBatch, Mesh, or ParticleSystem, or when the Canvas is used in
|
||||
// a shader as a non-default texture.
|
||||
if (Canvas::current == this)
|
||||
throw love::Exception("Cannot draw a Canvas to itself.");
|
||||
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
||||
if (gfx != nullptr)
|
||||
{
|
||||
const PassInfo &info = gfx->getActivePass();
|
||||
for (const auto &attachment : info.colorAttachments)
|
||||
{
|
||||
if (attachment.canvas == this)
|
||||
throw love::Exception("Cannot render a Canvas to itself!");
|
||||
}
|
||||
}
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Canvas draw");
|
||||
|
||||
@@ -378,320 +339,6 @@ const void *Canvas::getHandle() const
|
||||
return &texture;
|
||||
}
|
||||
|
||||
void Canvas::setupGrab()
|
||||
{
|
||||
// already grabbing
|
||||
if (current == this)
|
||||
return;
|
||||
|
||||
// cleanup after previous Canvas
|
||||
if (current != nullptr)
|
||||
{
|
||||
systemViewport = current->systemViewport;
|
||||
current->stopGrab(true);
|
||||
}
|
||||
else
|
||||
systemViewport = gl.getViewport();
|
||||
|
||||
// indicate we are using this Canvas.
|
||||
current = this;
|
||||
|
||||
// bind the framebuffer object.
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
gl.setViewport({0, 0, width, height});
|
||||
|
||||
// Set up the projection matrix
|
||||
gl.matrices.projection.push_back(Matrix4::ortho(0.0, (float) width, 0.0, (float) height));
|
||||
}
|
||||
|
||||
void Canvas::startGrab(const std::vector<Canvas *> &canvases)
|
||||
{
|
||||
// Whether the new canvas list is different from the old one.
|
||||
// A more thorough check is done below.
|
||||
bool canvaseschanged = canvases.size() != attachedCanvases.size();
|
||||
bool hasSRGBcanvas = getSizedFormat(format) == FORMAT_SRGB;
|
||||
|
||||
if (canvases.size() > 0)
|
||||
{
|
||||
if ((int) canvases.size() + 1 > gl.getMaxRenderTargets())
|
||||
throw love::Exception("This system can't simultaneously render to %d canvases.", canvases.size()+1);
|
||||
|
||||
if (actual_samples != 0)
|
||||
throw love::Exception("Multi-canvas rendering is not supported with MSAA.");
|
||||
}
|
||||
|
||||
bool multiformatsupported = isMultiFormatMultiCanvasSupported();
|
||||
|
||||
for (size_t i = 0; i < canvases.size(); i++)
|
||||
{
|
||||
if (canvases[i]->getWidth() != width || canvases[i]->getHeight() != height)
|
||||
throw love::Exception("All canvases must have the same dimensions.");
|
||||
|
||||
Format otherformat = canvases[i]->getTextureFormat();
|
||||
|
||||
if (otherformat != format && !multiformatsupported)
|
||||
throw love::Exception("This system doesn't support multi-canvas rendering with different canvas formats.");
|
||||
|
||||
if (canvases[i]->getMSAA() != 0)
|
||||
throw love::Exception("Multi-canvas rendering is not supported with MSAA.");
|
||||
|
||||
if (!canvaseschanged && canvases[i] != attachedCanvases[i])
|
||||
canvaseschanged = true;
|
||||
|
||||
if (getSizedFormat(otherformat) == FORMAT_SRGB)
|
||||
hasSRGBcanvas = true;
|
||||
}
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Canvas set");
|
||||
|
||||
setupGrab();
|
||||
|
||||
// Make sure the correct sRGB setting is used when drawing to the canvases.
|
||||
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
|
||||
{
|
||||
if (hasSRGBcanvas && !gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(true);
|
||||
else if (!hasSRGBcanvas && gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(false);
|
||||
}
|
||||
|
||||
// Don't attach anything if there's nothing to change.
|
||||
if (!canvaseschanged)
|
||||
return;
|
||||
|
||||
// Attach the canvas textures to the active FBO and set up MRTs.
|
||||
std::vector<GLenum> drawbuffers;
|
||||
drawbuffers.reserve(canvases.size() + 1);
|
||||
|
||||
drawbuffers.push_back(GL_COLOR_ATTACHMENT0);
|
||||
|
||||
// Attach the canvas textures to the currently bound framebuffer.
|
||||
for (int i = 0; i < (int) canvases.size(); i++)
|
||||
{
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 + i,
|
||||
GL_TEXTURE_2D, *(GLuint *) canvases[i]->getHandle(), 0);
|
||||
|
||||
drawbuffers.push_back(GL_COLOR_ATTACHMENT1 + i);
|
||||
}
|
||||
|
||||
// set up multiple render targets
|
||||
glDrawBuffers((int) drawbuffers.size(), &drawbuffers[0]);
|
||||
|
||||
// We want to avoid reference cycles, so we don't retain the attached
|
||||
// Canvases here. The code in Graphics::setCanvas retains them.
|
||||
|
||||
attachedCanvases = canvases;
|
||||
}
|
||||
|
||||
void Canvas::startGrab()
|
||||
{
|
||||
OpenGL::TempDebugGroup debuggroup("Canvas set");
|
||||
|
||||
setupGrab();
|
||||
|
||||
// Make sure the correct sRGB setting is used when drawing to the canvas.
|
||||
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
|
||||
{
|
||||
bool isSRGB = getSizedFormat(format) == FORMAT_SRGB;
|
||||
if (isSRGB && !gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(true);
|
||||
else if (!isSRGB && gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(false);
|
||||
}
|
||||
|
||||
if (attachedCanvases.size() > 0)
|
||||
{
|
||||
// Make sure the FBO is only using a single draw buffer.
|
||||
// GLES3 only has glDrawBuffers, so we avoid using glDrawBuffer.
|
||||
const GLenum buffers[] = {GL_COLOR_ATTACHMENT0};
|
||||
glDrawBuffers(1, buffers);
|
||||
|
||||
attachedCanvases.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::stopGrab(bool switchingToOtherCanvas)
|
||||
{
|
||||
// i am not grabbing. leave me alone
|
||||
if (current != this)
|
||||
return;
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Canvas un-set");
|
||||
|
||||
// Make sure the canvas texture is up to date if we're using MSAA.
|
||||
resolveMSAA(false);
|
||||
|
||||
if (gl.matrices.projection.size() > 1)
|
||||
gl.matrices.projection.pop_back();
|
||||
|
||||
if (!switchingToOtherCanvas)
|
||||
{
|
||||
// bind system framebuffer.
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, gl.getDefaultFBO());
|
||||
current = nullptr;
|
||||
gl.setViewport(systemViewport);
|
||||
|
||||
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
|
||||
{
|
||||
if (screenHasSRGB && !gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(true);
|
||||
else if (!screenHasSRGB && gl.hasFramebufferSRGB())
|
||||
gl.setFramebufferSRGB(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Canvas::checkCreateStencil()
|
||||
{
|
||||
// Do nothing if we've already created the stencil buffer.
|
||||
if (depth_stencil != 0)
|
||||
return true;
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Canvas create stencil");
|
||||
|
||||
if (current != this)
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
GLenum format = GL_STENCIL_INDEX8;
|
||||
std::vector<GLenum> attachments = {GL_STENCIL_ATTACHMENT};
|
||||
|
||||
// Prefer a combined depth/stencil buffer.
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object)
|
||||
{
|
||||
format = GL_DEPTH24_STENCIL8;
|
||||
attachments = {GL_DEPTH_STENCIL_ATTACHMENT};
|
||||
}
|
||||
else if (GLAD_EXT_packed_depth_stencil || GLAD_OES_packed_depth_stencil)
|
||||
{
|
||||
format = GL_DEPTH24_STENCIL8;
|
||||
attachments = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
|
||||
}
|
||||
|
||||
glGenRenderbuffers(1, &depth_stencil);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil);
|
||||
|
||||
if (requested_samples > 1)
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, requested_samples, format, width, height);
|
||||
else
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
|
||||
|
||||
// Attach the buffer to the framebuffer object.
|
||||
for (GLenum attachment : attachments)
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, depth_stencil);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
bool success = glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
|
||||
|
||||
// We don't want the stencil buffer filled with garbage.
|
||||
if (success)
|
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
else
|
||||
{
|
||||
glDeleteRenderbuffers(1, &depth_stencil);
|
||||
depth_stencil = 0;
|
||||
}
|
||||
|
||||
if (current && current != this)
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, current->fbo);
|
||||
else if (!current)
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, gl.getDefaultFBO());
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
love::image::ImageData *Canvas::newImageData(love::image::Image *image, int x, int y, int w, int h)
|
||||
{
|
||||
if (x < 0 || y < 0 || w <= 0 || h <= 0 || (x + w) > width || (y + h) > height)
|
||||
throw love::Exception("Invalid ImageData rectangle dimensions.");
|
||||
|
||||
GLenum datatype = GL_UNSIGNED_BYTE;
|
||||
image::ImageData::Format imageformat = image::ImageData::FORMAT_RGBA8;
|
||||
|
||||
switch (getSizedFormat(format))
|
||||
{
|
||||
case FORMAT_RGB10A2: // FIXME: Conversions aren't supported in GLES
|
||||
datatype = GL_UNSIGNED_SHORT;
|
||||
imageformat = image::ImageData::FORMAT_RGBA16;
|
||||
break;
|
||||
case FORMAT_R16F:
|
||||
case FORMAT_RG16F:
|
||||
case FORMAT_RGBA16F:
|
||||
case FORMAT_RG11B10F: // FIXME: Conversions aren't supported in GLES
|
||||
datatype = GL_HALF_FLOAT;
|
||||
imageformat = image::ImageData::FORMAT_RGBA16F;
|
||||
break;
|
||||
case FORMAT_R32F:
|
||||
case FORMAT_RG32F:
|
||||
case FORMAT_RGBA32F:
|
||||
datatype = GL_FLOAT;
|
||||
imageformat = image::ImageData::FORMAT_RGBA32F;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
size_t size = w * h * image::ImageData::getPixelSize(imageformat);
|
||||
uint8 *pixels = nullptr;
|
||||
try
|
||||
{
|
||||
pixels = new uint8[size];
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
throw love::Exception("Out of memory.");
|
||||
}
|
||||
|
||||
// Make sure the canvas texture is up to date if we're using MSAA.
|
||||
if (current == this)
|
||||
resolveMSAA(false);
|
||||
|
||||
// Our texture is attached to 'resolve_fbo' when we use MSAA.
|
||||
if (resolve_fbo != 0)
|
||||
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo);
|
||||
else
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
glReadPixels(x, y, w, h, GL_RGBA, datatype, pixels);
|
||||
|
||||
GLuint prevfbo = current ? current->fbo : gl.getDefaultFBO();
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, prevfbo);
|
||||
|
||||
// The new ImageData now owns the pixel data, so we don't delete it here.
|
||||
return image->newImageData(w, h, imageformat, pixels, true);
|
||||
}
|
||||
|
||||
bool Canvas::resolveMSAA(bool restoreprev)
|
||||
{
|
||||
if (resolve_fbo == 0 || msaa_buffer == 0)
|
||||
return false;
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Canvas MSAA resolve");
|
||||
|
||||
GLint w = width;
|
||||
GLint h = height;
|
||||
|
||||
// Do the MSAA resolve by blitting the MSAA renderbuffer to the texture.
|
||||
// For many of the MSAA extensions that add suffixes to the functions, we
|
||||
// assign function pointers in OpenGL.cpp so we can call the core functions.
|
||||
|
||||
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);
|
||||
|
||||
if (GLAD_APPLE_framebuffer_multisample)
|
||||
glResolveMultisampleFramebufferAPPLE();
|
||||
else
|
||||
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
if (restoreprev)
|
||||
{
|
||||
GLuint fbo = current ? current->fbo : gl.getDefaultFBO();
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Canvas::Format Canvas::getSizedFormat(Canvas::Format format)
|
||||
{
|
||||
switch (format)
|
||||
@@ -950,7 +597,7 @@ bool Canvas::isFormatSupported(Canvas::Format format)
|
||||
|
||||
GLuint fbo = 0;
|
||||
supported = (createFBO(fbo, texture) == GL_FRAMEBUFFER_COMPLETE);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
gl.deleteFramebuffer(fbo);
|
||||
|
||||
gl.deleteTexture(texture);
|
||||
|
||||
|
||||
@@ -84,26 +84,6 @@ public:
|
||||
bool setWrap(const Texture::Wrap &w) override;
|
||||
const void *getHandle() const override;
|
||||
|
||||
/**
|
||||
* @param canvases A list of other canvases to temporarily attach to this one,
|
||||
* to allow drawing to multiple canvases at once.
|
||||
**/
|
||||
void startGrab(const std::vector<Canvas *> &canvases);
|
||||
void startGrab();
|
||||
void stopGrab(bool switchingToOtherCanvas = false);
|
||||
|
||||
/**
|
||||
* Create and attach a stencil buffer to this Canvas' framebuffer, if necessary.
|
||||
**/
|
||||
bool checkCreateStencil();
|
||||
|
||||
love::image::ImageData *newImageData(love::image::Image *image, int x, int y, int w, int h);
|
||||
|
||||
inline const std::vector<Canvas *> &getAttachedCanvases() const
|
||||
{
|
||||
return attachedCanvases;
|
||||
}
|
||||
|
||||
inline GLenum getStatus() const
|
||||
{
|
||||
return status;
|
||||
@@ -119,19 +99,26 @@ public:
|
||||
return actual_samples;
|
||||
}
|
||||
|
||||
inline int getRequestedMSAA() const
|
||||
{
|
||||
return requested_samples;
|
||||
}
|
||||
|
||||
inline ptrdiff_t getMSAAHandle() const
|
||||
{
|
||||
return msaa_buffer;
|
||||
}
|
||||
|
||||
inline GLuint getFBO() const
|
||||
{
|
||||
return fbo;
|
||||
}
|
||||
|
||||
static Format getSizedFormat(Format format);
|
||||
static bool isSupported();
|
||||
static bool isMultiFormatMultiCanvasSupported();
|
||||
static bool isFormatSupported(Format format);
|
||||
|
||||
static Canvas *current;
|
||||
|
||||
// The viewport dimensions of the system (default) framebuffer.
|
||||
static OpenGL::Viewport systemViewport;
|
||||
|
||||
// Whether the main screen should have linear -> sRGB conversions enabled.
|
||||
static bool screenHasSRGB;
|
||||
|
||||
static int canvasCount;
|
||||
|
||||
static bool getConstant(const char *in, Format &out);
|
||||
@@ -139,29 +126,20 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void setupGrab();
|
||||
|
||||
bool createMSAAFBO(GLenum internalformat);
|
||||
bool resolveMSAA(bool restoreprev);
|
||||
|
||||
void drawv(const Matrix4 &t, const Vertex *v);
|
||||
|
||||
static void convertFormat(Format format, GLenum &internalformat, GLenum &externalformat, GLenum &type);
|
||||
static size_t getFormatBitsPerPixel(Format format);
|
||||
|
||||
GLuint fbo;
|
||||
GLuint resolve_fbo;
|
||||
|
||||
GLuint texture;
|
||||
GLuint msaa_buffer;
|
||||
GLuint depth_stencil;
|
||||
|
||||
Format format;
|
||||
|
||||
GLenum status;
|
||||
|
||||
std::vector<Canvas *> attachedCanvases;
|
||||
|
||||
int requested_samples;
|
||||
int actual_samples;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@
|
||||
// STD
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
// OpenGL
|
||||
#include "OpenGL.h"
|
||||
@@ -35,10 +36,10 @@
|
||||
#include "image/Image.h"
|
||||
#include "image/ImageData.h"
|
||||
|
||||
#include "window/Window.h"
|
||||
|
||||
#include "video/VideoStream.h"
|
||||
|
||||
#include "math/Transform.h"
|
||||
|
||||
#include "Font.h"
|
||||
#include "Image.h"
|
||||
#include "graphics/Quad.h"
|
||||
@@ -53,21 +54,63 @@
|
||||
|
||||
namespace love
|
||||
{
|
||||
|
||||
class Reference;
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
struct PassInfo
|
||||
{
|
||||
enum BeginAction
|
||||
{
|
||||
BEGIN_LOAD,
|
||||
BEGIN_CLEAR,
|
||||
BEGIN_DISCARD,
|
||||
};
|
||||
|
||||
enum EndAction
|
||||
{
|
||||
END_STORE,
|
||||
END_DISCARD,
|
||||
};
|
||||
|
||||
struct ColorAttachment
|
||||
{
|
||||
Canvas *canvas = nullptr;
|
||||
Colorf clearColor = Colorf(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
BeginAction beginAction = BEGIN_LOAD;
|
||||
};
|
||||
|
||||
ColorAttachment colorAttachments[MAX_COLOR_RENDER_TARGETS];
|
||||
int colorAttachmentCount = 0;
|
||||
|
||||
bool stencil = false;
|
||||
|
||||
bool addColorAttachment(const ColorAttachment &attachment)
|
||||
{
|
||||
if (colorAttachmentCount + 1 < MAX_COLOR_RENDER_TARGETS)
|
||||
{
|
||||
colorAttachments[colorAttachmentCount++] = attachment;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class Graphics : public love::graphics::Graphics
|
||||
{
|
||||
public:
|
||||
|
||||
struct OptionalColorf
|
||||
{
|
||||
float r, g, b, a;
|
||||
bool enabled;
|
||||
typedef void (*ScreenshotCallback)(love::image::ImageData *i, Reference *ref, void *ud);
|
||||
|
||||
Colorf toColor() const { return Colorf(r, g, b, a); }
|
||||
struct ScreenshotInfo
|
||||
{
|
||||
ScreenshotCallback callback;
|
||||
Reference *ref;
|
||||
};
|
||||
|
||||
Graphics();
|
||||
@@ -92,25 +135,19 @@ public:
|
||||
**/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Clears the screen to a specific color.
|
||||
**/
|
||||
void clear(Colorf c);
|
||||
void beginPass(PassInfo::BeginAction beginAction, Colorf clearColor);
|
||||
void beginPass(const PassInfo &info);
|
||||
|
||||
/**
|
||||
* Clears each active canvas to a different color.
|
||||
**/
|
||||
void clear(const std::vector<OptionalColorf> &colors);
|
||||
void endPass();
|
||||
void endPass(int sX, int sY, int sW, int sH, const ScreenshotInfo *info, void *screenshotCallbackData);
|
||||
|
||||
/**
|
||||
* Discards the contents of the screen.
|
||||
**/
|
||||
void discard(const std::vector<bool> &colorbuffers, bool stencil);
|
||||
const PassInfo &getActivePass() const;
|
||||
virtual bool isPassActive() const;
|
||||
|
||||
/**
|
||||
* Flips buffers. (Rendered geometry is presented on screen).
|
||||
**/
|
||||
void present();
|
||||
void present(void *screenshotCallbackData);
|
||||
|
||||
/**
|
||||
* Gets the width of the current graphics viewport.
|
||||
@@ -122,6 +159,9 @@ public:
|
||||
**/
|
||||
int getHeight() const;
|
||||
|
||||
int getPassWidth() const;
|
||||
int getPassHeight() const;
|
||||
|
||||
/**
|
||||
* True if a graphics viewport is set.
|
||||
**/
|
||||
@@ -231,13 +271,6 @@ public:
|
||||
|
||||
Shader *getShader() const;
|
||||
|
||||
void setCanvas(Canvas *canvas);
|
||||
void setCanvas(const std::vector<Canvas *> &canvases);
|
||||
void setCanvas(const std::vector<StrongRef<Canvas>> &canvases);
|
||||
void setCanvas();
|
||||
|
||||
std::vector<Canvas *> getCanvas() const;
|
||||
|
||||
/**
|
||||
* Sets the enabled color components when rendering.
|
||||
**/
|
||||
@@ -330,6 +363,9 @@ public:
|
||||
**/
|
||||
bool isWireframe() const;
|
||||
|
||||
void draw(Drawable *drawable, const Matrix4 &m);
|
||||
void drawq(Texture *texture, Quad *quad, const Matrix4 &m);
|
||||
|
||||
/**
|
||||
* Draws text at the specified coordinates
|
||||
**/
|
||||
@@ -422,12 +458,7 @@ public:
|
||||
**/
|
||||
void polygon(DrawMode mode, const float *coords, size_t count);
|
||||
|
||||
/**
|
||||
* Creates a screenshot of the view and saves it to the default folder.
|
||||
* @param image The love.image module.
|
||||
* @param copyAlpha If the alpha channel should be copied or set to full opacity (1.0).
|
||||
**/
|
||||
love::image::ImageData *newScreenshot(love::image::Image *image, bool copyAlpha = true);
|
||||
void captureScreenshot(const ScreenshotInfo &info);
|
||||
|
||||
/**
|
||||
* Returns system-dependent renderer information.
|
||||
@@ -459,6 +490,10 @@ public:
|
||||
void translate(float x, float y);
|
||||
void shear(float kx, float ky);
|
||||
void origin();
|
||||
|
||||
void applyTransform(love::math::Transform *transform);
|
||||
void replaceTransform(love::math::Transform *transform);
|
||||
|
||||
Vector transformPoint(Vector point);
|
||||
Vector inverseTransformPoint(Vector point);
|
||||
|
||||
@@ -488,8 +523,6 @@ private:
|
||||
StrongRef<Font> font;
|
||||
StrongRef<Shader> shader;
|
||||
|
||||
std::vector<StrongRef<Canvas>> canvases;
|
||||
|
||||
ColorMask colorMask = ColorMask(true, true, true, true);
|
||||
|
||||
bool wireframe = false;
|
||||
@@ -500,18 +533,46 @@ private:
|
||||
float defaultMipmapSharpness = 0.0f;
|
||||
};
|
||||
|
||||
struct CurrentPass
|
||||
{
|
||||
PassInfo info;
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
struct PassBufferInfo
|
||||
{
|
||||
bool stencil;
|
||||
Canvas *canvases[MAX_COLOR_RENDER_TARGETS];
|
||||
};
|
||||
|
||||
struct CachedRenderbuffer
|
||||
{
|
||||
int w;
|
||||
int h;
|
||||
int samples;
|
||||
GLenum attachments[2];
|
||||
GLuint renderbuffer;
|
||||
};
|
||||
|
||||
void restoreState(const DisplayState &s);
|
||||
void restoreStateChecked(const DisplayState &s);
|
||||
|
||||
void bindCachedFBOForPass(const PassInfo &pass);
|
||||
void discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil);
|
||||
GLuint attachCachedStencilBuffer(int w, int h, int samples);
|
||||
|
||||
void checkSetDefaultFont();
|
||||
|
||||
int calculateEllipsePoints(float rx, float ry) const;
|
||||
|
||||
StrongRef<love::window::Window> currentWindow;
|
||||
|
||||
StrongRef<Font> defaultFont;
|
||||
|
||||
std::vector<double> pixelSizeStack; // stores current size of a pixel (needed for line drawing)
|
||||
std::vector<double> pixelScaleStack;
|
||||
|
||||
std::vector<ScreenshotInfo> pendingScreenshotCallbacks;
|
||||
|
||||
std::unordered_map<uint32, GLuint> framebufferObjects;
|
||||
std::vector<CachedRenderbuffer> stencilBuffers;
|
||||
|
||||
QuadIndices *quadIndices;
|
||||
|
||||
@@ -520,11 +581,17 @@ private:
|
||||
bool created;
|
||||
bool active;
|
||||
|
||||
bool canCaptureScreenshot;
|
||||
|
||||
CurrentPass currentPass;
|
||||
|
||||
bool writingToStencil;
|
||||
|
||||
std::vector<DisplayState> states;
|
||||
std::vector<StackType> stackTypes; // Keeps track of the pushed stack types.
|
||||
|
||||
int renderPassCount;
|
||||
|
||||
static const size_t MAX_USER_STACK_DEPTH = 64;
|
||||
|
||||
}; // Graphics
|
||||
|
||||
@@ -283,6 +283,9 @@ void Image::loadFromImageData()
|
||||
|
||||
bool Image::loadVolatile()
|
||||
{
|
||||
if (texture != 0)
|
||||
return true;
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Image load");
|
||||
|
||||
if (isCompressed() && !hasCompressedTextureSupport(cdata[0]->getFormat(), sRGB))
|
||||
|
||||
@@ -311,7 +311,7 @@ bool Mesh::isAttributeEnabled(const std::string &name) const
|
||||
return it->second.enabled;
|
||||
}
|
||||
|
||||
void Mesh::attachAttribute(const std::string &name, Mesh *mesh)
|
||||
void Mesh::attachAttribute(const std::string &name, Mesh *mesh, const std::string &attachname)
|
||||
{
|
||||
if (mesh != this)
|
||||
{
|
||||
@@ -333,10 +333,10 @@ void Mesh::attachAttribute(const std::string &name, Mesh *mesh)
|
||||
|
||||
newattrib.mesh = mesh;
|
||||
newattrib.enabled = oldattrib.mesh ? oldattrib.enabled : true;
|
||||
newattrib.index = mesh->getAttributeIndex(name);
|
||||
newattrib.index = mesh->getAttributeIndex(attachname);
|
||||
|
||||
if (newattrib.index < 0)
|
||||
throw love::Exception("The specified mesh does not have a vertex attribute named '%s'", name.c_str());
|
||||
throw love::Exception("The specified mesh does not have a vertex attribute named '%s'", attachname.c_str());
|
||||
|
||||
if (newattrib.mesh != this)
|
||||
newattrib.mesh->retain();
|
||||
@@ -347,6 +347,24 @@ void Mesh::attachAttribute(const std::string &name, Mesh *mesh)
|
||||
oldattrib.mesh->release();
|
||||
}
|
||||
|
||||
bool Mesh::detachAttribute(const std::string &name)
|
||||
{
|
||||
auto it = attachedAttributes.find(name);
|
||||
|
||||
if (it != attachedAttributes.end() && it->second.mesh != this)
|
||||
{
|
||||
it->second.mesh->release();
|
||||
attachedAttributes.erase(it);
|
||||
|
||||
if (getAttributeIndex(name) != -1)
|
||||
attachAttribute(name, this, name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void *Mesh::mapVertexData()
|
||||
{
|
||||
return vbo->map();
|
||||
|
||||
@@ -140,7 +140,8 @@ public:
|
||||
* Attaches a vertex attribute from another Mesh to this one. The attribute
|
||||
* will be used when drawing this Mesh.
|
||||
**/
|
||||
void attachAttribute(const std::string &name, Mesh *mesh);
|
||||
void attachAttribute(const std::string &name, Mesh *mesh, const std::string &attachname);
|
||||
bool detachAttribute(const std::string &name);
|
||||
|
||||
void *mapVertexData();
|
||||
void unmapVertexData(size_t modifiedoffset = 0, size_t modifiedsize = -1);
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "OpenGL.h"
|
||||
|
||||
#include "Shader.h"
|
||||
#include "Canvas.h"
|
||||
#include "common/Exception.h"
|
||||
|
||||
// C++
|
||||
@@ -66,6 +65,7 @@ static void *LOVEGetProcAddress(const char *name)
|
||||
OpenGL::OpenGL()
|
||||
: stats()
|
||||
, contextInitialized(false)
|
||||
, pixelShaderHighpSupported(false)
|
||||
, maxAnisotropy(1.0f)
|
||||
, maxTextureSize(0)
|
||||
, maxRenderTargets(1)
|
||||
@@ -75,7 +75,6 @@ OpenGL::OpenGL()
|
||||
, state()
|
||||
{
|
||||
matrices.transform.reserve(10);
|
||||
matrices.projection.reserve(2);
|
||||
}
|
||||
|
||||
bool OpenGL::initContext()
|
||||
@@ -135,6 +134,10 @@ void OpenGL::setupContext()
|
||||
else
|
||||
state.pointSize = 1.0f;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
state.boundFramebuffers[i] = std::numeric_limits<GLuint>::max();
|
||||
bindFramebuffer(FRAMEBUFFER_ALL, getDefaultFBO());
|
||||
|
||||
if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
|
||||
|| GLAD_EXT_sRGB_write_control)
|
||||
{
|
||||
@@ -266,6 +269,16 @@ void OpenGL::initOpenGLFunctions()
|
||||
|
||||
void OpenGL::initMaxValues()
|
||||
{
|
||||
if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
|
||||
{
|
||||
GLint range = 0;
|
||||
GLint precision = 0;
|
||||
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, &range, &precision);
|
||||
pixelShaderHighpSupported = range > 0;
|
||||
}
|
||||
else
|
||||
pixelShaderHighpSupported = true;
|
||||
|
||||
// We'll need this value to clamp anisotropy.
|
||||
if (GLAD_EXT_texture_filter_anisotropic)
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
|
||||
@@ -283,7 +296,7 @@ void OpenGL::initMaxValues()
|
||||
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxdrawbuffers);
|
||||
}
|
||||
|
||||
maxRenderTargets = std::min(maxattachments, maxdrawbuffers);
|
||||
maxRenderTargets = std::max(std::min(maxattachments, maxdrawbuffers), 1);
|
||||
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object
|
||||
|| GLAD_EXT_framebuffer_multisample || GLAD_APPLE_framebuffer_multisample
|
||||
@@ -304,10 +317,9 @@ void OpenGL::initMaxValues()
|
||||
void OpenGL::initMatrices()
|
||||
{
|
||||
matrices.transform.clear();
|
||||
matrices.projection.clear();
|
||||
|
||||
matrices.transform.push_back(Matrix4());
|
||||
matrices.projection.push_back(Matrix4());
|
||||
matrices.projection = Matrix4();
|
||||
}
|
||||
|
||||
void OpenGL::createDefaultTexture()
|
||||
@@ -361,7 +373,7 @@ void OpenGL::prepareDraw()
|
||||
// because uniform uploads can be significantly slower than glLoadMatrix.
|
||||
if (GLAD_VERSION_1_0)
|
||||
{
|
||||
const Matrix4 &curproj = matrices.projection.back();
|
||||
const Matrix4 &curproj = matrices.projection;
|
||||
const Matrix4 &curxform = matrices.transform.back();
|
||||
|
||||
const Matrix4 &lastproj = state.lastProjectionMatrix;
|
||||
@@ -374,7 +386,7 @@ void OpenGL::prepareDraw()
|
||||
glLoadMatrixf(curproj.getElements());
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
state.lastProjectionMatrix = matrices.projection.back();
|
||||
state.lastProjectionMatrix = matrices.projection;
|
||||
}
|
||||
|
||||
// Same with the transform matrix.
|
||||
@@ -463,7 +475,7 @@ void OpenGL::useVertexAttribArrays(uint32 arraybits)
|
||||
glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void OpenGL::setViewport(const OpenGL::Viewport &v)
|
||||
void OpenGL::setViewport(const OpenGL::Viewport &v, bool canvasActive)
|
||||
{
|
||||
glViewport(v.x, v.y, v.w, v.h);
|
||||
state.viewport = v;
|
||||
@@ -471,7 +483,7 @@ void OpenGL::setViewport(const OpenGL::Viewport &v)
|
||||
// glScissor starts from the lower left, so we compensate when setting the
|
||||
// scissor. When the viewport is changed, we need to manually update the
|
||||
// scissor again.
|
||||
setScissor(state.scissor);
|
||||
setScissor(state.scissor, canvasActive);
|
||||
}
|
||||
|
||||
OpenGL::Viewport OpenGL::getViewport() const
|
||||
@@ -479,9 +491,9 @@ OpenGL::Viewport OpenGL::getViewport() const
|
||||
return state.viewport;
|
||||
}
|
||||
|
||||
void OpenGL::setScissor(const OpenGL::Viewport &v)
|
||||
void OpenGL::setScissor(const OpenGL::Viewport &v, bool canvasActive)
|
||||
{
|
||||
if (Canvas::current)
|
||||
if (canvasActive)
|
||||
glScissor(v.x, v.y, v.w, v.h);
|
||||
else
|
||||
{
|
||||
@@ -526,12 +538,53 @@ bool OpenGL::hasFramebufferSRGB() const
|
||||
return state.framebufferSRGBEnabled;
|
||||
}
|
||||
|
||||
void OpenGL::bindFramebuffer(GLenum target, GLuint framebuffer)
|
||||
void OpenGL::bindFramebuffer(FramebufferTarget target, GLuint framebuffer)
|
||||
{
|
||||
glBindFramebuffer(target, framebuffer);
|
||||
bool bindingmodified = false;
|
||||
|
||||
if (target == GL_FRAMEBUFFER)
|
||||
++stats.framebufferBinds;
|
||||
if ((target & FRAMEBUFFER_DRAW) && state.boundFramebuffers[0] != framebuffer)
|
||||
{
|
||||
bindingmodified = true;
|
||||
state.boundFramebuffers[0] = framebuffer;
|
||||
}
|
||||
|
||||
if ((target & FRAMEBUFFER_READ) && state.boundFramebuffers[1] != framebuffer)
|
||||
{
|
||||
bindingmodified = true;
|
||||
state.boundFramebuffers[1] = framebuffer;
|
||||
}
|
||||
|
||||
if (bindingmodified)
|
||||
{
|
||||
GLenum gltarget = GL_FRAMEBUFFER;
|
||||
if (target == FRAMEBUFFER_DRAW)
|
||||
gltarget = GL_DRAW_FRAMEBUFFER;
|
||||
else if (target == FRAMEBUFFER_READ)
|
||||
gltarget = GL_READ_FRAMEBUFFER;
|
||||
|
||||
glBindFramebuffer(gltarget, framebuffer);
|
||||
}
|
||||
}
|
||||
|
||||
GLenum OpenGL::getFramebuffer(FramebufferTarget target) const
|
||||
{
|
||||
if (target & FRAMEBUFFER_DRAW)
|
||||
return state.boundFramebuffers[0];
|
||||
else if (target & FRAMEBUFFER_READ)
|
||||
return state.boundFramebuffers[1];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OpenGL::deleteFramebuffer(GLuint framebuffer)
|
||||
{
|
||||
glDeleteFramebuffers(1, &framebuffer);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (state.boundFramebuffers[i] == framebuffer)
|
||||
state.boundFramebuffers[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGL::useProgram(GLuint program)
|
||||
@@ -673,6 +726,11 @@ bool OpenGL::isClampZeroTextureWrapSupported() const
|
||||
return GLAD_VERSION_1_3 || GLAD_EXT_texture_border_clamp || GLAD_NV_texture_border_clamp;
|
||||
}
|
||||
|
||||
bool OpenGL::isPixelShaderHighpSupported() const
|
||||
{
|
||||
return pixelShaderHighpSupported;
|
||||
}
|
||||
|
||||
int OpenGL::getMaxTextureSize() const
|
||||
{
|
||||
return maxTextureSize;
|
||||
@@ -680,7 +738,7 @@ int OpenGL::getMaxTextureSize() const
|
||||
|
||||
int OpenGL::getMaxRenderTargets() const
|
||||
{
|
||||
return maxRenderTargets;
|
||||
return std::min(maxRenderTargets, MAX_COLOR_RENDER_TARGETS);
|
||||
}
|
||||
|
||||
int OpenGL::getMaxRenderbufferSamples() const
|
||||
@@ -698,6 +756,11 @@ float OpenGL::getMaxPointSize() const
|
||||
return maxPointSize;
|
||||
}
|
||||
|
||||
float OpenGL::getMaxAnisotropy() const
|
||||
{
|
||||
return maxAnisotropy;
|
||||
}
|
||||
|
||||
void OpenGL::updateTextureMemorySize(size_t oldsize, size_t newsize)
|
||||
{
|
||||
int64 memsize = (int64) stats.textureMemory + ((int64) newsize - (int64) oldsize);
|
||||
@@ -739,6 +802,36 @@ const char *OpenGL::errorString(GLenum errorcode)
|
||||
return text;
|
||||
}
|
||||
|
||||
const char *OpenGL::framebufferStatusString(GLenum status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
return "complete (success)";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
return "Texture format cannot be rendered to on this system.";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
return "Error in graphics driver (missing render texture attachment)";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
return "Error in graphics driver (incomplete draw buffer)";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
return "Error in graphics driver (incomplete read buffer)";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
return "Canvas with the specified MSAA count cannot be rendered to on this system.";
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
return "Renderable textures are unsupported";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
static char text[64] = {};
|
||||
|
||||
memset(text, 0, sizeof(text));
|
||||
sprintf(text, "0x%x", status);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
const char *OpenGL::debugSeverityString(GLenum severity)
|
||||
{
|
||||
switch (severity)
|
||||
|
||||
@@ -104,6 +104,13 @@ public:
|
||||
VENDOR_UNKNOWN
|
||||
};
|
||||
|
||||
enum FramebufferTarget
|
||||
{
|
||||
FRAMEBUFFER_READ = (1 << 0),
|
||||
FRAMEBUFFER_DRAW = (1 << 1),
|
||||
FRAMEBUFFER_ALL = (FRAMEBUFFER_READ | FRAMEBUFFER_DRAW),
|
||||
};
|
||||
|
||||
// A rectangle representing an OpenGL viewport or a scissor box.
|
||||
struct Viewport
|
||||
{
|
||||
@@ -119,7 +126,7 @@ public:
|
||||
struct
|
||||
{
|
||||
std::vector<Matrix4> transform;
|
||||
std::vector<Matrix4> projection;
|
||||
Matrix4 projection;
|
||||
} matrices;
|
||||
|
||||
class TempTransform
|
||||
@@ -173,7 +180,6 @@ public:
|
||||
{
|
||||
size_t textureMemory;
|
||||
int drawCalls;
|
||||
int framebufferBinds;
|
||||
int shaderSwitches;
|
||||
} stats;
|
||||
|
||||
@@ -282,7 +288,7 @@ public:
|
||||
* Sets the OpenGL rendering viewport to the specified rectangle.
|
||||
* The y-coordinate starts at the top.
|
||||
**/
|
||||
void setViewport(const Viewport &v);
|
||||
void setViewport(const Viewport &v, bool canvasActive);
|
||||
|
||||
/**
|
||||
* Gets the current OpenGL rendering viewport rectangle.
|
||||
@@ -293,7 +299,7 @@ public:
|
||||
* Sets the scissor box to the specified rectangle.
|
||||
* The y-coordinate starts at the top and is flipped internally.
|
||||
**/
|
||||
void setScissor(const Viewport &v);
|
||||
void setScissor(const Viewport &v, bool canvasActive);
|
||||
|
||||
/**
|
||||
* Gets the current scissor box (regardless of whether scissoring is enabled.)
|
||||
@@ -323,7 +329,9 @@ public:
|
||||
/**
|
||||
* Binds a Framebuffer Object to the specified target.
|
||||
**/
|
||||
void bindFramebuffer(GLenum target, GLuint framebuffer);
|
||||
void bindFramebuffer(FramebufferTarget target, GLuint framebuffer);
|
||||
GLuint getFramebuffer(FramebufferTarget target) const;
|
||||
void deleteFramebuffer(GLuint framebuffer);
|
||||
|
||||
/**
|
||||
* Calls glUseProgram.
|
||||
@@ -375,6 +383,7 @@ public:
|
||||
void setTextureWrap(const graphics::Texture::Wrap &w);
|
||||
|
||||
bool isClampZeroTextureWrapSupported() const;
|
||||
bool isPixelShaderHighpSupported() const;
|
||||
|
||||
/**
|
||||
* Returns the maximum supported width or height of a texture.
|
||||
@@ -401,6 +410,12 @@ public:
|
||||
**/
|
||||
float getMaxPointSize() const;
|
||||
|
||||
/**
|
||||
* Returns the maximum anisotropic filtering value that can be used for
|
||||
* Texture filtering.
|
||||
**/
|
||||
float getMaxAnisotropy() const;
|
||||
|
||||
|
||||
void updateTextureMemorySize(size_t oldsize, size_t newsize);
|
||||
|
||||
@@ -413,6 +428,7 @@ public:
|
||||
static GLint getGLWrapMode(Texture::WrapMode wmode);
|
||||
|
||||
static const char *errorString(GLenum errorcode);
|
||||
static const char *framebufferStatusString(GLenum status);
|
||||
|
||||
// Get human-readable strings for debug info.
|
||||
static const char *debugSeverityString(GLenum severity);
|
||||
@@ -429,6 +445,7 @@ private:
|
||||
|
||||
bool contextInitialized;
|
||||
|
||||
bool pixelShaderHighpSupported;
|
||||
float maxAnisotropy;
|
||||
int maxTextureSize;
|
||||
int maxRenderTargets;
|
||||
@@ -456,6 +473,8 @@ private:
|
||||
|
||||
float pointSize;
|
||||
|
||||
GLuint boundFramebuffers[2];
|
||||
|
||||
bool framebufferSRGBEnabled;
|
||||
|
||||
GLuint defaultTexture;
|
||||
|
||||
@@ -22,11 +22,12 @@
|
||||
#include "common/config.h"
|
||||
|
||||
#include "Shader.h"
|
||||
#include "Canvas.h"
|
||||
#include "Graphics.h"
|
||||
|
||||
// C++
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -41,11 +42,12 @@ namespace
|
||||
// reattaches the originally active program when destroyed
|
||||
struct TemporaryAttacher
|
||||
{
|
||||
TemporaryAttacher(Shader *shader)
|
||||
TemporaryAttacher(Shader *shader, bool attachNow)
|
||||
: curShader(shader)
|
||||
, prevShader(Shader::current)
|
||||
{
|
||||
curShader->attach(true);
|
||||
if (attachNow)
|
||||
attach();
|
||||
}
|
||||
|
||||
~TemporaryAttacher()
|
||||
@@ -56,6 +58,11 @@ namespace
|
||||
curShader->detach();
|
||||
}
|
||||
|
||||
void attach()
|
||||
{
|
||||
curShader->attach(true);
|
||||
}
|
||||
|
||||
Shader *curShader;
|
||||
Shader *prevShader;
|
||||
};
|
||||
@@ -70,14 +77,12 @@ Shader *Shader::defaultVideoShader = nullptr;
|
||||
Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM][2];
|
||||
Shader::ShaderSource Shader::defaultVideoCode[Graphics::RENDERER_MAX_ENUM][2];
|
||||
|
||||
std::vector<int> Shader::textureCounters;
|
||||
|
||||
Shader::Shader(const ShaderSource &source)
|
||||
: shaderSource(source)
|
||||
, program(0)
|
||||
, builtinUniforms()
|
||||
, builtinAttributes()
|
||||
, lastCanvas((Canvas *) -1)
|
||||
, canvasWasActive(false)
|
||||
, lastViewport()
|
||||
, lastPointSize(0.0f)
|
||||
, videoTextureUnits()
|
||||
@@ -85,10 +90,6 @@ Shader::Shader(const ShaderSource &source)
|
||||
if (source.vertex.empty() && source.pixel.empty())
|
||||
throw love::Exception("Cannot create shader: no source code!");
|
||||
|
||||
// initialize global texture id counters if needed
|
||||
if ((int) textureCounters.size() < gl.getMaxTextureUnits() - 1)
|
||||
textureCounters.resize(gl.getMaxTextureUnits() - 1, 0);
|
||||
|
||||
// load shader source and create program object
|
||||
loadVolatile();
|
||||
}
|
||||
@@ -98,12 +99,25 @@ Shader::~Shader()
|
||||
if (current == this)
|
||||
detach();
|
||||
|
||||
for (const auto &retainable : boundRetainables)
|
||||
retainable.second->release();
|
||||
|
||||
boundRetainables.clear();
|
||||
|
||||
unloadVolatile();
|
||||
|
||||
for (const auto &p : uniforms)
|
||||
{
|
||||
// Allocated with malloc().
|
||||
if (p.second.data != nullptr)
|
||||
free(p.second.data);
|
||||
|
||||
if (p.second.baseType == UNIFORM_SAMPLER)
|
||||
{
|
||||
for (int i = 0; i < p.second.count; i++)
|
||||
{
|
||||
if (p.second.textures[i] != nullptr)
|
||||
p.second.textures[i]->release();
|
||||
}
|
||||
|
||||
delete[] p.second.textures;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLuint Shader::compileCode(ShaderStage stage, const std::string &code)
|
||||
@@ -177,8 +191,6 @@ void Shader::mapActiveUniforms()
|
||||
for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
|
||||
builtinUniforms[i] = -1;
|
||||
|
||||
uniforms.clear();
|
||||
|
||||
GLint activeprogram = 0;
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &activeprogram);
|
||||
|
||||
@@ -190,6 +202,9 @@ void Shader::mapActiveUniforms()
|
||||
GLchar cname[256];
|
||||
const GLint bufsize = (GLint) (sizeof(cname) / sizeof(GLchar));
|
||||
|
||||
std::map<std::string, UniformInfo> olduniforms = uniforms;
|
||||
uniforms.clear();
|
||||
|
||||
for (int i = 0; i < numuniforms; i++)
|
||||
{
|
||||
GLsizei namelen = 0;
|
||||
@@ -207,12 +222,6 @@ void Shader::mapActiveUniforms()
|
||||
else
|
||||
u.components = getUniformTypeComponents(gltype);
|
||||
|
||||
// Initialize all samplers to 0. Both GLSL and GLSL ES are supposed to
|
||||
// do this themselves, but some Android devices (galaxy tab 3 and 4)
|
||||
// don't seem to do it...
|
||||
if (u.baseType == UNIFORM_SAMPLER)
|
||||
glUniform1i(u.location, 0);
|
||||
|
||||
// glGetActiveUniform appends "[0]" to the end of array uniform names...
|
||||
if (u.name.length() > 3)
|
||||
{
|
||||
@@ -226,8 +235,138 @@ void Shader::mapActiveUniforms()
|
||||
if (builtinNames.find(u.name.c_str(), builtin))
|
||||
builtinUniforms[int(builtin)] = u.location;
|
||||
|
||||
if (u.location != -1)
|
||||
uniforms[u.name] = u;
|
||||
if (u.location == -1)
|
||||
continue;
|
||||
|
||||
// Make sure previously set uniform data is preserved, and shader-
|
||||
// initialized values are retrieved.
|
||||
auto oldu = olduniforms.find(u.name);
|
||||
if (oldu != olduniforms.end())
|
||||
{
|
||||
u.data = oldu->second.data;
|
||||
u.textures = oldu->second.textures;
|
||||
|
||||
updateUniform(&u, u.count, true);
|
||||
|
||||
if (u.baseType == UNIFORM_SAMPLER)
|
||||
{
|
||||
// Make sure all stored textures have their Volatiles loaded
|
||||
// before the sendTextures call, since it calls getHandle().
|
||||
for (int i = 0; i < u.count; i++)
|
||||
{
|
||||
if (u.textures[i] == nullptr)
|
||||
continue;
|
||||
|
||||
Volatile *v = dynamic_cast<Volatile *>(u.textures[i]);
|
||||
if (v != nullptr)
|
||||
v->loadVolatile();
|
||||
}
|
||||
|
||||
sendTextures(&u, u.textures, u.count, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t datasize = 0;
|
||||
|
||||
switch (u.baseType)
|
||||
{
|
||||
case UNIFORM_FLOAT:
|
||||
datasize = sizeof(float) * u.components * u.count;
|
||||
u.data = malloc(datasize);
|
||||
break;
|
||||
case UNIFORM_INT:
|
||||
case UNIFORM_BOOL:
|
||||
case UNIFORM_SAMPLER:
|
||||
datasize = sizeof(int) * u.components * u.count;
|
||||
u.data = malloc(datasize);
|
||||
break;
|
||||
case UNIFORM_MATRIX:
|
||||
datasize = sizeof(float) * (u.matrix.rows * u.matrix.columns) * u.count;
|
||||
u.data = malloc(datasize);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (datasize > 0)
|
||||
{
|
||||
memset(u.data, 0, datasize);
|
||||
|
||||
if (u.baseType == UNIFORM_SAMPLER)
|
||||
{
|
||||
// Initialize all samplers to 0. Both GLSL and GLSL ES are
|
||||
// supposed to do this themselves, but some Android devices
|
||||
// (galaxy tab 3 and 4) don't seem to do it...
|
||||
glUniform1iv(u.location, u.count, u.ints);
|
||||
|
||||
u.textures = new Texture*[u.count];
|
||||
memset(u.textures, 0, sizeof(Texture *) * u.count);
|
||||
}
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
// Store any shader-initialized values in our own memory.
|
||||
for (int i = 0; i < u.count; i++)
|
||||
{
|
||||
GLint location = u.location;
|
||||
|
||||
if (u.count > 1)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << i;
|
||||
|
||||
std::string indexname = u.name + "[" + ss.str() + "]";
|
||||
location = glGetUniformLocation(program, indexname.c_str());
|
||||
}
|
||||
|
||||
if (location == -1)
|
||||
continue;
|
||||
|
||||
switch (u.baseType)
|
||||
{
|
||||
case UNIFORM_FLOAT:
|
||||
glGetUniformfv(program, location, &u.floats[offset]);
|
||||
offset += u.components;
|
||||
break;
|
||||
case UNIFORM_INT:
|
||||
case UNIFORM_BOOL:
|
||||
glGetUniformiv(program, location, &u.ints[offset]);
|
||||
offset += u.components;
|
||||
break;
|
||||
case UNIFORM_MATRIX:
|
||||
glGetUniformfv(program, location, &u.floats[offset]);
|
||||
offset += u.matrix.rows * u.matrix.columns;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uniforms[u.name] = u;
|
||||
}
|
||||
|
||||
// Make sure uniforms that existed before but don't exist anymore are
|
||||
// cleaned up. This theoretically shouldn't happen, but...
|
||||
for (const auto &p : olduniforms)
|
||||
{
|
||||
if (uniforms.find(p.first) == uniforms.end())
|
||||
{
|
||||
free(p.second.data);
|
||||
|
||||
if (p.second.baseType != UNIFORM_SAMPLER)
|
||||
continue;
|
||||
|
||||
for (int i = 0; i < p.second.count; i++)
|
||||
{
|
||||
if (p.second.textures[i] != nullptr)
|
||||
p.second.textures[i]->release();
|
||||
}
|
||||
|
||||
delete[] p.second.textures;
|
||||
}
|
||||
}
|
||||
|
||||
gl.useProgram(activeprogram);
|
||||
@@ -238,7 +377,7 @@ bool Shader::loadVolatile()
|
||||
OpenGL::TempDebugGroup debuggroup("Shader load");
|
||||
|
||||
// Recreating the shader program will invalidate uniforms that rely on these.
|
||||
lastCanvas = (Canvas *) -1;
|
||||
canvasWasActive = false;
|
||||
lastViewport = OpenGL::Viewport();
|
||||
|
||||
lastPointSize = -1.0f;
|
||||
@@ -252,8 +391,8 @@ bool Shader::loadVolatile()
|
||||
videoTextureUnits[i] = 0;
|
||||
|
||||
// zero out active texture list
|
||||
activeTexUnits.clear();
|
||||
activeTexUnits.insert(activeTexUnits.begin(), gl.getMaxTextureUnits() - 1, 0);
|
||||
textureUnits.clear();
|
||||
textureUnits.resize(gl.getMaxTextureUnits(), TextureUnit());
|
||||
|
||||
std::vector<GLuint> shaderids;
|
||||
|
||||
@@ -340,31 +479,21 @@ bool Shader::loadVolatile()
|
||||
|
||||
void Shader::unloadVolatile()
|
||||
{
|
||||
if (current == this)
|
||||
gl.useProgram(0);
|
||||
|
||||
if (program != 0)
|
||||
{
|
||||
if (current == this)
|
||||
gl.useProgram(0);
|
||||
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
|
||||
// decrement global texture id counters for texture units which had textures bound from this shader
|
||||
for (size_t i = 0; i < activeTexUnits.size(); ++i)
|
||||
{
|
||||
if (activeTexUnits[i] > 0)
|
||||
textureCounters[i] = std::max(textureCounters[i] - 1, 0);
|
||||
}
|
||||
|
||||
// active texture list is probably invalid, clear it
|
||||
activeTexUnits.clear();
|
||||
activeTexUnits.resize(gl.getMaxTextureUnits() - 1, 0);
|
||||
textureUnits.clear();
|
||||
textureUnits.resize(gl.getMaxTextureUnits(), TextureUnit());
|
||||
|
||||
attributes.clear();
|
||||
|
||||
// same with uniform location list
|
||||
uniforms.clear();
|
||||
|
||||
// And the locations of any built-in uniform variables.
|
||||
for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
|
||||
builtinUniforms[i] = -1;
|
||||
@@ -421,10 +550,10 @@ void Shader::attach(bool temporary)
|
||||
{
|
||||
// make sure all sent textures are properly bound to their respective texture units
|
||||
// note: list potentially contains texture ids of deleted/invalid textures!
|
||||
for (int i = 0; i < (int) activeTexUnits.size(); ++i)
|
||||
for (int i = 1; i < (int) textureUnits.size(); ++i)
|
||||
{
|
||||
if (activeTexUnits[i] > 0)
|
||||
gl.bindTextureToUnit(activeTexUnits[i], i + 1, false);
|
||||
if (textureUnits[i].active)
|
||||
gl.bindTextureToUnit(textureUnits[i].texture, i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -456,160 +585,148 @@ const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
|
||||
return &(it->second);
|
||||
}
|
||||
|
||||
void Shader::sendInts(const UniformInfo *info, const int *vec, int count)
|
||||
void Shader::updateUniform(const UniformInfo *info, int count, bool internalUpdate)
|
||||
{
|
||||
if (info->baseType != UNIFORM_INT && info->baseType != UNIFORM_BOOL)
|
||||
return;
|
||||
|
||||
TemporaryAttacher attacher(this);
|
||||
TemporaryAttacher attacher(this, !internalUpdate);
|
||||
|
||||
int location = info->location;
|
||||
UniformType type = info->baseType;
|
||||
|
||||
switch (info->components)
|
||||
if (type == UNIFORM_FLOAT)
|
||||
{
|
||||
case 4:
|
||||
glUniform4iv(location, count, vec);
|
||||
break;
|
||||
case 3:
|
||||
glUniform3iv(location, count, vec);
|
||||
break;
|
||||
case 2:
|
||||
glUniform2iv(location, count, vec);
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
glUniform1iv(location, count, vec);
|
||||
break;
|
||||
switch (info->components)
|
||||
{
|
||||
case 1:
|
||||
glUniform1fv(location, count, info->floats);
|
||||
break;
|
||||
case 2:
|
||||
glUniform2fv(location, count, info->floats);
|
||||
break;
|
||||
case 3:
|
||||
glUniform3fv(location, count, info->floats);
|
||||
break;
|
||||
case 4:
|
||||
glUniform4fv(location, count, info->floats);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER)
|
||||
{
|
||||
switch (info->components)
|
||||
{
|
||||
case 1:
|
||||
glUniform1iv(location, count, info->ints);
|
||||
break;
|
||||
case 2:
|
||||
glUniform2iv(location, count, info->ints);
|
||||
break;
|
||||
case 3:
|
||||
glUniform3iv(location, count, info->ints);
|
||||
break;
|
||||
case 4:
|
||||
glUniform4iv(location, count, info->ints);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type == UNIFORM_MATRIX)
|
||||
{
|
||||
int columns = info->matrix.columns;
|
||||
int rows = info->matrix.rows;
|
||||
|
||||
if (columns == 2 && rows == 2)
|
||||
glUniformMatrix2fv(location, count, GL_FALSE, info->floats);
|
||||
else if (columns == 3 && rows == 3)
|
||||
glUniformMatrix3fv(location, count, GL_FALSE, info->floats);
|
||||
else if (columns == 4 && rows == 4)
|
||||
glUniformMatrix4fv(location, count, GL_FALSE, info->floats);
|
||||
else if (columns == 2 && rows == 3)
|
||||
glUniformMatrix2x3fv(location, count, GL_FALSE, info->floats);
|
||||
else if (columns == 2 && rows == 4)
|
||||
glUniformMatrix2x4fv(location, count, GL_FALSE, info->floats);
|
||||
else if (columns == 3 && rows == 2)
|
||||
glUniformMatrix3x2fv(location, count, GL_FALSE, info->floats);
|
||||
else if (columns == 3 && rows == 4)
|
||||
glUniformMatrix3x4fv(location, count, GL_FALSE, info->floats);
|
||||
else if (columns == 4 && rows == 2)
|
||||
glUniformMatrix4x2fv(location, count, GL_FALSE, info->floats);
|
||||
else if (columns == 4 && rows == 3)
|
||||
glUniformMatrix4x3fv(location, count, GL_FALSE, info->floats);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::sendFloats(const UniformInfo *info, const float *vec, int count)
|
||||
int Shader::getFreeTextureUnits(int count)
|
||||
{
|
||||
if (info->baseType != UNIFORM_FLOAT && info->baseType != UNIFORM_BOOL)
|
||||
return;
|
||||
int startunit = -1;
|
||||
|
||||
TemporaryAttacher attacher(this);
|
||||
|
||||
int location = info->location;
|
||||
|
||||
switch (info->components)
|
||||
// Ignore the first texture unit for Shader-local texture bindings.
|
||||
for (int i = 1; i < (int) textureUnits.size(); i++)
|
||||
{
|
||||
case 4:
|
||||
glUniform4fv(location, count, vec);
|
||||
break;
|
||||
case 3:
|
||||
glUniform3fv(location, count, vec);
|
||||
break;
|
||||
case 2:
|
||||
glUniform2fv(location, count, vec);
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
glUniform1fv(location, count, vec);
|
||||
break;
|
||||
if (!textureUnits[i].active && i + count <= (int) textureUnits.size())
|
||||
{
|
||||
startunit = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (startunit == -1)
|
||||
throw love::Exception("No more texture units available for shader.");
|
||||
|
||||
return startunit;
|
||||
}
|
||||
|
||||
void Shader::sendMatrices(const UniformInfo *info, const float *m, int count)
|
||||
{
|
||||
if (info->baseType != UNIFORM_MATRIX)
|
||||
return;
|
||||
|
||||
TemporaryAttacher attacher(this);
|
||||
|
||||
int location = info->location;
|
||||
|
||||
int columns = info->matrix.columns;
|
||||
int rows = info->matrix.rows;
|
||||
|
||||
if (columns == 2 && rows == 2)
|
||||
glUniformMatrix2fv(location, count, GL_FALSE, m);
|
||||
else if (columns == 3 && rows == 3)
|
||||
glUniformMatrix3fv(location, count, GL_FALSE, m);
|
||||
else if (columns == 4 && rows == 4)
|
||||
glUniformMatrix4fv(location, count, GL_FALSE, m);
|
||||
else if (columns == 2 && rows == 3)
|
||||
glUniformMatrix2x3fv(location, count, GL_FALSE, m);
|
||||
else if (columns == 2 && rows == 4)
|
||||
glUniformMatrix2x4fv(location, count, GL_FALSE, m);
|
||||
else if (columns == 3 && rows == 2)
|
||||
glUniformMatrix3x2fv(location, count, GL_FALSE, m);
|
||||
else if (columns == 3 && rows == 4)
|
||||
glUniformMatrix3x4fv(location, count, GL_FALSE, m);
|
||||
else if (columns == 4 && rows == 2)
|
||||
glUniformMatrix4x2fv(location, count, GL_FALSE, m);
|
||||
else if (columns == 4 && rows == 3)
|
||||
glUniformMatrix4x3fv(location, count, GL_FALSE, m);
|
||||
}
|
||||
|
||||
void Shader::sendTexture(const UniformInfo *info, Texture *texture)
|
||||
void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate)
|
||||
{
|
||||
if (info->baseType != UNIFORM_SAMPLER)
|
||||
return;
|
||||
|
||||
GLuint gltex = *(GLuint *) texture->getHandle();
|
||||
count = std::min(count, info->count);
|
||||
bool updateuniform = false;
|
||||
|
||||
TemporaryAttacher attacher(this);
|
||||
|
||||
int texunit = getTextureUnit(info->name);
|
||||
|
||||
// bind texture to assigned texture unit and send uniform to shader program
|
||||
gl.bindTextureToUnit(gltex, texunit, false);
|
||||
|
||||
glUniform1i(info->location, texunit);
|
||||
|
||||
// increment global shader texture id counter for this texture unit, if we haven't already
|
||||
if (activeTexUnits[texunit-1] == 0)
|
||||
++textureCounters[texunit-1];
|
||||
|
||||
// store texture id so it can be re-bound to the proper texture unit later
|
||||
activeTexUnits[texunit-1] = gltex;
|
||||
|
||||
retainObject(info->name, texture);
|
||||
}
|
||||
|
||||
void Shader::retainObject(const std::string &name, Object *object)
|
||||
{
|
||||
object->retain();
|
||||
|
||||
auto it = boundRetainables.find(name);
|
||||
if (it != boundRetainables.end())
|
||||
it->second->release();
|
||||
|
||||
boundRetainables[name] = object;
|
||||
}
|
||||
|
||||
int Shader::getTextureUnit(const std::string &name)
|
||||
{
|
||||
auto it = texUnitPool.find(name);
|
||||
|
||||
if (it != texUnitPool.end())
|
||||
return it->second;
|
||||
|
||||
int texunit = 1;
|
||||
|
||||
// prefer texture units which are unused by all other shaders
|
||||
auto freeunit_it = std::find(textureCounters.begin(), textureCounters.end(), 0);
|
||||
|
||||
if (freeunit_it != textureCounters.end())
|
||||
// Make sure the shader's samplers are associated with texture units.
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// we don't want to use unit 0
|
||||
texunit = (int) std::distance(textureCounters.begin(), freeunit_it) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no completely unused texture units exist, try to use next free slot in our own list
|
||||
auto nextunit_it = std::find(activeTexUnits.begin(), activeTexUnits.end(), 0);
|
||||
if (info->ints[i] == 0 && textures[i] != nullptr)
|
||||
{
|
||||
int texunit = getFreeTextureUnits(1);
|
||||
textureUnits[texunit].active = true;
|
||||
|
||||
if (nextunit_it == activeTexUnits.end())
|
||||
throw love::Exception("No more texture units available for shader.");
|
||||
|
||||
// we don't want to use unit 0
|
||||
texunit = (int) std::distance(activeTexUnits.begin(), nextunit_it) + 1;
|
||||
info->ints[i] = texunit;
|
||||
updateuniform = true;
|
||||
}
|
||||
}
|
||||
|
||||
texUnitPool[name] = texunit;
|
||||
return texunit;
|
||||
if (updateuniform)
|
||||
updateUniform(info, count, internalUpdate);
|
||||
|
||||
// Bind the textures to the texture units.
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (textures[i] != nullptr)
|
||||
textures[i]->retain();
|
||||
|
||||
if (info->textures[i] != nullptr)
|
||||
info->textures[i]->release();
|
||||
|
||||
info->textures[i] = textures[i];
|
||||
|
||||
int texunit = info->ints[i];
|
||||
|
||||
if (textures[i] != nullptr)
|
||||
{
|
||||
GLuint gltex = *(GLuint *) textures[i]->getHandle();
|
||||
|
||||
gl.bindTextureToUnit(gltex, texunit, false);
|
||||
|
||||
// store texture id so it can be re-bound to the proper texture unit later
|
||||
textureUnits[texunit].texture = gltex;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.bindTextureToUnit(0, texunit, false);
|
||||
textureUnits[texunit].texture = 0;
|
||||
textureUnits[texunit].active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Shader::hasUniform(const std::string &name) const
|
||||
@@ -636,12 +753,12 @@ bool Shader::hasVertexAttrib(VertexAttribID attrib) const
|
||||
|
||||
void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture)
|
||||
{
|
||||
TemporaryAttacher attacher(this);
|
||||
|
||||
// Set up the texture units that will be used by the shader to sample from
|
||||
// the textures, if they haven't been set up yet.
|
||||
if (videoTextureUnits[0] == 0)
|
||||
{
|
||||
TemporaryAttacher attacher(this, true);
|
||||
|
||||
const GLint locs[3] = {
|
||||
builtinUniforms[BUILTIN_VIDEO_Y_CHANNEL],
|
||||
builtinUniforms[BUILTIN_VIDEO_CB_CHANNEL],
|
||||
@@ -657,14 +774,15 @@ void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtextur
|
||||
{
|
||||
if (locs[i] >= 0 && names[i] != nullptr)
|
||||
{
|
||||
videoTextureUnits[i] = getTextureUnit(names[i]);
|
||||
const UniformInfo *info = getUniformInfo(names[i]);
|
||||
if (info != nullptr)
|
||||
{
|
||||
videoTextureUnits[i] = getFreeTextureUnits(1);
|
||||
textureUnits[videoTextureUnits[i]].active = true;
|
||||
|
||||
// Increment global shader texture id counter for this texture
|
||||
// unit, if we haven't already.
|
||||
if (activeTexUnits[videoTextureUnits[i] - 1] == 0)
|
||||
++textureCounters[videoTextureUnits[i] - 1];
|
||||
|
||||
glUniform1i(locs[i], videoTextureUnits[i]);
|
||||
info->ints[0] = videoTextureUnits[i];
|
||||
updateUniform(info, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -677,7 +795,7 @@ void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtextur
|
||||
if (videoTextureUnits[i] != 0)
|
||||
{
|
||||
// Store texture id so it can be re-bound later.
|
||||
activeTexUnits[videoTextureUnits[i] - 1] = textures[i];
|
||||
textureUnits[videoTextureUnits[i]].texture = textures[i];
|
||||
gl.bindTextureToUnit(textures[i], videoTextureUnits[i], false);
|
||||
}
|
||||
}
|
||||
@@ -687,7 +805,10 @@ void Shader::checkSetScreenParams()
|
||||
{
|
||||
OpenGL::Viewport view = gl.getViewport();
|
||||
|
||||
if (view == lastViewport && lastCanvas == Canvas::current)
|
||||
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
||||
bool canvasActive = gfx->getActivePass().colorAttachmentCount > 0;
|
||||
|
||||
if (view == lastViewport && canvasWasActive == canvasActive)
|
||||
return;
|
||||
|
||||
// In the shader, we do pixcoord.y = gl_FragCoord.y * params.z + params.w.
|
||||
@@ -698,7 +819,7 @@ void Shader::checkSetScreenParams()
|
||||
0.0f, 0.0f,
|
||||
};
|
||||
|
||||
if (Canvas::current != nullptr)
|
||||
if (canvasActive)
|
||||
{
|
||||
// No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0.
|
||||
params[2] = 1.0f;
|
||||
@@ -716,11 +837,11 @@ void Shader::checkSetScreenParams()
|
||||
|
||||
if (location >= 0)
|
||||
{
|
||||
TemporaryAttacher attacher(this);
|
||||
TemporaryAttacher attacher(this, true);
|
||||
glUniform4fv(location, 1, params);
|
||||
}
|
||||
|
||||
lastCanvas = Canvas::current;
|
||||
canvasWasActive = canvasActive;
|
||||
lastViewport = view;
|
||||
}
|
||||
|
||||
@@ -733,7 +854,7 @@ void Shader::checkSetPointSize(float size)
|
||||
|
||||
if (location >= 0)
|
||||
{
|
||||
TemporaryAttacher attacher(this);
|
||||
TemporaryAttacher attacher(this, true);
|
||||
glUniform1f(location, size);
|
||||
}
|
||||
|
||||
@@ -751,9 +872,9 @@ void Shader::checkSetBuiltinUniforms()
|
||||
checkSetPointSize(gl.getPointSize());
|
||||
|
||||
const Matrix4 &curxform = gl.matrices.transform.back();
|
||||
const Matrix4 &curproj = gl.matrices.projection.back();
|
||||
const Matrix4 &curproj = gl.matrices.projection;
|
||||
|
||||
TemporaryAttacher attacher(this);
|
||||
TemporaryAttacher attacher(this, true);
|
||||
|
||||
bool tpmatrixneedsupdate = false;
|
||||
|
||||
@@ -800,11 +921,6 @@ void Shader::checkSetBuiltinUniforms()
|
||||
}
|
||||
}
|
||||
|
||||
const std::map<std::string, Object *> &Shader::getBoundRetainables() const
|
||||
{
|
||||
return boundRetainables;
|
||||
}
|
||||
|
||||
std::string Shader::getGLSLVersion()
|
||||
{
|
||||
const char *tmp = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
|
||||
|
||||
@@ -41,8 +41,6 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
class Canvas;
|
||||
|
||||
// A GLSL shader
|
||||
class Shader : public Object, public Volatile
|
||||
{
|
||||
@@ -100,13 +98,24 @@ public:
|
||||
{
|
||||
int location;
|
||||
int count;
|
||||
|
||||
union
|
||||
{
|
||||
int components;
|
||||
MatrixSize matrix;
|
||||
};
|
||||
|
||||
UniformType baseType;
|
||||
std::string name;
|
||||
|
||||
union
|
||||
{
|
||||
void *data;
|
||||
float *floats;
|
||||
int *ints;
|
||||
};
|
||||
|
||||
Texture **textures;
|
||||
};
|
||||
|
||||
// Pointer to currently active Shader.
|
||||
@@ -151,11 +160,9 @@ public:
|
||||
std::string getWarnings() const;
|
||||
|
||||
const UniformInfo *getUniformInfo(const std::string &name) const;
|
||||
void updateUniform(const UniformInfo *info, int count, bool internalUpdate = false);
|
||||
|
||||
void sendInts(const UniformInfo *info, const int *vec, int count);
|
||||
void sendFloats(const UniformInfo *info, const float *vec, int count);
|
||||
void sendMatrices(const UniformInfo *info, const float *m, int count);
|
||||
void sendTexture(const UniformInfo *info, Texture *texture);
|
||||
void sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate = false);
|
||||
|
||||
/**
|
||||
* Gets whether a uniform with the specified name exists and is actively
|
||||
@@ -175,24 +182,11 @@ public:
|
||||
void checkSetPointSize(float size);
|
||||
void checkSetBuiltinUniforms();
|
||||
|
||||
const std::map<std::string, Object *> &getBoundRetainables() const;
|
||||
|
||||
GLuint getProgram() const
|
||||
{
|
||||
return program;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *getScratchBuffer(size_t count)
|
||||
{
|
||||
size_t bytes = sizeof(T) * count;
|
||||
|
||||
if (scratchBuffer.size() < bytes)
|
||||
scratchBuffer.resize(bytes);
|
||||
|
||||
return (T *) scratchBuffer.data();
|
||||
}
|
||||
|
||||
static std::string getGLSLVersion();
|
||||
static bool isSupported();
|
||||
|
||||
@@ -204,6 +198,12 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
struct TextureUnit
|
||||
{
|
||||
GLuint texture = 0;
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
// Map active uniform names to their locations.
|
||||
void mapActiveUniforms();
|
||||
|
||||
@@ -213,9 +213,7 @@ private:
|
||||
|
||||
GLuint compileCode(ShaderStage stage, const std::string &code);
|
||||
|
||||
int getTextureUnit(const std::string &name);
|
||||
|
||||
void retainObject(const std::string &name, Object *object);
|
||||
int getFreeTextureUnits(int count);
|
||||
|
||||
// Get any warnings or errors generated only by the shader program object.
|
||||
std::string getProgramWarnings() const;
|
||||
@@ -241,14 +239,9 @@ private:
|
||||
std::map<std::string, UniformInfo> uniforms;
|
||||
|
||||
// Texture unit pool for setting images
|
||||
std::map<std::string, GLint> texUnitPool; // texUnitPool[name] = textureunit
|
||||
std::vector<GLuint> activeTexUnits; // activeTexUnits[textureunit-1] = textureid
|
||||
std::vector<TextureUnit> textureUnits;
|
||||
|
||||
// Uniform name to retainable objects
|
||||
std::map<std::string, Object*> boundRetainables;
|
||||
|
||||
// Pointer to the active Canvas when the screen params were last checked.
|
||||
Canvas *lastCanvas;
|
||||
bool canvasWasActive;
|
||||
OpenGL::Viewport lastViewport;
|
||||
|
||||
float lastPointSize;
|
||||
@@ -258,11 +251,6 @@ private:
|
||||
|
||||
GLuint videoTextureUnits[3];
|
||||
|
||||
std::vector<char> scratchBuffer;
|
||||
|
||||
// Counts total number of textures bound to each texture unit in all shaders
|
||||
static std::vector<int> textureCounters;
|
||||
|
||||
static StringMap<ShaderStage, STAGE_MAX_ENUM>::Entry stageNameEntries[];
|
||||
static StringMap<ShaderStage, STAGE_MAX_ENUM> stageNames;
|
||||
|
||||
|
||||
@@ -33,55 +33,6 @@ Canvas *luax_checkcanvas(lua_State *L, int idx)
|
||||
return luax_checktype<Canvas>(L, idx);
|
||||
}
|
||||
|
||||
int w_Canvas_renderTo(lua_State *L)
|
||||
{
|
||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
|
||||
auto graphics = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
||||
|
||||
if (graphics)
|
||||
{
|
||||
// Save the current Canvas so we can restore it when we're done.
|
||||
std::vector<Canvas *> oldcanvases = graphics->getCanvas();
|
||||
|
||||
for (Canvas *c : oldcanvases)
|
||||
c->retain();
|
||||
|
||||
luax_catchexcept(L, [&](){ graphics->setCanvas(canvas); });
|
||||
|
||||
lua_settop(L, 2); // make sure the function is on top of the stack
|
||||
int status = lua_pcall(L, 0, 0, 0);
|
||||
|
||||
graphics->setCanvas(oldcanvases);
|
||||
|
||||
for (Canvas *c : oldcanvases)
|
||||
c->release();
|
||||
|
||||
if (status != 0)
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Canvas_newImageData(lua_State *L)
|
||||
{
|
||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
||||
love::image::Image *image = luax_getmodule<love::image::Image>(L);
|
||||
int x = (int) luaL_optnumber(L, 2, 0);
|
||||
int y = (int) luaL_optnumber(L, 3, 0);
|
||||
int w = (int) luaL_optnumber(L, 4, canvas->getWidth());
|
||||
int h = (int) luaL_optnumber(L, 5, canvas->getHeight());
|
||||
|
||||
love::image::ImageData *img = nullptr;
|
||||
luax_catchexcept(L, [&](){ img = canvas->newImageData(image, x, y, w, h); });
|
||||
|
||||
luax_pushtype(L, img);
|
||||
img->release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Canvas_getFormat(lua_State *L)
|
||||
{
|
||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
||||
@@ -103,8 +54,6 @@ int w_Canvas_getMSAA(lua_State *L)
|
||||
|
||||
static const luaL_Reg w_Canvas_functions[] =
|
||||
{
|
||||
{ "renderTo", w_Canvas_renderTo },
|
||||
{ "newImageData", w_Canvas_newImageData },
|
||||
{ "getFormat", w_Canvas_getFormat },
|
||||
{ "getMSAA", w_Canvas_getMSAA },
|
||||
{ 0, 0 }
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "filesystem/wrap_Filesystem.h"
|
||||
#include "video/VideoStream.h"
|
||||
#include "image/wrap_Image.h"
|
||||
#include "common/Reference.h"
|
||||
#include "math/wrap_Transform.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
@@ -60,79 +62,9 @@ int w_reset(lua_State *)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_clear(lua_State *L)
|
||||
int w_present(lua_State *L)
|
||||
{
|
||||
Colorf color;
|
||||
|
||||
if (lua_isnoneornil(L, 1))
|
||||
color.set(0.0, 0.0, 0.0, 0.0);
|
||||
else if (lua_istable(L, 1))
|
||||
{
|
||||
std::vector<Graphics::OptionalColorf> colors((size_t) lua_gettop(L));
|
||||
|
||||
for (int i = 0; i < lua_gettop(L); i++)
|
||||
{
|
||||
if (lua_isnoneornil(L, i + 1) || luax_objlen(L, i + 1) == 0)
|
||||
{
|
||||
colors[i].enabled = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 1; j <= 4; j++)
|
||||
lua_rawgeti(L, i + 1, j);
|
||||
|
||||
colors[i].enabled = true;
|
||||
colors[i].r = (float) luaL_checknumber(L, -4);
|
||||
colors[i].g = (float) luaL_checknumber(L, -3);
|
||||
colors[i].b = (float) luaL_checknumber(L, -2);
|
||||
colors[i].a = (float) luaL_optnumber(L, -1, 1.0);
|
||||
|
||||
lua_pop(L, 4);
|
||||
}
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->clear(colors); });
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
color.r = (float) luaL_checknumber(L, 1);
|
||||
color.g = (float) luaL_checknumber(L, 2);
|
||||
color.b = (float) luaL_checknumber(L, 3);
|
||||
color.a = (float) luaL_optnumber(L, 4, 1.0);
|
||||
}
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->clear(color); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_discard(lua_State *L)
|
||||
{
|
||||
std::vector<bool> colorbuffers;
|
||||
|
||||
if (lua_istable(L, 1))
|
||||
{
|
||||
for (size_t i = 1; i <= luax_objlen(L, 1); i++)
|
||||
{
|
||||
lua_rawgeti(L, 1, i);
|
||||
colorbuffers.push_back(luax_optboolean(L, -1, true));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool discardcolor = luax_optboolean(L, 1, true);
|
||||
size_t numbuffers = std::max((size_t) 1, instance()->getCanvas().size());
|
||||
colorbuffers = std::vector<bool>(numbuffers, discardcolor);
|
||||
}
|
||||
|
||||
bool stencil = luax_optboolean(L, 2, true);
|
||||
instance()->discard(colorbuffers, stencil);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_present(lua_State *)
|
||||
{
|
||||
instance()->present();
|
||||
luax_catchexcept(L, [&]() { instance()->present(L); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -173,6 +105,274 @@ int w_getDimensions(lua_State *L)
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_getPassWidth(lua_State *L)
|
||||
{
|
||||
lua_pushinteger(L, instance()->getPassWidth());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_getPassHeight(lua_State *L)
|
||||
{
|
||||
lua_pushinteger(L, instance()->getPassHeight());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_getPassDimensions(lua_State *L)
|
||||
{
|
||||
lua_pushinteger(L, instance()->getPassWidth());
|
||||
lua_pushinteger(L, instance()->getPassHeight());
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int w__beginPass(lua_State *L)
|
||||
{
|
||||
int nextstartidx = 1;
|
||||
|
||||
if (lua_isnoneornil(L, 1))
|
||||
{
|
||||
luax_catchexcept(L, [&]() { instance()->beginPass(PassInfo::BEGIN_LOAD, Colorf()); });
|
||||
nextstartidx = 1;
|
||||
}
|
||||
else if (lua_isnumber(L, 1))
|
||||
{
|
||||
Colorf c;
|
||||
c.r = (float) luaL_checknumber(L, 1);
|
||||
c.g = (float) luaL_checknumber(L, 2);
|
||||
c.b = (float) luaL_checknumber(L, 3);
|
||||
|
||||
if (lua_isnumber(L, 4))
|
||||
{
|
||||
c.a = (float) lua_tonumber(L, 4);
|
||||
nextstartidx = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
c.a = 1.0f;
|
||||
nextstartidx = 4;
|
||||
}
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->beginPass(PassInfo::BEGIN_CLEAR, c); });
|
||||
}
|
||||
else if (luax_istype(L, 1, Canvas::type))
|
||||
{
|
||||
PassInfo::ColorAttachment attachment;
|
||||
attachment.canvas = luax_checkcanvas(L, 1);
|
||||
attachment.beginAction = PassInfo::BEGIN_LOAD;
|
||||
|
||||
if (lua_isnumber(L, 2))
|
||||
{
|
||||
attachment.beginAction = PassInfo::BEGIN_CLEAR;
|
||||
attachment.clearColor.r = (float) luaL_checknumber(L, 2);
|
||||
attachment.clearColor.g = (float) luaL_checknumber(L, 3);
|
||||
attachment.clearColor.b = (float) luaL_checknumber(L, 4);
|
||||
|
||||
if (lua_isnumber(L, 5))
|
||||
{
|
||||
attachment.clearColor.a = (float) lua_tonumber(L, 5);
|
||||
nextstartidx = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
attachment.clearColor.a = 1.0f;
|
||||
nextstartidx = 5;
|
||||
}
|
||||
}
|
||||
else
|
||||
nextstartidx = 2;
|
||||
|
||||
PassInfo info;
|
||||
info.addColorAttachment(attachment);
|
||||
|
||||
if (lua_isboolean(L, nextstartidx))
|
||||
{
|
||||
info.stencil = luax_toboolean(L, nextstartidx);
|
||||
nextstartidx++;
|
||||
}
|
||||
else
|
||||
info.stencil = false;
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->beginPass(info); });
|
||||
}
|
||||
else
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
|
||||
int nattachments = std::max((int) luax_objlen(L, 1), 1);
|
||||
|
||||
if (nattachments > MAX_COLOR_RENDER_TARGETS)
|
||||
return luaL_error(L, "Cannot render to %d Canvases at once!", nattachments);
|
||||
|
||||
PassInfo info;
|
||||
|
||||
for (int i = 1; i <= nattachments; i++)
|
||||
{
|
||||
lua_rawgeti(L, 1, i);
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
|
||||
PassInfo::ColorAttachment attachment;
|
||||
attachment.beginAction = PassInfo::BEGIN_LOAD;
|
||||
|
||||
lua_rawgeti(L, -1, 1);
|
||||
attachment.canvas = luax_checkcanvas(L, -1);
|
||||
|
||||
lua_rawgeti(L, -2, 2);
|
||||
if (!lua_isnoneornil(L, -1))
|
||||
{
|
||||
attachment.beginAction = PassInfo::BEGIN_CLEAR;
|
||||
|
||||
for (int j = 3; j < 6; j++)
|
||||
lua_rawgeti(L, -j, j);
|
||||
|
||||
attachment.clearColor.r = (float) luaL_checknumber(L, -4);
|
||||
attachment.clearColor.g = (float) luaL_checknumber(L, -3);
|
||||
attachment.clearColor.b = (float) luaL_checknumber(L, -2);
|
||||
attachment.clearColor.a = (float) luaL_optnumber(L, -1, 1.0);
|
||||
}
|
||||
|
||||
lua_pop(L, 2 + (attachment.beginAction == PassInfo::BEGIN_CLEAR ? 4 : 1));
|
||||
|
||||
info.addColorAttachment(attachment);
|
||||
}
|
||||
|
||||
info.stencil = luax_boolflag(L, 1, "stencil", false);
|
||||
|
||||
luax_catchexcept(L, [&]() { instance()->beginPass(info); });
|
||||
|
||||
nextstartidx = 2;
|
||||
}
|
||||
|
||||
return nextstartidx;
|
||||
}
|
||||
|
||||
int w_beginPass(lua_State *L)
|
||||
{
|
||||
w__beginPass(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void screenshotCallback(love::image::ImageData *i, Reference *ref, void *gd)
|
||||
{
|
||||
if (i != nullptr)
|
||||
{
|
||||
lua_State *L = (lua_State *) gd;
|
||||
ref->push(L);
|
||||
delete ref;
|
||||
luax_pushtype(L, i);
|
||||
lua_call(L, 1, 0);
|
||||
}
|
||||
else
|
||||
delete ref;
|
||||
}
|
||||
|
||||
static int w__endPass(lua_State *L, int startidx)
|
||||
{
|
||||
if (lua_isnoneornil(L, startidx))
|
||||
{
|
||||
luax_catchexcept(L, []() { instance()->endPass(); });
|
||||
}
|
||||
else
|
||||
{
|
||||
int x, y, w, h;
|
||||
|
||||
if (lua_isnumber(L, startidx))
|
||||
{
|
||||
x = (int) luaL_checknumber(L, 1);
|
||||
y = (int) luaL_checknumber(L, 2);
|
||||
w = (int) luaL_checknumber(L, 3);
|
||||
h = (int) luaL_checknumber(L, 4);
|
||||
startidx += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = instance()->getPassWidth();
|
||||
h = instance()->getPassHeight();
|
||||
}
|
||||
|
||||
luaL_checktype(L, startidx, LUA_TFUNCTION);
|
||||
|
||||
Graphics::ScreenshotInfo info;
|
||||
info.callback = screenshotCallback;
|
||||
|
||||
lua_pushvalue(L, startidx);
|
||||
info.ref = luax_refif(L, LUA_TFUNCTION);
|
||||
lua_pop(L, 1);
|
||||
|
||||
luax_catchexcept(L,
|
||||
[&]() { instance()->endPass(x, y, w, h, &info, L); },
|
||||
[&](bool except) { if (except) delete info.ref; }
|
||||
);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_endPass(lua_State *L)
|
||||
{
|
||||
return w__endPass(L, 1);
|
||||
}
|
||||
|
||||
int w_renderPass(lua_State *L)
|
||||
{
|
||||
int startidx = w__beginPass(L);
|
||||
|
||||
if (lua_type(L, startidx) != LUA_TFUNCTION)
|
||||
{
|
||||
w__endPass(L, startidx + 1);
|
||||
luaL_checktype(L, startidx, LUA_TFUNCTION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nargs = lua_gettop(L) - startidx;
|
||||
int status = lua_pcall(L, nargs, 0, 0);
|
||||
|
||||
w__endPass(L, startidx + 1);
|
||||
|
||||
if (status != 0)
|
||||
return lua_error(L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_isPassActive(lua_State *L)
|
||||
{
|
||||
luax_pushboolean(L, instance()->isPassActive());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_getPassCanvases(lua_State *L)
|
||||
{
|
||||
if (!instance()->isPassActive())
|
||||
return 0;
|
||||
|
||||
const PassInfo &info = instance()->getActivePass();
|
||||
|
||||
for (const auto &attachment : info.colorAttachments)
|
||||
luax_pushtype(L, attachment.canvas);
|
||||
|
||||
return info.colorAttachmentCount;
|
||||
}
|
||||
|
||||
int w_captureScreenshot(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
|
||||
Graphics::ScreenshotInfo info;
|
||||
info.callback = screenshotCallback;
|
||||
|
||||
lua_pushvalue(L, 1);
|
||||
info.ref = luax_refif(L, LUA_TFUNCTION);
|
||||
lua_pop(L, 1);
|
||||
|
||||
luax_catchexcept(L,
|
||||
[&]() { instance()->captureScreenshot(info); },
|
||||
[&](bool except) { if (except) delete info.ref; }
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_setScissor(lua_State *L)
|
||||
{
|
||||
int nargs = lua_gettop(L);
|
||||
@@ -243,13 +443,13 @@ int w_stencil(lua_State *L)
|
||||
if (lua_toboolean(L, 4) == 0)
|
||||
instance()->clearStencil();
|
||||
|
||||
instance()->drawToStencilBuffer(action, stencilvalue);
|
||||
luax_catchexcept(L, [&](){ instance()->drawToStencilBuffer(action, stencilvalue); });
|
||||
|
||||
// Call stencilfunc()
|
||||
lua_pushvalue(L, 1);
|
||||
lua_call(L, 0, 0);
|
||||
|
||||
instance()->stopDrawToStencilBuffer();
|
||||
luax_catchexcept(L, [&](){ instance()->stopDrawToStencilBuffer(); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -268,7 +468,7 @@ int w_setStencilTest(lua_State *L)
|
||||
comparevalue = (int) luaL_checknumber(L, 2);
|
||||
}
|
||||
|
||||
instance()->setStencilTest(compare, comparevalue);
|
||||
luax_catchexcept(L, [&](){ instance()->setStencilTest(compare, comparevalue); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1246,79 +1446,6 @@ int w_isWireframe(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_newScreenshot(lua_State *L)
|
||||
{
|
||||
love::image::Image *image = luax_getmodule<love::image::Image>(L);
|
||||
bool copyAlpha = luax_optboolean(L, 1, false);
|
||||
love::image::ImageData *i = 0;
|
||||
|
||||
luax_catchexcept(L, [&](){ i = instance()->newScreenshot(image, copyAlpha); });
|
||||
|
||||
luax_pushtype(L, i);
|
||||
i->release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_setCanvas(lua_State *L)
|
||||
{
|
||||
// Disable stencil writes.
|
||||
instance()->stopDrawToStencilBuffer();
|
||||
|
||||
// called with none -> reset to default buffer
|
||||
if (lua_isnoneornil(L, 1))
|
||||
{
|
||||
instance()->setCanvas();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool is_table = lua_istable(L, 1);
|
||||
std::vector<Canvas *> canvases;
|
||||
|
||||
if (is_table)
|
||||
{
|
||||
for (int i = 1; i <= (int) luax_objlen(L, 1); i++)
|
||||
{
|
||||
lua_rawgeti(L, 1, i);
|
||||
canvases.push_back(luax_checkcanvas(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i <= lua_gettop(L); i++)
|
||||
canvases.push_back(luax_checkcanvas(L, i));
|
||||
}
|
||||
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (canvases.size() > 0)
|
||||
instance()->setCanvas(canvases);
|
||||
else
|
||||
instance()->setCanvas();
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getCanvas(lua_State *L)
|
||||
{
|
||||
const std::vector<Canvas *> canvases = instance()->getCanvas();
|
||||
int n = 0;
|
||||
|
||||
for (Canvas *c : canvases)
|
||||
{
|
||||
luax_pushtype(L, c);
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
n = 1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int w_setShader(lua_State *L)
|
||||
{
|
||||
if (lua_isnoneornil(L,1))
|
||||
@@ -1497,8 +1624,8 @@ int w_getStats(lua_State *L)
|
||||
lua_pushinteger(L, stats.drawCalls);
|
||||
lua_setfield(L, -2, "drawcalls");
|
||||
|
||||
lua_pushinteger(L, stats.canvasSwitches);
|
||||
lua_setfield(L, -2, "canvasswitches");
|
||||
lua_pushinteger(L, stats.renderPasses);
|
||||
lua_setfield(L, -2, "renderpasses");
|
||||
|
||||
lua_pushinteger(L, stats.shaderSwitches);
|
||||
lua_setfield(L, -2, "shaderswitches");
|
||||
@@ -1541,24 +1668,37 @@ int w_draw(lua_State *L)
|
||||
startidx = 2;
|
||||
}
|
||||
|
||||
float x = (float) luaL_optnumber(L, startidx + 0, 0.0);
|
||||
float y = (float) luaL_optnumber(L, startidx + 1, 0.0);
|
||||
float a = (float) luaL_optnumber(L, startidx + 2, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, startidx + 3, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, startidx + 4, sx);
|
||||
float ox = (float) luaL_optnumber(L, startidx + 5, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, startidx + 6, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, startidx + 7, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
|
||||
if (luax_istype(L, startidx, math::Transform::type))
|
||||
{
|
||||
math::Transform *tf = luax_totype<math::Transform>(L, startidx);
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (texture && quad)
|
||||
instance()->drawq(texture, quad, tf->getMatrix());
|
||||
else
|
||||
instance()->draw(drawable, tf->getMatrix());
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = (float) luaL_optnumber(L, startidx + 0, 0.0);
|
||||
float y = (float) luaL_optnumber(L, startidx + 1, 0.0);
|
||||
float a = (float) luaL_optnumber(L, startidx + 2, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, startidx + 3, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, startidx + 4, sx);
|
||||
float ox = (float) luaL_optnumber(L, startidx + 5, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, startidx + 6, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, startidx + 7, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
|
||||
|
||||
Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (texture && quad)
|
||||
texture->drawq(quad, m);
|
||||
else if (drawable)
|
||||
drawable->draw(m);
|
||||
});
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (texture && quad)
|
||||
instance()->drawq(texture, quad, m);
|
||||
else if (drawable)
|
||||
instance()->draw(drawable, m);
|
||||
});
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1568,19 +1708,27 @@ int w_print(lua_State *L)
|
||||
std::vector<Font::ColoredString> str;
|
||||
luax_checkcoloredstring(L, 1, str);
|
||||
|
||||
float x = (float)luaL_optnumber(L, 2, 0.0);
|
||||
float y = (float)luaL_optnumber(L, 3, 0.0);
|
||||
float angle = (float)luaL_optnumber(L, 4, 0.0f);
|
||||
float sx = (float)luaL_optnumber(L, 5, 1.0f);
|
||||
float sy = (float)luaL_optnumber(L, 6, sx);
|
||||
float ox = (float)luaL_optnumber(L, 7, 0.0f);
|
||||
float oy = (float)luaL_optnumber(L, 8, 0.0f);
|
||||
float kx = (float)luaL_optnumber(L, 9, 0.0f);
|
||||
float ky = (float)luaL_optnumber(L, 10, 0.0f);
|
||||
if (luax_istype(L, 2, math::Transform::type))
|
||||
{
|
||||
math::Transform *tf = luax_totype<math::Transform>(L, 2);
|
||||
luax_catchexcept(L, [&](){ instance()->print(str, tf->getMatrix()); });
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = (float)luaL_optnumber(L, 2, 0.0);
|
||||
float y = (float)luaL_optnumber(L, 3, 0.0);
|
||||
float angle = (float)luaL_optnumber(L, 4, 0.0f);
|
||||
float sx = (float)luaL_optnumber(L, 5, 1.0f);
|
||||
float sy = (float)luaL_optnumber(L, 6, sx);
|
||||
float ox = (float)luaL_optnumber(L, 7, 0.0f);
|
||||
float oy = (float)luaL_optnumber(L, 8, 0.0f);
|
||||
float kx = (float)luaL_optnumber(L, 9, 0.0f);
|
||||
float ky = (float)luaL_optnumber(L, 10, 0.0f);
|
||||
|
||||
Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky);
|
||||
Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky);
|
||||
|
||||
luax_catchexcept(L, [&](){ instance()->print(str, m); });
|
||||
luax_catchexcept(L, [&](){ instance()->print(str, m); });
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1589,36 +1737,38 @@ int w_printf(lua_State *L)
|
||||
std::vector<Font::ColoredString> str;
|
||||
luax_checkcoloredstring(L, 1, str);
|
||||
|
||||
float x = (float)luaL_checknumber(L, 2);
|
||||
float y = (float)luaL_checknumber(L, 3);
|
||||
float wrap = (float)luaL_checknumber(L, 4);
|
||||
|
||||
float angle = 0.0f;
|
||||
float sx = 1.0f, sy = 1.0f;
|
||||
float ox = 0.0f, oy = 0.0f;
|
||||
float kx = 0.0f, ky = 0.0f;
|
||||
|
||||
Font::AlignMode align = Font::ALIGN_LEFT;
|
||||
Matrix4 m;
|
||||
|
||||
if (lua_gettop(L) >= 5)
|
||||
int formatidx = 4;
|
||||
|
||||
if (luax_istype(L, 2, math::Transform::type))
|
||||
{
|
||||
if (!lua_isnil(L, 5))
|
||||
{
|
||||
const char *str = luaL_checkstring(L, 5);
|
||||
if (!Font::getConstant(str, align))
|
||||
return luaL_error(L, "Incorrect alignment: %s", str);
|
||||
}
|
||||
math::Transform *tf = luax_totype<math::Transform>(L, 2);
|
||||
m = tf->getMatrix();
|
||||
formatidx = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = (float)luaL_checknumber(L, 2);
|
||||
float y = (float)luaL_checknumber(L, 3);
|
||||
|
||||
angle = (float) luaL_optnumber(L, 6, 0.0f);
|
||||
sx = (float) luaL_optnumber(L, 7, 1.0f);
|
||||
sy = (float) luaL_optnumber(L, 8, sx);
|
||||
ox = (float) luaL_optnumber(L, 9, 0.0f);
|
||||
oy = (float) luaL_optnumber(L, 10, 0.0f);
|
||||
kx = (float) luaL_optnumber(L, 11, 0.0f);
|
||||
ky = (float) luaL_optnumber(L, 12, 0.0f);
|
||||
float angle = (float) luaL_optnumber(L, 6, 0.0f);
|
||||
float sx = (float) luaL_optnumber(L, 7, 1.0f);
|
||||
float sy = (float) luaL_optnumber(L, 8, sx);
|
||||
float ox = (float) luaL_optnumber(L, 9, 0.0f);
|
||||
float oy = (float) luaL_optnumber(L, 10, 0.0f);
|
||||
float kx = (float) luaL_optnumber(L, 11, 0.0f);
|
||||
float ky = (float) luaL_optnumber(L, 12, 0.0f);
|
||||
|
||||
m = Matrix4(x, y, angle, sx, sy, ox, oy, kx, ky);
|
||||
}
|
||||
|
||||
Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky);
|
||||
float wrap = (float)luaL_checknumber(L, formatidx);
|
||||
|
||||
const char *astr = lua_isnoneornil(L, formatidx + 1) ? nullptr : luaL_checkstring(L, formatidx + 1);
|
||||
if (astr != nullptr && !Font::getConstant(astr, align))
|
||||
return luaL_error(L, "Incorrect alignment: %s", astr);
|
||||
|
||||
luax_catchexcept(L, [&](){ instance()->printf(str, wrap, align, m); });
|
||||
return 0;
|
||||
@@ -1698,11 +1848,14 @@ int w_points(lua_State *L)
|
||||
coords[i] = luax_tofloat(L, i + 1);
|
||||
}
|
||||
|
||||
instance()->points(coords, colors, numpoints);
|
||||
|
||||
delete[] coords;
|
||||
if (colors)
|
||||
delete[] colors;
|
||||
luax_catchexcept(L,
|
||||
[&](){ instance()->points(coords, colors, numpoints); },
|
||||
[&](bool) {
|
||||
delete[] coords;
|
||||
if (colors)
|
||||
delete[] colors;
|
||||
}
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1738,9 +1891,11 @@ int w_line(lua_State *L)
|
||||
coords[i] = luax_tofloat(L, i + 1);
|
||||
}
|
||||
|
||||
instance()->polyline(coords, args);
|
||||
luax_catchexcept(L,
|
||||
[&](){ instance()->polyline(coords, args); },
|
||||
[&](bool) { delete[] coords; }
|
||||
);
|
||||
|
||||
delete[] coords;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1766,11 +1921,11 @@ int w_rectangle(lua_State *L)
|
||||
float ry = (float)luaL_optnumber(L, 7, rx);
|
||||
|
||||
if (lua_isnoneornil(L, 8))
|
||||
instance()->rectangle(mode, x, y, w, h, rx, ry);
|
||||
luax_catchexcept(L, [&](){ instance()->rectangle(mode, x, y, w, h, rx, ry); });
|
||||
else
|
||||
{
|
||||
int points = (int) luaL_checknumber(L, 8);
|
||||
instance()->rectangle(mode, x, y, w, h, rx, ry, points);
|
||||
luax_catchexcept(L, [&](){ instance()->rectangle(mode, x, y, w, h, rx, ry, points); });
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1788,11 +1943,11 @@ int w_circle(lua_State *L)
|
||||
float radius = (float)luaL_checknumber(L, 4);
|
||||
|
||||
if (lua_isnoneornil(L, 5))
|
||||
instance()->circle(mode, x, y, radius);
|
||||
luax_catchexcept(L, [&](){ instance()->circle(mode, x, y, radius); });
|
||||
else
|
||||
{
|
||||
int points = (int) luaL_checknumber(L, 5);
|
||||
instance()->circle(mode, x, y, radius, points);
|
||||
luax_catchexcept(L, [&](){ instance()->circle(mode, x, y, radius, points); });
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1811,11 +1966,11 @@ int w_ellipse(lua_State *L)
|
||||
float b = (float)luaL_optnumber(L, 5, a);
|
||||
|
||||
if (lua_isnoneornil(L, 6))
|
||||
instance()->ellipse(mode, x, y, a, b);
|
||||
luax_catchexcept(L, [&](){ instance()->ellipse(mode, x, y, a, b); });
|
||||
else
|
||||
{
|
||||
int points = (int) luaL_checknumber(L, 6);
|
||||
instance()->ellipse(mode, x, y, a, b, points);
|
||||
luax_catchexcept(L, [&](){ instance()->ellipse(mode, x, y, a, b, points); });
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1848,11 +2003,11 @@ int w_arc(lua_State *L)
|
||||
float angle2 = (float) luaL_checknumber(L, startidx + 4);
|
||||
|
||||
if (lua_isnoneornil(L, startidx + 5))
|
||||
instance()->arc(drawmode, arcmode, x, y, radius, angle1, angle2);
|
||||
luax_catchexcept(L, [&](){ instance()->arc(drawmode, arcmode, x, y, radius, angle1, angle2); });
|
||||
else
|
||||
{
|
||||
int points = (int) luaL_checknumber(L, startidx + 5);
|
||||
instance()->arc(drawmode, arcmode, x, y, radius, angle1, angle2, points);
|
||||
luax_catchexcept(L, [&](){ instance()->arc(drawmode, arcmode, x, y, radius, angle1, angle2, points); });
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1900,8 +2055,11 @@ int w_polygon(lua_State *L)
|
||||
// make a closed loop
|
||||
coords[args] = coords[0];
|
||||
coords[args+1] = coords[1];
|
||||
instance()->polygon(mode, coords, args+2);
|
||||
delete[] coords;
|
||||
|
||||
luax_catchexcept(L,
|
||||
[&](){ instance()->polygon(mode, coords, args+2); },
|
||||
[&](bool) { delete[] coords; }
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1914,6 +2072,13 @@ int w_push(lua_State *L)
|
||||
return luaL_error(L, "Invalid graphics stack type: %s", sname);
|
||||
|
||||
luax_catchexcept(L, [&](){ instance()->push(stype); });
|
||||
|
||||
if (luax_istype(L, 2, math::Transform::type))
|
||||
{
|
||||
math::Transform *t = luax_totype<math::Transform>(L, 2);
|
||||
instance()->applyTransform(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1960,6 +2125,20 @@ int w_origin(lua_State * /*L*/)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_applyTransform(lua_State *L)
|
||||
{
|
||||
math::Transform *t = math::luax_checktransform(L, 1);
|
||||
instance()->applyTransform(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_replaceTransform(lua_State *L)
|
||||
{
|
||||
math::Transform *t = math::luax_checktransform(L, 1);
|
||||
instance()->replaceTransform(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_transformPoint(lua_State *L)
|
||||
{
|
||||
Vector p;
|
||||
@@ -1987,8 +2166,6 @@ int w_inverseTransformPoint(lua_State *L)
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "reset", w_reset },
|
||||
{ "clear", w_clear },
|
||||
{ "discard", w_discard },
|
||||
{ "present", w_present },
|
||||
|
||||
{ "newImage", w_newImage },
|
||||
@@ -2030,9 +2207,6 @@ static const luaL_Reg functions[] =
|
||||
{ "getPointSize", w_getPointSize },
|
||||
{ "setWireframe", w_setWireframe },
|
||||
{ "isWireframe", w_isWireframe },
|
||||
{ "newScreenshot", w_newScreenshot },
|
||||
{ "setCanvas", w_setCanvas },
|
||||
{ "getCanvas", w_getCanvas },
|
||||
|
||||
{ "setShader", w_setShader },
|
||||
{ "getShader", w_getShader },
|
||||
@@ -2046,6 +2220,14 @@ static const luaL_Reg functions[] =
|
||||
{ "getSystemLimits", w_getSystemLimits },
|
||||
{ "getStats", w_getStats },
|
||||
|
||||
{ "beginPass", w_beginPass },
|
||||
{ "endPass", w_endPass },
|
||||
{ "renderPass", w_renderPass },
|
||||
{ "isPassActive", w_isPassActive },
|
||||
{ "getPassCanvases", w_getPassCanvases },
|
||||
|
||||
{ "captureScreenshot", w_captureScreenshot },
|
||||
|
||||
{ "draw", w_draw },
|
||||
|
||||
{ "print", w_print },
|
||||
@@ -2057,6 +2239,9 @@ static const luaL_Reg functions[] =
|
||||
{ "getWidth", w_getWidth },
|
||||
{ "getHeight", w_getHeight },
|
||||
{ "getDimensions", w_getDimensions },
|
||||
{ "getPassWidth", w_getPassWidth },
|
||||
{ "getPassHeight", w_getPassHeight },
|
||||
{ "getPassDimensions", w_getPassDimensions },
|
||||
|
||||
{ "setScissor", w_setScissor },
|
||||
{ "intersectScissor", w_intersectScissor },
|
||||
@@ -2082,6 +2267,8 @@ static const luaL_Reg functions[] =
|
||||
{ "translate", w_translate },
|
||||
{ "shear", w_shear },
|
||||
{ "origin", w_origin },
|
||||
{ "applyTransform", w_applyTransform },
|
||||
{ "replaceTransform", w_replaceTransform },
|
||||
{ "transformPoint", w_transformPoint },
|
||||
{ "inverseTransformPoint", w_inverseTransformPoint },
|
||||
|
||||
|
||||
@@ -338,10 +338,21 @@ int w_Mesh_attachAttribute(lua_State *L)
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
Mesh *mesh = luax_checkmesh(L, 3);
|
||||
luax_catchexcept(L, [&](){ t->attachAttribute(name, mesh); });
|
||||
const char *attachname = luaL_optstring(L, 4, name);
|
||||
luax_catchexcept(L, [&](){ t->attachAttribute(name, mesh, attachname); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_detachAttribute(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
bool success = false;
|
||||
luax_catchexcept(L, [&](){ success = t->detachAttribute(name); });
|
||||
luax_pushboolean(L, success);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Mesh_flush(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
@@ -514,6 +525,7 @@ static const luaL_Reg w_Mesh_functions[] =
|
||||
{ "setAttributeEnabled", w_Mesh_setAttributeEnabled },
|
||||
{ "isAttributeEnabled", w_Mesh_isAttributeEnabled },
|
||||
{ "attachAttribute", w_Mesh_attachAttribute },
|
||||
{ "detachAttribute", w_Mesh_detachAttribute },
|
||||
{ "flush", w_Mesh_flush },
|
||||
{ "setVertexMap", w_Mesh_setVertexMap },
|
||||
{ "getVertexMap", w_Mesh_getVertexMap },
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "wrap_Shader.h"
|
||||
#include "graphics/wrap_Texture.h"
|
||||
#include "math/MathModule.h"
|
||||
#include "math/Transform.h"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
@@ -48,14 +49,12 @@ int w_Shader_getWarnings(lua_State *L)
|
||||
|
||||
static int _getCount(lua_State *L, int startidx, const Shader::UniformInfo *info)
|
||||
{
|
||||
return std::min(std::max(lua_gettop(L) - startidx, 1), info->count);
|
||||
return std::min(std::max(lua_gettop(L) - startidx + 1, 1), info->count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T *_getNumbers(lua_State *L, int startidx, Shader *shader, int components, int count)
|
||||
static void _updateNumbers(lua_State *L, int startidx, T *values, int components, int count)
|
||||
{
|
||||
T *values = shader->getScratchBuffer<T>(components * count);
|
||||
|
||||
if (components == 1)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
@@ -76,16 +75,15 @@ static T *_getNumbers(lua_State *L, int startidx, Shader *shader, int components
|
||||
lua_pop(L, components);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
int w_Shader_sendFloats(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info, bool colors)
|
||||
{
|
||||
int count = _getCount(L, startidx, info);
|
||||
int components = info->components;
|
||||
float *values = info->floats;
|
||||
|
||||
float *values = _getNumbers<float>(L, startidx, shader, components, count);
|
||||
_updateNumbers(L, startidx, values, components, count);
|
||||
|
||||
if (colors && graphics::isGammaCorrect())
|
||||
{
|
||||
@@ -99,15 +97,15 @@ int w_Shader_sendFloats(lua_State *L, int startidx, Shader *shader, const Shader
|
||||
}
|
||||
}
|
||||
|
||||
luax_catchexcept(L, [&]() { shader->sendFloats(info, values, count); });
|
||||
luax_catchexcept(L, [&]() { shader->updateUniform(info, count); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Shader_sendInts(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info)
|
||||
{
|
||||
int count = _getCount(L, startidx, info);
|
||||
int *values = _getNumbers<int>(L, startidx, shader, info->components, count);
|
||||
luax_catchexcept(L, [&]() { shader->sendInts(info, values, count); });
|
||||
_updateNumbers(L, startidx, info->ints, info->components, count);
|
||||
luax_catchexcept(L, [&]() { shader->updateUniform(info, count); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -116,15 +114,15 @@ int w_Shader_sendBooleans(lua_State *L, int startidx, Shader *shader, const Shad
|
||||
int count = _getCount(L, startidx, info);
|
||||
int components = info->components;
|
||||
|
||||
// We have to send booleans as ints or floats.
|
||||
float *values = shader->getScratchBuffer<float>(components * count);
|
||||
// We have to send booleans as ints.
|
||||
int *values = info->ints;
|
||||
|
||||
if (components == 1)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
luaL_checktype(L, startidx + i, LUA_TBOOLEAN);
|
||||
values[i] = (float) lua_toboolean(L, startidx + i);
|
||||
values[i] = (int) lua_toboolean(L, startidx + i);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -137,14 +135,14 @@ int w_Shader_sendBooleans(lua_State *L, int startidx, Shader *shader, const Shad
|
||||
{
|
||||
lua_rawgeti(L, startidx + i, k);
|
||||
luaL_checktype(L, -1, LUA_TBOOLEAN);
|
||||
values[i * components + k - 1] = (float) lua_toboolean(L, -1);
|
||||
values[i * components + k - 1] = (int) lua_toboolean(L, -1);
|
||||
}
|
||||
|
||||
lua_pop(L, components);
|
||||
}
|
||||
}
|
||||
|
||||
luax_catchexcept(L, [&]() { shader->sendFloats(info, values, count); });
|
||||
luax_catchexcept(L, [&]() { shader->updateUniform(info, count); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -163,10 +161,17 @@ int w_Shader_sendMatrices(lua_State *L, int startidx, Shader *shader, const Shad
|
||||
int rows = info->matrix.rows;
|
||||
int elements = columns * rows;
|
||||
|
||||
float *values = shader->getScratchBuffer<float>(elements * count);
|
||||
float *values = info->floats;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (columns == 4 && rows == 4 && luax_istype(L, startidx + i, math::Transform::type))
|
||||
{
|
||||
math::Transform *t = luax_totype<math::Transform>(L, startidx + i);
|
||||
memcpy(&values[i * 16], t->getMatrix().getElements(), sizeof(float) * 16);
|
||||
continue;
|
||||
}
|
||||
|
||||
luaL_checktype(L, startidx + i, LUA_TTABLE);
|
||||
|
||||
lua_rawgeti(L, startidx + i, 1);
|
||||
@@ -243,15 +248,21 @@ int w_Shader_sendMatrices(lua_State *L, int startidx, Shader *shader, const Shad
|
||||
}
|
||||
}
|
||||
|
||||
shader->sendMatrices(info, values, count);
|
||||
shader->updateUniform(info, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Shader_sendTexture(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info)
|
||||
int w_Shader_sendTextures(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info)
|
||||
{
|
||||
// We don't support arrays of textures (yet).
|
||||
Texture *texture = luax_checktexture(L, startidx);
|
||||
luax_catchexcept(L, [&]() { shader->sendTexture(info, texture); });
|
||||
int count = _getCount(L, startidx, info);
|
||||
|
||||
std::vector<Texture *> textures;
|
||||
textures.reserve(count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
textures.push_back(luax_checktexture(L, startidx + i));
|
||||
|
||||
luax_catchexcept(L, [&]() { shader->sendTextures(info, textures.data(), count); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -277,7 +288,7 @@ int w_Shader_send(lua_State *L)
|
||||
case Shader::UNIFORM_BOOL:
|
||||
return w_Shader_sendBooleans(L, startidx, shader, info);
|
||||
case Shader::UNIFORM_SAMPLER:
|
||||
return w_Shader_sendTexture(L, startidx, shader, info);
|
||||
return w_Shader_sendTextures(L, startidx, shader, info);
|
||||
default:
|
||||
return luaL_error(L, "Unknown variable type for shader uniform '%s", name);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Image.h"
|
||||
#include "Canvas.h"
|
||||
#include "graphics/wrap_Texture.h"
|
||||
#include "math/wrap_Transform.h"
|
||||
|
||||
// C++
|
||||
#include <typeinfo>
|
||||
@@ -51,24 +52,37 @@ static inline int w_SpriteBatch_add_or_set(lua_State *L, SpriteBatch *t, int sta
|
||||
else if (lua_isnil(L, startidx) && !lua_isnoneornil(L, startidx + 1))
|
||||
return luax_typerror(L, startidx, "Quad");
|
||||
|
||||
float x = (float) luaL_optnumber(L, startidx + 0, 0.0);
|
||||
float y = (float) luaL_optnumber(L, startidx + 1, 0.0);
|
||||
float a = (float) luaL_optnumber(L, startidx + 2, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, startidx + 3, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, startidx + 4, sx);
|
||||
float ox = (float) luaL_optnumber(L, startidx + 5, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, startidx + 6, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, startidx + 7, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
|
||||
if (luax_istype(L, startidx, math::Transform::type))
|
||||
{
|
||||
math::Transform *tf = luax_totype<math::Transform>(L, startidx);
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (quad)
|
||||
index = t->addq(quad, tf->getMatrix(), index);
|
||||
else
|
||||
index = t->add(tf->getMatrix(), index);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = (float) luaL_optnumber(L, startidx + 0, 0.0);
|
||||
float y = (float) luaL_optnumber(L, startidx + 1, 0.0);
|
||||
float a = (float) luaL_optnumber(L, startidx + 2, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, startidx + 3, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, startidx + 4, sx);
|
||||
float ox = (float) luaL_optnumber(L, startidx + 5, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, startidx + 6, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, startidx + 7, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
|
||||
|
||||
Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (quad)
|
||||
index = t->addq(quad, m, index);
|
||||
else
|
||||
index = t->add(m, index);
|
||||
});
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (quad)
|
||||
index = t->addq(quad, m, index);
|
||||
else
|
||||
index = t->add(m, index);
|
||||
});
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
**/
|
||||
|
||||
#include "wrap_Text.h"
|
||||
#include "math/wrap_Transform.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -126,24 +127,33 @@ int w_Text_add(lua_State *L)
|
||||
{
|
||||
Text *t = luax_checktext(L, 1);
|
||||
|
||||
int index = 0;
|
||||
|
||||
std::vector<Font::ColoredString> text;
|
||||
luax_checkcoloredstring(L, 2, text);
|
||||
|
||||
float x = (float) luaL_optnumber(L, 3, 0.0);
|
||||
float y = (float) luaL_optnumber(L, 4, 0.0);
|
||||
float a = (float) luaL_optnumber(L, 5, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, 6, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, 7, sx);
|
||||
float ox = (float) luaL_optnumber(L, 8, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, 9, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, 10, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, 11, 0.0);
|
||||
if (luax_istype(L, 3, math::Transform::type))
|
||||
{
|
||||
math::Transform *tf = luax_totype<math::Transform>(L, 3);
|
||||
luax_catchexcept(L, [&](){ index = t->add(text, tf->getMatrix()); });
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = (float) luaL_optnumber(L, 3, 0.0);
|
||||
float y = (float) luaL_optnumber(L, 4, 0.0);
|
||||
float a = (float) luaL_optnumber(L, 5, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, 6, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, 7, sx);
|
||||
float ox = (float) luaL_optnumber(L, 8, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, 9, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, 10, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, 11, 0.0);
|
||||
|
||||
Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
luax_catchexcept(L, [&](){ index = t->add(text, m); });
|
||||
}
|
||||
|
||||
Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
int index = 0;
|
||||
luax_catchexcept(L, [&](){ index = t->add(text, m); });
|
||||
lua_pushnumber(L, index + 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -151,6 +161,8 @@ int w_Text_addf(lua_State *L)
|
||||
{
|
||||
Text *t = luax_checktext(L, 1);
|
||||
|
||||
int index = 0;
|
||||
|
||||
std::vector<Font::ColoredString> text;
|
||||
luax_checkcoloredstring(L, 2, text);
|
||||
|
||||
@@ -162,21 +174,28 @@ int w_Text_addf(lua_State *L)
|
||||
if (!Font::getConstant(alignstr, align))
|
||||
return luaL_error(L, "Invalid align mode: %s", alignstr);
|
||||
|
||||
float x = (float) luaL_optnumber(L, 5, 0.0);
|
||||
float y = (float) luaL_optnumber(L, 6, 0.0);
|
||||
float a = (float) luaL_optnumber(L, 7, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, 8, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, 9, sx);
|
||||
float ox = (float) luaL_optnumber(L, 10, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, 11, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, 12, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, 13, 0.0);
|
||||
if (luax_istype(L, 5, math::Transform::type))
|
||||
{
|
||||
math::Transform *tf = luax_totype<math::Transform>(L, 5);
|
||||
luax_catchexcept(L, [&](){ index = t->addf(text, wrap, align, tf->getMatrix()); });
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = (float) luaL_optnumber(L, 5, 0.0);
|
||||
float y = (float) luaL_optnumber(L, 6, 0.0);
|
||||
float a = (float) luaL_optnumber(L, 7, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, 8, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, 9, sx);
|
||||
float ox = (float) luaL_optnumber(L, 10, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, 11, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, 12, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, 13, 0.0);
|
||||
|
||||
Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
luax_catchexcept(L, [&](){ index = t->addf(text, wrap, align, m); });
|
||||
}
|
||||
|
||||
Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
int index = 0;
|
||||
luax_catchexcept(L, [&](){ index = t->addf(text, wrap, align, m); });
|
||||
lua_pushnumber(L, index + 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "common/int.h"
|
||||
#include "common/StringMap.h"
|
||||
#include "BezierCurve.h"
|
||||
#include "Transform.h"
|
||||
|
||||
// STL
|
||||
#include <cmath>
|
||||
@@ -374,6 +375,16 @@ BezierCurve *Math::newBezierCurve(const std::vector<Vector> &points)
|
||||
return new BezierCurve(points);
|
||||
}
|
||||
|
||||
Transform *Math::newTransform()
|
||||
{
|
||||
return new Transform();
|
||||
}
|
||||
|
||||
Transform *Math::newTransform(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
{
|
||||
return new Transform(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
}
|
||||
|
||||
std::string hash(HashFunction::Function function, Data *input)
|
||||
{
|
||||
return hash(function, (const char*) input->getData(), input->getSize());
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace math
|
||||
{
|
||||
|
||||
class BezierCurve;
|
||||
class Transform;
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
@@ -176,6 +177,9 @@ public:
|
||||
**/
|
||||
BezierCurve *newBezierCurve(const std::vector<Vector> &points);
|
||||
|
||||
Transform *newTransform();
|
||||
Transform *newTransform(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
// Implements Module.
|
||||
virtual ModuleType getModuleType() const
|
||||
{
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 "Transform.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
love::Type Transform::type("Transform", &Object::type);
|
||||
|
||||
Transform::Transform()
|
||||
: matrix()
|
||||
, inverseDirty(true)
|
||||
, inverseMatrix()
|
||||
{
|
||||
}
|
||||
|
||||
Transform::Transform(const Matrix4 &m)
|
||||
: matrix(m)
|
||||
, inverseDirty(true)
|
||||
, inverseMatrix()
|
||||
{
|
||||
}
|
||||
|
||||
Transform::Transform(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
: matrix(x, y, a, sx, sy, ox, oy, kx, ky)
|
||||
, inverseDirty(true)
|
||||
, inverseMatrix()
|
||||
{
|
||||
}
|
||||
|
||||
Transform::~Transform()
|
||||
{
|
||||
}
|
||||
|
||||
Transform *Transform::clone()
|
||||
{
|
||||
return new Transform(*this);
|
||||
}
|
||||
|
||||
Transform *Transform::inverse()
|
||||
{
|
||||
return new Transform(getInverseMatrix());
|
||||
}
|
||||
|
||||
void Transform::apply(Transform *other)
|
||||
{
|
||||
matrix *= other->getMatrix();
|
||||
inverseDirty = true;
|
||||
}
|
||||
|
||||
void Transform::translate(float x, float y)
|
||||
{
|
||||
matrix.translate(x, y);
|
||||
inverseDirty = true;
|
||||
}
|
||||
|
||||
void Transform::rotate(float angle)
|
||||
{
|
||||
matrix.rotate(angle);
|
||||
inverseDirty = true;
|
||||
}
|
||||
|
||||
void Transform::scale(float x, float y)
|
||||
{
|
||||
matrix.scale(x, y);
|
||||
inverseDirty = true;
|
||||
}
|
||||
|
||||
void Transform::shear(float x, float y)
|
||||
{
|
||||
matrix.shear(x, y);
|
||||
inverseDirty = true;
|
||||
}
|
||||
|
||||
void Transform::reset()
|
||||
{
|
||||
matrix.setIdentity();
|
||||
inverseDirty = true;
|
||||
}
|
||||
|
||||
void Transform::setTransformation(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
{
|
||||
matrix.setTransformation(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
inverseDirty = true;
|
||||
}
|
||||
|
||||
love::Vector Transform::transformPoint(love::Vector p) const
|
||||
{
|
||||
love::Vector result;
|
||||
matrix.transform(&result, &p, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
love::Vector Transform::inverseTransformPoint(love::Vector p)
|
||||
{
|
||||
love::Vector result;
|
||||
getInverseMatrix().transform(&result, &p, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
const Matrix4 &Transform::getMatrix() const
|
||||
{
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void Transform::setMatrix(const Matrix4 &m)
|
||||
{
|
||||
matrix = m;
|
||||
inverseDirty = true;
|
||||
}
|
||||
|
||||
} // math
|
||||
} // love
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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/Object.h"
|
||||
#include "common/Matrix.h"
|
||||
#include "common/Vector.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
class Transform : public Object
|
||||
{
|
||||
public:
|
||||
|
||||
static love::Type type;
|
||||
|
||||
Transform();
|
||||
Transform(const Matrix4 &m);
|
||||
Transform(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
virtual ~Transform();
|
||||
|
||||
Transform *clone();
|
||||
Transform *inverse();
|
||||
|
||||
void apply(Transform *other);
|
||||
|
||||
void translate(float x, float y);
|
||||
void rotate(float angle);
|
||||
void scale(float x, float y);
|
||||
void shear(float x, float y);
|
||||
|
||||
void reset();
|
||||
void setTransformation(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
love::Vector transformPoint(love::Vector p) const;
|
||||
love::Vector inverseTransformPoint(love::Vector p);
|
||||
|
||||
const Matrix4 &getMatrix() const;
|
||||
void setMatrix(const Matrix4 &m);
|
||||
|
||||
private:
|
||||
|
||||
inline const Matrix4 &getInverseMatrix()
|
||||
{
|
||||
if (inverseDirty)
|
||||
{
|
||||
inverseDirty = false;
|
||||
inverseMatrix = matrix.inverse();
|
||||
}
|
||||
|
||||
return inverseMatrix;
|
||||
}
|
||||
|
||||
Matrix4 matrix;
|
||||
bool inverseDirty;
|
||||
Matrix4 inverseMatrix;
|
||||
|
||||
}; // Transform
|
||||
|
||||
|
||||
} // math
|
||||
} // love
|
||||
@@ -22,8 +22,10 @@
|
||||
#include "wrap_RandomGenerator.h"
|
||||
#include "wrap_BezierCurve.h"
|
||||
#include "wrap_CompressedData.h"
|
||||
#include "wrap_Transform.h"
|
||||
#include "MathModule.h"
|
||||
#include "BezierCurve.h"
|
||||
#include "Transform.h"
|
||||
#include "common/b64.h"
|
||||
|
||||
#include <cmath>
|
||||
@@ -118,6 +120,31 @@ int w_newBezierCurve(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_newTransform(lua_State *L)
|
||||
{
|
||||
Transform *t = nullptr;
|
||||
|
||||
if (lua_isnoneornil(L, 1))
|
||||
t = Math::instance.newTransform();
|
||||
else
|
||||
{
|
||||
float x = (float) luaL_checknumber(L, 1);
|
||||
float y = (float) luaL_checknumber(L, 2);
|
||||
float a = (float) luaL_optnumber(L, 3, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, 4, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, 5, sx);
|
||||
float ox = (float) luaL_optnumber(L, 6, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, 7, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, 8, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, 9, 0.0);
|
||||
t = Math::instance.newTransform(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
}
|
||||
|
||||
luax_pushtype(L, t);
|
||||
t->release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_triangulate(lua_State *L)
|
||||
{
|
||||
std::vector<love::Vector> vertices;
|
||||
@@ -507,6 +534,7 @@ static const luaL_Reg functions[] =
|
||||
{ "_getRandomGenerator", w__getRandomGenerator },
|
||||
{ "newRandomGenerator", w_newRandomGenerator },
|
||||
{ "newBezierCurve", w_newBezierCurve },
|
||||
{ "newTransform", w_newTransform },
|
||||
{ "triangulate", w_triangulate },
|
||||
{ "isConvex", w_isConvex },
|
||||
{ "gammaToLinear", w_gammaToLinear },
|
||||
@@ -525,6 +553,7 @@ static const lua_CFunction types[] =
|
||||
luaopen_randomgenerator,
|
||||
luaopen_beziercurve,
|
||||
luaopen_compresseddata,
|
||||
luaopen_transform,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 "wrap_Transform.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
Transform *luax_checktransform(lua_State *L, int idx)
|
||||
{
|
||||
return luax_checktype<Transform>(L, idx, Transform::type);
|
||||
}
|
||||
|
||||
int w_Transform_clone(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
Transform *newtransform = t->clone();
|
||||
luax_pushtype(L, newtransform);
|
||||
newtransform->release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_inverse(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
Transform *inverse = t->inverse();
|
||||
luax_pushtype(L, inverse);
|
||||
inverse->release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_apply(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
Transform *other = luax_checktransform(L, 2);
|
||||
t->apply(other);
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_translate(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
float x = (float) luaL_checknumber(L, 2);
|
||||
float y = (float) luaL_checknumber(L, 3);
|
||||
t->translate(x, y);
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_rotate(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
float angle = (float) luaL_checknumber(L, 2);
|
||||
t->rotate(angle);
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_scale(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
float sx = (float) luaL_checknumber(L, 2);
|
||||
float sy = (float) luaL_optnumber(L, 3, sx);
|
||||
t->scale(sx, sy);
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_shear(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
float kx = (float) luaL_checknumber(L, 2);
|
||||
float ky = (float) luaL_checknumber(L, 3);
|
||||
t->shear(kx, ky);
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_reset(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
t->reset();
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_setTransformation(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
float x = (float) luaL_optnumber(L, 2, 0.0);
|
||||
float y = (float) luaL_optnumber(L, 3, 0.0);
|
||||
float a = (float) luaL_optnumber(L, 4, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, 5, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, 6, sx);
|
||||
float ox = (float) luaL_optnumber(L, 7, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, 8, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, 9, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, 10, 0.0);
|
||||
t->setTransformation(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_setMatrix(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
|
||||
bool columnmajor = false;
|
||||
|
||||
int idx = 2;
|
||||
if (lua_isboolean(L, idx))
|
||||
{
|
||||
columnmajor = lua_toboolean(L, idx);
|
||||
idx++;
|
||||
}
|
||||
|
||||
float elements[16];
|
||||
|
||||
if (lua_istable(L, idx))
|
||||
{
|
||||
lua_rawgeti(L, idx, 1);
|
||||
bool tableoftables = lua_istable(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (tableoftables)
|
||||
{
|
||||
if (columnmajor)
|
||||
{
|
||||
for (int column = 0; column < 4; column++)
|
||||
{
|
||||
lua_rawgeti(L, idx, column + 1);
|
||||
|
||||
for (int row = 0; row < 4; row++)
|
||||
{
|
||||
lua_rawgeti(L, -(row + 1), row + 1);
|
||||
elements[column * 4 + row] = (float) luaL_checknumber(L, -1);
|
||||
}
|
||||
|
||||
lua_pop(L, 4 + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int row = 0; row < 4; row++)
|
||||
{
|
||||
lua_rawgeti(L, idx, row + 1);
|
||||
|
||||
for (int column = 0; column < 4; column++)
|
||||
{
|
||||
// The table has the matrix elements laid out in row-major
|
||||
// order, but we need to store them column-major in memory.
|
||||
lua_rawgeti(L, -(column + 1), column + 1);
|
||||
elements[column * 4 + row] = (float) luaL_checknumber(L, -1);
|
||||
}
|
||||
|
||||
lua_pop(L, 4 + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (columnmajor)
|
||||
{
|
||||
for (int column = 0; column < 4; column++)
|
||||
{
|
||||
for (int row = 0; row < 4; row++)
|
||||
{
|
||||
lua_rawgeti(L, idx, column * 4 + row + 1);
|
||||
elements[column * 4 + row] = (float) luaL_checknumber(L, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int column = 0; column < 4; column++)
|
||||
{
|
||||
for (int row = 0; row < 4; row++)
|
||||
{
|
||||
// The table has the matrix elements laid out in row-major
|
||||
// order, but we need to store them column-major in memory.
|
||||
lua_rawgeti(L, idx, row * 4 + column + 1);
|
||||
elements[column * 4 + row] = (float) luaL_checknumber(L, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_pop(L, 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (columnmajor)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
elements[i] = (float) luaL_checknumber(L, idx + i);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int column = 0; column < 4; column++)
|
||||
{
|
||||
for (int row = 0; row < 4; row++)
|
||||
elements[column * 4 + row] = (float) luaL_checknumber(L, row * 4 + column + idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t->setMatrix(Matrix4(elements));
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Transform_getMatrix(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
const float *elements = t->getMatrix().getElements();
|
||||
|
||||
// We want to push elements in row-major order, but they're stored column-
|
||||
// major.
|
||||
for (int row = 0; row < 4; row++)
|
||||
{
|
||||
for (int column = 0; column < 4; column++)
|
||||
lua_pushnumber(L, elements[column * 4 + row]);
|
||||
}
|
||||
|
||||
return 16;
|
||||
}
|
||||
|
||||
int w_Transform_transformPoint(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
love::Vector p;
|
||||
p.x = (float) luaL_checknumber(L, 2);
|
||||
p.y = (float) luaL_checknumber(L, 3);
|
||||
p = t->transformPoint(p);
|
||||
lua_pushnumber(L, p.x);
|
||||
lua_pushnumber(L, p.y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_Transform_inverseTransformPoint(lua_State *L)
|
||||
{
|
||||
Transform *t = luax_checktransform(L, 1);
|
||||
love::Vector p;
|
||||
p.x = (float) luaL_checknumber(L, 2);
|
||||
p.y = (float) luaL_checknumber(L, 3);
|
||||
p = t->inverseTransformPoint(p);
|
||||
lua_pushnumber(L, p.x);
|
||||
lua_pushnumber(L, p.y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_Transform__mul(lua_State *L)
|
||||
{
|
||||
Transform *t1 = luax_checktransform(L, 1);
|
||||
Transform *t2 = luax_checktransform(L, 2);
|
||||
Transform *t3 = new Transform(t1->getMatrix() * t2->getMatrix());
|
||||
luax_pushtype(L, t3);
|
||||
t3->release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "clone", w_Transform_clone },
|
||||
{ "inverse", w_Transform_inverse },
|
||||
{ "apply", w_Transform_apply },
|
||||
{ "translate", w_Transform_translate },
|
||||
{ "rotate", w_Transform_rotate },
|
||||
{ "scale", w_Transform_scale },
|
||||
{ "shear", w_Transform_shear },
|
||||
{ "reset", w_Transform_reset },
|
||||
{ "setTransformation", w_Transform_setTransformation },
|
||||
{ "transformPoint", w_Transform_transformPoint },
|
||||
{ "inverseTransformPoint", w_Transform_inverseTransformPoint },
|
||||
{ "__mul", w_Transform__mul },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
extern "C" int luaopen_transform(lua_State *L)
|
||||
{
|
||||
return luax_register_type(L, &Transform::type, functions, nullptr);
|
||||
}
|
||||
|
||||
} // math
|
||||
} // love
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 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 "Transform.h"
|
||||
#include "common/runtime.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
Transform *luax_checktransform(lua_State *L, int idx);
|
||||
extern "C" int luaopen_transform(lua_State *L);
|
||||
|
||||
} // math
|
||||
} // love
|
||||
@@ -32,6 +32,12 @@
|
||||
|
||||
namespace love
|
||||
{
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
class Graphics;
|
||||
}
|
||||
|
||||
namespace window
|
||||
{
|
||||
|
||||
@@ -108,6 +114,8 @@ public:
|
||||
// Implements Module.
|
||||
virtual ModuleType getModuleType() const { return M_WINDOW; }
|
||||
|
||||
virtual void setGraphics(graphics::Graphics *graphics) = 0;
|
||||
|
||||
virtual bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr) = 0;
|
||||
virtual void getWindow(int &width, int &height, WindowSettings &settings) = 0;
|
||||
|
||||
|
||||
@@ -79,9 +79,16 @@ Window::~Window()
|
||||
{
|
||||
close();
|
||||
|
||||
graphics.set(nullptr);
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
}
|
||||
|
||||
void Window::setGraphics(graphics::Graphics *graphics)
|
||||
{
|
||||
this->graphics.set(graphics);
|
||||
}
|
||||
|
||||
void Window::setGLFramebufferAttributes(int msaa, bool sRGB)
|
||||
{
|
||||
// Set GL window / framebuffer attributes.
|
||||
@@ -401,6 +408,12 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
|
||||
|
||||
bool Window::setWindow(int width, int height, WindowSettings *settings)
|
||||
{
|
||||
if (!graphics.get())
|
||||
graphics.set(Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS));
|
||||
|
||||
if (graphics.get() && graphics->isPassActive())
|
||||
throw love::Exception("setMode cannot be called while a render pass is active in love.graphics.");
|
||||
|
||||
WindowSettings f;
|
||||
|
||||
if (settings)
|
||||
@@ -507,9 +520,8 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
|
||||
|
||||
updateSettings(f, false);
|
||||
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
if (gfx != nullptr)
|
||||
gfx->setMode(pixelWidth, pixelHeight);
|
||||
if (graphics.get())
|
||||
graphics->setMode(pixelWidth, pixelHeight);
|
||||
|
||||
#ifdef LOVE_ANDROID
|
||||
love::android::setImmersive(f.fullscreen);
|
||||
@@ -528,9 +540,8 @@ bool Window::onSizeChanged(int width, int height)
|
||||
|
||||
SDL_GL_GetDrawableSize(window, &pixelWidth, &pixelHeight);
|
||||
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
if (gfx != nullptr)
|
||||
gfx->setViewportSize(pixelWidth, pixelHeight);
|
||||
if (graphics.get())
|
||||
graphics->setViewportSize(pixelWidth, pixelHeight);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -596,13 +607,9 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi
|
||||
// May be 0 if the refresh rate can't be determined.
|
||||
settings.refreshrate = (double) dmode.refresh_rate;
|
||||
|
||||
if (updateGraphicsViewport)
|
||||
{
|
||||
// Update the viewport size now instead of waiting for event polling.
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
if (gfx != nullptr)
|
||||
gfx->setViewportSize(pixelWidth, pixelHeight);
|
||||
}
|
||||
// Update the viewport size now instead of waiting for event polling.
|
||||
if (updateGraphicsViewport && graphics.get())
|
||||
graphics->setViewportSize(pixelWidth, pixelHeight);
|
||||
}
|
||||
|
||||
void Window::getWindow(int &width, int &height, WindowSettings &newsettings)
|
||||
@@ -618,9 +625,13 @@ void Window::getWindow(int &width, int &height, WindowSettings &newsettings)
|
||||
|
||||
void Window::close()
|
||||
{
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
if (gfx != nullptr)
|
||||
gfx->unSetMode();
|
||||
if (graphics.get())
|
||||
{
|
||||
if (graphics->isPassActive())
|
||||
throw love::Exception("close cannot be called while a render pass is active in love.graphics.");
|
||||
|
||||
graphics->unSetMode();
|
||||
}
|
||||
|
||||
if (context)
|
||||
{
|
||||
@@ -646,6 +657,9 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype)
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
if (graphics.get() && graphics->isPassActive())
|
||||
throw love::Exception("setFullscreen cannot be called while a render pass is active in love.graphics.");
|
||||
|
||||
WindowSettings newsettings = settings;
|
||||
newsettings.fullscreen = fullscreen;
|
||||
newsettings.fstype = fstype;
|
||||
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
Window();
|
||||
~Window();
|
||||
|
||||
void setGraphics(graphics::Graphics *graphics);
|
||||
|
||||
bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr);
|
||||
void getWindow(int &width, int &height, WindowSettings &settings);
|
||||
|
||||
@@ -149,6 +151,8 @@ private:
|
||||
bool hasSDL203orEarlier;
|
||||
ContextAttribs contextAttribs;
|
||||
|
||||
StrongRef<graphics::Graphics> graphics;
|
||||
|
||||
}; // Window
|
||||
|
||||
} // sdl
|
||||
|
||||
@@ -119,7 +119,7 @@ int w_setMode(lua_State *L)
|
||||
|
||||
if (lua_isnoneornil(L, 3))
|
||||
{
|
||||
luax_pushboolean(L, instance()->setWindow(w, h, nullptr));
|
||||
luax_catchexcept(L, [&](){ luax_pushboolean(L, instance()->setWindow(w, h, nullptr)); });
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -266,10 +266,12 @@ int w_setFullscreen(lua_State *L)
|
||||
return luaL_error(L, "Invalid fullscreen type: %s", typestr);
|
||||
|
||||
bool success = false;
|
||||
if (fstype == Window::FULLSCREEN_MAX_ENUM)
|
||||
success = instance()->setFullscreen(fullscreen);
|
||||
else
|
||||
success = instance()->setFullscreen(fullscreen, fstype);
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (fstype == Window::FULLSCREEN_MAX_ENUM)
|
||||
success = instance()->setFullscreen(fullscreen);
|
||||
else
|
||||
success = instance()->setFullscreen(fullscreen, fstype);
|
||||
});
|
||||
|
||||
luax_pushboolean(L, success);
|
||||
return 1;
|
||||
@@ -296,9 +298,9 @@ int w_isOpen(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_close(lua_State * /*L*/)
|
||||
int w_close(lua_State *L)
|
||||
{
|
||||
instance()->close();
|
||||
luax_catchexcept(L, [&]() { instance()->close(); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+19
-11
@@ -122,11 +122,10 @@ function love.arg.parse_option(m, i)
|
||||
m.arg = {}
|
||||
for j=i,i+m.a-1 do
|
||||
table.insert(m.arg, arg[j])
|
||||
i = j
|
||||
end
|
||||
end
|
||||
|
||||
return i
|
||||
return m.a
|
||||
end
|
||||
|
||||
function love.arg.parse_options()
|
||||
@@ -134,15 +133,17 @@ function love.arg.parse_options()
|
||||
local game
|
||||
local argc = #arg
|
||||
|
||||
for i=1,argc do
|
||||
local i = 1
|
||||
while i <= argc do
|
||||
-- Look for options.
|
||||
local s, e, m = string.find(arg[i], "%-%-(.+)")
|
||||
local m = string.match(arg[i], "^%-%-(.+)")
|
||||
|
||||
if m and love.arg.options[m] then
|
||||
i = love.arg.parse_option(love.arg.options[m], i+1)
|
||||
i = i + love.arg.parse_option(love.arg.options[m], i+1)
|
||||
elseif not game then
|
||||
game = i
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if not love.arg.options.game.set then
|
||||
@@ -545,9 +546,14 @@ function love.run()
|
||||
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
|
||||
|
||||
if love.graphics and love.graphics.isActive() then
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.origin()
|
||||
|
||||
if love.drawpasses then love.drawpasses() end
|
||||
|
||||
love.graphics.beginPass(love.graphics.getBackgroundColor())
|
||||
if love.draw then love.draw() end
|
||||
love.graphics.endPass()
|
||||
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
@@ -598,15 +604,18 @@ function love.errhand(msg)
|
||||
end
|
||||
end
|
||||
if love.audio then love.audio.stop() end
|
||||
|
||||
love.graphics.reset()
|
||||
if love.graphics.isPassActive() then
|
||||
love.graphics.endPass()
|
||||
end
|
||||
|
||||
local font = love.graphics.setNewFont(math.floor(love.window.toPixels(14)))
|
||||
|
||||
love.graphics.setBackgroundColor(89/255, 157/255, 220/255)
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
local trace = debug.traceback()
|
||||
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.origin()
|
||||
|
||||
local err = {}
|
||||
@@ -628,9 +637,7 @@ function love.errhand(msg)
|
||||
|
||||
local function draw()
|
||||
local pos = love.window.toPixels(70)
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos)
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
while true do
|
||||
@@ -652,7 +659,8 @@ function love.errhand(msg)
|
||||
end
|
||||
end
|
||||
|
||||
draw()
|
||||
love.graphics.renderPass(89/255, 157/255, 220/255, draw)
|
||||
love.graphics.present()
|
||||
|
||||
if love.timer then
|
||||
love.timer.sleep(0.1)
|
||||
|
||||
+33
-28
@@ -218,30 +218,33 @@ const unsigned char boot_lua[] =
|
||||
0x64, 0x6f, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x6d, 0x2e,
|
||||
0x61, 0x72, 0x67, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x5b, 0x6a, 0x5d, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20, 0x6a, 0x0a,
|
||||
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x0a,
|
||||
0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x2e, 0x61, 0x0a,
|
||||
0x65, 0x6e, 0x64, 0x0a,
|
||||
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e,
|
||||
0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x72, 0x67, 0x63, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x72, 0x67, 0x0a,
|
||||
0x09, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x61, 0x72, 0x67, 0x63, 0x20, 0x64, 0x6f, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x31, 0x0a,
|
||||
0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x20, 0x3c, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x63, 0x20, 0x64,
|
||||
0x6f, 0x0a,
|
||||
0x09, 0x09, 0x2d, 0x2d, 0x20, 0x4c, 0x6f, 0x6f, 0x6b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6f, 0x70, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x2e, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x2c, 0x20, 0x65, 0x2c, 0x20, 0x6d, 0x20, 0x3d, 0x20,
|
||||
0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x61, 0x72, 0x67, 0x5b, 0x69, 0x5d,
|
||||
0x2c, 0x20, 0x22, 0x25, 0x2d, 0x25, 0x2d, 0x28, 0x2e, 0x2b, 0x29, 0x22, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
|
||||
0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x61, 0x72, 0x67, 0x5b, 0x69, 0x5d, 0x2c, 0x20, 0x22, 0x5e, 0x25,
|
||||
0x2d, 0x25, 0x2d, 0x28, 0x2e, 0x2b, 0x29, 0x22, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x69, 0x66, 0x20, 0x6d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72,
|
||||
0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x6d, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x70, 0x61,
|
||||
0x72, 0x73, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72,
|
||||
0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x6d, 0x5d, 0x2c, 0x20, 0x69, 0x2b, 0x31, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72,
|
||||
0x67, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76,
|
||||
0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5b, 0x6d, 0x5d, 0x2c, 0x20,
|
||||
0x69, 0x2b, 0x31, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20,
|
||||
0x74, 0x68, 0x65, 0x6e, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x0a,
|
||||
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x09, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x20, 0x2b, 0x20, 0x31, 0x0a,
|
||||
0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x61, 0x72, 0x67, 0x2e, 0x6f,
|
||||
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68,
|
||||
@@ -1005,14 +1008,19 @@ const unsigned char boot_lua[] =
|
||||
0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73,
|
||||
0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73,
|
||||
0x2e, 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63,
|
||||
0x6c, 0x65, 0x61, 0x72, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73,
|
||||
0x2e, 0x67, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f,
|
||||
0x72, 0x28, 0x29, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6f,
|
||||
0x72, 0x69, 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x70, 0x61, 0x73,
|
||||
0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x72, 0x61, 0x77,
|
||||
0x70, 0x61, 0x73, 0x73, 0x65, 0x73, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x62,
|
||||
0x65, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70,
|
||||
0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64,
|
||||
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x29, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x20, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x65,
|
||||
0x6e, 0x64, 0x50, 0x61, 0x73, 0x73, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70,
|
||||
0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
@@ -1098,23 +1106,21 @@ const unsigned char boot_lua[] =
|
||||
0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x72, 0x65, 0x73,
|
||||
0x65, 0x74, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e,
|
||||
0x69, 0x73, 0x50, 0x61, 0x73, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x65, 0x6e,
|
||||
0x64, 0x50, 0x61, 0x73, 0x73, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65,
|
||||
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x4e, 0x65, 0x77, 0x46, 0x6f,
|
||||
0x6e, 0x74, 0x28, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, 0x6c, 0x6f, 0x76, 0x65,
|
||||
0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x74, 0x6f, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x28, 0x31,
|
||||
0x34, 0x29, 0x29, 0x29, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74,
|
||||
0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x38, 0x39,
|
||||
0x2f, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x31, 0x35, 0x37, 0x2f, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x32, 0x30,
|
||||
0x2f, 0x32, 0x35, 0x35, 0x29, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74,
|
||||
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x62,
|
||||
0x75, 0x67, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c, 0x65,
|
||||
0x61, 0x72, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67,
|
||||
0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28,
|
||||
0x29, 0x29, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6f, 0x72, 0x69,
|
||||
0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a,
|
||||
@@ -1148,16 +1154,10 @@ const unsigned char boot_lua[] =
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x6f, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65,
|
||||
0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x74, 0x6f, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x28, 0x37,
|
||||
0x30, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c,
|
||||
0x65, 0x61, 0x72, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e,
|
||||
0x67, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72,
|
||||
0x28, 0x29, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72,
|
||||
0x69, 0x6e, 0x74, 0x66, 0x28, 0x70, 0x2c, 0x20, 0x70, 0x6f, 0x73, 0x2c, 0x20, 0x70, 0x6f, 0x73, 0x2c, 0x20,
|
||||
0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x57,
|
||||
0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x2d, 0x20, 0x70, 0x6f, 0x73, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72,
|
||||
0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x28,
|
||||
@@ -1194,7 +1194,12 @@ const unsigned char boot_lua[] =
|
||||
0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x72, 0x65,
|
||||
0x6e, 0x64, 0x65, 0x72, 0x50, 0x61, 0x73, 0x73, 0x28, 0x38, 0x39, 0x2f, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x31,
|
||||
0x35, 0x37, 0x2f, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x32, 0x30, 0x2f, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x64,
|
||||
0x72, 0x61, 0x77, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72,
|
||||
0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 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, 0x6c, 0x65, 0x65,
|
||||
|
||||
Reference in New Issue
Block a user