Browse Source

- added pixel correct hit test
- optimized atlases size
- refactored ResAtlas
- fixed ThreadMessages infinity loop
- updated to latest SDL
- minor fixes

dmuratshin 10 years ago
parent
commit
012c9cdcaf
47 changed files with 1319 additions and 623 deletions
  1. 2 2
      .hg_archival.txt
  2. 1 0
      Android.mk
  3. 1 1
      examples/Demo/data/ext/fonts.xml.ox/meta.xml
  4. BIN
      examples/Demo/data/images/flower.png
  5. 7 0
      examples/Demo/data/xmls/res.xml
  6. 1 1
      examples/Demo/proj.cmake/CMakeLists.txt
  7. 1 1
      examples/Demo/proj.emscripten/CMakeLists.txt
  8. 74 64
      examples/Demo/proj.ios/demo_ios.xcodeproj/project.pbxproj
  9. 74 64
      examples/Demo/proj.macosx/demo_macosx.xcodeproj/project.pbxproj
  10. 1 1
      examples/Demo/proj.win32/Demo_vs2010.vcxproj
  11. 1 1
      examples/Demo/proj.win32/Demo_vs2013.vcxproj
  12. 55 0
      examples/Demo/src/TestAlphaHitTest.h
  13. 2 2
      examples/Demo/src/TestDrag.h
  14. 6 0
      examples/Demo/src/example.cpp
  15. 17 2
      examples/HelloWorld/src/example.cpp
  16. 8 2
      oxygine/SDL/ios/oxygine/oxygine_ios.xcodeproj/project.pbxproj
  17. 8 2
      oxygine/SDL/macosx/oxygine_macosx/oxygine_macosx.xcodeproj/project.pbxproj
  18. 2 0
      oxygine/SDL/win32/oxygine_vs2010.vcxproj
  19. 6 0
      oxygine/SDL/win32/oxygine_vs2010.vcxproj.filters
  20. 2 0
      oxygine/SDL/win32/oxygine_vs2013.vcxproj
  21. 6 0
      oxygine/SDL/win32/oxygine_vs2013.vcxproj.filters
  22. 1 0
      oxygine/marmalade/oxygine-framework.mkf
  23. 15 3
      oxygine/src/AnimationFrame.h
  24. 2 2
      oxygine/src/Box9Sprite.cpp
  25. 2 2
      oxygine/src/ProgressBar.cpp
  26. 32 2
      oxygine/src/Sprite.cpp
  27. 2 0
      oxygine/src/Sprite.h
  28. 1 1
      oxygine/src/core/Mem2Native.cpp
  29. 25 2
      oxygine/src/core/ThreadMessages.cpp
  30. 16 2
      oxygine/src/core/ThreadMessages.h
  31. 2 2
      oxygine/src/core/curl/HttpRequestCurlTask.cpp
  32. 11 11
      oxygine/src/core/gl/ShaderProgramGL.cpp
  33. 8 6
      oxygine/src/core/oxygine.cpp
  34. 16 3
      oxygine/src/res/CreateResourceContext.cpp
  35. 4 2
      oxygine/src/res/CreateResourceContext.h
  36. 3 2
      oxygine/src/res/ResAnim.cpp
  37. 6 4
      oxygine/src/res/ResAnim.h
  38. 549 309
      oxygine/src/res/ResAtlas.cpp
  39. 26 13
      oxygine/src/res/ResAtlas.h
  40. 2 2
      oxygine/src/res/Resources.cpp
  41. 88 0
      oxygine/src/utils/cdecode.c
  42. 28 0
      oxygine/src/utils/cdecode.h
  43. 42 17
      tools/others/build_oxygine_with_sdl.py
  44. 0 29
      tools/others/build_oxygine_zip.py
  45. 162 64
      tools/resbuild/process_atlas.py
  46. 0 1
      tools/resbuild/process_starling_atlas.py
  47. 1 1
      tools/resbuild/xml_processor.py

+ 2 - 2
.hg_archival.txt

@@ -1,5 +1,5 @@
 repo: b6d71054df5712e643a0685bc3ba54b123db5729
-node: cfa7aa3a2e73acd0cfaca12d0e2090f3f5a13a1c
+node: a9037394e69248dceddea3b2e9a6d06cfed25bbb
 branch: default
 latesttag: oldrender
-latesttagdistance: 738
+latesttagdistance: 777

+ 1 - 0
Android.mk

@@ -32,6 +32,7 @@ LOCAL_SRC_FILES := \
 				$(wildcard $(SRC)/text_utils/*.cpp) \
 				$(wildcard $(SRC)/dev_tools/*.cpp) \
 				$(wildcard $(SRC)/utils/*.cpp) \
+				$(wildcard $(SRC)/utils/*.c) \
 				$(wildcard $(SRC)/winnie_alloc/*.cpp) \
 				$(wildcard $(SRC)/minizip/*.c) \
 				$(wildcard $(SRC)/*.cpp) \

+ 1 - 1
examples/Demo/data/ext/fonts.xml.ox/meta.xml

@@ -1 +1 @@
-<resources version="1"><set/><bmfc_font sf="1.0" size="16"/><bmfc_font sf="1.0" size="26"/></resources>
+<resources version="2"><set/><bmfc_font sf="1.0" size="16"/><bmfc_font sf="1.0" size="26"/></resources>

BIN
examples/Demo/data/images/flower.png


+ 7 - 0
examples/Demo/data/xmls/res.xml

@@ -2,12 +2,19 @@
 <resources>
 	<font file="demo/font.fnt" />
 	<set path = "./../images" />
+
+	<set alpha="1" />
+
 	<atlas id = "primary" format="8888">
 		<image file="gray.png"/>
 		<image file="logo2.png" /> <!-- border=2 adds 2 pixel border from each side of image in atlas to avoid problem with mask -->
 		<image file="brush.png"/>
 		<image file="palette.png"/>		
 		<image file="snow.png"/>
+
+		<set hit_test="true" />
+		<image file="flower.png"/>
+		<set hit_test="false" />
 		
 		<image id="anim" file="anim1.png" cols = "7" /> <!-- 'id' is optional -->
 		<image id="anim2" file="anim2.png" cols = "20" /> <!-- 'id' is optional -->

+ 1 - 1
examples/Demo/proj.cmake/CMakeLists.txt

@@ -7,7 +7,7 @@ include_directories(${OXYGINE_INCLUDE_DIRS})
 link_directories(${OXYGINE_LIBRARY_DIRS})
 
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
-add_executable(Demo ../src/entry_point.cpp ../src/example.cpp ../src/test.cpp  ../src/TestBox9Sprite.h ../src/TestClipRect.h ../src/TestDrag.h ../src/TestHttp.h ../src/TestInputText.h ../src/TestManageRes.h ../src/TestMask.h ../src/TestPerf.h ../src/TestPolygon.h ../src/TestProgressBar.h ../src/TestRender2Texture.h ../src/TestSliding.h ../src/TestTexel2Pixel.h ../src/TestText.h ../src/TestTextureFormat.h ../src/TestTweens.h ../src/TestUserShader.h ../src/TestUserShader2.h ../src/example.h ../src/test.h )
+add_executable(Demo ../src/entry_point.cpp ../src/example.cpp ../src/test.cpp  ../src/TestAlphaHitTest.h ../src/TestBox9Sprite.h ../src/TestClipRect.h ../src/TestDrag.h ../src/TestHttp.h ../src/TestInputText.h ../src/TestManageRes.h ../src/TestMask.h ../src/TestPerf.h ../src/TestPolygon.h ../src/TestProgressBar.h ../src/TestRender2Texture.h ../src/TestSliding.h ../src/TestTexel2Pixel.h ../src/TestText.h ../src/TestTextureFormat.h ../src/TestTweens.h ../src/TestUserShader.h ../src/TestUserShader2.h ../src/example.h ../src/test.h )
 
 if (WIN32) #disable console mode for VC++
 	set_target_properties(Demo PROPERTIES WIN32_EXECUTABLE TRUE)

+ 1 - 1
examples/Demo/proj.emscripten/CMakeLists.txt

@@ -9,7 +9,7 @@ link_directories(${OXYGINE_LIBRARY_DIRS})
 SET(CMAKE_EXECUTABLE_SUFFIX ".html")
 set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-Wno-warn-absolute-paths -std=c++11")
 
-add_executable(Demo ../src/entry_point.cpp ../src/example.cpp ../src/test.cpp  ../src/TestBox9Sprite.h ../src/TestClipRect.h ../src/TestDrag.h ../src/TestHttp.h ../src/TestInputText.h ../src/TestManageRes.h ../src/TestMask.h ../src/TestPerf.h ../src/TestPolygon.h ../src/TestProgressBar.h ../src/TestRender2Texture.h ../src/TestSliding.h ../src/TestTexel2Pixel.h ../src/TestText.h ../src/TestTextureFormat.h ../src/TestTweens.h ../src/TestUserShader.h ../src/TestUserShader2.h ../src/example.h ../src/test.h )
+add_executable(Demo ../src/entry_point.cpp ../src/example.cpp ../src/test.cpp  ../src/TestAlphaHitTest.h ../src/TestBox9Sprite.h ../src/TestClipRect.h ../src/TestDrag.h ../src/TestHttp.h ../src/TestInputText.h ../src/TestManageRes.h ../src/TestMask.h ../src/TestPerf.h ../src/TestPolygon.h ../src/TestProgressBar.h ../src/TestRender2Texture.h ../src/TestSliding.h ../src/TestTexel2Pixel.h ../src/TestText.h ../src/TestTextureFormat.h ../src/TestTweens.h ../src/TestUserShader.h ../src/TestUserShader2.h ../src/example.h ../src/test.h )
 
 if (CMAKE_BUILD_TYPE STREQUAL Debug)
 	SET(linkFlags "-g4 ")

+ 74 - 64
examples/Demo/proj.ios/demo_ios.xcodeproj/project.pbxproj

@@ -25,12 +25,14 @@
 		2DC477AC10D6C07B3FE008F6 /* ../src/entry_point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 360377333740D8A2FD15BBE6 /* ../src/entry_point.cpp */; };
 		DA49ED8903C628BA578C8670 /* ../src/example.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BF9628FC8D38F9748F0CDEB /* ../src/example.cpp */; };
 		C8860D93875589970329DCCD /* ../src/test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4DA100C319512824B7570663 /* ../src/test.cpp */; };
-		1E839D002B2BA83FC83A695A /* ../data/demo in Sources */ = {isa = PBXBuildFile; fileRef = 04FE4D4FB640E0DF92DFB865 /* ../data/demo */; };
-		3A631A475DE035FC53ADE5EA /* ../data/ext in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B12E3C9D554D9FE28101D /* ../data/ext */; };
-		CD59C69314E9E74CD0A11E03 /* ../data/images in Sources */ = {isa = PBXBuildFile; fileRef = F6123B1E6FE4471A00F49751 /* ../data/images */; };
-		EFF139F8BA484314F7AAF645 /* ../data/light_fs.glsl in Sources */ = {isa = PBXBuildFile; fileRef = 5DE458993031811A4C7D28C1 /* ../data/light_fs.glsl */; };
-		F2CFD518E4E2E05ECEDBB262 /* ../data/light_vs.glsl in Sources */ = {isa = PBXBuildFile; fileRef = BA41FC88D76540A6905224D6 /* ../data/light_vs.glsl */; };
-		693088A7AB377368EE4A018E /* ../data/xmls in Sources */ = {isa = PBXBuildFile; fileRef = 2CE4BD5BB9DEF92439C0AB58 /* ../data/xmls */; };
+		1E839D002B2BA83FC83A695A /* ../data/SDL2.lib in Sources */ = {isa = PBXBuildFile; fileRef = 04FE4D4FB640E0DF92DFB865 /* ../data/SDL2.lib */; };
+		3A631A475DE035FC53ADE5EA /* ../data/SDL2main.lib in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B12E3C9D554D9FE28101D /* ../data/SDL2main.lib */; };
+		CD59C69314E9E74CD0A11E03 /* ../data/demo in Sources */ = {isa = PBXBuildFile; fileRef = F6123B1E6FE4471A00F49751 /* ../data/demo */; };
+		EFF139F8BA484314F7AAF645 /* ../data/ext in Sources */ = {isa = PBXBuildFile; fileRef = 5DE458993031811A4C7D28C1 /* ../data/ext */; };
+		F2CFD518E4E2E05ECEDBB262 /* ../data/images in Sources */ = {isa = PBXBuildFile; fileRef = BA41FC88D76540A6905224D6 /* ../data/images */; };
+		693088A7AB377368EE4A018E /* ../data/light_fs.glsl in Sources */ = {isa = PBXBuildFile; fileRef = 2CE4BD5BB9DEF92439C0AB58 /* ../data/light_fs.glsl */; };
+		2B0FCA4EF2CDAB7EF6C6252E /* ../data/light_vs.glsl in Sources */ = {isa = PBXBuildFile; fileRef = F196143B0370A9D348494ACC /* ../data/light_vs.glsl */; };
+		F87DC9641C1B8FCF28948580 /* ../data/xmls in Sources */ = {isa = PBXBuildFile; fileRef = 7746CA7A63049ED8F7D6BF42 /* ../data/xmls */; };
 
 /* End PBXBuildFile section */
 
@@ -84,32 +86,35 @@
 		360377333740D8A2FD15BBE6 /* ../src/entry_point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = entry_point.cpp; path = ../src/entry_point.cpp; sourceTree = "<group>"; };
 		0BF9628FC8D38F9748F0CDEB /* ../src/example.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = example.cpp; path = ../src/example.cpp; sourceTree = "<group>"; };
 		4DA100C319512824B7570663 /* ../src/test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test.cpp; path = ../src/test.cpp; sourceTree = "<group>"; };
-		F196143B0370A9D348494ACC /* ../src/TestBox9Sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestBox9Sprite.h; path = ../src/TestBox9Sprite.h; sourceTree = "<group>"; };
-		7746CA7A63049ED8F7D6BF42 /* ../src/TestClipRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestClipRect.h; path = ../src/TestClipRect.h; sourceTree = "<group>"; };
-		D954BD82D7708B65A08FB6B9 /* ../src/TestDrag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestDrag.h; path = ../src/TestDrag.h; sourceTree = "<group>"; };
-		BD0E956CC3A2F7EB94822B5C /* ../src/TestHttp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestHttp.h; path = ../src/TestHttp.h; sourceTree = "<group>"; };
-		7623D793B59EF0CD569E6EC2 /* ../src/TestInputText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestInputText.h; path = ../src/TestInputText.h; sourceTree = "<group>"; };
-		AFA30E959880563E6ABBBC4F /* ../src/TestManageRes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestManageRes.h; path = ../src/TestManageRes.h; sourceTree = "<group>"; };
-		B52CCD463855CF91A7FBDB8E /* ../src/TestMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestMask.h; path = ../src/TestMask.h; sourceTree = "<group>"; };
-		7EEFDEEC289FCBB5FA67F822 /* ../src/TestPerf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestPerf.h; path = ../src/TestPerf.h; sourceTree = "<group>"; };
-		4E9DE6A8FCBDF43BC876EC90 /* ../src/TestPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestPolygon.h; path = ../src/TestPolygon.h; sourceTree = "<group>"; };
-		8F2AFB956EEAEED67C5B7571 /* ../src/TestProgressBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestProgressBar.h; path = ../src/TestProgressBar.h; sourceTree = "<group>"; };
-		047F6BD19F885FF186A1447C /* ../src/TestRender2Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestRender2Texture.h; path = ../src/TestRender2Texture.h; sourceTree = "<group>"; };
-		C570FAEF487CD34B62389F89 /* ../src/TestSliding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestSliding.h; path = ../src/TestSliding.h; sourceTree = "<group>"; };
-		2418B9A339E6004913AF5980 /* ../src/TestTexel2Pixel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTexel2Pixel.h; path = ../src/TestTexel2Pixel.h; sourceTree = "<group>"; };
-		CAD9D6A98986EA8082368448 /* ../src/TestText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestText.h; path = ../src/TestText.h; sourceTree = "<group>"; };
-		67194AC90FEA68E7C96E6907 /* ../src/TestTextureFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTextureFormat.h; path = ../src/TestTextureFormat.h; sourceTree = "<group>"; };
-		5AFC0664D7BA80AE2A75BF0E /* ../src/TestTweens.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTweens.h; path = ../src/TestTweens.h; sourceTree = "<group>"; };
-		12CAC42FDF06ABE860CFEA53 /* ../src/TestUserShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestUserShader.h; path = ../src/TestUserShader.h; sourceTree = "<group>"; };
-		0F4469FB587862663D529DC9 /* ../src/TestUserShader2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestUserShader2.h; path = ../src/TestUserShader2.h; sourceTree = "<group>"; };
-		B6A9281364AF5D3B581D374C /* ../src/example.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = example.h; path = ../src/example.h; sourceTree = "<group>"; };
-		4013C6794AAE8DFC641D2870 /* ../src/test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test.h; path = ../src/test.h; sourceTree = "<group>"; };
-		04FE4D4FB640E0DF92DFB865 /* ../data/demo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = demo; path = ../data/demo; sourceTree = "<group>"; };
-		7F3B12E3C9D554D9FE28101D /* ../data/ext */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = ext; path = ../data/ext; sourceTree = "<group>"; };
-		F6123B1E6FE4471A00F49751 /* ../data/images */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = images; path = ../data/images; sourceTree = "<group>"; };
-		5DE458993031811A4C7D28C1 /* ../data/light_fs.glsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = light_fs.glsl; path = ../data/light_fs.glsl; sourceTree = "<group>"; };
-		BA41FC88D76540A6905224D6 /* ../data/light_vs.glsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = light_vs.glsl; path = ../data/light_vs.glsl; sourceTree = "<group>"; };
-		2CE4BD5BB9DEF92439C0AB58 /* ../data/xmls */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = xmls; path = ../data/xmls; sourceTree = "<group>"; };
+		D954BD82D7708B65A08FB6B9 /* ../src/TestAlphaHitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestAlphaHitTest.h; path = ../src/TestAlphaHitTest.h; sourceTree = "<group>"; };
+		BD0E956CC3A2F7EB94822B5C /* ../src/TestBox9Sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestBox9Sprite.h; path = ../src/TestBox9Sprite.h; sourceTree = "<group>"; };
+		7623D793B59EF0CD569E6EC2 /* ../src/TestClipRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestClipRect.h; path = ../src/TestClipRect.h; sourceTree = "<group>"; };
+		AFA30E959880563E6ABBBC4F /* ../src/TestDrag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestDrag.h; path = ../src/TestDrag.h; sourceTree = "<group>"; };
+		B52CCD463855CF91A7FBDB8E /* ../src/TestHttp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestHttp.h; path = ../src/TestHttp.h; sourceTree = "<group>"; };
+		7EEFDEEC289FCBB5FA67F822 /* ../src/TestInputText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestInputText.h; path = ../src/TestInputText.h; sourceTree = "<group>"; };
+		4E9DE6A8FCBDF43BC876EC90 /* ../src/TestManageRes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestManageRes.h; path = ../src/TestManageRes.h; sourceTree = "<group>"; };
+		8F2AFB956EEAEED67C5B7571 /* ../src/TestMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestMask.h; path = ../src/TestMask.h; sourceTree = "<group>"; };
+		047F6BD19F885FF186A1447C /* ../src/TestPerf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestPerf.h; path = ../src/TestPerf.h; sourceTree = "<group>"; };
+		C570FAEF487CD34B62389F89 /* ../src/TestPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestPolygon.h; path = ../src/TestPolygon.h; sourceTree = "<group>"; };
+		2418B9A339E6004913AF5980 /* ../src/TestProgressBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestProgressBar.h; path = ../src/TestProgressBar.h; sourceTree = "<group>"; };
+		CAD9D6A98986EA8082368448 /* ../src/TestRender2Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestRender2Texture.h; path = ../src/TestRender2Texture.h; sourceTree = "<group>"; };
+		67194AC90FEA68E7C96E6907 /* ../src/TestSliding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestSliding.h; path = ../src/TestSliding.h; sourceTree = "<group>"; };
+		5AFC0664D7BA80AE2A75BF0E /* ../src/TestTexel2Pixel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTexel2Pixel.h; path = ../src/TestTexel2Pixel.h; sourceTree = "<group>"; };
+		12CAC42FDF06ABE860CFEA53 /* ../src/TestText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestText.h; path = ../src/TestText.h; sourceTree = "<group>"; };
+		0F4469FB587862663D529DC9 /* ../src/TestTextureFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTextureFormat.h; path = ../src/TestTextureFormat.h; sourceTree = "<group>"; };
+		B6A9281364AF5D3B581D374C /* ../src/TestTweens.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTweens.h; path = ../src/TestTweens.h; sourceTree = "<group>"; };
+		4013C6794AAE8DFC641D2870 /* ../src/TestUserShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestUserShader.h; path = ../src/TestUserShader.h; sourceTree = "<group>"; };
+		22E408FD6FCDA6E7E8E76952 /* ../src/TestUserShader2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestUserShader2.h; path = ../src/TestUserShader2.h; sourceTree = "<group>"; };
+		C0253E2158DFD901AD4F8991 /* ../src/example.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = example.h; path = ../src/example.h; sourceTree = "<group>"; };
+		5BE09AD6F31291430F5FB3E0 /* ../src/test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test.h; path = ../src/test.h; sourceTree = "<group>"; };
+		04FE4D4FB640E0DF92DFB865 /* ../data/SDL2.lib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = SDL2.lib; path = ../data/SDL2.lib; sourceTree = "<group>"; };
+		7F3B12E3C9D554D9FE28101D /* ../data/SDL2main.lib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = SDL2main.lib; path = ../data/SDL2main.lib; sourceTree = "<group>"; };
+		F6123B1E6FE4471A00F49751 /* ../data/demo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = demo; path = ../data/demo; sourceTree = "<group>"; };
+		5DE458993031811A4C7D28C1 /* ../data/ext */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = ext; path = ../data/ext; sourceTree = "<group>"; };
+		BA41FC88D76540A6905224D6 /* ../data/images */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = images; path = ../data/images; sourceTree = "<group>"; };
+		2CE4BD5BB9DEF92439C0AB58 /* ../data/light_fs.glsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = light_fs.glsl; path = ../data/light_fs.glsl; sourceTree = "<group>"; };
+		F196143B0370A9D348494ACC /* ../data/light_vs.glsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = light_vs.glsl; path = ../data/light_vs.glsl; sourceTree = "<group>"; };
+		7746CA7A63049ED8F7D6BF42 /* ../data/xmls */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = xmls; path = ../data/xmls; sourceTree = "<group>"; };
 
 /* End PBXFileReference section */
 
@@ -188,12 +193,14 @@
 		04998CF617F8A933003441C3 /* Supporting Files */ = {
 			isa = PBXGroup;
 			children = (
-				04FE4D4FB640E0DF92DFB865 /* demo */, 
-				7F3B12E3C9D554D9FE28101D /* ext */, 
-				F6123B1E6FE4471A00F49751 /* images */, 
-				5DE458993031811A4C7D28C1 /* light_fs.glsl */, 
-				BA41FC88D76540A6905224D6 /* light_vs.glsl */, 
-				2CE4BD5BB9DEF92439C0AB58 /* xmls */, 
+				04FE4D4FB640E0DF92DFB865 /* SDL2.lib */, 
+				7F3B12E3C9D554D9FE28101D /* SDL2main.lib */, 
+				F6123B1E6FE4471A00F49751 /* demo */, 
+				5DE458993031811A4C7D28C1 /* ext */, 
+				BA41FC88D76540A6905224D6 /* images */, 
+				2CE4BD5BB9DEF92439C0AB58 /* light_fs.glsl */, 
+				F196143B0370A9D348494ACC /* light_vs.glsl */, 
+				7746CA7A63049ED8F7D6BF42 /* xmls */, 
 
 			);
 			name = "Supporting Files";
@@ -213,26 +220,27 @@
 				360377333740D8A2FD15BBE6 /* entry_point.cpp */, 
 				0BF9628FC8D38F9748F0CDEB /* example.cpp */, 
 				4DA100C319512824B7570663 /* test.cpp */, 
-				F196143B0370A9D348494ACC /* TestBox9Sprite.h */, 
-				7746CA7A63049ED8F7D6BF42 /* TestClipRect.h */, 
-				D954BD82D7708B65A08FB6B9 /* TestDrag.h */, 
-				BD0E956CC3A2F7EB94822B5C /* TestHttp.h */, 
-				7623D793B59EF0CD569E6EC2 /* TestInputText.h */, 
-				AFA30E959880563E6ABBBC4F /* TestManageRes.h */, 
-				B52CCD463855CF91A7FBDB8E /* TestMask.h */, 
-				7EEFDEEC289FCBB5FA67F822 /* TestPerf.h */, 
-				4E9DE6A8FCBDF43BC876EC90 /* TestPolygon.h */, 
-				8F2AFB956EEAEED67C5B7571 /* TestProgressBar.h */, 
-				047F6BD19F885FF186A1447C /* TestRender2Texture.h */, 
-				C570FAEF487CD34B62389F89 /* TestSliding.h */, 
-				2418B9A339E6004913AF5980 /* TestTexel2Pixel.h */, 
-				CAD9D6A98986EA8082368448 /* TestText.h */, 
-				67194AC90FEA68E7C96E6907 /* TestTextureFormat.h */, 
-				5AFC0664D7BA80AE2A75BF0E /* TestTweens.h */, 
-				12CAC42FDF06ABE860CFEA53 /* TestUserShader.h */, 
-				0F4469FB587862663D529DC9 /* TestUserShader2.h */, 
-				B6A9281364AF5D3B581D374C /* example.h */, 
-				4013C6794AAE8DFC641D2870 /* test.h */, 
+				D954BD82D7708B65A08FB6B9 /* TestAlphaHitTest.h */, 
+				BD0E956CC3A2F7EB94822B5C /* TestBox9Sprite.h */, 
+				7623D793B59EF0CD569E6EC2 /* TestClipRect.h */, 
+				AFA30E959880563E6ABBBC4F /* TestDrag.h */, 
+				B52CCD463855CF91A7FBDB8E /* TestHttp.h */, 
+				7EEFDEEC289FCBB5FA67F822 /* TestInputText.h */, 
+				4E9DE6A8FCBDF43BC876EC90 /* TestManageRes.h */, 
+				8F2AFB956EEAEED67C5B7571 /* TestMask.h */, 
+				047F6BD19F885FF186A1447C /* TestPerf.h */, 
+				C570FAEF487CD34B62389F89 /* TestPolygon.h */, 
+				2418B9A339E6004913AF5980 /* TestProgressBar.h */, 
+				CAD9D6A98986EA8082368448 /* TestRender2Texture.h */, 
+				67194AC90FEA68E7C96E6907 /* TestSliding.h */, 
+				5AFC0664D7BA80AE2A75BF0E /* TestTexel2Pixel.h */, 
+				12CAC42FDF06ABE860CFEA53 /* TestText.h */, 
+				0F4469FB587862663D529DC9 /* TestTextureFormat.h */, 
+				B6A9281364AF5D3B581D374C /* TestTweens.h */, 
+				4013C6794AAE8DFC641D2870 /* TestUserShader.h */, 
+				22E408FD6FCDA6E7E8E76952 /* TestUserShader2.h */, 
+				C0253E2158DFD901AD4F8991 /* example.h */, 
+				5BE09AD6F31291430F5FB3E0 /* test.h */, 
 
 			);
 			name = src;
@@ -328,12 +336,14 @@
 			buildActionMask = 2147483647;
 			files = (
 				04E9AD3F1876FE84006A7317 /* Images.xcassets in Resources */,
-				1E839D002B2BA83FC83A695A /* demo */, 
-				3A631A475DE035FC53ADE5EA /* ext */, 
-				CD59C69314E9E74CD0A11E03 /* images */, 
-				EFF139F8BA484314F7AAF645 /* light_fs.glsl */, 
-				F2CFD518E4E2E05ECEDBB262 /* light_vs.glsl */, 
-				693088A7AB377368EE4A018E /* xmls */, 
+				1E839D002B2BA83FC83A695A /* SDL2.lib */, 
+				3A631A475DE035FC53ADE5EA /* SDL2main.lib */, 
+				CD59C69314E9E74CD0A11E03 /* demo */, 
+				EFF139F8BA484314F7AAF645 /* ext */, 
+				F2CFD518E4E2E05ECEDBB262 /* images */, 
+				693088A7AB377368EE4A018E /* light_fs.glsl */, 
+				2B0FCA4EF2CDAB7EF6C6252E /* light_vs.glsl */, 
+				F87DC9641C1B8FCF28948580 /* xmls */, 
 
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 74 - 64
examples/Demo/proj.macosx/demo_macosx.xcodeproj/project.pbxproj

@@ -18,12 +18,14 @@
 		2DC477AC10D6C07B3FE008F6 /* ../src/entry_point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 360377333740D8A2FD15BBE6 /* ../src/entry_point.cpp */; };
 		DA49ED8903C628BA578C8670 /* ../src/example.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BF9628FC8D38F9748F0CDEB /* ../src/example.cpp */; };
 		C8860D93875589970329DCCD /* ../src/test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4DA100C319512824B7570663 /* ../src/test.cpp */; };
-		1E839D002B2BA83FC83A695A /* ../data/demo in Sources */ = {isa = PBXBuildFile; fileRef = 04FE4D4FB640E0DF92DFB865 /* ../data/demo */; };
-		3A631A475DE035FC53ADE5EA /* ../data/ext in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B12E3C9D554D9FE28101D /* ../data/ext */; };
-		CD59C69314E9E74CD0A11E03 /* ../data/images in Sources */ = {isa = PBXBuildFile; fileRef = F6123B1E6FE4471A00F49751 /* ../data/images */; };
-		EFF139F8BA484314F7AAF645 /* ../data/light_fs.glsl in Sources */ = {isa = PBXBuildFile; fileRef = 5DE458993031811A4C7D28C1 /* ../data/light_fs.glsl */; };
-		F2CFD518E4E2E05ECEDBB262 /* ../data/light_vs.glsl in Sources */ = {isa = PBXBuildFile; fileRef = BA41FC88D76540A6905224D6 /* ../data/light_vs.glsl */; };
-		693088A7AB377368EE4A018E /* ../data/xmls in Sources */ = {isa = PBXBuildFile; fileRef = 2CE4BD5BB9DEF92439C0AB58 /* ../data/xmls */; };
+		1E839D002B2BA83FC83A695A /* ../data/SDL2.lib in Sources */ = {isa = PBXBuildFile; fileRef = 04FE4D4FB640E0DF92DFB865 /* ../data/SDL2.lib */; };
+		3A631A475DE035FC53ADE5EA /* ../data/SDL2main.lib in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B12E3C9D554D9FE28101D /* ../data/SDL2main.lib */; };
+		CD59C69314E9E74CD0A11E03 /* ../data/demo in Sources */ = {isa = PBXBuildFile; fileRef = F6123B1E6FE4471A00F49751 /* ../data/demo */; };
+		EFF139F8BA484314F7AAF645 /* ../data/ext in Sources */ = {isa = PBXBuildFile; fileRef = 5DE458993031811A4C7D28C1 /* ../data/ext */; };
+		F2CFD518E4E2E05ECEDBB262 /* ../data/images in Sources */ = {isa = PBXBuildFile; fileRef = BA41FC88D76540A6905224D6 /* ../data/images */; };
+		693088A7AB377368EE4A018E /* ../data/light_fs.glsl in Sources */ = {isa = PBXBuildFile; fileRef = 2CE4BD5BB9DEF92439C0AB58 /* ../data/light_fs.glsl */; };
+		2B0FCA4EF2CDAB7EF6C6252E /* ../data/light_vs.glsl in Sources */ = {isa = PBXBuildFile; fileRef = F196143B0370A9D348494ACC /* ../data/light_vs.glsl */; };
+		F87DC9641C1B8FCF28948580 /* ../data/xmls in Sources */ = {isa = PBXBuildFile; fileRef = 7746CA7A63049ED8F7D6BF42 /* ../data/xmls */; };
 
 		
 /* End PBXBuildFile section */
@@ -98,32 +100,35 @@
 		360377333740D8A2FD15BBE6 /* ../src/entry_point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = entry_point.cpp; path = ../src/entry_point.cpp; sourceTree = "<group>"; };
 		0BF9628FC8D38F9748F0CDEB /* ../src/example.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = example.cpp; path = ../src/example.cpp; sourceTree = "<group>"; };
 		4DA100C319512824B7570663 /* ../src/test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test.cpp; path = ../src/test.cpp; sourceTree = "<group>"; };
-		F196143B0370A9D348494ACC /* ../src/TestBox9Sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestBox9Sprite.h; path = ../src/TestBox9Sprite.h; sourceTree = "<group>"; };
-		7746CA7A63049ED8F7D6BF42 /* ../src/TestClipRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestClipRect.h; path = ../src/TestClipRect.h; sourceTree = "<group>"; };
-		D954BD82D7708B65A08FB6B9 /* ../src/TestDrag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestDrag.h; path = ../src/TestDrag.h; sourceTree = "<group>"; };
-		BD0E956CC3A2F7EB94822B5C /* ../src/TestHttp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestHttp.h; path = ../src/TestHttp.h; sourceTree = "<group>"; };
-		7623D793B59EF0CD569E6EC2 /* ../src/TestInputText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestInputText.h; path = ../src/TestInputText.h; sourceTree = "<group>"; };
-		AFA30E959880563E6ABBBC4F /* ../src/TestManageRes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestManageRes.h; path = ../src/TestManageRes.h; sourceTree = "<group>"; };
-		B52CCD463855CF91A7FBDB8E /* ../src/TestMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestMask.h; path = ../src/TestMask.h; sourceTree = "<group>"; };
-		7EEFDEEC289FCBB5FA67F822 /* ../src/TestPerf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestPerf.h; path = ../src/TestPerf.h; sourceTree = "<group>"; };
-		4E9DE6A8FCBDF43BC876EC90 /* ../src/TestPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestPolygon.h; path = ../src/TestPolygon.h; sourceTree = "<group>"; };
-		8F2AFB956EEAEED67C5B7571 /* ../src/TestProgressBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestProgressBar.h; path = ../src/TestProgressBar.h; sourceTree = "<group>"; };
-		047F6BD19F885FF186A1447C /* ../src/TestRender2Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestRender2Texture.h; path = ../src/TestRender2Texture.h; sourceTree = "<group>"; };
-		C570FAEF487CD34B62389F89 /* ../src/TestSliding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestSliding.h; path = ../src/TestSliding.h; sourceTree = "<group>"; };
-		2418B9A339E6004913AF5980 /* ../src/TestTexel2Pixel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTexel2Pixel.h; path = ../src/TestTexel2Pixel.h; sourceTree = "<group>"; };
-		CAD9D6A98986EA8082368448 /* ../src/TestText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestText.h; path = ../src/TestText.h; sourceTree = "<group>"; };
-		67194AC90FEA68E7C96E6907 /* ../src/TestTextureFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTextureFormat.h; path = ../src/TestTextureFormat.h; sourceTree = "<group>"; };
-		5AFC0664D7BA80AE2A75BF0E /* ../src/TestTweens.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTweens.h; path = ../src/TestTweens.h; sourceTree = "<group>"; };
-		12CAC42FDF06ABE860CFEA53 /* ../src/TestUserShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestUserShader.h; path = ../src/TestUserShader.h; sourceTree = "<group>"; };
-		0F4469FB587862663D529DC9 /* ../src/TestUserShader2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestUserShader2.h; path = ../src/TestUserShader2.h; sourceTree = "<group>"; };
-		B6A9281364AF5D3B581D374C /* ../src/example.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = example.h; path = ../src/example.h; sourceTree = "<group>"; };
-		4013C6794AAE8DFC641D2870 /* ../src/test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test.h; path = ../src/test.h; sourceTree = "<group>"; };
-		04FE4D4FB640E0DF92DFB865 /* ../data/demo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = demo; path = ../data/demo; sourceTree = "<group>"; };
-		7F3B12E3C9D554D9FE28101D /* ../data/ext */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = ext; path = ../data/ext; sourceTree = "<group>"; };
-		F6123B1E6FE4471A00F49751 /* ../data/images */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = images; path = ../data/images; sourceTree = "<group>"; };
-		5DE458993031811A4C7D28C1 /* ../data/light_fs.glsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = light_fs.glsl; path = ../data/light_fs.glsl; sourceTree = "<group>"; };
-		BA41FC88D76540A6905224D6 /* ../data/light_vs.glsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = light_vs.glsl; path = ../data/light_vs.glsl; sourceTree = "<group>"; };
-		2CE4BD5BB9DEF92439C0AB58 /* ../data/xmls */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = xmls; path = ../data/xmls; sourceTree = "<group>"; };
+		D954BD82D7708B65A08FB6B9 /* ../src/TestAlphaHitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestAlphaHitTest.h; path = ../src/TestAlphaHitTest.h; sourceTree = "<group>"; };
+		BD0E956CC3A2F7EB94822B5C /* ../src/TestBox9Sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestBox9Sprite.h; path = ../src/TestBox9Sprite.h; sourceTree = "<group>"; };
+		7623D793B59EF0CD569E6EC2 /* ../src/TestClipRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestClipRect.h; path = ../src/TestClipRect.h; sourceTree = "<group>"; };
+		AFA30E959880563E6ABBBC4F /* ../src/TestDrag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestDrag.h; path = ../src/TestDrag.h; sourceTree = "<group>"; };
+		B52CCD463855CF91A7FBDB8E /* ../src/TestHttp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestHttp.h; path = ../src/TestHttp.h; sourceTree = "<group>"; };
+		7EEFDEEC289FCBB5FA67F822 /* ../src/TestInputText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestInputText.h; path = ../src/TestInputText.h; sourceTree = "<group>"; };
+		4E9DE6A8FCBDF43BC876EC90 /* ../src/TestManageRes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestManageRes.h; path = ../src/TestManageRes.h; sourceTree = "<group>"; };
+		8F2AFB956EEAEED67C5B7571 /* ../src/TestMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestMask.h; path = ../src/TestMask.h; sourceTree = "<group>"; };
+		047F6BD19F885FF186A1447C /* ../src/TestPerf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestPerf.h; path = ../src/TestPerf.h; sourceTree = "<group>"; };
+		C570FAEF487CD34B62389F89 /* ../src/TestPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestPolygon.h; path = ../src/TestPolygon.h; sourceTree = "<group>"; };
+		2418B9A339E6004913AF5980 /* ../src/TestProgressBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestProgressBar.h; path = ../src/TestProgressBar.h; sourceTree = "<group>"; };
+		CAD9D6A98986EA8082368448 /* ../src/TestRender2Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestRender2Texture.h; path = ../src/TestRender2Texture.h; sourceTree = "<group>"; };
+		67194AC90FEA68E7C96E6907 /* ../src/TestSliding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestSliding.h; path = ../src/TestSliding.h; sourceTree = "<group>"; };
+		5AFC0664D7BA80AE2A75BF0E /* ../src/TestTexel2Pixel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTexel2Pixel.h; path = ../src/TestTexel2Pixel.h; sourceTree = "<group>"; };
+		12CAC42FDF06ABE860CFEA53 /* ../src/TestText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestText.h; path = ../src/TestText.h; sourceTree = "<group>"; };
+		0F4469FB587862663D529DC9 /* ../src/TestTextureFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTextureFormat.h; path = ../src/TestTextureFormat.h; sourceTree = "<group>"; };
+		B6A9281364AF5D3B581D374C /* ../src/TestTweens.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestTweens.h; path = ../src/TestTweens.h; sourceTree = "<group>"; };
+		4013C6794AAE8DFC641D2870 /* ../src/TestUserShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestUserShader.h; path = ../src/TestUserShader.h; sourceTree = "<group>"; };
+		22E408FD6FCDA6E7E8E76952 /* ../src/TestUserShader2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestUserShader2.h; path = ../src/TestUserShader2.h; sourceTree = "<group>"; };
+		C0253E2158DFD901AD4F8991 /* ../src/example.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = example.h; path = ../src/example.h; sourceTree = "<group>"; };
+		5BE09AD6F31291430F5FB3E0 /* ../src/test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test.h; path = ../src/test.h; sourceTree = "<group>"; };
+		04FE4D4FB640E0DF92DFB865 /* ../data/SDL2.lib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = SDL2.lib; path = ../data/SDL2.lib; sourceTree = "<group>"; };
+		7F3B12E3C9D554D9FE28101D /* ../data/SDL2main.lib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = SDL2main.lib; path = ../data/SDL2main.lib; sourceTree = "<group>"; };
+		F6123B1E6FE4471A00F49751 /* ../data/demo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = demo; path = ../data/demo; sourceTree = "<group>"; };
+		5DE458993031811A4C7D28C1 /* ../data/ext */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = ext; path = ../data/ext; sourceTree = "<group>"; };
+		BA41FC88D76540A6905224D6 /* ../data/images */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = images; path = ../data/images; sourceTree = "<group>"; };
+		2CE4BD5BB9DEF92439C0AB58 /* ../data/light_fs.glsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = light_fs.glsl; path = ../data/light_fs.glsl; sourceTree = "<group>"; };
+		F196143B0370A9D348494ACC /* ../data/light_vs.glsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wtf; name = light_vs.glsl; path = ../data/light_vs.glsl; sourceTree = "<group>"; };
+		7746CA7A63049ED8F7D6BF42 /* ../data/xmls */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = xmls; path = ../data/xmls; sourceTree = "<group>"; };
 
 		04A57D761871FFEB0068B1E5 /* oxygine_macosx.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = oxygine_macosx.xcodeproj; path = ../../..//oxygine/SDL/macosx/oxygine_macosx/oxygine_macosx.xcodeproj; sourceTree = "<group>"; };
 		04A57D7E1872012A0068B1E5 /* SDL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL.xcodeproj; path = ../../../..//SDL/Xcode/SDL/SDL.xcodeproj; sourceTree = "<group>"; };
@@ -212,12 +217,14 @@
 		049B57381871FBE900EF3C66 /* Supporting Files */ = {
 			isa = PBXGroup;
 			children = (
-				04FE4D4FB640E0DF92DFB865 /* demo */, 
-				7F3B12E3C9D554D9FE28101D /* ext */, 
-				F6123B1E6FE4471A00F49751 /* images */, 
-				5DE458993031811A4C7D28C1 /* light_fs.glsl */, 
-				BA41FC88D76540A6905224D6 /* light_vs.glsl */, 
-				2CE4BD5BB9DEF92439C0AB58 /* xmls */, 
+				04FE4D4FB640E0DF92DFB865 /* SDL2.lib */, 
+				7F3B12E3C9D554D9FE28101D /* SDL2main.lib */, 
+				F6123B1E6FE4471A00F49751 /* demo */, 
+				5DE458993031811A4C7D28C1 /* ext */, 
+				BA41FC88D76540A6905224D6 /* images */, 
+				2CE4BD5BB9DEF92439C0AB58 /* light_fs.glsl */, 
+				F196143B0370A9D348494ACC /* light_vs.glsl */, 
+				7746CA7A63049ED8F7D6BF42 /* xmls */, 
 
 				049B57391871FBE900EF3C66 /* Demo_macosx-Info.plist */,
 			);
@@ -230,26 +237,27 @@
 				360377333740D8A2FD15BBE6 /* entry_point.cpp */, 
 				0BF9628FC8D38F9748F0CDEB /* example.cpp */, 
 				4DA100C319512824B7570663 /* test.cpp */, 
-				F196143B0370A9D348494ACC /* TestBox9Sprite.h */, 
-				7746CA7A63049ED8F7D6BF42 /* TestClipRect.h */, 
-				D954BD82D7708B65A08FB6B9 /* TestDrag.h */, 
-				BD0E956CC3A2F7EB94822B5C /* TestHttp.h */, 
-				7623D793B59EF0CD569E6EC2 /* TestInputText.h */, 
-				AFA30E959880563E6ABBBC4F /* TestManageRes.h */, 
-				B52CCD463855CF91A7FBDB8E /* TestMask.h */, 
-				7EEFDEEC289FCBB5FA67F822 /* TestPerf.h */, 
-				4E9DE6A8FCBDF43BC876EC90 /* TestPolygon.h */, 
-				8F2AFB956EEAEED67C5B7571 /* TestProgressBar.h */, 
-				047F6BD19F885FF186A1447C /* TestRender2Texture.h */, 
-				C570FAEF487CD34B62389F89 /* TestSliding.h */, 
-				2418B9A339E6004913AF5980 /* TestTexel2Pixel.h */, 
-				CAD9D6A98986EA8082368448 /* TestText.h */, 
-				67194AC90FEA68E7C96E6907 /* TestTextureFormat.h */, 
-				5AFC0664D7BA80AE2A75BF0E /* TestTweens.h */, 
-				12CAC42FDF06ABE860CFEA53 /* TestUserShader.h */, 
-				0F4469FB587862663D529DC9 /* TestUserShader2.h */, 
-				B6A9281364AF5D3B581D374C /* example.h */, 
-				4013C6794AAE8DFC641D2870 /* test.h */, 
+				D954BD82D7708B65A08FB6B9 /* TestAlphaHitTest.h */, 
+				BD0E956CC3A2F7EB94822B5C /* TestBox9Sprite.h */, 
+				7623D793B59EF0CD569E6EC2 /* TestClipRect.h */, 
+				AFA30E959880563E6ABBBC4F /* TestDrag.h */, 
+				B52CCD463855CF91A7FBDB8E /* TestHttp.h */, 
+				7EEFDEEC289FCBB5FA67F822 /* TestInputText.h */, 
+				4E9DE6A8FCBDF43BC876EC90 /* TestManageRes.h */, 
+				8F2AFB956EEAEED67C5B7571 /* TestMask.h */, 
+				047F6BD19F885FF186A1447C /* TestPerf.h */, 
+				C570FAEF487CD34B62389F89 /* TestPolygon.h */, 
+				2418B9A339E6004913AF5980 /* TestProgressBar.h */, 
+				CAD9D6A98986EA8082368448 /* TestRender2Texture.h */, 
+				67194AC90FEA68E7C96E6907 /* TestSliding.h */, 
+				5AFC0664D7BA80AE2A75BF0E /* TestTexel2Pixel.h */, 
+				12CAC42FDF06ABE860CFEA53 /* TestText.h */, 
+				0F4469FB587862663D529DC9 /* TestTextureFormat.h */, 
+				B6A9281364AF5D3B581D374C /* TestTweens.h */, 
+				4013C6794AAE8DFC641D2870 /* TestUserShader.h */, 
+				22E408FD6FCDA6E7E8E76952 /* TestUserShader2.h */, 
+				C0253E2158DFD901AD4F8991 /* example.h */, 
+				5BE09AD6F31291430F5FB3E0 /* test.h */, 
 
 			);
 			name = src;
@@ -368,12 +376,14 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				1E839D002B2BA83FC83A695A /* demo */, 
-				3A631A475DE035FC53ADE5EA /* ext */, 
-				CD59C69314E9E74CD0A11E03 /* images */, 
-				EFF139F8BA484314F7AAF645 /* light_fs.glsl */, 
-				F2CFD518E4E2E05ECEDBB262 /* light_vs.glsl */, 
-				693088A7AB377368EE4A018E /* xmls */, 
+				1E839D002B2BA83FC83A695A /* SDL2.lib */, 
+				3A631A475DE035FC53ADE5EA /* SDL2main.lib */, 
+				CD59C69314E9E74CD0A11E03 /* demo */, 
+				EFF139F8BA484314F7AAF645 /* ext */, 
+				F2CFD518E4E2E05ECEDBB262 /* images */, 
+				693088A7AB377368EE4A018E /* light_fs.glsl */, 
+				2B0FCA4EF2CDAB7EF6C6252E /* light_vs.glsl */, 
+				F87DC9641C1B8FCF28948580 /* xmls */, 
 
 				049B574A1871FBE900EF3C66 /* Images.xcassets in Resources */,
 			);

+ 1 - 1
examples/Demo/proj.win32/Demo_vs2010.vcxproj

@@ -91,7 +91,7 @@
     <ClCompile Include="../src/entry_point.cpp" /><ClCompile Include="../src/example.cpp" /><ClCompile Include="../src/test.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="../src/TestBox9Sprite.h" /><ClInclude Include="../src/TestClipRect.h" /><ClInclude Include="../src/TestDrag.h" /><ClInclude Include="../src/TestHttp.h" /><ClInclude Include="../src/TestInputText.h" /><ClInclude Include="../src/TestManageRes.h" /><ClInclude Include="../src/TestMask.h" /><ClInclude Include="../src/TestPerf.h" /><ClInclude Include="../src/TestPolygon.h" /><ClInclude Include="../src/TestProgressBar.h" /><ClInclude Include="../src/TestRender2Texture.h" /><ClInclude Include="../src/TestSliding.h" /><ClInclude Include="../src/TestTexel2Pixel.h" /><ClInclude Include="../src/TestText.h" /><ClInclude Include="../src/TestTextureFormat.h" /><ClInclude Include="../src/TestTweens.h" /><ClInclude Include="../src/TestUserShader.h" /><ClInclude Include="../src/TestUserShader2.h" /><ClInclude Include="../src/example.h" /><ClInclude Include="../src/test.h" />
+    <ClInclude Include="../src/TestAlphaHitTest.h" /><ClInclude Include="../src/TestBox9Sprite.h" /><ClInclude Include="../src/TestClipRect.h" /><ClInclude Include="../src/TestDrag.h" /><ClInclude Include="../src/TestHttp.h" /><ClInclude Include="../src/TestInputText.h" /><ClInclude Include="../src/TestManageRes.h" /><ClInclude Include="../src/TestMask.h" /><ClInclude Include="../src/TestPerf.h" /><ClInclude Include="../src/TestPolygon.h" /><ClInclude Include="../src/TestProgressBar.h" /><ClInclude Include="../src/TestRender2Texture.h" /><ClInclude Include="../src/TestSliding.h" /><ClInclude Include="../src/TestTexel2Pixel.h" /><ClInclude Include="../src/TestText.h" /><ClInclude Include="../src/TestTextureFormat.h" /><ClInclude Include="../src/TestTweens.h" /><ClInclude Include="../src/TestUserShader.h" /><ClInclude Include="../src/TestUserShader2.h" /><ClInclude Include="../src/example.h" /><ClInclude Include="../src/test.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 1 - 1
examples/Demo/proj.win32/Demo_vs2013.vcxproj

@@ -93,7 +93,7 @@
     <ClCompile Include="../src/entry_point.cpp" /><ClCompile Include="../src/example.cpp" /><ClCompile Include="../src/test.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="../src/TestBox9Sprite.h" /><ClInclude Include="../src/TestClipRect.h" /><ClInclude Include="../src/TestDrag.h" /><ClInclude Include="../src/TestHttp.h" /><ClInclude Include="../src/TestInputText.h" /><ClInclude Include="../src/TestManageRes.h" /><ClInclude Include="../src/TestMask.h" /><ClInclude Include="../src/TestPerf.h" /><ClInclude Include="../src/TestPolygon.h" /><ClInclude Include="../src/TestProgressBar.h" /><ClInclude Include="../src/TestRender2Texture.h" /><ClInclude Include="../src/TestSliding.h" /><ClInclude Include="../src/TestTexel2Pixel.h" /><ClInclude Include="../src/TestText.h" /><ClInclude Include="../src/TestTextureFormat.h" /><ClInclude Include="../src/TestTweens.h" /><ClInclude Include="../src/TestUserShader.h" /><ClInclude Include="../src/TestUserShader2.h" /><ClInclude Include="../src/example.h" /><ClInclude Include="../src/test.h" />
+    <ClInclude Include="../src/TestAlphaHitTest.h" /><ClInclude Include="../src/TestBox9Sprite.h" /><ClInclude Include="../src/TestClipRect.h" /><ClInclude Include="../src/TestDrag.h" /><ClInclude Include="../src/TestHttp.h" /><ClInclude Include="../src/TestInputText.h" /><ClInclude Include="../src/TestManageRes.h" /><ClInclude Include="../src/TestMask.h" /><ClInclude Include="../src/TestPerf.h" /><ClInclude Include="../src/TestPolygon.h" /><ClInclude Include="../src/TestProgressBar.h" /><ClInclude Include="../src/TestRender2Texture.h" /><ClInclude Include="../src/TestSliding.h" /><ClInclude Include="../src/TestTexel2Pixel.h" /><ClInclude Include="../src/TestText.h" /><ClInclude Include="../src/TestTextureFormat.h" /><ClInclude Include="../src/TestTweens.h" /><ClInclude Include="../src/TestUserShader.h" /><ClInclude Include="../src/TestUserShader2.h" /><ClInclude Include="../src/example.h" /><ClInclude Include="../src/test.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 55 - 0
examples/Demo/src/TestAlphaHitTest.h

@@ -0,0 +1,55 @@
+#pragma once
+#include "test.h"
+#include "initActor.h"
+
+#undef OUT
+
+class TestAlphaHitTest : public Test
+{
+public:
+    spSprite sprite;
+    spTextField txt;
+
+    TestAlphaHitTest()
+    {
+        /*
+        'flower' resource has hit_test option enabled. check res.xml
+        <set hit_test = "true" / >
+        <image file = "flower.png" / >
+
+        'hit_test' enables access to alpha channel
+        */
+
+        sprite = initActor(new Sprite,
+                           arg_resAnim = resources.getResAnim("flower"),
+                           arg_attachTo = content,
+                           arg_anchor = Vector2(0.5f, 0.5f),
+                           arg_x = content->getWidth() / 2,
+                           arg_y = content->getHeight() / 2);
+
+        sprite->addEventListener(TouchEvent::OVER, CLOSURE(this, &TestAlphaHitTest::onEvent));
+        sprite->addEventListener(TouchEvent::OUT, CLOSURE(this, &TestAlphaHitTest::onEvent));
+
+        txt = new TextField;
+        txt->attachTo(content);
+        txt->setVAlign(TextStyle::VALIGN_BOTTOM);
+        txt->setHAlign(TextStyle::HALIGN_MIDDLE);
+        txt->setX(getWidth() / 2);
+        txt->setY(getHeight() - 10);
+        txt->setText("Move mouse over Sprite");
+    }
+
+    void onEvent(Event* ev)
+    {
+        if (ev->type == TouchEvent::OVER)
+        {
+            txt->setText("Mouse is OVER");
+            sprite->setColor(Color::Green);
+        }
+        else
+        {
+            txt->setText("Mouse is OUT");
+            sprite->setColor(Color::White);
+        }
+    }
+};

+ 2 - 2
examples/Demo/src/TestDrag.h

@@ -55,7 +55,7 @@ public:
     spSprite basket;
     spSprite ball;
     spSprite dragging;
-    spTextActor txt;
+    spTextField txt;
 
     timeMS timeLeft;
     const PointerState* touchedBy;
@@ -83,7 +83,7 @@ public:
         ball->addEventListener(TouchEvent::TOUCH_UP, CLOSURE(this,  &Drag2Test::ballTouchUp));
         content->addEventListener(TouchEvent::TOUCH_UP, CLOSURE(this, &Drag2Test::touchUp));
 
-        txt = new TextActor;
+        txt = new TextField;
         txt->attachTo(content);
         txt->setVAlign(TextStyle::VALIGN_MIDDLE);
         txt->setHAlign(TextStyle::HALIGN_MIDDLE);

+ 6 - 0
examples/Demo/src/example.cpp

@@ -19,6 +19,7 @@
 #include "TestPolygon.h"
 #include "TestInputText.h"
 #include "TestHttp.h"
+#include "TestAlphaHitTest.h"
 #include "core/STDFileSystem.h"
 
 #ifdef __S3E__
@@ -56,6 +57,7 @@ public:
         addButton("progress_bar", "Progress Bar");
         addButton("drag", "Drag and Drop");
         addButton("drag2", "Drag and Drop2");
+        addButton("hittest", "Alpha Hit Test");
         addButton("perf", "Performance");
         addButton("manage_res", "Manage Resources");
         addButton("texture_format", "Textures Format");
@@ -102,6 +104,10 @@ public:
         {
             showTest(new Drag2Test);
         }
+        if (id == "hittest")
+        {
+            showTest(new TestAlphaHitTest);
+        }
         if (id == "manage_res")
         {
             showTest(new ManageResTest);

+ 17 - 2
examples/HelloWorld/src/example.cpp

@@ -21,7 +21,11 @@ public:
 
         //setup it:
         //set button.png image. Resource 'button' defined in 'res.xml'
-        button->setResAnim(gameResources.getResAnim("button"));
+        button->setResAnim(gameResources.getResAnim("anim"));
+        //button->setScale(3);
+        //button->setRotation(1);
+        button->setAnchor(Vector2(0.5, 0.5f));
+        //button->addTween(TweenAnim(gameResources.getResAnim("anim")), 5000, -1);
 
         //centered button at screen
         Vector2 pos = getStage()->getSize() / 2 - button->getSize() / 2;
@@ -38,6 +42,17 @@ public:
             log::messageln("button clicked");
         });
 
+
+        button->addEventListener(TouchEvent::OVER, [ = ](Event * e)->void
+        {
+            button->setColor(Color::Red);
+        });
+
+        button->addEventListener(TouchEvent::OUT, [ = ](Event * e)->void
+        {
+            button->setColor(Color::White);
+        });
+
 #endif
 
         //attach button as child to current actor
@@ -51,7 +66,7 @@ public:
         //create TextField Actor
         spTextField text = new TextField();
         //attach it as child to button
-        text->attachTo(button);
+        //text->attachTo(button);
         //centered in button
         text->setPosition(button->getSize() / 2);
 

+ 8 - 2
oxygine/SDL/ios/oxygine/oxygine_ios.xcodeproj/project.pbxproj

@@ -78,6 +78,8 @@
 		92CE26631A589401003901D6 /* ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92CE26611A589401003901D6 /* ios.mm */; };
 		92DC0A251A2F0ED900D2B55C /* greenlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 92DC0A231A2F0ED900D2B55C /* greenlet.c */; };
 		92DC0A261A2F0ED900D2B55C /* greenlet.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DC0A241A2F0ED900D2B55C /* greenlet.h */; };
+		92E0C9A01B2491C200F0DB21 /* cdecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 92E0C99E1B2491C200F0DB21 /* cdecode.c */; };
+		92E0C9A11B2491C200F0DB21 /* cdecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92E0C99F1B2491C200F0DB21 /* cdecode.h */; };
 		C38704A617C0C71700015CA8 /* VideoDriverGLES20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C38704A417C0C71700015CA8 /* VideoDriverGLES20.cpp */; };
 		C38704A717C0C71700015CA8 /* VideoDriverGLES20.h in Headers */ = {isa = PBXBuildFile; fileRef = C38704A517C0C71700015CA8 /* VideoDriverGLES20.h */; };
 		C38EC22C1709600E00568283 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C38EC22B1709600E00568283 /* OpenGLES.framework */; };
@@ -301,6 +303,8 @@
 		92CE26611A589401003901D6 /* ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios.mm; path = ../../../src/core/ios/ios.mm; sourceTree = "<group>"; };
 		92DC0A231A2F0ED900D2B55C /* greenlet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = greenlet.c; path = ../../../greenlets/src/greenlet.c; sourceTree = "<group>"; };
 		92DC0A241A2F0ED900D2B55C /* greenlet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = greenlet.h; path = ../../../greenlets/src/greenlet.h; sourceTree = "<group>"; };
+		92E0C99E1B2491C200F0DB21 /* cdecode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cdecode.c; sourceTree = "<group>"; };
+		92E0C99F1B2491C200F0DB21 /* cdecode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cdecode.h; sourceTree = "<group>"; };
 		C38704A417C0C71700015CA8 /* VideoDriverGLES20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VideoDriverGLES20.cpp; path = gl/VideoDriverGLES20.cpp; sourceTree = "<group>"; };
 		C38704A517C0C71700015CA8 /* VideoDriverGLES20.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VideoDriverGLES20.h; path = gl/VideoDriverGLES20.h; sourceTree = "<group>"; };
 		C38EC22B1709600E00568283 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
@@ -431,7 +435,6 @@
 		C3E86FDD16EBC8EB00052915 /* TextStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextStyle.h; path = ../../../src/TextStyle.h; sourceTree = "<group>"; };
 		C3E86FEA16EBC8EB00052915 /* Tweener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Tweener.h; path = ../../../src/Tweener.h; sourceTree = "<group>"; };
 		C3E86FEB16EBC8EB00052915 /* UpdateState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdateState.h; path = ../../../src/UpdateState.h; sourceTree = "<group>"; };
-		C3E86FED16EBC8EB00052915 /* .oxbuild */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .oxbuild; sourceTree = "<group>"; };
 		C3E86FEE16EBC8EB00052915 /* AtlasTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AtlasTool.cpp; sourceTree = "<group>"; };
 		C3E86FEF16EBC8EB00052915 /* AtlasTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AtlasTool.h; sourceTree = "<group>"; };
 		C3E86FF016EBC8EB00052915 /* ImageUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageUtils.cpp; sourceTree = "<group>"; };
@@ -787,7 +790,8 @@
 		C3E86FEC16EBC8EB00052915 /* utils */ = {
 			isa = PBXGroup;
 			children = (
-				C3E86FED16EBC8EB00052915 /* .oxbuild */,
+				92E0C99E1B2491C200F0DB21 /* cdecode.c */,
+				92E0C99F1B2491C200F0DB21 /* cdecode.h */,
 				C3E86FEE16EBC8EB00052915 /* AtlasTool.cpp */,
 				C3E86FEF16EBC8EB00052915 /* AtlasTool.h */,
 				C3E86FF016EBC8EB00052915 /* ImageUtils.cpp */,
@@ -911,6 +915,7 @@
 				04AEC314182BD98D006413A9 /* UberShaderProgram.h in Headers */,
 				C3E8705716EBC8EB00052915 /* pugiconfig.hpp in Headers */,
 				C3E8705916EBC8EB00052915 /* pugixml.hpp in Headers */,
+				92E0C9A11B2491C200F0DB21 /* cdecode.h in Headers */,
 				C3E8705A16EBC8EB00052915 /* RenderState.h in Headers */,
 				C3E8705B16EBC8EB00052915 /* CreateResourceContext.h in Headers */,
 				C3E8705D16EBC8EB00052915 /* ResAnim.h in Headers */,
@@ -1099,6 +1104,7 @@
 				9240B4091ADFB856005F9C5B /* TweenAnim.cpp in Sources */,
 				C38EC2711709649300568283 /* TexturesInspector.cpp in Sources */,
 				C38EC2731709649300568283 /* TreeInspector.cpp in Sources */,
+				92E0C9A01B2491C200F0DB21 /* cdecode.c in Sources */,
 				0467086E192796E500D71824 /* Serialize.cpp in Sources */,
 				C38EC2751709649300568283 /* TreeInspectorLine.cpp in Sources */,
 				C38EC2771709649300568283 /* TreeInspectorPage.cpp in Sources */,

+ 8 - 2
oxygine/SDL/macosx/oxygine_macosx/oxygine_macosx.xcodeproj/project.pbxproj

@@ -222,6 +222,8 @@
 		92CE267E1A58ABDC003901D6 /* Property.h in Headers */ = {isa = PBXBuildFile; fileRef = 92CE26761A58ABDC003901D6 /* Property.h */; };
 		92CE267F1A58ABDC003901D6 /* WebImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 92CE26771A58ABDC003901D6 /* WebImage.cpp */; };
 		92CE26801A58ABDC003901D6 /* WebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 92CE26781A58ABDC003901D6 /* WebImage.h */; };
+		92E0C9A61B24922600F0DB21 /* cdecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 92E0C9A41B24922600F0DB21 /* cdecode.c */; };
+		92E0C9A71B24922600F0DB21 /* cdecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92E0C9A51B24922600F0DB21 /* cdecode.h */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -402,7 +404,6 @@
 		049B564F1871F21E00EF3C66 /* TextStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextStyle.h; path = ../../../src/TextStyle.h; sourceTree = "<group>"; };
 		049B56511871F21E00EF3C66 /* Tweener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Tweener.h; path = ../../../src/Tweener.h; sourceTree = "<group>"; };
 		049B56521871F21E00EF3C66 /* UpdateState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdateState.h; path = ../../../src/UpdateState.h; sourceTree = "<group>"; };
-		049B56541871F21E00EF3C66 /* .oxbuild */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .oxbuild; sourceTree = "<group>"; };
 		049B56551871F21E00EF3C66 /* AtlasTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AtlasTool.cpp; sourceTree = "<group>"; };
 		049B56561871F21E00EF3C66 /* AtlasTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AtlasTool.h; sourceTree = "<group>"; };
 		049B56571871F21E00EF3C66 /* ImageUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageUtils.cpp; sourceTree = "<group>"; };
@@ -448,6 +449,8 @@
 		92CE26761A58ABDC003901D6 /* Property.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Property.h; path = ../../../src/Property.h; sourceTree = "<group>"; };
 		92CE26771A58ABDC003901D6 /* WebImage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebImage.cpp; path = ../../../src/WebImage.cpp; sourceTree = "<group>"; };
 		92CE26781A58ABDC003901D6 /* WebImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebImage.h; path = ../../../src/WebImage.h; sourceTree = "<group>"; };
+		92E0C9A41B24922600F0DB21 /* cdecode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cdecode.c; sourceTree = "<group>"; };
+		92E0C9A51B24922600F0DB21 /* cdecode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cdecode.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -775,7 +778,8 @@
 		049B56531871F21E00EF3C66 /* utils */ = {
 			isa = PBXGroup;
 			children = (
-				049B56541871F21E00EF3C66 /* .oxbuild */,
+				92E0C9A41B24922600F0DB21 /* cdecode.c */,
+				92E0C9A51B24922600F0DB21 /* cdecode.h */,
 				049B56551871F21E00EF3C66 /* AtlasTool.cpp */,
 				049B56561871F21E00EF3C66 /* AtlasTool.h */,
 				049B56571871F21E00EF3C66 /* ImageUtils.cpp */,
@@ -862,6 +866,7 @@
 				049B569B1871F21E00EF3C66 /* NativeTexture.h in Headers */,
 				049B56F61871F21E00EF3C66 /* ResAnim.h in Headers */,
 				049B570C1871F21E00EF3C66 /* Aligner.h in Headers */,
+				92E0C9A71B24922600F0DB21 /* cdecode.h in Headers */,
 				92CE266D1A58AADB003901D6 /* ios.h in Headers */,
 				049B56F21871F21E00EF3C66 /* RenderState.h in Headers */,
 				049B56EE1871F21E00EF3C66 /* ProgressBar.h in Headers */,
@@ -1014,6 +1019,7 @@
 				049B566D1871F21E00EF3C66 /* Button.cpp in Sources */,
 				049B57011871F21E00EF3C66 /* Resources.cpp in Sources */,
 				049B56DF1871F21E00EF3C66 /* MemoryTexture.cpp in Sources */,
+				92E0C9A61B24922600F0DB21 /* cdecode.c in Sources */,
 				049B56ED1871F21E00EF3C66 /* ProgressBar.cpp in Sources */,
 				049B56A31871F21E00EF3C66 /* Renderer.cpp in Sources */,
 				04B3A71F18A6594D004C67E3 /* InputText.cpp in Sources */,

+ 2 - 0
oxygine/SDL/win32/oxygine_vs2010.vcxproj

@@ -173,6 +173,7 @@
     <ClCompile Include="..\..\src\Tween.cpp" />
     <ClCompile Include="..\..\src\TweenAnim.cpp" />
     <ClCompile Include="..\..\src\TweenQueue.cpp" />
+    <ClCompile Include="..\..\src\utils\cdecode.c" />
     <ClCompile Include="..\..\src\utils\stringUtils.cpp" />
     <ClCompile Include="..\..\src\math\AffineTransform.cpp" />
     <ClCompile Include="..\..\src\pugixml\pugixml.cpp" />
@@ -286,6 +287,7 @@
     <ClInclude Include="..\..\src\Tweener.h" />
     <ClInclude Include="..\..\src\TweenQueue.h" />
     <ClInclude Include="..\..\src\UpdateState.h" />
+    <ClInclude Include="..\..\src\utils\cdecode.h" />
     <ClInclude Include="..\..\src\utils\stringUtils.h" />
     <ClInclude Include="..\..\src\closure\closure.h" />
     <ClInclude Include="..\..\src\closure\closure_impl.h" />

+ 6 - 0
oxygine/SDL/win32/oxygine_vs2010.vcxproj.filters

@@ -321,6 +321,9 @@
     <ClCompile Include="..\..\src\TweenAnim.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\utils\cdecode.c">
+      <Filter>src\utils</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\src\closure\closure.h">
@@ -695,6 +698,9 @@
     <ClInclude Include="..\..\src\TweenAnim.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\utils\cdecode.h">
+      <Filter>src\utils</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="ReadMe.txt" />

+ 2 - 0
oxygine/SDL/win32/oxygine_vs2013.vcxproj

@@ -175,6 +175,7 @@
     <ClCompile Include="..\..\src\Tween.cpp" />
     <ClCompile Include="..\..\src\TweenAnim.cpp" />
     <ClCompile Include="..\..\src\TweenQueue.cpp" />
+    <ClCompile Include="..\..\src\utils\cdecode.c" />
     <ClCompile Include="..\..\src\utils\stringUtils.cpp" />
     <ClCompile Include="..\..\src\math\AffineTransform.cpp" />
     <ClCompile Include="..\..\src\pugixml\pugixml.cpp" />
@@ -288,6 +289,7 @@
     <ClInclude Include="..\..\src\Tweener.h" />
     <ClInclude Include="..\..\src\TweenQueue.h" />
     <ClInclude Include="..\..\src\UpdateState.h" />
+    <ClInclude Include="..\..\src\utils\cdecode.h" />
     <ClInclude Include="..\..\src\utils\stringUtils.h" />
     <ClInclude Include="..\..\src\closure\closure.h" />
     <ClInclude Include="..\..\src\closure\closure_impl.h" />

+ 6 - 0
oxygine/SDL/win32/oxygine_vs2013.vcxproj.filters

@@ -321,6 +321,9 @@
     <ClCompile Include="..\..\src\TweenAnim.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\utils\cdecode.c">
+      <Filter>src\utils</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\src\closure\closure.h">
@@ -695,6 +698,9 @@
     <ClInclude Include="..\..\src\TweenAnim.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\utils\cdecode.h">
+      <Filter>src\utils</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="ReadMe.txt" />

+ 1 - 0
oxygine/marmalade/oxygine-framework.mkf

@@ -46,6 +46,7 @@ files
 	(../src/utils)
 	"*.h"
 	"*.cpp"	
+	"*.c"	
 	
 	[src/math]
 	(../src/math)

+ 15 - 3
oxygine/src/AnimationFrame.h

@@ -18,11 +18,21 @@ namespace oxygine
         bool premultiplied;
     };
 
+    class HitTestData
+    {
+    public:
+        HitTestData(): data(0), w(0), h(0), pitch(0) {}
+
+        const unsigned char* data;
+        short w, h;
+        unsigned char pitch;
+    };
+
     class ResAnim;
     class AnimationFrame
     {
     public:
-        AnimationFrame(): _srcRect(0, 0, 1, 1), _destRect(0, 0, 1, 1), _frameSize(0, 0), _resAnim(0), _row(0), _column(0) {}
+        AnimationFrame() : _srcRect(0, 0, 1, 1), _destRect(0, 0, 1, 1), _frameSize(0, 0), _resAnim(0), _row(0), _column(0) {}
 
         void init(ResAnim* rs, const Diffuse& df,
                   const RectF& srcRect, const RectF& destRect, const Vector2& frame_size);
@@ -36,8 +46,6 @@ namespace oxygine
         const Vector2&  getSize() const {return _frameSize;}
         float           getWidth() const {return _frameSize.x;}
         float           getHeight() const {return _frameSize.y;}
-        //deprecated, use getSize
-        const Vector2&  getFrameSize() const {return _frameSize;}
 
         ResAnim*        getResAnim() const {return _resAnim;}
         short           getColumn() const {return _column;}
@@ -45,12 +53,14 @@ namespace oxygine
         const RectF&    getSrcRect() const {return _srcRect;}
         const RectF&    getDestRect() const {return _destRect;}
         const Diffuse&  getDiffuse() const {return _diffuse;}
+        const HitTestData& getHitTestData()const { return _hittest; }
 
         void            setSrcRect(const RectF& r) {_srcRect = r;}
         void            setDestRect(const RectF& r) {_destRect = r;}
         void            setResAnim(ResAnim* rs) {_resAnim = rs;}
         void            setDiffuse(const Diffuse& d) { _diffuse = d; }
         void            setSize(const Vector2& size) {_frameSize = size;}
+        void            setHitTestData(const HitTestData& ad) { _hittest = ad; }
 
 
     private:
@@ -67,6 +77,8 @@ namespace oxygine
         ResAnim*        _resAnim;
         short           _row;
         short           _column;
+
+        HitTestData       _hittest;
         //unsigned short    _flags;
     };
 }

+ 2 - 2
oxygine/src/Box9Sprite.cpp

@@ -123,8 +123,8 @@ namespace oxygine
         _pointsX.clear();
         _pointsY.clear();
 
-        float fFrameWidth = (float)_frame.getFrameSize().x;
-        float fFrameHeight = (float)_frame.getFrameSize().y;
+        float fFrameWidth = _frame.getWidth();
+        float fFrameHeight = _frame.getHeight();
 
         /*
         float fActorWidth = max((float)getSize().x, fFrameWidth);

+ 2 - 2
oxygine/src/ProgressBar.cpp

@@ -92,7 +92,7 @@ namespace oxygine
                 break;
         }
 
-        Vector2 newSize = _originalFrame.getFrameSize() * _progress;
+        Vector2 newSize = _originalFrame.getSize() * _progress;
         _frame.init(_frame.getResAnim(), _frame.getDiffuse(), newSrc, newDest, newSize);
         //_vstyle._material.srcRect = newSrc;
     }
@@ -338,7 +338,7 @@ namespace oxygine
 
     RectF ProgressBar::getDestRect() const
     {
-        return calcDestRectF(_frame.getDestRect(), _frame.getFrameSize());
+        return calcDestRectF(_frame.getDestRect(), _frame.getSize());
     }
 
     void ProgressBar::setProgress(float f)

+ 32 - 2
oxygine/src/Sprite.cpp

@@ -77,6 +77,36 @@ namespace oxygine
 
     }
 
+
+    extern int HIT_TEST_DOWNSCALE;
+
+    bool Sprite::isOn(const Vector2& localPosition)
+    {
+        if (!Actor::isOn(localPosition))
+            return false;
+
+        const HitTestData& ad = _frame.getHitTestData();
+        if (!ad.data)
+            return true;
+
+        const int BITS = (sizeof(int32_t) * 8);
+
+        const unsigned char* buff = ad.data;
+        Vector2 pos = localPosition * _frame.getResAnim()->getAppliedScale();
+        Point lp = pos.cast<Point>() / HIT_TEST_DOWNSCALE;
+        Rect r(0, 0, ad.w, ad.h);
+        if (r.pointIn(lp))
+        {
+            const int32_t* ints = reinterpret_cast<const int32_t*>(buff + lp.y * ad.pitch);
+
+            int n = lp.x / BITS;
+            int b = lp.x % BITS;
+
+            return (ints[n] >> b) & 1;
+        }
+        return false;
+    }
+
     void Sprite::setColumn(int column, int row)
     {
         const ResAnim* rs = getResAnim();
@@ -126,7 +156,7 @@ namespace oxygine
         }
 
         _frame = frame;
-        setSize(_frame.getFrameSize());
+        setSize(_frame.getSize());
 
         animFrameChanged(_frame);
     }
@@ -139,7 +169,7 @@ namespace oxygine
     RectF Sprite::getDestRect() const
     {
         if (_frame.getDiffuse().base)
-            return calcDestRectF(_frame.getDestRect(), _frame.getFrameSize());
+            return calcDestRectF(_frame.getDestRect(), _frame.getSize());
 
         return Actor::getDestRect();
     }

+ 2 - 0
oxygine/src/Sprite.h

@@ -40,6 +40,8 @@ namespace oxygine
         void                    setRow(int row, int column = -1);
         void                    setColumn(int column, int row = -1);
 
+        bool                    isOn(const Vector2& localPosition);
+
         void serialize(serializedata* data);
         void deserialize(const deserializedata* data);
 

+ 1 - 1
oxygine/src/core/Mem2Native.cpp

@@ -103,7 +103,7 @@ namespace oxygine
         //update only one texture per frame
         if (_prev == Point(0, 0))
         {
-            ThreadMessages::message ev;
+            ThreadMessages::peekMessage ev;
             while (_messages.peek(ev, true))
             {
                 MemoryTexture* src = (MemoryTexture*)ev.arg1;

+ 25 - 2
oxygine/src/core/ThreadMessages.cpp

@@ -1,5 +1,6 @@
 #include "ThreadMessages.h"
 #include "log.h"
+#include "pthread.h"
 namespace oxygine
 {
 #if 0
@@ -117,20 +118,27 @@ namespace oxygine
         _events.clear();
     }
 
-    bool ThreadMessages::peek(message& ev, bool del)
+    bool ThreadMessages::peek(peekMessage& ev, bool del)
     {
+        if (ev.end)
+            return false;
+
         bool has = false;
 
         MutexPthreadLock lock(_mutex);
         _replyLast(0);
 
+
         if (!_events.empty())
         {
-            ev = _events.front();
+            static_cast<message&>(ev) = _events.front();
             if (del)
                 _events.erase(_events.begin());
             has = true;
             _last = ev;
+
+            if (_events.empty())
+                ev.end = true;
         }
 
         return has;
@@ -245,6 +253,21 @@ namespace oxygine
         pthread_cond_signal(&_cond);
     }
 
+    void ThreadMessages::removeCallback(int msgid, callback cb, void* cbData)
+    {
+        MutexPthreadLock lock(_mutex);
+        for (messages::iterator i = _events.begin(); i != _events.end(); ++i)
+        {
+            message& m = *i;
+            if (m.cb == cb && m.cbData == cbData && m.msgid == msgid)
+            {
+                _events.erase(i);
+                break;
+            }
+        }
+
+    }
+
 #ifndef __S3E__
     void ThreadMessages::postCallback(const std::function<void()>& f)
     {

+ 16 - 2
oxygine/src/core/ThreadMessages.h

@@ -1,9 +1,15 @@
 #pragma once
 #include "oxygine_include.h"
 #include <vector>
-#include "pthread.h"
 #include <functional>
 
+#if defined(_WIN32) && !defined(__MINGW32__)
+typedef struct pthread_mutex_t_* pthread_mutex_t;
+typedef struct pthread_cond_t_* pthread_cond_t;
+#else
+#   include "pthread.h"
+#endif
+
 namespace oxygine
 {
     class MutexPthreadLock
@@ -42,6 +48,12 @@ namespace oxygine
             bool    _replied;
         };
 
+        struct peekMessage: public message
+        {
+            peekMessage() : end(false) {}
+            bool end;
+        };
+
 
         ThreadMessages();
         ~ThreadMessages();
@@ -51,12 +63,14 @@ namespace oxygine
 
         void wait();
         void get(message& ev);
-        bool peek(message& ev, bool del);
+        bool peek(peekMessage& ev, bool del);
         void clear();
 
         void* send(int msgid, void* arg1, void* arg2);
         void post(int msgid, void* arg1, void* arg2);
         void postCallback(int msgid, void* arg1, void* arg2, callback cb, void* cbData);
+        void removeCallback(int msgid, callback cb, void* cbData);
+
 #ifndef __S3E__
         void postCallback(const std::function<void()>&);
 #endif

+ 2 - 2
oxygine/src/core/curl/HttpRequestCurlTask.cpp

@@ -2,7 +2,7 @@
 #include "core/oxygine.h"
 #include "core/ThreadMessages.h"
 #include "SDL.h"
-
+#include "pthread.h"
 
 namespace oxygine
 {
@@ -81,7 +81,7 @@ namespace oxygine
                 static int i = 0;
                 //log::messageln("upd---------%d - %d", getTimeMS(), ++i);
 
-                ThreadMessages::message tmsg;
+                ThreadMessages::peekMessage tmsg;
                 if (_messages.peek(tmsg, true))
                 {
                     curl_multi_add_handle(multi_handle, (CURL*)tmsg.arg1);

+ 11 - 11
oxygine/src/core/gl/ShaderProgramGL.cpp

@@ -3,7 +3,7 @@
 #include "oxgl.h"
 
 #ifndef __S3E__
-	#include "SDL.h"
+#include "SDL.h"
 #endif
 
 namespace oxygine
@@ -71,7 +71,7 @@ namespace oxygine
 
 
 #ifndef __S3E__
-#	ifndef EMSCRIPTEN
+#   ifndef EMSCRIPTEN
         int profile = 0;
         SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile);
 
@@ -81,21 +81,21 @@ namespace oxygine
         else
         {
 
-			log::messageln("not gles version");
+            log::messageln("not gles version");
 
-			static const char nonGLES[] =
-				"#define lowp\n"
-				"#define mediump\n"
-				"#define highp\n";
+            static const char nonGLES[] =
+                "#define lowp\n"
+                "#define mediump\n"
+                "#define highp\n";
 
-			*ptr = nonGLES;
-			ptr++;
+            *ptr = nonGLES;
+            ptr++;
 
         }
 
-#	else
+#   else
         *ptr = "precision float mediump;";
-#	endif
+#   endif
 #endif
 
 

+ 8 - 6
oxygine/src/core/oxygine.cpp

@@ -224,7 +224,7 @@ namespace oxygine
 
         void updateUIMessages()
         {
-            ThreadMessages::message msg;
+            ThreadMessages::peekMessage msg;
             while (_uiMessages.peek(msg, true)) {}
         }
 
@@ -323,11 +323,12 @@ namespace oxygine
 
 #if TARGET_OS_IPHONE
             flags |= SDL_WINDOW_BORDERLESS;
+            flags |= SDL_WINDOW_ALLOW_HIGHDPI;
 #endif
 
-            SDL_DisplayMode mode;
-            SDL_GetCurrentDisplayMode(0, &mode);
-            log::messageln("display mode: %d %d", mode.w, mode.h);
+            //SDL_DisplayMode mode;
+            //SDL_GetCurrentDisplayMode(0, &mode);
+            //log::messageln("display mode: %d %d", mode.w, mode.h);
 
             if (desc.w == -1 && desc.h == -1)
             {
@@ -639,7 +640,7 @@ namespace oxygine
 
         bool update()
         {
-            ThreadMessages::message msg;
+            ThreadMessages::peekMessage msg;
             while (_threadMessages.peek(msg, true)) {}
 
 #ifdef __S3E__
@@ -767,7 +768,8 @@ namespace oxygine
 #elif OXYGINE_SDL
             int w = 0;
             int h = 0;
-            SDL_GetWindowSize(_window, &w, &h);
+
+            SDL_GL_GetDrawableSize(_window, &w, &h);
             return Point(w, h);
 #elif EMSCRIPTEN
             return _displaySize;

+ 16 - 3
oxygine/src/res/CreateResourceContext.cpp

@@ -4,16 +4,25 @@
 
 namespace oxygine
 {
-    XmlWalker::XmlWalker(const std::string* xmlFolder, const std::string& path, float scaleFactor, bool load, pugi::xml_node xml, pugi::xml_node meta) : _rootMeta(meta),
+    XmlWalker::XmlWalker(
+        const std::string* xmlFolder,
+        const std::string& path,
+        float scaleFactor,
+        bool load,
+        bool alpha,
+        pugi::xml_node xml, pugi::xml_node meta) :
+
+        _rootMeta(meta),
         _root(xml),
         _notStarted(true),
         _notStartedMeta(true),
         _scaleFactor(scaleFactor),
         _load(load),
+        _alphaHitTest(alpha),
         _xmlFolder(xmlFolder),
         _path(path)
     {
-
+        //_alphaTracking = true;
     }
 
     std::string XmlWalker::connectPath(const char* currentPath, const char* str)
@@ -77,7 +86,7 @@ namespace oxygine
             break;
         }
 
-        return XmlWalker(_xmlFolder, _path, _scaleFactor, _load, _last, _lastMeta);
+        return XmlWalker(_xmlFolder, _path, _scaleFactor, _load, _alphaHitTest, _last, _lastMeta);
     }
 
     void XmlWalker::_checkSetAttributes(pugi::xml_node node)
@@ -99,6 +108,10 @@ namespace oxygine
             {
                 _scaleFactor = attr.as_float(1.0f);
             }
+            else if (!strcmp(attr.name(), "hit_test"))
+            {
+                _alphaHitTest = attr.as_bool(false);
+            }
 
             attr = attr.next_attribute();
         }

+ 4 - 2
oxygine/src/res/CreateResourceContext.h

@@ -14,7 +14,7 @@ namespace oxygine
     class XmlWalker
     {
     public:
-        XmlWalker(const std::string* xmlFolder, const std::string& path, float scaleFactor, bool load, pugi::xml_node xml, pugi::xml_node meta);
+        XmlWalker(const std::string* xmlFolder, const std::string& path, float scaleFactor, bool load, bool alpha, pugi::xml_node xml, pugi::xml_node meta);
 
         bool empty() const {return _root.empty();}
 
@@ -25,6 +25,7 @@ namespace oxygine
         pugi::xml_node      getMeta() const {return _rootMeta;}
         float               getScaleFactor() const {return _scaleFactor;}
         bool                getLoad() const {return _load;}
+        bool                getAlphaHitTest() const { return _alphaHitTest; }
         const char*         getType() const {return _root.name();}
 
         void            checkSetAttributes();
@@ -51,13 +52,14 @@ namespace oxygine
 
         float _scaleFactor;
         bool _load;
+        bool _alphaHitTest;
     };
 
     class CreateResourceContext//todo rename
     {
     public:
         CreateResourceContext(): resources(0), xml_name(0), prebuilt_folder(0),
-            walker(0, "", 1.0f, true, pugi::xml_node(), pugi::xml_node())
+            walker(0, "", 1.0f, true, false, pugi::xml_node(), pugi::xml_node())
         {
 
         }

+ 3 - 2
oxygine/src/res/ResAnim.cpp

@@ -6,7 +6,7 @@
 namespace oxygine
 {
     static AnimationFrame emptyFrame;
-    ResAnim::ResAnim(Resource* atlas): _columns(1), _atlas(atlas), _scaleFactor(1.0f)
+    ResAnim::ResAnim(Resource* atlas) : _columns(1), _atlas(atlas), _scaleFactor(1.0f), _appliedScale(1.0f)
     {
     }
 
@@ -76,11 +76,12 @@ namespace oxygine
         init(texture, original->getSize(), columns, rows, scaleFactor);
     }
 
-    void ResAnim::init(animationFrames& frames, int columns, float scaleFactor)
+    void ResAnim::init(animationFrames& frames, int columns, float scaleFactor, float appliedScale)
     {
         _columns = columns;
         _frames.swap(frames);
         _scaleFactor = scaleFactor;
+        _appliedScale = appliedScale;
     }
 
     void ResAnim::_load(LoadResourcesContext* c)

+ 6 - 4
oxygine/src/res/ResAnim.h

@@ -21,7 +21,7 @@ namespace oxygine
         ~ResAnim();
 
         void init(MemoryTexture* original, int columns = 1, int rows = 1, float scaleFactor = 1.0f);
-        void init(animationFrames& frames, int columns, float scaleFactor = 1.0f);
+        void init(animationFrames& frames, int columns, float scaleFactor = 1.0f, float appliedScale = 1.0f);
         /**creates animation frames from NativeTexture*/
         void init(spNativeTexture texture, const Point& originalSize, int columns, int rows, float scaleFactor);
 
@@ -29,6 +29,7 @@ namespace oxygine
         //void addFrame(const AnimationFrame &frame);
 
         float                   getScaleFactor() const {return _scaleFactor;}
+        float                   getAppliedScale() const { return _appliedScale; }
         int                     getColumns() const {return _columns;}
         int                     getRows() const {return (int)_frames.size() / _columns;}
         int                     getTotalFrames() const {return (int)_frames.size();}
@@ -51,9 +52,10 @@ namespace oxygine
         void _load(LoadResourcesContext* ctx = 0);
         void _unload();
 
-        int _columns;
-        Resource* _atlas;
-        float _scaleFactor;
+        int         _columns;
+        Resource*   _atlas;
+        float       _scaleFactor;
+        float       _appliedScale;
 
         animationFrames _frames;
     };

+ 549 - 309
oxygine/src/res/ResAtlas.cpp

@@ -11,6 +11,12 @@
 #include "core/Mem2Native.h"
 #include "core/VideoDriver.h"
 #include "core/Renderer.h"
+#include <stdint.h>
+
+extern "C"
+{
+#include "utils/cdecode.h"
+}
 
 #ifdef __S3E__
 #include "IwImage.h"
@@ -37,7 +43,6 @@ namespace oxygine
         if (!ad.texture)
             return;
 
-
         MemoryTexture mt;
         const Rect& bounds = ad.atlas.getBounds();
         int w = nextPOT(bounds.getWidth());
@@ -71,6 +76,43 @@ namespace oxygine
         //ad.texture->init(ad.mt.getWidth(), ad.mt.getHeight(), ad.mt.getFormat());
     }
 
+
+    static load_texture_hook _hook = 0;
+    void set_load_texture_hook(load_texture_hook hook)
+    {
+        _hook = hook;
+    }
+
+    void load_texture_internal(const std::string& file, spNativeTexture nt, LoadResourcesContext* load_context)
+    {
+        ImageData im;
+        spMemoryTexture mt = new MemoryTexture;
+
+        LOGD("loading atlas: %s", file.c_str());
+        file::buffer bf;
+        file::read(file.c_str(), bf);
+        LOGD("atlas file loaded: %s", file.c_str());
+        mt->init(bf, Renderer::getPremultipliedAlphaRender(), nt->getFormat());
+        //mt->init(2048, 2048, TF_R8G8B8A8);
+        im = mt->lock();
+        LOGD("atlas size: %d %d", im.w, im.h);
+
+        //Object::dumpCreatedObjects();
+        load_context->createTexture(mt, nt);
+    }
+
+    void load_texture(const std::string& file, spNativeTexture nt, LoadResourcesContext* load_context)
+    {
+        if (_hook)
+        {
+            _hook(file, nt, load_context);
+            return;
+        }
+
+        load_texture_internal(file, nt, load_context);
+    }
+
+
     void ResAtlas::init_resAnim(ResAnim* rs, const std::string& file, pugi::xml_node node)
     {
         rs->setName(_Resource::extractID(node, file, ""));
@@ -96,57 +138,261 @@ namespace oxygine
         _atlasses.push_back(atl);
     }
 
-    void ResAtlas::loadAtlas(CreateResourceContext& context)
+    Resource* ResAtlas::create(CreateResourceContext& context)
     {
-        //string path = context.walker.getCurrentFolder();
+        context.walker.checkSetAttributes();
+        ResAtlas* ra = 0;
+        if (context.walker.getMeta())
+        {
+            ResAtlasPrebuilt* rs = new ResAtlasPrebuilt(context);
 
-        pugi::xml_node node = context.walker.getNode();
-        pugi::xml_node meta = context.walker.getMeta();
+            ra = rs;
+        }
+        else
+        {
+            ResAtlasGeneric* rs = new ResAtlasGeneric();
+            rs->loadAtlas(context);
 
-        int w = node.attribute("width").as_int(defaultAtlasWidth);
-        int h = node.attribute("height").as_int(defaultAtlasHeight);
-        const char* format = node.attribute("format").as_string("8888");
+            ra = rs;
+        }
 
-        _linearFilter = node.attribute("linearFilter").as_bool(true);
-        _clamp2edge = node.attribute("clamp2edge").as_bool(true);
+        ra->setName(_Resource::extractID(context.walker.getNode(), "", std::string("!atlas:") + *context.xml_name));
+        setNode(ra, context.walker.getNode());
 
-        atlas_data ad;
+        return ra;
+    }
 
+    ResAtlas::ResAtlas()//: _linearFilter(true), _clamp2edge(true)
+    {
 
-        TextureFormat tf = string2TextureFormat(format);
+    }
 
-        pugi::xml_node meta_image = meta.child("atlas");
+    ResAtlas::~ResAtlas()
+    {
+        for (atlasses::iterator i = _atlasses.begin(); i != _atlasses.end(); ++i)
+        {
+            atlas& atl = *i;
+            if (atl.base)
+                atl.base->release();
+            if (atl.alpha)
+                atl.alpha->release();
+        }
+    }
 
-        bool compressed = false;
+    void ResAtlas::_restore(Restorable* r, void*)
+    {
+        NativeTexture* texture = (NativeTexture*)r->_getRestorableObject();
 
-        while (meta_image)
+        for (atlasses::iterator i = _atlasses.begin(); i != _atlasses.end(); ++i)
         {
-            const char* file = meta_image.attribute("file").value();
+            atlas& atl = *i;
+            if (atl.base.get() == texture)
+            {
+                load_texture(atl.base_path, atl.base, &RestoreResourcesContext::instance);
+                atl.base->reg(CLOSURE(this, &ResAtlas::_restore), 0);
+                break;
+            }
 
-            int w = meta_image.attribute("w").as_int();
-            int h = meta_image.attribute("h").as_int();
+            if (atl.alpha.get() == texture)
+            {
+                load_texture(atl.alpha_path, atl.alpha, &RestoreResourcesContext::instance);
+                atl.alpha->reg(CLOSURE(this, &ResAtlas::_restore), 0);
+                break;
+            }
+        }
+    }
 
-            const char* file_format = meta_image.attribute("format").as_string(0);
-            TextureFormat ffmt = TF_UNDEFINED;
-            if (file_format)
+    void ResAtlas::_load(LoadResourcesContext* load_context)
+    {
+        for (atlasses::iterator i = _atlasses.begin(); i != _atlasses.end(); ++i)
+        {
+            atlas& atl = *i;
+            if (!load_context->isNeedProceed(atl.base))
+                continue;
+
+            load_texture(atl.base_path, atl.base, load_context);
+            atl.base->reg(CLOSURE(this, &ResAtlas::_restore), 0);
+
+            if (atl.alpha)
             {
-                ffmt = string2TextureFormat(file_format);
-                compressed = isCompressedFormat(ffmt);
+                load_texture(atl.alpha_path, atl.alpha, load_context);
+                atl.alpha->reg(CLOSURE(this, &ResAtlas::_restore), 0);
             }
+        }
+    }
 
-            std::string alpha_file = meta_image.attribute("alpha").as_string("");
-            if (!alpha_file.empty())
+    void ResAtlas::_unload()
+    {
+        for (atlasses::iterator i = _atlasses.begin(); i != _atlasses.end(); ++i)
+        {
+            atlas& atl = *i;
+            if (atl.base)
+                atl.base->release();
+
+            if (atl.alpha)
+                atl.alpha->release();
+        }
+    }
+
+    ResAnim* ResAtlas::createEmpty(const XmlWalker& walker, CreateResourceContext& context)
+    {
+        ResAnim* ra = new ResAnim(this);
+        ra->init(0, 0, 0, walker.getScaleFactor());
+        init_resAnim(ra, "", walker.getNode());
+        ra->setParent(this);
+        context.resources->add(ra);
+
+        return ra;
+    }
+
+
+    int roundUp(int numToRound, int multiple)
+    {
+        if (multiple == 0)
+            return numToRound;
+
+        int remainder = numToRound % multiple;
+        if (remainder == 0)
+            return numToRound;
+        return numToRound + multiple - remainder;
+    }
+
+
+    int HIT_TEST_DOWNSCALE = 4;
+    const int ALIGN = sizeof(int32_t);
+    const int BITS = ALIGN * 8;
+
+    void makeAlpha(const ImageData& srcImage, Rect& bounds, std::vector<unsigned char>& alpha, HitTestData& adata, bool hittest)
+    {
+        int w = srcImage.w;
+        int h = srcImage.h;
+
+        size_t pos = alpha.size();
+        adata.data = reinterpret_cast<unsigned char*>(pos);
+        adata.w = roundUp(w, HIT_TEST_DOWNSCALE) / HIT_TEST_DOWNSCALE;
+        adata.h = roundUp(h, HIT_TEST_DOWNSCALE) / HIT_TEST_DOWNSCALE;
+
+
+        int lineInts = roundUp(adata.w, BITS) / BITS;
+
+        int destPitch = lineInts * ALIGN;
+
+        int size = adata.h * destPitch;
+
+        alpha.resize(pos + size);
+
+
+        const unsigned char* srcData = srcImage.data;
+        int srcStep = srcImage.bytespp;
+        int srcPitch = srcImage.pitch;
+
+        unsigned char* destData = &alpha[pos];
+
+        adata.pitch = destPitch;
+
+        const unsigned char* srcRow = srcData;
+        unsigned char* destRow = destData;
+
+
+        int minX = w;
+        int minY = h;
+        int maxX = 0;
+        int maxY = 0;
+
+        bool hasAlpha = false;
+
+        for (int y = 0; y != h; y += 1)
+        {
+            const unsigned char* srcLine = srcRow;
+            int32_t* destLine = reinterpret_cast<int32_t*>(destRow);
+
+            bool lineWithAlpha = false;
+
+
+            for (int x = 0; x != w; x += 1)
             {
-                alpha_file = *context.prebuilt_folder + alpha_file;
+                PixelR8G8B8A8 pd;
+                Pixel p;
+                pd.getPixel(srcLine, p);
+
+
+                if (p.a > 10)
+                {
+                    hasAlpha = true;
+
+                    int dx = x / HIT_TEST_DOWNSCALE;
+                    int n = dx / BITS;
+                    int b = dx % BITS;
+
+                    destLine[n] |= 1 << b;
+
+                    lineWithAlpha = true;
+                    if (x > maxX)
+                        maxX = x;
+                    else if (x < minX)
+                        minX = x;
+                }
+                srcLine += srcStep;
             }
 
-            addAtlas(tf, *context.prebuilt_folder + file, alpha_file, w, h);
+            if (lineWithAlpha)
+            {
+                if (minY == h)
+                    minY = y;
+                maxY = y;
+            }
 
-            meta_image = meta_image.next_sibling("atlas");
-            context.walker.nextMeta();
+            if (y % HIT_TEST_DOWNSCALE == HIT_TEST_DOWNSCALE - 1)
+            {
+                //reset line
+                destRow += destPitch;
+            }
+
+            srcRow += srcPitch;
         }
 
-        //
+        //if image is transparent
+        if (minX == w && maxX == 0)
+        {
+            minX = 0;
+            maxX = 0;
+        }
+
+        if (minY == h && maxY == 0)
+        {
+            minY = 0;
+            maxY = 0;
+        }
+
+        bounds = Rect(minX, minY, maxX - minX + 1, maxY - minY + 1);
+
+        if (!hasAlpha || !hittest)
+        {
+            alpha.resize(pos);
+            adata = HitTestData();
+        }
+    }
+
+
+    void ResAtlasGeneric::loadAtlas(CreateResourceContext& context)
+    {
+        pugi::xml_node node = context.walker.getNode();
+
+        int w = node.attribute("width").as_int(defaultAtlasWidth);
+        int h = node.attribute("height").as_int(defaultAtlasHeight);
+        const char* format = node.attribute("format").as_string("8888");
+
+        //_linearFilter = node.attribute("linearFilter").as_bool(true);
+        //_clamp2edge = node.attribute("clamp2edge").as_bool(true);
+
+        atlas_data ad;
+
+
+        TextureFormat tf = string2TextureFormat(format);
+
+
+        bool compressed = false;
+
 
         std::vector<ResAnim*> anims;
 
@@ -158,234 +404,141 @@ namespace oxygine
                 break;
 
             pugi::xml_node child_node = walker.getNode();
-            pugi::xml_node meta_frames = walker.getMeta();
 
             const char* name = child_node.name();
-            if (!strcmp(name, "image"))
+            if (strcmp(name, "image"))
+                continue;
+
+
+            std::string id = child_node.attribute("id").value();
+            std::string file = child_node.attribute("file").value();
+
+            if (file.empty())
             {
-                std::string id = child_node.attribute("id").value();
-                std::string file = child_node.attribute("file").value();
+                createEmpty(walker, context);
+                continue;
+            }
 
-                if (file.empty())
-                {
-                    ResAnim* ra = new ResAnim(this);
-                    ra->init(0, 0, 0, walker.getScaleFactor());
-                    init_resAnim(ra, file, child_node);
-                    ra->setParent(this);
-                    context.resources->add(ra);
-                    continue;
-                }
 
-                if (meta)
-                {
-                    OX_ASSERT(meta_frames && "Did you recreate atlasses?");
-                }
 
-                MemoryTexture mt;
-                ImageData im;
+            MemoryTexture mt;
+            ImageData im;
 
-                int columns = 0;
-                int rows = 0;
-                int frame_width = 0;
-                int frame_height = 0;
-                float frame_scale = 1.0f;
-                bool loaded = false;
+            int columns = 0;
+            int rows = 0;
+            int frame_width = 0;
+            int frame_height = 0;
+            float frame_scale = 1.0f;
+            bool loaded = false;
 
-                if (meta_frames  || meta)
-                {
-                    const char* frame_size = meta_frames.attribute("fs").value();
 
-                    //int w = 0;
-                    //int h = 0;
+            file::buffer bf;
+            file::read(walker.getPath("file").c_str(), bf);
 
-                    sscanf(frame_size, "%d,%d,%d,%d,%f", &columns, &rows,
-                           &frame_width, &frame_height,
-                           &frame_scale);
-                    loaded = true;
-                    //frame_scale = 0.
-                    //frame_scale /= walker.getScaleFactor();//todo! fix
+            mt.init(bf, Renderer::getPremultipliedAlphaRender(), tf);
+            im = mt.lock();
+            if (im.w)
+            {
+                rows = child_node.attribute("rows").as_int();
+                frame_width = child_node.attribute("frame_width").as_int();
+                columns = child_node.attribute("cols").as_int();
+                frame_height = child_node.attribute("frame_height").as_int();
 
-                    //im.w = w;
-                    //im.h = h;
-                }
-                else
-                {
-                    file::buffer bf;
-                    file::read(walker.getPath("file").c_str(), bf);
+                if (!rows)
+                    rows = 1;
 
-                    mt.init(bf, Renderer::getPremultipliedAlphaRender(), tf);
-                    im = mt.lock();
-                    if (im.w)
-                    {
-                        rows = child_node.attribute("rows").as_int();
-                        frame_width = child_node.attribute("frame_width").as_int();
-                        columns = child_node.attribute("cols").as_int();
-                        frame_height = child_node.attribute("frame_height").as_int();
+                if (!columns)
+                    columns = 1;
 
-                        if (!rows)
-                            rows = 1;
+                if (frame_width)
+                    columns = im.w / frame_width;
+                else
+                    frame_width = im.w / columns;
 
-                        if (!columns)
-                            columns = 1;
 
-                        if (frame_width)
-                            columns = im.w / frame_width;
-                        else
-                            frame_width = im.w / columns;
+                if (frame_height)
+                    rows = im.h / frame_height;
+                else
+                    frame_height = im.h / rows;
+            }
 
 
-                        if (frame_height)
-                            rows = im.h / frame_height;
-                        else
-                            frame_height = im.h / rows;
+            if (columns)
+            {
+                animationFrames frames;
+                int frames_count = rows * columns;
+                frames.reserve(frames_count);
 
-                    }
-                }
+                ResAnim* ra = new ResAnim(this);
 
-                if (columns)
-                {
-                    animationFrames frames;
-                    int frames_count = rows * columns;
-                    frames.reserve(frames_count);
 
-                    ResAnim* ra = new ResAnim(this);
+                anims.push_back(ra);
 
-                    if (meta)
+                for (int y = 0; y < rows; ++y)
+                {
+                    for (int x = 0; x < columns; ++x)
                     {
-                        OX_ASSERT(meta_frames);
+                        Rect src;
+                        src.pos = Point(x * frame_width, y * frame_height);
+                        src.size = Point(frame_width, frame_height);
 
-                        /*
-                        if (string(meta_frames.attribute("debug_image").as_string()) == "backleft.png")
-                        {
+                        ImageData srcImage_ = im.getRect(src);
 
-                        }
-                        */
 
-                        char* frames_data = (char*)meta_frames.first_child().value();
+                        HitTestData adata;
+                        ImageData trimmedImage;
+                        Rect bounds;
+                        makeAlpha(srcImage_, bounds, _hitTestBuffer, adata, walker.getAlphaHitTest());
+                        trimmedImage = srcImage_.getRect(bounds);
 
+                        Rect dest(0, 0, 0, 0);
 
-                        const char* begin = frames_data;
-                        while (*frames_data)
+                        if (!ad.texture)
                         {
-                            if (*frames_data == ';')
-                            {
-                                *frames_data = 0;
-                                int id = 0;
-                                int x = 0;
-                                int y = 0;
-
-                                int bbox_x = 0;
-                                int bbox_y = 0;
-                                int bbox_w = 0;
-                                int bbox_h = 0;
-
-                                sscanf(begin, "%d,%d,%d,%d,%d,%d,%d", &id, &x, &y, &bbox_x, &bbox_y, &bbox_w, &bbox_h);
-
-                                begin = frames_data + 1;
-
-                                spNativeTexture& texture = _atlasses[id].base;
-                                spNativeTexture& alpha = _atlasses[id].alpha;
-
-                                float iw = 1.0f / texture->getWidth();
-                                float ih = 1.0f / texture->getHeight();
-
-                                RectF srcRect(x * iw, y * ih, bbox_w * iw, bbox_h * ih);
-
-                                float fs = frame_scale;
-                                RectF destRect(
-                                    Vector2((float)bbox_x, (float)bbox_y) * fs,
-                                    Vector2((float)bbox_w, (float)bbox_h) * fs
-                                );
-
-                                AnimationFrame frame;
-                                Diffuse df;
-                                df.base = texture;
-                                df.alpha = alpha;
-                                //compressed data could not be premultiplied
-                                if (Renderer::getPremultipliedAlphaRender())
-                                    df.premultiplied = !compressed;
-                                else
-                                    df.premultiplied = true;//render should think that it is already premultiplied and don't worry about alpha
-
-                                size_t n = frames.size();
-                                int column = n % columns;
-                                int row = n / columns;
-
-                                frame.init2(ra, column, row, df,
-                                            srcRect, destRect,
-                                            Vector2((float)frame_width, (float)frame_height));
-
-                                frames.push_back(frame);
-                                if ((int)frames.size() >= frames_count)
-                                    break;
-                            }
-
-                            ++frames_data;
+                            std::string atlas_id = getName();
+                            next_atlas(w, h, tf, ad, atlas_id.c_str());
                         }
-                    }
-                    else
-                    {
-                        anims.push_back(ra);
 
-                        for (int y = 0; y < rows; ++y)
+                        bool s = ad.atlas.add(&ad.mt, trimmedImage, dest);
+                        if (s == false)
                         {
-                            for (int x = 0; x < columns; ++x)
-                            {
-                                Rect src;
-                                src.pos = Point(x * frame_width, y * frame_height);
-                                src.size = Point(frame_width, frame_height);
-
-                                ImageData srcImage = im.getRect(src);
-
-                                Rect dest(0, 0, 0, 0);
-
-                                if (!ad.texture)
-                                {
-                                    std::string atlas_id = getName();
-                                    next_atlas(w, h, tf, ad, atlas_id.c_str());
-                                }
-
-                                bool s = ad.atlas.add(&ad.mt, srcImage, dest);
-                                if (s == false)
-                                {
-                                    apply_atlas(ad);
-                                    next_atlas(w, h, tf, ad, walker.getCurrentFolder().c_str());
-                                    s = ad.atlas.add(&ad.mt, srcImage, dest);
-                                    OX_ASSERT(s);
-                                }
-
-                                /*
-                                float iw = 1.0f / ad.mt.getWidth();
-                                float ih = 1.0f / ad.mt.getHeight();
-                                */
-
-                                float iw = 1.0f;
-                                float ih = 1.0f;
-
-                                RectF srcRect(dest.pos.x * iw, dest.pos.y * ih, dest.size.x * iw, dest.size.y * ih);
-
-                                Vector2 sizeScaled = Vector2((float)dest.size.x, (float)dest.size.y) * walker.getScaleFactor();
-                                RectF destRect(Vector2(0, 0), sizeScaled);
-
-                                AnimationFrame frame;
-                                Diffuse df;
-                                df.base = ad.texture;
-                                df.premultiplied = true;//!Renderer::getPremultipliedAlphaRender();
-                                frame.init2(ra, x, y, df, srcRect, destRect, Vector2((float)frame_width, (float)frame_height) * walker.getScaleFactor());
-                                frames.push_back(frame);
-                            }
+                            apply_atlas(ad);
+                            next_atlas(w, h, tf, ad, walker.getCurrentFolder().c_str());
+                            s = ad.atlas.add(&ad.mt, trimmedImage, dest);
+                            OX_ASSERT(s);
                         }
-                    }
 
 
+                        float iw = 1.0f;
+                        float ih = 1.0f;
 
-                    init_resAnim(ra, file, child_node);
+                        RectF srcRect(dest.pos.x * iw, dest.pos.y * ih, dest.size.x * iw, dest.size.y * ih);
 
-                    ra->init(frames, columns, walker.getScaleFactor());
-                    ra->setParent(this);
-                    context.resources->add(ra);
+                        Vector2 sizeScaled = Vector2((float)dest.size.x, (float)dest.size.y) * walker.getScaleFactor();
+                        RectF destRect(bounds.pos.cast<Vector2>(), sizeScaled);
+
+                        AnimationFrame frame;
+                        Diffuse df;
+                        df.base = ad.texture;
+                        df.premultiplied = true;//!Renderer::getPremultipliedAlphaRender();
+
+                        Vector2 fsize = Vector2((float)frame_width, (float)frame_height) * walker.getScaleFactor();
+                        frame.init2(ra, x, y, df,
+                                    srcRect, destRect, fsize);
+
+                        frame.setHitTestData(adata);
+
+                        frames.push_back(frame);
+                    }
                 }
+
+                init_resAnim(ra, file, child_node);
+
+                ra->init(frames, columns, walker.getScaleFactor(), 1.0f / walker.getScaleFactor());
+                ra->setParent(this);
+                context.resources->add(ra);
             }
+
         }
 
         apply_atlas(ad);
@@ -408,126 +561,213 @@ namespace oxygine
                 rect.size.x *= iw;
                 rect.size.y *= ih;
                 frame.setSrcRect(rect);
+
+                HitTestData ad = frame.getHitTestData();
+                if (ad.pitch)
+                {
+                    ad.data = &_hitTestBuffer[reinterpret_cast<size_t>(ad.data)];
+                    frame.setHitTestData(ad);
+                }
             }
         }
     }
 
-    Resource* ResAtlas::create(CreateResourceContext& context)
-    {
-        context.walker.checkSetAttributes();
-        ResAtlas* ra = new ResAtlas();
-        ra->setName(_Resource::extractID(context.walker.getNode(), "", std::string("!atlas:") + *context.xml_name));
-        ra->loadAtlas(context);
-        setNode(ra, context.walker.getNode());
-        //context.meta = context.meta.next_sibling();
-        return ra;
-    }
 
-    ResAtlas::ResAtlas(): _linearFilter(true), _clamp2edge(true)
+    ResAtlasPrebuilt::ResAtlasPrebuilt(CreateResourceContext& context)
     {
+        pugi::xml_node node = context.walker.getNode();
+        pugi::xml_node meta = context.walker.getMeta();
 
-    }
-
-    ResAtlas::~ResAtlas()
-    {
-        for (atlasses::iterator i = _atlasses.begin(); i != _atlasses.end(); ++i)
-        {
-            atlas& atl = *i;
-            if (atl.base)
-                atl.base->release();
-            if (atl.alpha)
-                atl.alpha->release();
-        }
-    }
-
-    static load_texture_hook _hook = 0;
-    void set_load_texture_hook(load_texture_hook hook)
-    {
-        _hook = hook;
-    }
+        const char* format = node.attribute("format").as_string("8888");
 
+        //_linearFilter = node.attribute("linearFilter").as_bool(true);
+        //_clamp2edge = node.attribute("clamp2edge").as_bool(true);
 
-    void load_texture_internal(const std::string& file, spNativeTexture nt, LoadResourcesContext* load_context)
-    {
-        ImageData im;
-        spMemoryTexture mt = new MemoryTexture;
 
-        LOGD("loading atlas: %s", file.c_str());
-        file::buffer bf;
-        file::read(file.c_str(), bf);
-        LOGD("atlas file loaded: %s", file.c_str());
-        mt->init(bf, Renderer::getPremultipliedAlphaRender(), nt->getFormat());
-        //mt->init(2048, 2048, TF_R8G8B8A8);
-        im = mt->lock();
-        LOGD("atlas size: %d %d", im.w, im.h);
+        TextureFormat tf = string2TextureFormat(format);
 
-        //Object::dumpCreatedObjects();
-        load_context->createTexture(mt, nt);
-    }
+        pugi::xml_node meta_image = meta.child("atlas");
 
-    void load_texture(const std::string& file, spNativeTexture nt, LoadResourcesContext* load_context)
-    {
-        if (_hook)
+        pugi::xml_node meta_alpha = meta.child("ht");
+        if (meta_alpha)
         {
-            _hook(file, nt, load_context);
-            return;
+            const char* data = meta_alpha.text().as_string();
+            int len = meta_alpha.attribute("len").as_int();
+            base64_decodestate state;
+            base64_init_decodestate(&state);
+            _hitTestBuffer.resize(len * 3 / 4);
+            if (len)
+                base64_decode_block(data, len, (char*)&_hitTestBuffer.front(), &state);
         }
 
-        load_texture_internal(file, nt, load_context);
-    }
-
-    void ResAtlas::_restore(Restorable* r, void*)
-    {
-        NativeTexture* texture = (NativeTexture*)r->_getRestorableObject();
+        bool compressed = false;
 
-        for (atlasses::iterator i = _atlasses.begin(); i != _atlasses.end(); ++i)
+        while (meta_image)
         {
-            atlas& atl = *i;
-            if (atl.base.get() == texture)
+            const char* file = meta_image.attribute("file").value();
+
+            int w = meta_image.attribute("w").as_int();
+            int h = meta_image.attribute("h").as_int();
+
+            const char* file_format = meta_image.attribute("format").as_string(0);
+            TextureFormat ffmt = TF_UNDEFINED;
+            if (file_format)
             {
-                load_texture(atl.base_path, atl.base, &RestoreResourcesContext::instance);
-                atl.base->reg(CLOSURE(this, &ResAtlas::_restore), 0);
-                break;
+                ffmt = string2TextureFormat(file_format);
+                compressed = isCompressedFormat(ffmt);
             }
 
-            if (atl.alpha.get() == texture)
+            std::string alpha_file = meta_image.attribute("alpha").as_string("");
+            if (!alpha_file.empty())
             {
-                load_texture(atl.alpha_path, atl.alpha, &RestoreResourcesContext::instance);
-                atl.alpha->reg(CLOSURE(this, &ResAtlas::_restore), 0);
-                break;
+                alpha_file = *context.prebuilt_folder + alpha_file;
             }
+
+            addAtlas(tf, *context.prebuilt_folder + file, alpha_file, w, h);
+
+            meta_image = meta_image.next_sibling("atlas");
+            context.walker.nextMeta();
         }
-    }
 
-    void ResAtlas::_load(LoadResourcesContext* load_context)
-    {
-        for (atlasses::iterator i = _atlasses.begin(); i != _atlasses.end(); ++i)
+        while (true)
         {
-            atlas& atl = *i;
-            if (!load_context->isNeedProceed(atl.base))
+            XmlWalker walker = context.walker.next();
+            if (walker.empty())
+                break;
+
+            pugi::xml_node child_node = walker.getNode();
+
+            const char* name = child_node.name();
+            if (strcmp(name, "image"))
                 continue;
 
-            load_texture(atl.base_path, atl.base, load_context);
-            atl.base->reg(CLOSURE(this, &ResAtlas::_restore), 0);
+            pugi::xml_node meta_frames = walker.getMeta();
 
-            if (atl.alpha)
+            std::string id = child_node.attribute("id").value();
+            std::string file = child_node.attribute("file").value();
+
+            if (file.empty())
             {
-                load_texture(atl.alpha_path, atl.alpha, load_context);
-                atl.alpha->reg(CLOSURE(this, &ResAtlas::_restore), 0);
+                createEmpty(walker, context);
+                continue;
             }
-        }
-    }
 
-    void ResAtlas::_unload()
-    {
-        for (atlasses::iterator i = _atlasses.begin(); i != _atlasses.end(); ++i)
-        {
-            atlas& atl = *i;
-            if (atl.base)
-                atl.base->release();
 
-            if (atl.alpha)
-                atl.alpha->release();
+            OX_ASSERT(meta_frames && "Did you recreate atlasses?");
+
+            int columns = 0;
+            int rows = 0;
+            int frame_width = 0;
+            int frame_height = 0;
+            float frame_scale = 1.0f;
+
+
+            const char* frame_size = meta_frames.attribute("fs").value();
+
+            sscanf(frame_size, "%d,%d,%d,%d,%f", &columns, &rows,
+                   &frame_width, &frame_height,
+                   &frame_scale);
+
+            HitTestData adata;
+            const char* alpha = meta_frames.attribute("ht").as_string(0);
+            if (alpha)
+            {
+                int ad_w, ad_h, ad_pos, ad_size;
+                sscanf(alpha, "%d,%d,%d,%d", &ad_pos, &ad_size, &ad_w, &ad_h);
+                adata.w = ad_w;
+                adata.h = ad_h;
+                adata.pitch = ad_size / ad_h;
+                adata.data = &_hitTestBuffer[ad_pos];
+            }
+
+
+
+            if (columns)
+            {
+                animationFrames frames;
+                int frames_count = rows * columns;
+                frames.reserve(frames_count);
+
+                ResAnim* ra = new ResAnim(this);
+
+
+                OX_ASSERT(meta_frames);
+
+
+                char* frames_data = (char*)meta_frames.first_child().value();
+
+
+                const char* begin = frames_data;
+                while (*frames_data)
+                {
+                    if (*frames_data == ';')
+                    {
+                        *frames_data = 0;
+                        int id = 0;
+                        int x = 0;
+                        int y = 0;
+
+                        int bbox_x = 0;
+                        int bbox_y = 0;
+                        int bbox_w = 0;
+                        int bbox_h = 0;
+
+                        sscanf(begin, "%d,%d,%d,%d,%d,%d,%d", &id, &x, &y, &bbox_x, &bbox_y, &bbox_w, &bbox_h);
+
+                        begin = frames_data + 1;
+
+                        spNativeTexture& texture = _atlasses[id].base;
+                        spNativeTexture& alpha = _atlasses[id].alpha;
+
+                        float iw = 1.0f / texture->getWidth();
+                        float ih = 1.0f / texture->getHeight();
+
+                        RectF srcRect(x * iw, y * ih, bbox_w * iw, bbox_h * ih);
+
+                        float fs = frame_scale;
+                        RectF destRect(
+                            Vector2((float)bbox_x, (float)bbox_y) * fs,
+                            Vector2((float)bbox_w, (float)bbox_h) * fs
+                        );
+
+                        AnimationFrame frame;
+                        Diffuse df;
+                        df.base = texture;
+                        df.alpha = alpha;
+
+                        //compressed data could not be premultiplied
+                        if (Renderer::getPremultipliedAlphaRender())
+                            df.premultiplied = !compressed;
+                        else
+                            df.premultiplied = true;//render should think that it is already premultiplied and don't worry about alpha
+
+                        size_t n = frames.size();
+                        int column = n % columns;
+                        int row = n / columns;
+
+                        frame.init2(ra, column, row, df,
+                                    srcRect, destRect,
+                                    Vector2((float)frame_width, (float)frame_height));
+                        if (adata.pitch)
+                        {
+                            frame.setHitTestData(adata);
+                            adata.data += adata.h * adata.pitch;
+                        }
+
+                        frames.push_back(frame);
+                        if ((int)frames.size() >= frames_count)
+                            break;
+                    }
+
+                    ++frames_data;
+                }
+
+                init_resAnim(ra, file, child_node);
+
+                ra->init(frames, columns, walker.getScaleFactor(), 1.0f / frame_scale);
+                ra->setParent(this);
+                context.resources->add(ra);
+            }
         }
     }
-}
+}

+ 26 - 13
oxygine/src/res/ResAtlas.h

@@ -5,15 +5,10 @@
 #include "Resource.h"
 #include "ResAnim.h"
 
-namespace pugi
-{
-    class xml_node;
-}
-
 namespace oxygine
 {
-
     class Resources;
+    class XmlWalker;
     class CreateResourceContext;
     DECLARE_SMART(NativeTexture, spNativeTexture);
 
@@ -44,16 +39,16 @@ namespace oxygine
         void _load(LoadResourcesContext*);
         void _unload();
 
-        void loadAtlas(CreateResourceContext& context);
+        //void loadAtlas(CreateResourceContext& context);
+        ResAnim* createEmpty(const XmlWalker& walker, CreateResourceContext& context);
         static void init_resAnim(ResAnim* rs, const std::string& file, pugi::xml_node node);
 
-    private:
-        //void next_atlas(int w, int h, TextureFormat tf, atlas_data &ad, const char *name);
-        //void apply_atlas(atlas_data &ad);
-
+    protected:
         //settings from xml
-        bool _linearFilter;
-        bool _clamp2edge;
+        //bool _linearFilter;
+        //bool _clamp2edge;
+
+        std::vector<unsigned char> _hitTestBuffer;
 
         typedef std::vector<atlas> atlasses;
         atlasses _atlasses;
@@ -61,4 +56,22 @@ namespace oxygine
 
     typedef void(*load_texture_hook)(const std::string& file, spNativeTexture nt, LoadResourcesContext* load_context);
     void set_load_texture_hook(load_texture_hook);
+
+
+    class ResAtlasGeneric : public ResAtlas
+    {
+    public:
+
+        //protected:
+        void loadAtlas(CreateResourceContext& context);
+    };
+
+    class ResAtlasPrebuilt : public ResAtlas
+    {
+    public:
+
+        ResAtlasPrebuilt(CreateResourceContext& context);
+
+    protected:
+    };
 }

+ 2 - 2
oxygine/src/res/Resources.cpp

@@ -240,7 +240,7 @@ namespace oxygine
         if (!resources_meta.empty())
         {
             int metaVersion = resources_meta.attribute("version").as_int(0);
-            OX_ASSERT(metaVersion == 1  && "Please rebuild xmls with latest 'oxyresbuild' tool");
+            OX_ASSERT(metaVersion <= 2  && "Please rebuild xmls with latest 'oxyresbuild' tool");
         }
 
 
@@ -251,7 +251,7 @@ namespace oxygine
         FS_LOG("loading xml resources");
 
         std::string xmlFolder = destHead;
-        XmlWalker walker(&xmlFolder, "", 1.0f, load_completely, resources, resources_meta);
+        XmlWalker walker(&xmlFolder, "", 1.0f, load_completely, false, resources, resources_meta);
 
         while (true)
         {

+ 88 - 0
oxygine/src/utils/cdecode.c

@@ -0,0 +1,88 @@
+/*
+cdecoder.c - c source to a base64 decoding algorithm implementation
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#include "cdecode.h"
+
+int base64_decode_value(char value_in)
+{
+	static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
+	static const char decoding_size = sizeof(decoding);
+	value_in -= 43;
+	if (value_in < 0 || value_in > decoding_size) return -1;
+	return decoding[(int)value_in];
+}
+
+void base64_init_decodestate(base64_decodestate* state_in)
+{
+	state_in->step = step_a;
+	state_in->plainchar = 0;
+}
+
+int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
+{
+	const char* codechar = code_in;
+	char* plainchar = plaintext_out;
+	char fragment;
+	
+	*plainchar = state_in->plainchar;
+	
+	switch (state_in->step)
+	{
+		while (1)
+		{
+	case step_a:
+			do {
+				if (codechar == code_in+length_in)
+				{
+					state_in->step = step_a;
+					state_in->plainchar = *plainchar;
+					return plainchar - plaintext_out;
+				}
+				fragment = (char)base64_decode_value(*codechar++);
+			} while (fragment < 0);
+			*plainchar    = (fragment & 0x03f) << 2;
+	case step_b:
+			do {
+				if (codechar == code_in+length_in)
+				{
+					state_in->step = step_b;
+					state_in->plainchar = *plainchar;
+					return plainchar - plaintext_out;
+				}
+				fragment = (char)base64_decode_value(*codechar++);
+			} while (fragment < 0);
+			*plainchar++ |= (fragment & 0x030) >> 4;
+			*plainchar    = (fragment & 0x00f) << 4;
+	case step_c:
+			do {
+				if (codechar == code_in+length_in)
+				{
+					state_in->step = step_c;
+					state_in->plainchar = *plainchar;
+					return plainchar - plaintext_out;
+				}
+				fragment = (char)base64_decode_value(*codechar++);
+			} while (fragment < 0);
+			*plainchar++ |= (fragment & 0x03c) >> 2;
+			*plainchar    = (fragment & 0x003) << 6;
+	case step_d:
+			do {
+				if (codechar == code_in+length_in)
+				{
+					state_in->step = step_d;
+					state_in->plainchar = *plainchar;
+					return plainchar - plaintext_out;
+				}
+				fragment = (char)base64_decode_value(*codechar++);
+			} while (fragment < 0);
+			*plainchar++   |= (fragment & 0x03f);
+		}
+	}
+	/* control should not reach here */
+	return plainchar - plaintext_out;
+}
+

+ 28 - 0
oxygine/src/utils/cdecode.h

@@ -0,0 +1,28 @@
+/*
+cdecode.h - c header for a base64 decoding algorithm
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#ifndef BASE64_CDECODE_H
+#define BASE64_CDECODE_H
+
+typedef enum
+{
+    step_a, step_b, step_c, step_d
+} base64_decodestep;
+
+typedef struct
+{
+    base64_decodestep step;
+    char plainchar;
+} base64_decodestate;
+
+void base64_init_decodestate(base64_decodestate* state_in);
+
+int base64_decode_value(char value_in);
+
+int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
+
+#endif /* BASE64_CDECODE_H */

+ 42 - 17
tools/others/build_oxygine_with_sdl.py

@@ -2,7 +2,43 @@ import os
 import sys
 import shutil
 import zipfile
+import time
 
+
+def recursive_zip(zipf, directory, folder = ""):
+    for item in os.listdir(directory):
+        if os.path.isfile(os.path.join(directory, item)):
+            src = os.path.join(directory, item)
+            dest = folder + os.sep + item
+            ext = os.path.splitext(dest)[1]
+            
+            st = os.stat(src)
+            mtime = time.localtime(st.st_mtime)
+            date_time = mtime[0:6]            
+
+            info = zipfile.ZipInfo(dest, date_time)
+            bts = open(src, "rb").read()
+            if ext == ".sh" or item in ("PVRTexToolCLI", "oxyresbuild.py", "gen_template.py", "png_strip.py"):
+                info.external_attr = 0755 << 16L #a+x
+            zipf.writestr(info, bts, zipfile.ZIP_DEFLATED)
+            
+            
+        elif os.path.isdir(os.path.join(directory, item)):
+            recursive_zip(zipf, os.path.join(directory, item), folder + os.sep + item)
+            
+
+
+def buildzip(name):
+    print("building zip: " + name)
+    destzip = "../../" + name
+    with zipfile.ZipFile(destzip, "w", compression = zipfile.ZIP_DEFLATED) as zp:
+        recursive_zip(zp, "../../temp")
+        
+    shutil.copyfile(destzip, "../../../gdrive/oxygine/" + name)
+    print("zip created: " + name)
+    
+    
+    
 temp = "../../temp"
 SDL_dest = temp + "/SDL"
 OXYGINE_dest = temp + "/oxygine-framework/"
@@ -15,6 +51,11 @@ print("hg archive...")
 cmd = "hg archive " + OXYGINE_dest
 os.system(cmd)
 
+#os.chdir(dest)
+
+buildzip("oxygine-framework.zip")
+
+
 cmd = "hg archive -R ../../../SDL %s" % (SDL_dest, )
 os.system(cmd)
 
@@ -43,7 +84,6 @@ def enum(folder, cb):
         path = folder + item 
         if os.path.isdir(path):
             if item == "data":
-                print(path)
                 cb(path)
             enum(path + "/", cb)
             
@@ -76,21 +116,6 @@ libs = ("libSDL2main.a", "libSDL2.dll", "libSDL2.dll.a")
 for lib in libs:
     shutil.copy("../../libs/" + lib, OXYGINE_dest + "/libs/" + lib)    
 
-os.chdir(OXYGINE_dest)
-
-
-
-def recursive_zip(zipf, directory, folder = ""):
-    for item in os.listdir(directory):
-        if os.path.isfile(os.path.join(directory, item)):
-            zipf.write(os.path.join(directory, item), folder + os.sep + item)
-        elif os.path.isdir(os.path.join(directory, item)):
-            recursive_zip(zipf, os.path.join(directory, item), folder + os.sep + item)
-
-destzip = "../../oxygine-framework-with-sdl.zip"
-with zipfile.ZipFile(destzip, "w", compression = zipfile.ZIP_DEFLATED) as zp:
-    recursive_zip(zp, "../")
-    
-shutil.copyfile(destzip, "../../../gdrive/oxygine/oxygine-framework-with-sdl.zip")
+buildzip("oxygine-framework-with-sdl.zip")
 
 print("done.")

+ 0 - 29
tools/others/build_oxygine_zip.py

@@ -1,29 +0,0 @@
-import os
-import sys
-import shutil
-import zipfile
-
-dest = "../../temp/oxygine-framework/"
-
-print("cleaning temp...")
-shutil.rmtree("../../temp", True)
-
-print("hg archive...")
-os.system("hg archive " + dest)
-os.chdir(dest)
-
-def recursive_zip(zipf, directory, folder = ""):
-    for item in os.listdir(directory):
-        if os.path.isfile(os.path.join(directory, item)):
-            zipf.write(os.path.join(directory, item), folder + os.sep + item)
-        elif os.path.isdir(os.path.join(directory, item)):
-            recursive_zip(zipf, os.path.join(directory, item), folder + os.sep + item)
-
-
-destzip = "../../oxygine-framework.zip"
-with zipfile.ZipFile(destzip, "w", compression = zipfile.ZIP_DEFLATED) as zp:
-    recursive_zip(zp, "../")
-    
-shutil.copyfile(destzip, "../../../gdrive/oxygine/oxygine-framework.zip")
-
-print("done.")

+ 162 - 64
tools/resbuild/process_atlas.py

@@ -9,6 +9,9 @@ import os
 from . import atlas
 from . import process
 
+import struct
+import base64
+
 def as_int(attr, df = 0):
     if not attr:
         return df
@@ -51,10 +54,19 @@ def premultipliedAlpha(image):
 
     return image    
 
+class alphaData:
+    def __init__(self, w, h, data):
+        self.w = w
+        self.h = h
+        self.data = data
+
+
 class frame:
-    def __init__(self, image, bbox, image_element, rs):
+    def __init__(self, image, bbox, image_element, rs, adata):
+
         self.image = image
         self.image_element = image_element
+        self.adata = adata
 
         self.node = None
         self.resanim = rs
@@ -106,7 +118,7 @@ def applyScale2(x, scale):
             return int(best[1])
 
         x += 1
-        
+
 def nextPOT(v):
     v = v - 1;
     v = v | (v >> 1);
@@ -126,11 +138,60 @@ class settings:
         self.atlasses = []
         self.square = False
         self.npot = False
+        
+def makeAlpha(a):
+    
+    def roundUp(v, multiple):
+        if multiple == 0:
+            return v
+        rem = v % multiple
+        if rem == 0:
+            return v     
+        res = v + multiple - rem
+        return res                
+    
+    asmall = a.resize((int(a.size[0]/4), int(a.size[1]/4)), Image.ANTIALIAS)
+
+
+    b = asmall.getextrema()
+    
+    if not b:
+        return None
+
+    if b[0] > 10:
+        return None
+
+    asmall_size = asmall.size                    
+
+    BITS = 32
+
+    val = roundUp(asmall_size[0], BITS)
+    lineLen = val // BITS
+
+
+    buff = b''
+
+    for y in range(asmall_size[1]):
+
+        line = [0 for x in range(lineLen)]                    
+        for x in range(asmall_size[0]):
+            p = asmall.getpixel((x,y))
+            if p > 5:                            
+                n = x // BITS
+                b = x % BITS                            
+                line[n] |= 1 << b
+
+
+        for v in line:
+            buff += struct.pack("<I", v)
+
+    adata = alphaData(asmall_size[0], asmall_size[1], buff)                        
+    return adata
 
 def pack(st, frames, sw, sh):                       
-                
+
     atl = atlas.Atlas(st.padding, sw, sh)            
-            
+
     not_packed = []    
     for fr in frames:
         ns = st.get_size(fr)
@@ -139,10 +200,10 @@ def pack(st, frames, sw, sh):
             not_packed.append(fr)
         else:
             st.set_node(fr, node)   
-        
+
     #atl.add(250, 250)
     #atl.save()
-        
+
     return not_packed, atl
 
 
@@ -176,42 +237,42 @@ def pck(st, frames):
             sq += size[0] * size[1]
             min_w = max(min_w, size[0])
             min_h = max(min_h, size[1])
-            
+
         sizes_w = list(get_pow2list(st.npot, min_w, st.max_w))
         sizes_h = list(get_pow2list(st.npot, min_h, st.max_h))
-        
+
         for sw in sizes_w:
             for sh in sizes_h:
                 end = sh == sizes_h[-1] and sw == sizes_w[-1]
-                
+
                 if st.square and sw != sh:
                     continue
-                
+
                 if sw * sh < sq and not end:
                     continue                
-                
+
                 not_packed, bn = pack(st, frames, sw, sh)
                 st.atlasses.append(bn)
                 if not not_packed:
                     return
-                
+
                 if end:                    
                     frames = not_packed   
                 else:
                     st.atlasses.pop()
-                    
-                    
+
+
 def processRS(context, walker):
-        
+
     image_el = walker.root
-    
+
     image_name = image_el.getAttribute("file")
     if not image_name:
         return None
 
     file_path = walker.getPath("file")
-    
-    
+
+
     #print image_path
 
     image = None
@@ -240,7 +301,7 @@ def processRS(context, walker):
     resAnim.image = image
     resAnim.name = image_name                        
 
-    
+
 
     columns = as_int(image_el.getAttribute("cols"))
     frame_width = as_int(image_el.getAttribute("frame_width"))
@@ -249,7 +310,7 @@ def processRS(context, walker):
     border = as_int(image_el.getAttribute("border"))
     #sq = as_float(image_el.getAttribute("scale_quality"), 1)
     #next.scale_quality *= sq
-    
+
     if not columns:
         columns = 1
     if not rows:
@@ -277,43 +338,47 @@ def processRS(context, walker):
 
     if size_warning:
         context.warnings += 1
-        
+
     scale_factor = walker.scale_factor    
-    
+
     resAnim.frame_scale2 = scale_factor        
     finalScale = 1    
-    
+
     upscale = False
-    
+
     if context.args.resize:
         max_scale = 1.0 / scale_factor
-        
+
         finalScale = context.scale * walker.scale_quality
-        
+
         if finalScale > max_scale:
             if not context.args.upscale:
                 finalScale = max_scale
             else:
                 upscale = True
-            
+
         resAnim.frame_scale2 = 1.0 / finalScale
-        
+
         finalScale = finalScale * scale_factor
-            
+
 
     frame_size = (applyScale(frame_width, finalScale),
                   applyScale(frame_height, finalScale))
-    
+
     resAnim.frame_size2 = (applyScale(frame_width, scale_factor),
-                          applyScale(frame_height, scale_factor))            
+                           applyScale(frame_height, scale_factor))            
 
     resAnim.columns = columns
     resAnim.rows = rows
-    
-    
+
+
     for row in range(rows):
         for col in range(columns):
-            rect = (int(col * frame_width), int(row * frame_height), int((col + 1) * frame_width), int((row + 1)* frame_height), )
+
+            rect = (int(col * frame_width),
+                    int(row * frame_height),
+                    int((col + 1) * frame_width), 
+                    int((row + 1) * frame_height))
 
 
             frame_image = image.crop(rect)      
@@ -328,7 +393,7 @@ def processRS(context, walker):
                 im.paste(frame_image, (0, 0, frame_image.size[0], frame_image.size[1]))
                 frame_image = im.resize((ax, ay), Image.ANTIALIAS)
                 frame_image = frame_image.crop((0, 0, frame_size[0], frame_size[1]))                        
-                
+
             resize_filter = Image.ANTIALIAS
             if upscale:
                 resize_filter = Image.BICUBIC
@@ -349,9 +414,16 @@ def processRS(context, walker):
             trim = True
             if image_el.getAttribute("trim") == "0":
                 trim = False
+
+
+            adata = None
+
             if image.mode == "RGBA" and trim:
                 r,g,b,a = frame_image.split()
                 a = a.point(lambda p: p - 2)
+
+                adata = makeAlpha(a)
+
                 frame_bbox = a.getbbox()
             else:
                 frame_bbox = frame_image.getbbox()
@@ -365,12 +437,14 @@ def processRS(context, walker):
 
             frame_image = frame_image.crop(frame_bbox)
 
-            fr = frame(frame_image, frame_bbox, image_el, resAnim)
+            fr = frame(frame_image, frame_bbox, image_el, resAnim, adata)
             if border:
                 fr.border_left = fr.border_right = fr.border_top = fr.border_bottom = border
-            
+
+
+
             resAnim.frames.append(fr)
-            
+
     return resAnim                    
 
 
@@ -388,23 +462,28 @@ class atlas_Processor(process.Process):
 
         anims = []
         frames = []
-        
+
+
+        import struct
+
+        alphaData = ""        
+
         while True:
             next = walker.next()
             if 0:
                 import xml_processor
                 next = xml_processor.XmlWalker()
-                
+
             if not next:
                 break
-            
+
             anim = processRS(context, next)
-            
+
             if anim:
                 anims.append(anim)
                 frames.extend(anim.frames)            
-            
-        
+
+
         #sort frames by size
         #frames = sorted(frames, key = lambda fr: -fr.image.size[1])
         #frames = sorted(frames, key = lambda fr: -fr.image.size[0])
@@ -430,15 +509,15 @@ class atlas_Processor(process.Process):
                 return p
             sz = frame.image.size
             return align_pixel(sz[0] + frame.border_left + frame.border_right), align_pixel(sz[1] + frame.border_top + frame.border_bottom)
-        
+
         def get_original_frame_size(frame):
             sz = frame.image.size
             return sz
-        
-        
+
+
         def set_node(frame, node):
             frame.node = node
-        
+
         st = settings()
         st.npot = context._npot
         st.get_size = get_aligned_frame_size
@@ -446,18 +525,18 @@ class atlas_Processor(process.Process):
         st.max_w = context.args.max_width
         st.max_h = context.args.max_height
         st.square = context.compression == "pvrtc"
-        
+
         if len(frames) == 1:
             st.get_size = get_original_frame_size
             st.padding = 0
-        
+
         pck(st, frames) 
 
         #print "done"
-        
+
         for atlas_id, atl in enumerate(st.atlasses):
             image = Image.new("RGBA", (atl.w, atl.h))
-            
+
             for node in atl.nodes:
                 fr = node.data
                 x = node.rect.x + fr.border_left
@@ -478,12 +557,12 @@ class atlas_Processor(process.Process):
             def compress(src, dest, fmt):
                 cmd = context.helper.path_pvrtextool + " -i %s -f %s,UBN,lRGB -o %s" % (src, fmt, dest)
                 cmd += " -l" #alpha bleed
-                                
+
                 if context.args.quality == "best":
                     cmd += " -q pvrtcbest"
                 else:
                     cmd += " -q pvrtcfast"
-                    
+
                 if context.args.dither:
                     cmd += " -dither"                            
                 cmd += " -shh" #silent
@@ -497,7 +576,7 @@ class atlas_Processor(process.Process):
                 base_alpha_name = base_name + "_alpha"
                 alpha_path = context.get_inner_dest(base_alpha_name + ".png")
                 alpha.save(alpha_path)
-                
+
                 image_atlas_el.setAttribute("alpha", base_alpha_name + ".png")
 
                 path_base = base_name + ".png"
@@ -529,7 +608,7 @@ class atlas_Processor(process.Process):
                     path_base = base_name + ".tga"
                 else:
                     path_base = base_name + ".png"
-                    
+
                 path = context.get_inner_dest(path_base)
                 image_atlas_el.setAttribute("file", path_base)
                 image.save(path)            
@@ -540,15 +619,15 @@ class atlas_Processor(process.Process):
                     compress(path, context.get_inner_dest(base_name + ".pvr"), "PVRTC1_4")
                     image_atlas_el.setAttribute("file", base_name + ".pvr")
                     os.remove(path)
-                    
+
                 if context.compression == "pvrtc2":
                     ox_fmt = "PVRTC2_4RGBA"
 
                     compress(path, context.get_inner_dest(base_name + ".pvr"), "PVRTC2_4")
                     image_atlas_el.setAttribute("file", base_name + ".pvr")
                     os.remove(path)                
-                    
-                    
+
+
 
 
             image_atlas_el.setAttribute("format", ox_fmt)
@@ -557,16 +636,22 @@ class atlas_Processor(process.Process):
             image_atlas_el.setAttribute("h", str(image.size[1]))  
 
 
-        for anim in anims:                
+        alpha = b''
+        
+
+        for anim in anims:           
+
             if 0:
                 anim = ResAnim()
-
+                
             image_frames_el = anim.walker.root_meta
 
-            
             image_frames_el.setAttribute("fs", "%d,%d,%d,%d,%f" % (anim.columns, anim.rows, 
                                                                    anim.frame_size2[0], anim.frame_size2[1], 
-                                                                   anim.frame_scale2))        
+                                                                   anim.frame_scale2)) 
+            adata = anim.frames[0].adata
+            if adata:
+                image_frames_el.setAttribute("ht", "%d,%d,%d,%d" % (len(alpha), len(adata.data), adata.w, adata.h))
 
             if context.debug:
                 image_frames_el.setAttribute("debug_image", anim.name)
@@ -578,6 +663,19 @@ class atlas_Processor(process.Process):
                                                   fr.node.rect.x + fr.border_left, fr.node.rect.y + fr.border_top, 
                                                   fr.bbox[0], fr.bbox[1],
                                                   fr.bbox[2] - fr.bbox[0], fr.bbox[3] - fr.bbox[1])
+                if fr.adata:
+                    alpha += fr.adata.data
 
             text = image_frames_el.ownerDocument.createTextNode(data)
-            image_frames_el.appendChild(text)
+            image_frames_el.appendChild(text)
+        
+        if alpha:
+            doc = walker.root_meta.ownerDocument
+    
+            alpha_el = doc.createElement("ht")            
+            adata_str = base64.b64encode(alpha)
+            text = doc.createTextNode(adata_str.decode("utf-8"))
+            alpha_el.setAttribute("len", str(len(adata_str)))
+            alpha_el.appendChild(text)        
+    
+            walker.root_meta.appendChild(alpha_el)

+ 0 - 1
tools/resbuild/process_starling_atlas.py

@@ -16,7 +16,6 @@ class starling_atlas_Processor(process.Process):
         meta = walker.root_meta
         xml_path = walker.getPath("file")
         folder = os.path.split(xml_path)[0] + "/"
-        print folder
         file_doc = context._open_xml(context.src_data + xml_path)
         
         file_root = file_doc

+ 1 - 1
tools/resbuild/xml_processor.py

@@ -228,7 +228,7 @@ class XmlProcessor:
 
         self._meta_doc = minidom.Document()
         meta_element = self._meta_doc.createElement("resources")
-        meta_element.setAttribute("version", "1")
+        meta_element.setAttribute("version", "2")
         self._meta_doc.appendChild(meta_element)
         
         totalAtlasses = 0