Просмотр исходного кода

Merge 9/22 screeninfo and ivansafrin Polycode branches

mcc 13 лет назад
Родитель
Сommit
e3e6758d7d
65 измененных файлов с 1157 добавлено и 572 удалено
  1. 2 2
      Assets/Templates/C++/Windows/Polycode.props
  2. 1 1
      Bindings/Contents/LUA/API/class.lua
  3. 415 316
      Bindings/Scripts/create_lua_library/create_lua_library.py
  4. 1 0
      Core/Contents/CMakeLists.txt
  5. 1 0
      Core/Contents/Include/PolyCamera.h
  6. 1 3
      Core/Contents/Include/PolyCocoaCore.h
  7. 11 3
      Core/Contents/Include/PolyCore.h
  8. 5 3
      Core/Contents/Include/PolyCoreInput.h
  9. 1 1
      Core/Contents/Include/PolyEntity.h
  10. 2 0
      Core/Contents/Include/PolyEvent.h
  11. 2 2
      Core/Contents/Include/PolyEventDispatcher.h
  12. 2 1
      Core/Contents/Include/PolyGlobals.h
  13. 1 0
      Core/Contents/Include/PolyInputEvent.h
  14. 24 2
      Core/Contents/Include/PolyMatrix4.h
  15. 10 1
      Core/Contents/Include/PolyQuaternion.h
  16. 1 1
      Core/Contents/Include/PolyRenderer.h
  17. 3 1
      Core/Contents/Include/PolySDLCore.h
  18. 7 6
      Core/Contents/Include/PolyScreenEntity.h
  19. 6 1
      Core/Contents/Include/PolyScreenMesh.h
  20. 4 0
      Core/Contents/Include/PolyScreenSprite.h
  21. 2 2
      Core/Contents/Include/PolyTexture.h
  22. 20 7
      Core/Contents/Include/PolyThreaded.h
  23. 0 2
      Core/Contents/Include/PolyWinCore.h
  24. 3 0
      Core/Contents/Source/PolyCamera.cpp
  25. 2 0
      Core/Contents/Source/PolyCocoaCore.mm
  26. 53 1
      Core/Contents/Source/PolyCore.cpp
  27. 33 4
      Core/Contents/Source/PolyCoreInput.cpp
  28. 4 1
      Core/Contents/Source/PolyEntity.cpp
  29. 1 0
      Core/Contents/Source/PolyEvent.cpp
  30. 1 0
      Core/Contents/Source/PolyGLRenderer.cpp
  31. 211 91
      Core/Contents/Source/PolyMatrix4.cpp
  32. 5 1
      Core/Contents/Source/PolyObject.cpp
  33. 33 4
      Core/Contents/Source/PolyRenderer.cpp
  34. 3 0
      Core/Contents/Source/PolySDLCore.cpp
  35. 1 1
      Core/Contents/Source/PolySceneLine.cpp
  36. 39 29
      Core/Contents/Source/PolyScreenEntity.cpp
  37. 1 2
      Core/Contents/Source/PolyScreenImage.cpp
  38. 24 0
      Core/Contents/Source/PolyScreenMesh.cpp
  39. 3 5
      Core/Contents/Source/PolyScreenShape.cpp
  40. 20 5
      Core/Contents/Source/PolyScreenSprite.cpp
  41. 39 0
      Core/Contents/Source/PolyThreaded.cpp
  42. 0 1
      Examples/C++/Contents/2DShapes/HelloPolycodeApp.h
  43. 24 1
      Modules/Contents/2DPhysics/Include/PolyPhysicsScreen.h
  44. 0 3
      Modules/Contents/2DPhysics/Include/PolyPhysicsScreenEntity.h
  45. 12 0
      Modules/Contents/2DPhysics/Source/PolyPhysicsScreen.cpp
  46. 20 28
      Modules/Contents/2DPhysics/Source/PolyPhysicsScreenEntity.cpp
  47. 2 0
      Modules/Contents/3DPhysics/Include/PolyPhysicsScene.h
  48. 4 0
      Modules/Contents/3DPhysics/Include/PolyPhysicsSceneEntity.h
  49. 8 0
      Modules/Contents/3DPhysics/Source/PolyPhysicsScene.cpp
  50. 9 0
      Modules/Contents/3DPhysics/Source/PolyPhysicsSceneEntity.cpp
  51. 19 4
      Modules/Contents/Curl/PolycodeDownloader.cpp
  52. 13 4
      Modules/Contents/Curl/PolycodeDownloader.h
  53. 5 1
      Modules/Contents/Networking/Include/PolyPeer.h
  54. 1 1
      Modules/Contents/Networking/Include/PolySocket.h
  55. 5 1
      Modules/Contents/Networking/Source/PolyPeer.cpp
  56. 1 0
      Modules/Contents/TUIO/Include/TUIOInputModule.h
  57. 3 1
      Modules/Contents/TUIO/Include/osc/OscHostEndianness.h
  58. 21 4
      Modules/Contents/TUIO/Source/TUIOInputModule.cpp
  59. 2 4
      Modules/Contents/UI/Source/PolyUIBox.cpp
  60. 2 4
      Modules/Contents/UI/Source/PolyUIScrollContainer.cpp
  61. 1 2
      Modules/Contents/UI/Source/PolyUITextInput.cpp
  62. 1 2
      Modules/Contents/UI/Source/PolyUITree.cpp
  63. 3 6
      Modules/Contents/UI/Source/PolyUITreeContainer.cpp
  64. 2 4
      Modules/Contents/UI/Source/PolyUIVScrollBar.cpp
  65. 1 2
      Modules/Contents/UI/Source/PolyUIWindow.cpp

+ 2 - 2
Assets/Templates/C++/Windows/Polycode.props

@@ -28,8 +28,8 @@
       <SubSystem>Windows</SubSystem>
     </Link>
     <PostBuildEvent>
-      <Command>if not exist "$(SolutionDir)default.pak" copy "$(PolycodeDir)Core\Assets\default.pak" "$(SolutionDir)"
-if not exist "$(SolutionDir)hdr.pak" copy "$(PolycodeDir)Core\Assets\hdr.pak" "$(SolutionDir)"
+      <Command>if not exist "$(ProjectDir)default.pak" copy "$(PolycodeDir)Core\Assets\default.pak" "$(ProjectDir)"
+if not exist "$(ProjectDir)hdr.pak" copy "$(PolycodeDir)Core\Assets\hdr.pak" "$(ProjectDir)"
 
 if "$(ConfigurationName)" == "Debug" (
   if not exist "$(TargetDir)OpenAL32d.dll" copy "$(PolycodeDir)Core\Dependencies\bin\OpenAL32d.dll" "$(TargetDir)"

+ 1 - 1
Bindings/Contents/LUA/API/class.lua

@@ -353,7 +353,7 @@ function Object:class()
 end
 
 function Object:__eq__(other)
-  return rawequal(self,other)
+  return rawequal(self,other) or (self.__ptr and other.__ptr and self.__ptr == other.__ptr)
 end
 
 function Object:__newindex__(name,value)

+ 415 - 316
Bindings/Scripts/create_lua_library/create_lua_library.py

@@ -5,7 +5,8 @@ import errno
 import re
 from zipfile import *
 import fnmatch
-  
+import re
+
 def mkdir_p(path): # Same effect as mkdir -p, create dir and all necessary parent dirs
 	try:
 		os.makedirs(path)
@@ -14,152 +15,212 @@ def mkdir_p(path): # Same effect as mkdir -p, create dir and all necessary paren
 			pass
 		else: raise
 
-def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, apiPath, apiClassPath, includePath, sourcePath):
+# Note we expect className to be a valid string
+def template_returnPtrLookup(prefix, className, ptr):
 	out = ""
-	sout = ""
+	out += "%sif __ptr_lookup[%s][%s] ~= nil then\n" % (prefix, className, ptr)
+	out += "%s\treturn __ptr_lookup[%s][%s]\n" % (prefix, className, ptr)
+	out += "%selse\n" % (prefix)
+	out += "%s\t__ptr_lookup[%s][%s] = _G[%s](\"__skip_ptr__\")\n" % (prefix, className, ptr, className)
+	out += "%s\t__ptr_lookup[%s][%s].__ptr = %s\n" % (prefix, className, ptr, ptr)
+	out += "%s\treturn __ptr_lookup[%s][%s]\n" % (prefix, className, ptr)
+	out += "%send\n" % (prefix)
+	return out
+	
+def template_quote(str):
+	return "\"%s\"" % str;
+
+# FIXME: Some "unsigned int *" functions are still being generated on the polycode API?
+def typeFilter(ty):
+	ty = ty.replace("Polycode::", "")
+	ty = ty.replace("std::", "")
+	ty = ty.replace("const", "")
+	ty = ty.replace("&", "")
+	ty = re.sub(r'^.*\sint\s*$', 'int', ty) # eg "unsigned int"
+	ty = re.sub(r'^.*\slong\s*$', 'int', ty)
+	ty = re.sub(r'^.*\sfloat\s*$', 'Number', ty)
+	ty = re.sub(r'^.*\sdouble\s*$', 'Number', ty) # eg "long double"
+	ty = ty.replace("unsigned", "int")
+	ty = ty.replace("long", "int")
+	ty = ty.replace("float", "Number")
+	ty = ty.replace("double", "Number")
+	ty = ty.replace(" ", "") # Not very safe!
+	return ty
+
+def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, apiPath, apiClassPath, includePath, sourcePath, inheritInModuleFiles):
+	wrappersHeaderOut = "" # Def: Global C++ *LUAWrappers.h
+	cppRegisterOut = "" # Def: Global C++ *LUA.cpp
 	
-	lfout = ""
+	luaIndexOut = "" # Def: Global Lua everything-gets-required-from-this-file file
 	
-	sout += "#include \"%sLUA.h\"\n" % (prefix)
-	sout += "#include \"%sLUAWrappers.h\"\n" % (prefix)
-	sout += "#include \"PolyCoreServices.h\"\n\n"
-	sout += "using namespace Polycode;\n\n"
-	sout += "int luaopen_%s(lua_State *L) {\n" % (prefix)
+	# Header boilerplate for wrappersHeaderOut and cppRegisterOut
+	cppRegisterOut += "#include \"%sLUA.h\"\n" % (prefix)
+	cppRegisterOut += "#include \"%sLUAWrappers.h\"\n" % (prefix)
+	cppRegisterOut += "#include \"PolyCoreServices.h\"\n\n"
+	cppRegisterOut += "using namespace Polycode;\n\n"
+	cppRegisterOut += "int luaopen_%s(lua_State *L) {\n" % (prefix)
 	if prefix != "Polycode":
-		sout += "CoreServices *inst = (CoreServices*)lua_topointer(L, 1);\n"
-		sout += "CoreServices::setInstance(inst);\n"
-	sout += "\tstatic const struct luaL_reg %sLib [] = {" % (libSmallName)
+		cppRegisterOut += "CoreServices *inst = (CoreServices*)lua_topointer(L, 1);\n"
+		cppRegisterOut += "CoreServices::setInstance(inst);\n"
+	cppRegisterOut += "\tstatic const struct luaL_reg %sLib [] = {" % (libSmallName)
 	
-	out += "#pragma once\n\n"
-
-	out += "extern \"C\" {\n\n"
-	out += "#include <stdio.h>\n"
-	out += "#include \"lua.h\"\n"
-	out += "#include \"lualib.h\"\n"
-	out += "#include \"lauxlib.h\"\n"
-	out += "} // extern \"C\" \n\n"
-
-	files = os.listdir(inputPath)
+	wrappersHeaderOut += "#pragma once\n\n"
+
+	wrappersHeaderOut += "extern \"C\" {\n\n"
+	wrappersHeaderOut += "#include <stdio.h>\n"
+	wrappersHeaderOut += "#include \"lua.h\"\n"
+	wrappersHeaderOut += "#include \"lualib.h\"\n"
+	wrappersHeaderOut += "#include \"lauxlib.h\"\n"
+	wrappersHeaderOut += "} // extern \"C\" \n\n"
+
+	# Get list of headers to create bindings from
+	inputPathIsDir = os.path.isdir(inputPath)
+	if inputPathIsDir:
+		files = os.listdir(inputPath)
+	else:
+		files = []
+		with open(inputPath) as f:
+			for line in f.readlines():
+				files.append(line.strip()) # Strip whitespace, path/
 	filteredFiles = []
 	for fileName in files:
+		if inputPathIsDir:
+			fileName = "%s/%s" % (inputPath, fileName)
+		head, tail = os.path.split(fileName)
 		ignore = ["PolyGLSLProgram", "PolyGLSLShader", "PolyGLSLShaderModule", "PolyWinCore", "PolyCocoaCore", "PolyAGLCore", "PolySDLCore", "Poly_iPhone", "PolyGLES1Renderer", "PolyGLRenderer", "tinyxml", "tinystr", "OpenGLCubemap", "PolyiPhoneCore", "PolyGLES1Texture", "PolyGLTexture", "PolyGLVertexBuffer", "PolyThreaded", "PolyGLHeaders", "GLee"]
-		if fileName.split(".")[1] == "h" and fileName.split(".")[0] not in ignore:
+		if tail.split(".")[1] == "h" and tail.split(".")[0] not in ignore:
 			filteredFiles.append(fileName)
-			out += "#include \"%s\"\n" % (fileName)
+			wrappersHeaderOut += "#include \"%s\"\n" % (tail)
 
-	out += "\nusing namespace std;\n\n"
-	out += "\nnamespace Polycode {\n\n"
+	wrappersHeaderOut += "\nusing namespace std;\n\n"
+	wrappersHeaderOut += "\nnamespace Polycode {\n\n"
 	
+	# Special case: If we are building the Polycode library itself, inject the LuaEventHandler class.
+	# Note: so that event callbacks can work, any object inheriting from EventHandler will secretly
+	# be modified to actually inherit from LuaEventHandler instead.
 	if prefix == "Polycode":
-		out += "class LuaEventHandler : public EventHandler {\n"
-		out += "public:\n"
-		out += "	LuaEventHandler() : EventHandler() {}\n"
-		out += "	void handleEvent(Event *e) {\n"
-		out += "		lua_rawgeti( L, LUA_REGISTRYINDEX, wrapperIndex );\n"
-		out += "		lua_getfield(L, -1, \"__handleEvent\");\n"
-		out += "		lua_rawgeti( L, LUA_REGISTRYINDEX, wrapperIndex );\n"
-		out += "		lua_pushlightuserdata(L, e);\n"
-		out += "		if(lua_pcall(L, 2, 0, 0) != 0) {\n"
-		out += "			const char *msg = lua_tostring(L, -1);\n"
-		out += "			lua_getfield(L, LUA_GLOBALSINDEX, \"__customError\");\n"
-		out += "			lua_pushstring(L, msg);\n"
-		out += "			lua_call(L, 1, 0);\n"
-		out += "		}\n"
-		out += "	}\n"
-		out += "	int wrapperIndex;\n"
-		out += "	lua_State *L;\n"
-		out += "};\n\n"
+		wrappersHeaderOut += "class LuaEventHandler : public EventHandler {\n"
+		wrappersHeaderOut += "public:\n"
+		wrappersHeaderOut += "	LuaEventHandler() : EventHandler() {}\n"
+		wrappersHeaderOut += "	void handleEvent(Event *e) {\n"
+		wrappersHeaderOut += "		lua_rawgeti( L, LUA_REGISTRYINDEX, wrapperIndex );\n"
+		wrappersHeaderOut += "		lua_getfield(L, -1, \"__handleEvent\");\n"
+		wrappersHeaderOut += "		lua_rawgeti( L, LUA_REGISTRYINDEX, wrapperIndex );\n"
+		wrappersHeaderOut += "		lua_pushlightuserdata(L, e);\n"
+		wrappersHeaderOut += "		if(lua_pcall(L, 2, 0, 0) != 0) {\n"
+		wrappersHeaderOut += "			const char *msg = lua_tostring(L, -1);\n"
+		wrappersHeaderOut += "			lua_getfield(L, LUA_GLOBALSINDEX, \"__customError\");\n"
+		wrappersHeaderOut += "			lua_pushstring(L, msg);\n"
+		wrappersHeaderOut += "			lua_call(L, 1, 0);\n"
+		wrappersHeaderOut += "		}\n"
+		wrappersHeaderOut += "	}\n"
+		wrappersHeaderOut += "	int wrapperIndex;\n"
+		wrappersHeaderOut += "	lua_State *L;\n"
+		wrappersHeaderOut += "};\n\n"
 	
+	# Iterate, process each input file
 	for fileName in filteredFiles:
+		# "Package owned" classes that ship with Polycode
 		inheritInModule = ["PhysicsSceneEntity", "CollisionScene", "CollisionSceneEntity"]
-		headerFile = "%s/%s" % (inputPath, fileName)
+		
+		# A file or comma-separated list of files can be given to specify classes which are "package owned"
+		# and should not be inherited out of Polycode/. The files should contain one class name per line,
+		# and the class name may be prefixed with a path (which will be ignored).
+		if inheritInModuleFiles:
+			for moduleFileName in inheritInModuleFiles.split(","):
+				with open(moduleFileName) as f:
+					for line in f.readlines():
+						inheritInModule.append(line.strip().split("/",1)[-1]) # Strip whitespace, path/
+		
 		print "Parsing %s" % fileName
-		try:
-			f = open(headerFile)
-			contents = f.read().replace("_PolyExport", "")
-			cppHeader = CppHeaderParser.CppHeader(contents, "string")
+		try: # One input file parse.
+			f = open(fileName) # Def: Input file handle
+			contents = f.read().replace("_PolyExport", "") # Def: Input file contents, strip out "_PolyExport"
+			cppHeader = CppHeaderParser.CppHeader(contents, "string") # Def: Input file contents, parsed structure
 			ignore_classes = ["PolycodeShaderModule", "Object", "Threaded", "OpenGLCubemap", "ParticleEmitter"]
 
-			for ckey in cppHeader.classes:
+			# Iterate, check each class in this file.
+			for ckey in cppHeader.classes: 
 				print ">> Parsing class %s" % ckey
-				c = cppHeader.classes[ckey]
-	#			if ckey == "ParticleEmitter":
-	#				print c
-				lout = ""
+				c = cppHeader.classes[ckey] # Def: The class structure
+
+				luaClassBindingOut = "" # Def: The local lua file to generate for this class.
 				inherits = False
-				if len(c["inherits"]) > 0:
+				if len(c["inherits"]) > 0: # Does this class have parents?
 					if c["inherits"][0]["class"] not in ignore_classes:
-						if c["inherits"][0]["class"] in inheritInModule:
-							lout += "require \"%s/%s\"\n\n" % (prefix, c["inherits"][0]["class"])
-						else:
-							lout += "require \"Polycode/%s\"\n\n" % (c["inherits"][0]["class"])
-						lout += "class \"%s\" (%s)\n\n" % (ckey, c["inherits"][0]["class"])
+						if c["inherits"][0]["class"] in inheritInModule: # Parent class is in this module
+							luaClassBindingOut += "require \"%s/%s\"\n\n" % (prefix, c["inherits"][0]["class"])
+						else: # Parent class is in Polycore
+							luaClassBindingOut += "require \"Polycode/%s\"\n\n" % (c["inherits"][0]["class"])
+						luaClassBindingOut += "class \"%s\" (%s)\n\n" % (ckey, c["inherits"][0]["class"])
 						inherits = True
-				if inherits == False:
-					lout += "class \"%s\"\n\n" % ckey
+				if inherits == False: # Class does not have parents
+					luaClassBindingOut += "class \"%s\"\n\n" % ckey
 
-				if len(c["methods"]["public"]) < 2 or ckey in ignore_classes:
+				if ckey in ignore_classes:
 					continue
 
-				if ckey == "OSFileEntry":
-					print c["methods"]["public"]
-				parsed_methods = []
+				if len(c["methods"]["public"]) < 2: # Used to, this was a continue.
+					print("Warning: Lua-binding class with less than two methods")
+					continue # FIXME: Remove this, move any non-compileable classes into ignore_classes
+
+				parsed_methods = [] # Def: List of discovered methods
 				ignore_methods = ["readByte32", "readByte16", "getCustomEntitiesByType", "Core", "Renderer", "Shader", "Texture", "handleEvent", "secondaryHandler", "getSTLString"]
-				lout += "\n\n"
+				luaClassBindingOut += "\n\n"
 
-				pps = []
+				classProperties = [] # Def: List of found property structures ("properties" meaning "data members")
 				for pp in c["properties"]["public"]:
 					pp["type"] = pp["type"].replace("Polycode::", "")
 					pp["type"] = pp["type"].replace("std::", "")
-					if pp["type"].find("static ") != -1:
-						if "defaltValue" in pp:
-							lout += "%s = %s\n" % (pp["name"], pp["defaltValue"])
-					else:
+					if pp["type"].find("POLYIGNORE") != -1:
+						continue
+					if pp["type"].find("static ") != -1: # If static. FIXME: Static doesn't work?
+						if "defaltValue" in pp: # FIXME: defaltValue is misspelled.
+							luaClassBindingOut += "%s = %s\n" % (pp["name"], pp["defaltValue"])
+					else: # FIXME: Nonstatic method ? variable ?? found.
 						#there are some bugs in the class parser that cause it to return junk
-						if pp["type"].find("*") == -1 and pp["type"].find("vector") == -1 and pp["name"] != "16" and pp["name"] != "setScale" and pp["name"] != "setPosition" and pp["name"] != "BUFFER_CACHE_PRECISION":
-							pps.append(pp)
-						#if pp["type"] == "Number" or  pp["type"] == "String" or pp["type"] == "int" or pp["type"] == "bool":
-						#	pps.append(pp)
-						#else:
-						#	print(">>> Skipping %s[%s %s]" % (ckey, pp["type"], pp["name"]))
-
-				pidx = 0
-
-				# hack to fix the lack of multiple inheritance
-				#if ckey == "ScreenParticleEmitter" or ckey == "SceneParticleEmitter":
-				#		pps.append({"name": "emitter", "type": "ParticleEmitter"})
-
-				if len(pps) > 0:
-					lout += "function %s:__index__(name)\n" % ckey
-					for pp in pps:
-						pp["type"] = pp["type"].replace("Polycode::", "")
-						pp["type"] = pp["type"].replace("std::", "")
+						if pp["type"].find("*") == -1 and pp["type"].find("vector") == -1 and pp["name"] != "setScale" and pp["name"] != "setPosition" and pp["name"] != "BUFFER_CACHE_PRECISION" and not pp["name"].isdigit():
+							classProperties.append(pp)
+
+				# Iterate over properties, creating getters
+				pidx = 0 # Def: Count of properties processed so far
+
+				# TODO: Remove or generalize ParticleEmitter special casing. These lines are marked with #SPEC
+
+				if len(classProperties) > 0: # If there are properties, add index lookup to the metatable
+					luaClassBindingOut += "function %s:__index__(name)\n" % ckey
+					# Iterate over property structures, creating if/else clauses for each.
+					# TODO: Could a table be more appropriate for 
+					for pp in classProperties:
+						pp["type"] = typeFilter(pp["type"])
 						if pidx == 0:
-							lout += "\tif name == \"%s\" then\n" % (pp["name"])
+							luaClassBindingOut += "\tif name == \"%s\" then\n" % (pp["name"])
 						else:
-							lout += "\telseif name == \"%s\" then\n" % (pp["name"])
+							luaClassBindingOut += "\telseif name == \"%s\" then\n" % (pp["name"])
+
+						# Generate Lua side of binding:
 
+						# If type is a primitive such as Number/String/int/bool
 						if pp["type"] == "Number" or  pp["type"] == "String" or pp["type"] == "int" or pp["type"] == "bool":
-							lout += "\t\treturn %s.%s_get_%s(self.__ptr)\n" % (libName, ckey, pp["name"])
+							luaClassBindingOut += "\t\treturn %s.%s_get_%s(self.__ptr)\n" % (libName, ckey, pp["name"])
+							
+						# If type is a particle emitter, specifically #SPEC
 						elif (ckey == "ScreenParticleEmitter" or ckey == "SceneParticleEmitter") and pp["name"] == "emitter":
-							lout += "\t\tlocal ret = %s(\"__skip_ptr__\")\n" % (pp["type"])
-							lout += "\t\tret.__ptr = self.__ptr\n"
-							lout += "\t\treturn ret\n"
+							luaClassBindingOut += "\t\tlocal ret = %s(\"__skip_ptr__\")\n" % (pp["type"])
+							luaClassBindingOut += "\t\tret.__ptr = self.__ptr\n"
+							luaClassBindingOut += "\t\treturn ret\n"
+							
+						# If type is a class
 						else:
-							lout += "\t\tretVal = %s.%s_get_%s(self.__ptr)\n" % (libName, ckey, pp["name"])
-							lout += "\t\tif Polycore.__ptr_lookup[retVal] ~= nil then\n"
-							lout += "\t\t\treturn Polycore.__ptr_lookup[retVal]\n"
-							lout += "\t\telse\n"
-							lout += "\t\t\tPolycore.__ptr_lookup[retVal] = %s(\"__skip_ptr__\")\n" % (pp["type"])
-							lout += "\t\t\tPolycore.__ptr_lookup[retVal].__ptr = retVal\n"
-							lout += "\t\t\treturn Polycore.__ptr_lookup[retVal]\n"
-							lout += "\t\tend\n"
-
-						if not ((ckey == "ScreenParticleEmitter" or ckey == "SceneParticleEmitter") and pp["name"] == "emitter"):
-							sout += "\t\t{\"%s_get_%s\", %s_%s_get_%s},\n" % (ckey, pp["name"], libName, ckey, pp["name"])
-							out += "static int %s_%s_get_%s(lua_State *L) {\n" % (libName, ckey, pp["name"])
-							out += "\tluaL_checktype(L, 1, LUA_TLIGHTUSERDATA);\n"
-							out += "\t%s *inst = (%s*)lua_topointer(L, 1);\n" % (ckey, ckey)
+							luaClassBindingOut += "\t\tretVal = %s.%s_get_%s(self.__ptr)\n" % (libName, ckey, pp["name"])
+							luaClassBindingOut += template_returnPtrLookup("\t\t", template_quote(pp["type"]), "retVal")
+
+						# Generate C++ side of binding:
+						if not ((ckey == "ScreenParticleEmitter" or ckey == "SceneParticleEmitter") and pp["name"] == "emitter"): #SPEC
+							cppRegisterOut += "\t\t{\"%s_get_%s\", %s_%s_get_%s},\n" % (ckey, pp["name"], libName, ckey, pp["name"])
+							wrappersHeaderOut += "static int %s_%s_get_%s(lua_State *L) {\n" % (libName, ckey, pp["name"])
+							wrappersHeaderOut += "\tluaL_checktype(L, 1, LUA_TLIGHTUSERDATA);\n"
+							wrappersHeaderOut += "\t%s *inst = (%s*)lua_topointer(L, 1);\n" % (ckey, ckey)
 
 							outfunc = "lua_pushlightuserdata"
 							retFunc = ""
@@ -174,35 +235,40 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 								outfunc = "lua_pushboolean"
 
 							if pp["type"] == "Number" or  pp["type"] == "String" or pp["type"] == "int" or pp["type"] == "bool":
-								out += "\t%s(L, inst->%s%s);\n" % (outfunc, pp["name"], retFunc)
+								wrappersHeaderOut += "\t%s(L, inst->%s%s);\n" % (outfunc, pp["name"], retFunc)
 							else:
-								out += "\t%s(L, &inst->%s%s);\n" % (outfunc, pp["name"], retFunc)
-							out += "\treturn 1;\n"
-							out += "}\n\n"
+								wrappersHeaderOut += "\t%s(L, &inst->%s%s);\n" % (outfunc, pp["name"], retFunc)
+							wrappersHeaderOut += "\treturn 1;\n"
+							wrappersHeaderOut += "}\n\n"
+						
+						# Success
 						pidx = pidx + 1
 
-					lout += "\tend\n"
-					lout += "end\n"
-
-				lout += "\n\n"
-				pidx = 0
-				if len(pps) > 0:
-					lout += "function %s:__set_callback(name,value)\n" % ckey
-					for pp in pps:
-						pp["type"] = pp["type"].replace("Polycode::", "")
-						pp["type"] = pp["type"].replace("std::", "")
+					luaClassBindingOut += "\tend\n"
+					luaClassBindingOut += "end\n"
+
+				luaClassBindingOut += "\n\n"
+				
+				# Iterate over properties again, creating setters
+				pidx = 0 # Def: Count of 
+				if len(classProperties) > 0: # If there are properties, add index setter to the metatable
+					luaClassBindingOut += "function %s:__set_callback(name,value)\n" % ckey
+					for pp in classProperties:
+						pp["type"] = typeFilter(pp["type"])
+						
+						# If type is a primitive: Create lua and C++ sides at the same time.
 						if pp["type"] == "Number" or  pp["type"] == "String" or pp["type"] == "int" or pp["type"] == "bool":
 							if pidx == 0:
-								lout += "\tif name == \"%s\" then\n" % (pp["name"])
+								luaClassBindingOut += "\tif name == \"%s\" then\n" % (pp["name"])
 							else:
-								lout += "\telseif name == \"%s\" then\n" % (pp["name"])
-							lout += "\t\t%s.%s_set_%s(self.__ptr, value)\n" % (libName, ckey, pp["name"])
-							lout += "\t\treturn true\n"
+								luaClassBindingOut += "\telseif name == \"%s\" then\n" % (pp["name"])
+							luaClassBindingOut += "\t\t%s.%s_set_%s(self.__ptr, value)\n" % (libName, ckey, pp["name"])
+							luaClassBindingOut += "\t\treturn true\n"
 
-							sout += "\t\t{\"%s_set_%s\", %s_%s_set_%s},\n" % (ckey, pp["name"], libName, ckey, pp["name"])
-							out += "static int %s_%s_set_%s(lua_State *L) {\n" % (libName, ckey, pp["name"])
-							out += "\tluaL_checktype(L, 1, LUA_TLIGHTUSERDATA);\n"
-							out += "\t%s *inst = (%s*)lua_topointer(L, 1);\n" % (ckey, ckey)
+							cppRegisterOut += "\t\t{\"%s_set_%s\", %s_%s_set_%s},\n" % (ckey, pp["name"], libName, ckey, pp["name"])
+							wrappersHeaderOut += "static int %s_%s_set_%s(lua_State *L) {\n" % (libName, ckey, pp["name"])
+							wrappersHeaderOut += "\tluaL_checktype(L, 1, LUA_TLIGHTUSERDATA);\n"
+							wrappersHeaderOut += "\t%s *inst = (%s*)lua_topointer(L, 1);\n" % (ckey, ckey)
 
 							outfunc = "lua_topointer"
 							if pp["type"] == "Number":
@@ -214,40 +280,58 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 							if pp["type"] == "bool":
 								outfunc = "lua_toboolean"
 
-							out += "\t%s param = %s(L, 2);\n" % (pp["type"], outfunc)
-							out += "\tinst->%s = param;\n" % (pp["name"])
+							wrappersHeaderOut += "\t%s param = %s(L, 2);\n" % (pp["type"], outfunc)
+							wrappersHeaderOut += "\tinst->%s = param;\n" % (pp["name"])
 
-							out += "\treturn 0;\n"
-							out += "}\n\n"
-							pidx = pidx + 1
+							wrappersHeaderOut += "\treturn 0;\n"
+							wrappersHeaderOut += "}\n\n"
+							pidx = pidx + 1 # Success
+							
+						# Notice: Setters for object types are not created.
 					if pidx != 0:
-						lout += "\tend\n"
-					lout += "\treturn false\n"
-					lout += "end\n"
+						luaClassBindingOut += "\tend\n"
+					luaClassBindingOut += "\treturn false\n"
+					luaClassBindingOut += "end\n"
 
-
-				lout += "\n\n"
+				# Iterate over methods
+				luaClassBindingOut += "\n\n"
 				for pm in c["methods"]["public"]:
-					if pm["name"] in parsed_methods or pm["name"].find("operator") > -1 or pm["name"] in ignore_methods:
+					# Skip argument-overloaded methods and operators.
+					# TODO: Instead of skipping arguemnt overloads, have special behavior.
+					# TODO: Instead of skipping operators, add to metatable.
+					if pm["name"] in parsed_methods or pm["name"].find("operator") > -1 or pm["rtnType"].find("POLYIGNORE") > -1 or pm["name"] in ignore_methods:
 						continue
 
+					# Skip destructors and methods which return templates.
+					# TODO: Special-case certain kind of vector<>s?
 					if pm["name"] == "~"+ckey or pm["rtnType"].find("<") > -1:
-						out += ""
-					else:
-						basicType = False
-						voidRet = False
-						if pm["name"] == ckey:
-							sout += "\t\t{\"%s\", %s_%s},\n" % (ckey, libName, ckey)
-							out += "static int %s_%s(lua_State *L) {\n" % (libName, ckey)
-							idx = 1
-						else:
-							sout += "\t\t{\"%s_%s\", %s_%s_%s},\n" % (ckey, pm["name"], libName, ckey, pm["name"])
-							out += "static int %s_%s_%s(lua_State *L) {\n" % (libName, ckey, pm["name"])
-
-							if pm["rtnType"].find("static ") == -1:
-								out += "\tluaL_checktype(L, 1, LUA_TLIGHTUSERDATA);\n"
-								out += "\t%s *inst = (%s*)lua_topointer(L, 1);\n" % (ckey, ckey)
-							idx = 2
+						continue
+					
+					basicType = False
+					voidRet = False
+					
+					# Def: True if method takes a lua_State* as argument (i.e.: no preprocessing by us)
+					rawMethod = len(pm["parameters"]) > 0 and pm["parameters"][0].get("type","").find("lua_State") > -1
+
+					# Basic setup, C++ side: Add function to registry and start building wrapper function.
+					if pm["name"] == ckey: # It's a constructor
+						cppRegisterOut += "\t\t{\"%s\", %s_%s},\n" % (ckey, libName, ckey)
+						wrappersHeaderOut += "static int %s_%s(lua_State *L) {\n" % (libName, ckey)
+						idx = 1 # Def: Current stack depth (TODO: Figure out, is this correct?)
+					else: # It's not a constructor
+						cppRegisterOut += "\t\t{\"%s_%s\", %s_%s_%s},\n" % (ckey, pm["name"], libName, ckey, pm["name"])
+						wrappersHeaderOut += "static int %s_%s_%s(lua_State *L) {\n" % (libName, ckey, pm["name"])
+
+						# Skip static methods (TODO: Figure out, why is this being done here?). # FIXME
+						if pm["rtnType"].find("static ") == -1:
+							wrappersHeaderOut += "\tluaL_checktype(L, 1, LUA_TLIGHTUSERDATA);\n"
+							wrappersHeaderOut += "\t%s *inst = (%s*)lua_topointer(L, 1);\n" % (ckey, ckey)
+						idx = 2
+					
+					if rawMethod:
+						wrappersHeaderOut += "\treturn inst->%s(L);\n" % (pm["name"])
+					else:	
+						# Generate C++ side parameter pushing
 						paramlist = []
 						lparamlist = []
 						for param in pm["parameters"]:
@@ -255,13 +339,8 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 								continue
 							if param["type"] == "0":
 								continue
-							param["type"] = param["type"].replace("Polycode::", "")
-							param["type"] = param["type"].replace("std::", "")
-							param["type"] = param["type"].replace("const", "")
-							param["type"] = param["type"].replace("&", "")
-							param["type"] = param["type"].replace(" ", "")
-							param["type"] = param["type"].replace("long", "long ")
-							param["type"] = param["type"].replace("unsigned", "unsigned ")
+								
+							param["type"] = typeFilter(param["type"])
 
 							param["name"] = param["name"].replace("end", "_end").replace("repeat", "_repeat")
 							if"type" in param:
@@ -304,56 +383,60 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 										#param["defaltValue"] = param["defaltValue"].replace("0 ", "0.")
 										param["defaltValue"] = re.sub(r'([0-9]+) ([0-9])+', r'\1.\2', param["defaltValue"])
 
-										out += "\t%s %s;\n" % (param["type"], param["name"])
-										out += "\tif(%s(L, %d)) {\n" % (checkfunc, idx)
-										out += "\t\t%s = %s(L, %d);\n" % (param["name"], luafunc, idx)
-										out += "\t} else {\n"
-										out += "\t\t%s = %s;\n" % (param["name"], param["defaltValue"])
-										out += "\t}\n"
+										wrappersHeaderOut += "\t%s %s;\n" % (param["type"], param["name"])
+										wrappersHeaderOut += "\tif(%s(L, %d)) {\n" % (checkfunc, idx)
+										wrappersHeaderOut += "\t\t%s = %s(L, %d);\n" % (param["name"], luafunc, idx)
+										wrappersHeaderOut += "\t} else {\n"
+										wrappersHeaderOut += "\t\t%s = %s;\n" % (param["name"], param["defaltValue"])
+										wrappersHeaderOut += "\t}\n"
 									else:
-										out += "\tluaL_checktype(L, %d, %s);\n" % (idx, luatype);
+										wrappersHeaderOut += "\tluaL_checktype(L, %d, %s);\n" % (idx, luatype);
 										if param["type"] == "String":
-											out += "\t%s %s = String(%s(L, %d));\n" % (param["type"], param["name"], luafunc, idx)
+											wrappersHeaderOut += "\t%s %s = String(%s(L, %d));\n" % (param["type"], param["name"], luafunc, idx)
 										else:
-											out += "\t%s %s = %s(L, %d);\n" % (param["type"], param["name"], luafunc, idx)
+											wrappersHeaderOut += "\t%s %s = %s(L, %d);\n" % (param["type"], param["name"], luafunc, idx)
 								else:
-									out += "\tluaL_checktype(L, %d, %s);\n" % (idx, luatype);
+									wrappersHeaderOut += "\tluaL_checktype(L, %d, %s);\n" % (idx, luatype);
 									if param["type"] == "String":
-										out += "\t%s %s = String(%s(L, %d));\n" % (param["type"], param["name"], luafunc, idx)
+										wrappersHeaderOut += "\t%s %s = String(%s(L, %d));\n" % (param["type"], param["name"], luafunc, idx)
 									else:
-										out += "\t%s %s = %s(L, %d);\n" % (param["type"], param["name"], luafunc, idx)
+										wrappersHeaderOut += "\t%s %s = %s(L, %d);\n" % (param["type"], param["name"], luafunc, idx)
 								paramlist.append(param["name"])
 
 								lparamlist.append(param["name"]+lend)
-								idx = idx +1
-
-						if pm["name"] == ckey:
-							if ckey == "EventHandler":
-								out += "\tLuaEventHandler *inst = new LuaEventHandler();\n"
-								out += "\tinst->wrapperIndex = luaL_ref(L, LUA_REGISTRYINDEX );\n"
-								out += "\tinst->L = L;\n"
+								idx = idx +1 # Param parse success-- mark the increased stack
+
+						# Generate C++-side method call / generate return value
+						if pm["name"] == ckey: # If constructor
+							if ckey == "EventHandler": # See LuaEventHandler above
+								wrappersHeaderOut += "\tLuaEventHandler *inst = new LuaEventHandler();\n"
+								wrappersHeaderOut += "\tinst->wrapperIndex = luaL_ref(L, LUA_REGISTRYINDEX );\n"
+								wrappersHeaderOut += "\tinst->L = L;\n"
 							else:
-								out += "\t%s *inst = new %s(%s);\n" % (ckey, ckey, ", ".join(paramlist))
-							out += "\tlua_pushlightuserdata(L, (void*)inst);\n"
-							out += "\treturn 1;\n"
-						else:
-							if pm["rtnType"].find("static ") == -1:
+								wrappersHeaderOut += "\t%s *inst = new %s(%s);\n" % (ckey, ckey, ", ".join(paramlist))
+							wrappersHeaderOut += "\tlua_pushlightuserdata(L, (void*)inst);\n"
+							wrappersHeaderOut += "\treturn 1;\n"
+						else: #If non-constructor
+							if pm["rtnType"].find("static ") == -1: # If non-static
 								call = "inst->%s(%s)" % (pm["name"], ", ".join(paramlist))
-							else:
+							else: # If static (FIXME: Why doesn't this work?)
 								call = "%s::%s(%s)" % (ckey, pm["name"], ", ".join(paramlist))
+							
+							# If void-typed:
 							if pm["rtnType"] == "void" or pm["rtnType"] == "static void" or pm["rtnType"] == "virtual void" or pm["rtnType"] == "inline void":
-								out += "\t%s;\n" % (call)
+								wrappersHeaderOut += "\t%s;\n" % (call)
 								basicType = True
 								voidRet = True
-								out += "\treturn 0;\n"
-							else:
+								wrappersHeaderOut += "\treturn 0;\n" # 0 arguments returned
+							else: # If there is a return value:
+								# What type is the return value? Default to pointer
 								outfunc = "lua_pushlightuserdata"
 								retFunc = ""
 								basicType = False
 								if pm["rtnType"] == "Number" or  pm["rtnType"] == "inline Number":
 									outfunc = "lua_pushnumber"
 									basicType = True
-								if pm["rtnType"] == "String" or pm["rtnType"] == "static String":
+								if pm["rtnType"] == "String" or pm["rtnType"] == "static String": # TODO: Path for STL strings?
 									outfunc = "lua_pushstring"
 									basicType = True
 									retFunc = ".c_str()"
@@ -364,156 +447,172 @@ def createLUABindings(inputPath, prefix, mainInclude, libSmallName, libName, api
 									outfunc = "lua_pushboolean"
 									basicType = True
 
-								if pm["rtnType"].find("*") > -1:
-									out += "\tvoid *ptrRetVal = (void*)%s%s;\n" % (call, retFunc)
-									out += "\tif(ptrRetVal == NULL) {\n"
-									out += "\t\tlua_pushnil(L);\n"
-									out += "\t} else {\n"
-									out += "\t\t%s(L, ptrRetVal);\n" % (outfunc)
-									out += "\t}\n"
-								elif basicType == True:
-									out += "\t%s(L, %s%s);\n" % (outfunc, call, retFunc)
-								else:
+								if pm["rtnType"].find("*") > -1: # Returned var is definitely a pointer.
+									wrappersHeaderOut += "\tvoid *ptrRetVal = (void*)%s%s;\n" % (call, retFunc)
+									wrappersHeaderOut += "\tif(ptrRetVal == NULL) {\n"
+									wrappersHeaderOut += "\t\tlua_pushnil(L);\n"
+									wrappersHeaderOut += "\t} else {\n"
+									wrappersHeaderOut += "\t\t%s(L, ptrRetVal);\n" % (outfunc)
+									wrappersHeaderOut += "\t}\n"
+								elif basicType == True: # Returned var has been flagged as a recognized primitive type
+									wrappersHeaderOut += "\t%s(L, %s%s);\n" % (outfunc, call, retFunc)
+								else: # Some static object is being returned. Convert it to a pointer, then return that.
 									className = pm["rtnType"].replace("const", "").replace("&", "").replace("inline", "").replace("virtual", "").replace("static", "")
-									if className == "Polygon":
+									if className == "Polygon": # Deal with potential windows.h conflict
 										className = "Polycode::Polygon"
 									if className == "Rectangle":
 										className = "Polycode::Rectangle"
-									out += "\t%s *retInst = new %s();\n" % (className, className)
-									out += "\t*retInst = %s;\n" % (call)
-									out += "\t%s(L, retInst);\n" % (outfunc)
-								out += "\treturn 1;\n"
-						out += "}\n\n"
-
-						if pm["name"] == ckey:
-							lout += "function %s:%s(...)\n" % (ckey, ckey)
-							if inherits:
-								lout += "\tif type(arg[1]) == \"table\" and count(arg) == 1 then\n"
-								lout += "\t\tif \"\"..arg[1]:class() == \"%s\" then\n" % (c["inherits"][0]["class"])
-								lout += "\t\t\tself.__ptr = arg[1].__ptr\n"
-								lout += "\t\t\treturn\n"
-								lout += "\t\tend\n"
-								lout += "\tend\n"
-							lout += "\tfor k,v in pairs(arg) do\n"
-							lout += "\t\tif type(v) == \"table\" then\n"
-							lout += "\t\t\tif v.__ptr ~= nil then\n"
-							lout += "\t\t\t\targ[k] = v.__ptr\n"
-							lout += "\t\t\tend\n"
-							lout += "\t\tend\n"
-							lout += "\tend\n"
-							lout += "\tif self.__ptr == nil and arg[1] ~= \"__skip_ptr__\" then\n"
-							if ckey == "EventHandler":
-								lout += "\t\tself.__ptr = %s.%s(self)\n" % (libName, ckey)
-							else:
-								lout += "\t\tself.__ptr = %s.%s(unpack(arg))\n" % (libName, ckey)
-							lout += "\t\tPolycore.__ptr_lookup[self.__ptr] = self\n"
-							lout += "\tend\n"
-							lout += "end\n\n"
+									wrappersHeaderOut += "\t%s *retInst = new %s();\n" % (className, className)
+									wrappersHeaderOut += "\t*retInst = %s;\n" % (call)
+									wrappersHeaderOut += "\t%s(L, retInst);\n" % (outfunc)
+								wrappersHeaderOut += "\treturn 1;\n"
+					wrappersHeaderOut += "}\n\n" # Close out C++ generation
+
+					# Now generate the Lua side method.
+					if rawMethod:
+						luaClassBindingOut += "function %s:%s(...)\n" % (ckey, pm["name"])
+						luaClassBindingOut += "\treturn %s.%s_%s(self.__ptr, ...)\n" % (libName, ckey, pm["name"])
+						luaClassBindingOut += "end\n"
+					elif pm["name"] == ckey: # Constructors
+						luaClassBindingOut += "function %s:%s(...)\n" % (ckey, ckey)
+						if inherits:
+							luaClassBindingOut += "\tif type(arg[1]) == \"table\" and count(arg) == 1 then\n"
+							luaClassBindingOut += "\t\tif \"\"..arg[1]:class() == \"%s\" then\n" % (c["inherits"][0]["class"])
+							luaClassBindingOut += "\t\t\tself.__ptr = arg[1].__ptr\n"
+							luaClassBindingOut += "\t\t\treturn\n"
+							luaClassBindingOut += "\t\tend\n"
+							luaClassBindingOut += "\tend\n"
+						luaClassBindingOut += "\tfor k,v in pairs(arg) do\n"
+						luaClassBindingOut += "\t\tif type(v) == \"table\" then\n"
+						luaClassBindingOut += "\t\t\tif v.__ptr ~= nil then\n"
+						luaClassBindingOut += "\t\t\t\targ[k] = v.__ptr\n"
+						luaClassBindingOut += "\t\t\tend\n"
+						luaClassBindingOut += "\t\tend\n"
+						luaClassBindingOut += "\tend\n"
+						luaClassBindingOut += "\tif self.__ptr == nil and arg[1] ~= \"__skip_ptr__\" then\n"
+						if ckey == "EventHandler": # See LuaEventHandler above
+							luaClassBindingOut += "\t\tself.__ptr = %s.%s(self)\n" % (libName, ckey)
 						else:
-							lout += "function %s:%s(%s)\n" % (ckey, pm["name"], ", ".join(paramlist))
-							if pm["rtnType"].find("static ") == -1:
-								if len(lparamlist):
-									lout += "\tlocal retVal = %s.%s_%s(self.__ptr, %s)\n" % (libName, ckey, pm["name"], ", ".join(lparamlist))
-								else:
-									lout += "\tlocal retVal =  %s.%s_%s(self.__ptr)\n" % (libName, ckey, pm["name"])
+							luaClassBindingOut += "\t\tself.__ptr = %s.%s(unpack(arg))\n" % (libName, ckey)
+						luaClassBindingOut += "\t\t__ptr_lookup.%s[self.__ptr] = self\n" % (ckey)
+						luaClassBindingOut += "\tend\n"
+						luaClassBindingOut += "end\n\n"
+					else: # Non-constructors.
+						luaClassBindingOut += "function %s:%s(%s)\n" % (ckey, pm["name"], ", ".join(paramlist))
+						if pm["rtnType"].find("static ") == -1: # Non-static method
+							if len(lparamlist):
+								luaClassBindingOut += "\tlocal retVal = %s.%s_%s(self.__ptr, %s)\n" % (libName, ckey, pm["name"], ", ".join(lparamlist))
 							else:
-								if len(lparamlist):
-									lout += "\tlocal retVal = %s.%s_%s(%s)\n" % (libName, ckey, pm["name"], ", ".join(lparamlist))
-								else:
-									lout += "\tlocal retVal =  %s.%s_%s()\n" % (libName, ckey, pm["name"])
-
-							if not voidRet:
-								if basicType == True:
-									lout += "\treturn retVal\n"
-								else:
-									className = pm["rtnType"].replace("const", "").replace("&", "").replace("inline", "").replace("virtual", "").replace("static", "").replace("*","").replace(" ", "")
-									lout += "\tif retVal == nil then return nil end\n"
-									lout += "\tif Polycore.__ptr_lookup[retVal] ~= nil then\n"
-									lout += "\t\treturn Polycore.__ptr_lookup[retVal]\n"
-									lout += "\telse\n"
-									lout += "\t\tPolycore.__ptr_lookup[retVal] = %s(\"__skip_ptr__\")\n" % (className)
-									lout += "\t\tPolycore.__ptr_lookup[retVal].__ptr = retVal\n"
-									lout += "\t\treturn Polycore.__ptr_lookup[retVal]\n"
-									lout += "\tend\n"
-							lout += "end\n\n"
-
-					parsed_methods.append(pm["name"])
-
-				#cleanup
-				sout += "\t\t{\"delete_%s\", %s_delete_%s},\n" % (ckey, libName, ckey)
-				out += "static int %s_delete_%s(lua_State *L) {\n" % (libName, ckey)
-				out += "\tluaL_checktype(L, 1, LUA_TLIGHTUSERDATA);\n"
-				out += "\t%s *inst = (%s*)lua_topointer(L, 1);\n" % (ckey, ckey)
-				out += "\tdelete inst;\n"
-				out += "\treturn 0;\n"
-				out += "}\n\n"
-
-				lout += "\n\n"
-				lout += "function %s:__delete()\n" % (ckey)
-				lout += "\tPolycore.__ptr_lookup[self.__ptr] = nil\n"
-				lout += "\t%s.delete_%s(self.__ptr)\n" % (libName, ckey)
-				lout += "end\n"
-				if ckey == "EventHandler":
-					lout += "\n\n"
-					lout += "function EventHandler:__handleEvent(event)\n"
-					lout += "\tevt = Event(\"__skip_ptr__\")\n"
-					lout += "\tevt.__ptr = event\n"
-					lout += "\tself:handleEvent(evt)\n"
-					#lout += "\tself:handleEvent(event)\n"
-					lout += "end\n"
-				lfout += "require \"%s/%s\"\n" % (prefix, ckey)
+								luaClassBindingOut += "\tlocal retVal =  %s.%s_%s(self.__ptr)\n" % (libName, ckey, pm["name"])
+						else: # Static method
+							if len(lparamlist):
+								luaClassBindingOut += "\tlocal retVal = %s.%s_%s(%s)\n" % (libName, ckey, pm["name"], ", ".join(lparamlist))
+							else:
+								luaClassBindingOut += "\tlocal retVal =  %s.%s_%s()\n" % (libName, ckey, pm["name"])
+
+						if not voidRet: # Was there a return value?
+							if basicType == True: # Yes, a primitive
+								luaClassBindingOut += "\treturn retVal\n"
+							else: # Yes, a pointer was returned
+								className = pm["rtnType"].replace("const", "").replace("&", "").replace("inline", "").replace("virtual", "").replace("static", "").replace("*","").replace(" ", "")
+								luaClassBindingOut += "\tif retVal == nil then return nil end\n"
+								luaClassBindingOut += template_returnPtrLookup("\t",template_quote(className),"retVal")
+						luaClassBindingOut += "end\n\n" # Close out Lua generation
+
+					parsed_methods.append(pm["name"]) # Method parse success
+
+				# With methods out of the way, do some final cleanup:
+				
+				# Delete method (C++ side)
+				cppRegisterOut += "\t\t{\"delete_%s\", %s_delete_%s},\n" % (ckey, libName, ckey)
+				wrappersHeaderOut += "static int %s_delete_%s(lua_State *L) {\n" % (libName, ckey)
+				wrappersHeaderOut += "\tluaL_checktype(L, 1, LUA_TLIGHTUSERDATA);\n"
+				wrappersHeaderOut += "\t%s *inst = (%s*)lua_topointer(L, 1);\n" % (ckey, ckey)
+				wrappersHeaderOut += "\tdelete inst;\n"
+				wrappersHeaderOut += "\treturn 0;\n"
+				wrappersHeaderOut += "}\n\n"
+
+				# Delete method (Lua side)
+				luaClassBindingOut += "\n\n"
+				luaClassBindingOut += "if not __ptr_lookup then __ptr_lookup = {} end\n"
+				luaClassBindingOut += "__ptr_lookup.%s = {}\n\n" % (ckey)
+				luaClassBindingOut += "function %s:__delete()\n" % (ckey)
+				luaClassBindingOut += "\t__ptr_lookup.%s[self.__ptr] = nil\n" % (ckey)
+				luaClassBindingOut += "\t%s.delete_%s(self.__ptr)\n" % (libName, ckey)
+				luaClassBindingOut += "end\n"
+				if ckey == "EventHandler": # See LuaEventHandler above
+					luaClassBindingOut += "\n\n"
+					luaClassBindingOut += "function EventHandler:__handleEvent(event)\n"
+					luaClassBindingOut += "\tevt = Event(\"__skip_ptr__\")\n"
+					luaClassBindingOut += "\tevt.__ptr = event\n"
+					luaClassBindingOut += "\tself:handleEvent(evt)\n"
+					#luaClassBindingOut += "\tself:handleEvent(event)\n"
+					luaClassBindingOut += "end\n\n"
+					
+					# Let's use this opportunity to put in some other "generated" utility functions.
+					luaClassBindingOut += "function __ptrToTable(className, ptr)\n"
+					luaClassBindingOut += template_returnPtrLookup("\t","className","ptr")
+					luaClassBindingOut += "end\n\n"
+					
+				# Add class to lua index file
+				luaIndexOut += "require \"%s/%s\"\n" % (prefix, ckey)
+				# Write lua file
 				mkdir_p(apiClassPath)
 				fout = open("%s/%s.lua" % (apiClassPath, ckey), "w")
-				fout.write(lout)
-		except CppHeaderParser.CppParseError,  e:
+				fout.write(luaClassBindingOut)
+		except CppHeaderParser.CppParseError,  e: # One input file parse; failed.
 			print e
 			sys.exit(1)
 
-	out += "} // namespace Polycode\n"
+	# Footer boilerplate for wrappersHeaderOut and cppRegisterOut.
+	wrappersHeaderOut += "} // namespace Polycode\n"
 	
-	sout += "\t\t{NULL, NULL}\n"
-	sout += "\t};\n"
-	sout += "\tluaL_openlib(L, \"%s\", %sLib, 0);\n" % (libName, libSmallName)
-	sout += "\treturn 1;\n"
-	sout += "}"
+	cppRegisterOut += "\t\t{NULL, NULL}\n"
+	cppRegisterOut += "\t};\n"
+	cppRegisterOut += "\tluaL_openlib(L, \"%s\", %sLib, 0);\n" % (libName, libSmallName)
+	cppRegisterOut += "\treturn 1;\n"
+	cppRegisterOut += "}"
 	
 	
-	shout = ""
-	shout += "#pragma once\n"
-	shout += "#include <%s>\n" % (mainInclude)
-	shout += "extern \"C\" {\n"
-	shout += "#include <stdio.h>\n"
-	shout += "#include \"lua.h\"\n"
-	shout += "#include \"lualib.h\"\n"
-	shout += "#include \"lauxlib.h\"\n"
-	shout += "int _PolyExport luaopen_%s(lua_State *L);\n" % (prefix)
-	shout += "}\n"
+	cppRegisterHeaderOut = "" # Def: Global C++ *LUA.h
+	cppRegisterHeaderOut += "#pragma once\n"
+	cppRegisterHeaderOut += "#include <%s>\n" % (mainInclude)
+	cppRegisterHeaderOut += "extern \"C\" {\n"
+	cppRegisterHeaderOut += "#include <stdio.h>\n"
+	cppRegisterHeaderOut += "#include \"lua.h\"\n"
+	cppRegisterHeaderOut += "#include \"lualib.h\"\n"
+	cppRegisterHeaderOut += "#include \"lauxlib.h\"\n"
+	cppRegisterHeaderOut += "int _PolyExport luaopen_%s(lua_State *L);\n" % (prefix)
+	cppRegisterHeaderOut += "}\n"
 	
+	# Write out global files
 	mkdir_p(includePath)
 	mkdir_p(apiPath)
 	mkdir_p(sourcePath)
 
 	fout = open("%s/%sLUA.h" % (includePath, prefix), "w")
-	fout.write(shout)
+	fout.write(cppRegisterHeaderOut)
 
 	fout = open("%s/%s.lua" % (apiPath, prefix), "w")
-	fout.write(lfout)
+	fout.write(luaIndexOut)
 	
 	fout = open("%s/%sLUAWrappers.h" % (includePath, prefix), "w")
-	fout.write(out)
+	fout.write(wrappersHeaderOut)
 	
 	fout = open("%s/%sLUA.cpp" % (sourcePath, prefix), "w")
-	fout.write(sout)
+	fout.write(cppRegisterOut)
 	
-
+	# Create .pak zip archive
 	pattern = '*.lua'
 	os.chdir(apiPath)
 	if libName == "Polycore":
 		with ZipFile("api.pak", 'w') as myzip:
 			for root, dirs, files in os.walk("."):
-			    for filename in fnmatch.filter(files, pattern):
-				myzip.write(os.path.join(root, filename))
-	#print cppHeader
-	
-createLUABindings(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[7], sys.argv[8], sys.argv[9])
-
+				for filename in fnmatch.filter(files, pattern):
+					myzip.write(os.path.join(root, filename))
+
+if len(sys.argv) < 10:
+	print ("Usage:\n%s [input path] [prefix] [main include] [lib small name] [lib name] [api path] [api class-path] [include path] [source path] [inherit-in-module-file path (optional)]" % (sys.argv[0]))
+	sys.exit(1)
+else:
+	createLUABindings(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[7], sys.argv[8], sys.argv[9], sys.argv[10] if len(sys.argv)>10 else None)

+ 1 - 0
Core/Contents/CMakeLists.txt

@@ -75,6 +75,7 @@ SET(polycore_SRCS
     Source/PolySoundManager.cpp
     Source/PolyString.cpp
     Source/PolyTexture.cpp
+    Source/PolyThreaded.cpp
     Source/PolyTimer.cpp
     Source/PolyTimerManager.cpp
     Source/PolyTween.cpp

+ 1 - 0
Core/Contents/Include/PolyCamera.h

@@ -125,6 +125,7 @@ namespace Polycode {
 			*/			
 			Material *getScreenShaderMaterial() { return filterShaderMaterial; }
 			
+			bool frustumCulling;
 			
 		protected:
 		

+ 1 - 3
Core/Contents/Include/PolyCocoaCore.h

@@ -137,9 +137,7 @@ namespace Polycode {
 		vector<Rectangle> getVideoModes();
 		
 		int lastMouseY;
-		int lastMouseX;		
-		
-		CoreMutex *eventMutex;
+		int lastMouseX;				
 		
 		vector<CocoaEvent> cocoaEvents;
 		

+ 11 - 3
Core/Contents/Include/PolyCore.h

@@ -121,7 +121,7 @@ namespace Polycode {
 		* @param target Target threaded class.
 		* @see Threaded
 		*/		
-		virtual void createThread(Threaded *target) = 0;
+		virtual void createThread(Threaded *target);
 
 		/**
 		* Locks a mutex.
@@ -308,9 +308,14 @@ namespace Polycode {
 		/**
 		* Returns the default working path of the application.
 		*/
-		String getUserHomeDirectory();		
+		String getUserHomeDirectory();	
 		
-	protected:
+		CoreMutex *getEventMutex();
+		CoreMutex *eventMutex;
+		
+		void removeThread(Threaded *thread);
+				
+	protected:	
 		
 		String userHomeDirectory;
 		String defaultWorkingDirectory;
@@ -338,6 +343,9 @@ namespace Polycode {
 		
 		unsigned int lastSleepFrameTicks;
 		
+		std::vector<Threaded*> threads;
+		CoreMutex *threadedEventMutex;
+		
 		int xRes;
 		int yRes;	
 		

+ 5 - 3
Core/Contents/Include/PolyCoreInput.h

@@ -109,12 +109,14 @@ namespace Polycode {
 		void setKeyState(PolyKEY keyCode, wchar_t code, bool newState, int ticks);
 		void setDeltaPosition(int x, int y);
 		
-		void touchesBegan(std::vector<TouchInfo> touches, int ticks);
-		void touchesMoved(std::vector<TouchInfo> touches, int ticks);
-		void touchesEnded(std::vector<TouchInfo> touches, int ticks);
+		void touchesBegan(TouchInfo touch, std::vector<TouchInfo> touches, int ticks);
+		void touchesMoved(TouchInfo touch, std::vector<TouchInfo> touches, int ticks);
+		void touchesEnded(TouchInfo touch, std::vector<TouchInfo> touches, int ticks);
 				
 		static InputEvent *createEvent(Event *event){ return (InputEvent*)event; }
 		
+		bool simulateTouchWithMouse;
+		
 	protected:
 		
 		std::vector<JoystickInfo> joysticks;

+ 1 - 1
Core/Contents/Include/PolyEntity.h

@@ -92,7 +92,7 @@ namespace Polycode {
 			* Returns the entity's matrix multiplied by its parent's concatenated matrix. This, in effect, returns the entity's actual world transformation.
 			@return Entity's concatenated matrix.
 			*/
-			Matrix4 getConcatenatedMatrix() const;
+			Matrix4 getConcatenatedMatrix();
 			
 			/** 
 			* Returns Same as getConcatenatedMatrix(), but contains only roll information for rotation. Used internally for billboards.

+ 2 - 0
Core/Contents/Include/PolyEvent.h

@@ -63,6 +63,8 @@ namespace Polycode {
 			
 			static const int COMPLETE_EVENT = 0;
 			static const int CHANGE_EVENT = 1;
+			
+			bool deleteOnDispatch;
 						
 		protected:
 			

+ 2 - 2
Core/Contents/Include/PolyEventDispatcher.h

@@ -82,8 +82,8 @@ typedef struct {
 			* @see Event
 			* @see EventHandler			
 			*/														
-			void dispatchEvent(Event *event, int eventCode);
-			void dispatchEventNoDelete(Event *event, int eventCode);
+			virtual void dispatchEvent(Event *event, int eventCode);
+			virtual void dispatchEventNoDelete(Event *event, int eventCode);
 		
 		protected:
 	

+ 2 - 1
Core/Contents/Include/PolyGlobals.h

@@ -80,5 +80,6 @@ inline Number clampf(Number x, Number a, Number b)
 #define MIN(a, b)  (((a) < (b)) ? (a) : (b))
 #define MAX(a, b)  (((a) > (b)) ? (a) : (b))
 
-
+// Special flag read by create_lua_library parser, suppresses Lua bindings for item.
+#define POLYIGNORE
 

+ 1 - 0
Core/Contents/Include/PolyInputEvent.h

@@ -107,6 +107,7 @@ namespace Polycode {
 		int timestamp;
 		
 		std::vector<TouchInfo> touches;
+		TouchInfo touch;
 		
 		unsigned int joystickDeviceID;
 		float joystickAxisValue;

+ 24 - 2
Core/Contents/Include/PolyMatrix4.h

@@ -242,7 +242,17 @@ namespace Polycode {
 				*az = fabs(angle_z);
 
 			}
-
+		
+			/**
+			 * Returns the transpose of the matrix.
+			 */
+			inline Matrix4 transpose() const {
+				return Matrix4(m[0][0], m[1][0], m[2][0], m[3][0],
+							   m[0][1], m[1][1], m[2][1], m[3][1],
+							   m[0][2], m[1][2], m[2][2], m[3][2],
+							   m[0][3], m[1][3], m[2][3], m[3][3]);
+			}
+			
 			/**
 			* Returns the inverse of the matrix.
 			*/
@@ -252,7 +262,19 @@ namespace Polycode {
 			* Returns the affine inverse of the matrix.
 			*/			
 			Matrix4 inverseAffine() const;
-	
+		
+			/**
+			* Returns the determinant of the matrix.
+			*/
+			Number determinant() const;
+		
+			/**
+			 * Returns the determinant of any general (square) matrix.
+			 * @param a A square matrix as an array of pointers to rows (or columns).
+			 * @param n The number of dimensions in matrix A.
+			 */
+			static Number generalDeterminant(Number const* const*a, int n);
+		
 		protected:
 		
 	};

+ 10 - 1
Core/Contents/Include/PolyQuaternion.h

@@ -265,7 +265,16 @@ namespace Polycode {
 			void createFromAxisAngle(Number x, Number y, Number z, Number degrees);
 			Matrix4 createMatrix() const;
 			
-			
+			/**
+			 * Rotate a Vector3 by this Quaternion.
+			 * @param v Vector to operate on.
+			 */
+			Vector3 applyTo(Vector3 v) const
+			{
+				const Quaternion &q = *this;
+				Quaternion result = q * Quaternion(0,v.x,v.y,v.z) * q.Inverse();
+				return Vector3(result.x,result.y,result.z);
+			}
 			
 			Quaternion operator *(Quaternion q);
 			

+ 1 - 1
Core/Contents/Include/PolyRenderer.h

@@ -212,7 +212,7 @@ namespace Polycode {
 		
 		void addShaderModule(PolycodeShaderModule *module);
 		
-		virtual bool test2DCoordinateInPolygon(Number x, Number y, Polygon *poly, const Matrix4 &matrix, bool testBackfacing, bool ortho, bool billboardMode);
+		virtual bool test2DCoordinateInPolygon(Number x, Number y, Polygon *poly, const Matrix4 &matrix, bool ortho, bool testBackfacing, bool billboardMode, bool reverseDirection = false, Matrix4 *adjustMatrix = NULL);
 		
 		virtual Matrix4 getProjectionMatrix() = 0;
 		virtual Matrix4 getModelviewMatrix() = 0;

+ 3 - 1
Core/Contents/Include/PolySDLCore.h

@@ -41,7 +41,7 @@ namespace Polycode {
 		
 	public:
 		
-		SDLCore(PolycodeView *view, int xRes, int yRes, bool fullScreen, bool vSync, int aaLevel, int anisotropyLevel, int frameRate);
+		SDLCore(PolycodeView *view, int xRes, int yRes, bool fullScreen, bool vSync, int aaLevel, int anisotropyLevel, int frameRate, int monitorIndex=-1);
 		~SDLCore();
 
 		void enableMouse(bool newval);
@@ -65,6 +65,8 @@ namespace Polycode {
 		std::vector<String> openFilePicker(std::vector<CoreFileExtension> extensions, bool allowMultiple);
 		void resizeTo(int xRes, int yRes);
 
+		void openURL(String url);
+
 	private:
 		
 		

+ 7 - 6
Core/Contents/Include/PolyScreenEntity.h

@@ -104,7 +104,7 @@ class _PolyExport ScreenEntity : public Entity, public EventDispatcher {
 		virtual void onKeyDown(PolyKEY key, wchar_t charCode){}
 		virtual void onKeyUp(PolyKEY key, wchar_t charCode){}
 		
-		bool hitTest(Number x, Number y) const;
+		bool hitTest(Number x, Number y);
 	
 		Matrix4 buildPositionMatrix();
 		void adjustMatrixForChildren();
@@ -124,13 +124,13 @@ class _PolyExport ScreenEntity : public Entity, public EventDispatcher {
 		* Sets the width of the screen entity.
 		* @param w New height value.
 		*/									
-		void setWidth(Number w) { width = w; hitwidth = w; }
+		void setWidth(Number w) { width = w; hit.w = w; hit.x = -w/2; }
 		
 		/**
 		* Sets the height of the screen entity.
 		* @param h New height value.
 		*/									
-		void setHeight(Number h) { height = h; hitheight = h; }
+		void setHeight(Number h) { height = h; hit.h = h; hit.y = -h/2; }
 	
 		virtual void onGainFocus(){}
 		virtual void onLoseFocus(){}		
@@ -175,7 +175,9 @@ class _PolyExport ScreenEntity : public Entity, public EventDispatcher {
 		bool snapToPixels;
 		bool processInputEvents;
 
-		Vector2 getHitbox();
+		Rectangle getHitbox();
+		void setHitbox(Number width, Number height);
+		void setHitbox(Number width, Number height, Number left, Number top);
 
 	protected:
 	
@@ -190,8 +192,7 @@ class _PolyExport ScreenEntity : public Entity, public EventDispatcher {
 		Number width;
 		Number height;
 
-		Number hitwidth;
-		Number hitheight;
+		Rectangle hit;
 		
 		Number xmouse;
 		Number ymouse;

+ 6 - 1
Core/Contents/Include/PolyScreenMesh.h

@@ -95,7 +95,12 @@ namespace Polycode {
 			* If true, will delete its Mesh upon destruction. (defaults to true)
 			*/ 			
 			bool ownsMesh;
-			
+		
+			/**
+			 * Updates hit.width, hit.height to coordinates of mesh.
+			 */
+			void updateHitBox();
+		
 		protected:
 		
 			Mesh *mesh;

+ 4 - 0
Core/Contents/Include/PolyScreenSprite.h

@@ -59,6 +59,8 @@ class _PolyExport ScreenSprite : public ScreenShape
 		*/
 		void addAnimation(const String& name, const String& frames, Number speed);
 		
+		void showFrame(unsigned int frameIndex);
+		
 		/**
 		* Play back a previously created animation by name.
 		* @param name Name of the animation to play.
@@ -70,6 +72,8 @@ class _PolyExport ScreenSprite : public ScreenShape
 		
 		void Pause(bool val);
 		
+		void updateSprite();
+		
 	protected:
 	
 		bool paused;

+ 2 - 2
Core/Contents/Include/PolyTexture.h

@@ -56,7 +56,8 @@ namespace Polycode {
 			int getHeight() const;
 		
 			bool clamp;
-		
+			char *textureData;
+					
 		protected:
 
 			int pixelSize;
@@ -66,7 +67,6 @@ namespace Polycode {
 			int width;
 			int height;
 			String resourcePath;
-			char *textureData;
 			Number scrollOffsetX;
 			Number scrollOffsetY;
 	};

+ 20 - 7
Core/Contents/Include/PolyThreaded.h

@@ -22,8 +22,12 @@ THE SOFTWARE.
 
 #pragma once
 #include "PolyGlobals.h"
+#include "PolyEventDispatcher.h"
 
 namespace Polycode{
+
+	class Core;
+	class CoreMutex;
 	
 	/**
 	* An easy way to create threaded processes. If you subclass this class, you can implement the updateThread method, which will be called in its own thread repeatedly until threadRunning is false once the thread is created. If you only need to run through something once, make sure to set threadRunning to avoid it being called again. 
@@ -31,24 +35,33 @@ namespace Polycode{
 		To create the thread, pass your Threaded subclass to createThread method of Core.
 		@see Core
 	*/
-	class _PolyExport Threaded {
+	class _PolyExport Threaded : public EventDispatcher {
 	public:
-		Threaded(){ threadRunning = true; }
-		virtual ~Threaded(){}
+		Threaded();
+		virtual ~Threaded();
 		
 		/**
 		* Sets the thread running flag to false.
 		*/ 
-		virtual void killThread() { threadRunning = false; }		
-		
-		virtual void runThread(){while(threadRunning) updateThread(); }
+		virtual void killThread();	
+		virtual void runThread();
 		
 		/**
 		* Implement this method with your own code.
 		*/
-		virtual void updateThread() = 0;
+		virtual void updateThread() {};
+		
+		void dispatchEvent(Event *event, int eventCode);		
+		void dispatchEventNoDelete(Event *event, int eventCode);
 		
 		bool threadRunning;
+		
+		Core *core;
+		
+		bool scheduledForRemoval;
+		
+		CoreMutex *eventMutex;		
+		std::vector<Event*> eventQueue;
 	};
 	
 }

+ 0 - 2
Core/Contents/Include/PolyWinCore.h

@@ -240,8 +240,6 @@ public:
 		PolyKEY keyMap[1024];
 		unsigned int lastGamepadDetect;
 
-		CoreMutex *eventMutex;
-
 		std::vector<Win32Event> win32Events;
 
 		void initMultisample(int numSamples);

+ 3 - 0
Core/Contents/Source/PolyCamera.cpp

@@ -42,6 +42,7 @@ Camera::Camera(Scene *parentScene) : SceneEntity() {
 	exposureLevel = 1.0f;
 	_hasFilterShader = false;	
 	fovSet = false;
+	frustumCulling = true;
 }
 
 Camera::~Camera() {	
@@ -73,6 +74,8 @@ Number Camera::getFOV() {
 
 
 bool Camera::isSphereInFrustrum(Vector3 pos, Number fRadius) {
+	if(!frustumCulling)
+		return true;
     for( int i = 0; i < 6; ++i )
     {
         if( frustumPlanes[i][0] * pos.x +

+ 2 - 0
Core/Contents/Source/PolyCocoaCore.mm

@@ -262,10 +262,12 @@ CocoaCore::~CocoaCore() {
 void *ManagedThreadFunc(void *data) {
 	Threaded *target = static_cast<Threaded*>(data);
 	target->runThread();
+	target->scheduledForRemoval = true;
 	return NULL;
 }
 
 void CocoaCore::createThread(Threaded *target) {
+	Core::createThread(target);
 	pthread_t thread;
 	pthread_create( &thread, NULL, ManagedThreadFunc, (void*)target);
 }

+ 53 - 1
Core/Contents/Source/PolyCore.cpp

@@ -70,7 +70,8 @@ namespace Polycode {
 		
 		this->monitorIndex = monitorIndex;
 		
-		refreshInterval = 1000 / frameRate;
+		refreshInterval = 1000 / frameRate;		
+		threadedEventMutex = NULL;
 	}
 	
 	void Core::enableMouse(bool newval) {
@@ -126,6 +127,36 @@ namespace Polycode {
 		setVideoMode(resList[index].w, resList[index].h, fullScreen, vSync, aaLevel, anisotropyLevel);
 	}
 	
+	void Core::createThread(Threaded *target) {
+		if(!threadedEventMutex) {
+			threadedEventMutex = createMutex();
+		}
+		target->eventMutex = threadedEventMutex;
+		target->core = this;
+		
+		lockMutex(threadedEventMutex);
+		threads.push_back(target);
+		unlockMutex(threadedEventMutex);			
+	}
+	
+	CoreMutex *Core::getEventMutex() {
+		return eventMutex;
+	}
+	
+	void Core::removeThread(Threaded *thread) {
+		if(threadedEventMutex){ 
+			lockMutex(threadedEventMutex);
+	
+			for(int i=0; i < threads.size(); i++) {
+				if(threads[i] == thread) {
+					threads.erase(threads.begin() + i);
+					return;
+				}
+			}
+			unlockMutex(threadedEventMutex);			
+		}
+	}
+							
 	void Core::updateCore() {
 		frames++;
 		frameTicks = getTicks();
@@ -142,6 +173,27 @@ namespace Polycode {
 		}
 		lastFrameTicks = frameTicks;
 		
+		if(threadedEventMutex){ 
+		lockMutex(threadedEventMutex);
+
+		std::vector<Threaded*>::iterator iter = threads.begin();
+		while (iter != threads.end()) {		
+			for(int j=0; j < (*iter)->eventQueue.size(); j++) {
+				Event *event = (*iter)->eventQueue[j];
+				(*iter)->__dispatchEvent(event, event->getEventCode());
+				if(event->deleteOnDispatch)
+					delete event;
+			}
+			(*iter)->eventQueue.clear();
+			if((*iter)->scheduledForRemoval) {
+				iter = threads.erase(iter);
+			} else {
+				++iter;
+			}
+		}
+		
+		unlockMutex(threadedEventMutex);
+		}
 	}
 	
 	void Core::doSleep() {

+ 33 - 4
Core/Contents/Source/PolyCoreInput.cpp

@@ -42,7 +42,9 @@ namespace Polycode {
 		
 		for(int i=0; i < 512; i++) {
 			keyboardState[i] = 0;
-		}		
+		}
+		
+		simulateTouchWithMouse = false;
 	}
 	
 	CoreInput::~CoreInput() {
@@ -139,6 +141,20 @@ namespace Polycode {
 		else
 			dispatchEvent(evt, InputEvent::EVENT_MOUSEUP);
 		mouseButtons[mouseButton] = state;
+				
+		if(simulateTouchWithMouse && mouseButton == MOUSE_BUTTON1) {
+			TouchInfo touch;
+			touch.position = mousePosition;
+			touch.id = 0;			
+			std::vector<TouchInfo> touches;
+			touches.push_back(touch);
+			
+			if(state) {
+				touchesBegan(touch, touches, ticks);
+			} else {
+				touchesEnded(touch, touches, ticks);			
+			}
+		}
 	}
 	
 	void CoreInput::mouseWheelDown(int ticks) {
@@ -156,6 +172,16 @@ namespace Polycode {
 		mousePosition.y = y;
 		InputEvent *evt = new InputEvent(mousePosition, ticks);
 		dispatchEvent(evt, InputEvent::EVENT_MOUSEMOVE);
+		
+		if(simulateTouchWithMouse && mouseButtons[MOUSE_BUTTON1]) {
+			TouchInfo touch;
+			touch.position = mousePosition;
+			touch.id = 0;			
+			std::vector<TouchInfo> touches;
+			touches.push_back(touch);
+			
+			touchesMoved(touch, touches, ticks);
+		}		
 	}
 	
 	Vector2 CoreInput::getMouseDelta() {
@@ -189,22 +215,25 @@ namespace Polycode {
 		}
 	}
 	
-	void CoreInput::touchesBegan(std::vector<TouchInfo> touches, int ticks) {
+	void CoreInput::touchesBegan(TouchInfo touch, std::vector<TouchInfo> touches, int ticks) {
 		InputEvent *evt = new InputEvent();
+		evt->touch = touch;		
 		evt->touches = touches;
 		evt->timestamp = ticks;
 		dispatchEvent(evt, InputEvent::EVENT_TOUCHES_BEGAN);
 	}
 	
-	void CoreInput::touchesMoved(std::vector<TouchInfo> touches, int ticks) {
+	void CoreInput::touchesMoved(TouchInfo touch, std::vector<TouchInfo> touches, int ticks) {
 		InputEvent *evt = new InputEvent();
+		evt->touch = touch;
 		evt->touches = touches;
 		evt->timestamp = ticks;		
 		dispatchEvent(evt, InputEvent::EVENT_TOUCHES_MOVED);	
 	}
 	
-	void CoreInput::touchesEnded(std::vector<TouchInfo> touches, int ticks) {
+	void CoreInput::touchesEnded(TouchInfo touch, std::vector<TouchInfo> touches, int ticks) {
 		InputEvent *evt = new InputEvent();
+		evt->touch = touch;		
 		evt->touches = touches;
 		evt->timestamp = ticks;		
 		dispatchEvent(evt, InputEvent::EVENT_TOUCHES_ENDED);	

+ 4 - 1
Core/Contents/Source/PolyEntity.cpp

@@ -438,7 +438,10 @@ Vector3 Entity::getScale() const {
 	return scale;
 }
 
-Matrix4 Entity::getConcatenatedMatrix() const {
+Matrix4 Entity::getConcatenatedMatrix() {
+	if(matrixDirty)
+		rebuildTransformMatrix();
+
 	if(parentEntity != NULL) 
 		return transformMatrix * parentEntity->getConcatenatedMatrix();
 	else

+ 1 - 0
Core/Contents/Source/PolyEvent.cpp

@@ -26,6 +26,7 @@ namespace Polycode {
 	
 	Event::Event() {
 			eventType = "Event";
+			deleteOnDispatch = true;
 	}
 	
 	Event::Event(int eventCode) {

+ 1 - 0
Core/Contents/Source/PolyGLRenderer.cpp

@@ -425,6 +425,7 @@ Matrix4 OpenGLRenderer::getModelviewMatrix() {
 }
 
 Image *OpenGLRenderer::renderScreenToImage() {
+	glReadBuffer(GL_FRONT);
 	char *imageBuffer = (char*)malloc(xRes * yRes * 4);
 	glReadPixels(0, 0, xRes, yRes, GL_RGBA, GL_UNSIGNED_BYTE, imageBuffer);
 	Image *retImage = new Image(imageBuffer, xRes, yRes, Image::IMAGE_RGBA);	

+ 211 - 91
Core/Contents/Source/PolyMatrix4.cpp

@@ -36,107 +36,227 @@ Matrix4::Matrix4(const Number *m) {
 	memcpy(ml, m, sizeof(Number)*16);
 }
 
-	Matrix4 Matrix4::inverse() const
-    {
-        Number m00 = m[0][0], m01 = m[0][1], m02 = m[0][2], m03 = m[0][3];
-        Number m10 = m[1][0], m11 = m[1][1], m12 = m[1][2], m13 = m[1][3];
-        Number m20 = m[2][0], m21 = m[2][1], m22 = m[2][2], m23 = m[2][3];
-        Number m30 = m[3][0], m31 = m[3][1], m32 = m[3][2], m33 = m[3][3];
-
-        Number v0 = m20 * m31 - m21 * m30;
-        Number v1 = m20 * m32 - m22 * m30;
-        Number v2 = m20 * m33 - m23 * m30;
-        Number v3 = m21 * m32 - m22 * m31;
-        Number v4 = m21 * m33 - m23 * m31;
-        Number v5 = m22 * m33 - m23 * m32;
-
-        Number t00 = + (v5 * m11 - v4 * m12 + v3 * m13);
-        Number t10 = - (v5 * m10 - v2 * m12 + v1 * m13);
-        Number t20 = + (v4 * m10 - v2 * m11 + v0 * m13);
-        Number t30 = - (v3 * m10 - v1 * m11 + v0 * m12);
-
-        Number invDet = 1 / (t00 * m00 + t10 * m01 + t20 * m02 + t30 * m03);
-
-        Number d00 = t00 * invDet;
-        Number d10 = t10 * invDet;
-        Number d20 = t20 * invDet;
-        Number d30 = t30 * invDet;
-
-        Number d01 = - (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
-        Number d11 = + (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
-        Number d21 = - (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
-        Number d31 = + (v3 * m00 - v1 * m01 + v0 * m02) * invDet;
-
-        v0 = m10 * m31 - m11 * m30;
-        v1 = m10 * m32 - m12 * m30;
-        v2 = m10 * m33 - m13 * m30;
-        v3 = m11 * m32 - m12 * m31;
-        v4 = m11 * m33 - m13 * m31;
-        v5 = m12 * m33 - m13 * m32;
-
-        Number d02 = + (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
-        Number d12 = - (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
-        Number d22 = + (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
-        Number d32 = - (v3 * m00 - v1 * m01 + v0 * m02) * invDet;
-
-        v0 = m21 * m10 - m20 * m11;
-        v1 = m22 * m10 - m20 * m12;
-        v2 = m23 * m10 - m20 * m13;
-        v3 = m22 * m11 - m21 * m12;
-        v4 = m23 * m11 - m21 * m13;
-        v5 = m23 * m12 - m22 * m13;
-
-        Number d03 = - (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
-        Number d13 = + (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
-        Number d23 = - (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
-        Number d33 = + (v3 * m00 - v1 * m01 + v0 * m02) * invDet;
-
-        return Matrix4(
-            d00, d01, d02, d03,
-            d10, d11, d12, d13,
-            d20, d21, d22, d23,
-            d30, d31, d32, d33);
-    }
-    //-----------------------------------------------------------------------
-	Matrix4 Matrix4::inverseAffine(void) const
-    {
+Matrix4 Matrix4::inverse() const
+{
+	Number m00 = m[0][0], m01 = m[0][1], m02 = m[0][2], m03 = m[0][3];
+	Number m10 = m[1][0], m11 = m[1][1], m12 = m[1][2], m13 = m[1][3];
+	Number m20 = m[2][0], m21 = m[2][1], m22 = m[2][2], m23 = m[2][3];
+	Number m30 = m[3][0], m31 = m[3][1], m32 = m[3][2], m33 = m[3][3];
+
+	Number v0 = m20 * m31 - m21 * m30;
+	Number v1 = m20 * m32 - m22 * m30;
+	Number v2 = m20 * m33 - m23 * m30;
+	Number v3 = m21 * m32 - m22 * m31;
+	Number v4 = m21 * m33 - m23 * m31;
+	Number v5 = m22 * m33 - m23 * m32;
+
+	Number t00 = + (v5 * m11 - v4 * m12 + v3 * m13);
+	Number t10 = - (v5 * m10 - v2 * m12 + v1 * m13);
+	Number t20 = + (v4 * m10 - v2 * m11 + v0 * m13);
+	Number t30 = - (v3 * m10 - v1 * m11 + v0 * m12);
+
+	Number invDet = 1 / (t00 * m00 + t10 * m01 + t20 * m02 + t30 * m03);
+
+	Number d00 = t00 * invDet;
+	Number d10 = t10 * invDet;
+	Number d20 = t20 * invDet;
+	Number d30 = t30 * invDet;
+
+	Number d01 = - (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
+	Number d11 = + (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
+	Number d21 = - (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
+	Number d31 = + (v3 * m00 - v1 * m01 + v0 * m02) * invDet;
+
+	v0 = m10 * m31 - m11 * m30;
+	v1 = m10 * m32 - m12 * m30;
+	v2 = m10 * m33 - m13 * m30;
+	v3 = m11 * m32 - m12 * m31;
+	v4 = m11 * m33 - m13 * m31;
+	v5 = m12 * m33 - m13 * m32;
+
+	Number d02 = + (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
+	Number d12 = - (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
+	Number d22 = + (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
+	Number d32 = - (v3 * m00 - v1 * m01 + v0 * m02) * invDet;
+
+	v0 = m21 * m10 - m20 * m11;
+	v1 = m22 * m10 - m20 * m12;
+	v2 = m23 * m10 - m20 * m13;
+	v3 = m22 * m11 - m21 * m12;
+	v4 = m23 * m11 - m21 * m13;
+	v5 = m23 * m12 - m22 * m13;
 
-        Number m10 = m[1][0], m11 = m[1][1], m12 = m[1][2];
-        Number m20 = m[2][0], m21 = m[2][1], m22 = m[2][2];
+	Number d03 = - (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
+	Number d13 = + (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
+	Number d23 = - (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
+	Number d33 = + (v3 * m00 - v1 * m01 + v0 * m02) * invDet;
 
-        Number t00 = m22 * m11 - m21 * m12;
-        Number t10 = m20 * m12 - m22 * m10;
-        Number t20 = m21 * m10 - m20 * m11;
+	return Matrix4(
+		d00, d01, d02, d03,
+		d10, d11, d12, d13,
+		d20, d21, d22, d23,
+		d30, d31, d32, d33);
+}
+
+Matrix4 Matrix4::inverseAffine(void) const
+{
+
+	Number m10 = m[1][0], m11 = m[1][1], m12 = m[1][2];
+	Number m20 = m[2][0], m21 = m[2][1], m22 = m[2][2];
 
-        Number m00 = m[0][0], m01 = m[0][1], m02 = m[0][2];
+	Number t00 = m22 * m11 - m21 * m12;
+	Number t10 = m20 * m12 - m22 * m10;
+	Number t20 = m21 * m10 - m20 * m11;
 
-        Number invDet = 1 / (m00 * t00 + m01 * t10 + m02 * t20);
+	Number m00 = m[0][0], m01 = m[0][1], m02 = m[0][2];
 
-        t00 *= invDet; t10 *= invDet; t20 *= invDet;
+	Number invDet = 1 / (m00 * t00 + m01 * t10 + m02 * t20);
 
-        m00 *= invDet; m01 *= invDet; m02 *= invDet;
+	t00 *= invDet; t10 *= invDet; t20 *= invDet;
 
-        Number r00 = t00;
-        Number r01 = m02 * m21 - m01 * m22;
-        Number r02 = m01 * m12 - m02 * m11;
+	m00 *= invDet; m01 *= invDet; m02 *= invDet;
 
-        Number r10 = t10;
-        Number r11 = m00 * m22 - m02 * m20;
-        Number r12 = m02 * m10 - m00 * m12;
+	Number r00 = t00;
+	Number r01 = m02 * m21 - m01 * m22;
+	Number r02 = m01 * m12 - m02 * m11;
 
-        Number r20 = t20;
-        Number r21 = m01 * m20 - m00 * m21;
-        Number r22 = m00 * m11 - m01 * m10;
+	Number r10 = t10;
+	Number r11 = m00 * m22 - m02 * m20;
+	Number r12 = m02 * m10 - m00 * m12;
 
-        Number m03 = m[0][3], m13 = m[1][3], m23 = m[2][3];
+	Number r20 = t20;
+	Number r21 = m01 * m20 - m00 * m21;
+	Number r22 = m00 * m11 - m01 * m10;
 
-        Number r03 = - (r00 * m03 + r01 * m13 + r02 * m23);
-        Number r13 = - (r10 * m03 + r11 * m13 + r12 * m23);
-        Number r23 = - (r20 * m03 + r21 * m13 + r22 * m23);
+	Number m03 = m[0][3], m13 = m[1][3], m23 = m[2][3];
 
-        return Matrix4(
-            r00, r01, r02, r03,
-            r10, r11, r12, r13,
-            r20, r21, r22, r23,
-              0,   0,   0,   1);
+	Number r03 = - (r00 * m03 + r01 * m13 + r02 * m23);
+	Number r13 = - (r10 * m03 + r11 * m13 + r12 * m23);
+	Number r23 = - (r20 * m03 + r21 * m13 + r22 * m23);
+
+	return Matrix4(
+		r00, r01, r02, r03,
+		r10, r11, r12, r13,
+		r20, r21, r22, r23,
+		  0,   0,   0,   1);
+}
+
+Number Matrix4::determinant() const {
+	const Number *cols[4] = {m[0],m[1],m[2],m[3]};
+	return generalDeterminant(cols, 4);
+}
+
+// Determinant function by Edward Popko
+// Source: http://paulbourke.net/miscellaneous/determinant/
+//==============================================================================
+// Recursive definition of determinate using expansion by minors.
+//
+// Notes: 1) arguments:
+//             a (double **) pointer to a pointer of an arbitrary square matrix
+//             n (int) dimension of the square matrix
+//
+//        2) Determinant is a recursive function, calling itself repeatedly
+//           each time with a sub-matrix of the original till a terminal
+//           2X2 matrix is achieved and a simple determinat can be computed.
+//           As the recursion works backwards, cumulative determinants are
+//           found till untimately, the final determinate is returned to the
+//           initial function caller.
+//
+//        3) m is a matrix (4X4 in example)  and m13 is a minor of it.
+//           A minor of m is a 3X3 in which a row and column of values
+//           had been excluded.   Another minor of the submartix is also
+//           possible etc.
+//             m  a b c d   m13 . . . .
+//                e f g h       e f . h     row 1 column 3 is elminated
+//                i j k l       i j . l     creating a 3 X 3 sub martix
+//                m n o p       m n . p
+//
+//        4) the following function finds the determinant of a matrix
+//           by recursively minor-ing a row and column, each time reducing
+//           the sub-matrix by one row/column.  When a 2X2 matrix is
+//           obtained, the determinat is a simple calculation and the
+//           process of unstacking previous recursive calls begins.
+//
+//                m n
+//                o p  determinant = m*p - n*o
+//
+//        5) this function uses dynamic memory allocation on each call to
+//           build a m X m matrix  this requires **  and * pointer variables
+//           First memory allocation is ** and gets space for a list of other
+//           pointers filled in by the second call to malloc.
+//
+//        6) C++ implements two dimensional arrays as an array of arrays
+//           thus two dynamic malloc's are needed and have corresponsing
+//           free() calles.
+//
+//        7) the final determinant value is the sum of sub determinants
+//
+//==============================================================================
+Number Matrix4::generalDeterminant(Number const* const*a,int n)
+{
+    int i,j,j1,j2;                    // general loop and matrix subscripts
+    Number det = 0;                   // init determinant
+    Number **m = NULL;                // pointer to pointers to implement 2d
+	// square array
+	
+    if (n < 1)    {   }                // error condition, should never get here
+	
+    else if (n == 1) {                 // should not get here
+        det = a[0][0];
+	}
+	
+    else if (n == 2)  {                // basic 2X2 sub-matrix determinate
+		// definition. When n==2, this ends the
+        det = a[0][0] * a[1][1] - a[1][0] * a[0][1];// the recursion series
+	}
+	
+	
+	// recursion continues, solve next sub-matrix
+    else {                             // solve the next minor by building a
+		// sub matrix
+        det = 0;                      // initialize determinant of sub-matrix
+		
+		// for each column in sub-matrix
+        for (j1 = 0; j1 < n; j1++) {
+			// get space for the pointer list
+            m = new Number*[n-1];
+			
+            for (i = 0; i < n-1; i++)
+                m[i] = new Number[n-1];
+			//     i[0][1][2][3]  first malloc
+			//  m -> +  +  +  +   space for 4 pointers
+			//       |  |  |  |          j  second malloc
+			//       |  |  |  +-> _ _ _ [0] pointers to
+			//       |  |  +----> _ _ _ [1] and memory for
+			//       |  +-------> _ a _ [2] 4 doubles
+			//       +----------> _ _ _ [3]
+			//
+			//                   a[1][2]
+			// build sub-matrix with minor elements excluded
+            for (i = 1; i < n; i++) {
+                j2 = 0;               // start at first sum-matrix column position
+				// loop to copy source matrix less one column
+                for (j = 0; j < n; j++) {
+                    if (j == j1) continue; // don't copy the minor column element
+					
+                    m[i-1][j2] = a[i][j];   // copy source element into new sub-matrix
+					// i-1 because new sub-matrix is one row
+					// (and column) smaller with excluded minors
+                    j2++;                  // move to next sub-matrix column position
+				}
+			}
+			
+            det += pow(-1.0,1.0 + j1 + 1.0) * a[0][j1] * generalDeterminant(m,n-1);
+			// sum x raised to y power
+			// recursively get determinant of next
+			// sub-matrix which is now one
+			// row & column smaller
+			
+            for (i = 0 ; i < n-1 ; i++) delete[] m[i];// free the storage allocated to
+			// to this minor's set of pointers
+            delete[] m;                       // free the storage for the original
+			// pointer to pointer
+        }
     }
+    return(det) ;
+}

+ 5 - 1
Core/Contents/Source/PolyObject.cpp

@@ -161,6 +161,10 @@ TiXmlElement *Object::createElementFromObjectEntry(ObjectEntry *entry) {
 
 bool Object::loadFromXMLString(const String &xmlString) {
 
+	if(xmlString.length() < 2) {
+		return false;
+	}
+
 	TiXmlDocument doc;
 	doc.Parse((const char*)xmlString.c_str(), 0, TIXML_ENCODING_UTF8);
 
@@ -249,7 +253,7 @@ void Object::createFromXMLElement(TiXmlElement *element, ObjectEntry *entry) {
 			entry->NumberVal = entry->intVal;
 			entry->boolVal = entry->intVal;
 		} else {
-			entry->NumberVal = strtof(rawVal, &endResult);
+			entry->NumberVal = strtod(rawVal, &endResult);
 			entry->intVal = entry->NumberVal;
 			entry->boolVal = entry->NumberVal;
 			if (endResult == success) {

+ 33 - 4
Core/Contents/Source/PolyRenderer.cpp

@@ -78,7 +78,7 @@ void Renderer::setExposureLevel(Number level) {
 }
 
 
-bool Renderer::test2DCoordinateInPolygon(Number x, Number y, Polycode::Polygon *poly, const Matrix4 &matrix, bool ortho, bool testBackfacing, bool billboardMode) {
+bool Renderer::test2DCoordinateInPolygon(Number x, Number y, Polycode::Polygon *poly, const Matrix4 &matrix, bool ortho, bool testBackfacing, bool billboardMode, bool reverseDirection, Matrix4 *adjustMatrix) {
 
 	Vector3 dirVec;
 	Vector3 origin;
@@ -118,23 +118,52 @@ bool Renderer::test2DCoordinateInPolygon(Number x, Number y, Polycode::Polygon *
 		dirVec = camInverse.rotateVector(dirVec);
 	}
 	
+	if(adjustMatrix) {
+			fullMatrix = (*adjustMatrix) * fullMatrix;
+	}	
+		
 	bool retStatus = false;	
 	
 	
 	if(poly->getVertexCount() == 3) {
-		retStatus = rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(0)), fullMatrix  * (*poly->getVertex(1)), fullMatrix *  (*poly->getVertex(2)), &hitPoint);
-		if(testBackfacing && !retStatus) {
+	
+		if(reverseDirection) {
+			retStatus = rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(2)), fullMatrix  * (*poly->getVertex(1)), fullMatrix *  (*poly->getVertex(0)), &hitPoint);
+			if(testBackfacing && !retStatus) {
+			retStatus = rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(0)), fullMatrix  * (*poly->getVertex(1)), fullMatrix *  (*poly->getVertex(2)), &hitPoint);
+		
+			}		
+		} else {
+			retStatus = rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(0)), fullMatrix  * (*poly->getVertex(1)), fullMatrix *  (*poly->getVertex(2)), &hitPoint);
+			if(testBackfacing && !retStatus) {
 			retStatus = rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(2)), fullMatrix  * (*poly->getVertex(1)), fullMatrix *  (*poly->getVertex(0)), &hitPoint);
 		
+			}
 		}
 	} else if(poly->getVertexCount() == 4) {
+	
+		if(reverseDirection) {
+		
+		retStatus = (rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(0)), fullMatrix  * (*poly->getVertex(1)), fullMatrix *  (*poly->getVertex(2)), &hitPoint) ||
+				rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(2)), fullMatrix  * (*poly->getVertex(3)), fullMatrix *  (*poly->getVertex(0)), &hitPoint));
+		if(testBackfacing && !retStatus) {
+			retStatus = (rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(2)), fullMatrix  * (*poly->getVertex(1)), fullMatrix *  (*poly->getVertex(0)), &hitPoint) ||
+				rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(0)), fullMatrix  * (*poly->getVertex(3)), fullMatrix *  (*poly->getVertex(2)), &hitPoint));
+		
+		}	
+		
+		
+		} else {
+		
 		retStatus = (rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(2)), fullMatrix  * (*poly->getVertex(1)), fullMatrix *  (*poly->getVertex(0)), &hitPoint) ||
 				rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(0)), fullMatrix  * (*poly->getVertex(3)), fullMatrix *  (*poly->getVertex(2)), &hitPoint));
 		if(testBackfacing && !retStatus) {
 			retStatus = (rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(0)), fullMatrix  * (*poly->getVertex(1)), fullMatrix *  (*poly->getVertex(2)), &hitPoint) ||
 				rayTriangleIntersect(origin, dirVec, fullMatrix * (*poly->getVertex(2)), fullMatrix  * (*poly->getVertex(3)), fullMatrix *  (*poly->getVertex(0)), &hitPoint));
 		
-		}				
+		}	
+		
+		}			
 	} else {
 		retStatus = false;
 	}

+ 3 - 0
Core/Contents/Source/PolySDLCore.cpp

@@ -112,6 +112,9 @@ SDLCore::~SDLCore() {
 	SDL_Quit();
 }
 
+void SDLCore::openURL(String url) {
+}
+
 int SDLThreadFunc(void *data) {
 	Threaded *target = (Threaded*)data;
 	target->runThread();

+ 1 - 1
Core/Contents/Source/PolySceneLine.cpp

@@ -66,7 +66,7 @@ SceneLine::SceneLine(SceneEntity *ent1, SceneEntity *ent2) : SceneEntity() {
 }
 
 SceneLine::~SceneLine() {
-
+	delete mesh;
 }
 
 void SceneLine::setStart(Vector3 start) {

+ 39 - 29
Core/Contents/Source/PolyScreenEntity.cpp

@@ -35,8 +35,7 @@ ScreenEntity::ScreenEntity() : Entity(), EventDispatcher() {
 	color = Color(1.0f,1.0f,1.0f,1.0f);
 	width = 1;
 	height = 1;
-	hitwidth = 1;
-	hitheight = 1;
+	setHitbox(1, 1);
 	backfaceCulled = false;
 	positionMode = POSITION_TOPLEFT;
 	mouseOver = false;
@@ -186,31 +185,29 @@ bool isPointInsidePolygon2D(Polycode::Polygon *poly, const Vector2 &p) {
 		return true;
 }
 
-bool ScreenEntity::hitTest(const Number x, const Number y) const {
+bool ScreenEntity::hitTest(const Number x, const Number y) {
 
 	Vector3 v;	
 	Polygon testPoly;
 	
 	Matrix4 transformMatrix = getConcatenatedMatrix();
-	
-	v = Vector3(-hitwidth/2.0, -hitheight/2.0,0);
-	v = transformMatrix * v;	
+	v = Vector3(hit.x, hit.y, 0);
+	v = transformMatrix * v;
 	testPoly.addVertex(v.x, v.y, 0.0);
 	
-	v = Vector3(hitwidth/2.0, -hitheight/2.0,0);
-	v = transformMatrix * v;	
+	v = Vector3(hit.x+hit.w, hit.y, 0);
+	v = transformMatrix * v;
 	testPoly.addVertex(v.x, v.y, 0.0);
 
-	v = Vector3(hitwidth/2.0, hitheight/2.0,0);
-	v = transformMatrix * v;	
+	v = Vector3(hit.x+hit.w, hit.y+hit.h, 0);
+	v = transformMatrix * v;
 	testPoly.addVertex(v.x, v.y, 0.0);
 
-	v = Vector3(-hitwidth/2.0,hitheight/2.0,0);
-	v = transformMatrix * v;	
+	v = Vector3(hit.x,hit.y+hit.h, 0);
+	v = transformMatrix * v;
 	testPoly.addVertex(v.x, v.y, 0.0);
 		
 	return isPointInsidePolygon2D(&testPoly, Vector2(x,y));
-	
 }
 
 void ScreenEntity::setPositionMode(int newPositionMode) {
@@ -249,8 +246,21 @@ void ScreenEntity::clearDragLimits() {
 	dragLimits = NULL;
 }
 
-Vector2 ScreenEntity::getHitbox() {
-	return Vector2(hitwidth, hitheight);
+Rectangle ScreenEntity::getHitbox() {
+	return hit;
+}
+
+void ScreenEntity::setHitbox(Number width, Number height) {
+	hit.w = width;
+	hit.h = height;
+	hit.x = -width/2;
+	hit.y = -height/2;
+}
+void ScreenEntity::setHitbox(Number width, Number height, Number left, Number top) {
+	hit.w = width;
+	hit.h = height;
+	hit.x = left;
+	hit.y = top;
 }
 
 Matrix4 ScreenEntity::getScreenConcatenatedMatrix() {
@@ -309,9 +319,9 @@ void ScreenEntity::_onMouseMove(Number x, Number y, int timestamp, Vector2 paren
 		Matrix4 inverse = getConcatenatedMatrix().inverse();
 		localCoordinate = inverse * localCoordinate;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.x += hitwidth/2.0;
+			localCoordinate.x += hit.w/2.0;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.y += hitheight/2.0;
+			localCoordinate.y += hit.h/2.0;
 
 
 		
@@ -333,9 +343,9 @@ void ScreenEntity::_onMouseMove(Number x, Number y, int timestamp, Vector2 paren
 		Matrix4 inverse = getConcatenatedMatrix().inverse();
 		localCoordinate = inverse * localCoordinate;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.x += hitwidth/2.0;
+			localCoordinate.x += hit.w/2.0;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.y += hitheight/2.0;
+			localCoordinate.y += hit.h/2.0;
 		
 		
 			dispatchEvent(new InputEvent(Vector2(localCoordinate.x,localCoordinate.y)-parentAdjust, timestamp), InputEvent::EVENT_MOUSEOUT);
@@ -378,9 +388,9 @@ bool ScreenEntity::_onMouseUp(Number x, Number y, int mouseButton, int timestamp
 		Matrix4 inverse = getConcatenatedMatrix().inverse();
 		localCoordinate = inverse * localCoordinate;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.x += hitwidth/2.0;
+			localCoordinate.x += hit.w/2.0;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.y += hitheight/2.0;
+			localCoordinate.y += hit.h/2.0;
 
 		
 		onMouseUp(localCoordinate.x,localCoordinate.y);		
@@ -395,9 +405,9 @@ bool ScreenEntity::_onMouseUp(Number x, Number y, int mouseButton, int timestamp
 		Matrix4 inverse = getConcatenatedMatrix().inverse();
 		localCoordinate = inverse * localCoordinate;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.x += hitwidth/2.0;
+			localCoordinate.x += hit.w/2.0;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.y += hitheight/2.0;
+			localCoordinate.y += hit.h/2.0;
 
 		
 		InputEvent *inputEvent = new InputEvent(Vector2(localCoordinate.x,localCoordinate.y)-parentAdjust, timestamp);		
@@ -441,9 +451,9 @@ void ScreenEntity::_onMouseWheelUp(Number x, Number y, int timestamp, Vector2 pa
 		Matrix4 inverse = getConcatenatedMatrix().inverse();
 		localCoordinate = inverse * localCoordinate;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.x += hitwidth/2.0;
+			localCoordinate.x += hit.w/2.0;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.y += hitheight/2.0;
+			localCoordinate.y += hit.h/2.0;
 
 		
 		onMouseWheelUp(localCoordinate.x,localCoordinate.y);
@@ -489,9 +499,9 @@ void ScreenEntity::_onMouseWheelDown(Number x, Number y, int timestamp, Vector2
 		Matrix4 inverse = getConcatenatedMatrix().inverse();
 		localCoordinate = inverse * localCoordinate;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.x += hitwidth/2.0;
+			localCoordinate.x += hit.w/2.0;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.y += hitheight/2.0;
+			localCoordinate.y += hit.h/2.0;
 
 		
 		onMouseWheelDown(localCoordinate.x,localCoordinate.y);
@@ -539,9 +549,9 @@ bool ScreenEntity::_onMouseDown(Number x, Number y, int mouseButton, int timesta
 		Matrix4 inverse = getConcatenatedMatrix().inverse();
 		localCoordinate = inverse * localCoordinate;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.x += hitwidth/2.0;
+			localCoordinate.x += hit.w/2.0;
 		if(positionMode == POSITION_TOPLEFT)
-			localCoordinate.y += hitheight/2.0;
+			localCoordinate.y += hit.h/2.0;
 
 		
 		onMouseDown(localCoordinate.x,localCoordinate.y);

+ 1 - 2
Core/Contents/Source/PolyScreenImage.cpp

@@ -65,8 +65,7 @@ void ScreenImage::setImageCoordinates(Number x, Number y, Number width, Number h
 	
 	this->width = width;
 	this->height = height;
-	hitwidth = width;
-	hitheight = height;
+	setHitbox(width, height);
 	Number whalf = floor(width/2.0f);
 	Number hhalf = floor(height/2.0f);	
 		

+ 24 - 0
Core/Contents/Source/PolyScreenMesh.cpp

@@ -33,6 +33,7 @@ ScreenMesh::ScreenMesh(Mesh *mesh) : ScreenEntity(), texture(NULL) {
 	lineSmooth = false;
 	lineWidth = 1.0;
 	ownsMesh = true;
+	updateHitBox();
 }
 
 ScreenMesh::ScreenMesh(const String& fileName) : ScreenEntity(), texture(NULL) {
@@ -90,3 +91,26 @@ void ScreenMesh::Render() {
 	renderer->pushDataArrayForMesh(mesh, RenderDataArray::TEXCOORD_DATA_ARRAY);	
 	renderer->drawArrays(mesh->getMeshType());
 }
+
+void ScreenMesh::updateHitBox() {
+	Number xmin, ymin, xmax, ymax;
+	bool any = false;
+	for(int c = 0; c < mesh->getPolygonCount(); c++) {
+		Polygon *poly = mesh->getPolygon(c);
+		for(int d = 0; d < poly->getVertexCount(); d++) {
+			Vertex *v = poly->getVertex(d);
+			if (any) {
+				xmin = MIN(v->x, xmin);
+				ymin = MIN(v->y, ymin);
+				xmax = MAX(v->x, xmax);
+				ymax = MAX(v->y, ymax);
+			} else {
+				xmin = v->x; xmax = v->x;
+				ymin = v->y; ymax = v->y;
+				any = true;
+			}
+		}
+	}
+	
+	setHitbox(xmax-xmin, ymax-ymin, xmin, ymin);
+}

+ 3 - 5
Core/Contents/Source/PolyScreenShape.cpp

@@ -34,9 +34,8 @@ ScreenShape::ScreenShape(int shapeType, Number option1, Number option2, Number o
 	this->shapeType = shapeType;
 	width = option1;
 	height = option2;
-
-	hitwidth = width;
-	hitheight = height;
+	
+	setHitbox(width, height);
 
 	this->option1 = option1;
 	this->option2 = option2;
@@ -93,8 +92,7 @@ void ScreenShape::setShapeSize(Number newWidth, Number newHeight) {
 	width = newWidth;
 	height = newHeight;
 	
-	hitwidth = width;
-	hitheight = height;	
+	setHitbox(width, height);
 	
 	Number whalf = floor(width/2.0f);
 	Number hhalf = floor(height/2.0f);

+ 20 - 5
Core/Contents/Source/PolyScreenSprite.cpp

@@ -77,7 +77,7 @@ void ScreenSprite::playAnimation(const String& name, int startFrame, bool once)
 	paused = false;
 	for(int i=0; i < animations.size(); i++) {
 		if(animations[i]->name == name) {
-			if(currentAnimation == animations[i])
+			if(currentAnimation == animations[i] && !playingOnce)
 				return;
 			currentFrame = 0;			
 			currentAnimation = animations[i];
@@ -93,6 +93,16 @@ void ScreenSprite::Pause(bool val) {
 	paused = val;
 }
 
+void ScreenSprite::showFrame(unsigned int frameIndex) {
+	if(!currentAnimation)
+		return;
+
+	if(frameIndex < currentAnimation->numFrames) {
+		currentFrame = frameIndex;
+		updateSprite();
+	}
+}
+
 void ScreenSprite::Update() {
 	if(!currentAnimation)
 		return;
@@ -115,6 +125,14 @@ void ScreenSprite::Update() {
 		}
 	}
 	
+	updateSprite();
+			
+	lastTick = newTick;
+		
+	}
+}
+
+void ScreenSprite::updateSprite() {
 	Number xOffset = currentAnimation->framesOffsets[currentFrame].x;
 	Number yOffset = 1.0f - currentAnimation->framesOffsets[currentFrame].y - spriteUVHeight;
 	
@@ -126,8 +144,5 @@ void ScreenSprite::Update() {
 	imagePolygon->getVertex(3)->setTexCoord(xOffset, yOffset);	
 		
 	mesh->arrayDirtyMap[RenderDataArray::TEXCOORD_DATA_ARRAY] = true;
-		
-	lastTick = newTick;
-		
-	}
+
 }

+ 39 - 0
Core/Contents/Source/PolyThreaded.cpp

@@ -0,0 +1,39 @@
+
+#include "PolyThreaded.h"
+#include "PolyCore.h"
+
+using namespace Polycode;
+
+Threaded::Threaded() : EventDispatcher() {
+	threadRunning = true;
+	scheduledForRemoval = false;
+}
+
+Threaded::~Threaded() {
+	core->removeThread(this);
+}
+
+void Threaded::killThread() {
+	threadRunning = false;
+}
+
+void Threaded::runThread(){
+	while(threadRunning) {
+		updateThread();
+	}
+}
+
+void Threaded::dispatchEvent(Event *event, int eventCode) {
+	core->lockMutex(eventMutex);
+	event->setEventCode(eventCode);
+	eventQueue.push_back(event);
+	core->unlockMutex(eventMutex);	
+}
+		
+void Threaded::dispatchEventNoDelete(Event *event, int eventCode) {
+	core->lockMutex(eventMutex);
+	event->setEventCode(eventCode);
+	event->deleteOnDispatch = false;
+	eventQueue.push_back(event);	
+	core->unlockMutex(eventMutex);			
+}

+ 0 - 1
Examples/C++/Contents/2DShapes/HelloPolycodeApp.h

@@ -6,7 +6,6 @@ using namespace Polycode;
 class HelloPolycodeApp : public EventHandler {
 public:
     HelloPolycodeApp(PolycodeView *view);
-    ~HelloPolycodeApp();
     bool Update();
     
 private:

+ 24 - 1
Modules/Contents/2DPhysics/Include/PolyPhysicsScreen.h

@@ -176,6 +176,21 @@ public:
 	* @return The physics entity wrapper.
 	*/
 	PhysicsScreenEntity *addPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction=0.1, Number density=1, Number restitution = 0, bool isSensor = false, bool fixedRotation = false);
+
+	/**
+	* Tracks a ScreenEntity as a physics enabled child. 
+	* @param newEntity Screen entity to add.
+	* @param entType Physics entity type to add as. Possible values are PhysicsScreenEntity::ENTITY_RECT, PhysicsScreenEntity::ENTITY_CIRCLE and PhysicsScreenEntity::ENTITY_MESH. If the type is ENTITY_MESH, the ScreenEntity passed must be a ScreenMesh!
+	* @param isStatic If this parameter is true, the body is static (doesn't move on its own).
+	* @param friction Friction of the physics entity. Friction controls how entities drag along each other.
+	* @param density Density of the physics entity. Density controls how heavy the entity is.
+	* @param restitution Restitution of the physics entity. Restitution controls how bouncy the entity is.
+	* @param isSensor If this is set to true, the entity won't collide with other entities, but its collision will register.
+	* @param fixedRotation If this is set to true, the entity will always have a locked rotation.
+	* @return The physics entity wrapper.
+	*/
+	PhysicsScreenEntity *trackPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction=0.1, Number density=1, Number restitution = 0, bool isSensor = false, bool fixedRotation = false);
+
 	
 	/**
 	* Removes a physics child from the screen.
@@ -188,13 +203,21 @@ public:
 	
 	
 	/**
-	* Begins tracking collisions for a ScreenEntity.
+	* Begins tracking collisions for a ScreenEntity and adds it to the scene.
 	* @param newEntity Entity to track collisions for.
 	* @param entType Physics shape of the entity. Possible values are PhysicsScreenEntity::ENTITY_RECT or PhysicsScreenEntity::ENTITY_CIRCLE.
 	* @param entityToRemove Entity to remove from the screen.
 	*/	
 	PhysicsScreenEntity *addCollisionChild(ScreenEntity *newEntity, int entType);
 	
+	/**
+	* Begins tracking collisions for a ScreenEntity.
+	* @param newEntity Entity to track collisions for.
+	* @param entType Physics shape of the entity. Possible values are PhysicsScreenEntity::ENTITY_RECT or PhysicsScreenEntity::ENTITY_CIRCLE.
+	* @param entityToRemove Entity to remove from the screen.
+	*/	
+	PhysicsScreenEntity *trackCollisionChild(ScreenEntity *newEntity, int entType);	
+	
 	/**
 	* Removes an existing joint.
 	* @param joint Joint to remove.

+ 0 - 3
Modules/Contents/2DPhysics/Include/PolyPhysicsScreenEntity.h

@@ -78,9 +78,6 @@ namespace Polycode {
 		protected:
 		
 		Number worldScale;
-		Vector2 lastPosition;
-		Number lastRotation;
-			
 		ScreenEntity *screenEntity;
 	};
 

+ 12 - 0
Modules/Contents/2DPhysics/Source/PolyPhysicsScreen.cpp

@@ -316,6 +316,13 @@ PhysicsScreenEntity *PhysicsScreen::addCollisionChild(ScreenEntity *newEntity, i
 	return ret;
 }
 
+PhysicsScreenEntity *PhysicsScreen::trackCollisionChild(ScreenEntity *newEntity, int entType) {
+	PhysicsScreenEntity *ret;
+	ret = trackPhysicsChild(newEntity, entType, false, 0,0.0,0, true);
+	ret->collisionOnly = true; 
+	return ret;
+}
+
 void PhysicsScreen::setTransform(ScreenEntity *ent, Vector2 pos, Number angle) {
 	PhysicsScreenEntity *pEnt = getPhysicsByScreenEntity(ent);
 	if(pEnt == NULL)
@@ -433,6 +440,10 @@ void PhysicsScreen::destroyMouseJoint(b2MouseJoint *mJoint) {
 
 PhysicsScreenEntity *PhysicsScreen::addPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction, Number density, Number restitution, bool isSensor, bool fixedRotation) {
 	addChild(newEntity);
+	return trackPhysicsChild(newEntity, entType, isSensor, friction, density, restitution, isSensor, fixedRotation);
+}
+
+PhysicsScreenEntity *PhysicsScreen::trackPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction, Number density, Number restitution, bool isSensor, bool fixedRotation) {
 	newEntity->setPositionMode(ScreenEntity::POSITION_CENTER);
 	PhysicsScreenEntity *newPhysicsEntity = new PhysicsScreenEntity(newEntity, world, worldScale, entType, isStatic, friction, density, restitution, isSensor,fixedRotation);
 	physicsChildren.push_back(newPhysicsEntity);
@@ -440,6 +451,7 @@ PhysicsScreenEntity *PhysicsScreen::addPhysicsChild(ScreenEntity *newEntity, int
 	return newPhysicsEntity;
 }
 
+
 void PhysicsScreen::removePhysicsChild(ScreenEntity *entityToRemove) {
 	PhysicsScreenEntity *physicsEntityToRemove = getPhysicsByScreenEntity(entityToRemove);
 	if(!physicsEntityToRemove) {

+ 20 - 28
Modules/Contents/2DPhysics/Source/PolyPhysicsScreenEntity.cpp

@@ -35,7 +35,7 @@ PhysicsScreenEntity::PhysicsScreenEntity(ScreenEntity *entity, b2World *world, N
 	
 	this->worldScale = worldScale;
 	
-	Vector3 entityScale = entity->getScale();
+	Vector3 entityScale = entity->getCompoundScale();
 	
 	screenEntity = entity;
 	
@@ -109,9 +109,6 @@ PhysicsScreenEntity::PhysicsScreenEntity(ScreenEntity *entity, b2World *world, N
 	
 	fixture = body->CreateFixture(&fDef);	
 	
-	lastPosition.x = screenEntity->getPosition2D().x;
-	lastPosition.y = screenEntity->getPosition2D().y;
-
 	collisionOnly = false;
 	
 }
@@ -135,34 +132,29 @@ void PhysicsScreenEntity::setTransform(Vector2 pos, Number angle) {
 }
 
 void PhysicsScreenEntity::Update() {
-	b2Vec2 position = body->GetPosition();
-	Number angle = body->GetAngle();
-
-	
-	if(collisionOnly) {
-		body->SetTransform(position, screenEntity->getRotation()*(PI/180.0f));		
-	} else {
-		screenEntity->setRotation(angle*(180.0f/PI));	
-	}
-	
 	if(collisionOnly) {
+		Matrix4 matrix = screenEntity->getConcatenatedMatrix();
 		b2Vec2 newPos;
-		newPos.x = screenEntity->getPosition2D().x/worldScale; 
-		newPos.y = screenEntity->getPosition2D().y/worldScale;				
-		body->SetTransform(newPos, screenEntity->getRotation()*(PI/180.0f));
-		position.x = screenEntity->getPosition2D().x/worldScale; 
-		position.y = screenEntity->getPosition2D().y/worldScale; 				
+		Number newRotation;
+		
+		Vector3 pos = matrix.getPosition();
+		newPos.x = pos.x/worldScale;
+		newPos.y = pos.y/worldScale;		
+
+		Number rx,ry,rz;
+
+		matrix.getEulerAngles(&rx, &ry, &rz);
+		newRotation = rz;
+
+		body->SetAwake(true);
+		body->SetTransform(newPos, newRotation * TORADIANS);
 	} else {
+		b2Vec2 position = body->GetPosition();
+		Number angle = body->GetAngle();	
+		screenEntity->setRotation(angle*(180.0f/PI));	
 		screenEntity->setPosition(position.x*worldScale, position.y*worldScale);
-	}
-	
-	screenEntity->dirtyMatrix(true);
-	screenEntity->rebuildTransformMatrix();
-	
-	lastPosition.x = position.x*worldScale;
-	lastPosition.y = position.y*worldScale;	
-	
-	lastRotation = angle * (180.0f/PI);
+		screenEntity->rebuildTransformMatrix();		
+	}	
 }
 
 PhysicsScreenEntity::~PhysicsScreenEntity() {

+ 2 - 0
Modules/Contents/3DPhysics/Include/PolyPhysicsScene.h

@@ -118,6 +118,8 @@ namespace Polycode {
 		PhysicsGenericConstraint *createGenericConstraint(SceneEntity *entity);
 				
 		void setVelocity(SceneEntity *entity, Vector3 velocity);
+		void setSpin(SceneEntity *entity, Vector3 spin);
+				
 		void warpEntity(SceneEntity *entity, Vector3 position, bool resetRotation = false);
 		
 		void applyImpulse(SceneEntity *entity, Vector3 force, Vector3 point);

+ 4 - 0
Modules/Contents/3DPhysics/Include/PolyPhysicsSceneEntity.h

@@ -50,6 +50,10 @@ namespace Polycode {
 		void setFriction(Number friction);		
 		int getType() { return type; }	
 		
+		void setSpin(Vector3 spin);
+		
+		void setMass(Number mass);
+		
 			void setVelocity(Vector3 velocity);
 			void warpTo(Vector3 position, bool resetRotation);
 			

+ 8 - 0
Modules/Contents/3DPhysics/Source/PolyPhysicsScene.cpp

@@ -166,6 +166,14 @@ void PhysicsScene::setVelocity(SceneEntity *entity, Vector3 velocity) {
 	}
 }
 
+void PhysicsScene::setSpin(SceneEntity *entity, Vector3 spin) {
+	PhysicsSceneEntity *physicsEntity = getPhysicsEntityBySceneEntity(entity);
+	if(physicsEntity) {
+		physicsEntity->setSpin(spin);
+	}
+}
+
+
 void PhysicsScene::warpEntity(SceneEntity *entity, Vector3 position, bool resetRotation) {
 	PhysicsSceneEntity *physicsEntity = getPhysicsEntityBySceneEntity(entity);
 	if(physicsEntity) {

+ 9 - 0
Modules/Contents/3DPhysics/Source/PolyPhysicsSceneEntity.cpp

@@ -223,6 +223,10 @@ void PhysicsSceneEntity::setFriction(Number friction) {
 		rigidBody->setFriction(friction);
 }
 
+void PhysicsSceneEntity::setMass(Number mass) {
+	rigidBody->setMassProps(mass, btVector3(0.0, 0.0, 0.0));
+}
+
 void PhysicsSceneEntity::Update() {		
 	Matrix4 m;
 		
@@ -244,6 +248,11 @@ void PhysicsSceneEntity::setVelocity(Vector3 velocity) {
 //	rigidBody->applyForce(btVector3(velocity.x, velocity.y, velocity.z), btVector3(0,0,0));
 }
 
+void PhysicsSceneEntity::setSpin(Vector3 spin) {
+	btVector3 angularVel = btVector3(spin.x, spin.y, spin.z);	
+	rigidBody->setAngularVelocity(angularVel);
+}
+
 void PhysicsSceneEntity::applyImpulse(Vector3 direction, Vector3 point) {
 	btVector3 imp = btVector3(direction.x, direction.y, direction.z);
 	btVector3 pos = btVector3(point.x, point.y, point.z);

+ 19 - 4
Modules/Contents/Curl/PolycodeDownloader.cpp

@@ -23,22 +23,37 @@ String PolycodeDownloader::getDataAsString() {
 	return ret;
 }
 		
-PolycodeDownloader::PolycodeDownloader(String url) {
-	
+PolycodeDownloader::PolycodeDownloader(String url) : Threaded() {
+	this->url = url;
 	data = (char*)malloc(0);
 	size = 0;
-	
+	returned = false;
+}
+
+bool PolycodeDownloader::writeToFile(String fileName) {
+	FILE *f = fopen(fileName.c_str(), "wb");
+	if(!f)
+		return false;	
+	fwrite(data, 1, size, f);
+	fclose(f);	
+	return true;
+}
+
+void PolycodeDownloader::runThread() {
 	curl = curl_easy_init();
 		
 	curl_easy_setopt(curl, CURLOPT_URL, url.c_str());	
 	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DownloaderCallback);
 	curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
+	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
 			
 	CURLcode curl_res = curl_easy_perform(curl);
 	
 	curl_easy_cleanup(curl);	
-	
+
+	returned = true;	
 	dispatchEvent(new Event(Event::COMPLETE_EVENT), Event::COMPLETE_EVENT);
+
 }
 
 PolycodeDownloader::~PolycodeDownloader() {

+ 13 - 4
Modules/Contents/Curl/PolycodeDownloader.h

@@ -1,20 +1,29 @@
+#pragma once
 
 #include <Polycode.h>
 #include <curl/curl.h>
 
 using namespace Polycode;
 
-class PolycodeDownloader : public EventDispatcher {
+class PolycodeDownloader : public Threaded {
 	public:
 		PolycodeDownloader(String url);
-		~PolycodeDownloader();		
+		virtual ~PolycodeDownloader();		
+		
+		void runThread();
 		
 		String getDataAsString();
 		
+		bool writeToFile(String fileName);
+		
 		char *data;
 		size_t size;
-				
-	protected:
 		
+		bool returned;
+		
+		void *userData;
+		
+	protected:
+		String url;		
 		CURL *curl;
 };

+ 5 - 1
Modules/Contents/Networking/Include/PolyPeer.h

@@ -70,7 +70,11 @@ namespace Polycode {
 		Address address;
 	};
 		
-	class _PolyExport Peer : public Threaded, public EventDispatcher {
+#if USE_THREADED_SOCKETS == 1		
+	class _PolyExport Peer : public Threaded {
+#else
+	class _PolyExport Peer : public EventDispatcher {
+#endif
 		public:
 			Peer(unsigned int port);
 			~Peer();

+ 1 - 1
Modules/Contents/Networking/Include/PolySocket.h

@@ -30,7 +30,7 @@ THE SOFTWARE.
 #define MAX_PACKET_SIZE 400
 
 // if set to 1, will create a thread for each network socket
-#define USE_THREADED_SOCKETS 0
+#define USE_THREADED_SOCKETS 1
 
 // Socket poll interval time in msecs
 #define SOCKET_POLL_INTERVAL 5

+ 5 - 1
Modules/Contents/Networking/Source/PolyPeer.cpp

@@ -36,7 +36,11 @@ void PeerConnection::ackPackets(unsigned int ack) {
 	}
 }
 
-Peer::Peer(unsigned int port) : EventDispatcher(), Threaded() {
+#if USE_THREADED_SOCKETS == 1
+	Peer::Peer(unsigned int port) : Threaded() {
+#else
+	Peer::Peer(unsigned int port) : EventDispatcher() {
+#endif
 	socket = new Socket(port);
 	socket->addEventListener(this, SocketEvent::EVENT_DATA_RECEIVED);
 

+ 1 - 0
Modules/Contents/TUIO/Include/TUIOInputModule.h

@@ -18,6 +18,7 @@ class TUIOEvent {
 	public:
 		std::vector<TouchInfo> touches;		
 		unsigned int type;
+		TouchInfo touch;
 };
 
 class TUIOInputModule : public PolycodeModule, TuioListener {

+ 3 - 1
Modules/Contents/TUIO/Include/osc/OscHostEndianness.h

@@ -61,7 +61,9 @@
 
 #else
 
-#error please edit OSCHostEndianness.h to configure endianness
+#define OSC_HOST_LITTLE_ENDIAN 1
+#undef OSC_HOST_BIG_ENDIAN
+//#error please edit OSCHostEndianness.h to configure endianness
 
 #endif
 

+ 21 - 4
Modules/Contents/TUIO/Source/TUIOInputModule.cpp

@@ -46,6 +46,10 @@ void TUIOInputModule::addTuioCursor(TuioCursor *tcur) {
 	event.type = InputEvent::EVENT_TOUCHES_BEGAN;
 	event.touches = touches;
 	
+	event.touch.position.x = tcur->getX();
+	event.touch.position.y = tcur->getY();
+	event.touch.id = tcur->getCursorID();
+	
 	CoreServices::getInstance()->getCore()->lockMutex(eventMutex);
 	events.push_back(event);					
 	CoreServices::getInstance()->getCore()->unlockMutex(eventMutex);
@@ -68,6 +72,10 @@ void TUIOInputModule::updateTuioCursor(TuioCursor *tcur) {
 	event.type = InputEvent::EVENT_TOUCHES_MOVED;
 	event.touches = touches;
 	
+	event.touch.position.x = tcur->getX();
+	event.touch.position.y = tcur->getY();
+	event.touch.id = tcur->getCursorID();
+		
 	CoreServices::getInstance()->getCore()->lockMutex(eventMutex);
 	events.push_back(event);					
 	CoreServices::getInstance()->getCore()->unlockMutex(eventMutex);
@@ -85,11 +93,15 @@ void TUIOInputModule::removeTuioCursor(TuioCursor *tcur) {
 			touch.id= tuioCursor->getCursorID();			
 			touches.push_back(touch);
 	}
-	tuioClient->unlockCursorList();	
+	tuioClient->unlockCursorList();
 	TUIOEvent event;
 	event.type = InputEvent::EVENT_TOUCHES_ENDED;
 	event.touches = touches;
 	
+	event.touch.position.x = tcur->getX();
+	event.touch.position.y = tcur->getY();
+	event.touch.id = tcur->getCursorID();	
+	
 	CoreServices::getInstance()->getCore()->lockMutex(eventMutex);
 	events.push_back(event);					
 	CoreServices::getInstance()->getCore()->unlockMutex(eventMutex);
@@ -102,24 +114,29 @@ void TUIOInputModule::Update(Number elapsed) {
 
 	Core *core = CoreServices::getInstance()->getCore();
 
+	core->lockMutex(core->eventMutex);	
 	CoreServices::getInstance()->getCore()->lockMutex(eventMutex);
 	for(int i=0; i < events.size(); i++) {
 		for(int j=0; j < events[i].touches.size(); j++) {
 			events[i].touches[j].position.x = events[i].touches[j].position.x * core->getXRes();
 			events[i].touches[j].position.y = events[i].touches[j].position.y * core->getYRes();			
 		}
+		events[i].touch.position.x = events[i].touch.position.x * core->getXRes();
+		events[i].touch.position.y = events[i].touch.position.y * core->getYRes();
+		
 		switch(events[i].type) {
 			case InputEvent::EVENT_TOUCHES_BEGAN:
-				CoreServices::getInstance()->getCore()->getInput()->touchesBegan(events[i].touches, core->getTicks());
+				CoreServices::getInstance()->getCore()->getInput()->touchesBegan(events[i].touch, events[i].touches, core->getTicks());
 			break;
 			case InputEvent::EVENT_TOUCHES_MOVED:
-				CoreServices::getInstance()->getCore()->getInput()->touchesMoved(events[i].touches, core->getTicks());
+				CoreServices::getInstance()->getCore()->getInput()->touchesMoved(events[i].touch, events[i].touches, core->getTicks());
 			break;
 			case InputEvent::EVENT_TOUCHES_ENDED:
-				CoreServices::getInstance()->getCore()->getInput()->touchesEnded(events[i].touches, core->getTicks());			
+				CoreServices::getInstance()->getCore()->getInput()->touchesEnded(events[i].touch, events[i].touches, core->getTicks());			
 			break;			
 		}
 	}
 	events.clear();
+	core->unlockMutex(core->eventMutex);	
 	CoreServices::getInstance()->getCore()->unlockMutex(eventMutex);	
 }

+ 2 - 4
Modules/Contents/UI/Source/PolyUIBox.cpp

@@ -30,8 +30,7 @@ UIBox::UIBox(String imageFile, Number t, Number r, Number b, Number l, Number bo
 	
 	width=boxWidth;
 	height = boxHeight;
-	hitwidth = boxWidth;
-	hitheight = boxHeight;
+	setHitbox(boxWidth, boxHeight);
 	
 	tlImage = new ScreenImage(imageFile);
 	tlImage->setImageCoordinates(0,0,l,t);
@@ -106,8 +105,7 @@ void UIBox::resizeBox(Number newWidth, Number newHeight) {
 	
 	width=newWidth;
 	height = newHeight;
-	hitwidth = newWidth;
-	hitheight = newHeight;
+	setHitbox(newWidth, newHeight);
 	
 	this->rebuildTransformMatrix();
 }

+ 2 - 4
Modules/Contents/UI/Source/PolyUIScrollContainer.cpp

@@ -42,8 +42,7 @@ UIScrollContainer::UIScrollContainer(ScreenEntity *scrolledEntity, bool hScroll,
 	
 	this->width = width;
 	this->height = height;
-	this->hitwidth = width;
-	this->hitheight = height;
+	setHitbox(width, height);
 	
 	Number uiScrollPanePadding = conf->getNumericValue("Polycode", "uiScrollPanePadding");			
 	
@@ -84,8 +83,7 @@ UIScrollContainer::UIScrollContainer(ScreenEntity *scrolledEntity, bool hScroll,
 void UIScrollContainer::Resize(int x, int y) {
 	width = x;
 	height = y;
-	hitwidth = width;
-	hitheight = height;
+	setHitbox(width, height);
 	
 	maskShape->setShapeSize(x, y);
 	vScrollBar->Resize(y);

+ 1 - 2
Modules/Contents/UI/Source/PolyUITextInput.cpp

@@ -124,8 +124,7 @@ UITextInput::UITextInput(bool multiLine, Number width, Number height) : ScreenEn
 	focusable = true;
 	this->width = width;
 	this->height = rectHeight;
-	hitwidth = width;
-	hitheight = rectHeight;
+	setHitbox(width, rectHeight);
 	
 	updateCaretPosition();
 }

+ 1 - 2
Modules/Contents/UI/Source/PolyUITree.cpp

@@ -259,8 +259,7 @@ void UITree::refreshTree() {
 	}
 	height = treeHeight + cellHeight;
 	width = treeWidth;
-	hitwidth = width;
-	hitheight = height;
+	setHitbox(width, height);
 	
 	selection->visible = selected;
 	dispatchEvent(new UITreeEvent(), UITreeEvent::NEED_REFRESH_EVENT);	

+ 3 - 6
Modules/Contents/UI/Source/PolyUITreeContainer.cpp

@@ -58,8 +58,7 @@ UITreeContainer::UITreeContainer(String icon, String text, Number treeWidth, Num
 	
 	width = treeWidth;
 	height = treeHeight;
-	hitwidth = width;
-	hitheight = height;
+	setHitbox(width, height);
 }
 
 void UITreeContainer::Resize(int x, int y) {
@@ -68,10 +67,8 @@ void UITreeContainer::Resize(int x, int y) {
 	mainContainer->setPositionY(0);
 
 //	width = x;
-//	height = y;
-	hitwidth = x;
-	hitheight = y;
-
+	//	height = y;
+	setHitbox(x, y);
 }
 
 void UITreeContainer::handleEvent(Event *event) {

+ 2 - 4
Modules/Contents/UI/Source/PolyUIVScrollBar.cpp

@@ -84,14 +84,12 @@ UIVScrollBar::UIVScrollBar(Number width, Number height, Number initialRatio) : S
 	this->height = height;
 	this->width = width;	
 	
-	this->hitwidth = width;
-	this->hitheight = height;	
+	setHitbox(width, height);
 }
 
 void UIVScrollBar::Resize(int newHeight) {
 	bgBox->resizeBox(width, newHeight);
-	this->height = newHeight;
-	this->hitheight = newHeight;
+	setHeight(newHeight);
 	dragRectHeight = height-(padding*2)-scrollHandleHeight;	
 	handleBox->setDragLimits(Rectangle(padding,padding,width-(padding*2)-(width-(padding*2)), dragRectHeight));	
 }

+ 1 - 2
Modules/Contents/UI/Source/PolyUIWindow.cpp

@@ -80,8 +80,7 @@ UIWindow::UIWindow(String windowName, Number width, Number height) : ScreenEntit
 	
 	this->width = width;
 	this->height = height;
-	this->hitwidth = width;
-	this->hitheight = height;
+	setHitbox(width, height);
 	
 	focusable = true;
 	blockMouseInput = true;