Sfoglia il codice sorgente

Emscripten support code

James Urquhart 11 anni fa
parent
commit
9e8d7921be
76 ha cambiato i file con 11193 aggiunte e 63 eliminazioni
  1. 78 0
      engine/compilers/cmake-modules/CopyFiles.cmake
  2. 14 0
      engine/compilers/cmake-modules/MakeTargetDirs.cmake
  3. 484 0
      engine/compilers/emscripten/CMakeLists.txt
  4. 448 0
      engine/compilers/emscripten/assets/CMakeLists.txt
  5. 5 0
      engine/compilers/emscripten/generate.sh
  6. 5 0
      engine/compilers/emscripten/generate_release.sh
  7. 1 1
      engine/lib/ljpeg/jconfig.h
  8. 2 2
      engine/lib/openal/LINUX/al/alc.h
  9. 1 1
      engine/lib/openal/LINUX/al/alc_func.h
  10. 3 0
      engine/lib/openal/LINUX/al/alctypes.h
  11. 7 0
      engine/lib/openal/LINUX/al/altypes.h
  12. 11 7
      engine/source/2d/gui/SceneWindow.cc
  13. 8 0
      engine/source/2d/sceneobject/Scroller.cc
  14. 1 1
      engine/source/2d/sceneobject/ShapeVector.cc
  15. 14 5
      engine/source/audio/audio.cc
  16. 4 4
      engine/source/audio/audio_ScriptBinding.cc
  17. 6 0
      engine/source/console/compiler.cc
  18. 1 1
      engine/source/console/metaScripting_ScriptBinding.cc
  19. 6 1
      engine/source/game/defaultGame.cc
  20. 50 4
      engine/source/graphics/TextureManager.cc
  21. 19 19
      engine/source/graphics/dgl.cc
  22. 13 0
      engine/source/graphics/gBitmap.cc
  23. 2 1
      engine/source/graphics/gBitmap.h
  24. 1 1
      engine/source/graphics/gFont.cc
  25. 1 1
      engine/source/gui/editor/guiFilterCtrl.cc
  26. 1 1
      engine/source/gui/editor/guiGraphCtrl.cc
  27. 1 1
      engine/source/gui/editor/guiMenuBar.cc
  28. 2 2
      engine/source/gui/guiCanvas.cc
  29. 1 1
      engine/source/gui/guiColorPicker.cc
  30. 1 1
      engine/source/gui/guiConsoleTextCtrl.cc
  31. 1 1
      engine/source/gui/guiControl.cc
  32. 1 1
      engine/source/gui/guiPopUpCtrlEx.cc
  33. 2 2
      engine/source/gui/guiSliderCtrl.cc
  34. 1 1
      engine/source/gui/guiTextEditSliderCtrl.cc
  35. 10 1
      engine/source/memory/dataChunker.cc
  36. 13 0
      engine/source/platform/platformAL.h
  37. 13 2
      engine/source/platform/platformAudio.h
  38. 2 0
      engine/source/platform/platformGL.h
  39. 16 0
      engine/source/platform/types.gcc.h
  40. 53 0
      engine/source/platformEmscripten/EmscriptenAlerts.cpp
  41. 41 0
      engine/source/platformEmscripten/EmscriptenAudio.cpp
  42. 35 0
      engine/source/platformEmscripten/EmscriptenCPUInfo.cpp
  43. 142 0
      engine/source/platformEmscripten/EmscriptenConsole.cpp
  44. 65 0
      engine/source/platformEmscripten/EmscriptenConsole.h
  45. 39 0
      engine/source/platformEmscripten/EmscriptenDialogs.cpp
  46. 65 0
      engine/source/platformEmscripten/EmscriptenEvents.cpp
  47. 1216 0
      engine/source/platformEmscripten/EmscriptenFileio.cpp
  48. 99 0
      engine/source/platformEmscripten/EmscriptenFont.cpp
  49. 60 0
      engine/source/platformEmscripten/EmscriptenFont.h
  50. 371 0
      engine/source/platformEmscripten/EmscriptenGL.cpp
  51. 586 0
      engine/source/platformEmscripten/EmscriptenGL2ES.cpp
  52. 1430 0
      engine/source/platformEmscripten/EmscriptenGL2ES.h
  53. 332 0
      engine/source/platformEmscripten/EmscriptenInput.cpp
  54. 1828 0
      engine/source/platformEmscripten/EmscriptenInputManager.cpp
  55. 195 0
      engine/source/platformEmscripten/EmscriptenInputManager.h
  56. 81 0
      engine/source/platformEmscripten/EmscriptenMath.cpp
  57. 67 0
      engine/source/platformEmscripten/EmscriptenMemory.cpp
  58. 63 0
      engine/source/platformEmscripten/EmscriptenMutex.cpp
  59. 198 0
      engine/source/platformEmscripten/EmscriptenNet.cpp
  60. 462 0
      engine/source/platformEmscripten/EmscriptenOGLVideo.cpp
  61. 57 0
      engine/source/platformEmscripten/EmscriptenOGLVideo.h
  62. 237 0
      engine/source/platformEmscripten/EmscriptenOutlineGL.cpp
  63. 51 0
      engine/source/platformEmscripten/EmscriptenOutlineGL.h
  64. 69 0
      engine/source/platformEmscripten/EmscriptenPlatform.cpp
  65. 77 0
      engine/source/platformEmscripten/EmscriptenProcessControl.cpp
  66. 53 0
      engine/source/platformEmscripten/EmscriptenSemaphore.cpp
  67. 400 0
      engine/source/platformEmscripten/EmscriptenStrings.cpp
  68. 184 0
      engine/source/platformEmscripten/EmscriptenThread.cpp
  69. 88 0
      engine/source/platformEmscripten/EmscriptenTime.cpp
  70. 508 0
      engine/source/platformEmscripten/EmscriptenWindow.cpp
  71. 77 0
      engine/source/platformEmscripten/dummy.c
  72. 199 0
      engine/source/platformEmscripten/main.cpp
  73. 73 0
      engine/source/platformEmscripten/menus/popupMenu.cpp
  74. 77 0
      engine/source/platformEmscripten/platform.js
  75. 116 0
      engine/source/platformEmscripten/platformEmscripten.h
  76. 249 0
      engine/source/platformEmscripten/platformGL.h

+ 78 - 0
engine/compilers/cmake-modules/CopyFiles.cmake

@@ -0,0 +1,78 @@
+include(MakeTargetDirs)
+ 
+# copyFiles(target
+#	[ALL]
+#	COMMAND <cmd>
+#	[ARGUMENTS <arg1> ... <argN>]
+#	[OUTPUT_DIR <dir>]
+#	[FORMAT <ext>]
+#	FILES <source1> ... <sourceN>
+#	[OUTPUT_FILES <outputVar>]
+# )
+function(copyFiles Target)
+	CMAKE_PARSE_ARGUMENTS(
+		ARGS
+		"ALL"
+		"OUTPUT_DIR;OUTPUT_FILES;INPUT_DIR;ARGUMENTS"
+		"FILES"
+		${ARGN}
+	)
+ 
+	# Argument flags.
+ 
+	if (ARGS_ALL)
+		set(ARGS_ALL "ALL")
+	else()
+		set(ARGS_ALL)
+	endif()
+ 
+	# Argument options.
+ 
+	if (ARGS_OUTPUT_DIR)
+		file(TO_CMAKE_PATH ${ARGS_OUTPUT_DIR} ARGS_OUTPUT_DIR)
+	endif()
+ 
+	foreach(SrcFile ${ARGS_FILES})
+		set(DstFile ${SrcFile})
+
+		# Set src filename
+ 
+		# Set destination filename to absolute.
+		if (ARGS_INPUT_DIR)
+			set(RealSrcFile ${ARGS_INPUT_DIR}/${SrcFile})
+		else()
+			set(RealSrcFile ${SrcFile})
+		endif()
+ 
+		# Set destination filename to absolute.
+		if (ARGS_OUTPUT_DIR)
+			get_filename_component(DstFile ${DstFile} NAME)
+			set(DstFile ${ARGS_OUTPUT_DIR}/${DstFile})
+		else()
+			set(DstFile ${OUTPUT_DIR}/${DstFile})
+		endif()
+ 
+		get_filename_component(SrcFileFull ${RealSrcFile} ABSOLUTE)
+ 
+		# Command needs existence of target directories.
+		makeTargetDirs(${DstFile})
+
+		#message("COPY ${SrcFileFull} TO ${DstFile} DEPENDS ${RealSrcFile}")
+ 
+		add_custom_command(
+			OUTPUT ${DstFile}
+			COMMAND cp ${SrcFileFull} ${DstFile}
+			DEPENDS ${RealSrcFile}
+			VERBATIM
+		)
+ 
+		list(APPEND DstFiles ${DstFile})
+	endforeach()
+ 
+	if(ARGS_OUTPUT_FILES)
+		set(${ARGS_OUTPUT_FILES} ${${ARGS_OUTPUT_FILES}} ${DstFiles} PARENT_SCOPE)
+	else()
+		add_custom_target(${Target} ${ARGS_ALL} DEPENDS ${DstFiles})
+	endif()
+endfunction()
+ 

+ 14 - 0
engine/compilers/cmake-modules/MakeTargetDirs.cmake

@@ -0,0 +1,14 @@
+# makeTargetDirs(<file1> ... <fileN>)
+function(makeTargetDirs)
+	foreach(TargetFile ${ARGV})
+		get_filename_component(TargetAbsPath ${TargetFile} PATH)
+		if(TargetAbsPath)
+			if(NOT IS_ABSOLUTE ${TargetAbsPath})
+				set(TargetAbsPath ${CMAKE_CURRENT_BINARY_DIR}/${TargetAbsPath})
+			endif()
+			if(NOT EXISTS ${TargetAbsPath})
+				file(MAKE_DIRECTORY ${TargetAbsPath})
+			endif()
+		endif()
+	endforeach()
+endfunction()

+ 484 - 0
engine/compilers/emscripten/CMakeLists.txt

@@ -0,0 +1,484 @@
+cmake_minimum_required(VERSION 2.8.3)
+
+Project(Torque2D)
+
+# Set required paths
+set(BASE_OUTPUT_DIR ${CMAKE_BINARY_DIR})
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/../cmake-modules")
+
+# Add modules
+INCLUDE(CheckCCompilerFlag)
+INCLUDE(CopyFiles)
+INCLUDE(CMakeParseArguments)
+
+# Add assets script
+add_subdirectory(assets)
+
+INCLUDE_DIRECTORIES(
+	../../source
+    ../../lib/zlib
+    ../../lib/lpng
+    ../../lib/ljpeg
+    ../../source/persistence/rapidjson/include
+    ../../source/testing/googleTest
+    ../../source/testing/googleTest/include
+)
+
+ADD_DEFINITIONS(-DEMSCRIPTEN=1)
+ADD_DEFINITIONS(-DUNICODE=1)
+ADD_DEFINITIONS(-w)
+
+SET(T2D_SRCS
+    ../../lib/lpng/png.c
+    ../../lib/lpng/pngerror.c
+    ../../lib/lpng/pngget.c
+    ../../lib/lpng/pngmem.c
+    ../../lib/lpng/pngpread.c
+    ../../lib/lpng/pngread.c
+    ../../lib/lpng/pngrio.c
+    ../../lib/lpng/pngrtran.c
+    ../../lib/lpng/pngrutil.c
+    ../../lib/lpng/pngset.c
+    ../../lib/lpng/pngtrans.c
+    ../../lib/lpng/pngwio.c
+    ../../lib/lpng/pngwrite.c
+    ../../lib/lpng/pngwtran.c
+    ../../lib/lpng/pngwutil.c
+    ../../lib/zlib/adler32.c
+    ../../lib/zlib/crc32.c
+    ../../lib/zlib/compress.c
+    ../../lib/zlib/deflate.c
+    ../../lib/zlib/infback.c
+    ../../lib/zlib/inffast.c
+    ../../lib/zlib/inflate.c
+    ../../lib/zlib/inftrees.c
+    ../../lib/zlib/trees.c
+    ../../lib/zlib/uncompr.c
+    ../../lib/zlib/zutil.c
+    ../../lib/ljpeg/jdapistd.c
+    ../../lib/ljpeg/jdmaster.c
+    ../../lib/ljpeg/jdapimin.c
+    ../../lib/ljpeg/jcapimin.c
+    ../../lib/ljpeg/jdmerge.c
+    ../../lib/ljpeg/jdatasrc.c
+    ../../lib/ljpeg/jdatadst.c
+    ../../lib/ljpeg/jdcoefct.c
+    ../../lib/ljpeg/jdcolor.c
+    ../../lib/ljpeg/jddctmgr.c
+    ../../lib/ljpeg/jdhuff.c
+    ../../lib/ljpeg/jdinput.c
+    ../../lib/ljpeg/jdmainct.c
+    ../../lib/ljpeg/jdmarker.c
+    ../../lib/ljpeg/jdpostct.c
+    ../../lib/ljpeg/jdsample.c
+    ../../lib/ljpeg/jdtrans.c
+    ../../lib/ljpeg/jerror.c
+    ../../lib/ljpeg/jidctflt.c
+    ../../lib/ljpeg/jidctfst.c
+    ../../lib/ljpeg/jidctint.c
+    ../../lib/ljpeg/jmemmgr.c
+    ../../lib/ljpeg/jutils.c
+    ../../lib/ljpeg/jmemnobs.c
+    ../../lib/ljpeg/jquant1.c
+    ../../lib/ljpeg/jquant2.c
+    ../../lib/ljpeg/jcomapi.c
+    ../../lib/ljpeg/jcmarker.c
+    ../../lib/ljpeg/jcapistd.c
+    ../../lib/ljpeg/jcparam.c
+    ../../lib/ljpeg/jcinit.c
+    ../../lib/ljpeg/jcdctmgr.c
+    ../../lib/ljpeg/jccoefct.c
+    ../../lib/ljpeg/jcmainct.c
+    ../../lib/ljpeg/jfdctflt.c
+    ../../lib/ljpeg/jfdctint.c
+    ../../lib/ljpeg/jfdctfst.c
+    ../../lib/ljpeg/jchuff.c
+    ../../lib/ljpeg/jcsample.c
+    ../../lib/ljpeg/jcmaster.c
+    ../../lib/ljpeg/jccolor.c
+    ../../lib/ljpeg/jcprepct.c
+    ../../lib/ljpeg/jdphuff.c
+    ../../lib/ljpeg/jcphuff.c
+    ../../lib/ljpeg/jidctred.c
+    ../../source/2d/scene/SceneRenderFactories.cpp
+	../../source/2d/scene/SceneRenderQueue.cpp
+	../../source/box2d/Collision/b2BroadPhase.cpp
+	../../source/box2d/Collision/b2CollideCircle.cpp
+	../../source/box2d/Collision/b2CollideEdge.cpp
+	../../source/box2d/Collision/b2CollidePolygon.cpp
+	../../source/box2d/Collision/b2Collision.cpp
+	../../source/box2d/Collision/b2Distance.cpp
+	../../source/box2d/Collision/b2DynamicTree.cpp
+	../../source/box2d/Collision/b2TimeOfImpact.cpp
+	../../source/box2d/Collision/Shapes/b2ChainShape.cpp
+	../../source/box2d/Collision/Shapes/b2CircleShape.cpp
+	../../source/box2d/Collision/Shapes/b2EdgeShape.cpp
+	../../source/box2d/Collision/Shapes/b2PolygonShape.cpp
+	../../source/box2d/Common/b2BlockAllocator.cpp
+	../../source/box2d/Common/b2Draw.cpp
+	../../source/box2d/Common/b2Math.cpp
+	../../source/box2d/Common/b2Settings.cpp
+	../../source/box2d/Common/b2StackAllocator.cpp
+	../../source/box2d/Common/b2Timer.cpp
+	../../source/box2d/Dynamics/b2Body.cpp
+	../../source/box2d/Dynamics/b2ContactManager.cpp
+	../../source/box2d/Dynamics/b2Fixture.cpp
+	../../source/box2d/Dynamics/b2Island.cpp
+	../../source/box2d/Dynamics/b2World.cpp
+	../../source/box2d/Dynamics/b2WorldCallbacks.cpp
+	../../source/box2d/Dynamics/Contacts/b2ChainAndCircleContact.cpp
+	../../source/box2d/Dynamics/Contacts/b2ChainAndPolygonContact.cpp
+	../../source/box2d/Dynamics/Contacts/b2CircleContact.cpp
+	../../source/box2d/Dynamics/Contacts/b2Contact.cpp
+	../../source/box2d/Dynamics/Contacts/b2ContactSolver.cpp
+	../../source/box2d/Dynamics/Contacts/b2EdgeAndCircleContact.cpp
+	../../source/box2d/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp
+	../../source/box2d/Dynamics/Contacts/b2PolygonAndCircleContact.cpp
+	../../source/box2d/Dynamics/Contacts/b2PolygonContact.cpp
+	../../source/box2d/Dynamics/Joints/b2DistanceJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2FrictionJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2GearJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2Joint.cpp
+	../../source/box2d/Dynamics/Joints/b2MotorJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2MouseJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2PrismaticJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2PulleyJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2RevoluteJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2RopeJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2WeldJoint.cpp
+	../../source/box2d/Dynamics/Joints/b2WheelJoint.cpp
+	../../source/box2d/Rope/b2Rope.cpp
+	../../source/collection/nameTags.cpp
+	../../source/component/behaviors/behaviorComponent.cpp
+	../../source/component/behaviors/behaviorInstance.cpp
+	../../source/component/behaviors/behaviorTemplate.cpp
+	../../source/component/dynamicConsoleMethodComponent.cpp
+	../../source/component/simComponent.cpp
+	../../source/delegates/delegateSignal.cpp
+	../../source/graphics/PNGImage.cpp
+	../../source/math/rectClipper.cpp
+	../../source/persistence/SimXMLDocument.cpp
+	../../source/persistence/tinyXML/tinystr.cpp
+	../../source/persistence/tinyXML/tinyxml.cpp
+	../../source/persistence/tinyXML/tinyxmlerror.cpp
+	../../source/persistence/tinyXML/tinyxmlparser.cpp
+	../../source/platform/nativeDialogs/msgBox.cpp
+	../../source/sim/simSerialize.cpp
+	../../source/string/stringUnit.cpp
+	../../source/2d/assets/AnimationAsset.cc
+	../../source/2d/assets/ImageAsset.cc
+	../../source/2d/assets/ParticleAsset.cc
+	../../source/2d/assets/ParticleAssetEmitter.cc
+	../../source/2d/assets/ParticleAssetField.cc
+	../../source/2d/assets/ParticleAssetFieldCollection.cc
+	../../source/2d/controllers/AmbientForceController.cc
+	../../source/2d/controllers/BuoyancyController.cc
+	../../source/2d/controllers/core/GroupedSceneController.cc
+	../../source/2d/controllers/core/PickingSceneController.cc
+	../../source/2d/controllers/PointForceController.cc
+	../../source/2d/core/BatchRender.cc
+	../../source/2d/core/CoreMath.cc
+	../../source/2d/core/ImageFrameProvider.cc
+	../../source/2d/core/ImageFrameProviderCore.cc
+	../../source/2d/core/ParticleSystem.cc
+	../../source/2d/core/RenderProxy.cc
+	../../source/2d/core/SpriteBase.cc
+	../../source/2d/core/SpriteBatch.cc
+	../../source/2d/core/SpriteBatchItem.cc
+	../../source/2d/core/SpriteBatchQuery.cc
+	../../source/2d/core/Utility.cc
+	../../source/2d/core/Vector2.cc
+	../../source/2d/experimental/composites/WaveComposite.cc
+	../../source/2d/gui/guiImageButtonCtrl.cc
+	../../source/2d/gui/guiSceneObjectCtrl.cc
+	../../source/2d/gui/guiSpriteCtrl.cc
+	../../source/2d/gui/SceneWindow.cc
+	../../source/2d/scene/ContactFilter.cc
+	../../source/2d/scene/DebugDraw.cc
+	../../source/2d/scene/Scene.cc
+	../../source/2d/scene/WorldQuery.cc
+	../../source/2d/sceneobject/CompositeSprite.cc
+	../../source/2d/sceneobject/ImageFont.cc
+	../../source/2d/sceneobject/ParticlePlayer.cc
+	../../source/2d/sceneobject/SceneObject.cc
+	../../source/2d/sceneobject/SceneObjectList.cc
+	../../source/2d/sceneobject/SceneObjectSet.cc
+	../../source/2d/sceneobject/Scroller.cc
+	../../source/2d/sceneobject/ShapeVector.cc
+	../../source/2d/sceneobject/Sprite.cc
+	../../source/2d/sceneobject/Trigger.cc
+	../../source/algorithm/crc.cc
+	../../source/algorithm/hashFunction.cc
+	../../source/assets/assetBase.cc
+	../../source/assets/assetFieldTypes.cc
+	../../source/assets/assetManager.cc
+	../../source/assets/assetQuery.cc
+	../../source/assets/assetTagsManifest.cc
+	../../source/assets/declaredAssets.cc
+	../../source/assets/referencedAssets.cc
+	../../source/audio/audio.cc
+	../../source/audio/audio_ScriptBinding.cc
+	../../source/audio/AudioAsset.cc
+	../../source/audio/audioBuffer.cc
+	../../source/audio/audioDataBlock.cc
+	../../source/audio/audioStreamSourceFactory.cc
+	../../source/audio/wavStreamSource.cc
+	../../source/collection/bitTables.cc
+	../../source/collection/hashTable.cc
+	../../source/collection/undo.cc
+	../../source/collection/vector.cc
+	../../source/console/astAlloc.cc
+	../../source/console/astNodes.cc
+	../../source/console/cmdgram.cc
+	../../source/console/CMDscan.cc
+	../../source/console/codeBlock.cc
+	../../source/console/compiledEval.cc
+	../../source/console/compiler.cc
+	../../source/console/console.cc
+	../../source/console/consoleBaseType.cc
+	../../source/console/consoleDictionary.cc
+	../../source/console/consoleDoc.cc
+	../../source/console/consoleExprEvalState.cc
+	../../source/console/consoleFunctions.cc
+	../../source/console/consoleLogger.cc
+	../../source/console/consoleNamespace.cc
+	../../source/console/consoleObject.cc
+	../../source/console/consoleParser.cc
+	../../source/console/consoleTypes.cc
+	../../source/console/ConsoleTypeValidators.cc
+	../../source/console/metaScripting_ScriptBinding.cc
+	../../source/console/Package.cc
+	../../source/debug/profiler.cc
+	../../source/debug/remote/RemoteDebugger1.cc
+	../../source/debug/remote/RemoteDebuggerBase.cc
+	../../source/debug/remote/RemoteDebuggerBridge.cc
+	../../source/debug/telnetDebugger.cc
+	../../source/game/defaultGame.cc
+	../../source/game/gameConnection.cc
+	../../source/game/gameInterface.cc
+	../../source/game/version.cc
+	../../source/graphics/bitmapBmp.cc
+	../../source/graphics/bitmapJpeg.cc
+	../../source/graphics/bitmapPng.cc
+	../../source/graphics/color.cc
+	../../source/graphics/dgl.cc
+	../../source/graphics/dglMatrix.cc
+	../../source/graphics/DynamicTexture.cc
+	../../source/graphics/gBitmap.cc
+	../../source/graphics/gFont.cc
+	../../source/graphics/gPalette.cc
+	../../source/graphics/splineUtil.cc
+	../../source/graphics/TextureDictionary.cc
+	../../source/graphics/TextureHandle.cc
+	../../source/graphics/TextureManager.cc
+	../../source/gui/buttons/guiBitmapButtonCtrl.cc
+	../../source/gui/buttons/guiBorderButton.cc
+	../../source/gui/buttons/guiButtonBaseCtrl.cc
+	../../source/gui/buttons/guiButtonCtrl.cc
+	../../source/gui/buttons/guiCheckBoxCtrl.cc
+	../../source/gui/buttons/guiIconButtonCtrl.cc
+	../../source/gui/buttons/guiRadioCtrl.cc
+	../../source/gui/buttons/guiToolboxButtonCtrl.cc
+	../../source/gui/containers/guiAutoScrollCtrl.cc
+	../../source/gui/containers/guiCtrlArrayCtrl.cc
+	../../source/gui/containers/guiDragAndDropCtrl.cc
+	../../source/gui/containers/guiDynamicCtrlArrayCtrl.cc
+	../../source/gui/containers/guiFormCtrl.cc
+	../../source/gui/containers/guiFrameCtrl.cc
+	../../source/gui/containers/guiPaneCtrl.cc
+	../../source/gui/containers/guiRolloutCtrl.cc
+	../../source/gui/containers/guiScrollCtrl.cc
+	../../source/gui/containers/guiStackCtrl.cc
+	../../source/gui/containers/guiTabBookCtrl.cc
+	../../source/gui/containers/guiWindowCtrl.cc
+	../../source/gui/editor/guiControlListPopup.cc
+	../../source/gui/editor/guiDebugger.cc
+	../../source/gui/editor/guiEditCtrl.cc
+	../../source/gui/editor/guiFilterCtrl.cc
+	../../source/gui/editor/guiGraphCtrl.cc
+	../../source/gui/editor/guiImageList.cc
+	../../source/gui/editor/guiInspector.cc
+	../../source/gui/editor/guiInspectorTypes.cc
+	../../source/gui/editor/guiMenuBar.cc
+	../../source/gui/editor/guiSeparatorCtrl.cc
+	../../source/gui/guiArrayCtrl.cc
+	../../source/gui/guiBackgroundCtrl.cc
+	../../source/gui/guiBitmapBorderCtrl.cc
+	../../source/gui/guiBitmapCtrl.cc
+	../../source/gui/guiCanvas.cc
+	../../source/gui/guiColorPicker.cc
+	../../source/gui/guiConsole.cc
+	../../source/gui/guiConsoleEditCtrl.cc
+	../../source/gui/guiConsoleTextCtrl.cc
+	../../source/gui/guiControl.cc
+	../../source/gui/guiDefaultControlRender.cc
+	../../source/gui/guiFadeinBitmapCtrl.cc
+	../../source/gui/guiInputCtrl.cc
+	../../source/gui/guiListBoxCtrl.cc
+	../../source/gui/guiMessageVectorCtrl.cc
+	../../source/gui/guiMLTextCtrl.cc
+	../../source/gui/guiMLTextEditCtrl.cc
+	../../source/gui/guiPopUpCtrl.cc
+	../../source/gui/guiPopUpCtrlEx.cc
+	../../source/gui/guiProgressCtrl.cc
+	../../source/gui/guiScriptNotifyControl.cc
+	../../source/gui/guiSliderCtrl.cc
+	../../source/gui/guiTabPageCtrl.cc
+	../../source/gui/guiTextCtrl.cc
+	../../source/gui/guiTextEditCtrl.cc
+	../../source/gui/guiTextEditSliderCtrl.cc
+	../../source/gui/guiTextListCtrl.cc
+	../../source/gui/guiTickCtrl.cc
+	../../source/gui/guiTypes.cc
+	../../source/gui/language/lang.cc
+	../../source/gui/messageVector.cc
+	../../source/input/actionMap.cc
+	../../source/io/bitStream.cc
+	../../source/io/bufferStream.cc
+	../../source/io/fileObject.cc
+	../../source/io/fileStream.cc
+	../../source/io/fileStreamObject.cc
+	../../source/io/fileSystem_ScriptBinding.cc
+	../../source/io/filterStream.cc
+	../../source/io/memStream.cc
+	../../source/io/nStream.cc
+	../../source/io/resizeStream.cc
+	../../source/io/resource/resourceDictionary.cc
+	../../source/io/resource/resourceManager.cc
+	../../source/io/streamObject.cc
+	../../source/io/zip/centralDir.cc
+	../../source/io/zip/compressor.cc
+	../../source/io/zip/deflate.cc
+	../../source/io/zip/extraField.cc
+	../../source/io/zip/fileHeader.cc
+	../../source/io/zip/stored.cc
+	../../source/io/zip/zipArchive.cc
+	../../source/io/zip/zipCryptStream.cc
+	../../source/io/zip/zipObject.cc
+	../../source/io/zip/zipSubStream.cc
+	../../source/io/zip/zipTempStream.cc
+	../../source/math/math_ScriptBinding.cc
+	../../source/math/mathTypes.cc
+	../../source/math/mathUtils.cc
+	../../source/math/mBox.cc
+	../../source/math/mMath_C.cc
+	../../source/math/mMathAltivec.cc
+	../../source/math/mMathAMD.cc
+	../../source/math/mMathFn.cc
+	../../source/math/mMathSSE.cc
+	../../source/math/mMatrix.cc
+	../../source/math/mPlaneTransformer.cc
+	../../source/math/mQuadPatch.cc
+	../../source/math/mQuat.cc
+	../../source/math/mRandom.cc
+	../../source/math/mSolver.cc
+	../../source/math/mSplinePatch.cc
+	../../source/memory/dataChunker.cc
+	../../source/memory/frameAllocator_ScriptBinding.cc
+	../../source/messaging/dispatcher.cc
+	../../source/messaging/eventManager.cc
+	../../source/messaging/message.cc
+	../../source/messaging/messageForwarder.cc
+	../../source/messaging/scriptMsgListener.cc
+	../../source/module/moduleDefinition.cc
+	../../source/module/moduleManager.cc
+	../../source/module/moduleMergeDefinition.cc
+	../../source/network/connectionProtocol.cc
+	../../source/network/connectionStringTable.cc
+	../../source/network/httpObject.cc
+	../../source/network/netConnection.cc
+	../../source/network/netDownload.cc
+	../../source/network/netEvent.cc
+	../../source/network/netGhost.cc
+	../../source/network/netInterface.cc
+	../../source/network/netObject.cc
+	../../source/network/netStringTable.cc
+	../../source/network/netTest.cc
+	../../source/network/networkProcessList.cc
+	../../source/network/RemoteCommandEvent.cc
+	../../source/network/serverQuery.cc
+	../../source/network/tcpObject.cc
+	../../source/network/telnetConsole.cc
+	../../source/persistence/taml/binary/tamlBinaryReader.cc
+	../../source/persistence/taml/binary/tamlBinaryWriter.cc
+	../../source/persistence/taml/json/tamlJSONParser.cc
+	../../source/persistence/taml/json/tamlJSONReader.cc
+	../../source/persistence/taml/json/tamlJSONWriter.cc
+	../../source/persistence/taml/taml.cc
+	../../source/persistence/taml/tamlCustom.cc
+	../../source/persistence/taml/tamlWriteNode.cc
+	../../source/persistence/taml/xml/tamlXmlParser.cc
+	../../source/persistence/taml/xml/tamlXmlReader.cc
+	../../source/persistence/taml/xml/tamlXmlWriter.cc
+	../../source/platform/CursorManager.cc
+	../../source/platform/menus/popupMenu.cc
+	../../source/platform/nativeDialogs/fileDialog.cc
+	../../source/platform/platform.cc
+	../../source/platform/platformAssert.cc
+	../../source/platform/platformCPU.cc
+	../../source/platform/platformFileIO.cc
+	../../source/platform/platformFont.cc
+	../../source/platform/platformMemory.cc
+	../../source/platform/platformNetwork_ScriptBinding.cc
+	../../source/platform/platformString.cc
+	../../source/platform/platformVideo.cc
+	../../source/platform/Tickable.cc
+	../../source/sim/scriptGroup.cc
+	../../source/sim/scriptObject.cc
+	../../source/sim/simBase.cc
+	../../source/sim/simConsoleEvent.cc
+	../../source/sim/simConsoleThreadExecEvent.cc
+	../../source/sim/simDatablock.cc
+	../../source/sim/simDictionary.cc
+	../../source/sim/simFieldDictionary.cc
+	../../source/sim/simManager.cc
+	../../source/sim/simObject.cc
+	../../source/sim/SimObjectList.cc
+	../../source/sim/simSet.cc
+	../../source/string/findMatch.cc
+	../../source/string/stringBuffer.cc
+	../../source/string/stringStack.cc
+	../../source/string/stringTable.cc
+	../../source/string/unicode.cc
+	../../source/platformEmscripten/EmscriptenAlerts.cpp
+	../../source/platformEmscripten/EmscriptenAudio.cpp
+	../../source/platformEmscripten/EmscriptenConsole.cpp
+	../../source/platformEmscripten/EmscriptenCPUInfo.cpp
+	../../source/platformEmscripten/EmscriptenDialogs.cpp
+	../../source/platformEmscripten/EmscriptenEvents.cpp
+	../../source/platformEmscripten/EmscriptenFileio.cpp
+	../../source/platformEmscripten/EmscriptenFont.cpp
+	../../source/platformEmscripten/EmscriptenGL.cpp
+	../../source/platformEmscripten/EmscriptenInput.cpp
+	../../source/platformEmscripten/EmscriptenInputManager.cpp
+	../../source/platformEmscripten/EmscriptenMath.cpp
+	../../source/platformEmscripten/EmscriptenMemory.cpp
+	../../source/platformEmscripten/EmscriptenMutex.cpp
+	../../source/platformEmscripten/EmscriptenNet.cpp
+	../../source/platformEmscripten/EmscriptenOGLVideo.cpp
+	../../source/platformEmscripten/EmscriptenOutlineGL.cpp
+	../../source/platformEmscripten/EmscriptenPlatform.cpp
+	../../source/platformEmscripten/EmscriptenProcessControl.cpp
+	../../source/platformEmscripten/EmscriptenSemaphore.cpp
+	../../source/platformEmscripten/EmscriptenStrings.cpp
+	../../source/platformEmscripten/EmscriptenThread.cpp
+	../../source/platformEmscripten/EmscriptenTime.cpp
+	../../source/platformEmscripten/EmscriptenWindow.cpp
+	../../source/platformEmscripten/main.cpp
+	../../source/platformEmscripten/menus/popupMenu.cpp
+)
+
+IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
+	set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} --js-library ../../source/platformEmscripten/platform.js --preload-file ${BASE_OUTPUT_DIR}/data@/ -s TOTAL_MEMORY=134217728 -O0 -s LEGACY_GL_EMULATION=1")#" -s TOTAL_MEMORY=134217728)
+	set(CMAKE_CXX__FLAGS "${CMAKE_CXX_LINK_FLAGS} -O0")
+ELSEIF(CMAKE_BUILD_TYPE STREQUAL "Release")
+	set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} --js-library ../../source/platformEmscripten/platform.js --preload-file ${BASE_OUTPUT_DIR}/data@/ -s TOTAL_MEMORY=134217728 -O2 -s LEGACY_GL_EMULATION=1")#" -s TOTAL_MEMORY=134217728)
+	set(CMAKE_CXX__FLAGS "${CMAKE_CXX_LINK_FLAGS} -O2")
+ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug")
+
+ADD_EXECUTABLE(Torque2D.html
+${T2D_SRCS})
+add_dependencies(Torque2D.html Assets)
+
+#em_link_js_library
+

+ 448 - 0
engine/compilers/emscripten/assets/CMakeLists.txt

@@ -0,0 +1,448 @@
+# List of processed files.
+set(OUTPUT_DIR "${BASE_OUTPUT_DIR}/data")
+set(OUTPUT_BUILD_DIR "${CMAKE_BINARY_DIR}/data_build")
+
+set(AssetFiles
+	main.cs
+	modules/AlphaBlendToy/1/main.cs
+	modules/AlphaBlendToy/1/module.taml
+	modules/AmbientForceControllerToy/1/main.cs
+	modules/AmbientForceControllerToy/1/module.taml
+	modules/AngleToy/1/main.cs
+	modules/AngleToy/1/module.taml
+	modules/AppCore/1/main.cs
+	modules/AppCore/1/module.taml
+	modules/AppCore/1/scripts/canvas.cs
+	modules/AppCore/1/scripts/constants.cs
+	modules/AppCore/1/scripts/defaultPreferences.cs
+	modules/AppCore/1/scripts/openal.cs
+	modules/BridgeToy/1/main.cs
+	modules/BridgeToy/1/module.taml
+	modules/BuoyancyControllerToy/1/assets/images/waveCrests.asset.taml
+	modules/BuoyancyControllerToy/1/assets/images/waveCrests.png
+	modules/BuoyancyControllerToy/1/main.cs
+	modules/BuoyancyControllerToy/1/module.taml
+	modules/ChainToy/1/main.cs
+	modules/ChainToy/1/module.taml
+	modules/CollisionToy/1/main.cs
+	modules/CollisionToy/1/module.taml
+	modules/CompositeSpriteToy/1/assets/images/isotiles.png
+	modules/CompositeSpriteToy/1/assets/images/isotiles2.asset.taml
+	modules/CompositeSpriteToy/1/main.cs
+	modules/CompositeSpriteToy/1/module.taml
+	modules/CompositeSpriteToy/1/scripts/customLayout.cs
+	modules/CompositeSpriteToy/1/scripts/isoLayout.cs
+	modules/CompositeSpriteToy/1/scripts/noLayout.cs
+	modules/CompositeSpriteToy/1/scripts/rectLayout.cs
+	modules/CompoundObjectsToy/1/main.cs
+	modules/CompoundObjectsToy/1/module.taml
+	modules/Experiments/WaveCompositeToy/1/main.cs
+	modules/Experiments/WaveCompositeToy/1/module.taml
+	modules/ImageFontToy/1/main.cs
+	modules/ImageFontToy/1/module.taml
+	modules/MoveToToy/1/main.cs
+	modules/MoveToToy/1/module.taml
+	modules/MultiWindowToy/1/main.cs
+	modules/MultiWindowToy/1/module.taml
+	modules/PickingToy/1/main.cs
+	modules/PickingToy/1/module.taml
+	modules/PointForceControllerToy/1/main.cs
+	modules/PointForceControllerToy/1/module.taml
+	modules/PyramidToy/1/main.cs
+	modules/PyramidToy/1/module.taml
+	modules/RestitutionToy/1/main.cs
+	modules/RestitutionToy/1/module.taml
+	modules/RotateToToy/1/main.cs
+	modules/RotateToToy/1/module.taml
+	modules/Sandbox/1/assets/cannotRender.asset.taml
+	modules/Sandbox/1/assets/cannotRender.png
+	modules/Sandbox/1/assets/gui/blueGradient.asset.taml
+	modules/Sandbox/1/assets/gui/blueGradient.png
+	modules/Sandbox/1/assets/gui/gglogo.asset.taml
+	modules/Sandbox/1/assets/gui/gglogo.png
+	modules/Sandbox/1/assets/gui/largeContainer.asset.taml
+	modules/Sandbox/1/assets/gui/largeContainer.png
+	modules/Sandbox/1/assets/gui/mediumCancelDown.asset.taml
+	modules/Sandbox/1/assets/gui/mediumCancelDown.png
+	modules/Sandbox/1/assets/gui/mediumCancelHover.asset.taml
+	modules/Sandbox/1/assets/gui/mediumCancelHover.png
+	modules/Sandbox/1/assets/gui/mediumCancelInactive.asset.taml
+	modules/Sandbox/1/assets/gui/mediumCancelInactive.png
+	modules/Sandbox/1/assets/gui/mediumCancelNormal.asset.taml
+	modules/Sandbox/1/assets/gui/mediumCancelNormal.png
+	modules/Sandbox/1/assets/gui/mediumContainer.asset.taml
+	modules/Sandbox/1/assets/gui/mediumContainer.png
+	modules/Sandbox/1/assets/gui/minusButtonDown.asset.taml
+	modules/Sandbox/1/assets/gui/minusButtonDown.png
+	modules/Sandbox/1/assets/gui/minusButtonHover.asset.taml
+	modules/Sandbox/1/assets/gui/minusButtonHover.png
+	modules/Sandbox/1/assets/gui/minusButtonInactive.asset.taml
+	modules/Sandbox/1/assets/gui/minusButtonInactive.png
+	modules/Sandbox/1/assets/gui/minusButtonNormal.asset.taml
+	modules/Sandbox/1/assets/gui/minusButtonNormal.png
+	modules/Sandbox/1/assets/gui/northArrowDown.asset.taml
+	modules/Sandbox/1/assets/gui/northArrowDown.png
+	modules/Sandbox/1/assets/gui/northArrowHover.asset.taml
+	modules/Sandbox/1/assets/gui/northArrowHover.png
+	modules/Sandbox/1/assets/gui/northArrowNormal.asset.taml
+	modules/Sandbox/1/assets/gui/northArrowNormal.png
+	modules/Sandbox/1/assets/gui/plusButtonDown.asset.taml
+	modules/Sandbox/1/assets/gui/plusButtonDown.png
+	modules/Sandbox/1/assets/gui/plusButtonHover.asset.taml
+	modules/Sandbox/1/assets/gui/plusButtonHover.png
+	modules/Sandbox/1/assets/gui/plusButtonInactive.asset.taml
+	modules/Sandbox/1/assets/gui/plusButtonInactive.png
+	modules/Sandbox/1/assets/gui/plusButtonNormal.asset.taml
+	modules/Sandbox/1/assets/gui/plusButtonNormal.png
+	modules/Sandbox/1/assets/gui/ReplayBtn128x128Down.asset.taml
+	modules/Sandbox/1/assets/gui/ReplayBtn128x128Down.png
+	modules/Sandbox/1/assets/gui/ReplayBtn128x128Hover.asset.taml
+	modules/Sandbox/1/assets/gui/ReplayBtn128x128Hover.png
+	modules/Sandbox/1/assets/gui/ReplayBtn128x128Inactive.asset.taml
+	modules/Sandbox/1/assets/gui/ReplayBtn128x128Inactive.png
+	modules/Sandbox/1/assets/gui/ReplayBtn128x128Up.asset.taml
+	modules/Sandbox/1/assets/gui/ReplayBtn128x128Up.png
+	modules/Sandbox/1/assets/gui/rotateArrowLeft.png
+	modules/Sandbox/1/assets/gui/southArrowDown.asset.taml
+	modules/Sandbox/1/assets/gui/southArrowDown.png
+	modules/Sandbox/1/assets/gui/southArrowHover.asset.taml
+	modules/Sandbox/1/assets/gui/southArrowHover.png
+	modules/Sandbox/1/assets/gui/southArrowNormal.asset.taml
+	modules/Sandbox/1/assets/gui/southArrowNormal.png
+	modules/Sandbox/1/gui/ConsoleDialog.gui.taml
+	modules/Sandbox/1/gui/guiProfiles.cs
+	modules/Sandbox/1/gui/images/blueButton.png
+	modules/Sandbox/1/gui/images/checkBox.png
+	modules/Sandbox/1/gui/images/defaultCursor.png
+	modules/Sandbox/1/gui/images/dropDown.png
+	modules/Sandbox/1/gui/images/greenButton.png
+	modules/Sandbox/1/gui/images/radioButton.png
+	modules/Sandbox/1/gui/images/redButton.png
+	modules/Sandbox/1/gui/images/scroll.png
+	modules/Sandbox/1/gui/images/scrollBar.png
+	modules/Sandbox/1/gui/images/slider.png
+	modules/Sandbox/1/gui/images/smallButtonContainer.png
+	modules/Sandbox/1/gui/images/sunkenContainer.png
+	modules/Sandbox/1/gui/images/tab.png
+	modules/Sandbox/1/gui/images/tabContainer.png
+	modules/Sandbox/1/gui/images/textEdit.png
+	modules/Sandbox/1/gui/images/textEdit_noSides.png
+	modules/Sandbox/1/gui/images/window.png
+	modules/Sandbox/1/gui/MainOverlay.gui.taml
+	modules/Sandbox/1/gui/ToolboxDialog.gui.taml
+	modules/Sandbox/1/main.cs
+	modules/Sandbox/1/module.taml
+	modules/Sandbox/1/scripts/console.cs
+	modules/Sandbox/1/scripts/customToolboxGui.cs
+	modules/Sandbox/1/scripts/manipulation.cs
+	modules/Sandbox/1/scripts/sandboxPreferences.cs
+	modules/Sandbox/1/scripts/scene.cs
+	modules/Sandbox/1/scripts/toolbox.cs
+	modules/Sandbox/1/scripts/toys.cs
+	modules/SceneLayerToy/1/main.cs
+	modules/SceneLayerToy/1/module.taml
+	modules/ShapeVectorToy/1/main.cs
+	modules/ShapeVectorToy/1/module.taml
+	modules/SoftbodyToy/1/main.cs
+	modules/SoftbodyToy/1/module.taml
+	modules/SphereStackToy/1/main.cs
+	modules/SphereStackToy/1/module.taml
+	modules/SpriteToy/1/main.cs
+	modules/SpriteToy/1/module.taml
+	modules/ToyAssets/1/assets/animations/1234Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/Cannonball_projectile_1Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/Cannonball_Projectile_2Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/Cannonball_Projectile_3Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/Ice_Projectile_1Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/Ice_Projectile_2Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/Ice_Projectile_3Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/IceCloudAnimation.asset.taml
+	modules/ToyAssets/1/assets/animations/Impact_ExplosionAnimation.asset.taml
+	modules/ToyAssets/1/assets/animations/Impact_FireCloudAnimation.asset.taml
+	modules/ToyAssets/1/assets/animations/Impact_ParticleAnimation.asset.taml
+	modules/ToyAssets/1/assets/animations/Impact_PoisonCloudAnimation.asset.taml
+	modules/ToyAssets/1/assets/animations/Poison_Projectile1Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/Poison_Projectile2Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/Poison_Projectile3Animation.asset.taml
+	modules/ToyAssets/1/assets/animations/PoisonCloudWobble.asset.taml
+	modules/ToyAssets/1/assets/animations/Projectile_FireballAnim.asset.taml
+	modules/ToyAssets/1/assets/animations/Projectile_Galvanic_BlastAnimation.asset.taml
+	modules/ToyAssets/1/assets/animations/Projectile_Meteor_StrikeAnimation.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Barbarian_Death.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Barbarian_North.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Barbarian_WalkSouth.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Barbarian_WalkWest.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_DwarfDeath.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_DwarfWalkNorth.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_DwarfWalkSouth.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_DwarfWalkWest.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Knight_Death.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Knight_MoveNorth.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Knight_MoveSouth.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Knight_MoveWest.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Wizard_Death.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Wizard_WalkNorth.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Wizard_WalkSouth.asset.taml
+	modules/ToyAssets/1/assets/animations/TD_Wizard_WalkWest.asset.taml
+	modules/ToyAssets/1/assets/animations/tileAnimation.asset.taml
+	modules/ToyAssets/1/assets/audio/BarbarianDeathSound.asset.taml
+	modules/ToyAssets/1/assets/audio/BaseAttackSound.asset.taml
+	modules/ToyAssets/1/assets/audio/buttonSound.asset.taml
+	modules/ToyAssets/1/assets/audio/CannonTowerFireSound.asset.taml
+	modules/ToyAssets/1/assets/audio/DwarfDeathSound.asset.taml
+	modules/ToyAssets/1/assets/audio/Fire_TowerFireSound.asset.taml
+	modules/ToyAssets/1/assets/audio/IceTowerFireSound.asset.taml
+	modules/ToyAssets/1/assets/audio/KnightDeathSound.asset.taml
+	modules/ToyAssets/1/assets/audio/level1Music.asset.taml
+	modules/ToyAssets/1/assets/audio/loseMusic.asset.taml
+	modules/ToyAssets/1/assets/audio/PoisonTowerFiredSound.asset.taml
+	modules/ToyAssets/1/assets/audio/TD_ButtonSound.wav
+	modules/ToyAssets/1/assets/audio/titleMusic.asset.taml
+	modules/ToyAssets/1/assets/audio/TowerMisplacementSound.asset.taml
+	modules/ToyAssets/1/assets/audio/TowerPlacementSound.asset.taml
+	modules/ToyAssets/1/assets/audio/TowerSoldSound.asset.taml
+	modules/ToyAssets/1/assets/audio/TowerUpgradeSound.asset.taml
+	modules/ToyAssets/1/assets/audio/VolleyTowerFireSound.asset.taml
+	modules/ToyAssets/1/assets/audio/WaveAnnouncementSound.asset.taml
+	modules/ToyAssets/1/assets/audio/winMusic.asset.taml
+	modules/ToyAssets/1/assets/audio/WizardDeathSound.asset.taml
+	modules/ToyAssets/1/assets/images/1234.asset.taml
+	modules/ToyAssets/1/assets/images/1234.png
+	modules/ToyAssets/1/assets/images/asteroids.asset.taml
+	modules/ToyAssets/1/assets/images/asteroids.png
+	modules/ToyAssets/1/assets/images/blank.asset.taml
+	modules/ToyAssets/1/assets/images/Blank.png
+	modules/ToyAssets/1/assets/images/blankCircle.asset.taml
+	modules/ToyAssets/1/assets/images/BlankCircle.png
+	modules/ToyAssets/1/assets/images/blocks.asset.taml
+	modules/ToyAssets/1/assets/images/Blocks.png
+	modules/ToyAssets/1/assets/images/brick_01.asset.taml
+	modules/ToyAssets/1/assets/images/brick_01.png
+	modules/ToyAssets/1/assets/images/brick_02.asset.taml
+	modules/ToyAssets/1/assets/images/brick_02.png
+	modules/ToyAssets/1/assets/images/brick_03.asset.taml
+	modules/ToyAssets/1/assets/images/brick_03.png
+	modules/ToyAssets/1/assets/images/brick_04.asset.taml
+	modules/ToyAssets/1/assets/images/brick_04.png
+	modules/ToyAssets/1/assets/images/brick_05.asset.taml
+	modules/ToyAssets/1/assets/images/brick_05.png
+	modules/ToyAssets/1/assets/images/cable.asset.taml
+	modules/ToyAssets/1/assets/images/cable.png
+	modules/ToyAssets/1/assets/images/Cannonball_projectile_1.asset.taml
+	modules/ToyAssets/1/assets/images/Cannonball_Projectile_2.asset.taml
+	modules/ToyAssets/1/assets/images/Cannonball_Projectile_3.asset.taml
+	modules/ToyAssets/1/assets/images/CardDeck.asset.taml
+	modules/ToyAssets/1/assets/images/chain.asset.taml
+	modules/ToyAssets/1/assets/images/chain.png
+	modules/ToyAssets/1/assets/images/checkered.asset.taml
+	modules/ToyAssets/1/assets/images/checkered.png
+	modules/ToyAssets/1/assets/images/Coconut.asset.taml
+	modules/ToyAssets/1/assets/images/crate.asset.taml
+	modules/ToyAssets/1/assets/images/crate.png
+	modules/ToyAssets/1/assets/images/crosshair1.asset.taml
+	modules/ToyAssets/1/assets/images/crossHair1.png
+	modules/ToyAssets/1/assets/images/crosshair2.asset.taml
+	modules/ToyAssets/1/assets/images/crosshair2.png
+	modules/ToyAssets/1/assets/images/crosshair3.asset.taml
+	modules/ToyAssets/1/assets/images/crosshair3.png
+	modules/ToyAssets/1/assets/images/crosshair4.asset.taml
+	modules/ToyAssets/1/assets/images/crosshair4.png
+	modules/ToyAssets/1/assets/images/dirtGround.asset.taml
+	modules/ToyAssets/1/assets/images/dirtGround.png
+	modules/ToyAssets/1/assets/images/fancyFont.asset.taml
+	modules/ToyAssets/1/assets/images/font.asset.taml
+	modules/ToyAssets/1/assets/images/font.png
+	modules/ToyAssets/1/assets/images/football.asset.taml
+	modules/ToyAssets/1/assets/images/football.png
+	modules/ToyAssets/1/assets/images/gems.asset.taml
+	modules/ToyAssets/1/assets/images/gems.png
+	modules/ToyAssets/1/assets/images/grassForeground.asset.taml
+	modules/ToyAssets/1/assets/images/grassForeground.png
+	modules/ToyAssets/1/assets/images/hexagon.asset.taml
+	modules/ToyAssets/1/assets/images/hexagon.png
+	modules/ToyAssets/1/assets/images/highlightBackground.asset.taml
+	modules/ToyAssets/1/assets/images/highlightBackground.png
+	modules/ToyAssets/1/assets/images/hollowArrow.asset.taml
+	modules/ToyAssets/1/assets/images/hollowArrow.png
+	modules/ToyAssets/1/assets/images/Ice_Projectile_1Sprite.asset.taml
+	modules/ToyAssets/1/assets/images/Ice_Projectile_2Sprite.asset.taml
+	modules/ToyAssets/1/assets/images/Ice_Projectile_3Sprite.asset.taml
+	modules/ToyAssets/1/assets/images/IceCloud.asset.taml
+	modules/ToyAssets/1/assets/images/Impact_Explosion.asset.taml
+	modules/ToyAssets/1/assets/images/Impact_Explosion.png
+	modules/ToyAssets/1/assets/images/Impact_FireCloud.asset.taml
+	modules/ToyAssets/1/assets/images/Impact_Particle.asset.taml
+	modules/ToyAssets/1/assets/images/Impact_PoisonCloud.asset.taml
+	modules/ToyAssets/1/assets/images/Impact_PoisonCloud.png
+	modules/ToyAssets/1/assets/images/jungleSky.asset.taml
+	modules/ToyAssets/1/assets/images/jungleSky.png
+	modules/ToyAssets/1/assets/images/jungleTree.asset.taml
+	modules/ToyAssets/1/assets/images/jungleTree.png
+	modules/ToyAssets/1/assets/images/landscapeFar.asset.taml
+	modules/ToyAssets/1/assets/images/landscapeNear.asset.taml
+	modules/ToyAssets/1/assets/images/livesIcon.asset.taml
+	modules/ToyAssets/1/assets/images/livesIcon.png
+	modules/ToyAssets/1/assets/images/particles1.asset.taml
+	modules/ToyAssets/1/assets/images/particles1.png
+	modules/ToyAssets/1/assets/images/particles2.asset.taml
+	modules/ToyAssets/1/assets/images/particles2.png
+	modules/ToyAssets/1/assets/images/particles3.asset.taml
+	modules/ToyAssets/1/assets/images/particles3.png
+	modules/ToyAssets/1/assets/images/particles4.asset.taml
+	modules/ToyAssets/1/assets/images/particles4.png
+	modules/ToyAssets/1/assets/images/particles5.asset.taml
+	modules/ToyAssets/1/assets/images/particles5.png
+	modules/ToyAssets/1/assets/images/particles6.asset.taml
+	modules/ToyAssets/1/assets/images/particles6.png
+	modules/ToyAssets/1/assets/images/particles7.asset.taml
+	modules/ToyAssets/1/assets/images/particles7.png
+	modules/ToyAssets/1/assets/images/particles8.asset.taml
+	modules/ToyAssets/1/assets/images/particles8.png
+	modules/ToyAssets/1/assets/images/particles9.asset.taml
+	modules/ToyAssets/1/assets/images/particles9.png
+	modules/ToyAssets/1/assets/images/Planetoid.asset.taml
+	modules/ToyAssets/1/assets/images/Planetoid.png
+	modules/ToyAssets/1/assets/images/Poison_Projectile1.asset.taml
+	modules/ToyAssets/1/assets/images/Poison_Projectile2.asset.taml
+	modules/ToyAssets/1/assets/images/Poison_Projectile3.asset.taml
+	modules/ToyAssets/1/assets/images/Projectile_Fireball.asset.taml
+	modules/ToyAssets/1/assets/images/Projectile_Fireball.png
+	modules/ToyAssets/1/assets/images/Projectile_Galvanic_Blast.asset.taml
+	modules/ToyAssets/1/assets/images/Projectile_Galvanic_Blast.png
+	modules/ToyAssets/1/assets/images/Projectile_Meteor_Strike.asset.taml
+	modules/ToyAssets/1/assets/images/Projectile_Meteor_Strike.png
+	modules/ToyAssets/1/assets/images/skyBackground.asset.taml
+	modules/ToyAssets/1/assets/images/skyBackground.png
+	modules/ToyAssets/1/assets/images/TD_Barbarian_Comp.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Bones_01.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Bones_02.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Bones_03.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Bones_04.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Bones_05.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Crystal_blue.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Crystal_green.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Crystal_purple.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Crystal_red.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Crystal_yellow.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Dwarf.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Gold.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Knight_Comp.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Ribs.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Stalagmite_01.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Stalagmite_02.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Stalagmite_03.asset.taml
+	modules/ToyAssets/1/assets/images/TD_TreasureChest_closed.asse.taml
+	modules/ToyAssets/1/assets/images/TD_TreasureChest_open.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Wizard_Comp.asset.taml
+	modules/ToyAssets/1/assets/images/TD_Wizard_Comp.png
+	modules/ToyAssets/1/assets/images/tiles.asset.taml
+	modules/ToyAssets/1/assets/images/tiles.png
+	modules/ToyAssets/1/assets/images/tires.asset.taml
+	modules/ToyAssets/1/assets/images/tires.png
+	modules/ToyAssets/1/assets/images/Trail_Leaf.asset.taml
+	modules/ToyAssets/1/assets/images/Trail_Leaf.png
+	modules/ToyAssets/1/assets/images/TreeBackground1.asset.taml
+	modules/ToyAssets/1/assets/images/TreeBackground2.asset.taml
+	modules/ToyAssets/1/assets/images/whiteSphere.asset.taml
+	modules/ToyAssets/1/assets/images/WhiteSphere.png
+	modules/ToyAssets/1/assets/images/woodGround.asset.taml
+	modules/ToyAssets/1/assets/images/woodGround.png
+	modules/ToyAssets/1/assets/particles/bonfire.asset.taml
+	modules/ToyAssets/1/assets/particles/forceBubble.asset.taml
+	modules/ToyAssets/1/assets/particles/impactExplosion.asset.taml
+	modules/ToyAssets/1/module.taml
+	modules/TruckToy/1/assets/images/background_day.asset.taml
+	modules/TruckToy/1/assets/images/background_day.png
+	modules/TruckToy/1/assets/images/background_night.asset.taml
+	modules/TruckToy/1/assets/images/background_night.png
+	modules/TruckToy/1/assets/images/background_nightStars.asset.taml
+	modules/TruckToy/1/assets/images/background_nightStars.png
+	modules/TruckToy/1/assets/images/brickPile.asset.taml
+	modules/TruckToy/1/assets/images/brickPile.png
+	modules/TruckToy/1/assets/images/brickWall_01.asset.taml
+	modules/TruckToy/1/assets/images/brickWall_01.png
+	modules/TruckToy/1/assets/images/brickWall_02.asset.taml
+	modules/TruckToy/1/assets/images/brickWall_02.png
+	modules/TruckToy/1/assets/images/brokenCementWall.asset.taml
+	modules/TruckToy/1/assets/images/brokenCementWall.png
+	modules/TruckToy/1/assets/images/foregroundWall_01.asset.taml
+	modules/TruckToy/1/assets/images/foregroundWall_01.png
+	modules/TruckToy/1/assets/images/foregroundWall_02.asset.taml
+	modules/TruckToy/1/assets/images/foregroundWall_02.png
+	modules/TruckToy/1/assets/images/industrial_01.asset.taml
+	modules/TruckToy/1/assets/images/industrial_01.png
+	modules/TruckToy/1/assets/images/industrial_02.asset.taml
+	modules/TruckToy/1/assets/images/industrial_02.png
+	modules/TruckToy/1/assets/images/industrial_lowOpacity.asset.taml
+	modules/TruckToy/1/assets/images/industrial_lowOpacity.png
+	modules/TruckToy/1/assets/images/industrialBuildings.asset.taml
+	modules/TruckToy/1/assets/images/industrialBuildings.png
+	modules/TruckToy/1/assets/images/motorPile.asset.taml
+	modules/TruckToy/1/assets/images/motorPile.png
+	modules/TruckToy/1/assets/images/pileORocks.asset.taml
+	modules/TruckToy/1/assets/images/pileORocks.png
+	modules/TruckToy/1/assets/images/plank_01.asset.taml
+	modules/TruckToy/1/assets/images/plank_01.png
+	modules/TruckToy/1/assets/images/plank_02.asset.taml
+	modules/TruckToy/1/assets/images/plank_02.png
+	modules/TruckToy/1/assets/images/plank_03.asset.taml
+	modules/TruckToy/1/assets/images/plank_03.png
+	modules/TruckToy/1/assets/images/rock_01.asset.taml
+	modules/TruckToy/1/assets/images/rock_01.png
+	modules/TruckToy/1/assets/images/rock_02.asset.taml
+	modules/TruckToy/1/assets/images/rock_02.png
+	modules/TruckToy/1/assets/images/rock_03.asset.taml
+	modules/TruckToy/1/assets/images/rock_03.png
+	modules/TruckToy/1/assets/images/rock_04.asset.taml
+	modules/TruckToy/1/assets/images/rock_04.png
+	modules/TruckToy/1/assets/images/rock_05.asset.taml
+	modules/TruckToy/1/assets/images/rock_05.png
+	modules/TruckToy/1/assets/images/rock_06.asset.taml
+	modules/TruckToy/1/assets/images/rock_06.png
+	modules/TruckToy/1/assets/images/tires.asset.taml
+	modules/TruckToy/1/assets/images/tires.png
+	modules/TruckToy/1/assets/images/truckBody.asset.taml
+	modules/TruckToy/1/assets/images/truckBody.png
+	modules/TruckToy/1/assets/images/woodPile.asset.taml
+	modules/TruckToy/1/assets/images/woodPile.png
+	modules/TruckToy/1/assets/images/wreckedBuilding.asset.taml
+	modules/TruckToy/1/assets/images/wreckedBuilding.png
+	modules/TruckToy/1/assets/images/wreckedCar_01.asset.taml
+	modules/TruckToy/1/assets/images/wreckedCar_01.png
+	modules/TruckToy/1/assets/images/wreckedCar_02.asset.taml
+	modules/TruckToy/1/assets/images/wreckedCar_02.png
+	modules/TruckToy/1/assets/images/wreckedCar_03.asset.taml
+	modules/TruckToy/1/assets/images/wreckedCar_03.png
+	modules/TruckToy/1/assets/images/wreckedCar_hood.asset.taml
+	modules/TruckToy/1/assets/images/wreckedCar_hood.png
+	modules/TruckToy/1/assets/particles/exhaust.asset.taml
+	modules/TruckToy/1/main.cs
+	modules/TruckToy/1/module.taml
+	modules/TumblerToy/1/main.cs
+	modules/TumblerToy/1/module.taml
+)
+
+# These needs to be compiled beforehand
+set(FontAssetFiles
+	"modules/AppCore/1/fonts/monaco 12\ (ansi).uft"
+	"modules/AppCore/1/fonts/monaco 13\ (ansi).uft"
+)
+
+set(DstAssetFiles "")
+
+copyFiles(T2D_ASSETS
+    INPUT_DIR ../../../../
+	OUTPUT_FILES DstAssetFiles
+	FILES ${AssetFiles})
+
+copyFiles(T2D_FONT_ASSETS
+    INPUT_DIR ../../../../
+	OUTPUT_FILES DstAssetFiles
+	FILES ${FontAssetFiles})
+
+#foreach(SrcFile ${DstAssetFiles})
+#	message("Assets Will copy" ${SrcFile})
+#endforeach()
+
+add_custom_target(Assets ALL DEPENDS ${DstAssetFiles})
+

+ 5 - 0
engine/compilers/emscripten/generate.sh

@@ -0,0 +1,5 @@
+#!/bin/sh
+EMSCRIPTEN_PATH=~/External/emscripten
+BUILD_TYPE=Debug
+
+cmake -DEMSCRIPTEN=1 -DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN_PATH/cmake/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_MODULE_PATH=$EMSCRIPTEN_PATH/cmake -G "Unix Makefiles" .

+ 5 - 0
engine/compilers/emscripten/generate_release.sh

@@ -0,0 +1,5 @@
+#!/bin/sh
+EMSCRIPTEN_PATH=~/External/emscripten
+BUILD_TYPE=Release
+
+cmake -DEMSCRIPTEN=1 -DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN_PATH/cmake/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_MODULE_PATH=$EMSCRIPTEN_PATH/cmake -G "Unix Makefiles" .

+ 1 - 1
engine/lib/ljpeg/jconfig.h

@@ -24,7 +24,7 @@
    #define JCONFIG_INCLUDED
 #endif
 
-#if (( __GNUC__ >= 2 ) && (defined (__CYGWIN32__) || defined (__linux__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__WIN32__)) )
+#if (( __GNUC__ >= 2 ) && (defined (__CYGWIN32__) || defined (__linux__) || defined(EMSCRIPTEN) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__WIN32__)) )
    #include "jconfig.gcc.linux.h"
    #define JCONFIG_INCLUDED
 #endif

+ 2 - 2
engine/lib/openal/LINUX/al/alc.h

@@ -34,8 +34,8 @@ extern "C" {
 ALCAPI ALCubyte*  ALCAPIENTRY alcGetString(ALCdevice *device,ALCenum param);
 ALCAPI ALCvoid    ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALCsizei size,ALCint *data);
 
-ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(ALCubyte *deviceName);
-ALCAPI ALCvoid    ALCAPIENTRY alcCloseDevice(ALCdevice *device);
+ALC_API ALCdevice *     ALC_APIENTRY alcOpenDevice( const ALCchar *devicename );
+ALC_API ALCboolean      ALC_APIENTRY alcCloseDevice( ALCdevice *device );
 
 ALCAPI ALCcontext*ALCAPIENTRY alcCreateContext(ALCdevice *device,ALCint *attrList);
 ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context);

+ 1 - 1
engine/lib/openal/LINUX/al/alc_func.h

@@ -2,7 +2,7 @@
 //AL_FUNCTION(ALCubyte*,   alcGetString, (ALCdevice *device,ALCenum param), return NULL; )
 //AL_FUNCTION(ALCvoid,     alcGetIntegerv, (ALCdevice * device,ALCenum param,ALCsizei size,ALCint *data), return; )
 
-AL_FUNCTION(ALCdevice*,  alcOpenDevice, (ALubyte *deviceName), return NULL; )
+AL_FUNCTION(ALCdevice*,  alcOpenDevice, (const ALCchar *deviceName), return NULL; )
 AL_FUNCTION(ALCvoid,     alcCloseDevice, (ALCdevice *device), return; )
 
 AL_FUNCTION(ALCcontext*, alcCreateContext, (ALCdevice *device,ALCint *attrList), return NULL; )

+ 3 - 0
engine/lib/openal/LINUX/al/alctypes.h

@@ -32,6 +32,9 @@ typedef char ALCboolean;
 /** ALC 8bit signed byte. */
 typedef char ALCbyte;
 
+/** character */
+typedef char ALCchar;
+
 /** ALC 8bit unsigned byte. */
 typedef unsigned char ALCubyte;
 

+ 7 - 0
engine/lib/openal/LINUX/al/altypes.h

@@ -234,6 +234,13 @@ typedef int ALenum;
 #define AL_BUFFERS_QUEUED                        0x1015
 #define AL_BUFFERS_PROCESSED                     0x1016
 
+/**
+ * Source buffer position information
+ */
+#define AL_SEC_OFFSET                             0x1024
+#define AL_SAMPLE_OFFSET                          0x1025
+#define AL_BYTE_OFFSET                            0x1026
+
 /** Sound buffers: format specifier. */
 #define AL_FORMAT_MONO8                          0x1100
 #define AL_FORMAT_MONO16                         0x1101

+ 11 - 7
engine/source/2d/gui/SceneWindow.cc

@@ -1763,13 +1763,17 @@ void SceneWindow::renderMetricsOverlay( Point2I offset, const RectI& updateRect
     // Calculate Debug Banner Offset.
     Point2I bannerOffset = updateRect.point + Point2I(8,8);
 
-    // Draw Banner Background.
-    glBegin(GL_TRIANGLE_STRIP);
-        glVertex2i( updateRect.point.x, updateRect.point.y );
-        glVertex2i( updateRect.point.x + updateRect.extent.x, updateRect.point.y );
-        glVertex2i( updateRect.point.x, updateRect.point.y + bannerHeight + 16);
-        glVertex2i( updateRect.point.x + updateRect.extent.x, updateRect.point.y + bannerHeight + 16);
-    glEnd();
+    static GLfloat sWindowVertices[] = {
+        (GLfloat)updateRect.point.x, (GLfloat)updateRect.point.y,
+        (GLfloat)updateRect.point.x + updateRect.extent.x, (GLfloat)updateRect.point.y,
+        (GLfloat)updateRect.point.x, (GLfloat)updateRect.point.y + bannerHeight + 16,
+        (GLfloat)updateRect.point.x + updateRect.extent.x, (GLfloat)updateRect.point.y + bannerHeight + 16
+    };
+    
+    glVertexPointer(2, GL_FLOAT, 0, sWindowVertices);
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    glDisableClientState(GL_VERTEX_ARRAY);
 
     // Disable Banner Blending.
     glDisable       ( GL_BLEND );

+ 8 - 0
engine/source/2d/sceneobject/Scroller.cc

@@ -316,6 +316,9 @@ void Scroller::sceneRender( const SceneRenderState* pSceneRenderState, const Sce
     // Flush any existing batches.
     pBatchRenderer->flush();
 
+    // jamesu - no clip planes in webgl
+#ifndef TORQUE_OS_EMSCRIPTEN
+
     // Set-up a set of clip-planes against the OOBB.
     GLdouble left[4] = {1, 0, 0, -renderOOBB0.x};
     GLdouble right[4] = {-1, 0, 0, renderOOBB1.x};
@@ -343,6 +346,8 @@ void Scroller::sceneRender( const SceneRenderState* pSceneRenderState, const Sce
     if (maxClip > 3)
     	glEnable(GL_CLIP_PLANE3);
 
+#endif
+
     // Render repeat Y.
     for ( S32 repeatIndexY = 0; repeatIndexY < wholeRegionY; ++repeatIndexY )
     {
@@ -385,6 +390,7 @@ void Scroller::sceneRender( const SceneRenderState* pSceneRenderState, const Sce
     // Flush the scroller batches.
     pBatchRenderer->flush();
 
+#ifndef TORQUE_OS_EMSCRIPTEN
     // Disable the OOBB clip-planes.
     glDisable(GL_CLIP_PLANE0);
     if (maxClip > 1)
@@ -393,6 +399,8 @@ void Scroller::sceneRender( const SceneRenderState* pSceneRenderState, const Sce
     	glDisable(GL_CLIP_PLANE2);
     if (maxClip > 3)
     	glDisable(GL_CLIP_PLANE3);
+
+#endif
 }
 
 //------------------------------------------------------------------------------

+ 1 - 1
engine/source/2d/sceneobject/ShapeVector.cc

@@ -213,7 +213,7 @@ void ShapeVector::renderCircleShape(Vector2 position, F32 radius)
 
 void ShapeVector::renderPolygonShape(U32 vertexCount)
 {
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
     // Fill Mode?
     if ( mFillMode )
     {

+ 14 - 5
engine/source/audio/audio.cc

@@ -356,7 +356,7 @@ static bool cullSource(U32 *index, F32 volume)
 static F32 approximate3DVolume(const Audio::Description& desc, const Point3F &position)
 {
    Point3F p1;
-   alGetListener3f(AL_POSITION, &p1.x, &p1.y, &p1.z);
+   alxGetListenerPoint3F(AL_POSITION, &p1);
 
    p1 -= position;
    F32 distance = p1.magnitudeSafe();
@@ -1969,7 +1969,7 @@ void alxCloseHandles()
 void alxUpdateScores(bool sourcesOnly)
 {
    Point3F listener;
-   alGetListener3f(AL_POSITION, &listener.x, &listener.y, &listener.z);
+   alxGetListenerPoint3F(AL_POSITION, &listener);
 
    // do the base sources
    for(U32 i = 0; i < mNumSources; i++)
@@ -2085,7 +2085,7 @@ void alxUpdateScores(bool sourcesOnly)
 void alxUpdateMaxDistance()
 {
    Point3F listener;
-   alGetListener3f(AL_POSITION, &listener.x, &listener.y, &listener.z);
+   alxGetListenerPoint3F(AL_POSITION, &listener);
 
    for(U32 i = 0; i < mNumSources; i++)
    {
@@ -2500,8 +2500,10 @@ bool OpenALInit()
       0
    };
    mContext = alcCreateContext(mDevice,attrlist);
-#elif TORQUE_OS_ANDROID
+#elif defined(TORQUE_OS_ANDROID)
    mContext = alcCreateContext((ALCdevice*)mDevice, NULL);
+#elif defined(TORQUE_OS_EMSCRIPTEN)
+   mContext = alcCreateContext((ALCdevice*)mDevice, NULL);;
 #else
    mContext = alcCreateContext(mDevice,NULL);
 #endif
@@ -2509,7 +2511,10 @@ bool OpenALInit()
       return false;
 
    // Make this context the active context
-#ifdef TORQUE_OS_ANDROID
+#ifdef defined(TORQUE_OS_ANDROID)
+   alcMakeContextCurrent((ALCcontext*)mContext);
+#elif defined(TORQUE_OS_EMSCRIPTEN)
+   //
    alcMakeContextCurrent((ALCcontext*)mContext);
 #else
    alcMakeContextCurrent(mContext);
@@ -2597,6 +2602,8 @@ void OpenALShutdown()
    {
 #ifdef TORQUE_OS_ANDROID
 	   alcDestroyContext((ALCcontext*)mContext);
+#elif defined(TORQUE_OS_EMSCRIPTEN)
+      alcDestroyContext((ALCcontext*)mContext);
 #else
 	   alcDestroyContext(mContext);
 #endif
@@ -2607,6 +2614,8 @@ void OpenALShutdown()
    {
 #ifdef TORQUE_OS_ANDROID
 	   alcCloseDevice((ALCdevice*)mDevice);
+#elif defined(TORQUE_OS_EMSCRIPTEN)
+      alcCloseDevice((ALCdevice*)mDevice);
 #else
 	   alcCloseDevice(mDevice);
 #endif

+ 4 - 4
engine/source/audio/audio_ScriptBinding.cc

@@ -594,7 +594,7 @@ ConsoleFunctionWithDocs(alListener3f, ConsoleVoid, 3, 5, ( ALEnum , x , y , z))
       pos.z = dAtof(argv[4]);
    }
 
-   alListener3f(e, pos.x, pos.y, pos.z);
+   alxListenerPoint3F(e, &pos);
 }
 
 
@@ -636,11 +636,11 @@ ConsoleFunctionWithDocs(alGetListener3f, ConsoleString, 2, 2, ( ALEnum ))
       return("0 0 0");
    }
 
-   F32 value1, value2, value3;
-   alGetListener3f(e, &value1, &value2, &value3);
+   Point3F v;
+   alxGetListenerPoint3F(e, &v);
 
    char * ret = Con::getReturnBuffer(64);
-   dSprintf(ret, 64, "%7.3f %7.3 %7.3", value1, value2, value3);
+   dSprintf(ret, 64, "%7.3f %7.3 %7.3", v.x, v.y, v.z);
    return(ret);
 }
 

+ 6 - 0
engine/source/console/compiler.cc

@@ -169,6 +169,12 @@ U32 CompilerStringTable::add(const char *str, bool caseSens, bool tag)
    newStr->len = len;
    newStr->tag = tag;
    dStrcpy(newStr->string, str);
+   
+#ifdef EMSCRIPTEN
+   consoleAlloc(2);
+   Con::printf("CompilerStringTable::add(%s) %s %s @ %u:%u", str, caseSens ? "CASE" : "NOCASE", tag ? "TAG" : "NOTAG", newStr->string, len);
+#endif
+
    return newStr->start;
 }
 

+ 1 - 1
engine/source/console/metaScripting_ScriptBinding.cc

@@ -510,7 +510,7 @@ ConsoleFunctionWithDocs(exec, ConsoleBool, 2, 4, ( fileName, [nocalls]?, [journa
 // work with cs files as is, as they are included with the source either way.
 
 //Also, no DSO generation on iPhone
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
       if(false) 
 #else
       if(compiled)

+ 6 - 1
engine/source/game/defaultGame.cc

@@ -126,7 +126,7 @@ bool initializeLibraries()
     // Create the stock colors.
     StockColor::create();
     
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
    //3MB default is way too big for iPhone!!!
 #ifdef	TORQUE_SHIPPING
     FrameAllocator::init(256 * 1024);	//256KB for now... but let's test and see!
@@ -344,6 +344,11 @@ bool DefaultGame::mainInitialize(int argc, const char **argv)
     if(!initializeLibraries())
         return false;
     
+#ifdef TORQUE_OS_EMSCRIPTEN
+    // temp hack
+    argc = 0;
+#endif
+    
     // Set up the command line args for the console scripts...
     Con::setIntVariable("$GameProject::argc", argc);
     U32 i;

+ 50 - 4
engine/source/graphics/TextureManager.cc

@@ -124,6 +124,28 @@ void TextureManager::postTextureEvent(const TextureEventCode eventCode)
 
 //--------------------------------------------------------------------------------------------------------------------
 
+U8 *getLuminanceAlphaBits(GBitmap *bmp)
+{
+   U8 *data = new U8[bmp->getWidth() * bmp->getHeight() * 2];
+   
+   S32 w = bmp->getWidth();
+   S32 h = bmp->getHeight();
+   U8 *src = bmp->getAddress(0, 0);
+   U8 *dest = data;
+   for (int y=0; y<h; y++)
+   {
+      for (int x=0; x<w; x++)
+      {
+         *dest++ = 255;
+         *dest++ = *src++;
+      }
+   }
+   
+   return data;
+}
+
+//--------------------------------------------------------------------------------------------------------------------
+
 void TextureManager::create()
 {
     AssertISV(mManagerState == NotInitialized, "TextureManager::create() - already created!");
@@ -358,7 +380,7 @@ void TextureManager::getSourceDestByteFormat(GBitmap *pBitmap, U32 *sourceFormat
 {
     *byteFormat = GL_UNSIGNED_BYTE;
     U32 byteSize = 1;
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
     switch(pBitmap->getFormat()) 
     {
     case GBitmap::Intensity:
@@ -369,7 +391,11 @@ void TextureManager::getSourceDestByteFormat(GBitmap *pBitmap, U32 *sourceFormat
         break;
     case GBitmap::Luminance:
         *sourceFormat = GL_LUMINANCE;
-        break;
+          break;
+    case GBitmap::LuminanceAlpha:
+          *sourceFormat = GL_LUMINANCE_ALPHA;
+          byteSize = 2;
+          break;
     case GBitmap::RGB:
         *sourceFormat = GL_RGB;
         break;
@@ -567,10 +593,27 @@ void TextureManager::refresh( TextureObject* pTextureObject )
     // Fetch bitmaps.
     GBitmap* pSourceBitmap = pTextureObject->mpBitmap;
     GBitmap* pNewBitmap = createPowerOfTwoBitmap(pSourceBitmap);
+   
+    U8 *bits = (U8*)pNewBitmap->getBits();
+    U8 *lumBits = NULL;
 
     // Fetch source/dest formats.
     U32 sourceFormat, destFormat, byteFormat, texelSize;
-    getSourceDestByteFormat(pSourceBitmap, &sourceFormat, &destFormat, &byteFormat, &texelSize);
+   
+#if defined(TORQUE_OS_EMSCRIPTEN)
+    if (pSourceBitmap->getFormat() == GBitmap::Alpha)
+    {
+        // special case: alpha should be converted to luminancealpha
+        bits = lumBits = getLuminanceAlphaBits(pNewBitmap);
+        sourceFormat = destFormat = GL_LUMINANCE_ALPHA;
+        byteFormat = GL_UNSIGNED_BYTE;
+        texelSize = 2;
+    }
+    else
+#endif
+    {
+        getSourceDestByteFormat(pSourceBitmap, &sourceFormat, &destFormat, &byteFormat, &texelSize);
+    }
 
 #if defined(TORQUE_OS_IOS)
     bool isCompressed = (pNewBitmap->getFormat() >= GBitmap::PVR2) && (pNewBitmap->getFormat() <= GBitmap::PVR4A);
@@ -633,7 +676,7 @@ void TextureManager::refresh( TextureObject* pTextureObject )
             0,
             sourceFormat,
             byteFormat,
-            pNewBitmap->getBits());
+            bits);
     }
 
     const GLuint filter = pTextureObject->getFilter();
@@ -653,6 +696,9 @@ void TextureManager::refresh( TextureObject* pTextureObject )
     {
         delete pNewBitmap;
     }
+   
+    if (lumBits)
+        delete[] lumBits;
 }
 
 //--------------------------------------------------------------------------------------------------------------------

+ 19 - 19
engine/source/graphics/dgl.cc

@@ -175,7 +175,7 @@ void dglDrawBitmapStretchSR(TextureObject* texture,
              sg_bitmapModulation.blue,
              sg_bitmapModulation.alpha);
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 
     GLfloat verts[] = {
         (GLfloat)scrPoints[0].x, (GLfloat)scrPoints[0].y,
@@ -192,7 +192,7 @@ void dglDrawBitmapStretchSR(TextureObject* texture,
     
     
     glDisableClientState(GL_COLOR_ARRAY);
-    glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
+    //glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
     glEnableClientState(GL_VERTEX_ARRAY);
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     
@@ -348,7 +348,7 @@ U32 dglDrawTextN(GFont*          font,
 
 //-----------------------------------------------------------------------------
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 U32 dglDrawTextN(GFont*          font,
                  const Point2I&  ptDraw,
                  const UTF16*    in_string,
@@ -361,7 +361,7 @@ U32 dglDrawTextN(GFont*          font,
    // return on zero length strings
    if( n < 1 )
       return ptDraw.x;
-   PROFILE_START(DrawText);
+
 
    MatrixF rotMatrix( EulerF( 0.0, 0.0, mDegToRad( rot ) ) );
    Point3F offset( ptDraw.x, ptDraw.y, 0.0 );
@@ -780,7 +780,7 @@ void dglDrawLine(S32 x1, S32 y1, S32 x2, S32 y2, const ColorI &color)
    glDisable(GL_TEXTURE_2D);
 
    glColor4ub(color.red, color.green, color.blue, color.alpha);
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
     GLfloat verts[] = {
         (GLfloat)(x1 + 0.5f), (GLfloat)(y1 + 0.5f),
         (GLfloat)(x2 + 0.5f), (GLfloat)(y2 + 0.5f),
@@ -814,7 +814,7 @@ void dglDrawRect(const Point2I &upperL, const Point2I &lowerR, const ColorI &col
    glLineWidth(lineWidth);
 
    glColor4ub(color.red, color.green, color.blue, color.alpha);
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
     GLfloat verts[] = {
         (GLfloat)(upperL.x), (GLfloat)(upperL.y),
         (GLfloat)(lowerR.x), (GLfloat)(upperL.y),
@@ -853,7 +853,7 @@ void dglDrawRectFill(const Point2I &upperL, const Point2I &lowerR, const ColorI
    glDisable(GL_TEXTURE_2D);
 
    glColor4ub(color.red, color.green, color.blue, color.alpha);
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
     GLfloat vertices[] = {
         (GLfloat)upperL.x, (GLfloat)upperL.y,
         (GLfloat)upperL.x, (GLfloat)lowerR.y,
@@ -895,7 +895,7 @@ void dglDraw2DSquare( const Point2F &screenPoint, F32 width, F32 spinAngle )
       points[i] += offset;
    }
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
     GLfloat verts[] = {
         0.0, 0.0,
         1.0, 0.0,
@@ -911,7 +911,7 @@ void dglDraw2DSquare( const Point2F &screenPoint, F32 width, F32 spinAngle )
     };
     
     glDisableClientState(GL_COLOR_ARRAY);
-    glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
+    //glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
     glEnableClientState(GL_VERTEX_ARRAY);
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     
@@ -960,7 +960,7 @@ void dglDrawBillboard( const Point3F &position, F32 width, F32 spinAngle )
    }
 
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
     GLfloat verts[] = {
         0.0, 1.0,
         0.0, 0.0,
@@ -976,7 +976,7 @@ void dglDrawBillboard( const Point3F &position, F32 width, F32 spinAngle )
     };
     
     glDisableClientState(GL_COLOR_ARRAY);
-    glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
+    //glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
     glEnableClientState(GL_VERTEX_ARRAY);
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     
@@ -1016,7 +1016,7 @@ void dglWireCube(const Point3F & extent, const Point3F & center)
 
    glDisable(GL_CULL_FACE);
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 //PUAP -Mat untested
    for (S32 i = 0; i < 6; i++)
    {
@@ -1071,7 +1071,7 @@ void dglSolidCube(const Point3F & extent, const Point3F & center)
       { 3, 2, 6, 7 }, { 7, 6, 4, 5 }, { 3, 7, 5, 1 }
    };
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 //PUAP -Mat untested
    for (S32 i = 0; i < 6; i++)
    {
@@ -1146,7 +1146,7 @@ const RectI& dglGetClipRect()
 
 bool dglPointToScreen( Point3F &point3D, Point3F &screenPoint )
 {
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
    GLfloat       glMV[16];
    GLfloat       glPR[16];
    GLint          glVP[4];
@@ -1228,7 +1228,7 @@ bool dglIsInCanonicalState()
    ret &= glIsEnabled(GL_BLEND) == GL_FALSE;
    ret &= glIsEnabled(GL_CULL_FACE) == GL_FALSE;
    GLint temp;
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 // PUAP -Mat removed unsupported textureARB and Fog stuff
    if (dglDoesSupportARBMultitexture() == true) {
       //glActiveTextureARB(GL_TEXTURE1_ARB);
@@ -1300,7 +1300,7 @@ bool dglIsInCanonicalState()
 
 void dglSetCanonicalState()
 {
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 // PUAP -Mat removed unsupported textureARB and Fog stuff
    glDisable(GL_BLEND);
    glDisable(GL_CULL_FACE);
@@ -1365,7 +1365,7 @@ void dglGetTransformState(S32* mvDepth,
    glGetFloatv(GL_TEXTURE_MATRIX, t0Matrix);
    if (dglDoesSupportARBMultitexture())
    {
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 // PUAP -Mat removed unsupported textureARB stuff
       //glActiveTextureARB(GL_TEXTURE1_ARB);
       glGetIntegerv(GL_TEXTURE_STACK_DEPTH, (GLint*)t1Depth);
@@ -1411,7 +1411,7 @@ bool dglCheckState(const S32 mvDepth, const S32 pDepth,
    glGetFloatv(GL_TEXTURE_MATRIX, t0m);
    if (dglDoesSupportARBMultitexture())
    {
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 // PUAP -Mat removed unsupported textureARB and Fog stuff
       //glActiveTextureARB(GL_TEXTURE1_ARB);
       glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &t1d);
@@ -1445,7 +1445,7 @@ bool dglCheckState(const S32 mvDepth, const S32 pDepth,
             (v.extent.y == vp[3])));
 }
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 GLfloat gVertexFloats[8];
 GLfloat gTextureVerts[8];
 #endif

+ 13 - 0
engine/source/graphics/gBitmap.cc

@@ -175,6 +175,7 @@ void GBitmap::allocateBitmap(const U32 in_width, const U32 in_height, const bool
       break;
      case RGBA:       bytesPerPixel = 4;
       break;
+     case LuminanceAlpha:
      case RGB565:
      case RGB5551:    bytesPerPixel = 2;
       break;
@@ -436,6 +437,7 @@ void GBitmap::extrudeMipLevels(bool clearBorders)
       
       case Intensity:
       case Luminance:
+      case LuminanceAlpha:
       case Alpha:
       case RGB565:
 #ifdef TORQUE_OS_IOS
@@ -626,6 +628,11 @@ bool GBitmap::getColor(const U32 x, const U32 y, ColorI& rColor) const
      case RGBA:
       rColor.set( pLoc[0], pLoc[1], pLoc[2], pLoc[3] );
       break;
+         
+     case LuminanceAlpha:
+      rColor.set( pLoc[0], pLoc[0], pLoc[0], pLoc[1] );
+      break;
+         
 
      case RGB5551:
 #if defined(TORQUE_BIG_ENDIAN)
@@ -670,6 +677,12 @@ bool GBitmap::setColor(const U32 x, const U32 y, ColorI& rColor)
      case Luminance:
       *pLoc = rColor.alpha;
       break;
+         
+     case LuminanceAlpha:
+      *pLoc = rColor.red;
+      *(pLoc+1) = rColor.alpha;
+      break;
+         
 
      case RGB:
       dMemcpy( pLoc, &rColor, 3 * sizeof( U8 ) );

+ 2 - 1
engine/source/graphics/gBitmap.h

@@ -66,7 +66,8 @@ class GBitmap: public ResourceInstance
       Alpha      = 4,
       RGB565     = 5,
       RGB5551    = 6,
-      Luminance  = 7
+      Luminance  = 7,
+      LuminanceAlpha = 8
 #ifdef TORQUE_OS_IOS
        , PVR2 = 8,
        PVR2A = 9,

+ 1 - 1
engine/source/graphics/gFont.cc

@@ -229,7 +229,7 @@ bool GFont::loadCharInfo(const UTF16 ch)
         mCharInfoList.push_back(ci);
         mRemapTable[ch] = mCharInfoList.size() - 1;
 //don't save UFTs on the iPhone or android device
-#if !defined(TORQUE_OS_IOS) && !defined(TORQUE_OS_ANDROID)
+#if !defined(TORQUE_OS_IOS) && !defined(TORQUE_OS_ANDROID) && !defined(TORQUE_OS_EMSCRIPTEN)
         mNeedSave = true;
 #endif
 

+ 1 - 1
engine/source/gui/editor/guiFilterCtrl.cc

@@ -163,7 +163,7 @@ void GuiFilterCtrl::onRender(Point2I offset, const RectI &updateRect)
    ext.x -= 4;
    ext.y -= 4;
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 	//this was the same drawing as dglDrawLine		<Mat>
 	dglDrawLine( (pos.x), (pos.y+ext.y), (pos.x+ext.x), (pos.y), ColorI(255 *0.9, 255 *0.9, 255 *0.9, 255 *1) );
 

+ 1 - 1
engine/source/gui/editor/guiGraphCtrl.cc

@@ -102,7 +102,7 @@ void GuiGraphCtrl::onRender(Point2I offset, const RectI &updateRect)
 		if (mPlots[k].mGraphData.size() == 0)
 			continue;
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 		// Bar graph
 		if(mPlots[k].mGraphType == Bar)
 		{

+ 1 - 1
engine/source/gui/editor/guiMenuBar.cc

@@ -1145,7 +1145,7 @@ void GuiMenuTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool select
    idx = mList[cell.y].text[1];
    if(idx != 1)
    {
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 // PUAP -Mat untested	
 //How are these used/made? cannot create in TGB GUI editor
        if(selected || mouseOver)

+ 2 - 2
engine/source/gui/guiCanvas.cc

@@ -1163,7 +1163,7 @@ void GuiCanvas::renderFrame(bool preRenderOnly, bool bufferSwap /* = true */)
 {
    PROFILE_START(CanvasPreRender);
 
-#if !defined TORQUE_OS_IOS && !defined TORQUE_OS_ANDROID
+#if !defined TORQUE_OS_IOS && !defined TORQUE_OS_ANDROID && !defined TORQUE_OS_EMSCRIPTEN
     
    if(mRenderFront)
       glDrawBuffer(GL_FRONT);
@@ -1297,7 +1297,7 @@ void GuiCanvas::renderFrame(bool preRenderOnly, bool bufferSwap /* = true */)
       //temp draw the mouse
       if (cursorON && mShowCursor && !mouseCursor)
       {
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
          glColor4ub(255, 0, 0, 255);
          GLfloat vertices[] = {
               (GLfloat)(cursorPt.x),(GLfloat)(cursorPt.y),

+ 1 - 1
engine/source/gui/guiColorPicker.cc

@@ -100,7 +100,7 @@ void GuiColorPickerCtrl::initPersistFields()
 
 //--------------------------------------------------------------------------
 // Function to draw a box which can have 4 different colors in each corner blended together
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 void dglDrawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4)
 {
    S32 left = bounds.point.x, right = bounds.point.x + bounds.extent.x - 1;

+ 1 - 1
engine/source/gui/guiConsoleTextCtrl.cc

@@ -124,7 +124,7 @@ void GuiConsoleTextCtrl::onRender(Point2I offset, const RectI &updateRect)
    r.extent += r.point;
    glColor4ub(0, 0, 0, 0);
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
    Point2I topleft(r.point.x,  r.point.y);
    Point2I bottomRight(r.extent.x-1, r.extent.y-1);
 	//this was the same drawing as dglDrawRect

+ 1 - 1
engine/source/gui/guiControl.cc

@@ -460,7 +460,7 @@ void GuiControl::onRender(Point2I offset, const RectI &updateRect)
 
 bool GuiControl::renderTooltip(Point2I cursorPos, const char* tipText )
 {
-#if !defined(TORQUE_OS_IOS) && !defined(TORQUE_OS_ANDROID)
+#if !defined(TORQUE_OS_IOS) && !defined(TORQUE_OS_ANDROID) && !defined(TORQUE_OS_EMSCRIPTEN)
     // Short Circuit.
     if (!mAwake) 
         return false;

+ 1 - 1
engine/source/gui/guiPopUpCtrlEx.cc

@@ -1082,7 +1082,7 @@ void GuiPopUpMenuCtrlEx::onRender(Point2I offset, const RectI &updateRect)
       F32 top = (F32)(r.extent.y / 2 + r.point.y - 4);
       F32 bottom = (F32)(top + 8);
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 // PUAP -Mat untested
        glColor4ub(mProfile->mFontColor.red,mProfile->mFontColor.green,mProfile->mFontColor.blue, 255);
 	   GLfloat verts[] = {

+ 2 - 2
engine/source/gui/guiSliderCtrl.cc

@@ -254,7 +254,7 @@ void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect)
             pos += Point2I(1, 0);
             glColor4f(0, 0, 0, 1);
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
             // tick marks
             for (U32 t = 0; t <= (mTicks + 1); t++)
             {
@@ -354,7 +354,7 @@ void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect)
                 mid.set(ext.x, mThumbSize.y / 2);
 
             glColor4f(0, 0, 0, 1);
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
             // tick marks
             for (U32 t = 0; t <= (mTicks + 1); t++)
             {

+ 1 - 1
engine/source/gui/guiTextEditSliderCtrl.cc

@@ -226,7 +226,7 @@ void GuiTextEditSliderCtrl::onRender(Point2I offset, const RectI &updateRect)
                Point2I(start.x+14,midPoint.y),
                mProfile->mFontColor);
 
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
 
    glColor4f(0,0,0,255);
 	

+ 10 - 1
engine/source/memory/dataChunker.cc

@@ -50,7 +50,16 @@ void *DataChunker::alloc(S32 size)
       curBlock = temp;
    }
    void *ret = curBlock->data + curBlock->curIndex;
-   curBlock->curIndex += (size + 3) & ~3; // dword align
+   
+   S32 index = curBlock->curIndex;
+   curBlock->curIndex += ((U32)size + 3) & ~3; // dword align
+   
+#ifdef EMSCRIPTEN
+   if (curBlock->curIndex < index || ((curBlock->data + curBlock->curIndex) - (U8*)ret) < size) {
+      AssertFatal(false, "Something weird is going on here");
+   }
+#endif
+
    return ret;
 }
 

+ 13 - 0
engine/source/platform/platformAL.h

@@ -38,6 +38,19 @@
 #elif defined(TORQUE_OS_IOS)
 #include <OpenAL/al.h>
 #include <OpenAL/alc.h>
+#elif defined(DUMMY_PLATFORM)
+#include "al/altypes.h"
+#include "al/alctypes.h"
+#include "al/eaxtypes.h"
+#define AL_FUNCTION(fn_return,fn_name,fn_args, fn_value) extern fn_return (FN_CDECL *fn_name)fn_args;
+#include "al/al_func.h"
+#include "al/alc_func.h"
+#include "al/eax_func.h"
+#undef AL_FUNCTION
+#elif defined(TORQUE_OS_EMSCRIPTEN)
+#include <AL/al.h>
+#include <AL/alc.h>
+#include "platform/eaxtypes.h"
 #else
 // declare externs of the AL fns here.
 #include "al/altypes.h"

+ 13 - 2
engine/source/platform/platformAudio.h

@@ -142,7 +142,11 @@ void alxGetListenerf(ALenum param, ALfloat *value);
 
 inline void alxListenerPoint3F(ALenum pname, const Point3F *value)
 {
-   alListener3f(pname, value->x, value->y, value->z);   
+   ALfloat ptArray[10];
+   ptArray[0] = value->x;
+   ptArray[1] = value->y;
+   ptArray[2] = value->z;
+   alListenerfv(pname, ptArray);
 }
 
 /**   alGetListener3f access extension for use with Point3F's
@@ -150,7 +154,14 @@ inline void alxListenerPoint3F(ALenum pname, const Point3F *value)
 
 inline void alxGetListenerPoint3F(ALenum pname, Point3F *value)
 {
-   alGetListener3f(pname, &value->x, &value->y, &value->z);
+   ALfloat ptArray[10];
+   ptArray[0] = value->x;
+   ptArray[1] = value->y;
+   ptArray[2] = value->z;
+   alGetListenerfv(pname, ptArray);
+   value->x = ptArray[0];
+   value->y = ptArray[1];
+   value->z = ptArray[2];
 }
 
 // Environment

+ 2 - 0
engine/source/platform/platformGL.h

@@ -32,5 +32,7 @@
 #include "platformiOS/platformGL.h"
 #elif defined(TORQUE_OS_ANDROID)
 #include "platformAndroid/platformGL.h"
+#elif defined(TORQUE_OS_EMSCRIPTEN)
+#include "platformEmscripten/platformGL.h"
 #endif
 #endif

+ 16 - 0
engine/source/platform/types.gcc.h

@@ -66,6 +66,10 @@ typedef unsigned long long  U64;
 		#define TORQUE_OS_ANDROID
 #endif
 #  include "platform/types.arm.h"
+#elif defined(EMSCRIPTEN)
+#  define TORQUE_OS_STRING "Emscripten"
+#  define TORQUE_OS_EMSCRIPTEN
+#  include "platform/types.posix.h"
 #elif defined(linux)
 #  define TORQUE_OS_STRING "Linux"
 #  define TORQUE_OS_LINUX
@@ -104,6 +108,7 @@ typedef unsigned long long  U64;
 #  define TORQUE_SUPPORTS_NASM
 #endif
 #  include "platform/types.ppc.h"
+
 #else 
 #  error "GCC: Unsupported Operating System"
 #endif
@@ -116,6 +121,12 @@ typedef unsigned long long  U64;
 #  define TORQUE_CPU_X86
 #  define TORQUE_LITTLE_ENDIAN
 
+#elif defined(__amd64__)
+#  define TORQUE_CPU_STRING "Intel x86-64"
+#  define TORQUE_CPU_X86_64
+#  define TORQUE_LITTLE_ENDIAN
+#  define TORQUE_64
+
 #elif defined(__ppc__)
 #  define TORQUE_CPU_STRING "PowerPC"
 #  define TORQUE_CPU_PPC
@@ -126,6 +137,11 @@ typedef unsigned long long  U64;
 #  define TORQUE_CPU_ARM
 #  define TORQUE_LITTLE_ENDIAN
 
+#elif defined(EMSCRIPTEN)
+
+#  define TORQUE_OS_STRING "Emscripten"
+#  define TORQUE_LITTLE_ENDIAN
+
 #else
 #  error "GCC: Unsupported Target CPU"
 #endif

+ 53 - 0
engine/source/platformEmscripten/EmscriptenAlerts.cpp

@@ -0,0 +1,53 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) James S Urquhart 2014
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#include "platformEmscripten/platformEmscripten.h"
+
+extern "C"
+{
+	extern int js_AlertOK(const char *title, const char *message);
+	extern int js_AlertOKCancel(const char *title, const char *message);
+	extern int js_AlertRetry(const char *title, const char *message);
+	extern int js_AlertYesNo(const char *title, const char *message);
+}
+
+//-----------------------------------------------------------------------------
+void Platform::AlertOK(const char *windowTitle, const char *message)
+{
+	js_AlertOK(windowTitle, message);
+}
+//-----------------------------------------------------------------------------
+bool Platform::AlertOKCancel(const char *windowTitle, const char *message)
+{
+	return js_AlertOKCancel(windowTitle, message) == 1;
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::AlertRetry(const char *windowTitle, const char *message)
+{//retry/cancel
+	return js_AlertRetry(windowTitle, message) == 1;
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::AlertYesNo(const char *windowTitle, const char *message)
+{
+	return js_AlertYesNo(windowTitle, message) == 1;
+}

+ 41 - 0
engine/source/platformEmscripten/EmscriptenAudio.cpp

@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platform/platformAL.h"
+
+namespace Audio
+{
+	
+	/*!  The MacOS X build links against the OpenAL framework.
+     It can be built to use either an internal framework, or the system framework.
+     Since OpenAL is weak-linked in at compile time, we don't need to init anything.
+     Stub it out...
+	 */
+	bool OpenALDLLInit() {  return true; }
+	
+	/*!   Stubbed out, see the note on OpenALDLLInit().  
+	 */
+	void OpenALDLLShutdown() { }   
+	
+	
+} // namespace Audio

+ 35 - 0
engine/source/platformEmscripten/EmscriptenCPUInfo.cpp

@@ -0,0 +1,35 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "string/stringTable.h"
+
+void Processor::init()
+{
+   PlatformSystemInfo.processor.mhz = 1337;
+
+   //PlatformSystemInfo.processor.type =  ARM_1176;
+   PlatformSystemInfo.processor.name = StringTable->insert("JavaScript");
+
+   PlatformSystemInfo.processor.properties = CPU_PROP_PPCMIN;
+}
+

+ 142 - 0
engine/source/platformEmscripten/EmscriptenConsole.cpp

@@ -0,0 +1,142 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platformEmscripten/EmscriptenCOnsole.h"
+#include "platform/event.h"
+#include "game/gameInterface.h"
+
+#include <stdio.h>
+
+extern "C"
+{
+extern void js_ConsoleEnabled(const char *prompt);
+extern void js_ConsoleDisabled();
+extern void js_ConsoleLine(const char *message);
+}
+
+EmscriptenConsole *gConsole = NULL;
+
+ConsoleFunction(enableWinConsole, void, 2, 2, "(bool enable)")
+{
+   if (gConsole)
+      gConsole->enable(dAtob(argv[1]));
+}
+
+ConsoleFunction(enableDebugOutput, void, 2, 2, "(bool enable)")
+{
+	if (gConsole)
+		gConsole->enableDebugOutput(dAtob(argv[1]));
+}
+
+static void EmscriptenConsoleConsumer(ConsoleLogEntry::Level, const char *line)
+{
+   if (gConsole)
+      gConsole->processConsoleLine(line);
+}
+
+void EmscriptenConsole::create()
+{
+   gConsole = new EmscriptenConsole();
+}
+
+void EmscriptenConsole::destroy()
+{
+   if (gConsole)
+      delete gConsole;
+   gConsole = NULL;
+}
+
+void EmscriptenConsole::enable(bool enabled)
+{
+   if (gConsole == NULL)
+      return;
+   
+   consoleEnabled = enabled;
+   if(consoleEnabled)
+   {
+      printf("Initializing Console...\n");
+      printf("Console Initialized.\n");
+
+      js_ConsoleEnabled(Con::getVariable("Con::Prompt"));
+   }
+   else
+   {
+      printf("Deactivating Console.");
+      js_ConsoleDisabled();
+   }
+}
+
+void EmscriptenConsole::enableDebugOutput(bool enabled)
+{
+	if (gConsole != NULL)
+	  debugOutputEnabled = enabled;
+}
+
+
+bool EmscriptenConsole::isEnabled()
+{
+   return gConsole ? gConsole->consoleEnabled : false;
+}
+
+EmscriptenConsole::EmscriptenConsole()
+{
+   consoleEnabled = false;
+
+   clearInBuf();
+   
+   Con::addConsumer(EmscriptenConsoleConsumer);
+}
+
+EmscriptenConsole::~EmscriptenConsole()
+{
+   Con::removeConsumer(EmscriptenConsoleConsumer);
+}
+
+void EmscriptenConsole::processConsoleLine(const char *consoleLine)
+{
+   if(consoleEnabled)
+   {
+      printf("%s\n", consoleLine);
+   }
+}
+
+void EmscriptenConsole::clearInBuf()
+{
+   dMemset(inBuf, 0, MaxConsoleLineSize);
+   inBufPos=0;
+}
+
+void Torque2D_postConsole(const char *buffer)
+{
+   if (!gConsole)
+      return;
+
+   dStrncpy(gConsole->postEvent.data, buffer, MaxConsoleLineSize-1);
+   gConsole->postEvent.data[MaxConsoleLineSize] = '\0';
+   gConsole->postEvent.size = ConsoleEventHeaderSize + dStrlen(gConsole->postEvent.data) + 1;
+   Con::printf("=> %s",gConsole->postEvent.data);
+   
+   Game->postEvent(gConsole->postEvent);
+}
+

+ 65 - 0
engine/source/platformEmscripten/EmscriptenConsole.h

@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _EMSCRIPTENCONSOLE_H_
+#define _EMSCRIPTENCONSOLE_H_
+
+#ifndef _CONSOLE_H_
+#include "console/console.h"
+#endif
+#ifndef _EVENT_H_
+#include "Platform/event.h"
+#endif
+
+
+class EmscriptenConsole
+{
+private:
+   bool consoleEnabled;
+	bool debugOutputEnabled;
+   
+   U32   inBufPos;
+   char  inBuf[MaxConsoleLineSize];
+   
+   void clearInBuf();
+
+public:
+   ConsoleEvent postEvent;
+   
+public:
+   static void create();
+   static void destroy();
+   static bool isEnabled();
+
+   EmscriptenConsole();
+   ~EmscriptenConsole();
+   void enable(bool);
+	//%PUAP%
+	void enableDebugOutput( bool );
+
+   void processConsoleLine(const char *consoleLine);
+
+};
+
+extern EmscriptenConsole *gConsole;
+
+#endif

+ 39 - 0
engine/source/platformEmscripten/EmscriptenDialogs.cpp

@@ -0,0 +1,39 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platform/nativeDialogs/fileDialog.h"
+
+bool FileDialog::Execute()
+{
+    return true;
+}
+
+bool FileDialog::setDefaultPath(void* obj, const char* data)
+{
+   return true;
+}
+
+bool FileDialog::setDefaultFile(void* obj, const char* data)
+{
+   return true;
+};

+ 65 - 0
engine/source/platformEmscripten/EmscriptenEvents.cpp

@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platform/event.h"
+#include "platform/platformInput.h"
+#include "game/gameInterface.h"
+#include "platform/threads/thread.h"
+#include "platform/platformVideo.h"
+
+#include "gui/guiCanvas.h"
+
+bool gKeyboardTranslation = false;
+
+//-----------------------------------------------------------------------------
+static void _OnActivate(bool activating)
+{
+   if(activating)
+   {
+      Input::activate();
+      Game->refreshWindow();
+      gPlatState.backgrounded = false;
+   }
+   else
+   {
+      Input::deactivate();
+      gPlatState.backgrounded = true;
+   }
+}
+
+//------------------------------------------------------------------------------
+void Platform::enableKeyboardTranslation(void)
+{
+   gKeyboardTranslation = true;
+   // TODO: accept text input from sdl
+}
+
+//------------------------------------------------------------------------------
+void Platform::disableKeyboardTranslation(void)
+{
+   gKeyboardTranslation = false;
+   // TODO: stop accepting text input from sdl
+}
+
+

+ 1216 - 0
engine/source/platformEmscripten/EmscriptenFileio.cpp

@@ -0,0 +1,1216 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+/* JMQ:
+
+  Here's the scoop on unix file IO.  The windows platform makes some 
+  assumptions about fileio: 1) the file system is case-insensitive, and 
+  2) the platform can write to the directory in which
+  the game is running.  Both of these are usually false on linux.  So, to 
+  compensate, we "route" created files and directories to the user's home
+  directory (see GetPrefPath()).  When a file is to be accessed, the code 
+  looks in the home directory first.  If the file is not found there and the
+  open mode is read only, the code will look in the game installation 
+  directory.  Files are never created or modified in the game directory.
+
+  For case-sensitivity, the MungePath code will test whether a given path
+  specified by the engine exists.  If not, it will use the MungeCase function
+  which will try to determine if an actual filesystem path matches the 
+  specified path case insensitive.  If one is found, the actual path 
+  transparently (we hope) replaces the one requested by the engine.
+
+  The preference directory is global to all torque executables with the same
+  name.  You should make sure you keep it clean if you build from multiple
+  torque development trees.
+*/
+
+#include "platformEmscripten/platformEmscripten.h"
+
+#include "platform/platformFileIO.h"
+#include "collection/vector.h"
+#include "string/stringTable.h"
+#include "string/stringUnit.h"
+#include "console/console.h"
+#include "debug/profiler.h"
+#include "io/resource/resourceManager.h"
+#include "game/gameInterface.h" 
+
+#if defined(__FreeBSD__)
+  #include <sys/types.h>
+#endif
+#include <utime.h>
+
+/* include sys/param.h for MAXPATHLEN */
+#include <sys/param.h>
+#ifndef MAX_PATH
+#define MAX_PATH MAXPATHLEN
+#endif
+
+/* these are for reading directors, getting stats, etc. */
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+extern int x86UNIXOpen(const char *path, int oflag);
+extern int x86UNIXClose(int fd);
+extern ssize_t x86UNIXRead(int fd, void *buf, size_t nbytes);
+extern ssize_t x86UNIXWrite(int fd, const void *buf, size_t nbytes);
+
+const int MaxPath = 2048;
+
+// Various handy utility functions:
+//------------------------------------------------------------------------------
+// find all \ in a path and convert them in place to /
+static void ForwardSlash(char *str)
+{
+  while(*str)
+  {
+     if(*str == '\\')
+        *str = '/';
+     str++;
+  }
+}
+
+//------------------------------------------------------------------------------
+// copy a file from src to dest
+static bool CopyFile(const char* src, const char* dest)
+{
+  S32 srcFd = x86UNIXOpen(src, O_RDONLY);
+  S32 destFd = x86UNIXOpen(dest, O_WRONLY | O_CREAT | O_TRUNC);
+  bool error = false;
+
+  if (srcFd != -1 && destFd != -1)
+  {
+     const int BufSize = 8192;
+     char buf[BufSize];
+     S32 bytesRead = 0;
+     while ((bytesRead = x86UNIXRead(srcFd, buf, BufSize)) > 0)
+     {
+        // write data
+        if (x86UNIXWrite(destFd, buf, bytesRead) == -1)
+        {
+           error = true;
+           break;
+        }
+     }
+
+     if (bytesRead == -1)
+        error = true;
+  }
+
+  if (srcFd != -1)
+     x86UNIXClose(srcFd);
+  if (destFd != -1)
+     x86UNIXClose(destFd);
+
+  if (error)
+  {
+     Con::errorf("Error copying file: %s, %s", src, dest);
+     remove(dest);
+  }
+  return error;
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::pathCopy(const char *fromName, const char *toName, bool nooverwrite)
+{
+  return CopyFile(fromName,toName);
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::fileRename(const char *source, const char *dest)
+{
+  int result = rename(source, dest);
+  return result >= 0;
+}
+
+//-----------------------------------------------------------------------------
+static char sgPrefDir[MaxPath];
+static bool sgPrefDirInitialized = false;
+
+// get the "pref dir", which is where game output files are stored.  the pref
+// dir is ~/PREF_DIR_ROOT/PREF_DIR_GAME_NAME
+static const char* GetPrefDir()
+{
+#ifdef DUMMY_PLATFORM
+  getcwd(sgPrefDir, MaxPath);
+  return sgPrefDir;
+#else
+  return "/.data/";/*
+  if (sgPrefDirInitialized)
+     return sgPrefDir;
+
+  if (gPlatState.useRedirect)
+  {
+     const char *home = getenv("HOME");
+     AssertFatal(home, "HOME environment variable must be set");
+
+     dSprintf(sgPrefDir, MaxPath, "%s/%s/%s", 
+        home, PREF_DIR_ROOT, PREF_DIR_GAME_NAME);
+  }
+  else
+  {
+     getcwd(sgPrefDir, MaxPath);
+  }
+
+  sgPrefDirInitialized = true;
+  return sgPrefDir;*/
+#endif
+}
+
+//------------------------------------------------------------------------------
+// munge the case of the specified pathName.  This means try to find the actual
+// filename in with case-insensitive matching on the specified pathName, and
+// store the actual found name.
+static void MungeCase(char* pathName, S32 pathNameSize)
+{
+  char tempBuf[MaxPath];
+  dStrncpy(tempBuf, pathName, pathNameSize);
+
+  AssertFatal(pathName[0] == '/', "PATH must be absolute");
+
+  struct stat filestat;
+  const int MaxPathEl = 200;
+  char *currChar = pathName;
+  char testPath[MaxPath];
+  char pathEl[MaxPathEl];
+  bool done = false;
+
+  dStrncpy(tempBuf, "/", MaxPath);
+  currChar++;
+
+  while (!done)
+  {
+     char* termChar = dStrchr(currChar, '/');
+     if (termChar == NULL)
+        termChar = dStrchr(currChar, '\0');
+     AssertFatal(termChar, "Can't find / or NULL terminator");
+
+     S32 pathElLen = (termChar - currChar);
+     dStrncpy(pathEl, currChar, pathElLen);
+     pathEl[pathElLen] = '\0';
+     dStrncpy(testPath, tempBuf, MaxPath);
+     dStrcat(testPath, pathEl);
+     if (stat(testPath, &filestat) != -1)
+     {
+        dStrncpy(tempBuf, testPath, MaxPath);
+     }
+     else
+     {
+        DIR *dir = opendir(tempBuf);
+        struct dirent* ent;
+        bool foundMatch = false;
+        while (dir != NULL && (ent = readdir(dir)) != NULL)
+        {
+           if (dStricmp(pathEl, ent->d_name) == 0)
+           {
+              foundMatch = true;
+              dStrcat(tempBuf, ent->d_name);
+              break;
+           }
+        }
+
+        if (!foundMatch)
+           dStrncpy(tempBuf, testPath, MaxPath);
+        if (dir)
+           closedir(dir);
+     }
+     if (*termChar == '/')
+     {
+        dStrcat(tempBuf, "/");
+        termChar++;
+        currChar = termChar;
+     }
+     else
+        done = true;
+  }
+
+  dStrncpy(pathName, tempBuf, pathNameSize);  
+}
+
+//-----------------------------------------------------------------------------
+// Returns true if the pathname exists, false otherwise.  If isFile is true,
+// the pathname is assumed to be a file path, and only the directory part
+// will be examined (everything before last /)
+bool DirExists(char* pathname, bool isFile)
+{
+  static char testpath[20000];
+  dStrncpy(testpath, pathname, sizeof(testpath));
+  if (isFile)
+  {
+     // find the last / and make it into null
+     char* lastSlash = dStrrchr(testpath, '/');
+     if (lastSlash != NULL)
+        *lastSlash = 0;
+  }
+  return Platform::isDirectory(testpath);
+}
+
+//-----------------------------------------------------------------------------
+// Munge the specified path.  
+static void MungePath(char* dest, S32 destSize, 
+  const char* src, const char* absolutePrefix)
+{
+  char tempBuf[MaxPath];
+  dStrncpy(dest, src, MaxPath);
+
+  // translate all \ to /
+  ForwardSlash(dest);
+
+  // if it is relative, make it absolute with the absolutePrefix
+  if (dest[0] != '/')
+  {
+     AssertFatal(absolutePrefix, "Absolute Prefix must not be NULL");
+
+     dSprintf(tempBuf, MaxPath, "%s/%s", 
+        absolutePrefix, dest);
+
+     // copy the result back into dest
+     dStrncpy(dest, tempBuf, destSize);
+  }
+
+  // if the path exists, we're done
+  struct stat filestat;
+  if (stat(dest, &filestat) != -1)
+     return;
+
+  // otherwise munge the case of the path
+  MungeCase(dest, destSize);
+}
+
+//-----------------------------------------------------------------------------
+enum
+{
+  TOUCH,
+  DELETE
+};
+
+//-----------------------------------------------------------------------------
+// perform a modification on the specified file.  allowed modifications are 
+// specified in the enum above.
+bool ModifyFile(const char * name, S32 modType)
+{
+  if(!name || (dStrlen(name) >= MAX_PATH) || dStrstr(name, "../") != NULL)
+     return(false);
+
+  // if its absolute skip it
+  if (name[0]=='/' || name[0]=='\\')
+     return(false);
+
+  // only modify files in home directory
+  char prefPathName[MaxPath];
+  MungePath(prefPathName, MaxPath, name, GetPrefDir());
+
+  if (modType == TOUCH)
+     return(utime(prefPathName, 0) != -1);
+  else if (modType == DELETE)
+     return (remove(prefPathName) != -1);
+  else 
+     AssertFatal(false, "Unknown File Mod type");
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+static bool RecurseDumpPath(const char *path, const char* relativePath, const char *pattern, Vector<Platform::FileInfo> &fileVector, int recurseDepth) 
+{
+  char search[1024];
+  dSprintf(search, sizeof(search), "%s", path, pattern);
+  
+  DIR *directory = opendir(search);
+
+  if (directory == NULL)
+     return false;
+
+  struct dirent *fEntry;
+  fEntry = readdir(directory);		// read the first "file" in the directory
+
+  if (fEntry == NULL)
+     return false;
+
+  do
+  {
+     char filename[BUFSIZ+1];
+     struct stat fStat;
+
+     dSprintf(filename, sizeof(filename), "%s/%s", search, fEntry->d_name); // "construct" the file name
+     stat(filename, &fStat); // get the file stats
+
+     if ( (fStat.st_mode & S_IFMT) == S_IFDIR )
+     {
+        // Directory
+        // skip . and .. directories
+        if (dStrcmp(fEntry->d_name, ".") == 0 || dStrcmp(fEntry->d_name, "..") == 0)
+           continue;
+          
+      // skip excluded directories
+      if( Platform::isExcludedDirectory(fEntry->d_name))
+          continue;
+
+
+        char child[MaxPath];
+        dSprintf(child, sizeof(child), "%s/%s", path, fEntry->d_name);
+        char* childRelative = NULL;
+        char childRelativeBuf[MaxPath];
+        if (relativePath)
+        {
+           dSprintf(childRelativeBuf, sizeof(childRelativeBuf), "%s/%s", 
+              relativePath, fEntry->d_name);
+           childRelative = childRelativeBuf;
+        }
+
+        if (recurseDepth > 0)
+      RecurseDumpPath(child, childRelative, pattern, fileVector, recurseDepth - 1);
+    else if (recurseDepth == -1)
+      RecurseDumpPath(child, childRelative, pattern, fileVector, -1);
+     }      
+     else
+     {
+        // File
+        
+        // add it to the list
+        fileVector.increment();
+        Platform::FileInfo& rInfo = fileVector.last();
+
+        if (relativePath)
+           rInfo.pFullPath = StringTable->insert(relativePath);
+        else
+           rInfo.pFullPath = StringTable->insert(path);
+        rInfo.pFileName = StringTable->insert(fEntry->d_name);
+        rInfo.fileSize  = fStat.st_size;
+        //dPrintf("Adding file: %s/%s\n", rInfo.pFullPath, rInfo.pFileName);
+     }
+
+  } while( (fEntry = readdir(directory)) != NULL );
+
+  closedir(directory);
+  return true;
+}   
+
+//-----------------------------------------------------------------------------
+bool Platform::fileDelete(const char * name)
+{
+  return ModifyFile(name, DELETE);
+}
+
+//-----------------------------------------------------------------------------
+bool dFileTouch(const char * name)
+{
+  return ModifyFile(name, TOUCH);
+}
+
+//-----------------------------------------------------------------------------
+// Constructors & Destructor
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// After construction, the currentStatus will be Closed and the capabilities
+// will be 0.
+//-----------------------------------------------------------------------------
+File::File() 
+: currentStatus(Closed), capability(0)
+{
+//    AssertFatal(sizeof(int) == sizeof(void *), "File::File: cannot cast void* to int");
+
+   handle = (void *)NULL;
+}
+
+//-----------------------------------------------------------------------------
+// insert a copy constructor here... (currently disabled)
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+File::~File()
+{
+   close();
+   handle = (void *)NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Open a file in the mode specified by openMode (Read, Write, or ReadWrite).
+// Truncate the file if the mode is either Write or ReadWrite and truncate is
+// true.
+//
+// Sets capability appropriate to the openMode.
+// Returns the currentStatus of the file.
+//-----------------------------------------------------------------------------
+File::Status File::open(const char *filename, const AccessMode openMode)
+{
+  AssertFatal(NULL != filename, "File::open: NULL filename");
+  AssertWarn(NULL == handle, "File::open: handle already valid");
+  
+  // Close the file if it was already open...
+  if (Closed != currentStatus)
+     close();
+
+  char prefPathName[MaxPath];
+  char gamePathName[MaxPath];
+  char cwd[MaxPath];
+  getcwd(cwd, MaxPath);
+  MungePath(prefPathName, MaxPath, filename, GetPrefDir());
+  MungePath(gamePathName, MaxPath, filename, cwd);
+
+  int oflag;
+  struct stat filestat;
+  handle = (void *)dRealMalloc(sizeof(int));
+
+  switch (openMode)
+  {
+     case Read:
+        oflag = O_RDONLY;
+        break;
+     case Write:
+        oflag = O_WRONLY | O_CREAT | O_TRUNC;
+        break;
+     case ReadWrite:
+        oflag = O_RDWR | O_CREAT;
+        // if the file does not exist copy it before reading/writing
+        if (stat(prefPathName, &filestat) == -1)
+           bool ret = CopyFile(gamePathName, prefPathName);
+        break;
+     case WriteAppend:
+        oflag = O_WRONLY | O_CREAT | O_APPEND;
+        // if the file does not exist copy it before appending
+        if (stat(prefPathName, &filestat) == -1)
+            bool ret = CopyFile(gamePathName, prefPathName);
+        break;
+     default:
+        AssertFatal(false, "File::open: bad access mode");    // impossible
+  }
+
+  // if we are writing, make sure output path exists
+  if (openMode == Write || openMode == ReadWrite || openMode == WriteAppend)
+      Platform::createPath(prefPathName);
+
+  int fd = -1;
+  fd = x86UNIXOpen(prefPathName, oflag);
+  if (fd == -1 && openMode == Read)
+     // for read only files we can use the gamePathName
+     fd = x86UNIXOpen(gamePathName, oflag);
+
+  dMemcpy(handle, &fd, sizeof(int));
+   
+#ifdef DEBUG
+//   fprintf(stdout,"fd = %d, handle = %d\n", fd, *((int *)handle));
+#endif
+
+  if (*((int *)handle) == -1)                
+  {
+     // handle not created successfully
+     Con::errorf("Can't open file: %s", filename);
+     return setStatus();
+  }
+  else
+  {
+     // successfully created file, so set the file capabilities...
+     switch (openMode)
+     {
+        case Read:
+           capability = U32(FileRead);
+           break;
+        case Write:
+        case WriteAppend:
+           capability = U32(FileWrite);
+           break;
+        case ReadWrite:
+           capability = U32(FileRead)  |
+              U32(FileWrite);
+           break;
+        default:
+           AssertFatal(false, "File::open: bad access mode");
+     }
+     return currentStatus = Ok;                                // success!
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Get the current position of the file pointer.
+//-----------------------------------------------------------------------------
+U32 File::getPosition() const
+{
+   AssertFatal(Closed != currentStatus, "File::getPosition: file closed");
+   AssertFatal(NULL != handle, "File::getPosition: invalid file handle");
+
+#ifdef DEBUG
+//   fprintf(stdout, "handle = %d\n",*((int *)handle));fflush(stdout);
+#endif
+   return (U32) lseek(*((int *)handle), 0, SEEK_CUR);
+}
+
+//-----------------------------------------------------------------------------
+// Set the position of the file pointer.
+// Absolute and relative positioning is supported via the absolutePos
+// parameter.
+//
+// If positioning absolutely, position MUST be positive - an IOError results if
+// position is negative.
+// Position can be negative if positioning relatively, however positioning
+// before the start of the file is an IOError.
+//
+// Returns the currentStatus of the file.
+//-----------------------------------------------------------------------------
+File::Status File::setPosition(S32 position, bool absolutePos)
+{
+   AssertFatal(Closed != currentStatus, "File::setPosition: file closed");
+   AssertFatal(NULL != handle, "File::setPosition: invalid file handle");
+   
+   if (Ok != currentStatus && EOS != currentStatus)
+       return currentStatus;
+   
+   U32 finalPos = 0;
+   switch (absolutePos)
+   {
+   case true:                                                    // absolute position
+       AssertFatal(0 <= position, "File::setPosition: negative absolute position");
+       
+       // position beyond EOS is OK
+       finalPos = lseek(*((int *)handle), position, SEEK_SET);
+       break;
+   case false:                                                    // relative position
+       AssertFatal((getPosition() >= (U32)abs(position) && 0 > position) || 0 <= position, "File::setPosition: negative relative position");
+       
+       // position beyond EOS is OK
+       finalPos = lseek(*((int *)handle), position, SEEK_CUR);
+  break;
+   }
+
+   if (0xffffffff == finalPos)
+       return setStatus();                                        // unsuccessful
+   else if (finalPos >= getSize())
+       return currentStatus = EOS;                                // success, at end of file
+   else
+       return currentStatus = Ok;                                // success!
+}
+
+//-----------------------------------------------------------------------------
+// Get the size of the file in bytes.
+// It is an error to query the file size for a Closed file, or for one with an
+// error status.
+//-----------------------------------------------------------------------------
+U32 File::getSize() const
+{
+   AssertWarn(Closed != currentStatus, "File::getSize: file closed");
+   AssertFatal(NULL != handle, "File::getSize: invalid file handle");
+   
+   if (Ok == currentStatus || EOS == currentStatus)
+   {
+  long	currentOffset = getPosition();                  // keep track of our current position
+  long	fileSize;
+  lseek(*((int *)handle), 0, SEEK_END);                     // seek to the end of the file
+  fileSize = getPosition();                               // get the file size
+  lseek(*((int *)handle), currentOffset, SEEK_SET);         // seek back to our old offset
+       return fileSize;                                        // success!
+   }
+   else
+       return 0;                                               // unsuccessful
+}
+
+//-----------------------------------------------------------------------------
+// Flush the file.
+// It is an error to flush a read-only file.
+// Returns the currentStatus of the file.
+//-----------------------------------------------------------------------------
+File::Status File::flush()
+{
+   AssertFatal(Closed != currentStatus, "File::flush: file closed");
+   AssertFatal(NULL != handle, "File::flush: invalid file handle");
+   AssertFatal(true == hasCapability(FileWrite), "File::flush: cannot flush a read-only file");
+
+   if (fsync(*((int *)handle)) == 0)
+       return currentStatus = Ok;                                // success!
+   else
+       return setStatus();                                       // unsuccessful
+}
+
+//-----------------------------------------------------------------------------
+// Close the File.
+//
+// Returns the currentStatus
+//-----------------------------------------------------------------------------
+File::Status File::close()
+{
+  // if the handle is non-NULL, close it if necessary and free it
+  if (NULL != handle)
+  {
+     // make a local copy of the handle value and
+     // free the handle
+     int handleVal = *((int *)handle);
+     dRealFree(handle);
+     handle = (void *)NULL;
+     
+     // close the handle if it is valid
+     if (handleVal != -1 && x86UNIXClose(handleVal) != 0)
+        return setStatus();                                    // unsuccessful
+  }
+  // Set the status to closed
+  return currentStatus = Closed;
+}
+
+//-----------------------------------------------------------------------------
+// Self-explanatory.
+//-----------------------------------------------------------------------------
+File::Status File::getStatus() const
+{
+   return currentStatus;
+}
+
+//-----------------------------------------------------------------------------
+// Sets and returns the currentStatus when an error has been encountered.
+//-----------------------------------------------------------------------------
+File::Status File::setStatus()
+{
+  Con::printf("File IO error: %s", strerror(errno));
+  return currentStatus = IOError;
+}
+
+//-----------------------------------------------------------------------------
+// Sets and returns the currentStatus to status.
+//-----------------------------------------------------------------------------
+File::Status File::setStatus(File::Status status)
+{
+   return currentStatus = status;
+}
+
+//-----------------------------------------------------------------------------
+// Read from a file.
+// The number of bytes to read is passed in size, the data is returned in src.
+// The number of bytes read is available in bytesRead if a non-Null pointer is
+// provided.
+//-----------------------------------------------------------------------------
+File::Status File::read(U32 size, char *dst, U32 *bytesRead)
+{
+#ifdef DEBUG
+//   fprintf(stdout,"reading %d bytes\n",size);fflush(stdout);
+#endif
+   AssertFatal(Closed != currentStatus, "File::read: file closed");
+   AssertFatal(NULL != handle, "File::read: invalid file handle");
+   AssertFatal(NULL != dst, "File::read: NULL destination pointer");
+   AssertFatal(true == hasCapability(FileRead), "File::read: file lacks capability");
+   AssertWarn(0 != size, "File::read: size of zero");
+
+/* show stats for this file */
+#ifdef DEBUG
+//struct stat st;
+//fstat(*((int *)handle), &st);
+//fprintf(stdout,"file size = %d\n", st.st_size);
+#endif
+/****************************/
+   
+   if (Ok != currentStatus || 0 == size)
+       return currentStatus;
+   else
+   {
+       long lastBytes;
+       long *bytes = (NULL == bytesRead) ? &lastBytes : (long *)bytesRead;
+       if ( (*((U32 *)bytes) = x86UNIXRead(*((int *)handle), dst, size)) == -1)
+       {
+#ifdef DEBUG
+//   fprintf(stdout,"unsuccessful: %d\n", *((U32 *)bytes));fflush(stdout);
+#endif
+          return setStatus();                                    // unsuccessful
+       } else {
+//            dst[*((U32 *)bytes)] = '\0';
+           if (*((U32 *)bytes) != size || *((U32 *)bytes) == 0) {
+#ifdef DEBUG
+//  fprintf(stdout,"end of stream: %d\n", *((U32 *)bytes));fflush(stdout);
+#endif
+               return currentStatus = EOS;                        // end of stream
+           }
+       }
+   }
+//    dst[*bytesRead] = '\0';
+#ifdef DEBUG
+//fprintf(stdout, "We read:\n");
+//fprintf(stdout, "====================================================\n");
+//fprintf(stdout, "%s\n",dst);
+//fprintf(stdout, "====================================================\n");
+//fprintf(stdout,"read ok: %d\n", *bytesRead);fflush(stdout);
+#endif
+   return currentStatus = Ok;                                    // successfully read size bytes
+}
+
+//-----------------------------------------------------------------------------
+// Write to a file.
+// The number of bytes to write is passed in size, the data is passed in src.
+// The number of bytes written is available in bytesWritten if a non-Null
+// pointer is provided.
+//-----------------------------------------------------------------------------
+File::Status File::write(U32 size, const char *src, U32 *bytesWritten)
+{
+  // JMQ: despite the U32 parameters, the maximum filesize supported by this
+  // function is probably the max value of S32, due to the unix syscall
+  // api.
+  AssertFatal(Closed != currentStatus, "File::write: file closed");
+  AssertFatal(NULL != handle, "File::write: invalid file handle");
+  AssertFatal(NULL != src, "File::write: NULL source pointer");
+  AssertFatal(true == hasCapability(FileWrite), "File::write: file lacks capability");
+  AssertWarn(0 != size, "File::write: size of zero");
+   
+  if ((Ok != currentStatus && EOS != currentStatus) || 0 == size)
+     return currentStatus;
+  else
+  {
+     S32 numWritten = x86UNIXWrite(*((int *)handle), src, size);
+     if (numWritten < 0)
+        return setStatus();
+
+     if (bytesWritten)
+        *bytesWritten = static_cast<U32>(numWritten);
+     return currentStatus = Ok;
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Self-explanatory.  JMQ: No explanation needed.  Move along.  These aren't 
+// the droids you're looking for.
+//-----------------------------------------------------------------------------
+bool File::hasCapability(Capability cap) const
+{
+   return (0 != (U32(cap) & capability));
+}
+
+//-----------------------------------------------------------------------------
+S32 Platform::compareFileTimes(const FileTime &a, const FileTime &b)
+{
+  if(a > b)
+     return 1;
+  if(a < b)
+     return -1;
+  return 0;
+}
+
+//-----------------------------------------------------------------------------
+static bool GetFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime)
+{
+  struct stat fStat;
+
+  if (stat(filePath, &fStat) == -1)
+     return false;
+
+  if(createTime)
+  {
+     // no where does SysV/BSD UNIX keep a record of a file's
+     // creation time.  instead of creation time I'll just use
+     // changed time for now.
+     *createTime = fStat.st_ctime;
+  }
+  if(modifyTime)
+  {
+     *modifyTime = fStat.st_mtime;
+  }
+
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::getFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime)
+{
+  char pathName[MaxPath];
+
+  // if it starts with cwd, we need to strip that off so that we can look for
+  // the file in the pref dir
+  char cwd[MaxPath];
+  getcwd(cwd, MaxPath);
+  if (dStrstr(filePath, cwd) == filePath)
+     filePath = filePath + dStrlen(cwd) + 1;
+  
+  // if its relative, first look in the pref dir
+  if (filePath[0] != '/' && filePath[0] != '\\')
+  {
+     MungePath(pathName, MaxPath, filePath, GetPrefDir());
+     if (GetFileTimes(pathName, createTime, modifyTime))
+        return true;
+  }
+
+  // here if the path is absolute or not in the pref dir
+  MungePath(pathName, MaxPath, filePath, cwd);
+  return GetFileTimes(pathName, createTime, modifyTime);
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::createPath(const char *file)
+{
+  char pathbuf[MaxPath];
+  const char *dir;
+  pathbuf[0] = 0;
+  U32 pathLen = 0;
+
+  // all paths should be created in home directory
+  char prefPathName[MaxPath];
+  MungePath(prefPathName, MaxPath, file, GetPrefDir());
+  file = prefPathName;
+
+  // does the directory exist already?
+  if (DirExists(prefPathName, true)) // true means that the path is a filepath
+     return true;
+  
+  while((dir = dStrchr(file, '/')) != NULL)
+  {
+     dStrncpy(pathbuf + pathLen, file, dir - file);
+     pathbuf[pathLen + dir-file] = 0;
+     bool ret = mkdir(pathbuf, 0700);
+     pathLen += dir - file;
+     pathbuf[pathLen++] = '/';
+     file = dir + 1;
+  }
+  return true;
+}
+
+// JMQ: Platform:cdFileExists in unimplemented
+//------------------------------------------------------------------------------
+// bool Platform::cdFileExists(const char *filePath, const char *volumeName, 
+//    S32 serialNum)
+// {
+// }
+
+//-----------------------------------------------------------------------------
+bool Platform::dumpPath(const char *path, Vector<Platform::FileInfo> &fileVector, int depth)
+{
+  const char* pattern = "*";
+
+  // if it is not absolute, dump the pref dir first
+  if (path[0] != '/' && path[0] != '\\')
+  {
+     char prefPathName[MaxPath];
+     MungePath(prefPathName, MaxPath, path, GetPrefDir());
+     RecurseDumpPath(prefPathName, path, pattern, fileVector, depth);
+  }
+
+  // munge the requested path and dump it
+  char mungedPath[MaxPath];
+  char cwd[MaxPath];
+  getcwd(cwd, MaxPath);
+  MungePath(mungedPath, MaxPath, path, cwd);
+  return RecurseDumpPath(mungedPath, path, pattern, fileVector, depth);
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::isFile(const char *pFilePath)
+{
+  if (!pFilePath || !*pFilePath)
+     return false;
+  // Get file info
+  struct stat fStat;
+  if (stat(pFilePath, &fStat) < 0)
+     return false;
+
+  // if the file is a "regular file" then true
+  if ( (fStat.st_mode & S_IFMT) == S_IFREG)
+     return true;
+  // must be some other file (directory, device, etc.)
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+S32 Platform::getFileSize(const char *pFilePath)
+{
+ if (!pFilePath || !*pFilePath)
+   return -1;
+ // Get the file info
+ struct stat fStat;
+ if (stat(pFilePath, &fStat) < 0)
+   return -1;
+ // if the file is a "regular file" then return the size
+ if ( (fStat.st_mode & S_IFMT) == S_IFREG)
+   return fStat.st_size;
+ // Must be something else or we can't read the file.
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::isDirectory(const char *pDirPath)
+{
+  if (!pDirPath || !*pDirPath)
+     return false;
+
+  // Get file info
+  struct stat fStat;
+  if (stat(pDirPath, &fStat) < 0)
+     return false;
+     
+  // if the file is a Directory then true
+  if ( (fStat.st_mode & S_IFMT) == S_IFDIR)
+     return true;
+
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::isSubDirectory(const char *pParent, const char *pDir)
+{
+  if (!pParent || !*pDir)
+     return false;
+  
+  // this is somewhat of a brute force method but we need to be 100% sure
+  // that the user cannot enter things like ../dir or /dir etc,...
+  DIR *directory;
+
+  directory = opendir(pParent);
+  if (directory == NULL)
+     return false;
+
+  struct dirent *fEntry;
+  fEntry = readdir(directory);
+  if ( fEntry == NULL )
+     return false;
+
+  do
+  {
+     char dirBuf[MAXPATHLEN];
+     struct stat fStat;
+
+     dSprintf(dirBuf, sizeof(dirBuf), "%s/%s", pParent, fEntry->d_name);
+     if (stat(dirBuf, &fStat) < 0)
+        continue;
+     // if it is a directory...
+     if ( (fStat.st_mode & S_IFMT) == S_IFDIR)
+     {
+        // and the names match
+        if (dStrcmp(pDir, fEntry->d_name ) == 0)
+        {
+           // then we have a real sub directory
+           closedir(directory);
+           return true;
+        }
+     }
+  } while( (fEntry = readdir(directory)) != NULL );
+  
+  closedir(directory);
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool Platform::hasSubDirectory(const char *pPath)
+{
+ if (!pPath)
+   return false;
+ ResourceManager->initExcludedDirectories();
+ 
+ struct dirent *d;
+ DIR           *dip;
+ dip = opendir(pPath);
+ if (dip == NULL)
+   return false;
+
+ while (d = readdir(dip))
+   {
+  bool isDir = false;
+  if (d->d_type == DT_UNKNOWN) 
+  {
+      char child [1024];
+      if ((pPath[dStrlen(pPath) - 1] == '/'))
+          dSprintf(child, 1024, "%s%s", pPath, d->d_name);
+      else
+          dSprintf(child, 1024, "%s/%s", pPath, d->d_name);
+      isDir = Platform::isDirectory (child);
+  }
+  else if (d->d_type & DT_DIR)
+      isDir = true;
+      if( isDir )
+      {
+      // Skip the . and .. directories
+      if (dStrcmp(d->d_name, ".") == 0 ||dStrcmp(d->d_name, "..") == 0)
+          continue;
+      if (Platform::isExcludedDirectory(d->d_name))
+          continue;
+        Platform::clearExcludedDirectories();
+        closedir(dip);
+        return true;
+  }
+   }
+ closedir(dip);
+ Platform::clearExcludedDirectories();
+ return false;
+}
+
+static bool recurseDumpDirectories(const char *basePath, const char *subPath, Vector<StringTableEntry> &directoryVector, S32 currentDepth, S32 recurseDepth, bool noBasePath)
+{
+ char Path[1024];
+ DIR *dip;
+ struct dirent *d;
+
+ if (subPath && (dStrncmp(subPath, "", 1) != 0))
+   {
+     if ((basePath[dStrlen(basePath) - 1]) == '/')
+  dSprintf(Path, 1024, "%s%s", basePath, subPath);
+     else
+  dSprintf(Path, 1024, "%s/%s", basePath, subPath);
+   }
+ else
+   dSprintf(Path, 1024, "%s", basePath);
+ dip = opendir(Path);
+ if (dip == NULL)
+   return false;
+ //////////////////////////////////////////////////////////////////////////
+ // add path to our return list ( provided it is valid )
+ //////////////////////////////////////////////////////////////////////////
+ if (!Platform::isExcludedDirectory(subPath))
+   {
+     if (noBasePath)
+  {
+    // We have a path and it's not an empty string or an excluded directory
+    if ( (subPath && (dStrncmp (subPath, "", 1) != 0)) )
+      directoryVector.push_back(StringTable->insert(subPath));
+  }
+     else
+  {
+    if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) )
+      {
+        char szPath[1024];
+        dMemset(szPath, 0, 1024);
+        if ( (basePath[dStrlen(basePath) - 1]) != '/')
+      dSprintf(szPath, 1024, "%s%s", basePath, subPath);
+        else
+      dSprintf(szPath, 1024, "%s%s", basePath, &subPath[1]);
+        directoryVector.push_back(StringTable->insert(szPath));
+      }
+    else
+      directoryVector.push_back(StringTable->insert(basePath));
+  }
+   }
+ //////////////////////////////////////////////////////////////////////////
+ // Iterate through and grab valid directories
+ //////////////////////////////////////////////////////////////////////////
+
+  while (d = readdir(dip))
+  {
+      bool	isDir;
+      isDir = false;
+      if (d->d_type == DT_UNKNOWN) 
+      {
+          char child [1024];
+          if ((Path[dStrlen(Path) - 1] == '/'))
+              dSprintf(child, 1024, "%s%s", Path, d->d_name);
+          else
+              dSprintf(child, 1024, "%s/%s", Path, d->d_name);
+          isDir = Platform::isDirectory (child);
+      }
+      else if (d->d_type & DT_DIR)
+      isDir = true;
+          
+     if ( isDir )
+  {
+    if (dStrcmp(d->d_name, ".") == 0 ||
+        dStrcmp(d->d_name, "..") == 0)
+      continue;
+    if (Platform::isExcludedDirectory(d->d_name))
+      continue;
+    if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) )
+      {
+        char child[1024];
+        if ((subPath[dStrlen(subPath) - 1] == '/'))
+      dSprintf(child, 1024, "%s%s", subPath, d->d_name);
+        else
+      dSprintf(child, 1024, "%s/%s", subPath, d->d_name);
+        if (currentDepth < recurseDepth || recurseDepth == -1 )
+      recurseDumpDirectories(basePath, child, directoryVector,
+                     currentDepth + 1, recurseDepth,
+                     noBasePath);
+      }
+    else
+      {
+        char child[1024];
+        if ( (basePath[dStrlen(basePath) - 1]) == '/')
+      dStrcpy (child, d->d_name);
+        else
+      dSprintf(child, 1024, "/%s", d->d_name);
+        if (currentDepth < recurseDepth || recurseDepth == -1)
+      recurseDumpDirectories(basePath, child, directoryVector, 
+                     currentDepth + 1, recurseDepth, 
+                     noBasePath);
+      }
+  }
+   }
+ closedir(dip);
+ return true;
+}
+
+bool Platform::dumpDirectories(const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath)
+{
+ ResourceManager->initExcludedDirectories();
+ bool retVal = recurseDumpDirectories(path, "", directoryVector, 0, depth, noBasePath);
+ clearExcludedDirectories();
+ return retVal;
+}
+
+StringTableEntry Platform::getExecutablePath()
+{
+    return StringTable->insert("/");
+}
+
+
+StringTableEntry Platform::getExecutableName()
+{
+    return StringTable->insert("Torque2D-Emscripten");
+}
+
+//-----------------------------------------------------------------------------
+StringTableEntry Platform::getCurrentDirectory()
+{
+#ifdef DUMMY_PLATFORM
+    getcwd(sgPrefDir, MaxPath);
+    return sgPrefDir;
+#else
+    return StringTable->insert("/");
+#endif
+}
+
+//-----------------------------------------------------------------------------
+bool Platform::setCurrentDirectory(StringTableEntry newDir)
+{
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+void Platform::openFolder(const char* path )
+{
+   // TODO
+}
+
+//-----------------------------------------------------------------------------
+
+int x86UNIXOpen(const char *path, int oflag)
+{
+   return open(path, oflag, 0666);
+}
+
+int x86UNIXClose(int fd)
+{
+   return close(fd);
+}
+
+ssize_t x86UNIXRead(int fd, void *buf, size_t nbytes)
+{
+   return read(fd, buf, nbytes);
+}
+
+ssize_t x86UNIXWrite(int fd, const void *buf, size_t nbytes)
+{
+   return write(fd, buf, nbytes);
+}

+ 99 - 0
engine/source/platformEmscripten/EmscriptenFont.cpp

@@ -0,0 +1,99 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/platform.h"
+#include "platformEmscripten/platformEmscripten.h"
+#include "platformEmscripten/EmscriptenFont.h"
+#include "string/Unicode.h"
+
+//------------------------------------------------------------------------------
+// New Unicode capable font class.
+PlatformFont *createPlatformFont(const char *name, U32 size, U32 charset /* = TGE_ANSI_CHARSET */)
+{
+    return NULL;
+}
+
+//------------------------------------------------------------------------------
+
+void PlatformFont::enumeratePlatformFonts( Vector<StringTableEntry>& fonts )
+{
+}
+
+//------------------------------------------------------------------------------
+
+EmscriptenFont::EmscriptenFont()
+{
+}
+
+//------------------------------------------------------------------------------
+
+EmscriptenFont::~EmscriptenFont()
+{
+}
+
+//------------------------------------------------------------------------------
+
+bool EmscriptenFont::create( const char* name, U32 size, U32 charset )
+{
+    return false;
+}
+
+//------------------------------------------------------------------------------
+
+bool EmscriptenFont::isValidChar( const UTF8* str ) const
+{
+    // since only low order characters are invalid, and since those characters
+    // are single codeunits in UTF8, we can safely cast here.
+    return isValidChar((UTF16)*str);
+}
+
+//------------------------------------------------------------------------------
+
+bool EmscriptenFont::isValidChar( const UTF16 character) const
+{
+    // We cut out the ASCII control chars here. Only printable characters are valid.
+    // 0x20 == 32 == space
+    if( character < 0x20 )
+        return false;
+    
+    return true;
+}
+
+//------------------------------------------------------------------------------
+
+PlatformFont::CharInfo& EmscriptenFont::getCharInfo(const UTF8 *str) const
+{
+    return getCharInfo( oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)) );
+}
+
+//------------------------------------------------------------------------------
+
+PlatformFont::CharInfo& EmscriptenFont::getCharInfo(const UTF16 character) const
+{
+    // Declare and clear out the CharInfo that will be returned.
+    static PlatformFont::CharInfo characterInfo;
+    dMemset(&characterInfo, 0, sizeof(characterInfo));
+
+    // Return character information.
+    return characterInfo;
+}

+ 60 - 0
engine/source/platformEmscripten/EmscriptenFont.h

@@ -0,0 +1,60 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _EMSCRIPTENFONT_H_
+#define _EMSCRIPTENFONT_H_
+
+#include "platform/platformFont.h"
+
+class EmscriptenFont : public PlatformFont
+{
+private:
+    // Distance from drawing point to typographic baseline.
+    // Think of the drawing point as the upper left corner of a text box.
+    // NOTE: 'baseline' is synonymous with 'ascent' in Torque.
+    U32             mBaseline;
+    
+    // Distance between lines.
+    U32             mHeight;
+
+public:
+    EmscriptenFont();
+    virtual ~EmscriptenFont();
+    
+    /// Look up the requested font, cache style, layout, colorspace, and some metrics.
+    virtual bool create( const char* name, U32 size, U32 charset = TGE_ANSI_CHARSET);
+    
+    /// Determine if the character requested is a drawable character, or if it should be ignored.
+    virtual bool isValidChar( const UTF16 character) const;
+    virtual bool isValidChar( const UTF8* str) const;
+    
+    /// Get some vertical data on the font at large. Useful for drawing multiline text, and sizing text boxes.
+    virtual U32 getFontHeight() const { return mHeight; }
+    virtual U32 getFontBaseLine() const { return mBaseline; }
+    
+    // Draw the character to a temporary bitmap, and fill the CharInfo with various text metrics.
+    virtual PlatformFont::CharInfo &getCharInfo(const UTF16 character) const;
+    virtual PlatformFont::CharInfo &getCharInfo(const UTF8 *str) const;
+};
+
+#endif

+ 371 - 0
engine/source/platformEmscripten/EmscriptenGL.cpp

@@ -0,0 +1,371 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+// Many OSX frameworks include OpenTransport, and OT's new operator conflicts 
+// with our redefinition of 'new', so we have to pre-include platformAndroid.h,
+// which contains the workaround.
+#include "platformEmscripten/platformEmscripten.h"
+#include "platformEmscripten/platformGL.h"
+
+#include "console/console.h"
+#include "graphics/dgl.h"
+
+#define TEST_FOR_OPENGL_ERRORS 0;
+
+GLState gGLState;
+
+bool gOpenGLDisablePT          = false;
+bool gOpenGLDisableCVA         = false;
+bool gOpenGLDisableTEC         = false;
+bool gOpenGLDisableARBMT       = false;
+bool gOpenGLDisableFC          = true; //false;
+bool gOpenGLDisableTCompress   = false;
+bool gOpenGLNoEnvColor         = false;
+float gOpenGLGammaCorrection   = 0.5;
+bool gOpenGLNoDrawArraysAlpha  = false;
+
+// Find out which extensions are available for this renderer. 
+void getGLCapabilities( )
+{
+   AssertFatal(platState.engine, "getGLCapabilities() was called before a monitor was chosen!");
+
+   // silently create an opengl context on the current display,
+   // so that we can get valid renderer and capability info.
+   // we save off the current context so that we can silently restore it.
+   // the user should not be aware of this little shuffle.
+   //CGLContextObj curr_ctx = CGLGetCurrentContext ();
+   //CGLContextObj temp_ctx =  getContextForCapsCheck();
+   /*
+   if(!temp_ctx)
+   {
+      Con::errorf("OpenGL may not be set up correctly!");
+      return;
+   }
+   */
+   //CGLSetCurrentContext(temp_ctx);
+
+   // Get the OpenGL info strings we'll need
+   const char* pVendString    = (const char*) glGetString( GL_VENDOR );
+   const char* pRendString    = (const char*) glGetString( GL_RENDERER );
+   const char* pVersString    = (const char*) glGetString( GL_VERSION );
+   const char* pExtString     = (const char*) glGetString( GL_EXTENSIONS );
+
+   // Output some driver info to the console:
+   Con::printf( "OpenGL driver information:" );
+   if ( pVendString )
+      Con::printf( "  Vendor: %s", pVendString );
+   if ( pRendString )
+      Con::printf( "  Renderer: %s", pRendString );
+   if ( pVersString )
+      Con::printf( "  Version: %s", pVersString );
+
+   // pre-clear the structure
+   dMemset(&gGLState, 0, sizeof(gGLState));
+
+   if(pExtString)
+   {
+      // EXT_paletted_texture ========================================
+      if (dStrstr(pExtString, (const char*)"GL_EXT_paletted_texture") != NULL)
+         gGLState.suppPalettedTexture = true;
+      
+      // EXT_compiled_vertex_array ========================================
+      gGLState.suppLockedArrays = false;
+      if (dStrstr(pExtString, (const char*)"GL_EXT_compiled_vertex_array") != NULL)
+         gGLState.suppLockedArrays = true;
+
+      // ARB_multitexture ========================================
+      if (dStrstr(pExtString, (const char*)"GL_ARB_multitexture") != NULL)
+		  gGLState.suppARBMultitexture = true;
+      
+      // EXT_blend_color
+      if(dStrstr(pExtString, (const char*)"GL_EXT_blend_color") != NULL)
+         gGLState.suppEXTblendcolor = true;
+
+      // EXT_blend_minmax
+      if(dStrstr(pExtString, (const char*)"GL_EXT_blend_minmax") != NULL)
+         gGLState.suppEXTblendminmax = true;
+
+      // NV_vertex_array_range ========================================
+      // does not appear to be supported by apple, at all. ( as of 10.4.3 )
+      // GL_APPLE_vertex_array_range is similar, and may be nearly identical.
+      if (dStrstr(pExtString, (const char*)"GL_NV_vertex_array_range") != NULL)
+         gGLState.suppVertexArrayRange = true;
+      
+
+      // EXT_fog_coord ========================================
+      if (dStrstr(pExtString, (const char*)"GL_EXT_fog_coord") != NULL)
+         gGLState.suppFogCoord = true;
+      
+      // ARB_texture_compression ========================================
+      if (dStrstr(pExtString, (const char*)"GL_ARB_texture_compression") != NULL)
+         gGLState.suppTextureCompression = true;
+
+      // 3DFX_texture_compression_FXT1 ========================================
+      if (dStrstr(pExtString, (const char*)"GL_3DFX_texture_compression_FXT1") != NULL)
+         gGLState.suppFXT1 = true;
+
+      // EXT_texture_compression_S3TC ========================================
+      if (dStrstr(pExtString, (const char*)"GL_EXT_texture_compression_s3tc") != NULL)
+         gGLState.suppS3TC = true;
+
+      // EXT_vertex_buffer ========================================
+      // This extension is deprecated, and not supported by Apple. ( 10.4.3 )
+      // Instead, the ARB Vertex Buffer extension is supported.
+      // The new extension has a different API, so TGE should be updated to use it.
+      if (dStrstr(pExtString, (const char*)"GL_EXT_vertex_buffer") != NULL)
+         gGLState.suppVertexBuffer = true;
+
+      // Anisotropic filtering ========================================
+      gGLState.suppTexAnisotropic    = (dStrstr(pExtString, (const char*)"GL_EXT_texture_filter_anisotropic") != NULL);
+
+      if (gGLState.suppTexAnisotropic)
+         glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGLState.maxAnisotropy);
+
+      // Binary states, i.e., no supporting functions  ========================================
+      // NOTE:
+      // Some of these have multiple representations, via EXT and|or ARB and|or NV and|or SGIS ... etc.
+      // Check all relative versions.
+      
+      gGLState.suppPackedPixels      = (dStrstr(pExtString, (const char*)"GL_EXT_packed_pixels") != NULL);
+      gGLState.suppPackedPixels     |= (dStrstr(pExtString, (const char*)"GL_APPLE_packed_pixel") != NULL);
+
+      gGLState.suppTextureEnvCombine = (dStrstr(pExtString, (const char*)"GL_EXT_texture_env_combine") != NULL);
+      gGLState.suppTextureEnvCombine|= (dStrstr(pExtString, (const char*)"GL_ARB_texture_env_combine") != NULL);
+
+      gGLState.suppEdgeClamp         = (dStrstr(pExtString, (const char*)"GL_EXT_texture_edge_clamp") != NULL);
+      gGLState.suppEdgeClamp        |= (dStrstr(pExtString, (const char*)"GL_SGIS_texture_edge_clamp") != NULL);
+      gGLState.suppEdgeClamp        |= (dStrstr(pExtString, (const char*)"GL_ARB_texture_border_clamp") != NULL);
+	   gGLState.suppEdgeClamp		= true;
+
+      gGLState.suppTexEnvAdd         = (dStrstr(pExtString, (const char*)"GL_ARB_texture_env_add") != NULL);
+      gGLState.suppTexEnvAdd        |= (dStrstr(pExtString, (const char*)"GL_EXT_texture_env_add") != NULL);
+
+   }
+   
+   // Texture combine units  ========================================
+//   if (gGLState.suppARBMultitexture)
+//      glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gGLState.maxTextureUnits);
+	  gGLState.suppARBMultitexture = false;
+      gGLState.maxTextureUnits = 1;
+
+   // Swap interval ========================================
+   // Mac inherently supports a swap interval via AGL-set-integer.
+   gGLState.suppSwapInterval = true;
+
+   // FSAA support, TODO: check for ARB multisample support
+   // multisample support should be checked via CGL
+   gGLState.maxFSAASamples = 4;
+
+   // dump found extensions to the console... 
+   Con::printf("OpenGL Init: Enabled Extensions");
+   if (gGLState.suppARBMultitexture)    Con::printf("  ARB_multitexture (Max Texture Units: %d)", gGLState.maxTextureUnits);
+   if (gGLState.suppEXTblendcolor)      Con::printf("  EXT_blend_color");
+   if (gGLState.suppEXTblendminmax)     Con::printf("  EXT_blend_minmax");
+   if (gGLState.suppPalettedTexture)    Con::printf("  EXT_paletted_texture");
+   if (gGLState.suppLockedArrays)       Con::printf("  EXT_compiled_vertex_array");
+   if (gGLState.suppVertexArrayRange)   Con::printf("  NV_vertex_array_range");
+   if (gGLState.suppTextureEnvCombine)  Con::printf("  EXT_texture_env_combine");
+   if (gGLState.suppPackedPixels)       Con::printf("  EXT_packed_pixels");
+   if (gGLState.suppFogCoord)           Con::printf("  EXT_fog_coord");
+   if (gGLState.suppTextureCompression) Con::printf("  ARB_texture_compression");
+   if (gGLState.suppS3TC)               Con::printf("  EXT_texture_compression_s3tc");
+   if (gGLState.suppFXT1)               Con::printf("  3DFX_texture_compression_FXT1");
+   if (gGLState.suppTexEnvAdd)          Con::printf("  (ARB|EXT)_texture_env_add");
+   if (gGLState.suppTexAnisotropic)     Con::printf("  EXT_texture_filter_anisotropic (Max anisotropy: %f)", gGLState.maxAnisotropy);
+   if (gGLState.suppSwapInterval)       Con::printf("  Vertical Sync");
+   if (gGLState.maxFSAASamples)         Con::printf("  ATI_FSAA");
+
+   Con::warnf("OpenGL Init: Disabled Extensions");
+   if (!gGLState.suppARBMultitexture)    Con::warnf("  ARB_multitexture");
+   if (!gGLState.suppEXTblendcolor)      Con::warnf("  EXT_blend_color");
+   if (!gGLState.suppEXTblendminmax)     Con::warnf("  EXT_blend_minmax");
+   if (!gGLState.suppPalettedTexture)    Con::warnf("  EXT_paletted_texture");
+   if (!gGLState.suppLockedArrays)       Con::warnf("  EXT_compiled_vertex_array");
+   if (!gGLState.suppVertexArrayRange)   Con::warnf("  NV_vertex_array_range");
+   if (!gGLState.suppTextureEnvCombine)  Con::warnf("  EXT_texture_env_combine");
+   if (!gGLState.suppPackedPixels)       Con::warnf("  EXT_packed_pixels");
+   if (!gGLState.suppFogCoord)           Con::warnf("  EXT_fog_coord");
+   if (!gGLState.suppTextureCompression) Con::warnf("  ARB_texture_compression");
+   if (!gGLState.suppS3TC)               Con::warnf("  EXT_texture_compression_s3tc");
+   if (!gGLState.suppFXT1)               Con::warnf("  3DFX_texture_compression_FXT1");
+   if (!gGLState.suppTexEnvAdd)          Con::warnf("  (ARB|EXT)_texture_env_add");
+   if (!gGLState.suppTexAnisotropic)     Con::warnf("  EXT_texture_filter_anisotropic");
+   if (!gGLState.suppSwapInterval)       Con::warnf("  Vertical Sync");
+   if (!gGLState.maxFSAASamples)         Con::warnf("  ATI_FSAA");
+   Con::printf("");
+
+   // Set some console variables:
+   Con::setBoolVariable( "$FogCoordSupported", gGLState.suppFogCoord );
+   Con::setBoolVariable( "$TextureCompressionSupported", gGLState.suppTextureCompression );
+   Con::setBoolVariable( "$AnisotropySupported", gGLState.suppTexAnisotropic );
+   Con::setBoolVariable( "$PalettedTextureSupported", gGLState.suppPalettedTexture );
+   Con::setBoolVariable( "$SwapIntervalSupported", gGLState.suppSwapInterval );
+
+   if (!gGLState.suppPalettedTexture && Con::getBoolVariable("$pref::OpenGL::forcePalettedTexture",false))
+   {
+      Con::setBoolVariable("$pref::OpenGL::forcePalettedTexture", false);
+      Con::setBoolVariable("$pref::OpenGL::force16BitTexture", true);
+   }
+
+   // get fsaa samples. default to normal, no antialiasing
+   // TODO: clamp this against ARB_multisample capabilities.
+   gFSAASamples = Con::getIntVariable("$pref::OpenGL::numFSAASamples", 1);
+
+}
+
+void dglSetFSAASamples(GLint aasamp)
+{
+    if (gGLState.maxFSAASamples < 2)
+        return;
+    
+    // fix out of range values
+    if (aasamp < 1)
+        aasamp = 1;
+    else if (aasamp == 3)
+        aasamp = 2;
+    else if (aasamp > 4)
+        aasamp = 4;
+    
+    /* 
+    THIS IS CARBON
+     aglSetInteger(platState.ctx, ATI_FSAA_LEVEL, &aasamp);
+    
+    IT NEEDS OT BE REPLACED WITH SOMETHING LIKE THIS:
+     const char *glRenderer = (const char *) glGetString(GL_RENDERER);
+     
+     if (strstr(glRenderer, "ATI"))
+     {
+        NSOpenGLContext* testContext; /// <<< Need to get ahold of the current context
+       [testContext setValues:&aasamp forParameter:ATI_FSAA_LEVEL];
+     }
+     */
+    
+    Con::printf(">>Number of FSAA samples is now [%d].", aasamp);
+    Con::setIntVariable("$pref::OpenGL::numFSAASamples", aasamp);
+}
+
+
+#ifdef DUMMY_GL
+
+// declare stub functions
+#define GL_FUNCTION(fn_return, fn_name, fn_args, fn_value) fn_return fn_name fn_args{ printf(" fn_name \n"); fn_value }
+#include "platform/GLCoreFunc.h"
+#include "platform/GLExtFunc.h"
+#undef GL_FUNCTION
+
+// point gl function pointers at stub functions
+/*#define GL_FUNCTION(fn_return,fn_name,fn_args, fn_value) fn_return (*fn_name)fn_args = stub_##fn_name;
+#include "platform/GLCoreFunc.h"
+#include "platform/GLExtFunc.h"
+#undef GL_FUNCTION
+*/
+#else
+
+
+// stub out these
+
+GLAPI void GLAPIENTRY glPointSize( GLfloat size )
+{
+
+}
+
+GLAPI void GLAPIENTRY glClipPlane( GLenum plane, const GLdouble *equation )
+{
+
+}
+
+GLAPI GLboolean GLAPIENTRY glAreTexturesResident( GLsizei n, const GLuint *textures, GLboolean *residences )
+{
+    return true;
+}
+
+GLAPI void GLAPIENTRY glColor3i( GLint red, GLint green, GLint blue )
+{
+    glColor3f(255.0f/red, 255.0f/green, 255.0f/blue);
+}
+
+GLAPI void GLAPIENTRY glRecti( GLint x1, GLint y1, GLint x2, GLint y2 )
+{
+    //glRectf(x1, y2, x2, y2);
+}
+
+
+#endif
+
+
+void gluOrtho2D( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top )
+{
+    glOrtho( left, right, bottom, top, -1.0f, 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+
+GLint gluProject( GLdouble objx, GLdouble objy, GLdouble objz, const F64 *model, const F64 * proj, const GLint * vp, F64 * winx, F64 * winy, F64 * winz )
+{
+    Vector4F v = Vector4F( objx, objy, objz, 1.0f );
+    MatrixF pmat = MatrixF( false );
+        for (int i=0; i<16; i++) { ((F32*)pmat)[i] = (float)proj[i]; }
+    MatrixF mmat = MatrixF( false );
+        for (int i=0; i<16; i++) { ((F32*)mmat)[i] = (float)model[i]; }
+        
+    //Luma: Projection fix
+    mmat.transpose();
+    pmat.transpose();
+    (pmat.mul(mmat)).mul(v);
+    
+    //Luma: Projection fix
+    if(v.w == 0.0f)
+    {
+        return GL_FALSE;
+    }
+    F32     invW = 1.0f / v.w;
+    v.x *= invW;
+    v.y *= invW;
+    v.z *= invW;
+        
+    *winx = (GLfloat)vp[0] + (GLfloat)vp[2] * (v.x + 1.0f) * 0.5f;
+    *winy = (GLfloat)vp[1] + (GLfloat)vp[3] * (v.y + 1.0f) * 0.5f;
+    *winz = (v.z + 1.0f) * 0.5f;
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+    return GL_TRUE;
+}
+
+GLint gluUnProject( GLdouble winx, GLdouble winy, GLdouble winz, const F64 *model, const F64 * proj, const GLint * vp, F64 * x, F64 * y, F64 * z )
+{
+    Vector4F v = Vector4F( 2.0f*(winx-vp[0])/vp[2] - 1.0f, 2.0f*(winy-vp[1])/vp[2] - 1.0f, 2.0f*vp[2] - 1.0f, 1.0f );
+    MatrixF pmat = MatrixF( false );
+    for (int i=0; i<16; i++) { ((F32*)pmat)[i] = (float)proj[i]; }
+    MatrixF mmat = MatrixF( false );
+    for (int i=0; i<16; i++) { ((F32*)mmat)[i] = (float)model[i]; }
+    mmat = pmat.mul(mmat);
+
+    mmat = mmat.inverse();
+    mmat.mul( v );
+    *x = v.x;
+    *y = v.y;
+    *z = v.z;
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+    return GL_TRUE;
+}

+ 586 - 0
engine/source/platformEmscripten/EmscriptenGL2ES.cpp

@@ -0,0 +1,586 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "EmscriptenGL2ES.h"
+#include "platform/platformAssert.h"
+#include "EmscriptenOGLVideo.h"
+
+#include "math/mMatrix.h"
+#include "math/mPoint.h"
+
+
+#define	INV_255		0.0039215686f
+#define	INV_32767	3.0518509476e-5f
+
+/* EAGL and GL functions calling wrappers that log on error */
+#define CALL_EAGL_FUNCTION(__FUNC__, ...) ({ EAGLError __error = __FUNC__( __VA_ARGS__ ); if(__error != kEAGLErrorSuccess) Con::printf("%s() called from %s returned error %i\n", #__FUNC__, __FUNCTION__, __error); (__error ? 0 : 1); })
+#define CHECK_GL_ERROR() ({ int __error = glGetError(); if(__error) Con::printf("OpenGL error 0x%04X in %s\n", __error, __FUNCTION__); (__error ? 0 : 1); })
+// define this to print out glErrors, un-define to get rid of it
+#define TEST_FOR_OPENGL_ERRORS CHECK_GL_ERROR();
+
+    
+/////////////////////////////////////////////////////////////////////////////
+//
+//    Wrapper around the matrix stack ops, to see if ever have over/underflow
+//
+extern "C"
+{
+static GLenum currentMatrixMode = GL_MODELVIEW;
+static int currentProjStackDepth = 0;
+    static GLfloat projStack[256];
+static int currentTexStackDepth = 0;
+    static GLfloat texStack[256];
+static int currentModelStackDepth = 0;
+    static GLfloat modStack[256];
+    
+#undef glPushMatrix // temporarily
+void EmscriptenGLPushMatrix() {
+    GLint depth;
+    switch (currentMatrixMode) {
+        case GL_MODELVIEW:
+            if (currentModelStackDepth > 15) {
+                AssertFatal( 0, "ModelView Stack overflow" );
+            } else {
+                glGetFloatv( GL_MODELVIEW_MATRIX, &modStack[currentModelStackDepth*16] );
+                currentModelStackDepth++;
+                glGetIntegerv( GL_MODELVIEW_STACK_DEPTH, &depth );
+//				AssertWarn( (currentModelStackDepth > depth), "Native ModelView stack depth has been exceeded" );
+            }
+            break;
+        case GL_PROJECTION:
+            if (currentProjStackDepth > 15) {
+                AssertFatal( 0, "Projection Stack overflow" );
+            } else {
+                glGetFloatv( GL_PROJECTION_MATRIX, &projStack[currentProjStackDepth*16] );
+                currentProjStackDepth++;
+                glGetIntegerv( GL_PROJECTION_STACK_DEPTH, &depth );
+//				AssertWarn( (currentProjStackDepth > depth), "Native Projection stack depth has been exceeded" );
+            }
+            break;
+        case GL_TEXTURE:
+            if (currentTexStackDepth > 15) {
+                AssertFatal( 0, "Texture Stack overflow" );
+            } else {
+                glGetFloatv( GL_TEXTURE_MATRIX, &texStack[currentTexStackDepth*16] );
+                currentTexStackDepth++;
+                glGetIntegerv( GL_TEXTURE_STACK_DEPTH, &depth );
+//				AssertWarn( (currentTexStackDepth > depth), "Native Texture stack depth has been exceeded" );
+            }
+            break;
+        default:
+            glPushMatrix();
+            GLenum err;
+            err = glGetError();
+            AssertFatal( !(err == GL_STACK_OVERFLOW), "GL Stack overflow" );
+            break;
+    }
+}
+#define glPushMatrix EmscriptenGLPushMatrix
+    
+#undef glPopMatrix // temporarily
+void EmscriptenGLPopMatrix() {
+    switch (currentMatrixMode) {
+        case GL_MODELVIEW:
+            if (currentModelStackDepth <= 0) {
+                AssertFatal( 0, "ModelView Stack underflow" );
+            } else {
+                currentModelStackDepth--;
+                glLoadMatrixf( &modStack[currentModelStackDepth*16] );
+            }
+            break;
+        case GL_PROJECTION:
+            if (currentProjStackDepth <= 0) {
+                AssertFatal( 0, "Projection Stack underflow" );
+            } else {
+                currentProjStackDepth--;
+                glLoadMatrixf( &projStack[currentProjStackDepth*16] );
+            }
+            break;
+        case GL_TEXTURE:
+            if (currentTexStackDepth <= 0) {
+                AssertFatal( 0, "Texture Stack underflow" );
+            } else {
+                currentTexStackDepth--;
+                glLoadMatrixf( &texStack[currentTexStackDepth*16] );
+            }
+            break;
+        default:
+            glPopMatrix();
+            GLenum err;
+            err = glGetError();
+            AssertFatal( !(err == GL_STACK_UNDERFLOW), "GL Stack underflow" );
+            break;
+    }
+}
+#define glPopMatrix EmscriptenGLPopMatrix
+
+#undef glMatrixMode // temporarily
+void EmscriptenGLMatrixMode( GLenum mode ) {
+    currentMatrixMode = mode;
+    glMatrixMode( mode );
+}
+#define glMatrixMode EmscriptenGLMatrixMode // redefine for everyone else
+}	
+
+/////////////////////////////////////////////////////////////////////////////
+//
+//    The following API functions are wrappers to add opengl functionality to opengl-es
+//
+static GLint beginEndMode = -1;
+// tex coord array
+static GLfloat * beginEndTexCoord2f = NULL; // 2 entries per coord
+static int beginEndTexCoord2f_alloc = 0; // number of bytes allocated to the array
+static int beginEndTexCoord2f_size = 0; // number of coords in the array
+// vertex array
+static GLfloat * beginEndVertex = NULL; // 4 entries per vertex
+static int beginEndVertex_alloc = 0; // number of bytes allocated to the array
+static int beginEndVertex_size = 0; // number of vertexes in the array
+// color array -- needed if glColor is called inside begin/end
+static GLfloat * beginEndColor = NULL; // 4 entries per color
+static int beginEndColor_size = 0; // number of colors in the array
+// normal array
+static GLfloat * beginEndNormal = NULL; // 3 entries per normal
+static int beginEndNormal_alloc = 0; // number of bytes allocated to the array
+static int beginEndNormal_size = 0; // number of normals in the array
+
+// macros to handle re-sizing the arrays as needed
+#define CHECK_ARRAY_SIZE( ppArray, pAlloc, pSize, nType, nGroup ) \
+    if (*ppArray == NULL) { \
+        *pAlloc =  32 * sizeof(nType) * nGroup; \
+        *ppArray = (nType*)dMalloc( 32 * sizeof(nType) * nGroup ); \
+    } \
+    if (*pSize >= *pAlloc / (nGroup * sizeof(nType))) { \
+        *ppArray = (nType*)dRealloc( *ppArray, 2 * (*pAlloc) ); \
+        *pAlloc *= 2; \
+    }
+    
+    
+void glBegin( GLint mode )
+{
+    if (beginEndMode >= 0) {
+        AssertFatal(0, "glBegin(): called without a glEnd");
+    }
+    beginEndMode = mode;
+    beginEndTexCoord2f_size = 0;
+    beginEndVertex_size = 0;
+    beginEndColor_size = 0;
+    beginEndNormal_size = 0;
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+
+void glEnd()
+{
+    if (beginEndMode < 0) {
+        AssertFatal(0, "glEnd(): called without a glBegin");
+    }
+    
+    if (beginEndVertex_size > 0) {
+        glEnableClientState( GL_VERTEX_ARRAY );
+        glVertexPointer( 4, GL_FLOAT, 4*sizeof(GL_FLOAT), beginEndVertex );
+    }
+    if (beginEndNormal_size > 0) {
+        glEnableClientState( GL_NORMAL_ARRAY );
+        glNormalPointer( GL_FLOAT, 3*sizeof(GL_FLOAT), beginEndNormal );
+    }
+    if (beginEndColor_size > 0) {
+        glEnableClientState( GL_COLOR_ARRAY );
+        glColorPointer( 4, GL_FLOAT, 4*sizeof(GL_FLOAT), beginEndColor );
+    }
+    if (beginEndTexCoord2f_size > 0) {
+        glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+        glTexCoordPointer( 2, GL_FLOAT, 2*sizeof(GL_FLOAT), beginEndTexCoord2f );
+    }
+
+    switch (beginEndMode) {
+        case GL_POINTS:
+            glDrawArrays( GL_POINTS, 0, beginEndVertex_size );
+            break;
+        case GL_LINES:
+            glDrawArrays( GL_LINES, 0, beginEndVertex_size );
+            break;
+        case GL_LINE_STRIP:
+            glDrawArrays( GL_LINE_STRIP, 0, beginEndVertex_size );
+            break;
+        case GL_LINE_LOOP:
+            glDrawArrays( GL_LINE_LOOP, 0, beginEndVertex_size );
+            break;
+        case GL_TRIANGLES:
+            glDrawArrays( GL_TRIANGLES, 0, beginEndVertex_size );
+            break;
+        case GL_TRIANGLE_STRIP:
+            glDrawArrays( GL_TRIANGLE_STRIP, 0, beginEndVertex_size );
+            break;
+        case GL_TRIANGLE_FAN:
+            glDrawArrays( GL_TRIANGLE_FAN, 0, beginEndVertex_size );
+            break;
+        case GL_QUADS:
+#if 1 // %%PUAP%% TESTING
+            // for now, just draw a couple lines to indicate the edges of the quads
+            glDrawArrays( GL_LINES, 0, beginEndVertex_size );
+#else
+            // draw these as individual pairs of triangle_strips
+            glDrawArrays( GL_TRIANGLE_STRIP, 0, beginEndVertex_size );
+#endif
+            break;
+        case GL_QUAD_STRIP:
+#if 1 // %%PUAP%% TESTING
+            glDrawArrays( GL_LINES, 0, beginEndVertex_size );
+#endif
+            break;
+        case GL_POLYGON:
+            // see if it is really just a triangle...
+            if (beginEndVertex_size == 3) {
+                glDrawArrays( GL_TRIANGLES, 0, 3 );
+            } else 
+            // see if it is really just a quad...
+            if (beginEndVertex_size == 4) {
+                glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
+            } else
+                AssertFatal( 0, "glBegin(GL_POLYGON): this method call needs to be implemented");
+            break;
+    }
+    
+    if (beginEndVertex_size > 0) {
+        glDisableClientState( GL_VERTEX_ARRAY );
+    }
+    if (beginEndNormal_size > 0) {
+        glDisableClientState( GL_NORMAL_ARRAY );
+    }
+    if (beginEndColor_size > 0) {
+        glDisableClientState( GL_COLOR_ARRAY );
+    }
+    if (beginEndTexCoord2f_size > 0) {
+        glDisableClientState( GL_TEXTURE_COORD_ARRAY );
+    }
+    beginEndMode = -1;	
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+
+void glTexCoord2f( GLfloat x, GLfloat y)
+{
+    AssertFatal( (beginEndMode >= 0), "glTexCoord2f(): called outside glBegin/glEnd");
+    CHECK_ARRAY_SIZE( &beginEndTexCoord2f, &beginEndTexCoord2f_alloc, &beginEndTexCoord2f_size, GLfloat, 2 );
+    beginEndTexCoord2f[ beginEndTexCoord2f_size*2 ] = x;
+    beginEndTexCoord2f[ beginEndTexCoord2f_size*2+1 ] = y;
+    beginEndTexCoord2f_size++;
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glVertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+    AssertFatal( (beginEndMode >= 0), "glVertex3f(): called outside glBegin/glEnd");
+    CHECK_ARRAY_SIZE( &beginEndVertex, &beginEndVertex_alloc, &beginEndVertex_size, GLfloat, 4 );
+    beginEndVertex[ beginEndVertex_size*4 ] = x;
+    beginEndVertex[ beginEndVertex_size*4+1 ] = y;
+    beginEndVertex[ beginEndVertex_size*4+2 ] = z;
+    beginEndVertex[ beginEndVertex_size*4+3 ] = w;
+    beginEndVertex_size++;
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glVertex2f( GLfloat x, GLfloat y )
+{
+    AssertFatal( (beginEndMode >= 0), "glVertex2f(): called outside glBegin/glEnd");
+    glVertex4f( x, y, 0.0f, 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glVertex3f( GLfloat x, GLfloat y, GLfloat z )
+{
+    AssertFatal( (beginEndMode >= 0), "glVertex3f(): called outside glBegin/glEnd");
+    glVertex4f( x, y, z, 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glVertex2fv( const F32 * pv )
+{
+    AssertFatal( (beginEndMode >= 0), "glVertex2fv(): called outside glBegin/glEnd");
+    glVertex4f( pv[0], pv[1], 0.0f, 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glVertex2i( GLint x, GLint y)
+{
+    AssertFatal( (beginEndMode >= 0), "glVertex2i(): called outside glBegin/glEnd");
+    glVertex4f( GLfloat(x), GLfloat(y), 0.0f, 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glVertex3fv( const F32 * pv )
+{
+    AssertFatal( (beginEndMode >= 0), "glVertex3fv(): called outside glBegin/glEnd");
+    glVertex4f( pv[0], pv[1], pv[2], 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glVertex4fv( const F32 * pv )
+{
+    AssertFatal( (beginEndMode >= 0), "glVertex3fv(): called outside glBegin/glEnd");
+    glVertex4f( pv[0], pv[1], pv[2], pv[3] );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glNormal3f( GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+    AssertFatal( (beginEndMode >= 0), "glNormal3f(): called outside glBegin/glEnd");
+    CHECK_ARRAY_SIZE( &beginEndNormal, &beginEndNormal_alloc, &beginEndNormal_size, GLfloat, 3 );
+    beginEndNormal[ beginEndNormal_size*3 ] = x;
+    beginEndNormal[ beginEndNormal_size*3+1 ] = y;
+    beginEndNormal[ beginEndNormal_size*3+2 ] = z;
+    beginEndNormal_size++;
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glNormal3fv( const F32 * pv)
+{
+    AssertFatal( (beginEndMode >= 0), "glNormal3fv(): called outside glBegin/glEnd");
+    glNormal3f( pv[0], pv[1], pv[2] );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glColor3fv( const F32 * pv)
+{
+    glColor4f( pv[0], pv[1], pv[2], 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glColor4fv( const F32 * pv)
+{
+    glColor4f( pv[0], pv[1], pv[2], pv[3] );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glActiveTextureARB( GLint index )
+{
+    glActiveTexture( index );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glMultiTexCoord2fARB( GLint, GLfloat, GLfloat)
+{
+    AssertWarn( 0, "glMultiTexCoord2fARB(): this method call needs to be implemented");
+}
+void glPushAttrib( GLint )
+{
+    AssertWarn( 0, "glPushAttrib(): this method call needs to be implemented");
+}
+void glPopAttrib()
+{
+    AssertWarn( 0, "glPopAttrib(): this method call needs to be implemented");
+}
+//void glOrtho( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+//{
+//	GLfloat tx = -(right+left)/(right-left);
+//	GLfloat ty = -(top+bottom)/(top-bottom);
+//	GLfloat tz = -(zFar+zNear)/(zFar-zNear);
+//	MatrixF m = MatrixF(true);
+//	((F32*)m)[0] = 2.0f/(right-left);
+//	((F32*)m)[3] = tx;
+//	((F32*)m)[5] = 2.0f/(top-bottom);
+//	((F32*)m)[7] = ty;
+//	((F32*)m)[10] = -2.0f/(zFar-zNear);
+//	((F32*)m)[11] = tz;
+//	
+//	glMultMatrixf( (F32*)(m.transpose())); // make col major for opengl
+//}
+//void glFrustum( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar )
+//{
+//	MatrixF m = MatrixF(true);
+//	((F32*)m)[0] = 2.0f*zNear/(right-left);
+//	((F32*)m)[2] = (right+left)/(right-left);
+//	((F32*)m)[5] = 2.0f*zNear/(top-bottom);
+//	((F32*)m)[6] = (top+bottom)/(top-bottom);
+//	((F32*)m)[10] = -(zFar+zNear)/(zFar-zNear);
+//	((F32*)m)[11] = -2.0f*zFar*zNear/(zFar-zNear);
+//	((F32*)m)[14] = -1.0f;
+//	((F32*)m)[15] = 0.0f;
+//	
+//	glMultMatrixf( (F32*)(m.transpose())); // make col major for opengl
+//}
+void glReadBuffer( GLint )
+{
+    AssertWarn( 0, "glReadBuffer(): this method call needs to be implemented");
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glClientActiveTextureARB( GLint texture )
+{
+    glClientActiveTexture( texture );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glColor3i( GLint  r, GLint g, GLint b )
+{
+    glColor4f( ((GLfloat)r) * INV_32767, ((GLfloat)g) * INV_32767, ((GLfloat)b) * INV_32767, 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glColor3ubv( const GLubyte *v )
+{
+    glColor4f( ((GLfloat)v[0]) * INV_255, ((GLfloat)v[1]) * INV_255, ((GLfloat)v[2]) * INV_255, 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glColor4ubv( const GLubyte *v )
+{
+    glColor4f( ((GLfloat)v[0]) * INV_255, ((GLfloat)v[1]) * INV_255, ((GLfloat)v[2]) * INV_255, ((GLfloat)v[3]) * INV_255 );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glRecti( GLint x1, GLint y1, GLint x2, GLint y2 )
+{
+    AssertFatal( beginEndMode<0, "glRecti(): called inside glBegin/glEnd");
+    glBegin(GL_LINE_LOOP);
+    glVertex2i(x1, y1);
+    glVertex2i(x2, y1);
+    glVertex2i(x2, y2);
+    glVertex2i(x1, y2);
+    glEnd();
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+
+void glGetDoublev( GLint pname, GLdouble * params )
+{
+    int i;
+    GLfloat fparams[16];
+    glGetFloatv( pname, fparams );
+    AssertFatal((glGetError() == GL_NO_ERROR), "glGetDoublev parameter invalid");
+    params[0] = (double)fparams[0]; 
+    if ((pname == GL_ALIASED_POINT_SIZE_RANGE) ||
+        (pname == GL_ALIASED_LINE_WIDTH_RANGE) ||
+        (pname == GL_DEPTH_RANGE) ||
+        (pname == GL_MAX_VIEWPORT_DIMS) ||
+        (pname == GL_SMOOTH_LINE_WIDTH_RANGE) ||
+        (pname == GL_SMOOTH_POINT_SIZE_RANGE)) {
+        // 2 items
+        params[1] = (double)fparams[1];
+        return;
+    }
+    if ((pname == GL_COLOR_CLEAR_VALUE) ||
+        (pname == GL_COLOR_WRITEMASK) ||
+        (pname == GL_FOG_COLOR) ||
+        (pname == GL_LIGHT_MODEL_AMBIENT) ||
+        (pname == GL_SCISSOR_BOX) ||
+        (pname == GL_VIEWPORT) ) {
+        // 4 items
+        params[1] = (double)fparams[1];
+        params[2] = (double)fparams[2];
+        params[3] = (double)fparams[3];
+        return;
+    }
+    if ((pname == GL_PROJECTION_MATRIX) ||
+        //Luma: Added MODDELVIEW support
+        (pname == GL_MODELVIEW_MATRIX) ||
+        //(pname == GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS) ||
+        //(pname == GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS) ||  
+        (pname == GL_TEXTURE_MATRIX) ) {
+        // 16 items
+        for (i=1; i<16; i++) {
+            params[i] = (double)fparams[i];
+        }
+        return;
+    }
+}
+void glPolygonMode( GLint, GLint )
+{
+    //AssertFatal( 0, "glPolygonMode(): this method call needs to be implemented");
+}
+void glLockArraysEXT( GLint, GLint )
+{
+    AssertFatal( 0, "glLockArraysEXT(): this method call needs to be implemented");
+}
+void glUnlockArraysEXT()
+{
+    AssertFatal( 0, "glUnlockArraysEXT(): this method call needs to be implemented");
+}
+void glColor3ub( GLint r, GLint g, GLint b )
+{
+    glColor4f( ((GLfloat)r) * INV_255, ((GLfloat)g) * INV_255, ((GLfloat)b) * INV_255, 1.0f );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+void glFogi( GLint pname, GLint param )
+{
+    glFogf( pname, (GLfloat)param );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+/*	-Mat note: only guiCanvas uses this, and before adding this GL2ES stuff we didn't need to use it (it was one of the first things if'ed out)
+void glDrawBuffer( GLint buffid )
+{
+    ((EAGLView *)platState.ctx).currentRenderBuffer = buffid;
+    TEST_FOR_OPENGL_ERRORS
+}
+*/
+void glColorTableEXT( GLint, GLint, GLint, GLint, GLint, const ColorI * )
+{
+    AssertFatal( 0, "glColorTableEXT(): this method call needs to be implemented");
+}
+void glBlendColorEXT( GLfloat, GLfloat, GLfloat, GLfloat )
+{
+    AssertFatal( 0, "glBlendColorEXT(): this method call needs to be implemented");
+}
+void glBlendEquationEXT( GLint )
+{
+    AssertFatal( 0, "glBlendEquationEXT(): this method call needs to be implemented");
+}
+void glArrayElement( GLint )
+{
+    AssertFatal( 0, "glArrayElement(): this method call needs to be implemented");
+}
+void glFogCoordPointerEXT(GLenum, GLsizei, void *)
+{
+    AssertFatal( 0, "glFogCoordPointerEXT(): this method call needs to be implemented");
+}
+//void glDepthRange( GLfloat, GLfloat )
+//{
+//	AssertFatal( 0, "glDepthRange(): this method call needs to be implemented");
+//}
+void glTexGeni( GLenum coord, GLenum pname, GLint param )
+{
+    AssertFatal( 0, "glTexGeni(): this method call needs to be implemented");
+}
+void glTexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
+{
+    AssertFatal( 0, "glTexGenfv(): this method call needs to be implemented");
+}
+void glClipPlane( GLuint plane, GLdouble * equation )
+{
+    GLfloat fequ[4];
+    fequ[0] = (GLfloat)equation[0];
+    fequ[1] = (GLfloat)equation[1];
+    fequ[2] = (GLfloat)equation[2];
+    fequ[3] = (GLfloat)equation[3];
+    glClipPlanef( plane, fequ );
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+}
+GLboolean glAreTexturesResident( GLsizei, const GLuint *, GLboolean*)
+{
+    int glError;
+    glError = TEST_FOR_OPENGL_ERRORS
+    return GL_FALSE;
+}
+

+ 1430 - 0
engine/source/platformEmscripten/EmscriptenGL2ES.h

@@ -0,0 +1,1430 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _GL2ES_H_
+#define _GL2ES_H_
+
+
+#include "platform/types.h"
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+extern "C"
+{
+void EmscriptenGLPushMatrix();
+void EmscriptenGLPopMatrix();
+void EmscriptenGLMatrixMode( GLenum mode );
+}
+
+// help out the shallow matrix stacks...
+#define glPushMatrix EmscriptenGLPushMatrix
+#define glPopMatrix EmscriptenGLPopMatrix
+#define glMatrixMode EmscriptenGLMatrixMode
+
+class ColorI;
+
+// defines that need functional workarounds
+//
+//typedef unsigned int GLenum;
+//typedef unsigned char GLboolean;
+//typedef unsigned int GLbitfield;
+//typedef signed char GLbyte;
+//typedef short GLshort;
+//typedef int GLint;
+//typedef int GLsizei;
+//typedef unsigned char GLubyte;
+//typedef unsigned short GLushort;
+//typedef unsigned int GLuint;
+//typedef float GLfloat;
+//typedef float GLclampf;
+//typedef double GLdouble;
+//typedef double GLclampd;
+//typedef void GLvoid;
+//typedef int GLfixed;
+//typedef int GLclampx;
+//
+///* AccumOp */
+//#define GL_ACCUM                          0x0100
+//#define GL_LOAD                           0x0101
+//#define GL_RETURN                         0x0102
+//#define GL_MULT                           0x0103
+//#define GL_ADD                            0x0104
+//
+///* AlphaFunction */
+//#define GL_NEVER                          0x0200
+//#define GL_LESS                           0x0201
+//#define GL_EQUAL                          0x0202
+//#define GL_LEQUAL                         0x0203
+//#define GL_GREATER                        0x0204
+//#define GL_NOTEQUAL                       0x0205
+//#define GL_GEQUAL                         0x0206
+//#define GL_ALWAYS                         0x0207
+//
+///* AttribMask */
+//#define GL_CURRENT_BIT                    0x00000001
+//#define GL_POINT_BIT                      0x00000002
+//#define GL_LINE_BIT                       0x00000004
+//#define GL_POLYGON_BIT                    0x00000008
+//#define GL_POLYGON_STIPPLE_BIT            0x00000010
+//#define GL_PIXEL_MODE_BIT                 0x00000020
+//#define GL_LIGHTING_BIT                   0x00000040
+//#define GL_FOG_BIT                        0x00000080
+//#define GL_DEPTH_BUFFER_BIT               0x00000100
+//#define GL_ACCUM_BUFFER_BIT               0x00000200
+//#define GL_STENCIL_BUFFER_BIT             0x00000400
+//#define GL_VIEWPORT_BIT                   0x00000800
+//#define GL_TRANSFORM_BIT                  0x00001000
+//#define GL_ENABLE_BIT                     0x00002000
+//#define GL_COLOR_BUFFER_BIT               0x00004000
+//#define GL_HINT_BIT                       0x00008000
+//#define GL_EVAL_BIT                       0x00010000
+//#define GL_LIST_BIT                       0x00020000
+//#define GL_TEXTURE_BIT                    0x00040000
+//#define GL_SCISSOR_BIT                    0x00080000
+//#define GL_ALL_ATTRIB_BITS                0x000fffff
+//
+///* BeginMode */
+//#define GL_POINTS                         0x0000
+//#define GL_LINES                          0x0001
+//#define GL_LINE_LOOP                      0x0002
+//#define GL_LINE_STRIP                     0x0003
+//#define GL_TRIANGLES                      0x0004
+//#define GL_TRIANGLE_STRIP                 0x0005
+//#define GL_TRIANGLE_FAN                   0x0006
+#define GL_QUADS                          0x0007
+#define GL_QUAD_STRIP                     0x0008
+#define GL_POLYGON                        0x0009
+//
+///* BlendingFactorDest */
+//#define GL_ZERO                           0
+//#define GL_ONE                            1
+//#define GL_SRC_COLOR                      0x0300
+//#define GL_ONE_MINUS_SRC_COLOR            0x0301
+//#define GL_SRC_ALPHA                      0x0302
+//#define GL_ONE_MINUS_SRC_ALPHA            0x0303
+//#define GL_DST_ALPHA                      0x0304
+//#define GL_ONE_MINUS_DST_ALPHA            0x0305
+//
+///* BlendingFactorSrc */
+///*      GL_ZERO */
+///*      GL_ONE */
+//#define GL_DST_COLOR                      0x0306
+//#define GL_ONE_MINUS_DST_COLOR            0x0307
+//#define GL_SRC_ALPHA_SATURATE             0x0308
+///*      GL_SRC_ALPHA */
+///*      GL_ONE_MINUS_SRC_ALPHA */
+///*      GL_DST_ALPHA */
+///*      GL_ONE_MINUS_DST_ALPHA */
+//
+///* Boolean */
+//#define GL_TRUE                           1
+//#define GL_FALSE                          0
+//
+///* ClearBufferMask */
+///*      GL_COLOR_BUFFER_BIT */
+///*      GL_ACCUM_BUFFER_BIT */
+///*      GL_STENCIL_BUFFER_BIT */
+///*      GL_DEPTH_BUFFER_BIT */
+//
+///* ClientArrayType */
+///*      GL_VERTEX_ARRAY */
+///*      GL_NORMAL_ARRAY */
+///*      GL_COLOR_ARRAY */
+///*      GL_INDEX_ARRAY */
+///*      GL_TEXTURE_COORD_ARRAY */
+///*      GL_EDGE_FLAG_ARRAY */
+//
+///* ClipPlaneName */
+//#define GL_CLIP_PLANE0                    0x3000
+//#define GL_CLIP_PLANE1                    0x3001
+//#define GL_CLIP_PLANE2                    0x3002
+//#define GL_CLIP_PLANE3                    0x3003
+//#define GL_CLIP_PLANE4                    0x3004
+//#define GL_CLIP_PLANE5                    0x3005
+//
+///* ColorMaterialFace */
+///*      GL_FRONT */
+///*      GL_BACK */
+///*      GL_FRONT_AND_BACK */
+//
+///* ColorMaterialParameter */
+///*      GL_AMBIENT */
+///*      GL_DIFFUSE */
+///*      GL_SPECULAR */
+///*      GL_EMISSION */
+///*      GL_AMBIENT_AND_DIFFUSE */
+//
+///* ColorPointerType */
+///*      GL_BYTE */
+///*      GL_UNSIGNED_BYTE */
+///*      GL_SHORT */
+///*      GL_UNSIGNED_SHORT */
+///*      GL_INT */
+///*      GL_UNSIGNED_INT */
+///*      GL_FLOAT */
+///*      GL_DOUBLE */
+//
+///* CullFaceMode */
+///*      GL_FRONT */
+///*      GL_BACK */
+///*      GL_FRONT_AND_BACK */
+//
+///* DataType */
+//#define GL_BYTE                           0x1400
+#define GL_UNSIGNED_BYTE                  0x1401
+//#define GL_SHORT                          0x1402
+//#define GL_UNSIGNED_SHORT                 0x1403
+//#define GL_INT                            0x1404
+#define GL_UNSIGNED_INT                   0x1405
+//#define GL_FLOAT                          0x1406
+//#define GL_2_BYTES                        0x1407
+//#define GL_3_BYTES                        0x1408
+//#define GL_4_BYTES                        0x1409
+//#define GL_DOUBLE                         0x140A
+//#define GL_FIXED                          0x140C
+//
+///* DepthFunction */
+///*      GL_NEVER */
+///*      GL_LESS */
+///*      GL_EQUAL */
+///*      GL_LEQUAL */
+///*      GL_GREATER */
+///*      GL_NOTEQUAL */
+///*      GL_GEQUAL */
+///*      GL_ALWAYS */
+//
+///* DrawBufferMode */
+//#define GL_NONE                           0
+//#define GL_FRONT_LEFT                     0x0400
+//#define GL_FRONT_RIGHT                    0x0401
+//#define GL_BACK_LEFT                      0x0402
+//#define GL_BACK_RIGHT                     0x0403
+//#define GL_FRONT                          0x0404
+//#define GL_BACK                           0x0405
+//#define GL_LEFT                           0x0406
+//#define GL_RIGHT                          0x0407
+//#define GL_FRONT_AND_BACK                 0x0408
+//#define GL_AUX0                           0x0409
+//#define GL_AUX1                           0x040A
+//#define GL_AUX2                           0x040B
+//#define GL_AUX3                           0x040C
+//
+///* Enable */
+///*      GL_FOG */
+///*      GL_LIGHTING */
+///*      GL_TEXTURE_1D */
+///*      GL_TEXTURE_2D */
+///*      GL_LINE_STIPPLE */
+///*      GL_POLYGON_STIPPLE */
+///*      GL_CULL_FACE */
+///*      GL_ALPHA_TEST */
+///*      GL_BLEND */
+///*      GL_INDEX_LOGIC_OP */
+///*      GL_COLOR_LOGIC_OP */
+///*      GL_DITHER */
+///*      GL_STENCIL_TEST */
+///*      GL_DEPTH_TEST */
+///*      GL_CLIP_PLANE0 */
+///*      GL_CLIP_PLANE1 */
+///*      GL_CLIP_PLANE2 */
+///*      GL_CLIP_PLANE3 */
+///*      GL_CLIP_PLANE4 */
+///*      GL_CLIP_PLANE5 */
+///*      GL_LIGHT0 */
+///*      GL_LIGHT1 */
+///*      GL_LIGHT2 */
+///*      GL_LIGHT3 */
+///*      GL_LIGHT4 */
+///*      GL_LIGHT5 */
+///*      GL_LIGHT6 */
+///*      GL_LIGHT7 */
+///*      GL_TEXTURE_GEN_S */
+///*      GL_TEXTURE_GEN_T */
+///*      GL_TEXTURE_GEN_R */
+///*      GL_TEXTURE_GEN_Q */
+///*      GL_MAP1_VERTEX_3 */
+///*      GL_MAP1_VERTEX_4 */
+///*      GL_MAP1_COLOR_4 */
+///*      GL_MAP1_INDEX */
+///*      GL_MAP1_NORMAL */
+///*      GL_MAP1_TEXTURE_COORD_1 */
+///*      GL_MAP1_TEXTURE_COORD_2 */
+///*      GL_MAP1_TEXTURE_COORD_3 */
+///*      GL_MAP1_TEXTURE_COORD_4 */
+///*      GL_MAP2_VERTEX_3 */
+///*      GL_MAP2_VERTEX_4 */
+///*      GL_MAP2_COLOR_4 */
+///*      GL_MAP2_INDEX */
+///*      GL_MAP2_NORMAL */
+///*      GL_MAP2_TEXTURE_COORD_1 */
+///*      GL_MAP2_TEXTURE_COORD_2 */
+///*      GL_MAP2_TEXTURE_COORD_3 */
+///*      GL_MAP2_TEXTURE_COORD_4 */
+///*      GL_POINT_SMOOTH */
+///*      GL_LINE_SMOOTH */
+///*      GL_POLYGON_SMOOTH */
+///*      GL_SCISSOR_TEST */
+///*      GL_COLOR_MATERIAL */
+///*      GL_NORMALIZE */
+///*      GL_AUTO_NORMAL */
+///*      GL_VERTEX_ARRAY */
+///*      GL_NORMAL_ARRAY */
+///*      GL_COLOR_ARRAY */
+///*      GL_INDEX_ARRAY */
+///*      GL_TEXTURE_COORD_ARRAY */
+///*      GL_EDGE_FLAG_ARRAY */
+///*      GL_POLYGON_OFFSET_POINT */
+///*      GL_POLYGON_OFFSET_LINE */
+///*      GL_POLYGON_OFFSET_FILL */
+//
+///* ErrorCode */
+//#define GL_NO_ERROR                       0
+//#define GL_INVALID_ENUM                   0x0500
+//#define GL_INVALID_VALUE                  0x0501
+//#define GL_INVALID_OPERATION              0x0502
+//#define GL_STACK_OVERFLOW                 0x0503
+//#define GL_STACK_UNDERFLOW                0x0504
+//#define GL_OUT_OF_MEMORY                  0x0505
+//
+///* FeedBackMode */
+//#define GL_2D                             0x0600
+//#define GL_3D                             0x0601
+//#define GL_3D_COLOR                       0x0602
+//#define GL_3D_COLOR_TEXTURE               0x0603
+//#define GL_4D_COLOR_TEXTURE               0x0604
+//
+///* FeedBackToken */
+//#define GL_PASS_THROUGH_TOKEN             0x0700
+//#define GL_POINT_TOKEN                    0x0701
+//#define GL_LINE_TOKEN                     0x0702
+//#define GL_POLYGON_TOKEN                  0x0703
+//#define GL_BITMAP_TOKEN                   0x0704
+//#define GL_DRAW_PIXEL_TOKEN               0x0705
+//#define GL_COPY_PIXEL_TOKEN               0x0706
+//#define GL_LINE_RESET_TOKEN               0x0707
+//
+///* FogMode */
+///*      GL_LINEAR */
+//#define GL_EXP                            0x0800
+//#define GL_EXP2                           0x0801
+//
+//
+///* FogParameter */
+///*      GL_FOG_COLOR */
+///*      GL_FOG_DENSITY */
+///*      GL_FOG_END */
+///*      GL_FOG_INDEX */
+///*      GL_FOG_MODE */
+///*      GL_FOG_START */
+//
+#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450
+#define GL_FOG_COORDINATE_EXT 0x8451
+#define GL_FRAGMENT_DEPTH_EXT 0x8452
+//#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453
+//#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454
+//#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455
+//#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
+#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 
+//
+///* FrontFaceDirection */
+//#define GL_CW                             0x0900
+//#define GL_CCW                            0x0901
+//
+///* GetMapTarget */
+//#define GL_COEFF                          0x0A00
+//#define GL_ORDER                          0x0A01
+//#define GL_DOMAIN                         0x0A02
+//
+///* GetPixelMap */
+///*      GL_PIXEL_MAP_I_TO_I */
+///*      GL_PIXEL_MAP_S_TO_S */
+///*      GL_PIXEL_MAP_I_TO_R */
+///*      GL_PIXEL_MAP_I_TO_G */
+///*      GL_PIXEL_MAP_I_TO_B */
+///*      GL_PIXEL_MAP_I_TO_A */
+///*      GL_PIXEL_MAP_R_TO_R */
+///*      GL_PIXEL_MAP_G_TO_G */
+///*      GL_PIXEL_MAP_B_TO_B */
+///*      GL_PIXEL_MAP_A_TO_A */
+//
+///* GetPointerTarget */
+///*      GL_VERTEX_ARRAY_POINTER */
+///*      GL_NORMAL_ARRAY_POINTER */
+///*      GL_COLOR_ARRAY_POINTER */
+///*      GL_INDEX_ARRAY_POINTER */
+///*      GL_TEXTURE_COORD_ARRAY_POINTER */
+///*      GL_EDGE_FLAG_ARRAY_POINTER */
+//
+///* GetTarget */
+//#define GL_CURRENT_COLOR                  0x0B00
+//#define GL_CURRENT_INDEX                  0x0B01
+//#define GL_CURRENT_NORMAL                 0x0B02
+//#define GL_CURRENT_TEXTURE_COORDS         0x0B03
+//#define GL_CURRENT_RASTER_COLOR           0x0B04
+//#define GL_CURRENT_RASTER_INDEX           0x0B05
+//#define GL_CURRENT_RASTER_TEXTURE_COORDS  0x0B06
+//#define GL_CURRENT_RASTER_POSITION        0x0B07
+//#define GL_CURRENT_RASTER_POSITION_VALID  0x0B08
+//#define GL_CURRENT_RASTER_DISTANCE        0x0B09
+//#define GL_POINT_SMOOTH                   0x0B10
+//#define GL_POINT_SIZE                     0x0B11
+//#define GL_POINT_SIZE_RANGE               0x0B12
+//#define GL_POINT_SIZE_GRANULARITY         0x0B13
+//#define GL_LINE_SMOOTH                    0x0B20
+//#define GL_LINE_WIDTH                     0x0B21
+//#define GL_LINE_WIDTH_RANGE               0x0B22
+//#define GL_LINE_WIDTH_GRANULARITY         0x0B23
+//#define GL_LINE_STIPPLE                   0x0B24
+//#define GL_LINE_STIPPLE_PATTERN           0x0B25
+//#define GL_LINE_STIPPLE_REPEAT            0x0B26
+//#define GL_LIST_MODE                      0x0B30
+//#define GL_MAX_LIST_NESTING               0x0B31
+//#define GL_LIST_BASE                      0x0B32
+//#define GL_LIST_INDEX                     0x0B33
+#define GL_POLYGON_MODE                   0x0B40
+//#define GL_POLYGON_SMOOTH                 0x0B41
+//#define GL_POLYGON_STIPPLE                0x0B42
+//#define GL_EDGE_FLAG                      0x0B43
+//#define GL_CULL_FACE                      0x0B44
+//#define GL_CULL_FACE_MODE                 0x0B45
+//#define GL_FRONT_FACE                     0x0B46
+//#define GL_LIGHTING                       0x0B50
+//#define GL_LIGHT_MODEL_LOCAL_VIEWER       0x0B51
+//#define GL_LIGHT_MODEL_TWO_SIDE           0x0B52
+//#define GL_LIGHT_MODEL_AMBIENT            0x0B53
+//#define GL_SHADE_MODEL                    0x0B54
+//#define GL_COLOR_MATERIAL_FACE            0x0B55
+//#define GL_COLOR_MATERIAL_PARAMETER       0x0B56
+//#define GL_COLOR_MATERIAL                 0x0B57
+//#define GL_FOG                            0x0B60
+//#define GL_FOG_INDEX                      0x0B61
+//#define GL_FOG_DENSITY                    0x0B62
+//#define GL_FOG_START                      0x0B63
+//#define GL_FOG_END                        0x0B64
+//#define GL_FOG_MODE                       0x0B65
+//#define GL_FOG_COLOR                      0x0B66
+//#define GL_DEPTH_RANGE                    0x0B70
+//#define GL_DEPTH_TEST                     0x0B71
+//#define GL_DEPTH_WRITEMASK                0x0B72
+//#define GL_DEPTH_CLEAR_VALUE              0x0B73
+//#define GL_DEPTH_FUNC                     0x0B74
+//#define GL_ACCUM_CLEAR_VALUE              0x0B80
+//#define GL_STENCIL_TEST                   0x0B90
+//#define GL_STENCIL_CLEAR_VALUE            0x0B91
+//#define GL_STENCIL_FUNC                   0x0B92
+//#define GL_STENCIL_VALUE_MASK             0x0B93
+//#define GL_STENCIL_FAIL                   0x0B94
+//#define GL_STENCIL_PASS_DEPTH_FAIL        0x0B95
+//#define GL_STENCIL_PASS_DEPTH_PASS        0x0B96
+//#define GL_STENCIL_REF                    0x0B97
+//#define GL_STENCIL_WRITEMASK              0x0B98
+//#define GL_MATRIX_MODE                    0x0BA0
+//#define GL_NORMALIZE                      0x0BA1
+//#define GL_VIEWPORT                       0x0BA2
+//#define GL_MODELVIEW_STACK_DEPTH          0x0BA3
+//#define GL_PROJECTION_STACK_DEPTH         0x0BA4
+//#define GL_TEXTURE_STACK_DEPTH            0x0BA5
+//#define GL_MODELVIEW_MATRIX               0x0BA6
+//#define GL_PROJECTION_MATRIX              0x0BA7
+//#define GL_TEXTURE_MATRIX                 0x0BA8
+//#define GL_ATTRIB_STACK_DEPTH             0x0BB0
+//#define GL_CLIENT_ATTRIB_STACK_DEPTH      0x0BB1
+//#define GL_ALPHA_TEST                     0x0BC0
+//#define GL_ALPHA_TEST_FUNC                0x0BC1
+//#define GL_ALPHA_TEST_REF                 0x0BC2
+//#define GL_DITHER                         0x0BD0
+//#define GL_BLEND_DST                      0x0BE0
+//#define GL_BLEND_SRC                      0x0BE1
+//#define GL_BLEND                          0x0BE2
+//#define GL_LOGIC_OP_MODE                  0x0BF0
+//#define GL_INDEX_LOGIC_OP                 0x0BF1
+//#define GL_COLOR_LOGIC_OP                 0x0BF2
+//#define GL_AUX_BUFFERS                    0x0C00
+//#define GL_DRAW_BUFFER                    0x0C01
+//#define GL_READ_BUFFER                    0x0C02
+//#define GL_SCISSOR_BOX                    0x0C10
+//#define GL_SCISSOR_TEST                   0x0C11
+//#define GL_INDEX_CLEAR_VALUE              0x0C20
+//#define GL_INDEX_WRITEMASK                0x0C21
+//#define GL_COLOR_CLEAR_VALUE              0x0C22
+//#define GL_COLOR_WRITEMASK                0x0C23
+//#define GL_INDEX_MODE                     0x0C30
+//#define GL_RGBA_MODE                      0x0C31
+//#define GL_DOUBLEBUFFER                   0x0C32
+//#define GL_STEREO                         0x0C33
+//#define GL_RENDER_MODE                    0x0C40
+//#define GL_PERSPECTIVE_CORRECTION_HINT    0x0C50
+//#define GL_POINT_SMOOTH_HINT              0x0C51
+//#define GL_LINE_SMOOTH_HINT               0x0C52
+//#define GL_POLYGON_SMOOTH_HINT            0x0C53
+//#define GL_FOG_HINT                       0x0C54
+#define GL_TEXTURE_GEN_S                  0x0C60
+#define GL_TEXTURE_GEN_T                  0x0C61
+//#define GL_TEXTURE_GEN_R                  0x0C62
+//#define GL_TEXTURE_GEN_Q                  0x0C63
+//#define GL_PIXEL_MAP_I_TO_I               0x0C70
+//#define GL_PIXEL_MAP_S_TO_S               0x0C71
+//#define GL_PIXEL_MAP_I_TO_R               0x0C72
+//#define GL_PIXEL_MAP_I_TO_G               0x0C73
+//#define GL_PIXEL_MAP_I_TO_B               0x0C74
+//#define GL_PIXEL_MAP_I_TO_A               0x0C75
+//#define GL_PIXEL_MAP_R_TO_R               0x0C76
+//#define GL_PIXEL_MAP_G_TO_G               0x0C77
+//#define GL_PIXEL_MAP_B_TO_B               0x0C78
+//#define GL_PIXEL_MAP_A_TO_A               0x0C79
+//#define GL_PIXEL_MAP_I_TO_I_SIZE          0x0CB0
+//#define GL_PIXEL_MAP_S_TO_S_SIZE          0x0CB1
+//#define GL_PIXEL_MAP_I_TO_R_SIZE          0x0CB2
+//#define GL_PIXEL_MAP_I_TO_G_SIZE          0x0CB3
+//#define GL_PIXEL_MAP_I_TO_B_SIZE          0x0CB4
+//#define GL_PIXEL_MAP_I_TO_A_SIZE          0x0CB5
+//#define GL_PIXEL_MAP_R_TO_R_SIZE          0x0CB6
+//#define GL_PIXEL_MAP_G_TO_G_SIZE          0x0CB7
+//#define GL_PIXEL_MAP_B_TO_B_SIZE          0x0CB8
+//#define GL_PIXEL_MAP_A_TO_A_SIZE          0x0CB9
+//#define GL_UNPACK_SWAP_BYTES              0x0CF0
+//#define GL_UNPACK_LSB_FIRST               0x0CF1
+//#define GL_UNPACK_ROW_LENGTH              0x0CF2
+//#define GL_UNPACK_SKIP_ROWS               0x0CF3
+//#define GL_UNPACK_SKIP_PIXELS             0x0CF4
+//#define GL_UNPACK_ALIGNMENT               0x0CF5
+//#define GL_PACK_SWAP_BYTES                0x0D00
+//#define GL_PACK_LSB_FIRST                 0x0D01
+//#define GL_PACK_ROW_LENGTH                0x0D02
+//#define GL_PACK_SKIP_ROWS                 0x0D03
+//#define GL_PACK_SKIP_PIXELS               0x0D04
+//#define GL_PACK_ALIGNMENT                 0x0D05
+//#define GL_MAP_COLOR                      0x0D10
+//#define GL_MAP_STENCIL                    0x0D11
+//#define GL_INDEX_SHIFT                    0x0D12
+//#define GL_INDEX_OFFSET                   0x0D13
+//#define GL_RED_SCALE                      0x0D14
+//#define GL_RED_BIAS                       0x0D15
+//#define GL_ZOOM_X                         0x0D16
+//#define GL_ZOOM_Y                         0x0D17
+//#define GL_GREEN_SCALE                    0x0D18
+//#define GL_GREEN_BIAS                     0x0D19
+//#define GL_BLUE_SCALE                     0x0D1A
+//#define GL_BLUE_BIAS                      0x0D1B
+//#define GL_ALPHA_SCALE                    0x0D1C
+//#define GL_ALPHA_BIAS                     0x0D1D
+//#define GL_DEPTH_SCALE                    0x0D1E
+//#define GL_DEPTH_BIAS                     0x0D1F
+//#define GL_MAX_EVAL_ORDER                 0x0D30
+//#define GL_MAX_LIGHTS                     0x0D31
+//#define GL_MAX_CLIP_PLANES                0x0D32
+//#define GL_MAX_TEXTURE_SIZE               0x0D33
+//#define GL_MAX_PIXEL_MAP_TABLE            0x0D34
+//#define GL_MAX_ATTRIB_STACK_DEPTH         0x0D35
+//#define GL_MAX_MODELVIEW_STACK_DEPTH      0x0D36
+//#define GL_MAX_NAME_STACK_DEPTH           0x0D37
+//#define GL_MAX_PROJECTION_STACK_DEPTH     0x0D38
+//#define GL_MAX_TEXTURE_STACK_DEPTH        0x0D39
+//#define GL_MAX_VIEWPORT_DIMS              0x0D3A
+//#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH  0x0D3B
+//#define GL_SUBPIXEL_BITS                  0x0D50
+//#define GL_INDEX_BITS                     0x0D51
+//#define GL_RED_BITS                       0x0D52
+//#define GL_GREEN_BITS                     0x0D53
+//#define GL_BLUE_BITS                      0x0D54
+//#define GL_ALPHA_BITS                     0x0D55
+//#define GL_DEPTH_BITS                     0x0D56
+//#define GL_STENCIL_BITS                   0x0D57
+//#define GL_ACCUM_RED_BITS                 0x0D58
+//#define GL_ACCUM_GREEN_BITS               0x0D59
+//#define GL_ACCUM_BLUE_BITS                0x0D5A
+//#define GL_ACCUM_ALPHA_BITS               0x0D5B
+//#define GL_NAME_STACK_DEPTH               0x0D70
+//#define GL_AUTO_NORMAL                    0x0D80
+//#define GL_MAP1_COLOR_4                   0x0D90
+//#define GL_MAP1_INDEX                     0x0D91
+//#define GL_MAP1_NORMAL                    0x0D92
+//#define GL_MAP1_TEXTURE_COORD_1           0x0D93
+//#define GL_MAP1_TEXTURE_COORD_2           0x0D94
+//#define GL_MAP1_TEXTURE_COORD_3           0x0D95
+//#define GL_MAP1_TEXTURE_COORD_4           0x0D96
+//#define GL_MAP1_VERTEX_3                  0x0D97
+//#define GL_MAP1_VERTEX_4                  0x0D98
+//#define GL_MAP2_COLOR_4                   0x0DB0
+//#define GL_MAP2_INDEX                     0x0DB1
+//#define GL_MAP2_NORMAL                    0x0DB2
+//#define GL_MAP2_TEXTURE_COORD_1           0x0DB3
+//#define GL_MAP2_TEXTURE_COORD_2           0x0DB4
+//#define GL_MAP2_TEXTURE_COORD_3           0x0DB5
+//#define GL_MAP2_TEXTURE_COORD_4           0x0DB6
+//#define GL_MAP2_VERTEX_3                  0x0DB7
+//#define GL_MAP2_VERTEX_4                  0x0DB8
+//#define GL_MAP1_GRID_DOMAIN               0x0DD0
+//#define GL_MAP1_GRID_SEGMENTS             0x0DD1
+//#define GL_MAP2_GRID_DOMAIN               0x0DD2
+//#define GL_MAP2_GRID_SEGMENTS             0x0DD3
+//#define GL_TEXTURE_1D                     0x0DE0
+//#define GL_TEXTURE_2D                     0x0DE1
+//#define GL_FEEDBACK_BUFFER_POINTER        0x0DF0
+//#define GL_FEEDBACK_BUFFER_SIZE           0x0DF1
+//#define GL_FEEDBACK_BUFFER_TYPE           0x0DF2
+//#define GL_SELECTION_BUFFER_POINTER       0x0DF3
+//#define GL_SELECTION_BUFFER_SIZE          0x0DF4
+///*      GL_TEXTURE_BINDING_1D */
+///*      GL_TEXTURE_BINDING_2D */
+///*      GL_VERTEX_ARRAY */
+///*      GL_NORMAL_ARRAY */
+///*      GL_COLOR_ARRAY */
+///*      GL_INDEX_ARRAY */
+///*      GL_TEXTURE_COORD_ARRAY */
+///*      GL_EDGE_FLAG_ARRAY */
+///*      GL_VERTEX_ARRAY_SIZE */
+///*      GL_VERTEX_ARRAY_TYPE */
+///*      GL_VERTEX_ARRAY_STRIDE */
+///*      GL_NORMAL_ARRAY_TYPE */
+///*      GL_NORMAL_ARRAY_STRIDE */
+///*      GL_COLOR_ARRAY_SIZE */
+///*      GL_COLOR_ARRAY_TYPE */
+///*      GL_COLOR_ARRAY_STRIDE */
+///*      GL_INDEX_ARRAY_TYPE */
+///*      GL_INDEX_ARRAY_STRIDE */
+///*      GL_TEXTURE_COORD_ARRAY_SIZE */
+///*      GL_TEXTURE_COORD_ARRAY_TYPE */
+///*      GL_TEXTURE_COORD_ARRAY_STRIDE */
+///*      GL_EDGE_FLAG_ARRAY_STRIDE */
+///*      GL_POLYGON_OFFSET_FACTOR */
+///*      GL_POLYGON_OFFSET_UNITS */
+//
+///* GetTextureParameter */
+///*      GL_TEXTURE_MAG_FILTER */
+///*      GL_TEXTURE_MIN_FILTER */
+///*      GL_TEXTURE_WRAP_S */
+///*      GL_TEXTURE_WRAP_T */
+//#define GL_TEXTURE_WIDTH                  0x1000
+//#define GL_TEXTURE_HEIGHT                 0x1001
+//#define GL_TEXTURE_INTERNAL_FORMAT        0x1003
+#define GL_TEXTURE_BORDER_COLOR           0x1004
+//#define GL_TEXTURE_BORDER                 0x1005
+///*      GL_TEXTURE_RED_SIZE */
+///*      GL_TEXTURE_GREEN_SIZE */
+///*      GL_TEXTURE_BLUE_SIZE */
+///*      GL_TEXTURE_ALPHA_SIZE */
+///*      GL_TEXTURE_LUMINANCE_SIZE */
+///*      GL_TEXTURE_INTENSITY_SIZE */
+///*      GL_TEXTURE_PRIORITY */
+///*      GL_TEXTURE_RESIDENT */
+//
+///* HintMode */
+//#define GL_DONT_CARE                      0x1100
+//#define GL_FASTEST                        0x1101
+//#define GL_NICEST                         0x1102
+//
+///* HintTarget */
+///*      GL_PERSPECTIVE_CORRECTION_HINT */
+///*      GL_POINT_SMOOTH_HINT */
+///*      GL_LINE_SMOOTH_HINT */
+///*      GL_POLYGON_SMOOTH_HINT */
+///*      GL_FOG_HINT */
+///*      GL_PHONG_HINT */
+//
+///* IndexPointerType */
+///*      GL_SHORT */
+///*      GL_INT */
+///*      GL_FLOAT */
+///*      GL_DOUBLE */
+//
+///* LightModelParameter */
+///*      GL_LIGHT_MODEL_AMBIENT */
+///*      GL_LIGHT_MODEL_LOCAL_VIEWER */
+///*      GL_LIGHT_MODEL_TWO_SIDE */
+//
+///* LightName */
+//#define GL_LIGHT0                         0x4000
+//#define GL_LIGHT1                         0x4001
+//#define GL_LIGHT2                         0x4002
+//#define GL_LIGHT3                         0x4003
+//#define GL_LIGHT4                         0x4004
+//#define GL_LIGHT5                         0x4005
+//#define GL_LIGHT6                         0x4006
+//#define GL_LIGHT7                         0x4007
+//
+///* LightParameter */
+//#define GL_AMBIENT                        0x1200
+//#define GL_DIFFUSE                        0x1201
+//#define GL_SPECULAR                       0x1202
+//#define GL_POSITION                       0x1203
+//#define GL_SPOT_DIRECTION                 0x1204
+//#define GL_SPOT_EXPONENT                  0x1205
+//#define GL_SPOT_CUTOFF                    0x1206
+//#define GL_CONSTANT_ATTENUATION           0x1207
+//#define GL_LINEAR_ATTENUATION             0x1208
+//#define GL_QUADRATIC_ATTENUATION          0x1209
+//
+///* InterleavedArrays */
+///*      GL_V2F */
+///*      GL_V3F */
+///*      GL_C4UB_V2F */
+///*      GL_C4UB_V3F */
+///*      GL_C3F_V3F */
+///*      GL_N3F_V3F */
+///*      GL_C4F_N3F_V3F */
+///*      GL_T2F_V3F */
+///*      GL_T4F_V4F */
+///*      GL_T2F_C4UB_V3F */
+///*      GL_T2F_C3F_V3F */
+///*      GL_T2F_N3F_V3F */
+///*      GL_T2F_C4F_N3F_V3F */
+///*      GL_T4F_C4F_N3F_V4F */
+//
+///* ListMode */
+//#define GL_COMPILE                        0x1300
+//#define GL_COMPILE_AND_EXECUTE            0x1301
+//
+///* ListNameType */
+///*      GL_BYTE */
+///*      GL_UNSIGNED_BYTE */
+///*      GL_SHORT */
+///*      GL_UNSIGNED_SHORT */
+///*      GL_INT */
+///*      GL_UNSIGNED_INT */
+///*      GL_FLOAT */
+///*      GL_2_BYTES */
+///*      GL_3_BYTES */
+///*      GL_4_BYTES */
+//
+///* LogicOp */
+//#define GL_CLEAR                          0x1500
+//#define GL_AND                            0x1501
+//#define GL_AND_REVERSE                    0x1502
+//#define GL_COPY                           0x1503
+//#define GL_AND_INVERTED                   0x1504
+//#define GL_NOOP                           0x1505
+//#define GL_XOR                            0x1506
+//#define GL_OR                             0x1507
+//#define GL_NOR                            0x1508
+//#define GL_EQUIV                          0x1509
+//#define GL_INVERT                         0x150A
+//#define GL_OR_REVERSE                     0x150B
+//#define GL_COPY_INVERTED                  0x150C
+//#define GL_OR_INVERTED                    0x150D
+//#define GL_NAND                           0x150E
+//#define GL_SET                            0x150F
+//
+///* MapTarget */
+///*      GL_MAP1_COLOR_4 */
+///*      GL_MAP1_INDEX */
+///*      GL_MAP1_NORMAL */
+///*      GL_MAP1_TEXTURE_COORD_1 */
+///*      GL_MAP1_TEXTURE_COORD_2 */
+///*      GL_MAP1_TEXTURE_COORD_3 */
+///*      GL_MAP1_TEXTURE_COORD_4 */
+///*      GL_MAP1_VERTEX_3 */
+///*      GL_MAP1_VERTEX_4 */
+///*      GL_MAP2_COLOR_4 */
+///*      GL_MAP2_INDEX */
+///*      GL_MAP2_NORMAL */
+///*      GL_MAP2_TEXTURE_COORD_1 */
+///*      GL_MAP2_TEXTURE_COORD_2 */
+///*      GL_MAP2_TEXTURE_COORD_3 */
+///*      GL_MAP2_TEXTURE_COORD_4 */
+///*      GL_MAP2_VERTEX_3 */
+///*      GL_MAP2_VERTEX_4 */
+//
+///* MaterialFace */
+///*      GL_FRONT */
+///*      GL_BACK */
+///*      GL_FRONT_AND_BACK */
+//
+///* MaterialParameter */
+//#define GL_EMISSION                       0x1600
+//#define GL_SHININESS                      0x1601
+//#define GL_AMBIENT_AND_DIFFUSE            0x1602
+//#define GL_COLOR_INDEXES                  0x1603
+///*      GL_AMBIENT */
+///*      GL_DIFFUSE */
+///*      GL_SPECULAR */
+//
+///* MatrixMode */
+//#define GL_MODELVIEW                      0x1700
+//#define GL_PROJECTION                     0x1701
+//#define GL_TEXTURE                        0x1702
+//
+///* MeshMode1 */
+///*      GL_POINT */
+///*      GL_LINE */
+//
+///* MeshMode2 */
+///*      GL_POINT */
+///*      GL_LINE */
+///*      GL_FILL */
+//
+///* NormalPointerType */
+///*      GL_BYTE */
+///*      GL_SHORT */
+///*      GL_INT */
+///*      GL_FLOAT */
+///*      GL_DOUBLE */
+//
+///* PixelCopyType */
+//#define GL_COLOR                          0x1800
+//#define GL_DEPTH                          0x1801
+//#define GL_STENCIL                        0x1802
+//
+///* PixelFormat */
+#define GL_COLOR_INDEX                    0x1900
+//#define GL_STENCIL_INDEX                  0x1901
+//#define GL_DEPTH_COMPONENT                0x1902
+//#define GL_RED                            0x1903
+//#define GL_GREEN                          0x1904
+//#define GL_BLUE                           0x1905
+//#define GL_ALPHA                          0x1906
+//#define GL_RGB                            0x1907
+//#define GL_RGBA                           0x1908
+//#define GL_LUMINANCE                      0x1909
+//#define GL_LUMINANCE_ALPHA                0x190A
+//#define GL_BGR					          0x80E0
+//#define GL_BGRA					          0x80E1
+//
+///* PixelMap */
+///*      GL_PIXEL_MAP_I_TO_I */
+///*      GL_PIXEL_MAP_S_TO_S */
+///*      GL_PIXEL_MAP_I_TO_R */
+///*      GL_PIXEL_MAP_I_TO_G */
+///*      GL_PIXEL_MAP_I_TO_B */
+///*      GL_PIXEL_MAP_I_TO_A */
+///*      GL_PIXEL_MAP_R_TO_R */
+///*      GL_PIXEL_MAP_G_TO_G */
+///*      GL_PIXEL_MAP_B_TO_B */
+///*      GL_PIXEL_MAP_A_TO_A */
+//
+///* PixelStore */
+///*      GL_UNPACK_SWAP_BYTES */
+///*      GL_UNPACK_LSB_FIRST */
+///*      GL_UNPACK_ROW_LENGTH */
+///*      GL_UNPACK_SKIP_ROWS */
+///*      GL_UNPACK_SKIP_PIXELS */
+///*      GL_UNPACK_ALIGNMENT */
+///*      GL_PACK_SWAP_BYTES */
+///*      GL_PACK_LSB_FIRST */
+///*      GL_PACK_ROW_LENGTH */
+///*      GL_PACK_SKIP_ROWS */
+///*      GL_PACK_SKIP_PIXELS */
+///*      GL_PACK_ALIGNMENT */
+//
+///* PixelTransfer */
+///*      GL_MAP_COLOR */
+///*      GL_MAP_STENCIL */
+///*      GL_INDEX_SHIFT */
+///*      GL_INDEX_OFFSET */
+///*      GL_RED_SCALE */
+///*      GL_RED_BIAS */
+///*      GL_GREEN_SCALE */
+///*      GL_GREEN_BIAS */
+///*      GL_BLUE_SCALE */
+///*      GL_BLUE_BIAS */
+///*      GL_ALPHA_SCALE */
+///*      GL_ALPHA_BIAS */
+///*      GL_DEPTH_SCALE */
+///*      GL_DEPTH_BIAS */
+//
+///* PixelType */
+//#define GL_BITMAP                         0x1A00
+///*      GL_BYTE */
+///*      GL_UNSIGNED_BYTE */
+///*      GL_SHORT */
+///*      GL_UNSIGNED_SHORT */
+///*      GL_INT */
+///*      GL_UNSIGNED_INT */
+///*      GL_FLOAT */
+//
+///* PolygonMode */
+//#define GL_POINT                          0x1B00
+#define GL_LINE                           0x1B01
+#define GL_FILL                           0x1B02
+//
+///* ReadBufferMode */
+///*      GL_FRONT_LEFT */
+///*      GL_FRONT_RIGHT */
+///*      GL_BACK_LEFT */
+///*      GL_BACK_RIGHT */
+///*      GL_FRONT */
+///*      GL_BACK */
+///*      GL_LEFT */
+///*      GL_RIGHT */
+///*      GL_AUX0 */
+///*      GL_AUX1 */
+///*      GL_AUX2 */
+///*      GL_AUX3 */
+//
+///* RenderingMode */
+//#define GL_RENDER                         0x1C00
+//#define GL_FEEDBACK                       0x1C01
+//#define GL_SELECT                         0x1C02
+//
+///* ShadingModel */
+//#define GL_FLAT                           0x1D00
+//#define GL_SMOOTH                         0x1D01
+//
+//
+///* StencilFunction */
+///*      GL_NEVER */
+///*      GL_LESS */
+///*      GL_EQUAL */
+///*      GL_LEQUAL */
+///*      GL_GREATER */
+///*      GL_NOTEQUAL */
+///*      GL_GEQUAL */
+///*      GL_ALWAYS */
+//
+///* StencilOp */
+///*      GL_ZERO */
+//#define GL_KEEP                           0x1E00
+//#define GL_REPLACE                        0x1E01
+//#define GL_INCR                           0x1E02
+//#define GL_DECR                           0x1E03
+///*      GL_INVERT */
+//
+///* StringName */
+//#define GL_VENDOR                         0x1F00
+//#define GL_RENDERER                       0x1F01
+//#define GL_VERSION                        0x1F02
+//#define GL_EXTENSIONS                     0x1F03
+//
+///* TextureCoordName */
+#define GL_S                              0x2000
+#define GL_T                              0x2001
+//#define GL_R                              0x2002
+//#define GL_Q                              0x2003
+//
+///* TexCoordPointerType */
+///*      GL_SHORT */
+///*      GL_INT */
+///*      GL_FLOAT */
+///*      GL_DOUBLE */
+//
+///* TextureEnvMode */
+//#define GL_MODULATE                       0x2100
+//#define GL_DECAL                          0x2101
+///*      GL_BLEND */
+///*      GL_REPLACE */
+//
+///* TextureEnvParameter */
+//#define GL_TEXTURE_ENV_MODE               0x2200
+//#define GL_TEXTURE_ENV_COLOR              0x2201
+//
+///* TextureEnvTarget */
+//#define GL_TEXTURE_ENV                    0x2300
+//
+///* TextureGenMode */
+//#define GL_EYE_LINEAR                     0x2400
+#define GL_OBJECT_LINEAR                  0x2401
+#define GL_SPHERE_MAP                     0x2402
+//
+///* TextureGenParameter */
+#define GL_TEXTURE_GEN_MODE               0x2500
+#define GL_OBJECT_PLANE                   0x2501
+//#define GL_EYE_PLANE                      0x2502
+//
+///* TextureMagFilter */
+//#define GL_NEAREST                        0x2600
+//#define GL_LINEAR                         0x2601
+//
+///* TextureMinFilter */
+///*      GL_NEAREST */
+///*      GL_LINEAR */
+//#define GL_NEAREST_MIPMAP_NEAREST         0x2700
+//#define GL_LINEAR_MIPMAP_NEAREST          0x2701
+//#define GL_NEAREST_MIPMAP_LINEAR          0x2702
+//#define GL_LINEAR_MIPMAP_LINEAR           0x2703
+//
+///* TextureParameterName */
+//#define GL_TEXTURE_MAG_FILTER             0x2800
+//#define GL_TEXTURE_MIN_FILTER             0x2801
+//#define GL_TEXTURE_WRAP_S                 0x2802
+//#define GL_TEXTURE_WRAP_T                 0x2803
+///*      GL_TEXTURE_BORDER_COLOR */
+///*      GL_TEXTURE_PRIORITY */
+//
+///* TextureTarget */
+///*      GL_TEXTURE_1D */
+///*      GL_TEXTURE_2D */
+///*      GL_PROXY_TEXTURE_1D */
+///*      GL_PROXY_TEXTURE_2D */
+//
+///* TextureWrapMode */
+#define GL_CLAMP                          0x2900
+//#define GL_REPEAT                         0x2901
+//
+//#define GL_TEXTURE0                       0x84C0
+//#define GL_TEXTURE1                       0x84C1
+//#define GL_TEXTURE2                       0x84C2
+//#define GL_TEXTURE3                       0x84C3
+//#define GL_TEXTURE4                       0x84C4
+//#define GL_TEXTURE5                       0x84C5
+//#define GL_TEXTURE6                       0x84C6
+//#define GL_TEXTURE7                       0x84C7
+//#define GL_TEXTURE8                       0x84C8
+//#define GL_TEXTURE9                       0x84C9
+//#define GL_TEXTURE10                      0x84CA
+//#define GL_TEXTURE11                      0x84CB
+//#define GL_TEXTURE12                      0x84CC
+//#define GL_TEXTURE13                      0x84CD
+//#define GL_TEXTURE14                      0x84CE
+//#define GL_TEXTURE15                      0x84CF
+//#define GL_TEXTURE16                      0x84D0
+//#define GL_TEXTURE17                      0x84D1
+//#define GL_TEXTURE18                      0x84D2
+//#define GL_TEXTURE19                      0x84D3
+//#define GL_TEXTURE20                      0x84D4
+//#define GL_TEXTURE21                      0x84D5
+//#define GL_TEXTURE22                      0x84D6
+//#define GL_TEXTURE23                      0x84D7
+//#define GL_TEXTURE24                      0x84D8
+//#define GL_TEXTURE25                      0x84D9
+//#define GL_TEXTURE26                      0x84DA
+//#define GL_TEXTURE27                      0x84DB
+//#define GL_TEXTURE28                      0x84DC
+//#define GL_TEXTURE29                      0x84DD
+//#define GL_TEXTURE30                      0x84DE
+//#define GL_TEXTURE31                      0x84DF
+//#define GL_ACTIVE_TEXTURE                 0x84E0
+//#define GL_CLIENT_ACTIVE_TEXTURE          0x84E1
+//#define GL_MAX_TEXTURE_UNITS              0x84E2
+//#define GL_TRANSPOSE_MODELVIEW_MATRIX     0x84E3
+//#define GL_TRANSPOSE_PROJECTION_MATRIX    0x84E4
+//#define GL_TRANSPOSE_TEXTURE_MATRIX       0x84E5
+//#define GL_TRANSPOSE_COLOR_MATRIX         0x84E6
+//#define GL_MULTISAMPLE                    0x809D
+//#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E
+//#define GL_SAMPLE_ALPHA_TO_ONE            0x809F
+//#define GL_SAMPLE_COVERAGE                0x80A0
+//#define GL_SAMPLE_BUFFERS                 0x80A8
+//#define GL_SAMPLES                        0x80A9
+//#define GL_SAMPLE_COVERAGE_VALUE          0x80AA
+//#define GL_SAMPLE_COVERAGE_INVERT         0x80AB
+//#define GL_MULTISAMPLE_BIT                0x20000000
+//#define GL_NORMAL_MAP                     0x8511
+//#define GL_REFLECTION_MAP                 0x8512
+//#define GL_TEXTURE_CUBE_MAP               0x8513
+//#define GL_TEXTURE_BINDING_CUBE_MAP       0x8514
+//#define GL_TEXTURE_CUBE_MAP_POSITIVE_X    0x8515
+//#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X    0x8516
+//#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y    0x8517
+//#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y    0x8518
+//#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z    0x8519
+//#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z    0x851A
+//#define GL_PROXY_TEXTURE_CUBE_MAP         0x851B
+//#define GL_MAX_CUBE_MAP_TEXTURE_SIZE      0x851C
+//#define GL_COMPRESSED_ALPHA               0x84E9
+//#define GL_COMPRESSED_LUMINANCE           0x84EA
+//#define GL_COMPRESSED_LUMINANCE_ALPHA     0x84EB
+//#define GL_COMPRESSED_INTENSITY           0x84EC
+//#define GL_COMPRESSED_RGB                 0x84ED
+//#define GL_COMPRESSED_RGBA                0x84EE
+//#define GL_TEXTURE_COMPRESSION_HINT       0x84EF
+//#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE  0x86A0
+//#define GL_TEXTURE_COMPRESSED             0x86A1
+//#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+//#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3
+//#define GL_CLAMP_TO_BORDER                0x812D
+//#define GL_COMBINE                        0x8570
+//#define GL_COMBINE_RGB                    0x8571
+//#define GL_COMBINE_ALPHA                  0x8572
+#define GL_SOURCE0_RGB                    0x8580
+#define GL_SOURCE1_RGB                    0x8581
+#define GL_SOURCE2_RGB                    0x8582
+#define GL_SOURCE0_ALPHA                  0x8588
+#define GL_SOURCE1_ALPHA                  0x8589
+#define GL_SOURCE2_ALPHA                  0x858A
+//#define GL_OPERAND0_RGB                   0x8590
+//#define GL_OPERAND1_RGB                   0x8591
+//#define GL_OPERAND2_RGB                   0x8592
+//#define GL_OPERAND0_ALPHA                 0x8598
+//#define GL_OPERAND1_ALPHA                 0x8599
+//#define GL_OPERAND2_ALPHA                 0x859A
+//#define GL_RGB_SCALE                      0x8573
+//#define GL_ADD_SIGNED                     0x8574
+//#define GL_INTERPOLATE                    0x8575
+//#define GL_SUBTRACT                       0x84E7
+//#define GL_CONSTANT                       0x8576
+//#define GL_PRIMARY_COLOR                  0x8577
+//#define GL_PREVIOUS                       0x8578
+//#define GL_DOT3_RGB                       0x86AE
+//#define GL_DOT3_RGBA                      0x86AF
+//
+///* VertexPointerType */
+///*      GL_SHORT */
+///*      GL_INT */
+///*      GL_FLOAT */
+///*      GL_DOUBLE */
+//
+///* ClientAttribMask */
+//#define GL_CLIENT_PIXEL_STORE_BIT         0x00000001
+//#define GL_CLIENT_VERTEX_ARRAY_BIT        0x00000002
+//#define GL_CLIENT_ALL_ATTRIB_BITS         0xffffffff
+//
+///* polygon_offset */
+//#define GL_POLYGON_OFFSET_FACTOR          0x8038
+//#define GL_POLYGON_OFFSET_UNITS           0x2A00
+//#define GL_POLYGON_OFFSET_POINT           0x2A01
+//#define GL_POLYGON_OFFSET_LINE            0x2A02
+//#define GL_POLYGON_OFFSET_FILL            0x8037
+//
+///* texture */
+//#define GL_ALPHA4                         0x803B
+//#define GL_ALPHA8                         0x803C
+//#define GL_ALPHA12                        0x803D
+//#define GL_ALPHA16                        0x803E
+//#define GL_LUMINANCE4                     0x803F
+//#define GL_LUMINANCE8                     0x8040
+//#define GL_LUMINANCE12                    0x8041
+//#define GL_LUMINANCE16                    0x8042
+//#define GL_LUMINANCE4_ALPHA4              0x8043
+//#define GL_LUMINANCE6_ALPHA2              0x8044
+//#define GL_LUMINANCE8_ALPHA8              0x8045
+//#define GL_LUMINANCE12_ALPHA4             0x8046
+//#define GL_LUMINANCE12_ALPHA12            0x8047
+//#define GL_LUMINANCE16_ALPHA16            0x8048
+#define GL_INTENSITY                      0x8049
+//#define GL_INTENSITY4                     0x804A
+//#define GL_INTENSITY8                     0x804B
+//#define GL_INTENSITY12                    0x804C
+//#define GL_INTENSITY16                    0x804D
+//#define GL_R3_G3_B2                       0x2A10
+//#define GL_RGB4                           0x804F
+#define GL_RGB5                           0x8050
+#define GL_RGB8                           0x8051
+//#define GL_RGB10                          0x8052
+//#define GL_RGB12                          0x8053
+//#define GL_RGB16                          0x8054
+//#define GL_RGBA2                          0x8055
+#define GL_RGBA4                          0x8056
+#define GL_RGB5_A1                        0x8057
+#define GL_RGBA8                          0x8058
+//#define GL_RGB10_A2                       0x8059
+//#define GL_RGBA12                         0x805A
+//#define GL_RGBA16                         0x805B
+//#define GL_TEXTURE_RED_SIZE               0x805C
+//#define GL_TEXTURE_GREEN_SIZE             0x805D
+//#define GL_TEXTURE_BLUE_SIZE              0x805E
+//#define GL_TEXTURE_ALPHA_SIZE             0x805F
+//#define GL_TEXTURE_LUMINANCE_SIZE         0x8060
+//#define GL_TEXTURE_INTENSITY_SIZE         0x8061
+//#define GL_PROXY_TEXTURE_1D               0x8063
+//#define GL_PROXY_TEXTURE_2D               0x8064
+//
+///* texture_object */
+//#define GL_TEXTURE_PRIORITY               0x8066
+//#define GL_TEXTURE_RESIDENT               0x8067
+//#define GL_TEXTURE_BINDING_1D             0x8068
+//#define GL_TEXTURE_BINDING_2D             0x8069
+//
+///* vertex_array */
+//#define GL_VERTEX_ARRAY                   0x8074
+//#define GL_NORMAL_ARRAY                   0x8075
+//#define GL_COLOR_ARRAY                    0x8076
+//#define GL_INDEX_ARRAY                    0x8077
+//#define GL_TEXTURE_COORD_ARRAY            0x8078
+//#define GL_EDGE_FLAG_ARRAY                0x8079
+//#define GL_VERTEX_ARRAY_SIZE              0x807A
+//#define GL_VERTEX_ARRAY_TYPE              0x807B
+//#define GL_VERTEX_ARRAY_STRIDE            0x807C
+//#define GL_NORMAL_ARRAY_TYPE              0x807E
+//#define GL_NORMAL_ARRAY_STRIDE            0x807F
+//#define GL_COLOR_ARRAY_SIZE               0x8081
+//#define GL_COLOR_ARRAY_TYPE               0x8082
+//#define GL_COLOR_ARRAY_STRIDE             0x8083
+//#define GL_INDEX_ARRAY_TYPE               0x8085
+//#define GL_INDEX_ARRAY_STRIDE             0x8086
+//#define GL_TEXTURE_COORD_ARRAY_SIZE       0x8088
+//#define GL_TEXTURE_COORD_ARRAY_TYPE       0x8089
+//#define GL_TEXTURE_COORD_ARRAY_STRIDE     0x808A
+//#define GL_EDGE_FLAG_ARRAY_STRIDE         0x808C
+//#define GL_VERTEX_ARRAY_POINTER           0x808E
+//#define GL_NORMAL_ARRAY_POINTER           0x808F
+//#define GL_COLOR_ARRAY_POINTER            0x8090
+//#define GL_INDEX_ARRAY_POINTER            0x8091
+//#define GL_TEXTURE_COORD_ARRAY_POINTER    0x8092
+//#define GL_EDGE_FLAG_ARRAY_POINTER        0x8093
+//#define GL_V2F                            0x2A20
+//#define GL_V3F                            0x2A21
+//#define GL_C4UB_V2F                       0x2A22
+//#define GL_C4UB_V3F                       0x2A23
+//#define GL_C3F_V3F                        0x2A24
+//#define GL_N3F_V3F                        0x2A25
+//#define GL_C4F_N3F_V3F                    0x2A26
+//#define GL_T2F_V3F                        0x2A27
+//#define GL_T4F_V4F                        0x2A28
+//#define GL_T2F_C4UB_V3F                   0x2A29
+//#define GL_T2F_C3F_V3F                    0x2A2A
+//#define GL_T2F_N3F_V3F                    0x2A2B
+//#define GL_T2F_C4F_N3F_V3F                0x2A2C
+//#define GL_T4F_C4F_N3F_V4F                0x2A2D
+//
+///* Extensions */
+//#define GL_EXT_vertex_array               1
+//#define GL_EXT_bgra                       1
+//#define GL_EXT_paletted_texture           1
+//#define GL_WIN_swap_hint                  1
+//#define GL_WIN_draw_range_elements        1
+//// #define GL_WIN_phong_shading              1
+//// #define GL_WIN_specular_fog               1
+//
+///* EXT_vertex_array */
+//#define GL_VERTEX_ARRAY_EXT               0x8074
+//#define GL_NORMAL_ARRAY_EXT               0x8075
+//#define GL_COLOR_ARRAY_EXT                0x8076
+//#define GL_INDEX_ARRAY_EXT                0x8077
+//#define GL_TEXTURE_COORD_ARRAY_EXT        0x8078
+//#define GL_EDGE_FLAG_ARRAY_EXT            0x8079
+//#define GL_VERTEX_ARRAY_SIZE_EXT          0x807A
+//#define GL_VERTEX_ARRAY_TYPE_EXT          0x807B
+//#define GL_VERTEX_ARRAY_STRIDE_EXT        0x807C
+//#define GL_VERTEX_ARRAY_COUNT_EXT         0x807D
+//#define GL_NORMAL_ARRAY_TYPE_EXT          0x807E
+//#define GL_NORMAL_ARRAY_STRIDE_EXT        0x807F
+//#define GL_NORMAL_ARRAY_COUNT_EXT         0x8080
+//#define GL_COLOR_ARRAY_SIZE_EXT           0x8081
+//#define GL_COLOR_ARRAY_TYPE_EXT           0x8082
+//#define GL_COLOR_ARRAY_STRIDE_EXT         0x8083
+//#define GL_COLOR_ARRAY_COUNT_EXT          0x8084
+//#define GL_INDEX_ARRAY_TYPE_EXT           0x8085
+//#define GL_INDEX_ARRAY_STRIDE_EXT         0x8086
+//#define GL_INDEX_ARRAY_COUNT_EXT          0x8087
+//#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT   0x8088
+//#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT   0x8089
+//#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A
+//#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT  0x808B
+//#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT     0x808C
+//#define GL_EDGE_FLAG_ARRAY_COUNT_EXT      0x808D
+//#define GL_VERTEX_ARRAY_POINTER_EXT       0x808E
+//#define GL_NORMAL_ARRAY_POINTER_EXT       0x808F
+//#define GL_COLOR_ARRAY_POINTER_EXT        0x8090
+//#define GL_INDEX_ARRAY_POINTER_EXT        0x8091
+//#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092
+//#define GL_EDGE_FLAG_ARRAY_POINTER_EXT    0x8093
+//#define GL_DOUBLE_EXT                     GL_DOUBLE
+//
+///* EXT_bgra */
+//#define GL_BGR_EXT                        0x80E0
+#define GL_BGRA_EXT                       0x80E1
+//
+///* Extensions */
+//#define GL_EXT_abgr                       1
+//#define GL_EXT_blend_color                1
+//#define GL_EXT_blend_minmax               1
+//#define GL_EXT_blend_subtract             1
+//
+///* EXT_abgr */
+//#define GL_ABGR_EXT                       0x8000
+//
+///* EXT_blend_color */
+#define GL_CONSTANT_COLOR_EXT             0x8001
+//#define GL_ONE_MINUS_CONSTANT_COLOR_EXT   0x8002
+//#define GL_CONSTANT_ALPHA_EXT             0x8003
+//#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT   0x8004
+#define GL_BLEND_COLOR_EXT                0x8005
+//
+///* EXT_blend_minmax */
+#define GL_FUNC_ADD_EXT                   0x8006
+//#define GL_MIN_EXT                        0x8007
+//#define GL_MAX_EXT                        0x8008
+//#define GL_BLEND_EQUATION_EXT             0x8009
+//
+///* EXT_blend_subtract */
+//#define GL_FUNC_SUBTRACT_EXT              0x800A
+//#define GL_FUNC_REVERSE_SUBTRACT_EXT      0x800B
+//
+///* EXT_paletted_texture */
+//
+///* These must match the GL_COLOR_TABLE_*_SGI enumerants */
+//#define GL_COLOR_TABLE_FORMAT_EXT         0x80D8
+//#define GL_COLOR_TABLE_WIDTH_EXT          0x80D9
+//#define GL_COLOR_TABLE_RED_SIZE_EXT       0x80DA
+//#define GL_COLOR_TABLE_GREEN_SIZE_EXT     0x80DB
+//#define GL_COLOR_TABLE_BLUE_SIZE_EXT      0x80DC
+//#define GL_COLOR_TABLE_ALPHA_SIZE_EXT     0x80DD
+//#define GL_COLOR_TABLE_LUMINANCE_SIZE_EXT 0x80DE
+//#define GL_COLOR_TABLE_INTENSITY_SIZE_EXT 0x80DF
+//
+//#define GL_COLOR_INDEX1_EXT               0x80E2
+//#define GL_COLOR_INDEX2_EXT               0x80E3
+//#define GL_COLOR_INDEX4_EXT               0x80E4
+#define GL_COLOR_INDEX8_EXT               0x80E5
+//#define GL_COLOR_INDEX12_EXT              0x80E6
+//#define GL_COLOR_INDEX16_EXT              0x80E7
+//
+///* WIN_draw_range_elements */
+//#define GL_MAX_ELEMENTS_VERTICES_WIN      0x80E8
+//#define GL_MAX_ELEMENTS_INDICES_WIN       0x80E9
+//
+///* WIN_phong_shading */
+//#define GL_PHONG_WIN                      0x80EA 
+//#define GL_PHONG_HINT_WIN                 0x80EB 
+//
+///* WIN_specular_fog */
+//#define GL_FOG_SPECULAR_TEXTURE_WIN       0x80EC
+//
+///* For compatibility with OpenGL v1.0 */
+//#define GL_LOGIC_OP GL_INDEX_LOGIC_OP
+//#define GL_TEXTURE_COMPONENTS GL_TEXTURE_INTERNAL_FORMAT
+//
+//// Pi
+//#ifndef M_PI
+//#define M_PI 3.1415926f
+//#endif 
+//
+//#ifndef EGL_FALSE
+//#define EGL_FALSE                      0
+//#endif
+//
+//#ifndef EGL_TRUE
+//#define EGL_TRUE                       1
+//#endif
+//
+//#define EGL_DRAW                       0x3059
+//#define EGL_READ                       0x305A
+//
+//typedef void *	EGLDisplay;
+//typedef void *	EGLConfig;
+//typedef void *	EGLSurface;
+//typedef void *	EGLContext;
+//
+//typedef int				EGLBoolean;
+//typedef unsigned int	EGLint;
+//
+//
+//#define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0)
+//#define EGL_NO_CONTEXT ((EGLContext)0)
+//#define EGL_NO_DISPLAY ((EGLDisplay)0)
+//#define EGL_NO_SURFACE ((EGLSurface)0)
+//
+//typedef void*		NativeDisplayType;
+//typedef void*		NativeWindowType;
+//typedef void*		NativePixmapType;
+
+#define GL_TEXTURE0_ARB                   0x84C0
+#define GL_TEXTURE1_ARB                   0x84C1
+#define GL_TEXTURE2_ARB                   0x84C2
+#define GL_TEXTURE3_ARB                   0x84C3
+//#define GL_TEXTURE4_ARB                   0x84C4
+//#define GL_TEXTURE5_ARB                   0x84C5
+//#define GL_TEXTURE6_ARB                   0x84C6
+//#define GL_TEXTURE7_ARB                   0x84C7
+//#define GL_TEXTURE8_ARB                   0x84C8
+//#define GL_TEXTURE9_ARB                   0x84C9
+//#define GL_TEXTURE10_ARB                  0x84CA
+//#define GL_TEXTURE11_ARB                  0x84CB
+//#define GL_TEXTURE12_ARB                  0x84CC
+//#define GL_TEXTURE13_ARB                  0x84CD
+//#define GL_TEXTURE14_ARB                  0x84CE
+//#define GL_TEXTURE15_ARB                  0x84CF
+//#define GL_TEXTURE16_ARB                  0x84D0
+//#define GL_TEXTURE17_ARB                  0x84D1
+//#define GL_TEXTURE18_ARB                  0x84D2
+//#define GL_TEXTURE19_ARB                  0x84D3
+//#define GL_TEXTURE20_ARB                  0x84D4
+//#define GL_TEXTURE21_ARB                  0x84D5
+//#define GL_TEXTURE22_ARB                  0x84D6
+//#define GL_TEXTURE23_ARB                  0x84D7
+//#define GL_TEXTURE24_ARB                  0x84D8
+//#define GL_TEXTURE25_ARB                  0x84D9
+//#define GL_TEXTURE26_ARB                  0x84DA
+//#define GL_TEXTURE27_ARB                  0x84DB
+//#define GL_TEXTURE28_ARB                  0x84DC
+//#define GL_TEXTURE29_ARB                  0x84DD
+//#define GL_TEXTURE30_ARB                  0x84DE
+//#define GL_TEXTURE31_ARB                  0x84DF
+//#define GL_ACTIVE_TEXTURE_ARB             0x84E0
+//#define GL_CLIENT_ACTIVE_TEXTURE_ARB      0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB          0x84E2
+//
+//#define GL_COMPRESSED_ALPHA_ARB 0x84E9
+//#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA
+//#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
+//#define GL_COMPRESSED_INTENSITY_ARB 0x84EC
+#define GL_COMPRESSED_RGB_ARB 0x84ED
+#define GL_COMPRESSED_RGBA_ARB 0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF
+//#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
+//#define GL_TEXTURE_COMPRESSED_ARB 0x86A1
+//#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
+//#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
+#ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#endif
+//
+
+// ------------------------------------------------------------------------------------------------------
+//  Only function prototypes that were actually used in TGE are
+//    listed here
+// ------------------------------------------------------------------------------------------------------
+	
+	
+	// straightforward conversions
+#define glColor3f(r,g,b) glColor4f(r,g,b,1)
+#define GLdouble F64
+#define glOrtho( left, right, bottom, top, near, far ) glOrthof( left, right, bottom, top, near, far )
+#define glFrustum( left, right, bottom, top, near, far ) glFrustumf( left, right, bottom, top, near, far )
+#define glDepthRange( near, far ) glDepthRangef( near, far )
+
+// functions that need workarounds
+void glBegin( GLint );
+void glEnd();
+
+void glTexCoord2f( GLfloat, GLfloat );
+void glActiveTextureARB( GLint );
+void glMultiTexCoord2fARB( GLint, GLfloat, GLfloat);
+void glPushAttrib( GLint );
+void glPopAttrib();
+void glReadBuffer( GLint );
+void glVertex3f( GLfloat, GLfloat, GLfloat );
+void glVertex2f( GLfloat, GLfloat );
+void glVertex2i( GLint, GLint );
+void glClientActiveTextureARB( GLint );
+void glVertex3fv( const F32 * );
+void glVertex2fv( const F32 * );
+void glNormal3fv( const F32 * );
+void glColor3fv( const F32 * );
+void glColor4fv( const F32 * );
+void glColor3i( GLint, GLint, GLint );
+void glColor3ubv( const GLubyte *v );
+void glColor4ubv( const GLubyte *v );
+void glRecti( GLint, GLint, GLint, GLint );
+void glGetDoublev( GLint, GLdouble * );
+void glPolygonMode( GLint, GLint );
+void glLockArraysEXT( GLint, GLint );
+void glUnlockArraysEXT();
+void glColor3ub( GLint, GLint, GLint );
+void glFogi( GLint, GLint );
+
+void glColorTableEXT( GLint, GLint, GLint, GLint, GLint, const ColorI * );
+void glBlendColorEXT( GLfloat, GLfloat, GLfloat, GLfloat );
+void glBlendEquationEXT( GLint );
+void glArrayElement( GLint );
+void glFogCoordPointerEXT(GLenum, GLsizei, void *);
+void glTexGeni( GLenum coord, GLenum pname, GLint param );
+void glTexGenfv( GLenum coord, GLenum pname, const GLfloat *params );
+void glClipPlane( GLuint plane, GLdouble * equation );
+GLboolean glAreTexturesResident( GLsizei, const GLuint *, GLboolean*);
+
+void gluOrtho2D( GLfloat, GLfloat, GLfloat, GLfloat );
+GLint gluProject( GLdouble winx, GLdouble winy, GLdouble winz, const F64 *model, const F64 * proj, const GLint * vp, F64 * x, F64 * y, F64 * z );
+GLint gluUnProject( GLdouble winx, GLdouble winy, GLdouble winz, const F64 *model, const F64 * proj, const GLint * vp, F64 * x, F64 * y, F64 * z );
+
+
+#endif //_GL2ES_H_

+ 332 - 0
engine/source/platformEmscripten/EmscriptenInput.cpp

@@ -0,0 +1,332 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platform/platformInput.h"
+#include "platform/platformVideo.h"
+#include "platform/event.h"
+#include "game/gameInterface.h"
+#include "console/console.h"
+#include "platformEmscripten/EmscriptenInputManager.h"
+
+#include <SDL/SDL.h>
+
+#ifdef LOG_INPUT
+#include <time.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#endif
+
+// Static class variables:
+InputManager*  Input::smManager = NULL;
+
+// smActive is not maintained under unix.  Use Input::isActive()
+// instead
+bool           Input::smActive = false;
+CursorManager* Input::smCursorManager = 0;
+
+//extern AsciiData AsciiTable[NUM_KEYS];
+
+#ifdef LOG_INPUT
+S32 gInputLog = -1;
+#endif 
+
+//------------------------------------------------------------------------------
+void Input::init()
+{
+   Con::printf( "Input Init:" );
+
+   destroy();
+
+   smActive = false;
+   smManager = NULL;
+
+   UInputManager *uInputManager = new UInputManager;
+   if ( !uInputManager->enable() )
+   {
+      Con::errorf( "   Failed to enable Input Manager." );
+      delete uInputManager;
+      return;
+   }
+
+   uInputManager->init();
+
+   smManager = uInputManager;
+
+   Con::printf("   Input initialized");
+   Con::printf(" ");
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( isJoystickDetected, bool, 1, 1, "isJoystickDetected()" )
+{
+   argc; argv;
+   UInputManager* manager = dynamic_cast<UInputManager*>(Input::getManager());
+   if (manager)
+      return manager->joystickDetected();
+   else
+      return false;
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( getJoystickAxes, const char*, 2, 2, "getJoystickAxes( instance )" )
+{
+   argc; argv;
+   UInputManager* manager = dynamic_cast<UInputManager*>(Input::getManager());
+   if (manager)
+      return manager->getJoystickAxesString(dAtoi(argv[1]));
+   else
+      return "";
+}
+
+//------------------------------------------------------------------------------
+U16 Input::getKeyCode( U16 asciiCode )
+{
+   U16 keyCode = 0;
+   U16 i;
+   
+   // This is done three times so the lowerkey will always
+   // be found first. Some foreign keyboards have duplicate
+   // chars on some keys.
+   for ( i = KEY_FIRST; i < NUM_KEYS && !keyCode; i++ )
+   {
+      if ( AsciiTable[i].lower.ascii == asciiCode )
+      {
+         keyCode = i;
+         break;
+      };
+   }
+
+   for ( i = KEY_FIRST; i < NUM_KEYS && !keyCode; i++ )
+   {
+      if ( AsciiTable[i].upper.ascii == asciiCode )
+      {
+         keyCode = i;
+         break;
+      };
+   }
+
+   for ( i = KEY_FIRST; i < NUM_KEYS && !keyCode; i++ )
+   {
+      if ( AsciiTable[i].goofy.ascii == asciiCode )
+      {
+         keyCode = i;
+         break;
+      };
+   }
+
+   return( keyCode );
+}
+
+//-----------------------------------------------------------------------------
+U16 Input::getAscii( U16 keyCode, KEY_STATE keyState )
+{
+   if ( keyCode >= NUM_KEYS )
+      return 0;
+
+   switch ( keyState )
+   {
+      case STATE_LOWER:
+         return AsciiTable[keyCode].lower.ascii;
+      case STATE_UPPER:
+         return AsciiTable[keyCode].upper.ascii;
+      case STATE_GOOFY:
+         return AsciiTable[keyCode].goofy.ascii;
+      default:
+         return(0);
+            
+   }
+}
+
+//------------------------------------------------------------------------------
+void Input::destroy()
+{
+   if ( smManager && smManager->isEnabled() )
+   {
+      smManager->disable();
+      delete smManager;
+      smManager = NULL;
+   }
+}
+
+//------------------------------------------------------------------------------
+bool Input::enable()
+{   
+   if ( smManager && !smManager->isEnabled() )
+      return( smManager->enable() );
+   
+   return( false );
+}
+
+//------------------------------------------------------------------------------
+void Input::disable()
+{
+   if ( smManager && smManager->isEnabled() )
+      smManager->disable();
+}
+
+//------------------------------------------------------------------------------
+void Input::activate()
+{
+   if ( smManager && smManager->isEnabled() && !isActive())
+   {
+#ifdef LOG_INPUT
+      Input::log( "Activating Input...\n" );
+#endif
+      UInputManager* uInputManager = dynamic_cast<UInputManager*>( smManager );
+      if ( uInputManager )
+         uInputManager->activate();
+   }
+}
+
+//------------------------------------------------------------------------------
+void Input::deactivate()
+{
+   if ( smManager && smManager->isEnabled() && isActive() )
+   {
+#ifdef LOG_INPUT
+      Input::log( "Deactivating Input...\n" );
+#endif
+      UInputManager* uInputManager = dynamic_cast<UInputManager*>( smManager );
+      if ( uInputManager )
+         uInputManager->deactivate();
+   }
+}
+
+//------------------------------------------------------------------------------
+void Input::reactivate()
+{
+   Input::deactivate();
+   Input::activate();
+}
+
+//------------------------------------------------------------------------------
+bool Input::isEnabled()
+{
+   if ( smManager )
+      return smManager->isEnabled();
+   return false;
+}
+
+//------------------------------------------------------------------------------
+bool Input::isActive()
+{
+   UInputManager* uInputManager = dynamic_cast<UInputManager*>( smManager );
+   if ( uInputManager )
+      return uInputManager->isActive();
+   return false;
+}
+
+//------------------------------------------------------------------------------
+void Input::process()
+{
+   if ( smManager )
+      smManager->process();
+}
+
+//------------------------------------------------------------------------------
+InputManager* Input::getManager()
+{
+   return smManager;
+}
+
+#ifdef LOG_INPUT
+//------------------------------------------------------------------------------
+void Input::log( const char* format, ... )
+{
+}
+
+ConsoleFunction( inputLog, void, 2, 2, "inputLog( string )" )
+{
+   argc;
+   Input::log( "%s\n", argv[1] );
+}
+#endif // LOG_INPUT
+
+//------------------------------------------------------------------------------
+const char* Platform::getClipboard()
+{
+   return "";
+}
+
+//------------------------------------------------------------------------------
+bool Platform::setClipboard(const char *text)
+{
+   return false;
+}
+
+#pragma mark ---- Cursor Functions ----
+//------------------------------------------------------------------------------
+void Input::pushCursor(S32 cursorID)
+{
+   CursorManager* cm = getCursorManager();
+   if(cm)
+      cm->pushCursor(cursorID);
+}
+
+//------------------------------------------------------------------------------
+void Input::popCursor()
+{
+   CursorManager* cm = getCursorManager();
+   if(cm)
+      cm->popCursor();
+}
+
+//------------------------------------------------------------------------------
+void Input::refreshCursor()
+{
+   CursorManager* cm = getCursorManager();
+   if(cm)
+      cm->refreshCursor();
+}
+
+#pragma mark ---- DoubleClick Functions ----
+//------------------------------------------------------------------------------
+U32 Input::getDoubleClickTime()
+{
+   return ( 50 * 60.0f * 1000.0f);
+}
+
+//------------------------------------------------------------------------------
+S32 Input::getDoubleClickWidth()
+{
+   // this is an arbitrary value.
+   return 10;
+}
+
+//------------------------------------------------------------------------------
+S32 Input::getDoubleClickHeight()
+{
+   return getDoubleClickWidth();
+}
+
+#pragma mark -
+
+//------------------------------------------------------------------------------
+void Input::setCursorPos(S32 x, S32 y)
+{
+   SDL_WarpMouse((S16)x, (S16)y);
+}
+

+ 1828 - 0
engine/source/platformEmscripten/EmscriptenInputManager.cpp

@@ -0,0 +1,1828 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "console/consoleTypes.h"
+#include "platform/event.h"
+#include "game/gameInterface.h"
+#include "platformEmscripten/EmscriptenInputManager.h"
+#include "math/mMathFn.h"
+
+#include <SDL/SDL.h>
+
+// ascii table
+AsciiData AsciiTable[NUM_KEYS];
+
+// keymap table
+static const U32 SDLtoTKeyMapSize = SDLK_LAST;
+static U8 SDLtoTKeyMap[SDLtoTKeyMapSize];
+static bool keyMapsInitialized = false;
+
+// helper functions
+static void MapKey(Uint16 SDLkey, U8 tkey);
+static void InitKeyMaps();
+static inline U8 TranslateSDLKeytoTKey(SDLKey keysym);
+
+// constants
+
+static const U32 MouseMask = SDL_MOUSEMOTION | SDL_MOUSEBUTTONUP;//SDL_MOUSEEVENTMASK;
+static const U32 KeyboardMask = SDL_KEYUP;//SDL_KEYUPMASK | SDL_KEYDOWNMASK;
+static const U32 JoystickMask = SDL_JOYAXISMOTION | SDL_JOYBUTTONUP;//SDL_JOYEVENTMASK;
+
+static const U32 AllInputEvents = MouseMask | KeyboardMask | JoystickMask;
+
+// defined in SDL
+extern "C" Uint16 X11_KeyToUnicode( SDLKey keysym, SDLMod modifiers );
+
+//==============================================================================
+// Static helper functions
+//==============================================================================
+static void MapKey(Uint16 SDLkey, U8 tkey)
+{
+   SDLtoTKeyMap[SDLkey] = tkey;
+
+   AsciiTable[tkey].lower.ascii = SDLkey;
+   AsciiTable[tkey].upper.ascii = SDLkey;
+   AsciiTable[tkey].goofy.ascii = SDLkey;
+
+   switch (tkey)
+   {
+      case KEY_0:
+         AsciiTable[tkey].upper.ascii = (U16)')';
+         break;
+      case KEY_1:
+         AsciiTable[tkey].upper.ascii = (U16)'!';
+         break;
+      case KEY_2:
+         AsciiTable[tkey].upper.ascii = (U16)'@';
+         break;
+      case KEY_3:
+         AsciiTable[tkey].upper.ascii = 163;
+         break;
+      case KEY_4:
+         AsciiTable[tkey].upper.ascii = (U16)'$';
+         break;
+      case KEY_5:
+         AsciiTable[tkey].upper.ascii = (U16)'%';
+         break;
+      case KEY_6:
+         AsciiTable[tkey].upper.ascii = (U16)'^';
+         break;
+      case KEY_7:
+         AsciiTable[tkey].upper.ascii = (U16)'&';
+         break;
+      case KEY_8:
+         AsciiTable[tkey].upper.ascii = (U16)'*';
+         break;
+      case KEY_9:
+         AsciiTable[tkey].upper.ascii = (U16)'(';
+         break;
+      case KEY_MINUS:
+         AsciiTable[tkey].upper.ascii = (U16)'_';
+         break;
+      case KEY_EQUALS:
+         AsciiTable[tkey].upper.ascii = (U16)'+';
+         break;
+      case KEY_TILDE:
+         AsciiTable[tkey].upper.ascii = (U16)126;
+         break;
+      case KEY_SEMICOLON:
+         AsciiTable[tkey].upper.ascii = ':';
+         break;
+      case KEY_APOSTROPHE:
+         AsciiTable[tkey].upper.ascii = '"';
+         break;
+      case KEY_BACKSLASH:
+         AsciiTable[tkey].upper.ascii = '|';
+         break;
+      case KEY_LBRACKET:
+         AsciiTable[tkey].upper.ascii = '{';
+         break;
+      case KEY_RBRACKET:
+         AsciiTable[tkey].upper.ascii = '}';
+         break;
+      case KEY_COMMA:
+         AsciiTable[tkey].upper.ascii = '<';
+         break;
+      case KEY_PERIOD:
+         AsciiTable[tkey].upper.ascii = '>';
+         break;
+   }
+}
+
+//------------------------------------------------------------------------------
+void InitKeyMaps()
+{
+   Con::printf("InitKeyMaps size == %i, ASCIITABLE SIZE == %i", SDLtoTKeyMapSize, NUM_KEYS);
+
+   dMemset( &AsciiTable, 0, sizeof( AsciiTable ) );
+   dMemset(SDLtoTKeyMap, KEY_NULL, sizeof( SDLtoTKeyMap ));
+   
+   // set up the X to Torque key map
+   // stuff
+   MapKey(SDLK_BACKSPACE, KEY_BACKSPACE);
+   MapKey(SDLK_TAB, KEY_TAB);
+   MapKey(SDLK_RETURN, KEY_RETURN);
+   MapKey(SDLK_PAUSE, KEY_PAUSE);
+   MapKey(SDLK_CAPSLOCK, KEY_CAPSLOCK);
+   MapKey(SDLK_ESCAPE, KEY_ESCAPE);
+
+   // more stuff
+   MapKey(SDLK_SPACE, KEY_SPACE);
+   MapKey(SDLK_PAGEDOWN, KEY_PAGE_DOWN);
+   MapKey(SDLK_PAGEUP, KEY_PAGE_UP);
+   MapKey(SDLK_END, KEY_END);
+   MapKey(SDLK_HOME, KEY_HOME);
+   MapKey(SDLK_LEFT, KEY_LEFT);
+   MapKey(SDLK_UP, KEY_UP);
+   MapKey(SDLK_RIGHT, KEY_RIGHT);
+   MapKey(SDLK_DOWN, KEY_DOWN);
+   MapKey(SDLK_PRINT, KEY_PRINT);
+   MapKey(SDLK_INSERT, KEY_INSERT);
+   MapKey(SDLK_DELETE, KEY_DELETE);
+   
+   S32 keysym;
+   S32 tkeycode;
+   // main numeric keys
+   for (keysym = SDLK_0, tkeycode = KEY_0;
+        keysym <= SDLK_9; 
+        ++keysym, ++tkeycode)
+      MapKey(static_cast<SDLKey>(keysym), tkeycode);
+   
+   // lowercase letters
+   for (keysym = SDLK_a, tkeycode = KEY_A; 
+        keysym <= SDLK_z; 
+        ++keysym, ++tkeycode)
+      MapKey(static_cast<SDLKey>(keysym), tkeycode);
+
+   // various punctuation
+   MapKey('|', KEY_TILDE);
+   MapKey(SDLK_BACKQUOTE, KEY_TILDE);
+   MapKey(SDLK_MINUS, KEY_MINUS);
+   MapKey(SDLK_EQUALS, KEY_EQUALS);
+   MapKey(SDLK_LEFTBRACKET, KEY_LBRACKET);
+   MapKey('{', KEY_LBRACKET);
+   MapKey(SDLK_RIGHTBRACKET, KEY_RBRACKET);
+   MapKey('}', KEY_RBRACKET);
+   MapKey(SDLK_BACKSLASH, KEY_BACKSLASH);
+   MapKey(SDLK_SEMICOLON, KEY_SEMICOLON);
+   MapKey(SDLK_QUOTE, KEY_APOSTROPHE);
+   MapKey(SDLK_COMMA, KEY_COMMA);
+   MapKey(SDLK_PERIOD, KEY_PERIOD);
+   MapKey(SDLK_SLASH, KEY_SLASH); 
+
+   // numpad numbers
+   for (keysym = SDLK_KP0, tkeycode = KEY_NUMPAD0; 
+        keysym <= SDLK_KP9; 
+        ++keysym, ++tkeycode)
+      MapKey(static_cast<SDLKey>(keysym), tkeycode);
+
+   // other numpad stuff
+   MapKey(SDLK_KP_MULTIPLY, KEY_MULTIPLY);
+   MapKey(SDLK_KP_PLUS, KEY_ADD);
+   MapKey(SDLK_KP_EQUALS, KEY_SEPARATOR);
+   MapKey(SDLK_KP_MINUS, KEY_SUBTRACT);
+   MapKey(SDLK_KP_PERIOD, KEY_DECIMAL);
+   MapKey(SDLK_KP_DIVIDE, KEY_DIVIDE);
+   MapKey(SDLK_KP_ENTER, KEY_NUMPADENTER);
+
+   // F keys
+   for (keysym = SDLK_F1, tkeycode = KEY_F1; 
+        keysym <= SDLK_F15; 
+        ++keysym, ++tkeycode)
+      MapKey(static_cast<SDLKey>(keysym), tkeycode);
+
+   // various modifiers
+   MapKey(SDLK_NUMLOCK, KEY_NUMLOCK);
+   MapKey(SDLK_SCROLLOCK, KEY_SCROLLLOCK);
+   MapKey(SDLK_LCTRL, KEY_LCONTROL);
+   MapKey(SDLK_RCTRL, KEY_RCONTROL);
+   MapKey(SDLK_LALT, KEY_LALT);
+   MapKey(SDLK_RALT, KEY_RALT);
+   MapKey(313, KEY_RALT);   
+   MapKey(SDLK_LSHIFT, KEY_LSHIFT);
+   MapKey(SDLK_RSHIFT, KEY_RSHIFT);
+   MapKey(SDLK_LSUPER, KEY_WIN_LWINDOW);
+   MapKey(SDLK_RSUPER, KEY_WIN_RWINDOW);
+   MapKey(SDLK_MENU, KEY_WIN_APPS);
+   MapKey(SDLK_MODE, KEY_OEM_102);
+
+   keyMapsInitialized = true;
+};
+
+//------------------------------------------------------------------------------
+U8 TranslateSDLKeytoTKey(SDLKey keysym)
+{
+   if (!keyMapsInitialized)
+   {
+      Con::printf("WARNING: SDLkeysymMap is not initialized");
+      return 0;
+   }
+   if (keysym < 0 || 
+       static_cast<U32>(keysym) >= SDLtoTKeyMapSize)
+   {
+      Con::printf("WARNING: invalid keysym: %d", keysym);
+      return 0;
+   }
+   return SDLtoTKeyMap[keysym];
+}
+
+//==============================================================================
+// UInputManager
+//==============================================================================
+UInputManager::UInputManager()
+{
+   mActive = false;
+   mEnabled = false;
+   mLocking = true; // locking enabled by default
+   mKeyboardEnabled = mMouseEnabled = mJoystickEnabled = false;
+   mKeyboardActive = mMouseActive = mJoystickActive = false;
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::init()
+{
+   Con::addVariable( "pref::Input::KeyboardEnabled",  
+      TypeBool, &mKeyboardEnabled );
+   Con::addVariable( "pref::Input::MouseEnabled",     
+      TypeBool, &mMouseEnabled );
+   Con::addVariable( "pref::Input::JoystickEnabled",  
+      TypeBool, &mJoystickEnabled );
+}
+
+//------------------------------------------------------------------------------
+bool UInputManager::enable()
+{
+   disable();
+#ifdef LOG_INPUT
+   Input::log( "Enabling Input...\n" );
+#endif
+
+   mModifierKeys = 0;
+   dMemset( mMouseButtonState, 0, sizeof( mMouseButtonState ) );
+   dMemset( mKeyboardState, 0, 256 );
+
+   InitKeyMaps();
+
+   mJoystickEnabled = false;
+   initJoystick();
+
+   mEnabled = true;
+   mMouseEnabled = true;
+   mKeyboardEnabled = true;
+
+   SDL_EnableKeyRepeat(
+      SDL_DEFAULT_REPEAT_DELAY, 
+      SDL_DEFAULT_REPEAT_INTERVAL);
+
+   return true;     
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::disable()
+{
+   deactivate();
+   mEnabled = false;
+   return;
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::initJoystick()
+{
+   mJoystickList.clear();
+
+   // initialize SDL joystick system
+   if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
+   {
+      Con::warnf("   Unable to initialize joystick: %s", SDL_GetError());
+      return;
+   }
+
+   int numJoysticks = SDL_NumJoysticks();
+   if (numJoysticks == 0)
+      Con::printf("   No joysticks found.");
+
+   // disable joystick events (use polling instead)
+   SDL_JoystickEventState(SDL_IGNORE);
+
+   // install joysticks
+   for(int i = 0; i < numJoysticks; i++ ) 
+   {
+      JoystickInputDevice* newDevice = new JoystickInputDevice(i);
+      addObject(newDevice);
+      mJoystickList.push_back(newDevice);
+      Con::printf("   %s: %s", 
+         newDevice->getDeviceName(), newDevice->getName());
+#ifdef LOG_INPUT
+      Input::log("   %s: %s\n", 
+         newDevice->getDeviceName(), newDevice->getName());
+#endif
+   }
+
+   mJoystickEnabled = true;
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::activate()
+{
+   if (mEnabled && !isActive())
+   {
+      mActive = true;
+      SDL_ShowCursor(SDL_DISABLE);
+      resetInputState();
+      // hack; if the mouse or keyboard has been disabled, re-enable them.
+      // prevents scripts like default.cs from breaking our input, although
+      // there is probably a better solution
+      mMouseEnabled = mKeyboardEnabled = true;
+      activateMouse();
+      activateKeyboard();
+      activateJoystick();
+      if (gPlatState.mouseLocked)
+         lockInput();
+   }
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::deactivate()
+{
+   if (mEnabled && isActive())
+   {
+      unlockInput();
+      deactivateKeyboard();
+      deactivateMouse();
+      deactivateJoystick();
+      resetInputState();
+      SDL_ShowCursor(SDL_ENABLE);
+      mActive = false;
+   }
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::resetKeyboardState()
+{
+   // unpress any pressed keys; in the future we may want
+   // to actually sync with the keyboard state
+   for (int i = 0; i < 256; ++i)
+   {
+      if (mKeyboardState[i])
+      {
+         InputEvent event;
+         
+         event.deviceInst = 0;
+         event.deviceType = KeyboardDeviceType;
+         event.objType = SI_KEY;
+         event.objInst = i;
+         event.action = SI_BREAK;
+         event.fValue = 0.0;
+         Game->postEvent(event);
+      }
+   }
+   dMemset(mKeyboardState, 0, 256);
+
+   // clear modifier keys
+   mModifierKeys = 0;
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::resetMouseState()
+{
+   // unpress any buttons; in the future we may want
+   // to actually sync with the mouse state
+   for (int i = 0; i < 3; ++i)
+   {
+      if (mMouseButtonState[i])
+      {
+         // add KEY_BUTTON0 to the index to get the real
+         // button ID
+         S32 buttonID = i + KEY_BUTTON0;
+         InputEvent event;
+        
+         event.deviceInst = 0;
+         event.deviceType = MouseDeviceType;
+         event.objType = SI_BUTTON;
+         event.objInst = buttonID;
+         event.action = SI_BREAK;
+         event.fValue = 0.0;
+         Game->postEvent(event);
+      }
+   }
+
+   dMemset(mMouseButtonState, 0, 3);
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::resetInputState()
+{
+   resetKeyboardState();
+   resetMouseState();
+
+   // reset joysticks
+   for (Vector<JoystickInputDevice*>::iterator iter = mJoystickList.begin(); 
+        iter != mJoystickList.end();
+        ++iter)
+   {
+      (*iter)->reset();
+   }
+   gPlatState.eventList.clear();
+
+#ifndef DUMMY_PLATFORM
+   // Need to do this since there seems to be no flush method!
+   SDL_Event e;
+   while (SDL_PollEvent(&e))
+   {
+      // ....
+   }
+#endif
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::setLocking(bool enabled)
+{
+   mLocking = enabled;
+   if (mLocking)
+      lockInput();
+   else
+      unlockInput();
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::lockInput()
+{
+   if (!gPlatState.backgrounded && !gPlatState.mouseLocked && 
+      mLocking &&
+      SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF)
+      SDL_WM_GrabInput(SDL_GRAB_ON);
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::unlockInput()
+{
+   if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON)
+      SDL_WM_GrabInput(SDL_GRAB_OFF);
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::onDeleteNotify( SimObject* object )
+{
+   Parent::onDeleteNotify( object );
+}
+
+//------------------------------------------------------------------------------
+bool UInputManager::onAdd()
+{
+   if ( !Parent::onAdd() )
+      return false;
+
+   return true;
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::onRemove()
+{
+   deactivate();
+   Parent::onRemove();
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::mouseMotionEvent(const SDL_Event& event)
+{
+//    Con::printf("motion event: %d %d %d %d",
+//       event.motion.xrel, event.motion.yrel,
+//       event.motion.x, event.motion.y);
+   if (gPlatState.mouseLocked)
+   {
+      InputEvent ievent;
+      ievent.deviceInst = 0;
+      ievent.deviceType = MouseDeviceType;
+      ievent.objInst = 0;
+      ievent.modifier = mModifierKeys;
+      ievent.ascii = 0;
+      ievent.action = SI_MOVE;
+            
+      // post events if things have changed
+      if (event.motion.xrel != 0)
+      {
+         ievent.objType = SI_XAXIS;
+         ievent.fValue = event.motion.xrel;
+         Game->postEvent(ievent);
+      }
+      if (event.motion.yrel != 0)
+      {
+         ievent.objType = SI_YAXIS;
+         ievent.fValue = event.motion.yrel; 
+         Game->postEvent(ievent);
+      }
+#ifdef LOG_INPUT
+#ifdef LOG_MOUSEMOVE
+         Input::log( "EVENT (Input): Mouse relative move (%.1f, %.1f).\n",
+            event.motion.xrel != 0 ? F32(event.motion.xrel) : 0.0,
+            event.motion.yrel != 0 ? F32(event.motion.yrel) : 0.0);
+#endif
+#endif
+   }
+   else
+   {
+      MouseMoveEvent mmevent;
+      mmevent.xPos = mLastMouseX = event.motion.x;
+      mmevent.yPos = mLastMouseY = event.motion.y;
+      mmevent.modifier = mModifierKeys;
+      Game->postEvent(mmevent);
+#ifdef LOG_INPUT
+#ifdef LOG_MOUSEMOVE
+         Input::log( "EVENT (Input): Mouse absolute move (%.1f, %.1f).\n",
+            F32(event.motion.x),
+            F32(event.motion.y));
+#endif
+#endif
+   }
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::joyButtonEvent(const SDL_Event& event)
+{
+   joyButtonEvent(event.jbutton.which, event.jbutton.button, 
+      event.type == SDL_JOYBUTTONDOWN);
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::joyButtonEvent(U8 deviceID, U8 buttonNum, bool pressed)
+
+{
+   S32 action = pressed ? SI_MAKE : SI_BREAK;
+   S32 objInst = buttonNum + KEY_BUTTON0;
+
+   InputEvent ievent;
+
+   ievent.deviceInst = deviceID;
+   ievent.deviceType = JoystickDeviceType;
+   ievent.modifier = mModifierKeys;
+   ievent.ascii = 0;
+   ievent.objType = SI_BUTTON;
+   ievent.objInst = objInst;
+   ievent.action = action;
+   ievent.fValue = (action == SI_MAKE) ? 1.0 : 0.0;
+
+   Game->postEvent(ievent);
+#ifdef LOG_INPUT
+   Input::log( "EVENT (Input): joystick%d button%d %s. MODS:%c%c%c \n",
+      deviceID,
+      buttonNum,
+      pressed ? "pressed" : "released",
+      ( mModifierKeys & SI_SHIFT ? 'S' : '.' ), 
+      ( mModifierKeys & SI_CTRL ? 'C' : '.' ), 
+      ( mModifierKeys & SI_ALT ? 'A' : '.' ));
+#endif
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::joyHatEvent(U8 deviceID, U8 hatNum, 
+   U8 prevHatState, U8 currHatState)
+{
+   if (prevHatState == currHatState)
+      return;
+
+   InputEvent ievent;
+
+   ievent.deviceInst = deviceID;
+   ievent.deviceType = JoystickDeviceType;
+   ievent.modifier = mModifierKeys;
+   ievent.ascii = 0;
+   ievent.objType = SI_POV;
+
+   // first break any positions that are no longer valid
+   ievent.action = SI_BREAK;
+   ievent.fValue = 0.0;
+
+   if (prevHatState & SDL_HAT_UP && !(currHatState & SDL_HAT_UP))
+   {
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): Up POV released.\n");
+#endif
+      ievent.objInst = SI_UPOV;
+      Game->postEvent(ievent);
+   }
+   else if (prevHatState & SDL_HAT_DOWN && !(currHatState & SDL_HAT_DOWN))
+   {
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): Down POV released.\n");
+#endif
+      ievent.objInst = SI_DPOV;
+      Game->postEvent(ievent);
+   }
+   if (prevHatState & SDL_HAT_LEFT && !(currHatState & SDL_HAT_LEFT))
+   {
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): Left POV released.\n");
+#endif
+      ievent.objInst = SI_LPOV;
+      Game->postEvent(ievent);
+   }
+   else if (prevHatState & SDL_HAT_RIGHT && !(currHatState & SDL_HAT_RIGHT))
+   {
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): Right POV released.\n");
+#endif
+      ievent.objInst = SI_RPOV;
+      Game->postEvent(ievent);
+   }
+
+   // now do the make events
+   ievent.action = SI_MAKE;
+   ievent.fValue = 1.0;
+
+   if (!(prevHatState & SDL_HAT_UP) && currHatState & SDL_HAT_UP)
+   {
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): Up POV pressed.\n");
+#endif
+      ievent.objInst = SI_UPOV;
+      Game->postEvent(ievent);
+   }
+   else if (!(prevHatState & SDL_HAT_DOWN) && currHatState & SDL_HAT_DOWN)
+   {
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): Down POV pressed.\n");
+#endif
+      ievent.objInst = SI_DPOV;
+      Game->postEvent(ievent);
+   }
+   if (!(prevHatState & SDL_HAT_LEFT) && currHatState & SDL_HAT_LEFT)
+   {
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): Left POV pressed.\n");
+#endif
+      ievent.objInst = SI_LPOV;
+      Game->postEvent(ievent);
+   }
+   else if (!(prevHatState & SDL_HAT_RIGHT) && currHatState & SDL_HAT_RIGHT)
+   {
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): Right POV pressed.\n");
+#endif
+      ievent.objInst = SI_RPOV;
+      Game->postEvent(ievent);
+   }
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::joyAxisEvent(const SDL_Event& event)
+{
+   joyAxisEvent(event.jaxis.which, event.jaxis.axis, event.jaxis.value);
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::joyAxisEvent(U8 deviceID, U8 axisNum, S16 axisValue)
+{
+   JoystickInputDevice* stick;
+
+   stick = mJoystickList[deviceID];
+   AssertFatal(stick, "JoystickInputDevice* is NULL");
+   JoystickAxisInfo axisInfo = stick->getAxisInfo(axisNum);
+
+   if (axisInfo.type == -1)
+      return;
+
+   // scale the value to [-1,1]
+   F32 scaledValue = 0;  
+   if (axisValue < 0)
+      scaledValue = -F32(axisValue) / axisInfo.minValue;
+   else if (axisValue > 0)
+      scaledValue = F32(axisValue) / axisInfo.maxValue;
+
+//    F32 range = F32(axisInfo.maxValue - axisInfo.minValue);
+//    F32 scaledValue = F32((2 * axisValue) - axisInfo.maxValue -
+//       axisInfo.minValue) / range;
+
+   if (scaledValue > 1.f)
+      scaledValue = 1.f;
+   else if (scaledValue < -1.f)
+      scaledValue = -1.f;
+
+   // create and post the event
+   InputEvent ievent;
+
+   ievent.deviceInst = deviceID;
+   ievent.deviceType = JoystickDeviceType;
+   ievent.modifier = mModifierKeys;
+   ievent.ascii = 0;
+   ievent.objType = axisInfo.type;
+   ievent.objInst = 0;
+   ievent.action = SI_MOVE;
+   ievent.fValue = scaledValue;
+
+   Game->postEvent(ievent);
+
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): joystick axis %d moved: %.1f.\n",
+         axisNum, ievent.fValue);
+#endif
+
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::mouseButtonEvent(const SDL_Event& event)
+{
+   S32 action = (event.type == SDL_MOUSEBUTTONDOWN) ? SI_MAKE : SI_BREAK;
+   S32 objInst = -1;
+   // JMQTODO: support wheel delta like windows version?
+   // JMQTODO: make this value configurable?
+   S32 wheelDelta = 10;
+   bool wheel = false;
+
+   switch (event.button.button)
+   {
+      case SDL_BUTTON_LEFT:
+         objInst = KEY_BUTTON0;
+         break;
+      case SDL_BUTTON_RIGHT:
+         objInst = KEY_BUTTON1;
+         break;
+      case SDL_BUTTON_MIDDLE:
+         objInst = KEY_BUTTON2;
+         break;
+/*      case Button4:
+         wheel = true;
+         break;
+      case Button5:
+         wheel = true;
+         wheelDelta = -wheelDelta;
+         break;*/
+   }
+
+   if (objInst == -1 && !wheel)
+      // unsupported button
+      return;
+
+   InputEvent ievent;
+
+   ievent.deviceInst = 0;
+   ievent.deviceType = MouseDeviceType;
+   ievent.modifier = mModifierKeys;
+   ievent.ascii = 0;
+
+   if (wheel)
+   {
+      // SDL generates a button press/release for each wheel move,
+      // so ignore breaks to translate those into a single event
+      if (action == SI_BREAK)
+         return;
+      ievent.objType = SI_ZAXIS;
+      ievent.objInst = 0;
+      ievent.action = SI_MOVE;
+      ievent.fValue = wheelDelta;
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): mouse wheel moved %s: %.1f. MODS:%c%c%c\n",
+         wheelDelta > 0 ? "up" : "down",
+         ievent.fValue,
+         ( mModifierKeys & SI_SHIFT ? 'S' : '.' ), 
+         ( mModifierKeys & SI_CTRL ? 'C' : '.' ), 
+         ( mModifierKeys & SI_ALT ? 'A' : '.' ));
+#endif
+   }
+   else // regular button
+   {
+      S32 buttonID = (objInst - KEY_BUTTON0);
+      if (buttonID < 3)
+         mMouseButtonState[buttonID] = ( action == SI_MAKE ) ? true : false;
+
+      ievent.objType = SI_BUTTON;
+      ievent.objInst = objInst;
+      ievent.action = action;
+      ievent.fValue = (action == SI_MAKE) ? 1.0 : 0.0;
+#ifdef LOG_INPUT
+      Input::log( "EVENT (Input): mouse button%d %s. MODS:%c%c%c\n",
+         buttonID,
+         action == SI_MAKE ? "pressed" : "released",
+         ( mModifierKeys & SI_SHIFT ? 'S' : '.' ), 
+         ( mModifierKeys & SI_CTRL ? 'C' : '.' ), 
+         ( mModifierKeys & SI_ALT ? 'A' : '.' ));
+#endif
+   }
+
+   Game->postEvent(ievent);
+}
+
+//------------------------------------------------------------------------------
+const char* getKeyName( U16 key )
+{
+   switch ( key )
+   {
+      case KEY_BACKSPACE:     return "Backspace";
+      case KEY_TAB:           return "Tab";
+      case KEY_RETURN:        return "Return";
+      case KEY_PAUSE:         return "Pause";
+      case KEY_CAPSLOCK:      return "CapsLock";
+      case KEY_ESCAPE:        return "Esc";
+
+      case KEY_SPACE:         return "SpaceBar";
+      case KEY_PAGE_DOWN:     return "PageDown";
+      case KEY_PAGE_UP:       return "PageUp";
+      case KEY_END:           return "End";
+      case KEY_HOME:          return "Home";
+      case KEY_LEFT:          return "Left";
+      case KEY_UP:            return "Up";
+      case KEY_RIGHT:         return "Right";
+      case KEY_DOWN:          return "Down";
+      case KEY_PRINT:         return "PrintScreen";
+      case KEY_INSERT:        return "Insert";
+      case KEY_DELETE:        return "Delete";
+      case KEY_HELP:          return "Help";
+
+      case KEY_NUMPAD0:       return "Numpad 0";
+      case KEY_NUMPAD1:       return "Numpad 1";
+      case KEY_NUMPAD2:       return "Numpad 2";
+      case KEY_NUMPAD3:       return "Numpad 3";
+      case KEY_NUMPAD4:       return "Numpad 4";
+      case KEY_NUMPAD5:       return "Numpad 5";
+      case KEY_NUMPAD6:       return "Numpad 6";
+      case KEY_NUMPAD7:       return "Numpad 7";
+      case KEY_NUMPAD8:       return "Numpad 8";
+      case KEY_NUMPAD9:       return "Numpad 9";
+      case KEY_MULTIPLY:      return "Multiply";
+      case KEY_ADD:           return "Add";
+      case KEY_SEPARATOR:     return "Separator";
+      case KEY_SUBTRACT:      return "Subtract";
+      case KEY_DECIMAL:       return "Decimal";
+      case KEY_DIVIDE:        return "Divide";
+      case KEY_NUMPADENTER:   return "Numpad Enter";
+
+      case KEY_F1:            return "F1";
+      case KEY_F2:            return "F2";
+      case KEY_F3:            return "F3";
+      case KEY_F4:            return "F4";
+      case KEY_F5:            return "F5";
+      case KEY_F6:            return "F6";
+      case KEY_F7:            return "F7";
+      case KEY_F8:            return "F8";
+      case KEY_F9:            return "F9";
+      case KEY_F10:           return "F10";
+      case KEY_F11:           return "F11";
+      case KEY_F12:           return "F12";
+      case KEY_F13:           return "F13";
+      case KEY_F14:           return "F14";
+      case KEY_F15:           return "F15";
+      case KEY_F16:           return "F16";
+      case KEY_F17:           return "F17";
+      case KEY_F18:           return "F18";
+      case KEY_F19:           return "F19";
+      case KEY_F20:           return "F20";
+      case KEY_F21:           return "F21";
+      case KEY_F22:           return "F22";
+      case KEY_F23:           return "F23";
+      case KEY_F24:           return "F24";
+
+      case KEY_NUMLOCK:       return "NumLock";
+      case KEY_SCROLLLOCK:    return "ScrollLock";
+      case KEY_LCONTROL:      return "LCtrl";
+      case KEY_RCONTROL:      return "RCtrl";
+      case KEY_LALT:          return "LAlt";
+      case KEY_RALT:          return "RAlt";
+      case KEY_LSHIFT:        return "LShift";
+      case KEY_RSHIFT:        return "RShift";
+
+      case KEY_WIN_LWINDOW:   return "LWin";
+      case KEY_WIN_RWINDOW:   return "RWin";
+      case KEY_WIN_APPS:      return "Apps";
+   }
+
+   static char returnString[5];
+   dSprintf( returnString, sizeof( returnString ), "%c", Input::getAscii( key, STATE_UPPER ) );
+   return returnString;
+}
+
+
+//------------------------------------------------------------------------------
+void UInputManager::keyEvent(const SDL_Event& event)
+{
+   S32 action = (event.type == SDL_KEYDOWN) ? SI_MAKE : SI_BREAK;
+   InputEvent ievent;
+
+//   Con::printf("keyEvent: %u", event.key.keysym.sym);
+
+   ievent.deviceInst = 0;
+   ievent.deviceType = KeyboardDeviceType;
+   ievent.objType = SI_KEY;
+   ievent.objInst = TranslateSDLKeytoTKey(event.key.keysym.sym);
+//   Con::printf("keyEvent: objInst %u", ievent.objInst);
+   // if the action is a make but this key is already pressed, 
+   // count it as a repeat
+   if (action == SI_MAKE && mKeyboardState[ievent.objInst])
+      action = SI_REPEAT;
+   ievent.action = action;
+   ievent.fValue = (action == SI_MAKE || action == SI_REPEAT) ? 1.0 : 0.0;
+
+   processKeyEvent(ievent);
+   Game->postEvent(ievent);
+
+#if 0
+   if (ievent.action == SI_MAKE)
+      dPrintf("key event: : %s key pressed. MODS:%c%c%c\n",
+         getKeyName(ievent.objInst),
+         ( mModifierKeys & SI_SHIFT ? 'S' : '.' ), 
+         ( mModifierKeys & SI_CTRL ? 'C' : '.' ), 
+         ( mModifierKeys & SI_ALT ? 'A' : '.' ));
+   else if (ievent.action == SI_REPEAT)
+      dPrintf("key event: : %s key repeated. MODS:%c%c%c\n",
+         getKeyName(ievent.objInst),
+         ( mModifierKeys & SI_SHIFT ? 'S' : '.' ), 
+         ( mModifierKeys & SI_CTRL ? 'C' : '.' ), 
+         ( mModifierKeys & SI_ALT ? 'A' : '.' ));
+   else if (ievent.action == SI_BREAK)
+      dPrintf("key event: : %s key released. MODS:%c%c%c\n",
+         getKeyName(ievent.objInst),
+         ( mModifierKeys & SI_SHIFT ? 'S' : '.' ), 
+         ( mModifierKeys & SI_CTRL ? 'C' : '.' ), 
+         ( mModifierKeys & SI_ALT ? 'A' : '.' ));
+   else
+      dPrintf("unknown key event!\n");
+#endif
+
+#ifdef LOG_INPUT
+   Input::log( "EVENT (Input): %s key %s. MODS:%c%c%c\n",
+      getKeyName(ievent.objInst),
+      action == SI_MAKE ? "pressed" : "released",
+      ( mModifierKeys & SI_SHIFT ? 'S' : '.' ), 
+      ( mModifierKeys & SI_CTRL ? 'C' : '.' ), 
+      ( mModifierKeys & SI_ALT ? 'A' : '.' ));
+#endif
+}
+
+//------------------------------------------------------------------------------
+// This function was ripped from DInputDevice almost entirely intact.  
+bool UInputManager::processKeyEvent( InputEvent &event )
+{
+   if ( event.deviceType != KeyboardDeviceType || event.objType != SI_KEY )
+      return false;
+
+   bool modKey = false;
+   U8 keyCode = event.objInst;
+
+   if ( event.action == SI_MAKE || event.action == SI_REPEAT)
+   {
+      // Maintain the key structure:
+      mKeyboardState[keyCode] = true;
+
+      switch ( event.objInst )
+      {
+         case KEY_LSHIFT:
+//   Con::printf("keyEvent: LSHIFT");
+            mModifierKeys |= SI_LSHIFT;
+            modKey = true;
+            break;
+
+         case KEY_RSHIFT:
+//   Con::printf("keyEvent: RSHIFT");
+            mModifierKeys |= SI_RSHIFT;
+            modKey = true;
+            break;
+
+         case KEY_LCONTROL:
+            mModifierKeys |= SI_LCTRL;
+            modKey = true;
+            break;
+
+         case KEY_RCONTROL:
+            mModifierKeys |= SI_RCTRL;
+            modKey = true;
+            break;
+
+         case KEY_LALT:
+            mModifierKeys |= SI_LALT;
+            modKey = true;
+            break;
+
+         case KEY_RALT:
+            mModifierKeys |= SI_RALT;
+            modKey = true;
+            break;
+      }
+   }
+   else
+   {
+      // Maintain the keys structure:
+      mKeyboardState[keyCode] = false;
+
+      switch ( event.objInst )
+      {
+         case KEY_LSHIFT:
+//   Con::printf("keyEvent UNSET: LSHIFT");
+            mModifierKeys &= ~SI_LSHIFT;
+            modKey = true;
+            break;
+
+         case KEY_RSHIFT:
+//   Con::printf("keyEvent UNSET: RSHIFT");
+            mModifierKeys &= ~SI_RSHIFT;
+            modKey = true;
+            break;
+
+         case KEY_LCONTROL:
+            mModifierKeys &= ~SI_LCTRL;
+            modKey = true;
+            break;
+
+         case KEY_RCONTROL:
+            mModifierKeys &= ~SI_RCTRL;
+            modKey = true;
+            break;
+
+         case KEY_LALT:
+            mModifierKeys &= ~SI_LALT;
+            modKey = true;
+            break;
+
+         case KEY_RALT:
+            mModifierKeys &= ~SI_RALT;
+            modKey = true;
+            break;
+      }
+   }
+
+   if ( modKey )
+      event.modifier = 0;
+   else
+      event.modifier = mModifierKeys;
+
+   // TODO: alter this getAscii call
+   KEY_STATE state = STATE_LOWER;
+   if (event.modifier & (SI_CTRL|SI_ALT) )
+   {
+      state = STATE_GOOFY;
+   }
+   if ( event.modifier & SI_SHIFT )
+   {
+//   Con::printf("keyEvent: UPCASE GET KEY");
+      state = STATE_UPPER;
+   }
+
+   event.ascii = Input::getAscii( event.objInst, state );
+
+   return modKey;
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::setWindowLocked(bool locked)
+{
+   if (locked)
+      lockInput();
+   else
+   {
+      unlockInput();
+      // SDL keeps track of abs mouse position in fullscreen mode, which means
+      // that if you switch to unlocked mode while fullscreen, the mouse will
+      // suddenly warp to someplace unexpected on screen.  To fix this, we 
+      // warp the mouse to the last known Torque abs mouse position.
+      if (mLastMouseX != -1 && mLastMouseY != -1)
+         SDL_WarpMouse(mLastMouseX, mLastMouseY);
+   }
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::process()
+{
+   if (!mEnabled || !isActive())
+      return;
+
+#ifndef DUMMY_PLATFORM
+   if (mMouseActive || mKeyboardActive)
+   {
+      S32 numEvents = gPlatState.eventList.size();
+      for (int i = 0; i < numEvents; ++i)
+      {
+         switch (gPlatState.eventList[i].type) 
+         {
+            case SDL_MOUSEMOTION:
+               if (mMouseActive)
+                  mouseMotionEvent(gPlatState.eventList[i]);
+               break;
+            case SDL_MOUSEBUTTONUP:
+            case SDL_MOUSEBUTTONDOWN:
+               if (mMouseActive)
+                  mouseButtonEvent(gPlatState.eventList[i]);
+               break;
+            case SDL_KEYDOWN:
+            case SDL_KEYUP:
+               if (mKeyboardActive)
+                  keyEvent(gPlatState.eventList[i]);
+               break;
+         }
+      }
+   }
+#endif
+
+   // poll joysticks
+   if (!mJoystickActive)
+      return;
+
+   SDL_JoystickUpdate();
+
+   for (Vector<JoystickInputDevice*>::iterator iter = mJoystickList.begin(); 
+        iter != mJoystickList.end();
+        ++iter)
+   {
+      (*iter)->process();
+   }
+}
+
+//------------------------------------------------------------------------------
+bool UInputManager::enableKeyboard()
+{
+   if ( !isEnabled() )
+      return( false );
+
+   if ( isKeyboardEnabled() && isKeyboardActive() )
+      return( true );
+
+   mKeyboardEnabled = true;
+   if ( isActive() )
+      mKeyboardEnabled = activateKeyboard();
+
+   if ( mKeyboardEnabled )
+   {
+      Con::printf( "Keyboard enabled." );
+#ifdef LOG_INPUT
+      Input::log( "Keyboard enabled.\n" );
+#endif
+   }
+   else
+   {
+      Con::warnf( "Keyboard failed to enable!" );
+#ifdef LOG_INPUT
+      Input::log( "Keyboard failed to enable!\n" );
+#endif
+   }
+      
+   return( mKeyboardEnabled );
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::disableKeyboard()
+{
+   if ( !isEnabled() || !isKeyboardEnabled())
+      return;
+
+   deactivateKeyboard();
+   mKeyboardEnabled = false;
+   Con::printf( "Keyboard disabled." );
+#ifdef LOG_INPUT
+   Input::log( "Keyboard disabled.\n" );
+#endif
+}
+
+//------------------------------------------------------------------------------
+bool UInputManager::activateKeyboard()
+{
+   if ( !isEnabled() || !isActive() || !isKeyboardEnabled() )
+      return( false );
+
+   mKeyboardActive = true;
+#ifdef LOG_INPUT
+   Input::log( mKeyboardActive ? "Keyboard activated.\n" : "Keyboard failed to activate!\n" );
+#endif
+   return( mKeyboardActive );
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::deactivateKeyboard()
+{
+   if ( isEnabled() && isKeyboardActive() )
+   {
+      mKeyboardActive = false;
+#ifdef LOG_INPUT
+      Input::log( "Keyboard deactivated.\n" );
+#endif
+   }
+}
+
+//------------------------------------------------------------------------------
+bool UInputManager::enableMouse()
+{
+   if ( !isEnabled() )
+      return( false );
+
+   if ( isMouseEnabled() && isMouseActive() )
+      return( true );
+
+   mMouseEnabled = true;
+   if ( isActive() )
+      mMouseEnabled = activateMouse();
+
+   if ( mMouseEnabled )
+   {
+      Con::printf( "Mouse enabled." );
+#ifdef LOG_INPUT
+      Input::log( "Mouse enabled.\n" );
+#endif
+   }
+   else
+   {
+      Con::warnf( "Mouse failed to enable!" );
+#ifdef LOG_INPUT
+      Input::log( "Mouse failed to enable!\n" );
+#endif
+   }
+
+   return( mMouseEnabled );
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::disableMouse()
+{
+   if ( !isEnabled() || !isMouseEnabled())
+      return;
+
+   deactivateMouse();
+   mMouseEnabled = false;
+   Con::printf( "Mouse disabled." );
+#ifdef LOG_INPUT
+   Input::log( "Mouse disabled.\n" );
+#endif
+}
+
+//------------------------------------------------------------------------------
+bool UInputManager::activateMouse()
+{
+   if ( !isEnabled() || !isActive() || !isMouseEnabled() )
+      return( false );
+
+   Con::printf("Mouse Activated");
+
+   mMouseActive = true;
+#ifdef LOG_INPUT
+   Input::log( mMouseActive ? 
+      "Mouse activated.\n" : "Mouse failed to activate!\n" );
+#endif
+   return( mMouseActive );
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::deactivateMouse()
+{
+
+   Con::printf("Mouse Deactivated");
+   if ( isEnabled() && isMouseActive() )
+   {
+      mMouseActive = false;
+#ifdef LOG_INPUT
+      Input::log( "Mouse deactivated.\n" );
+#endif
+   }
+}
+
+//------------------------------------------------------------------------------
+bool UInputManager::enableJoystick()
+{
+   if ( !isEnabled() )
+      return( false );
+
+   if ( isJoystickEnabled() && isJoystickActive() )
+      return( true );
+
+   mJoystickEnabled = true;
+   if ( isActive() )
+      mJoystickEnabled = activateJoystick();
+
+   if ( mJoystickEnabled )
+   {
+      Con::printf( "Joystick enabled." );
+#ifdef LOG_INPUT
+      Input::log( "Joystick enabled.\n" );
+#endif
+   }
+   else
+   {
+      Con::warnf( "Joystick failed to enable!" );
+#ifdef LOG_INPUT
+      Input::log( "Joystick failed to enable!\n" );
+#endif
+   }
+
+   return( mJoystickEnabled );
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::disableJoystick()
+{
+   if ( !isEnabled() || !isJoystickEnabled())
+      return;
+
+   deactivateJoystick();
+   mJoystickEnabled = false;
+   Con::printf( "Joystick disabled." );
+#ifdef LOG_INPUT
+   Input::log( "Joystick disabled.\n" );
+#endif
+}
+
+//------------------------------------------------------------------------------
+bool UInputManager::activateJoystick()
+{
+   if ( !isEnabled() || !isActive() || !isJoystickEnabled() )
+      return( false );
+
+   mJoystickActive = false;
+   JoystickInputDevice* dptr;
+   for ( iterator ptr = begin(); ptr != end(); ptr++ )
+   {
+      dptr = dynamic_cast<JoystickInputDevice*>( *ptr );
+      if ( dptr && dptr->getDeviceType() == JoystickDeviceType)
+         if ( dptr->activate() )
+            mJoystickActive = true;
+   }
+#ifdef LOG_INPUT
+   Input::log( mJoystickActive ? 
+      "Joystick activated.\n" : "Joystick failed to activate!\n" );
+#endif
+   return( mJoystickActive );
+}
+
+//------------------------------------------------------------------------------
+void UInputManager::deactivateJoystick()
+{
+   if ( isEnabled() && isJoystickActive() )
+   {
+      mJoystickActive = false;
+      JoystickInputDevice* dptr;
+      for ( iterator ptr = begin(); ptr != end(); ptr++ )
+      {
+         dptr = dynamic_cast<JoystickInputDevice*>( *ptr );
+         if ( dptr && dptr->getDeviceType() == JoystickDeviceType)
+            dptr->deactivate();
+      }
+#ifdef LOG_INPUT
+      Input::log( "Joystick deactivated.\n" );
+#endif
+   }
+}
+
+//------------------------------------------------------------------------------
+const char* UInputManager::getJoystickAxesString( U32 deviceID )
+{
+   for (Vector<JoystickInputDevice*>::iterator iter = mJoystickList.begin();
+        iter != mJoystickList.end();
+        ++iter)
+   {
+      if ((*iter)->getDeviceID() == deviceID)
+         return (*iter)->getJoystickAxesString();
+   }
+   return( "" );
+}
+
+//==============================================================================
+// JoystickInputDevice
+//==============================================================================
+JoystickInputDevice::JoystickInputDevice(U8 deviceID)
+{
+   mActive = false;
+   mStick = NULL;
+   mAxisList.clear();
+   mDeviceID = deviceID;
+   dSprintf(mName, 29, "joystick%d", mDeviceID);
+
+   mButtonState.clear();
+   mHatState.clear();
+   mNumAxes = mNumButtons = mNumHats = mNumBalls = 0;
+
+   loadJoystickInfo();
+
+   // initialize state variables
+   for (int i = 0; i < mNumButtons; ++i)
+      mButtonState.push_back(false); // all buttons unpressed initially
+
+   for (int i = 0; i < mNumHats; ++i)
+      mHatState.push_back(SDL_HAT_CENTERED); // hats centered initially
+}
+
+//------------------------------------------------------------------------------
+JoystickInputDevice::~JoystickInputDevice()
+{
+   if (isActive())
+      deactivate();
+}
+
+//------------------------------------------------------------------------------
+bool JoystickInputDevice::activate()
+{
+   if (isActive())
+      return true;
+
+   // open the stick
+   mStick = SDL_JoystickOpen(mDeviceID);
+   if (mStick == NULL)
+   {
+      Con::printf("Unable to activate %s: %s", getDeviceName(), SDL_GetError());
+      return false;
+   }
+
+   // reload axis mapping info
+   loadAxisInfo();
+
+   mActive = true;
+   return true;
+}
+
+//------------------------------------------------------------------------------
+bool JoystickInputDevice::deactivate()
+{
+   if (!isActive())
+      return true;
+
+   if (mStick != NULL)
+   {
+      SDL_JoystickClose(mStick);
+      mStick = NULL;
+   }
+
+   mActive = false;
+   return true;
+}
+
+//------------------------------------------------------------------------------
+const char* JoystickInputDevice::getName()
+{
+   return SDL_JoystickName(mDeviceID);
+}
+
+//------------------------------------------------------------------------------
+void JoystickInputDevice::reset()
+{
+   UInputManager* manager = dynamic_cast<UInputManager*>(Input::getManager());
+   if (!manager)
+      return;
+
+   // clear joystick state variables
+
+   // buttons
+   for (int i = 0; i < mButtonState.size(); ++i)
+      if (mButtonState[i])
+      {
+         manager->joyButtonEvent(mDeviceID, i, false);
+         mButtonState[i] = false;
+      }
+
+   // hats
+   for (int i = 0; i < mHatState.size(); ++i)
+      if (mHatState[i] != SDL_HAT_CENTERED)
+      {
+         manager->joyHatEvent(mDeviceID, i, mHatState[i], SDL_HAT_CENTERED);
+         mHatState[i] = SDL_HAT_CENTERED;
+      }
+
+   // axis and ball state is not maintained
+}
+
+//------------------------------------------------------------------------------
+bool JoystickInputDevice::process()
+{
+   if (!isActive())
+      return false;
+
+   UInputManager* manager = dynamic_cast<UInputManager*>(Input::getManager());
+   if (!manager)
+      return false;
+
+   // axes
+   for (int i = 0; i < mNumAxes; ++i)
+   {
+      // skip the axis if we don't have a mapping for it
+      if (mAxisList[i].type == -1)
+         continue;
+      manager->joyAxisEvent(mDeviceID, i, SDL_JoystickGetAxis(mStick, i));
+   }
+
+   // buttons
+   for (int i = 0; i < mNumButtons; ++i)
+   {
+      if (bool(SDL_JoystickGetButton(mStick, i)) == 
+         mButtonState[i])
+         continue;
+      mButtonState[i] = !mButtonState[i];
+      manager->joyButtonEvent(mDeviceID, i, mButtonState[i]);
+   }
+
+   // hats
+   for (int i = 0; i < mNumHats; ++i)
+   {
+      U8 currHatState = SDL_JoystickGetHat(mStick, i);
+      if (mHatState[i] == currHatState)
+         continue;
+         
+      manager->joyHatEvent(mDeviceID, i, mHatState[i], currHatState);
+      mHatState[i] = currHatState;
+   }
+      
+   // ballz
+   // JMQTODO: how to map ball events (xaxis,yaxis?)
+   return true;
+}
+
+//------------------------------------------------------------------------------
+static S32 GetAxisType(S32 axisNum, const char* namedType)
+{
+   S32 axisType = -1;
+
+   if (namedType != NULL)
+   {
+      if (dStricmp(namedType, "xaxis")==0)
+         axisType = SI_XAXIS;
+      else if (dStricmp(namedType, "yaxis")==0)
+         axisType = SI_YAXIS;
+      else if (dStricmp(namedType, "zaxis")==0)
+         axisType = SI_ZAXIS;
+      else if (dStricmp(namedType, "rxaxis")==0)
+         axisType = SI_RXAXIS;
+      else if (dStricmp(namedType, "ryaxis")==0)
+         axisType = SI_RYAXIS;
+      else if (dStricmp(namedType, "rzaxis")==0)
+         axisType = SI_RZAXIS;
+      else if (dStricmp(namedType, "slider")==0)
+         axisType = SI_SLIDER;
+   }
+
+   if (axisType == -1)
+   {
+      // use a hardcoded default mapping if possible
+      switch (axisNum)
+      {
+         case 0:
+            axisType = SI_XAXIS;
+            break;
+         case 1:
+            axisType = SI_YAXIS;
+            break;
+         case 2: 
+            axisType = SI_RZAXIS;
+            break;
+         case 3:
+            axisType = SI_SLIDER;
+            break;
+      }
+   }
+
+   return axisType;
+}
+
+//------------------------------------------------------------------------------
+void JoystickInputDevice::loadJoystickInfo()
+{
+   bool opened = false;
+   if (mStick == NULL)
+   {
+      mStick = SDL_JoystickOpen(mDeviceID);
+      if (mStick == NULL)
+      {
+         Con::printf("Unable to open %s: %s", getDeviceName(), SDL_GetError());
+         return;
+      }
+      opened = true;
+   }
+
+   // get the number of thingies on this joystick
+   mNumAxes = SDL_JoystickNumAxes(mStick);
+   mNumButtons = SDL_JoystickNumButtons(mStick);
+   mNumHats = SDL_JoystickNumHats(mStick);
+   mNumBalls = SDL_JoystickNumBalls(mStick);
+
+   // load axis mapping info
+   loadAxisInfo();
+
+   if (opened)
+      SDL_JoystickClose(mStick);
+}
+
+//------------------------------------------------------------------------------
+// for each axis on a joystick, torque needs to know the type of the axis 
+// (SI_XAXIS, etc), the minimum value, and the maximum value.  However none of
+// this information is generally available with the unix/linux api.  All you
+// get is a device and axis number and a value.  Therefore,
+// we allow the user to specify these values in preferences.  hopefully 
+// someday we can implement a gui joystick calibrator that takes care of this
+// cruft for the user.
+void JoystickInputDevice::loadAxisInfo()
+{
+   mAxisList.clear();
+
+   AssertFatal(mStick, "mStick is NULL");
+
+   static int AxisDefaults[] = { SI_XAXIS, SI_YAXIS, SI_ZAXIS, 
+                                 SI_RXAXIS, SI_RYAXIS, SI_RZAXIS,
+                                 SI_SLIDER };
+
+   int numAxis = SDL_JoystickNumAxes(mStick);
+   for (int i = 0; i < numAxis; ++i)
+   {
+      JoystickAxisInfo axisInfo;
+
+      // defaults
+      axisInfo.type = -1;
+      axisInfo.minValue = -32768;
+      axisInfo.maxValue = 32767;
+
+      // look in console to see if there is mapping information for this axis
+      const int TempBufSize = 1024;
+      char tempBuf[TempBufSize];
+      dSprintf(tempBuf, TempBufSize, "$Pref::Input::Joystick%d::Axis%d", 
+         mDeviceID, i);
+
+      const char* axisStr = Con::getVariable(tempBuf);
+      if (axisStr == NULL || dStrlen(axisStr) == 0)
+      {
+         if (i < sizeof(AxisDefaults))
+            axisInfo.type = AxisDefaults[i];
+      }
+      else
+      {
+         // format is "TorqueAxisName MinValue MaxValue";
+         dStrncpy(tempBuf, axisStr, TempBufSize);
+         char* temp = dStrtok( tempBuf, " \0" );
+         if (temp)
+         {
+            axisInfo.type = GetAxisType(i, temp);
+            temp = dStrtok( NULL, " \0" );
+            if (temp)
+            {
+               axisInfo.minValue = dAtoi(temp);
+               temp = dStrtok( NULL, "\0" );
+               if (temp)
+               {
+                  axisInfo.maxValue = dAtoi(temp);
+               }
+            }
+         }
+      }
+
+      mAxisList.push_back(axisInfo);
+   }
+}
+
+//------------------------------------------------------------------------------
+const char* JoystickInputDevice::getJoystickAxesString()
+{
+   char buf[64];
+   dSprintf( buf, sizeof( buf ), "%d", mAxisList.size());
+
+   for (Vector<JoystickAxisInfo>::iterator iter = mAxisList.begin();
+        iter != mAxisList.end();
+        ++iter)
+   {
+      switch ((*iter).type)
+      {
+         case SI_XAXIS:
+            dStrcat( buf, "\tX" );
+            break;
+         case SI_YAXIS:
+            dStrcat( buf, "\tY" );
+            break;
+         case SI_ZAXIS:
+            dStrcat( buf, "\tZ" );
+            break;
+         case SI_RXAXIS:
+            dStrcat( buf, "\tR" );
+            break;
+         case SI_RYAXIS:
+            dStrcat( buf, "\tU" );
+            break;
+         case SI_RZAXIS:
+            dStrcat( buf, "\tV" );
+            break;
+         case SI_SLIDER:
+            dStrcat( buf, "\tS" );
+            break;
+      }
+   }
+
+   char* returnString = Con::getReturnBuffer( dStrlen( buf ) + 1 );
+   dStrcpy( returnString, buf );
+   return( returnString );
+}
+
+
+//==============================================================================
+// Console Functions
+//==============================================================================
+ConsoleFunction( activateKeyboard, bool, 1, 1, "activateKeyboard()" )
+{
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr )
+      return( mgr->activateKeyboard() );
+
+   return( false );
+}
+
+// JMQ: disabled deactivateKeyboard since the script calls it but there is
+// no fallback keyboard input in unix, resulting in a permanently disabled
+// keyboard
+//------------------------------------------------------------------------------
+ConsoleFunction( deactivateKeyboard, void, 1, 1, "deactivateKeyboard()" )
+{
+#if 0
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr )
+      mgr->deactivateKeyboard();
+#endif
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( enableMouse, bool, 1, 1, "enableMouse()" )
+{
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr )
+      return( mgr->enableMouse() );
+
+   return ( false );
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( disableMouse, void, 1, 1, "disableMouse()" )
+{
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr )
+      mgr->disableMouse();
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( enableJoystick, bool, 1, 1, "enableJoystick()" )
+{
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr )
+      return( mgr->enableJoystick() );
+
+   return ( false );
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( disableJoystick, void, 1, 1, "disableJoystick()" )
+{
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr )
+      mgr->disableJoystick();
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( enableLocking, void, 1, 1, "enableLocking()" )
+{
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr )
+      mgr->setLocking(true);
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( disableLocking, void, 1, 1, "disableLocking()" )
+{
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr )
+      mgr->setLocking(false);
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( toggleLocking, void, 1, 1, "toggleLocking()" )
+{
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr )
+      mgr->setLocking(!mgr->getLocking());
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( echoInputState, void, 1, 1, "echoInputState()" )
+{
+   UInputManager* mgr = dynamic_cast<UInputManager*>( Input::getManager() );
+   if ( mgr && mgr->isEnabled() )
+   {
+      Con::printf( "Input is enabled %s.", 
+         mgr->isActive() ? "and active" : "but inactive" );
+      Con::printf( "- Keyboard is %sabled and %sactive.", 
+         mgr->isKeyboardEnabled() ? "en" : "dis",
+         mgr->isKeyboardActive() ? "" : "in" );
+      Con::printf( "- Mouse is %sabled and %sactive.", 
+         mgr->isMouseEnabled() ? "en" : "dis",
+         mgr->isMouseActive() ? "" : "in" );
+      Con::printf( "- Joystick is %sabled and %sactive.", 
+         mgr->isJoystickEnabled() ? "en" : "dis",
+         mgr->isJoystickActive() ? "" : "in" );
+   }
+   else
+      Con::printf( "Input is not enabled." );
+}
+

+ 195 - 0
engine/source/platformEmscripten/EmscriptenInputManager.h

@@ -0,0 +1,195 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+
+
+#ifndef _EMSCRIPTENINPUTMANAGER_H_
+#define _EMSCRIPTENINPUTMANAGER_H_
+
+#include "collection/vector.h"
+#include "platform/platformInput.h"
+#include "platformEmscripten/platformEmscripten.h"
+
+#include <SDL/SDL_events.h>
+
+#define NUM_KEYS ( KEY_BUTTON31 + 1 )
+#define KEY_FIRST KEY_ESCAPE
+
+struct AsciiData
+{
+   struct KeyData
+   {
+      U16   ascii;
+      bool  isDeadChar;
+   };
+
+   KeyData upper;
+   KeyData lower;
+   KeyData goofy;
+};
+
+extern AsciiData AsciiTable[NUM_KEYS];
+
+typedef struct _SDL_Joystick;
+
+struct JoystickAxisInfo
+{
+      S32 type;
+      S32 minValue;
+      S32 maxValue;
+};
+
+//------------------------------------------------------------------------------
+class JoystickInputDevice : public InputDevice
+{   
+  public:
+    JoystickInputDevice(U8 deviceID);
+    ~JoystickInputDevice();
+    
+    bool activate();
+    bool deactivate();
+    bool isActive() { return( mActive ); }
+    
+    U8 getDeviceType() { return( JoystickDeviceType ); }
+    U8 getDeviceID() { return( mDeviceID ); }
+    const char* getName();
+    const char* getJoystickAxesString();
+
+    void loadJoystickInfo();
+    void loadAxisInfo();
+    JoystickAxisInfo& getAxisInfo(int axisNum) { return mAxisList[axisNum]; }
+
+    bool process();
+    void reset();
+    
+  private:
+    bool mActive;
+    U8 mDeviceID;
+    SDL_Joystick* mStick;
+    Vector<JoystickAxisInfo> mAxisList;
+    Vector<bool> mButtonState;
+    Vector<U8> mHatState;
+
+    S32 mNumAxes; 
+    S32 mNumButtons;
+    S32 mNumHats;
+    S32 mNumBalls;
+};
+
+//------------------------------------------------------------------------------
+class UInputManager : public InputManager
+{
+   friend bool JoystickInputDevice::process(); // for joystick event funcs
+   friend void JoystickInputDevice::reset(); 
+
+   public:
+      UInputManager();
+
+      void init();
+      bool enable();
+      void disable();
+      void activate();
+      void deactivate();
+      void setWindowLocked(bool locked);
+      bool isActive()               { return( mActive ); }
+
+      void onDeleteNotify( SimObject* object );
+      bool onAdd();
+      void onRemove();
+
+      void process();
+
+      bool enableKeyboard();
+      void disableKeyboard();
+      bool isKeyboardEnabled()      { return( mKeyboardEnabled ); }
+      bool activateKeyboard();
+      void deactivateKeyboard();
+      bool isKeyboardActive()       { return( mKeyboardActive ); }
+
+      bool enableMouse();
+      void disableMouse();
+      bool isMouseEnabled()         { return( mMouseEnabled ); }
+      bool activateMouse();
+      void deactivateMouse();
+      bool isMouseActive()          { return( mMouseActive ); }          
+
+      bool enableJoystick();
+      void disableJoystick();
+      bool isJoystickEnabled()      { return( mJoystickEnabled ); }
+      bool activateJoystick();
+      void deactivateJoystick();
+      bool isJoystickActive()       { return( mJoystickActive ); }          
+
+      void setLocking(bool enabled);
+      bool getLocking() { return mLocking; }
+
+      const char* getJoystickAxesString( U32 deviceID );
+      bool joystickDetected()       { return mJoystickList.size() > 0; }
+   private:
+      typedef SimGroup Parent;
+      // the following vector is just for quick access during event processing.
+      // it does not manage the cleanup of the JoystickInputDevice objects
+      Vector<JoystickInputDevice*> mJoystickList;
+
+      bool mKeyboardEnabled;
+      bool mMouseEnabled;
+      bool mJoystickEnabled;
+
+      bool mKeyboardActive;
+      bool mMouseActive;
+      bool mJoystickActive;
+
+      bool mActive;
+
+      // Device state variables
+      S32 mModifierKeys;
+      bool mKeyboardState[256];
+      bool mMouseButtonState[3];
+
+      // last mousex and y are maintained when window is unlocked
+      S32 mLastMouseX;
+      S32 mLastMouseY;
+
+      void initJoystick();
+
+      void resetKeyboardState();
+      void resetMouseState();
+      void resetInputState();
+
+      void lockInput();
+      void unlockInput();
+      bool mLocking;
+
+      void joyHatEvent(U8 deviceID, U8 hatNum, 
+          U8 prevHatState, U8 currHatState);
+      void joyButtonEvent(U8 deviceID, U8 buttonNum, bool pressed);
+      void joyButtonEvent(const SDL_Event& event);
+      void joyAxisEvent(const SDL_Event& event);
+      void joyAxisEvent(U8 deviceID, U8 axisNum, S16 axisValue);
+      void mouseButtonEvent(const SDL_Event& event);
+      void mouseMotionEvent(const SDL_Event& event);
+      void keyEvent(const SDL_Event& event);
+      bool processKeyEvent(InputEvent &event);
+};
+
+#endif  // _EMSCRIPTENINPUTMANAGER_H_
+

+ 81 - 0
engine/source/platformEmscripten/EmscriptenMath.cpp

@@ -0,0 +1,81 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platform/platform.h"
+#include "console/console.h"
+#include "math/mMath.h"
+
+extern void mInstallLibrary_C();
+extern void mInstallLibrary_Vec();
+
+
+//--------------------------------------
+ConsoleFunction( MathInit, void, 1, 10, "(DETECT|C)")
+{
+   U32 properties = CPU_PROP_C;  // C entensions are always used
+   
+   if (argc == 1)
+   {
+         Math::init(0);
+         return;
+   }
+   for (argc--, argv++; argc; argc--, argv++)
+   {
+      if (dStricmp(*argv, "DETECT") == 0) { 
+         Math::init(0);
+         return;
+      }
+      if (dStricmp(*argv, "C") == 0) { 
+         properties |= CPU_PROP_C; 
+         continue; 
+      }
+      Con::printf("Error: MathInit(): ignoring unknown math extension '%s'", *argv);
+   }
+   Math::init(properties);
+}
+
+
+
+//------------------------------------------------------------------------------
+void Math::init(U32 properties)
+{
+   if (!properties)
+      // detect what's available
+      properties = PlatformSystemInfo.processor.properties;  
+   else
+      // Make sure we're not asking for anything that's not supported
+      properties &= PlatformSystemInfo.processor.properties;  
+
+   Con::printf("Math Init:");
+   Con::printf("   Installing Standard C extensions");
+   mInstallLibrary_C();
+   
+   Con::printf(" ");
+}   
+
+//------------------------------------------------------------------------------
+F32 Platform::getRandom()
+{
+   return gPlatState.platRandom.randF();
+}
+

+ 67 - 0
engine/source/platformEmscripten/EmscriptenMemory.cpp

@@ -0,0 +1,67 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/platform.h"
+#include <stdlib.h>
+#include <string.h>
+
+//-----------------------------------------------------------------------------
+
+void* dRealMalloc(dsize_t in_size)
+{
+   return malloc(in_size);
+}
+
+//-----------------------------------------------------------------------------
+
+void dRealFree(void* in_pFree)
+{
+   free(in_pFree);
+}
+
+//-----------------------------------------------------------------------------
+
+void* dMemcpy(void *dst, const void *src, dsize_t size)
+{
+   return memcpy(dst,src,size);
+}   
+
+//-----------------------------------------------------------------------------
+
+void* dMemmove(void *dst, const void *src, dsize_t size)
+{
+   return memmove(dst,src,size);
+}  
+ 
+//-----------------------------------------------------------------------------
+
+void* dMemset(void *dst, int c, dsize_t size)
+{
+   return memset(dst,c,size);   
+}   
+
+//-----------------------------------------------------------------------------
+
+int dMemcmp(const void *ptr1, const void *ptr2, dsize_t len)
+{
+   return(memcmp(ptr1, ptr2, len));
+}

+ 63 - 0
engine/source/platformEmscripten/EmscriptenMutex.cpp

@@ -0,0 +1,63 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "platform/platform.h"
+#include "platform/threads/mutex.h"
+#include "platform/threads/thread.h"
+#include "memory/safeDelete.h"
+
+struct PlatformMutexData
+{
+   bool              locked;
+   U32         lockedByThread;
+};
+
+Mutex::Mutex(void)
+{
+   bool ok;
+   mData = new PlatformMutexData;
+   
+   mData->locked = false;
+   mData->lockedByThread = 0;
+}
+
+Mutex::~Mutex()
+{
+   SAFE_DELETE(mData);
+}
+ 
+bool Mutex::lock( bool block)
+{
+   mData->locked = true;
+   mData->lockedByThread = ThreadManager::getCurrentThreadId();
+   return true;
+}
+
+void Mutex::unlock()
+{
+   mData->locked = false;
+   mData->lockedByThread = 0;
+}

+ 198 - 0
engine/source/platformEmscripten/EmscriptenNet.cpp

@@ -0,0 +1,198 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platform/platform.h"
+#include "platform/event.h"
+#include "platform/platformNetAsync.unix.h"
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+
+// Header clean-up by William Taysom
+#include <sys/ioctl.h>
+
+// IPX fixes from William Taysom.
+#define IPX_NODE_LEN 6
+
+// for 10.2 compatability...
+#ifndef socklen_t
+#define socklen_t unsigned int
+#endif
+
+#include <stdlib.h>
+
+#include "console/console.h"
+#include "game/gameInterface.h"
+#include "io/fileStream.h"
+#include "collection/vector.h"
+
+static Net::Error getLastError();
+static S32 defaultPort = 28000;
+static S32 netPort = 0;
+static int ipxSocket = InvalidSocket;
+static int udpSocket = InvalidSocket;
+
+// local enum for socket states for polled sockets
+enum SocketState
+{
+   InvalidState,
+   Connected,
+   ConnectionPending,
+   Listening,
+   NameLookupRequired
+};
+
+bool Net::init()
+{
+   return(true);
+}
+
+void Net::shutdown()
+{
+}
+
+NetSocket Net::openListenPort(U16 port)
+{
+   Con::errorf("Sockets not implemented on Emscripten");
+   return InvalidSocket;
+}
+
+NetSocket Net::openConnectTo(const char *addressString)
+{
+   Con::errorf("Sockets not implemented on Emscripten");
+   return InvalidSocket;
+}
+
+void Net::closeConnectTo(NetSocket sock)
+{
+}
+
+Net::Error Net::sendtoSocket(NetSocket socket, const U8 *buffer, int  bufferSize)
+{
+   return NoError;
+}
+
+bool Net::openPort(S32 port)
+{
+   return false;
+}
+
+void Net::closePort()
+{
+}
+
+Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32  bufferSize)
+{
+   return NoError;
+}
+
+void Net::process()
+{
+}
+
+NetSocket Net::openSocket()
+{
+   return InvalidSocket;
+}
+
+Net::Error Net::closeSocket(NetSocket socket)
+{
+   return NoError;
+}
+
+Net::Error Net::connect(NetSocket socket, const NetAddress *address)
+{
+   return NoError;
+}
+
+Net::Error Net::listen(NetSocket socket, S32 backlog)
+{
+   return NoError;
+}
+
+NetSocket Net::accept(NetSocket acceptSocket, NetAddress *remoteAddress)
+{
+   return InvalidSocket;
+}
+
+Net::Error Net::bind(NetSocket socket, U16 port)
+{
+   return NoError;
+}
+
+Net::Error Net::setBufferSize(NetSocket socket, S32 bufferSize)
+{
+   return NoError;
+}
+
+Net::Error Net::setBroadcast(NetSocket socket, bool broadcast)
+{
+   return NoError;
+}
+
+Net::Error Net::setBlocking(NetSocket socket, bool blockingIO)
+{
+   return NoError;
+}
+
+Net::Error Net::send(NetSocket socket, const U8 *buffer, S32 bufferSize)
+{
+   return NoError;
+}
+
+Net::Error Net::recv(NetSocket socket, U8 *buffer, S32 bufferSize, S32  *bytesRead)
+{
+   return NoError;
+}
+
+bool Net::compareAddresses(const NetAddress *a1, const NetAddress *a2)
+{
+   if((a1->type != a2->type)  ||
+      (*((U32 *)a1->netNum) != *((U32 *)a2->netNum)) ||
+      (a1->port != a2->port))
+      return false;
+
+   if(a1->type == NetAddress::IPAddress)
+      return true;
+   for(S32 i = 0; i < 6; i++)
+      if(a1->nodeNum[i] != a2->nodeNum[i])
+         return false;
+   return true;
+}
+
+bool Net::stringToAddress(const char *addressString, NetAddress  *address)
+{
+   return false;
+}
+
+void Net::addressToString(const NetAddress *address, char  addressString[256])
+{
+   addressString[0] = '\0';
+}
+
+Net::Error getLastError()
+{
+   return Net::UnknownError;
+}

+ 462 - 0
engine/source/platformEmscripten/EmscriptenOGLVideo.cpp

@@ -0,0 +1,462 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+
+
+#include "console/console.h"
+#include "platform/event.h"
+#include "game/gameInterface.h"
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platformEmscripten/platformGL.h"
+#include "platformEmscripten/EmscriptenOGLVideo.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_syswm.h>
+#include <SDL/SDL_version.h>
+
+//------------------------------------------------------------------------------
+bool InitOpenGL()
+{
+   DisplayDevice::init();
+
+   // Get the video settings from the prefs:
+   const char* resString = Con::getVariable( "$pref::Video::resolution" );
+   char* tempBuf = new char[dStrlen( resString ) + 1];
+   dStrcpy( tempBuf, resString );
+   char* temp = dStrtok( tempBuf, " x\0" );
+   U32 width = ( temp ? dAtoi( temp ) : 800 );
+   temp = dStrtok( NULL, " x\0" );
+   U32 height = ( temp ? dAtoi( temp ) : 600 );
+   temp = dStrtok( NULL, "\0" );
+   U32 bpp = ( temp ? dAtoi( temp ) : 16 );
+   delete [] tempBuf;
+
+   bool fullScreen = Con::getBoolVariable( "$pref::Video::fullScreen" );
+
+   // the only supported video device in unix is OpenGL
+   if ( !Video::setDevice( "OpenGL", width, height, bpp, fullScreen ) )
+   {
+      Con::errorf("Unable to create default OpenGL mode: %d %d %d %d",
+         width, height, bpp, fullScreen);
+
+      // if we can't create the default, attempt to create a "safe" window
+      if ( !Video::setDevice( "OpenGL", 640, 480, 16, true ) )
+      {
+         Platform::AlertOK("Error", "Could not find a compatible OpenGL display " \
+            "resolution.  Please check your driver configuration.");
+         return false;
+      }
+   }
+
+   return true;
+}
+
+//------------------------------------------------------------------------------
+bool OpenGLDevice::smCanSwitchBitDepth = false;
+
+//------------------------------------------------------------------------------
+OpenGLDevice::OpenGLDevice()
+{
+   Con::printf("OpenGLDevice created");
+   initDevice();
+}
+
+//------------------------------------------------------------------------------
+OpenGLDevice::~OpenGLDevice()
+{
+}
+
+//------------------------------------------------------------------------------
+void OpenGLDevice::addResolution(S32 width, S32 height, bool check)
+{
+   Resolution res = Video::getDesktopResolution();
+   Point2I desktopSize = Point2I(res.w, res.h);
+   U32 desktopBpp = res.bpp;
+
+   // don't allow any resolution under this size
+   if (width < 640 || height < 480)
+      return;
+
+   if (check)
+   {
+      // don't allow resolutions that exceed the current desktop size
+      if (width > desktopSize.x || height > desktopSize.y)
+         return;
+   }
+
+   if (smCanSwitchBitDepth)
+   {
+      // add both 16 and 32 bit resolutions
+      mResolutionList.push_back(Resolution(width, height, 16));
+      mResolutionList.push_back(Resolution(width, height, 32));
+   }
+   else
+   {
+      // add just the desktop resolution
+      mResolutionList.push_back(Resolution(width, height, desktopBpp));
+   }
+}
+
+//------------------------------------------------------------------------------
+void OpenGLDevice::initDevice()
+{
+   mDeviceName = "OpenGL";
+   mFullScreenOnly = false;
+}
+
+//------------------------------------------------------------------------------
+void OpenGLDevice::loadResolutions()
+{
+   mResolutionList.clear();
+
+   // X cannot switch bit depths on the fly.  In case this feature is
+   // implemented someday, calling this function will let you take
+   // advantage of it
+   if (Con::getBoolVariable("$pref::Unix::CanSwitchBitDepth"))
+      smCanSwitchBitDepth = true;
+
+   // add some default resolutions
+   addResolution(640, 480);
+   addResolution(800, 600);
+   addResolution(1024, 768);
+   addResolution(1152, 864);
+   addResolution(1280, 1024);
+   addResolution(1600, 1200);
+
+   // specifying full screen should give us the resolutions that the
+   // X server allows
+   SDL_Rect** modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
+   if (modes &&
+      (modes != (SDL_Rect **)-1))
+   {
+      for (int i = 0; modes[i] != NULL; ++i)
+      {
+         // do we already have this mode?
+         bool found = false;
+         for (Vector<Resolution>::iterator iter = mResolutionList.begin();
+              iter != mResolutionList.end();
+              ++iter)
+         {
+            if (iter->w == modes[i]->w && iter->h == modes[i]->h)
+            {
+               found = true;
+               break;
+            }
+         }
+         if (!found)
+            // don't check these resolutions because they should be OK
+            // (and checking might drop resolutions that are higher than the
+            // current desktop bpp)
+            addResolution(modes[i]->w, modes[i]->h, false);
+      }
+   }
+}
+
+//------------------------------------------------------------------------------
+bool OpenGLDevice::activate( U32 width, U32 height, U32 bpp, bool fullScreen )
+{
+   if (!setScreenMode(width, height, bpp, fullScreen))
+   {
+      Con::printf("Unable to set screen mode.");
+      return false;
+   }
+
+   // Output some driver info to the console
+   const char* vendorString   = (const char*) glGetString( GL_VENDOR );
+   const char* rendererString = (const char*) glGetString( GL_RENDERER );
+   const char* versionString  = (const char*) glGetString( GL_VERSION );
+   Con::printf( "OpenGL driver information:" );
+   if ( vendorString )
+      Con::printf( "  Vendor: %s", vendorString );
+   if ( rendererString )
+      Con::printf( "  Renderer: %s", rendererString );
+   if ( versionString )
+      Con::printf( "  Version: %s", versionString );
+
+   getGLCapabilities();
+
+   Con::setVariable( "$pref::Video::displayDevice", mDeviceName );
+
+   // Do this here because we now know about the extensions:
+   if ( gGLState.suppSwapInterval )
+      setVerticalSync(
+         !Con::getBoolVariable( "$pref::Video::disableVerticalSync" ) );
+   Con::setBoolVariable("$pref::OpenGL::allowTexGen", true);
+
+   return true;
+}
+
+
+//------------------------------------------------------------------------------
+void OpenGLDevice::shutdown()
+{
+   // Shutdown is deferred to Platform::shutdown()
+}
+
+//------------------------------------------------------------------------------
+static void PrintGLAttributes()
+{
+   int doubleBuf;
+   int bufferSize, depthSize, stencilSize;
+   int red, green, blue, alpha;
+   int aRed, aGreen, aBlue, aAlpha;
+
+   SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &doubleBuf);
+   SDL_GL_GetAttribute(SDL_GL_BUFFER_SIZE, &bufferSize);
+   SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depthSize);
+   SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencilSize);
+   SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &red);
+   SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &green);
+   SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &blue);
+   SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &alpha);
+   SDL_GL_GetAttribute(SDL_GL_ACCUM_RED_SIZE, &aRed);
+   SDL_GL_GetAttribute(SDL_GL_ACCUM_GREEN_SIZE, &aGreen);
+   SDL_GL_GetAttribute(SDL_GL_ACCUM_BLUE_SIZE, &aBlue);
+   SDL_GL_GetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, &aAlpha);
+
+   Con::printf("OpenGL Attributes:");
+   Con::printf("  DoubleBuffer: %d", doubleBuf);
+   Con::printf("  BufferSize: %d, DepthSize: %d, StencilSize: %d",
+      bufferSize, depthSize, stencilSize);
+   Con::printf("  Red: %d, Green: %d, Blue: %d, Alpha: %d",
+      red, green, blue, alpha);
+   Con::printf("  Accum Red: %d, Green: %d, Blue: %d, Alpha: %d",
+      aRed, aGreen, aBlue, aAlpha);
+}
+
+//------------------------------------------------------------------------------
+bool OpenGLDevice::setScreenMode( U32 width, U32 height, U32 bpp,
+   bool fullScreen, bool forceIt, bool repaint )
+{
+    Resolution desktopRes = Video::getDesktopResolution();
+   // load resolutions, this is done lazily so that we can check the setting
+   // of smCanSwitchBitDepth, which may be overridden by console
+   if (mResolutionList.size()==0)
+      loadResolutions();
+
+   if (mResolutionList.size()==0)
+   {
+      Con::printf("No resolutions available!");
+      return false;
+   }
+
+   if (bpp == 0)
+   {
+      // bpp comes in as "0" when it is set to "Default"
+      bpp = desktopRes.bpp;
+   }
+
+   if (height == 0 || width == 0)
+   {
+      // paranoia check.  set it to the default to prevent crashing
+      width = 800;
+      height = 600;
+   }
+
+   U32 desktopDepth = desktopRes.bpp;
+   // if we can't switch bit depths and the requested bpp is not equal to
+   // the desktop bpp, set bpp to the desktop bpp
+   if (!smCanSwitchBitDepth &&
+      bpp != desktopDepth)
+   {
+      bpp = desktopDepth;
+   }
+
+   bool IsInList = false;
+
+   Resolution NewResolution( width, height, bpp );
+
+   // See if the desired resolution is in the list
+   if ( mResolutionList.size() )
+   {
+      for ( int i = 0; i < mResolutionList.size(); i++ )
+      {
+         if ( width == mResolutionList[i].w
+              && height == mResolutionList[i].h
+              && bpp == mResolutionList[i].bpp )
+         {
+            IsInList = true;
+            break;
+         }
+      }
+
+      if ( !IsInList )
+      {
+         Con::printf( "Selected resolution not available: %d %d %d",
+            width, height, bpp);
+         return false;
+      }
+   }
+   else
+   {
+      AssertFatal( false, "No resolution list found!!" );
+   }
+
+   // Here if we found a matching resolution in the list
+
+   bool needResurrect = false;
+   if (gPlatState.windowCreated)
+   {
+      Con::printf( "Killing the texture manager..." );
+      Game->textureKill();
+      needResurrect = true;
+   }
+
+   // Set the desired GL Attributes
+   SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+   SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
+   SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 0);
+   SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 0);
+   SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, 0);
+   SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 0);
+
+   U32 flags = SDL_OPENGL;
+   if (fullScreen)
+      flags |= SDL_FULLSCREEN;
+
+   Con::printf( "Setting screen mode to %dx%dx%d (%s)...", width, height,
+      bpp, ( fullScreen ? "fs" : "w" ) );
+
+   // set the new video mode
+   if (SDL_SetVideoMode(width, height, bpp, flags) == NULL)
+   {
+      Con::printf("Unable to set SDL Video Mode: %s", SDL_GetError());
+      return false;
+   }
+
+   PrintGLAttributes();
+
+   // clear screen here to prevent buffer garbage from being displayed when
+   // video mode is switched
+   glClearColor(0.0, 0.0, 0.0, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT);
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+   if ( needResurrect )
+   {
+      // Reload the textures:
+      Con::printf( "Resurrecting the texture manager..." );
+      Game->textureResurrect();
+   }
+
+   if ( gGLState.suppSwapInterval )
+      setVerticalSync( !Con::getBoolVariable( "$pref::Video::disableVerticalSync" ) );
+
+   // set various other parameters
+   gPlatState.windowCreated = true;
+   smCurrentRes = NewResolution;
+   Platform::setWindowSize ( width, height );
+   smIsFullScreen = fullScreen;
+   Con::setBoolVariable( "$pref::Video::fullScreen", smIsFullScreen );
+   char tempBuf[15];
+   dSprintf( tempBuf, sizeof( tempBuf ), "%d %d %d",
+      smCurrentRes.w, smCurrentRes.h, smCurrentRes.bpp );
+   Con::setVariable( "$pref::Video::resolution", tempBuf );
+
+   // post a TORQUE_SETVIDEOMODE user event
+   static SDL_Event sVideoChangeEvent;
+   sVideoChangeEvent.type = SDL_USEREVENT;
+   sVideoChangeEvent.user.code = TORQUE_SETVIDEOMODE;
+   sVideoChangeEvent.user.data1 = NULL;
+   sVideoChangeEvent.user.data2 = NULL;
+   SDL_PushEvent(&sVideoChangeEvent);
+
+   // reset the caption
+   SDL_WM_SetCaption(gPlatState.appWindowTitle, NULL);
+
+   // repaint
+   if ( repaint )
+      Con::evaluate( "resetCanvas();" );
+
+   return true;
+}
+
+//------------------------------------------------------------------------------
+void OpenGLDevice::swapBuffers()
+{
+   SDL_GL_SwapBuffers();
+}
+
+//------------------------------------------------------------------------------
+const char* OpenGLDevice::getDriverInfo()
+{
+   const char* vendorString   = (const char*) glGetString( GL_VENDOR );
+   const char* rendererString = (const char*) glGetString( GL_RENDERER );
+   const char* versionString  = (const char*) glGetString( GL_VERSION );
+   const char* extensionsString = (const char*) glGetString( GL_EXTENSIONS );
+
+   U32 bufferLen = ( vendorString ? dStrlen( vendorString ) : 0 )
+                 + ( rendererString ? dStrlen( rendererString ) : 0 )
+                 + ( versionString  ? dStrlen( versionString ) : 0 )
+                 + ( extensionsString ? dStrlen( extensionsString ) : 0 )
+                 + 4;
+
+   char* returnString = Con::getReturnBuffer( bufferLen );
+   dSprintf( returnString, bufferLen, "%s\t%s\t%s\t%s",
+      ( vendorString ? vendorString : "" ),
+      ( rendererString ? rendererString : "" ),
+      ( versionString ? versionString : "" ),
+      ( extensionsString ? extensionsString : "" ) );
+
+   return( returnString );
+}
+
+//------------------------------------------------------------------------------
+bool OpenGLDevice::getGammaCorrection(F32 &g)
+{
+   g = 1.0f;
+   return true;
+}
+
+//------------------------------------------------------------------------------
+bool OpenGLDevice::setGammaCorrection(F32 g)
+{
+   U16 redtable[256];
+   U16 greentable[256];
+   U16 bluetable[256];
+
+   for (U16 i = 0; i < 256; ++i)
+      redtable[i] = static_cast<U16>(mPow((F32) i/256.0f, g) * 65535.0f);
+   dMemcpy(greentable,redtable,256*sizeof(U16));
+   dMemcpy(bluetable,redtable,256*sizeof(U16));
+
+   S32 ok = SDL_SetGammaRamp(redtable, greentable, bluetable);
+   if (ok == -1)
+      Con::warnf("Error setting gamma correction: %s", SDL_GetError());
+
+   return ok != -1;
+}
+
+//------------------------------------------------------------------------------
+bool OpenGLDevice::setVerticalSync( bool on )
+{
+   Con::printf("WARNING: OpenGLDevice::setVerticalSync is unimplemented %s %d\n", __FILE__, __LINE__);
+   return false;
+}
+
+//------------------------------------------------------------------------------
+DisplayDevice* OpenGLDevice::create()
+{
+   return new OpenGLDevice();
+}
+

+ 57 - 0
engine/source/platformEmscripten/EmscriptenOGLVideo.h

@@ -0,0 +1,57 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _EMSCRIPTENOGLVIDEO_H_
+#define _EMSCRIPTENOGLVIDEO_H_
+
+#include "platform/platformVideo.h"
+
+
+class OpenGLDevice : public DisplayDevice
+{
+      static bool smCanSwitchBitDepth;
+
+      bool mRestoreGamma;
+      U16  mOriginalRamp[256*3];
+
+      void addResolution(S32 width, S32 height, bool check=true);
+
+   public:
+      OpenGLDevice();
+      virtual ~OpenGLDevice();
+
+      void initDevice();
+      bool activate( U32 width, U32 height, U32 bpp, bool fullScreen );
+      void shutdown();
+      void destroy();
+      bool setScreenMode( U32 width, U32 height, U32 bpp, bool fullScreen, bool forceIt = false, bool repaint = true );
+      void swapBuffers();
+      const char* getDriverInfo();
+      bool getGammaCorrection(F32 &g);
+      bool setGammaCorrection(F32 g);
+      bool setVerticalSync( bool on );
+      void loadResolutions();
+
+      static DisplayDevice* create();
+};
+
+#endif //_EMSCRIPTENOGLVIDEO_H_

+ 237 - 0
engine/source/platformEmscripten/EmscriptenOutlineGL.cpp

@@ -0,0 +1,237 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+// The debug render modes are only built in a debug build, 
+// partially because a release build should not need them
+// and partially because using aglMacro.h or cglMacro.h would prevent us from
+// playing this little function-pointer-hijacking trick
+#if defined(TORQUE_DEBUG)
+
+#define NO_REDEFINE_GL_FUNCS
+
+#include "platformEmscriptenplatformGL.h"
+#include "console/console.h"
+
+bool gOutlineEnabled = false;
+
+void (* glDrawElementsProcPtr) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) = glDrawElements;
+void (* glDrawArraysProcPtr) (GLenum mode, GLint first, GLsizei count) = glDrawArrays;
+void (* glNormDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) = glDrawElements;
+void (* glNormDrawArrays) (GLenum mode, GLint first, GLsizei count) = glDrawArrays;      
+
+
+/// A utility for the outline drawing routines
+static U32 getIndex(GLenum type, const void *indices, U32 i)
+{
+   if(type == GL_UNSIGNED_BYTE)
+      return ((U8 *) indices)[i];
+   else if(type == GL_UNSIGNED_SHORT)
+      return ((U16 *) indices)[i];
+   else
+      return ((U32 *) indices)[i];
+}
+
+void glOutlineDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+{ 
+   if(mode == GL_POLYGON)
+      mode = GL_LINE_LOOP;
+
+   if(mode == GL_POINTS || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP || mode == GL_LINES)   
+      glDrawElements( mode, count, type, indices );
+   else
+   {
+      glBegin(GL_LINES);
+      if(mode == GL_TRIANGLE_STRIP)
+      {
+         U32 i;
+         for(i = 0; i < count - 1; i++)
+         {
+            glArrayElement(getIndex(type, indices, i));
+            glArrayElement(getIndex(type, indices, i + 1));
+            if(i + 2 != count)
+            {
+               glArrayElement(getIndex(type, indices, i));
+               glArrayElement(getIndex(type, indices, i + 2));
+            }
+         }
+      }
+      else if(mode == GL_TRIANGLE_FAN)
+      {
+         for(U32 i = 1; i < count; i ++)
+         {
+            glArrayElement(getIndex(type, indices, 0));
+            glArrayElement(getIndex(type, indices, i));
+            if(i != count - 1)
+            {
+               glArrayElement(getIndex(type, indices, i));
+               glArrayElement(getIndex(type, indices, i + 1));
+            }
+         }
+      }
+      else if(mode == GL_TRIANGLES)
+      {
+         for(U32 i = 3; i <= count; i += 3)
+         {
+            glArrayElement(getIndex(type, indices, i - 3));
+            glArrayElement(getIndex(type, indices, i - 2));
+            glArrayElement(getIndex(type, indices, i - 2));
+            glArrayElement(getIndex(type, indices, i - 1));
+            glArrayElement(getIndex(type, indices, i - 3));
+            glArrayElement(getIndex(type, indices, i - 1));
+         }
+      }
+      else if(mode == GL_QUADS)
+      {
+         for(U32 i = 4; i <= count; i += 4)
+         {
+            glArrayElement(getIndex(type, indices, i - 4));
+            glArrayElement(getIndex(type, indices, i - 3));
+            glArrayElement(getIndex(type, indices, i - 3));
+            glArrayElement(getIndex(type, indices, i - 2));
+            glArrayElement(getIndex(type, indices, i - 2));
+            glArrayElement(getIndex(type, indices, i - 1));
+            glArrayElement(getIndex(type, indices, i - 4));
+            glArrayElement(getIndex(type, indices, i - 1));
+         }
+      }
+      else if(mode == GL_QUAD_STRIP)
+      {
+         if(count < 4)
+            return;
+         glArrayElement(getIndex(type, indices, 0));
+         glArrayElement(getIndex(type, indices, 1));
+         for(U32 i = 4; i <= count; i += 2)
+         {
+            glArrayElement(getIndex(type, indices, i - 4));
+            glArrayElement(getIndex(type, indices, i - 2));
+
+            glArrayElement(getIndex(type, indices, i - 3));
+            glArrayElement(getIndex(type, indices, i - 1));
+
+            glArrayElement(getIndex(type, indices, i - 2));
+            glArrayElement(getIndex(type, indices, i - 1));
+         }
+      }
+      glEnd();
+   }
+}
+
+void glOutlineDrawArrays(GLenum mode, GLint first, GLsizei count) 
+{ 
+   if(mode == GL_POLYGON)
+      mode = GL_LINE_LOOP;
+
+   if(mode == GL_POINTS || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP || mode == GL_LINES)   
+      glDrawArrays( mode, first, count );
+   else
+   {
+      glBegin(GL_LINES);
+      if(mode == GL_TRIANGLE_STRIP)
+      {
+         U32 i;
+         for(i = 0; i < count - 1; i++) 
+         {
+            glArrayElement(first + i);
+            glArrayElement(first + i + 1);
+            if(i + 2 != count)
+            {
+               glArrayElement(first + i);
+               glArrayElement(first + i + 2);
+            }
+         }
+      }
+      else if(mode == GL_TRIANGLE_FAN)
+      {
+         for(U32 i = 1; i < count; i ++)
+         {
+            glArrayElement(first);
+            glArrayElement(first + i);
+            if(i != count - 1)
+            {
+               glArrayElement(first + i);
+               glArrayElement(first + i + 1);
+            }
+         }
+      }
+      else if(mode == GL_TRIANGLES)
+      {
+         for(U32 i = 3; i <= count; i += 3)
+         {
+            glArrayElement(first + i - 3);
+            glArrayElement(first + i - 2);
+            glArrayElement(first + i - 2);
+            glArrayElement(first + i - 1);
+            glArrayElement(first + i - 3);
+            glArrayElement(first + i - 1);
+         }
+      }
+      else if(mode == GL_QUADS)
+      {
+         for(U32 i = 4; i <= count; i += 4)
+         {
+            glArrayElement(first + i - 4);
+            glArrayElement(first + i - 3);
+            glArrayElement(first + i - 3);
+            glArrayElement(first + i - 2);
+            glArrayElement(first + i - 2);
+            glArrayElement(first + i - 1);
+            glArrayElement(first + i - 4);
+            glArrayElement(first + i - 1);
+         }
+      }
+      else if(mode == GL_QUAD_STRIP)
+      {
+         if(count < 4)
+            return;
+         glArrayElement(first + 0);
+         glArrayElement(first + 1);
+         for(U32 i = 4; i <= count; i += 2)
+         {
+            glArrayElement(first + i - 4);
+            glArrayElement(first + i - 2);
+
+            glArrayElement(first + i - 3);
+            glArrayElement(first + i - 1);
+
+            glArrayElement(first + i - 2);
+            glArrayElement(first + i - 1);
+         }
+      }
+      glEnd();
+   }
+}
+
+ConsoleFunction(GLEnableOutline,void,2,2,"GLEnableOutline( true | false ) - sets whether to render wireframe") 
+{
+   gOutlineEnabled = dAtob(argv[1]);
+   if(gOutlineEnabled)
+   {
+      glDrawElementsProcPtr = glOutlineDrawElements;
+      glDrawArraysProcPtr = glOutlineDrawArrays;
+      Con::printf("swapped to outline mode funcs");
+   } else {
+      glDrawElementsProcPtr = glDrawElements;
+      glDrawArraysProcPtr = glDrawArrays;
+      Con::printf("swapped to normal funcs");
+   }
+}
+#endif

+ 51 - 0
engine/source/platformEmscripten/EmscriptenOutlineGL.h

@@ -0,0 +1,51 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef __EMSCRIPTENOUTLINE__
+#define __EMSCRIPTENOUTLINE__
+
+#if defined(TORQUE_DEBUG)
+#ifndef __GL_OUTLINE_FUNCS__
+#define __GL_OUTLINE_FUNCS__
+
+extern bool gOutlineEnabled;
+
+extern void (* glDrawElementsProcPtr) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+extern void (* glDrawArraysProcPtr) (GLenum mode, GLint first, GLsizei count);
+
+void glOutlineDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+void glOutlineDrawArrays(GLenum mode, GLint first, GLsizei count);
+
+extern void (* glNormDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+extern void (* glNormDrawArrays) (GLenum mode, GLint first, GLsizei count);
+
+#ifndef NO_REDEFINE_GL_FUNCS
+#define glDrawElements glDrawElementsProcPtr
+#define glDrawArrays glDrawArraysProcPtr
+#else 
+//#warning glDrawElements and glDrawArrays not redefined
+#endif // NO_REDEFINE_GL_FUNCS
+#endif // __GL_OUTLINE_FUNCS__
+#endif // TORQUE_DEBUG
+
+#endif // __EMSCRIPTENOUTLINE__
+

+ 69 - 0
engine/source/platformEmscripten/EmscriptenPlatform.cpp

@@ -0,0 +1,69 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#include <unistd.h>
+#include "platform/platform.h"
+#include "console/console.h"
+#include "string/stringTable.h"
+#include "platform/platformInput.h"
+#include "platform/threads/thread.h"
+
+//-----------------------------------------------------------------------------
+const char* Platform::getUserDataDirectory() 
+{
+	return StringTable->insert("/.data");
+}
+
+//-----------------------------------------------------------------------------
+const char* Platform::getUserHomeDirectory() 
+{
+	return StringTable->insert("/home");
+}
+
+//-----------------------------------------------------------------------------
+StringTableEntry Platform::osGetTemporaryDirectory()
+{
+	return StringTable->insert("/tmp");
+}
+
+//-----------------------------------------------------------------------------
+S32 Platform::messageBox(const UTF8 *title, const UTF8 *message, MBButtons buttons, MBIcons icon)
+{
+    Platform::AlertOK( title, message );
+    return 1;
+}
+
+ConsoleFunction(shellExecute, bool, 2, 4, "(executable, [args], [directory])")
+{
+   return true;
+}
+
+
+void Input::setCursorShape(U32 cursorID)
+{
+    //no cursors on Android except Torque cursors
+}
+
+void Input::setCursorState(bool on)
+{
+}
+

+ 77 - 0
engine/source/platformEmscripten/EmscriptenProcessControl.cpp

@@ -0,0 +1,77 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platformEmscripten/EmscriptenConsole.h"
+#include "platform/event.h"
+#include "platform/platformInput.h"
+#include "platform/platformVideo.h"
+#include "game/gameInterface.h"
+
+
+#include <SDL/sdl.h>
+
+void Platform::postQuitMessage(const U32 in_quitVal)
+{
+   gPlatState.quit = true;
+   Event quitEvent;
+   quitEvent.type = QuitEventType;
+
+   Game->postEvent(quitEvent);
+}
+
+void Platform::debugBreak()
+{
+   Platform::outputDebugString((const char *)"\pDEBUG_BREAK!");
+}
+
+void Platform::forceShutdown(S32 returnValue)
+{
+   exit(returnValue);
+}   
+
+void Platform::restartInstance()
+{
+   if( Game->isRunning() )
+   {
+      Con::errorf("The game is still running, we cant relaunch now!");
+      return;
+   }
+   
+   Con::errorf("restartInstance is not supported on Emscripten");
+}
+
+//-----------------------------------------------------------------------------
+void Cleanup(bool minimal)
+{
+   if (!minimal)
+   {
+      Video::destroy();
+      Input::destroy();
+   }
+
+   EmscriptenConsole::destroy();
+#ifndef DEDICATED
+   SDL_Quit();
+#endif
+}
+

+ 53 - 0
engine/source/platformEmscripten/EmscriptenSemaphore.cpp

@@ -0,0 +1,53 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/platform.h"
+#include "platform/threads/semaphore.h"
+
+struct PlatformSemaphore
+{
+   S32 count;
+};
+
+Semaphore::Semaphore(S32 initialCount)
+{
+   bool ok;
+   PlatformSemaphore* semaphore = new PlatformSemaphore();
+   
+   semaphore->count = initialCount;
+   mData = semaphore;
+}
+
+Semaphore::~Semaphore()
+{
+   delete mData;
+}
+
+bool Semaphore::acquire( bool block, S32 timeoutMS )
+{
+   return true;
+}
+
+void Semaphore::release()
+{
+}

+ 400 - 0
engine/source/platformEmscripten/EmscriptenStrings.cpp

@@ -0,0 +1,400 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platform/platform.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include "console/console.h"
+
+char *dStrdup_r(const char *src, const char *file, dsize_t line)
+{
+   char *buffer = (char *) dMalloc_r(dStrlen(src) + 1, file, line);
+   dStrcpy(buffer, src);
+   return buffer;
+}
+
+char *dStrnew(const char *src)
+{
+   char *buffer = new char[dStrlen(src) + 1];
+   dStrcpy(buffer, src);
+   return buffer;
+}
+
+char* dStrcat(char *dst, const char *src)
+{
+   return strcat(dst,src);
+}   
+
+char* dStrncat(char *dst, const char *src, dsize_t len)
+{
+   return strncat(dst,src,len);
+}
+
+// concatenates a list of src's onto the end of dst
+// the list of src's MUST be terminated by a NULL parameter
+// dStrcatl(dst, sizeof(dst), src1, src2, NULL);
+char* dStrcatl(char *dst, dsize_t dstSize, ...)
+{
+   const char* src;
+   char *p = dst;
+
+   AssertFatal(dstSize > 0, "dStrcatl: destination size is set zero");
+   dstSize--;  // leave room for string termination
+
+   // find end of dst
+   while (dstSize && *p)
+   {
+       p++;
+      dstSize--;
+   }
+   
+   va_list args;
+   va_start(args, dstSize);
+
+   // concatenate each src to end of dst
+   while ( (src = va_arg(args, const char*)) != NULL )
+      while( dstSize && *src )
+      {
+         *p++ = *src++;
+         dstSize--;   
+      }
+
+   va_end(args);
+
+   // make sure the string is terminated 
+   *p = 0;
+
+   return dst;
+}
+
+// copy a list of src's into dst
+// the list of src's MUST be terminated by a NULL parameter
+// dStrccpyl(dst, sizeof(dst), src1, src2, NULL);
+char* dStrcpyl(char *dst, dsize_t dstSize, ...)
+{
+   const char* src;
+   char *p = dst;
+
+   AssertFatal(dstSize > 0, "dStrcpyl: destination size is set zero");
+   dstSize--;  // leave room for string termination
+
+   va_list args;
+   va_start(args, dstSize);
+
+   // concatenate each src to end of dst
+   while ( (src = va_arg(args, const char*)) != NULL )
+      while( dstSize && *src )
+      {
+         *p++ = *src++;
+         dstSize--;   
+      }
+
+   va_end(args);
+
+   // make sure the string is terminated 
+   *p = 0;
+
+   return dst;
+}
+
+int dStrcmp(const char *str1, const char *str2)
+{
+   return strcmp(str1, str2);   
+}
+
+int dStrcmp( const UTF16 *str1, const UTF16 *str2)
+{
+    int ret;
+    const UTF16 *a, *b;
+    a = str1;
+    b = str2;
+    
+    while(*a && *b && (ret = *a - *b) == 0)
+    {
+        a++, b++;
+    }
+    
+    if ( *a == 0 && *b != 0 )
+        return -1;
+    
+    if ( *b == 0 && *a != 0 )
+        return 1;
+    
+    return ret;
+}
+
+int dStricmp(const char *str1, const char *str2)
+{
+   char c1, c2;
+   while (1)
+   {
+      c1 = tolower(*str1++);
+      c2 = tolower(*str2++);
+      if (c1 < c2) return -1;
+      if (c1 > c2) return 1;
+      if (c1 == 0) return 0;
+   }
+}  
+
+int dStrncmp(const char *str1, const char *str2, dsize_t len)
+{
+   return strncmp(str1, str2, len);   
+}  
+ 
+int dStrnicmp(const char *str1, const char *str2, dsize_t len)
+{
+   S32 i;
+   char c1, c2;
+   for (i=0; i<len; i++)
+   {
+      c1 = tolower(*str1++);
+      c2 = tolower(*str2++);
+      if (c1 < c2) return -1;
+      if (c1 > c2) return 1;
+      if (!c1) return 0;
+     }
+   return 0;
+}   
+
+char* dStrcpy(char *dst, const char *src)
+{
+   AssertFatal(dst && src, "bad strings passed to dStrcpy()");
+   return strcpy(dst,src);
+}   
+
+char* dStrncpy(char *dst, const char *src, dsize_t len)
+{
+   return strncpy(dst,src,len);
+}   
+
+dsize_t dStrlen(const char *str)
+{
+   return str ? strlen(str) : 0;
+}   
+
+char* dStrupr(char *str)
+{
+   char* saveStr = str;
+   while (*str)
+   {
+      *str = toupper(*str);
+      str++;
+   }
+   return saveStr;
+}   
+
+char* dStrlwr(char *str)
+{
+   char* saveStr = str;
+   while (*str)
+   {
+      *str = tolower(*str);
+      str++;
+   }
+   return saveStr;
+}   
+
+char* dStrchr(char *str, int c)
+{
+   return strchr(str,c);
+}   
+
+const char* dStrchr(const char *str, int c)
+{
+   return strchr(str,c);
+}   
+
+const char* dStrrchr(const char *str, int c)
+{
+   return strrchr(str,c);
+}   
+
+char* dStrrchr(char *str, int c)
+{
+   return strrchr(str,c);
+}   
+
+dsize_t dStrspn(const char *str, const char *set)
+{
+   return(strspn(str, set));
+}
+
+dsize_t dStrcspn(const char *str, const char *set)
+{
+   return strcspn(str, set);
+}   
+
+
+char* dStrstr(char *str1, char *str2)
+{
+   return strstr(str1,str2);
+}
+
+char* dStrstr(const char *str1, const char *str2)
+{
+   return strstr(str1,str2);
+}   
+
+char* dStrtok(char *str, const char *sep)
+{
+   return strtok(str, sep);
+}
+
+int dAtoi(const char *str)
+{
+   if(!str)
+      return 0;
+   return atoi(str);
+}  
+
+float dAtof(const char *str)
+{
+   if(!str)
+      return 0;
+   return atof(str);   
+}   
+
+bool dAtob(const char *str)
+{
+   return !dStricmp(str, "true") || !dStricmp(str, "1") || (0!=dAtoi(str));
+}   
+
+bool dIsalnum(const char c)
+{
+   return isalnum(c);
+}
+
+bool dIsalpha(const char c)
+{
+   return(isalpha(c));
+}
+
+bool dIsspace(const char c)
+{
+   return(isspace(c));
+}
+
+bool dIsdigit(const char c)
+{
+   return(isdigit(c));
+}
+
+void dPrintf(const char *format, ...)
+{
+   va_list args;
+   va_start(args, format);
+   vprintf(format, args);
+   va_end(args);
+}
+
+int dVprintf(const char *format, va_list arglist)
+{
+   S32 len = vprintf(format, arglist);
+
+   return (len);
+}   
+
+int dSprintf(char *buffer, dsize_t bufferSize, const char *format, ...)
+{
+   va_list args;
+   va_start(args, format);
+   S32 len = vsnprintf(buffer, bufferSize, format, args);
+   va_end(args);
+
+   return (len);
+}
+
+int dVsprintf(char *buffer, dsize_t bufferSize, const char *format, va_list arglist)
+{
+   S32 len = vsnprintf(buffer, bufferSize, format, arglist);
+
+   return (len);
+}
+
+int dStrrev(char* str)
+{
+   int l=dStrlen(str)-1; //get the string length
+   for(int x=0;x < l;x++,l--)
+   {
+      str[x]^=str[l];  //triple XOR Trick
+      str[l]^=str[x];  //for not using a temp
+      str[x]^=str[l];
+   }
+   return l;
+}
+
+//-Mat hack
+int dItoa(int n, char s[])
+{
+  int i, sign;
+   
+   if ((sign = n) < 0)  /* record sign */
+      n = -n;          /* make n positivNSStringe */
+   i = 0;
+   do {       /* generate digits in reverse order */
+      s[i++] = n % 10 + '0';   /* get next digit */
+   } while ((n /= 10) > 0);     /* delete it */
+   if (sign < 0)
+      s[i++] = '-';
+   s[i] = '\0';
+    
+    // Reverse string.
+   dStrrev(s);
+    
+  // Return length.
+  return dStrlen(s);
+} 
+
+int dSscanf(const char *buffer, const char *format, ...)
+{
+   va_list args;
+   va_start(args, format);
+   int ret = vsscanf(buffer, format, args);
+   va_end(args);
+   return ret;
+}
+
+int dFflushStdout()
+{
+   return fflush(stdout);
+}
+
+int dFflushStderr()
+{
+   return fflush(stderr);
+}
+
+void dQsort(void *base, U32 nelem, U32 width, int (QSORT_CALLBACK *fcmp)(const void *, const void *))
+{
+   qsort(base, nelem, width, fcmp);
+}   
+
+StringTableEntry Platform::createUUID( void )
+{
+  Con::errorf("createUUID not supported on Emscripten");
+  return StringTable->insert("");
+}

+ 184 - 0
engine/source/platformEmscripten/EmscriptenThread.cpp

@@ -0,0 +1,184 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/threads/thread.h"
+#include "platform/platformSemaphore.h"
+#include "platform/threads/mutex.h"
+#include "platform/platformTLS.h"
+#include "memory/safeDelete.h"
+#include <stdlib.h>
+
+struct PlatformThreadData
+{
+   ThreadRunFunction       mRunFunc;
+   void*                   mRunArg;
+   Thread*                 mThread;
+   Semaphore               mGateway; // default count is 1
+   U32                     mThreadID;
+};
+
+//-----------------------------------------------------------------------------
+// Function:    ThreadRunHandler
+// Summary:     Calls Thread::run() with the thread's specified run argument.
+//               Neccesary because Thread::run() is provided as a non-threaded
+//               way to execute the thread's run function. So we have to keep
+//               track of the thread's lock here.
+static void *ThreadRunHandler(void * arg)
+{
+   PlatformThreadData *mData = reinterpret_cast<PlatformThreadData*>(arg);
+   Thread *thread = mData->mThread;
+
+   mData->mThreadID = ThreadManager::getCurrentThreadId();
+   ThreadManager::addThread(thread);
+   
+   // not possible with emscripten
+   AssertFatal(false, "Cannot run threads with emscripten");
+   //thread->run(mData->mRunArg);
+
+	mData->mGateway.release();
+   // we could delete the Thread here, if it wants to be auto-deleted...
+   if(thread->autoDelete)
+   {
+      ThreadManager::removeThread(thread);
+      delete thread;
+   }
+   // return value for pthread lib's benefit
+   return NULL;
+   // the end of this function is where the created pthread will die.
+}
+   
+//-----------------------------------------------------------------------------
+Thread::Thread(ThreadRunFunction func, void* arg, bool start_thread, bool autodelete)
+{
+   mData = new PlatformThreadData;
+   mData->mRunFunc = func;
+   mData->mRunArg = arg;
+   mData->mThread = this;
+   mData->mThreadID = 0;
+   autoDelete = autodelete;
+   
+   //if(start_thread)
+   //   start();
+}
+
+Thread::~Thread()
+{
+   stop();
+   join();
+
+   SAFE_DELETE(mData);
+}
+
+void Thread::start()
+{
+   if(isAlive())
+      return;
+
+   // cause start to block out other pthreads from using this Thread, 
+   // at least until ThreadRunHandler exits.
+   mData->mGateway.acquire();
+
+   // reset the shouldStop flag, so we'll know when someone asks us to stop.
+   shouldStop = false;
+
+   //pthread_create((pthread_t*)(&mData->mThreadID), NULL, ThreadRunHandler, mData);
+}
+
+bool Thread::join()
+{
+   if(!isAlive())
+      return true;
+
+   // not using pthread_join here because pthread_join cannot deal
+   // with multiple simultaneous calls.
+   mData->mGateway.acquire();
+   mData->mGateway.release();
+   return true;
+}
+
+void Thread::run(void* arg)
+{
+   //if(mData->mRunFunc)
+   //   mData->mRunFunc(arg);
+}
+
+bool Thread::isAlive()
+{
+   if(mData->mThreadID == 0)
+      return false;
+
+   if( mData->mGateway.acquire(false) ) 
+   {
+     mData->mGateway.release();
+     return false; // we got the lock, it aint alive.
+   }
+   else
+     return true; // we could not get the lock, it must be alive.
+}
+
+U32 Thread::getId()
+{
+   return mData->mThreadID;
+}
+
+U32 ThreadManager::getCurrentThreadId()
+{
+   return 0;//(U32)pthread_self();
+}
+
+bool ThreadManager::compare(U32 threadId_1, U32 threadId_2)
+{
+   return threadId_1 == threadId_2;//(bool)pthread_equal((pthread_t)threadId_1, (pthread_t)threadId_2);
+}
+
+
+
+class PlatformThreadStorage
+{
+public:
+   //pthread_key_t mThreadKey;
+};
+
+ThreadStorage::ThreadStorage()
+{
+   mThreadStorage = (PlatformThreadStorage *) mStorage;
+   constructInPlace(mThreadStorage);
+
+   //pthread_key_create(&mThreadStorage->mThreadKey, NULL);
+}
+
+ThreadStorage::~ThreadStorage()
+{
+   //pthread_key_delete(mThreadStorage->mThreadKey);
+}
+
+void *ThreadStorage::get()
+{
+   return NULL;//return pthread_getspecific(mThreadStorage->mThreadKey);
+}
+
+void ThreadStorage::set(void *value)
+{
+   return;//pthread_setspecific(mThreadStorage->mThreadKey, value);
+}
+

+ 88 - 0
engine/source/platformEmscripten/EmscriptenTime.cpp

@@ -0,0 +1,88 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "game/gameInterface.h"
+
+#include <SDL/SDL.h>
+#include <unistd.h>
+//--------------------------------------
+void Platform::getLocalTime(LocalTime &lt)
+{
+   // TODO
+	dMemset(&lt, '\0', sizeof(LocalTime));
+}   
+
+/// Gets the time in seconds since the Epoch
+U32 Platform::getTime()
+{
+   // TODO
+   return SDL_GetTicks() / 1000;
+}
+
+/// Gets the time in milliseconds since some epoch. In this case, system start time.
+/// Storing milisec in a U32 overflows every 49.71 days
+U32 Platform::getRealMilliseconds()
+{
+   return SDL_GetTicks();
+}   
+
+U32 Platform::getVirtualMilliseconds()
+{
+   return gPlatState.currentTime;   
+}   
+
+void Platform::advanceTime(U32 delta)
+{
+   gPlatState.currentTime += delta;
+}   
+
+void Platform::sleep(U32 ms)
+{
+   usleep( ms * 1000 );
+}
+
+#pragma mark ---- TimeManager ----
+
+//--------------------------------------
+void TimeManager::process()
+{
+   if (gPlatState.backgrounded)
+      gPlatState.sleepTicks = Platform::getBackgroundSleepTime();
+   else
+      gPlatState.sleepTicks = sgTimeManagerProcessInterval;
+         
+   U32 curTime = Platform::getRealMilliseconds(); // GTC returns Milliseconds, FYI.
+   S32 elapsedTime = curTime - gPlatState.lastTimeTick;
+
+   if(elapsedTime <= gPlatState.sleepTicks)
+   {
+      Platform::sleep(gPlatState.sleepTicks - elapsedTime);
+   }
+
+   gPlatState.lastTimeTick = Platform::getRealMilliseconds();
+
+   TimeEvent event;
+   event.elapsedTime = elapsedTime;
+   Game->postEvent(event);
+}

+ 508 - 0
engine/source/platformEmscripten/EmscriptenWindow.cpp

@@ -0,0 +1,508 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+
+
+#include "console/console.h"
+#include "io/fileStream.h"
+#include "game/resource.h"
+#include "game/version.h"
+#include "math/mRandom.h"
+#include "platformEmscripten/platformEmscripten.h"
+#include "platformEmscripten/EmscriptenConsole.h"
+#include "platform/event.h"
+#include "game/gameInterface.h"
+#include "platform/platform.h"
+#include "platform/platformAL.h"
+#include "platform/platformInput.h"
+#include "platform/platformVideo.h"
+#include "debug/profiler.h"
+#include "platformEmscripten/platformGL.h"
+#include "platformEmscripten/EmscriptenOGLVideo.h"
+
+#ifndef DEDICATED
+#include "platformEmscripten/EmscriptenInputManager.h"
+#endif
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h> // fork, execvp, chdir
+#include <time.h> // nanosleep
+
+#ifndef DEDICATED
+#include <SDL/SDL.h>
+#include <SDL/SDL_syswm.h>
+#include <SDL/SDL_version.h>
+
+extern bool InitOpenGL();
+extern void Cleanup(bool minimal=false);
+#endif
+
+extern "C"
+{
+    extern U32 _EmscriptenGetDesktopHeight();
+    extern U32 _EmscriptenGetDesktopWidth();
+    extern U32 _EmscriptenGetDesktopBpp();
+}
+
+EmscriptenPlatState::EmscriptenPlatState()
+{
+    captureDisplay = true;
+    fadeWindows = true;
+    backgrounded = false;
+    minimized = false;
+
+    quit = false;
+
+    portrait = true;//-Mat Android is in portrait mode by default
+
+
+    // start with something reasonable.
+    fullscreen = true;
+
+    osVersion = 0;
+
+    dStrcpy(appWindowTitle, "Emscripten Torque Game Engine");
+
+    // directory that contains main.cs . This will help us detect whether we are
+    // running with the scripts in the bundle or not.
+    mainDotCsDir = NULL;
+
+    useRedirect = true;
+    windowCreated = false;
+    dedicated = false;
+
+    printf("platstate init\n");
+}
+
+//------------------------------------------------------------------------------
+static void InitWindow(const Point2I &initialSize, const char *name)
+{
+    gPlatState.windowSize = initialSize;
+    gPlatState.setWindowTitle(name);
+}
+
+#ifndef DEDICATED
+//------------------------------------------------------------------------------
+static bool InitSDL()
+{
+   if (SDL_Init(SDL_INIT_VIDEO) != 0)
+      return false;
+
+   atexit(SDL_Quit);
+
+   SDL_SysWMinfo sysinfo;
+   SDL_VERSION(&sysinfo.version);
+   //if (SDL_GetWMInfo(&sysinfo) == 0)
+   //   return false;
+
+   return true;
+}
+
+//------------------------------------------------------------------------------
+static void SetAppState()
+{
+   U8 state = SDL_GetAppState();
+
+   // if we're not active but we have appactive and inputfocus, set window
+   // active and reactivate input
+   if ((gPlatState.backgrounded || !Input::isActive()) &&
+      state & SDL_APPACTIVE &&
+      state & SDL_APPINPUTFOCUS)
+   {
+      gPlatState.backgrounded = false;
+      Input::reactivate();
+      Con::printf("Input activated by SetAppState");
+   }
+   // if we are active, but we don't have appactive or input focus,
+   // deactivate input (if window not locked) and clear windowActive
+   else if (!gPlatState.backgrounded && 
+      !(state & SDL_APPACTIVE && state & SDL_APPINPUTFOCUS))
+   {
+      if (gPlatState.mouseLocked)
+         Input::deactivate();
+      gPlatState.backgrounded = true;
+      Con::printf("Input deactivated by SetAppState");
+   }
+}
+
+//------------------------------------------------------------------------------
+static S32 NumEventsPending()
+{
+   static const int MaxEvents = 255;
+   static SDL_Event events[MaxEvents];
+
+   SDL_PumpEvents();
+#ifdef DUMMY_PLATFORM
+   return 0;
+#else
+   return SDL_PeepEvents(events, MaxEvents, SDL_PEEKEVENT, 0, SDL_LASTEVENT);
+#endif
+}
+
+//------------------------------------------------------------------------------
+static bool ProcessMessages()
+{
+#ifndef DUMMY_PLATFORM
+   SDL_PumpEvents();
+
+   // We're going to have to maintain our own list of events here, since the emscripten API
+   // is a bit broken for our purposes...
+   gPlatState.eventList.clear();
+   gPlatState.eventList.reserve(255);
+
+   SDL_Event e;
+   while (SDL_PollEvent(&e))
+   {
+      gPlatState.eventList.push_back(e);
+   }
+
+   S32 numEvents = gPlatState.eventList.size();
+   //if (numEvents > 0)
+   //   Con::printf("ProcessMessages: %i events pending", numEvents);
+
+   if (numEvents == 0)
+      return true;
+
+   for (int i = 0; i < numEvents; ++i)
+   {
+      SDL_Event& event = gPlatState.eventList[i];
+      //Con::printf("Event.type == %u", event.type);
+      switch (event.type)
+      {
+         case SDL_QUIT:
+            return false;
+            break;
+         case SDL_VIDEORESIZE:
+         case SDL_VIDEOEXPOSE:
+            Game->refreshWindow();
+            break;
+         case SDL_USEREVENT:
+            Con::printf("User event handled");
+            if (event.user.code == TORQUE_SETVIDEOMODE)
+            {
+               SetAppState();
+               // SDL will send a motion event to restore the mouse position
+               // on the new window.  Ignore that if the window is locked.
+               if (gPlatState.mouseLocked)
+               {
+                  SDL_Event tempEvent;
+                  SDL_PeepEvents(&tempEvent, 1, SDL_GETEVENT, SDL_MOUSEMOTION,
+                     SDL_MOUSEMOTION);
+               }
+            }
+            break;
+         case SDL_ACTIVEEVENT:
+         Con::printf("Active event");
+            SetAppState();
+            break;
+      }
+   }
+#endif
+   return true;
+}
+
+//------------------------------------------------------------------------------
+// send a destroy window event to the window.  assumes
+// window is created.
+void SendQuitEvent()
+{
+   SDL_Event quitevent;
+   quitevent.type = SDL_QUIT;
+   SDL_PushEvent(&quitevent);
+}
+#endif // DEDICATED
+
+//------------------------------------------------------------------------------
+static inline void Sleep(int secs, int nanoSecs)
+{
+   timespec sleeptime;
+   sleeptime.tv_sec = secs;
+   sleeptime.tv_nsec = nanoSecs;
+   nanosleep(&sleeptime, NULL);
+}
+
+#ifndef DEDICATED
+struct AlertWinState
+{
+      bool fullScreen;
+      bool cursorHidden;
+      bool inputGrabbed;
+};
+
+//------------------------------------------------------------------------------
+void DisplayErrorAlert(const char* errMsg, bool showSDLError)
+{
+   char fullErrMsg[2048];
+   dStrncpy(fullErrMsg, errMsg, sizeof(fullErrMsg));
+   
+   if (showSDLError)
+   {
+      const char* sdlerror = SDL_GetError();
+      if (sdlerror != NULL && dStrlen(sdlerror) > 0)
+      {
+         dStrcat(fullErrMsg, "  (Error: ");
+         dStrcat(fullErrMsg, sdlerror);
+         dStrcat(fullErrMsg, ")");
+      }
+   }
+   
+   Platform::AlertOK("Error", fullErrMsg);
+}
+
+
+//------------------------------------------------------------------------------
+static inline void AlertDisableVideo(AlertWinState& state)
+{
+
+   state.fullScreen = Video::isFullScreen();
+   state.cursorHidden = (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE);
+   state.inputGrabbed = (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON);
+
+   if (state.fullScreen)
+      SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
+   if (state.cursorHidden)
+      SDL_ShowCursor(SDL_ENABLE);
+   if (state.inputGrabbed)
+      SDL_WM_GrabInput(SDL_GRAB_OFF);
+}
+
+//------------------------------------------------------------------------------
+static inline void AlertEnableVideo(AlertWinState& state)
+{
+   if (state.fullScreen)
+      SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
+   if (state.cursorHidden)
+      SDL_ShowCursor(SDL_DISABLE);
+   if (state.inputGrabbed)
+      SDL_WM_GrabInput(SDL_GRAB_ON);
+}
+#endif // DEDICATED
+
+//------------------------------------------------------------------------------
+void Platform::setMouseLock(bool locked)
+{
+#ifndef DEDICATED
+   gPlatState.mouseLocked = locked;
+
+   UInputManager* uInputManager = 
+      dynamic_cast<UInputManager*>( Input::getManager() );
+
+   if ( uInputManager && uInputManager->isEnabled() && 
+      Input::isActive() )
+      uInputManager->setWindowLocked(locked);
+#endif
+}
+
+//------------------------------------------------------------------------------
+void Platform::process()
+{
+   PROFILE_START(XUX_PlatformProcess);
+
+   if (gPlatState.windowCreated)
+   {
+#ifndef DEDICATED
+      // process window events
+      PROFILE_START(XUX_ProcessMessages);
+      bool quit = !ProcessMessages();
+      PROFILE_END();
+      if(quit)
+      {
+         // generate a quit event
+         Event quitEvent;
+         quitEvent.type = QuitEventType;
+         Game->postEvent(quitEvent);
+      }
+
+      // process input events
+      PROFILE_START(XUX_InputProcess);
+      Input::process();
+      PROFILE_END();
+
+      // if we're not the foreground window, sleep for 1 ms
+      if (gPlatState.backgrounded)
+         Sleep(0, getBackgroundSleepTime() * 1000000);
+#endif
+   }
+   else
+   {
+     Sleep(0, getBackgroundSleepTime() * 1000000);
+   }
+   PROFILE_END();
+}
+
+//------------------------------------------------------------------------------
+const Point2I &Platform::getWindowSize()
+{
+   return gPlatState.windowSize;
+}
+
+//------------------------------------------------------------------------------
+void Platform::setWindowSize( U32 newWidth, U32 newHeight )
+{
+    gPlatState.windowSize = Point2I(newWidth, newHeight);
+}
+
+//------------------------------------------------------------------------------
+void Platform::minimizeWindow()
+{
+#ifndef DEDICATED
+   if (gPlatState.windowCreated)
+      SDL_WM_IconifyWindow();
+#endif
+}
+
+//------------------------------------------------------------------------------
+void Platform::restoreWindow()
+{
+}
+
+//------------------------------------------------------------------------------
+void Platform::shutdown()
+{
+   Cleanup();
+}
+
+//------------------------------------------------------------------------------
+void Platform::init()
+{
+   Con::printf("Platform::init");
+
+   // Set the platform variable for the scripts
+   Con::setVariable( "$platform", "x86UNIX" );
+   Con::setVariable( "$platformUnixType", "emscripten" );
+
+   EmscriptenConsole::create();
+   
+#ifndef DEDICATED
+   Con::printf("Dedicated == %i", gPlatState.dedicated);
+   // if we're not dedicated do more initialization
+   //if (!gPlatState.dedicated)
+   {
+     printf("Init non-dedicated\n");
+      // init SDL
+      if (!InitSDL())
+      {
+         Con::printf( "   Unable to initialize SDL." );
+         Platform::AlertOK("Error", "Unable to initialize SDL.");
+         exit(1);
+      }
+
+      // initialize input
+      Input::init();
+
+      Con::printf( "Video Init:" );
+
+      // initialize video
+      Video::init();
+      if ( Video::installDevice( OpenGLDevice::create() ) )
+         Con::printf( "   OpenGL display device detected." );
+      else
+         Con::printf( "   OpenGL display device not detected." );
+      
+      Con::printf(" ");
+   }
+#endif
+}
+
+//------------------------------------------------------------------------------
+void Platform::initWindow(const Point2I &initialSize, const char *name)
+{
+#ifndef DEDICATED
+   // initialize window
+   InitWindow(initialSize, name);
+   if (!InitOpenGL()) {
+      Con::printf( "   Unable to init OpenGL window." );
+      exit(1);
+   }
+#endif
+}
+
+//------------------------------------------------------------------------------
+// Web browser function:
+//------------------------------------------------------------------------------
+bool Platform::openWebBrowser( const char* webAddress )
+{
+    return false;
+}
+
+//------------------------------------------------------------------------------
+ConsoleFunction( getDesktopResolution, const char*, 1, 1, 
+   "getDesktopResolution()" )
+{
+   if (!gPlatState.windowCreated)
+      return "0 0 0";
+
+   char buffer[256];
+   char* returnString = Con::getReturnBuffer( dStrlen( buffer ) + 1 );
+
+   Resolution res = Video::getDesktopResolution();
+
+   dSprintf( buffer, sizeof( buffer ), "%d %d %d", 
+      res.w,
+      res.h, 
+      res.bpp );
+   dStrcpy( returnString, buffer );
+   return( returnString );
+}
+
+//------------------------------------------------------------------------------
+// Silly Korean registry key checker:
+//------------------------------------------------------------------------------
+ConsoleFunction( isKoreanBuild, bool, 1, 1, "isKoreanBuild()" )
+{
+   Con::printf("WARNING: isKoreanBuild() is unimplemented");
+   return false;
+}
+
+//------------------------------------------------------------------------------
+
+void Platform::setWindowTitle( const char* title )
+{
+#ifndef DEDICATED
+   gPlatState.setWindowTitle(title);
+   SDL_WM_SetCaption(gPlatState.appWindowTitle, NULL);
+#endif
+}
+
+//------------------------------------------------------------------------------
+
+Resolution Video::getDesktopResolution()
+{
+   Resolution  Result;
+
+   Result.h   = _EmscriptenGetDesktopHeight();
+   Result.w   = _EmscriptenGetDesktopWidth();
+   Result.bpp  = _EmscriptenGetDesktopBpp();
+
+  return Result;
+}
+
+//-----------------------------------------------------------------------------
+void Platform::outputDebugString( const char *string )
+{
+    fprintf(stderr, "%s", string);
+    fprintf(stderr, "\n" );
+    fflush(stderr);
+}

+ 77 - 0
engine/source/platformEmscripten/dummy.c

@@ -0,0 +1,77 @@
+// Dummy file for testing out Emscripten build with plain GCC
+
+typedef signed char        S8;      ///< Compiler independent Signed Char
+typedef unsigned char      U8;      ///< Compiler independent Unsigned Char
+
+typedef signed short       S16;     ///< Compiler independent Signed 16-bit short
+typedef unsigned short     U16;     ///< Compiler independent Unsigned 16-bit short
+
+typedef signed int         S32;     ///< Compiler independent Signed 32-bit integer
+typedef unsigned int       U32;     ///< Compiler independent Unsigned 32-bit integer
+
+typedef float              F32;     ///< Compiler independent 32-bit float
+typedef double             F64;     ///< Compiler independent 64-bit float
+
+
+//------------------------------------------------------------------------------
+//------------------------------------- String Types
+
+typedef char           UTF8;        ///< Compiler independent 8  bit Unicode encoded character
+typedef unsigned short UTF16;       ///< Compiler independent 16 bit Unicode encoded character
+typedef unsigned int   UTF32;       ///< Compiler independent 32 bit Unicode encoded character
+
+typedef const char* StringTableEntry;
+
+U32 _EmscriptenGetDesktopHeight()
+{
+	return 600;
+}
+
+U32 _EmscriptenGetDesktopWidth()
+{
+	return 800;
+}
+
+U32 _EmscriptenGetDesktopBpp()
+{
+	return 32;
+}
+
+int js_AlertOK(const char *title, const char *message)
+{
+	return 0;
+}
+
+int js_AlertOKCancel(const char *title, const char *message)
+{
+	return 0;
+}
+
+int js_AlertRetry(const char *title, const char *message)
+{
+	return 0;
+}
+
+int js_AlertYesNo(const char *title, const char *message)
+{
+	return 0;
+}
+
+void step_warn()
+{
+}
+
+void js_ConsoleEnabled(const char *prompt)
+{
+
+}
+
+void js_ConsoleDisabled()
+{
+
+}
+
+void js_ConsoleLine(const char *message)
+{
+
+}

+ 199 - 0
engine/source/platformEmscripten/main.cpp

@@ -0,0 +1,199 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#include "platformEmscripten/platformEmscripten.h"
+#include "platform/threads/thread.h"
+#include "game/gameInterface.h"
+#include "io/fileObject.h"
+#include "game/version.h"
+
+
+#ifndef DUMMY_PLATFORM
+#include <emscripten/emscripten.h>
+#endif
+
+//------------------------------------------------------------------------------
+
+S32 gLastStart = 0;
+EmscriptenPlatState gPlatState;
+
+bool appIsRunning = true;
+
+int _EmscriptenRunTorqueMain()
+{
+  gPlatState.firstThreadId = ThreadManager::getCurrentThreadId();
+   
+   printf("performing mainInit()\n");
+   
+   gPlatState.lastTimeTick = Platform::getRealMilliseconds();
+   
+   if(!Game->mainInitialize(gPlatState.argc, gPlatState.argv))
+   {
+     return 0;
+   }
+
+   return 1;
+}
+
+
+void _EmscriptenGameInnerLoop()
+{
+   if (!appIsRunning)
+   {
+      return;
+   }
+   else if (Game->isRunning())
+   {
+      S32 start = Platform::getRealMilliseconds();
+     
+      Game->mainLoop();
+         
+      gLastStart = start;
+      
+   }
+   else
+   {
+     Game->mainShutdown();
+      
+     // Need to actually exit the application now
+     exit(0);
+   }
+}
+
+void _EmscriptenGameResignActive()
+{
+   if ( Con::isFunction("onEmscriptenResignActive") )
+      Con::executef( 1, "onEmscriptenResignActive" );
+   
+   appIsRunning = false;
+}
+
+void _EmscriptenGameBecomeActive()
+{
+   if ( Con::isFunction("onEmscriptenBecomeActive") )
+      Con::executef( 1, "onEmscriptenBecomeActive" );
+   
+   appIsRunning = true;
+}
+
+void _EmscriptenGameWillTerminate()
+{
+   if ( Con::isFunction("onEmscriptenWillTerminate") )
+      Con::executef( 1, "onEmscriptenWillTerminate" );
+   
+   Con::executef( 1, "onExit" );
+   
+   Game->mainShutdown();
+}
+
+static void _EmscriptenGetTxtFileArgs(int &argc, char** argv, int maxargc)
+{
+   argc = 0;
+   
+   const U32 kMaxTextLen = 2048;
+   
+   U32 textLen;
+   
+   char* text = new char[kMaxTextLen];
+   
+   // Open the file, kick out if we can't
+   File cmdfile;
+   
+   File::Status err = cmdfile.open("EmscriptenCmdLine.txt", cmdfile.Read);
+   
+   // Re-organise function to handle memory deletion better
+   if (err == File::Ok)
+   {
+      // read in the first kMaxTextLen bytes, kick out if we get errors or no data
+      err = cmdfile.read(kMaxTextLen-1, text, &textLen);
+      
+      if (((err == File::Ok || err == File::EOS) || textLen > 0))
+      {
+         // Null terminate
+         text[textLen++] = '\0';
+         
+         // Truncate to the 1st line of the file
+         for(int i = 0; i < textLen; i++)
+         {
+            if( text[i] == '\n' || text[i] == '\r' )
+            {
+               text[i] = '\0';
+               textLen = i+1;
+               break;
+            }
+         }
+         
+         // Tokenize the args with nulls, save them in argv, count them in argc
+         char* tok;
+         
+         for(tok = dStrtok(text, " "); tok && argc < maxargc; tok = dStrtok(NULL, " "))
+            argv[argc++] = tok;
+     }
+   }
+   
+   // Close file and delete memory before returning
+   cmdfile.close();
+   
+   delete[] text;
+   
+   text = NULL;
+}
+
+int main(int argc, char **argv)
+{      
+   // get the actual command line args
+   S32   newArgc = argc;
+   
+   const char* newArgv[10];
+   
+   for(int i=0; i < argc && i < 10; i++)
+      newArgv[i] = argv[i];
+   
+   // get the text file args
+   S32 textArgc;
+   char* textArgv[10];
+   
+   _EmscriptenGetTxtFileArgs(textArgc, textArgv, 10);
+   
+   // merge them
+   int i=0;
+   
+   while(i < textArgc && newArgc < 10)
+      newArgv[newArgc++] = textArgv[i++];
+   
+   // store them in platState
+   gPlatState.argc = newArgc;
+   gPlatState.argv = newArgv;
+
+   if (_EmscriptenRunTorqueMain() > 0)
+   {
+#ifndef DUMMY_PLATFORM
+      emscripten_set_main_loop(_EmscriptenGameInnerLoop, 60, false);
+#endif
+      return 0;
+   }
+   else
+   {
+      return 1;
+   }
+}
+

+ 73 - 0
engine/source/platformEmscripten/menus/popupMenu.cpp

@@ -0,0 +1,73 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platformEmscripten/platformEmscripten.h"
+#include "platform/menus/popupMenu.h"
+#include "memory/safeDelete.h"
+#include "gui/guiCanvas.h"
+
+S32 PopupMenu::insertItem(S32 pos, const char *title, const char* accel)
+{ return 0; }
+
+S32 PopupMenu::insertSubMenu(S32 pos, const char *title, PopupMenu *submenu)
+{ return 0; }
+
+void PopupMenu::removeItem(S32 itemPos)
+{}
+
+void PopupMenu::enableItem(S32 pos, bool enable)
+{}
+
+void PopupMenu::checkItem(S32 pos, bool checked)
+{}
+
+void PopupMenu::checkRadioItem(S32 firstPos, S32 lastPos, S32 checkPos)
+{}
+
+bool PopupMenu::isItemChecked(S32 pos)
+{ return false; }
+
+bool PopupMenu::canHandleID(U32 iD)
+{ return false; }
+
+bool PopupMenu::handleSelect(U32 command, const char *text /* = NULL */)
+{ return false; }
+
+void PopupMenu::showPopup(S32 x /* = -1 */, S32 y /* = -1 */)
+{}
+
+void PopupMenu::attachToMenuBar(S32 pos, const char *title)
+{}
+
+void PopupMenu::removeFromMenuBar()
+{}
+
+
+void PopupMenu::createPlatformPopupMenuData()
+{}
+
+void PopupMenu::deletePlatformPopupMenuData()
+{}
+
+void PopupMenu::createPlatformMenu()
+{}
+

+ 77 - 0
engine/source/platformEmscripten/platform.js

@@ -0,0 +1,77 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+mergeInto(LibraryManager.library, {
+
+js_AlertOK: function(title, message) {
+	alert(message);
+	return 1;
+},
+
+js_AlertOKCancel: function(title, message) {
+	alert(message);
+	return 1;
+},
+
+js_AlertRetry: function(title, message) {
+	alert(message);
+	return 1;
+},
+
+js_AlertYesNo: function(title, message) {
+	alert(message);
+	return 1;
+},
+
+js_AlertOk: function(title, message) {
+	alert(message);
+	return 1;
+},
+
+js_ConsoleEnabled: function(prompt) {
+	// TODO
+},
+
+js_ConsoleDisabled: function() {
+	// TODO
+},
+
+js_ConsoleLine: function(message) {
+},
+
+step_warn: function() {
+	console.log('step warn');
+},
+
+_EmscriptenGetDesktopHeight: function() {
+	return 768;
+},
+
+_EmscriptenGetDesktopWidth: function() {
+	return 1024;
+},
+
+_EmscriptenGetDesktopBpp: function() {
+	return 32;
+}
+
+});

+ 116 - 0
engine/source/platformEmscripten/platformEmscripten.h

@@ -0,0 +1,116 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _PLATFORMEMSCRIPTEN_H_
+#define _PLATFORMEMSCRIPTEN_H_
+
+#include "platform/platform.h"
+#include "math/mMath.h"
+
+#include "platformEmscripten/EmscriptenOGLVideo.h"
+
+#include <SDL/sdl.h>
+
+#define PREF_DIR_ROOT "/.torque"
+#define PREF_DIR_GAME_NAME "T2D"
+
+// event codes for custom SDL events
+const S32 TORQUE_SETVIDEOMODE = 1;
+
+class EmscriptenPlatState
+{
+public:
+    bool              captureDisplay;
+    bool              fadeWindows;
+
+    char              appWindowTitle[256];
+    bool              quit;
+    bool              ctxNeedsUpdate;
+
+    bool			portrait;
+    
+    U32               currentTime;
+    bool				 fullscreen;
+
+    U32               osVersion;
+
+    U32               firstThreadId;
+    U32               torqueThreadId;
+
+    RandomLCG         platRandom;
+
+    bool              mouseLocked;
+    bool              backgrounded;
+    bool              minimized;
+
+    U32               sleepTicks;
+    U32               lastTimeTick;
+
+    Point2I           windowSize;
+    bool              windowCreated;
+
+    U32               appReturn;
+
+    int               argc;
+    const char**      argv;
+
+    bool              useRedirect;
+
+    bool              dedicated;
+
+    // JMQTODO: make these be class members
+    const int MaxEvents = 255;
+    Vector<SDL_Event> eventList;
+
+    StringTableEntry  mainDotCsDir;
+
+    EmscriptenPlatState();
+
+
+    void setWindowTitle(const char *title)
+    {
+        dStrncpy(appWindowTitle, title, sizeof(appWindowTitle));
+    }
+};
+
+/// Global singleton that encapsulates a lot of mac platform state & globals.
+extern EmscriptenPlatState gPlatState;
+
+/// @name Misc Emscripten Plat Functions
+/// Functions that are used by multiple files in the mac plat, but too trivial
+/// to require their own header file.
+/// @{
+/// Fills gGLState with info about this gl renderer's capabilities.
+void getGLCapabilities(void);
+
+
+/// Display a file dialog.
+/// calls FileDialog::Execute() on \p dialog
+/// @param dialog The FileDialog object to Execute. A void* is used to cut down on header dependencies.
+/// @see platform/nativeDialogs/fileDialog.h
+void EmscriptenShowDialog(void* dialog);
+/// @}
+
+
+#endif //_PLATFORMEMSCRIPTEN_H_
+

+ 249 - 0
engine/source/platformEmscripten/platformGL.h

@@ -0,0 +1,249 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+// Portions Copyright (c) 2014 James S Urquhart
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+
+#ifndef _PLATFORMGL_H_
+#define _PLATFORMGL_H_
+
+//#define DUMMY_GL
+
+#ifdef DUMMY_GL
+
+#include "platformWin32/gl_types.h"
+
+#define GLAPI 
+#define GLAPIENTRY
+
+#include "platformWin32/gl_types.h"
+
+#define GL_FUNCTION(fn_type,fn_name,fn_args, fn_value)  fn_type fn_name fn_args;
+#include "platform/GLCoreFunc.h"
+#include "platform/GLExtFunc.h"
+#undef GL_FUNCTION
+
+void gluOrtho2D( GLfloat, GLfloat, GLfloat, GLfloat );
+GLint gluProject( GLdouble winx, GLdouble winy, GLdouble winz, const F64 *model, const F64 * proj, const GLint * vp, F64 * x, F64 * y, F64 * z );
+GLint gluUnProject( GLdouble winx, GLdouble winy, GLdouble winz, const F64 *model, const F64 * proj, const GLint * vp, F64 * x, F64 * y, F64 * z );
+
+#else
+
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+void gluOrtho2D( GLfloat, GLfloat, GLfloat, GLfloat );
+GLint gluProject( GLdouble winx, GLdouble winy, GLdouble winz, const F64 *model, const F64 * proj, const GLint * vp, F64 * x, F64 * y, F64 * z );
+GLint gluUnProject( GLdouble winx, GLdouble winy, GLdouble winz, const F64 *model, const F64 * proj, const GLint * vp, F64 * x, F64 * y, F64 * z );
+
+#endif
+
+
+
+#define MIN_RESOLUTION_X				1
+#define MIN_RESOLUTION_Y				1
+#define MIN_RESOLUTION_BIT_DEPTH		16
+#define MIN_RESOLUTION_XY_STRING		"480 320"
+
+#define EMSCRIPTEN_DEFAULT_RESOLUTION_X    1024
+#define EMSCRIPTEN_DEFAULT_RESOLUTION_Y    768
+
+#define EMSCRIPTEN_DEFAULT_RESOLUTION_BIT_DEPTH	32
+
+#define EMSCRIPTEN_SCREEN_PORTRAIT			0
+#define EMSCRIPTEN_SCREEN_LANDSCAPE			1
+#define EMSCRIPTEN_SCREEN_RIGHT_SIDE_UP		3
+#define EMSCRIPTEN_SCREEN_UPSIDE_DOWN		4
+
+
+/// Allows outline mode drawing via a function pointer swapping trick.
+/// Must be included AFTER all the OpenGL headers.
+#include "platformEmscripten/EmscriptenOutlineGL.h"
+
+// these are extensions for glAllocateVertexBufferEXT
+#define GL_V12MTVFMT_EXT                      0x8702
+#define GL_V12MTNVFMT_EXT                     0x8703
+#define GL_V12FTVFMT_EXT                      0x8704
+#define GL_V12FMTVFMT_EXT                     0x8705
+//------------------------------------------------------------------------------
+
+// make sure this is defined, as we need to use it when around.
+// some versions of OSX only define the SGIS version ( same hexcode )
+//#ifndef GL_CLAMP_TO_EDGE_EXT
+//#define GL_CLAMP_TO_EDGE_EXT                     0x812F
+//#endif
+
+/// GL state information.
+struct GLState
+{
+   bool suppARBMultitexture;
+   bool suppEXTblendcolor;
+   bool suppEXTblendminmax;
+   bool suppPackedPixels;
+   bool suppTexEnvAdd;
+   bool suppLockedArrays;
+
+   bool suppTextureEnvCombine;
+   bool suppVertexArrayRange;
+   bool suppFogCoord;
+   bool suppEdgeClamp;
+
+   bool suppTextureCompression;
+   bool suppS3TC;
+   bool suppFXT1;
+   bool suppTexAnisotropic;
+
+   bool suppPalettedTexture;
+   bool suppVertexBuffer;
+   bool suppSwapInterval;
+
+   GLint maxFSAASamples;
+
+   unsigned int triCount[4];
+   unsigned int primCount[4];
+   unsigned int primMode; // 0-3
+
+   GLfloat maxAnisotropy;
+   GLint   maxTextureUnits;
+};
+
+extern GLState gGLState;
+
+extern bool gOpenGLDisablePT;
+extern bool gOpenGLDisableCVA;
+extern bool gOpenGLDisableTEC;
+extern bool gOpenGLDisableARBMT;
+extern bool gOpenGLDisableFC;
+extern bool gOpenGLDisableTCompress;
+extern bool gOpenGLNoEnvColor;
+extern float gOpenGLGammaCorrection;
+extern bool gOpenGLNoDrawArraysAlpha;
+
+//------------------------------------------------------------------------------
+/// Inline state getters for dgl
+//------------------------------------------------------------------------------
+inline void dglSetRenderPrimType(unsigned int type)
+{
+   gGLState.primMode = type;
+}
+
+inline void dglClearPrimMetrics()
+{
+   for(int i = 0; i < 4; i++)
+      gGLState.triCount[i] = gGLState.primCount[i] = 0;
+}
+
+inline bool dglDoesSupportPalettedTexture()
+{
+   return gGLState.suppPalettedTexture && (gOpenGLDisablePT == false);
+}
+
+inline bool dglDoesSupportCompiledVertexArray()
+{
+   return gGLState.suppLockedArrays && (gOpenGLDisableCVA == false);
+}
+
+inline bool dglDoesSupportTextureEnvCombine()
+{
+   return gGLState.suppTextureEnvCombine && (gOpenGLDisableTEC == false);
+}
+
+inline bool dglDoesSupportARBMultitexture()
+{
+   return gGLState.suppARBMultitexture && (gOpenGLDisableARBMT == false);
+}
+
+inline bool dglDoesSupportEXTBlendColor()
+{
+   return gGLState.suppEXTblendcolor;
+}
+
+inline bool dglDoesSupportEXTBlendMinMax()
+{
+   return gGLState.suppEXTblendminmax;
+}
+
+inline bool dglDoesSupportVertexArrayRange()
+{
+   return gGLState.suppVertexArrayRange;
+}
+
+inline bool dglDoesSupportFogCoord()
+{
+   return gGLState.suppFogCoord && (gOpenGLDisableFC == false);
+}
+
+inline bool dglDoesSupportEdgeClamp()
+{
+   return gGLState.suppEdgeClamp;
+}
+
+inline bool dglDoesSupportTextureCompression()
+{
+   return gGLState.suppTextureCompression && (gOpenGLDisableTCompress == false);
+}
+
+inline bool dglDoesSupportS3TC()
+{
+   return gGLState.suppS3TC;
+}
+
+inline bool dglDoesSupportFXT1()
+{
+   return gGLState.suppFXT1;
+}
+
+inline bool dglDoesSupportTexEnvAdd()
+{
+   return gGLState.suppTexEnvAdd;
+}
+
+inline bool dglDoesSupportTexAnisotropy()
+{
+   return gGLState.suppTexAnisotropic;
+}
+
+inline bool dglDoesSupportVertexBuffer()
+{
+   return false;
+}
+
+inline GLfloat dglGetMaxAnisotropy()
+{
+   return gGLState.maxAnisotropy;
+}
+
+inline GLint dglGetMaxTextureUnits()
+{
+   if (dglDoesSupportARBMultitexture())
+      return gGLState.maxTextureUnits;
+   else
+      return 1; 
+}
+
+//------------------------------------------------------------------------------
+/// For radeon cards we can do fast FSAA mode switching.
+/// Sets Full Scene Anti-Aliasing (FSAA) samples ( 1x, 2x, 4x ) via aglSetInteger()
+//------------------------------------------------------------------------------
+#define ATI_FSAA_LEVEL ((unsigned long)510)  
+void dglSetFSAASamples(GLint aasamp);
+
+#endif // _PLATFORMGL_H_