2
0
Эх сурвалжийг харах

Initial iOS support.
Do not use glPolygonOffset() constant bias due to its inconsistency. Instead offset the projection matrix as necessary.
Do not use multiple glUniform calls to set an array of transposed matrices, as it is not guaranteed to work. Instead transpose all matrices first, then set them in one call.

Lasse Öörni 13 жил өмнө
parent
commit
e1a1c974e5
36 өөрчлөгдсөн 463 нэмэгдсэн , 295 устгасан
  1. 1 1
      Bin/Data/Scripts/NinjaSnowWar.as
  2. 50 21
      CMakeLists.txt
  3. 13 1
      Docs/GettingStarted.dox
  4. 3 3
      Docs/Reference.dox
  5. 5 1
      Engine/Core/CMakeLists.txt
  6. 16 10
      Engine/Core/ProcessUtils.cpp
  7. 1 0
      Engine/Engine/Engine.cpp
  8. 15 2
      Engine/Graphics/Batch.cpp
  9. 5 3
      Engine/Graphics/CMakeLists.txt
  10. 27 59
      Engine/Graphics/OpenGL/OGLGraphics.cpp
  11. 5 0
      Engine/Graphics/OpenGL/OGLGraphics.h
  12. 1 2
      Engine/Graphics/OpenGL/OGLGraphicsImpl.cpp
  13. 9 8
      Engine/Graphics/OpenGL/OGLGraphicsImpl.h
  14. 12 5
      Engine/Graphics/OpenGL/OGLTexture.cpp
  15. 0 4
      Engine/Graphics/OpenGL/OGLTexture.h
  16. 0 9
      Engine/Graphics/OpenGL/OGLTexture2D.cpp
  17. 17 10
      Engine/IO/FileSystem.cpp
  18. 16 9
      Engine/IO/Log.cpp
  19. 2 2
      Engine/Input/Input.cpp
  20. 20 0
      Engine/Math/Matrix3.h
  21. 27 0
      Engine/Math/Matrix4.h
  22. 26 3
      Readme.txt
  23. 7 2
      ThirdParty/AngelScript/CMakeLists.txt
  24. 3 1
      ThirdParty/AngelScript/source/as_atomic.cpp
  25. 3 2
      ThirdParty/AngelScript/source/as_config.h
  26. 2 1
      ThirdParty/FreeType/src/base/ftbase.c
  27. 6 9
      ThirdParty/SDL/CMakeLists.txt
  28. 3 1
      ThirdParty/SDL/include/SDL_config_iphoneos.h
  29. 120 96
      ThirdParty/SDL/src/video/uikit/SDL_uikitappdelegate.m
  30. 7 18
      ThirdParty/SDL/src/video/uikit/SDL_uikitevents.m
  31. 4 1
      ThirdParty/SDL/src/video/uikit/SDL_uikitopengles.m
  32. 12 4
      ThirdParty/SDL/src/video/uikit/SDL_uikitview.m
  33. 4 1
      Tools/AssetImporter/CMakeLists.txt
  34. 14 1
      Urho3D/CMakeLists.txt
  35. 5 5
      Urho3D/Urho3D.cpp
  36. 2 0
      cmake_ios.sh

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar.as

@@ -245,7 +245,7 @@ void CreateOverlays()
     healthBar.SetSize(116, 16);
     healthBorder.AddChild(healthBar);
 
-    if (GetPlatform() == "Android")
+    if (GetPlatform() == "Android" || GetPlatform() == "iOS")
     {
         touchEnabled = true;
 

+ 50 - 21
CMakeLists.txt

@@ -4,6 +4,15 @@ cmake_minimum_required (VERSION 2.6)
 # Disable "unnecessary" build types
 set (CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo" CACHE STRING "Configurations" FORCE)
 
+# IOS-specific setup
+if (IOS)
+    add_definitions (-DIOS)
+    enable_language (ASM)
+    set (CMAKE_OSX_ARCHITECTURES $(ARCHS_STANDARD_32_BIT))
+    set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos;-iphonesimulator")
+    set (MACOSX_BUNDLE_GUI_IDENTIFIER "com.googlecode.urho3d")
+endif ()
+
 if (COMMAND cmake_policy)
     cmake_policy (SET CMP0003 NEW)
 endif ()
@@ -53,7 +62,7 @@ if (MSVC)
     endif ()
     set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF /DEBUG")
     set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF")
-else ()
+elseif (NOT IOS)
     set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -m32")
     if (ENABLE_SSE)
@@ -82,7 +91,7 @@ macro (finalize_exe)
     if (MSVC)
         add_custom_command (TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different $(TARGETPATH) ${PROJECT_BINARY_DIR}/Bin)
         add_custom_command (TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different $(TARGETDIR)$(TARGETNAME).pdb ${PROJECT_BINARY_DIR}/Bin)
-    else ()
+    elseif (NOT IOS)
         get_target_property (EXECUTABLE_NAME ${TARGET_NAME} LOCATION)
         add_custom_command (TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${EXECUTABLE_NAME} ${PROJECT_BINARY_DIR}/Bin)
     endif ()
@@ -94,11 +103,19 @@ endmacro ()
 
 # Macro for model asset compilation
 macro (add_model NAME PARAMETERS)
-    add_custom_command (
-        OUTPUT ../../Bin/Data/Models/${NAME}.mdl
-        COMMAND ../../Bin/OgreImporter ${NAME}.mesh.xml ../../Bin/Data/Models/${NAME}.mdl ${PARAMETERS}
-        DEPENDS OgreImporter ${NAME}.mesh.xml
-    )
+    if (IOS)
+        add_custom_command (
+            OUTPUT ../../Bin/Data/Models/${NAME}.mdl
+            COMMAND ../../Bin/OgreImporter ${NAME}.mesh.xml ../../Bin/Data/Models/${NAME}.mdl ${PARAMETERS}
+            DEPENDS ${NAME}.mesh.xml
+        )
+    else ()
+        add_custom_command (
+            OUTPUT ../../Bin/Data/Models/${NAME}.mdl
+            COMMAND ../../Bin/OgreImporter ${NAME}.mesh.xml ../../Bin/Data/Models/${NAME}.mdl ${PARAMETERS}
+            DEPENDS OgreImporter ${NAME}.mesh.xml
+        )
+    endif ()
 
     set (ALL_MODELS ${ALL_MODELS} ../../Bin/Data/Models/${NAME}.mdl)
 endmacro ()
@@ -106,15 +123,23 @@ endmacro ()
 # Macro for shader asset compilation
 if (USE_OPENGL)
     macro (add_shader NAME)
-        add_custom_command (
-            OUTPUT ../../Bin/CoreData/Shaders/GLSL/${NAME}.vert
-            COMMAND ../../Bin/GLShaderProcessor ${NAME}.xml ../../Bin/CoreData/Shaders/GLSL
-            DEPENDS GLShaderProcessor ${NAME}.vert ${NAME}.frag Uniforms.vert Transform.vert ScreenPos.vert Lighting.vert Uniforms.frag Samplers.frag Lighting.frag Fog.frag ${NAME}.xml
-        )
+        if (IOS)
+            add_custom_command (
+                OUTPUT ../../Bin/CoreData/Shaders/GLSL/${NAME}.vert
+                COMMAND ../../Bin/GLShaderProcessor ${NAME}.xml ../../Bin/CoreData/Shaders/GLSL
+                DEPENDS ${NAME}.vert ${NAME}.frag Uniforms.vert Transform.vert ScreenPos.vert Lighting.vert Uniforms.frag Samplers.frag Lighting.frag Fog.frag ${NAME}.xml
+            )
+        else ()
+            add_custom_command (
+                OUTPUT ../../Bin/CoreData/Shaders/GLSL/${NAME}.vert
+                COMMAND ../../Bin/GLShaderProcessor ${NAME}.xml ../../Bin/CoreData/Shaders/GLSL
+                DEPENDS GLShaderProcessor ${NAME}.vert ${NAME}.frag Uniforms.vert Transform.vert ScreenPos.vert Lighting.vert Uniforms.frag Samplers.frag Lighting.frag Fog.frag ${NAME}.xml
+            )
+        endif ()
         
         set (ALL_SHADERS ${ALL_SHADERS} ../../Bin/CoreData/Shaders/GLSL/${NAME}.vert)
     endmacro ()
-else()
+else ()
     macro (add_shader NAME)
         add_custom_command (
             OUTPUT ../../Bin/CoreData/Shaders/SM2/${NAME}.vs2
@@ -152,28 +177,32 @@ add_subdirectory (Engine/Script)
 add_subdirectory (Engine/UI)
 add_subdirectory (SourceAssets/Models)
 add_subdirectory (ThirdParty/AngelScript)
-add_subdirectory (ThirdParty/Assimp)
 add_subdirectory (ThirdParty/Bullet)
 add_subdirectory (ThirdParty/FreeType)
 add_subdirectory (ThirdParty/kNet)
-add_subdirectory (ThirdParty/LibCpuId)
 add_subdirectory (ThirdParty/PugiXml)
 add_subdirectory (ThirdParty/SDL)
 add_subdirectory (ThirdParty/Squish)
 add_subdirectory (ThirdParty/StanHull)
 add_subdirectory (ThirdParty/STB)
-add_subdirectory (Tools/AssetImporter)
-add_subdirectory (Tools/OgreImporter)
-add_subdirectory (Tools/PackageTool)
-add_subdirectory (Tools/RampGenerator)
 add_subdirectory (Urho3D)
 
 if (USE_OPENGL)
     add_subdirectory (SourceAssets/GLSLShaders)
-    add_subdirectory (ThirdParty/GLee)
-    add_subdirectory (Tools/GLShaderProcessor)
+    if (NOT IOS)
+        add_subdirectory (ThirdParty/GLee)
+        add_subdirectory (Tools/GLShaderProcessor)
+    endif ()
 else ()
     add_subdirectory (SourceAssets/HLSLShaders)
     add_subdirectory (Tools/ShaderCompiler)
 endif ()
 
+if (NOT IOS)
+    add_subdirectory (ThirdParty/Assimp)
+    add_subdirectory (ThirdParty/LibCpuId)
+    add_subdirectory (Tools/AssetImporter)
+    add_subdirectory (Tools/OgreImporter)
+    add_subdirectory (Tools/PackageTool)
+    add_subdirectory (Tools/RampGenerator)
+endif ()

+ 13 - 1
Docs/GettingStarted.dox

@@ -20,7 +20,9 @@ To run Urho3D, the minimum system requirements are:
 
 - Linux & Mac OS X: GPU with OpenGL 2.0 support and EXT_framebuffer_object, EXT_packed_depth_stencil and EXT_texture_filter_anisotropic extensions.
 
-- Android: OS version 2.2 or newer, OpenGL ES 2 capable GPU.
+- Android: OS version 2.2 or newer, OpenGL ES 2.0 capable GPU.
+
+- iOS: OpenGL ES 2.0 capable GPU.
 
 For Windows, SSE and Windows XP requirements can be eliminated by disabling SSE, crash dump support and file watcher from the root CMakeLists.txt. Windows 2000 will then be the absolute minimum.
 
@@ -58,6 +60,16 @@ By default the Android package for Urho3D is com.googlecode.urho3d. For a real a
 - Android/src/com/googlecode/urho3d/SDLActivity.java (rename directories also)
 - ThirdParty/SDL/include/SDL_config_android.h, look for the NATIVE_FUNCTION macro
 
+\section Building_Ios iOS build process
+
+First build desktop Urho3D to generate the OgreImporter and GLShaderProcessor utilities into the Bin directory. Then run cmake_ios.sh. This generates an Xcode project named Urho3D.xcodeproj.
+
+Open the Xcode project and check the properties for the Urho3D project (topmost in the Project Navigator.) In Architectures -> Base SDK, choose your iOS SDK. In Code Signing, enter your developer identity as necessary.
+
+The Urho3D target will actually build the application bundle and copy resources from Bin/Data and Bin/CoreData directories. Edit its build scheme to choose debug or release mode.
+
+Note that due to a CMake / Xcode bug, you may need to modify and save Urho3D.cpp after modifying any of the libraries to get Xcode to re-link the executable. Do this also if you modify the data files and get an error about resources having been added or modified after signing.
+
 
 \page Running Running Urho3D
 

+ 3 - 3
Docs/Reference.dox

@@ -440,7 +440,7 @@ Note that many more optimization opportunities are possible at the content level
 
 \section Rendering_GPUResourceLoss Handling GPU resource loss
 
-On Direct3D9 and Android OpenGL ES 2 it is possible to lose the rendering context (and therefore GPU resources) due to the application window being minimized to the background. Also, to work around possible GPU driver bugs the desktop OpenGL context will be voluntarily destroyed and recreated when changing screen mode or toggling between fullscreen and windowed. Therefore, on all graphics APIs one must be prepared for losing GPU resources.
+On Direct3D9 and Android OpenGL ES 2.0 it is possible to lose the rendering context (and therefore GPU resources) due to the application window being minimized to the background. Also, to work around possible GPU driver bugs the desktop OpenGL context will be voluntarily destroyed and recreated when changing screen mode or toggling between fullscreen and windowed. Therefore, on all graphics APIs one must be prepared for losing GPU resources.
 
 Textures that have been loaded from a file, as well as vertex & index buffers that have shadowing enabled will restore their contents automatically, the rest have to be restored manually. On Direct3D9 non-dynamic (managed) textures and buffers will never be lost, as the runtime automatically backs them up to system memory.
 
@@ -457,7 +457,7 @@ See \ref APIDifferences "Differences between Direct3D9 and OpenGL" for what to w
 
 \page RenderingModes Rendering modes
 
-Urho3D implements both forward, light pre-pass and deferred rendering modes. Where they differ is how per-pixel lighting is calculated for opaque objects; transparent objects always use forward rendering. Note that on OpenGL ES 2 only forward rendering is available.
+Urho3D implements both forward, light pre-pass and deferred rendering modes. Where they differ is how per-pixel lighting is calculated for opaque objects; transparent objects always use forward rendering. Note that on OpenGL ES 2.0 only forward rendering is available.
 
 \section RenderingModes_Forward Forward rendering
 
@@ -524,7 +524,7 @@ These differences need to be observed when using the low-level rendering functio
 
 - To ensure similar UV addressing for render-to-texture viewports on both APIs, on OpenGL texture viewports will be rendered upside down.
 
-OpenGL ES 2 has further limitations:
+OpenGL ES 2.0 has further limitations:
 
 - Only DXT1 compressed textures will be uploaded as compressed if the EXT_texture_compression_dxt1 extension is present. Other compressed texture formats will be uploaded as uncompressed RGBA. Mobile hardware specific compression formats such as ETC or PVRTC are not yet supported.
 

+ 5 - 1
Engine/Core/CMakeLists.txt

@@ -13,7 +13,11 @@ include_directories (
 
 # Define target & libraries to link
 add_library (${TARGET_NAME} STATIC ${SOURCE_FILES})
-target_link_libraries (${TARGET_NAME} Container LibCpuId Math)
+target_link_libraries (${TARGET_NAME} Container Math)
+
+if (NOT IOS)
+    target_link_libraries (${TARGET_NAME} LibCpuId)
+endif ()
 
 if (WIN32)
     target_link_libraries (${TARGET_NAME} winmm.lib)

+ 16 - 10
Engine/Core/ProcessUtils.cpp

@@ -29,7 +29,7 @@
 #include <cstdlib>
 #include <fcntl.h>
 
-#ifndef ANDROID
+#if !defined(ANDROID) && !defined(IOS)
 #include <libcpuid.h>
 #endif
 
@@ -42,7 +42,7 @@
 
 #if defined(_MSC_VER)
 #include <float.h>
-#elif !defined(ANDROID)
+#elif !defined(ANDROID) && !defined(IOS)
 // From http://stereopsis.com/FPU.html
 
 #define FPU_CW_PREC_MASK        0x0300
@@ -77,7 +77,7 @@ static String currentLine;
 static Vector<String> arguments;
 static Mutex staticMutex;
 
-#ifndef ANDROID
+#if !defined(ANDROID) && !defined(IOS)
 void GetCPUData(struct cpu_id_t* data)
 {
     if (cpu_identify(0, data) < 0)
@@ -90,7 +90,7 @@ void GetCPUData(struct cpu_id_t* data)
 
 void InitFPU()
 {
-    #ifndef ANDROID
+    #if !defined(ANDROID) && !defined(IOS)
     // Make sure FPU is in round-to-nearest, single precision mode
     // This ensures Direct3D and OpenGL behave similarly, and all threads behave similarly
     #ifdef _MSC_VER
@@ -145,6 +145,7 @@ void OpenConsoleWindow()
 
 void PrintUnicode(const String& str)
 {
+    #if !defined(ANDROID) && !defined(IOS)
     #ifdef WIN32
     HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
     if (output == INVALID_HANDLE_VALUE)
@@ -155,6 +156,7 @@ void PrintUnicode(const String& str)
     #else
     printf("%s", str.CString());
     #endif
+    #endif
 }
 
 void PrintUnicodeLine(const String& str)
@@ -164,7 +166,9 @@ void PrintUnicodeLine(const String& str)
 
 void PrintLine(const String& str)
 {
+    #if !defined(ANDROID) && !defined(IOS)
     printf("%s\n", str.CString());
+    #endif
 }
 
 const Vector<String>& ParseArguments(const String& cmdLine)
@@ -302,7 +306,7 @@ String GetConsoleInput()
             }
         }
     }
-    #else
+    #elif !defined(ANDROID) && !defined(IOS)
     int flags = fcntl(STDIN_FILENO, F_GETFL);
     fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
     for (;;)
@@ -320,12 +324,14 @@ String GetConsoleInput()
 
 String GetPlatform()
 {
-    #if defined(WIN32)
+    #if defined(ANDROID)
+    return "Android";    
+    #elif defined(IOS)
+    return "iOS";
+    #elif defined(WIN32)
     return "Windows";
     #elif defined(__APPLE__)
     return "Mac OS X";
-    #elif defined(ANDROID)
-    return "Android";
     #elif defined(__linux__)
     return "Linux";
     #else
@@ -335,7 +341,7 @@ String GetPlatform()
 
 unsigned GetNumPhysicalCPUs()
 {
-    #ifndef ANDROID
+    #if !defined(ANDROID) && !defined(IOS)
     struct cpu_id_t data;
     GetCPUData(&data);
     return data.num_cores;
@@ -347,7 +353,7 @@ unsigned GetNumPhysicalCPUs()
 
 unsigned GetNumLogicalCPUs()
 {
-    #ifndef ANDROID
+    #if !defined(ANDROID) && !defined(IOS)
     struct cpu_id_t data;
     GetCPUData(&data);
     return data.num_logical_cpus;

+ 1 - 0
Engine/Engine/Engine.cpp

@@ -206,6 +206,7 @@ bool Engine::Initialize(const String& windowTitle, const String& logName, const
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     FileSystem* fileSystem = GetSubsystem<FileSystem>();
     String exePath = fileSystem->GetProgramDir();
+    
     if (fileSystem->FileExists(exePath + "CoreData.pak"))
     {
         SharedPtr<PackageFile> package(new PackageFile(context_));

+ 15 - 2
Engine/Graphics/Batch.cpp

@@ -217,10 +217,23 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         Vector4 viewportParams(farVector.x_, farVector.y_, farVector.z_, 0.0f);
         graphics->SetShaderParameter(VSP_FRUSTUMSIZE, viewportParams);
         
+        Matrix4 projection = camera_->GetProjection();
+        #ifdef USE_OPENGL
+        // Add constant depth bias manually to the projection matrix due to glPolygonOffset() inconsistency
+        float constantBias = 2.0f * graphics->GetDepthConstantBias();
+        // On OpenGL ES slope-scaled bias can not be guaranteed to be available, and the shadow filtering is more coarse,
+        // so use a higher constant bias
+        #ifdef GL_ES_VERSION_2_0
+        constantBias *= 1.5f;
+        #endif
+        projection.m22_ += projection.m32_ * constantBias;
+        projection.m23_ += projection.m33_ * constantBias;
+        #endif
+        
         if (overrideView_)
-            graphics->SetShaderParameter(VSP_VIEWPROJ, camera_->GetProjection());
+            graphics->SetShaderParameter(VSP_VIEWPROJ, projection);
         else
-            graphics->SetShaderParameter(VSP_VIEWPROJ, camera_->GetProjection() * camera_->GetInverseWorldTransform());
+            graphics->SetShaderParameter(VSP_VIEWPROJ, projection * camera_->GetInverseWorldTransform());
         
         graphics->SetShaderParameter(VSP_VIEWRIGHTVECTOR, cameraWorldRotation * Vector3::RIGHT);
         graphics->SetShaderParameter(VSP_VIEWUPVECTOR, cameraWorldRotation * Vector3::UP);

+ 5 - 3
Engine/Graphics/CMakeLists.txt

@@ -20,7 +20,7 @@ include_directories (
     . ../Container ../Core ../IO ../Math ../Resource ../Scene
 )
 
-if (USE_OPENGL)
+if (USE_OPENGL AND NOT IOS)
     include_directories (../../ThirdParty/GLee)
 endif ()
 
@@ -28,8 +28,10 @@ endif ()
 add_library (${TARGET_NAME} STATIC ${SOURCE_FILES})
 target_link_libraries (${TARGET_NAME} Container Core Math Resource Scene SDL)
 
-if (USE_OPENGL)
-    target_link_libraries (${TARGET_NAME} GLee)
+if (USE_OPENGL)
+    if (NOT IOS)
+        target_link_libraries (${TARGET_NAME} GLee)
+    endif ()
 else ()
     target_link_libraries (${TARGET_NAME} d3d9.lib)
 endif ()

+ 27 - 59
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -230,6 +230,7 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool vsync, bool
         // SDL window parameters are static, so need to operate under static lock
         MutexLock lock(GetStaticMutex());
         
+        SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight");
         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
         SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
@@ -301,9 +302,10 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool vsync, bool
     // Set vsync
     SDL_GL_SetSwapInterval(vsync ? 1 : 0);
     
-    // Query for system backbuffer depth
-    glGetIntegerv(GL_DEPTH_BITS, &impl_->windowDepthBits_);
-    impl_->depthBits_ = impl_->windowDepthBits_;
+    // Store the system FBO on IOS now
+    #ifdef IOS
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&impl_->systemFbo_);
+    #endif
     
     SDL_GetWindowSize(impl_->window_, &width_, &height_);
     fullscreen_ = fullscreen;
@@ -870,31 +872,15 @@ void Graphics::SetShaderParameter(StringHash param, const float* data, unsigned
                 break;
                 
             case GL_FLOAT_MAT3:
-                #ifndef GL_ES_VERSION_2_0
-                glUniformMatrix3fv(info->location_, count / 9, GL_TRUE, data);
-                #else
-                {
-                    for (unsigned i = 0; i < count; i += 9)
-                    {
-                        Matrix3 matrix(&data[i]);
-                        glUniformMatrix3fv(info->location_ + i / 9, 1, GL_FALSE, matrix.Transpose().Data());
-                    }
-                }
-                #endif
+                count = Min((int)count, (int)NUM_TEMP_MATRICES * 9);
+                Matrix3::BulkTranspose(&tempMatrices3_[0].m00_, data, count / 9);
+                glUniformMatrix3fv(info->location_, count / 9, GL_FALSE, tempMatrices3_[0].Data());
                 break;
                 
             case GL_FLOAT_MAT4:
-                #ifndef GL_ES_VERSION_2_0
-                glUniformMatrix4fv(info->location_, count / 16, GL_TRUE, data);
-                #else
-                {
-                    for (unsigned i = 0; i < count; i += 16)
-                    {
-                        Matrix4 matrix(&data[i]);
-                        glUniformMatrix4fv(info->location_ + i / 16, 1, GL_FALSE, matrix.Transpose().Data());
-                    }
-                }
-                #endif
+                count = Min((int)count, (int)NUM_TEMP_MATRICES * 16);
+                Matrix4::BulkTranspose(&tempMatrices4_[0].m00_, data, count / 16);
+                glUniformMatrix4fv(info->location_, count / 16, GL_FALSE, tempMatrices4_[0].Data());
                 break;
             }
         }
@@ -922,13 +908,7 @@ void Graphics::SetShaderParameter(StringHash param, const Matrix3& matrix)
     {
         const ShaderParameter* info = shaderProgram_->GetParameter(param);
         if (info)
-        {
-            #ifndef GL_ES_VERSION_2_0
-            glUniformMatrix3fv(info->location_, 1, GL_TRUE, matrix.Data());
-            #else
             glUniformMatrix3fv(info->location_, 1, GL_FALSE, matrix.Transpose().Data());
-            #endif
-        }
     }
 }
 
@@ -964,13 +944,7 @@ void Graphics::SetShaderParameter(StringHash param, const Matrix4& matrix)
     {
         const ShaderParameter* info = shaderProgram_->GetParameter(param);
         if (info)
-        {
-            #ifndef GL_ES_VERSION_2_0
-            glUniformMatrix4fv(info->location_, 1, GL_TRUE, matrix.Data());
-            #else
             glUniformMatrix4fv(info->location_, 1, GL_FALSE, matrix.Transpose().Data());
-            #endif
-        }
     }
 }
 
@@ -1373,29 +1347,21 @@ void Graphics::SetDepthBias(float constantBias, float slopeScaledBias)
 {
     if (constantBias != constantDepthBias_ || slopeScaledBias != slopeScaledDepthBias_)
     {
-        if (constantBias != 0.0f || slopeScaledBias != 0.0f)
+        #ifndef GL_ES_VERSION_2_0
+        if (slopeScaledBias != 0.0f)
         {
-            // Bring the constant bias from Direct3D9 scale to OpenGL (depends on depth buffer bitdepth)
-            // Zero depth bits may be returned if using the packed depth-stencil format. Assume 24bit in that case
-            #ifndef GL_ES_VERSION_2_0
-            int depthBits = Min(impl_->depthBits_, 23);
-            if (!depthBits)
-                depthBits = 23;
-            #else
-            int depthBits = 25;
-            #endif
-            
-            float adjustedConstantBias = constantBias * (float)(1 << (depthBits - 1));
+            // OpenGL constant bias is unreliable and dependant on depth buffer bitdepth, apply in the projection matrix instead
             float adjustedSlopeScaledBias = slopeScaledBias + 1.0f;
-            
             glEnable(GL_POLYGON_OFFSET_FILL);
-            glPolygonOffset(adjustedSlopeScaledBias, adjustedConstantBias);
+            glPolygonOffset(adjustedSlopeScaledBias, 0.0f);
         }
         else
             glDisable(GL_POLYGON_OFFSET_FILL);
+        #endif
         
         constantDepthBias_ = constantBias;
         slopeScaledDepthBias_ = slopeScaledBias;
+        shaderParameterSources_[SP_CAMERA] = (const void*)M_MAX_UNSIGNED;
     }
 }
 
@@ -1771,10 +1737,15 @@ void Graphics::Restore()
 {
     if (!impl_->window_)
         return;
-    
+
     // Ensure first that the context exists
     if (!impl_->context_)
+    {
         impl_->context_ = SDL_GL_CreateContext(impl_->window_);
+        #ifdef IOS
+        glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&impl_->systemFbo_);
+        #endif
+    }
     if (!impl_->context_)
         return;
     
@@ -1963,10 +1934,10 @@ void Graphics::CommitFramebuffer()
     
     if (noFbo)
     {
-        if (impl_->boundFbo_)
+        if (impl_->boundFbo_ != impl_->systemFbo_)
         {
-            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-            impl_->boundFbo_ = 0;
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, impl_->systemFbo_);
+            impl_->boundFbo_ = impl_->systemFbo_;
         }
         
         return;
@@ -2117,8 +2088,6 @@ void Graphics::CommitFramebuffer()
                 i->second_.depthAttachment_ = depthStencil_;
             }
         }
-        
-        impl_->depthBits_ = texture->GetDepthBits();
     }
     else
     {
@@ -2127,7 +2096,6 @@ void Graphics::CommitFramebuffer()
             glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);
             glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);
             i->second_.depthAttachment_ = 0;
-            impl_->depthBits_ = impl_->windowDepthBits_;
         }
     }
 }
@@ -2203,7 +2171,7 @@ void Graphics::ResetCachedState()
     stencilWriteMask_ = M_MAX_UNSIGNED;
     impl_->activeTexture_ = 0;
     impl_->enabledAttributes_ = 0;
-    impl_->boundFbo_ = 0;
+    impl_->boundFbo_ = impl_->systemFbo_;
     
     // Set initial state to match Direct3D
     if (impl_->context_)

+ 5 - 0
Engine/Graphics/OpenGL/OGLGraphics.h

@@ -51,6 +51,7 @@ class VertexBuffer;
 typedef Map<Pair<ShaderVariation*, ShaderVariation*>, SharedPtr<ShaderProgram> > ShaderProgramMap;
 
 static const unsigned NUM_SCREEN_BUFFERS = 2;
+static const unsigned NUM_TEMP_MATRICES = 8;
 
 /// CPU-side scratch buffer for vertex data updates.
 struct ScratchBuffer
@@ -472,6 +473,10 @@ private:
     HashMap<int, SharedPtr<Texture2D> > depthTextures_;
     /// Remembered shader parameter sources.
     const void* shaderParameterSources_[MAX_SHADER_PARAMETER_GROUPS];
+    /// Temp matrices for transposing shader parameters.
+    Matrix3 tempMatrices3_[NUM_TEMP_MATRICES];
+    /// Temp matrices for transposing shader parameters.
+    Matrix4 tempMatrices4_[NUM_TEMP_MATRICES];
 };
 
 /// Register Graphics library objects.

+ 1 - 2
Engine/Graphics/OpenGL/OGLGraphicsImpl.cpp

@@ -34,12 +34,11 @@
 GraphicsImpl::GraphicsImpl() :
     window_(0),
     context_(0),
+    systemFbo_(0),
     activeTexture_(0),
     enabledAttributes_(0),
     boundFbo_(0),
     pixelFormat_(0),
-    depthBits_(0),
-    windowDepthBits_(0),
     fboDirty_(false)
 {
 }

+ 9 - 8
Engine/Graphics/OpenGL/OGLGraphicsImpl.h

@@ -27,11 +27,14 @@
 #include "Map.h"
 #include "Timer.h"
 
-#ifndef ANDROID
-#include <GLee.h>
-#else
+#if defined(ANDROID)
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#elif defined(IOS)
+#include <OpenGLES/ES2/gl.h>
+#include <OpenGLES/ES2/glext.h>
+#else
+#include <GLee.h>
 #endif
 
 #include <SDL.h>
@@ -79,8 +82,10 @@ public:
 private:
     /// SDL window.
     SDL_Window* window_;
-    /// SDL OpenGL context
+    /// SDL OpenGL context.
     SDL_GLContext context_;
+    /// IOS system framebuffer handle.
+    unsigned systemFbo_;
     /// Active texture unit.
     unsigned activeTexture_;
     /// Vertex attributes in use.
@@ -89,10 +94,6 @@ private:
     unsigned boundFbo_;
     /// Current pixel format.
     int pixelFormat_;
-    /// Current depth bits.
-    int depthBits_;
-    /// Backbuffer depth bits.
-    int windowDepthBits_;
     /// Map for FBO's per resolution and format.
     Map<unsigned long long, FrameBufferObject> frameBuffers_;
     /// Need FBO commit flag.

+ 12 - 5
Engine/Graphics/OpenGL/OGLTexture.cpp

@@ -71,7 +71,6 @@ Texture::Texture(Context* context) :
     GPUObject(GetSubsystem<Graphics>()),
     levels_(0),
     requestedLevels_(0),
-    depthBits_(0),
     width_(0),
     height_(0),
     dynamic_(false),
@@ -202,7 +201,11 @@ bool Texture::IsCompressed() const
     return format_ == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format_ == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
         format_ == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
     #else
+    #ifdef ANDROID
     return format_ == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+    #else
+    return false;
+    #endif
     #endif
 }
 
@@ -258,9 +261,11 @@ unsigned Texture::GetRowDataSize(int width) const
     #endif
         return width * 4;
         
+    #if !defined(GL_ES_VERSION_2_0) || defined(ANDROID)
     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
         return ((width + 3) >> 2) * 8;
-        
+    #endif
+            
     #ifndef GL_ES_VERSION_2_0
     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
@@ -276,9 +281,11 @@ unsigned Texture::GetDXTFormat(CompressedFormat format)
 {
     switch (format)
     {
+    #if !defined(GL_ES_VERSION_2_0) || defined(ANDROID)
     case CF_DXT1:
         return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
-        
+    #endif
+            
     #ifndef GL_ES_VERSION_2_0
     case CF_DXT3:
         return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
@@ -304,7 +311,7 @@ unsigned Texture::GetExternalFormat(unsigned format)
     else
         return format;
     #else
-    if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_COMPONENT24_OES || format == GL_DEPTH_COMPONENT32_OES)
+    if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_COMPONENT16 || format == GL_DEPTH_COMPONENT24_OES)
         return GL_DEPTH_COMPONENT;
     else
         return format;
@@ -319,7 +326,7 @@ unsigned Texture::GetDataType(unsigned format)
     else
         return GL_UNSIGNED_BYTE;
     #else
-    if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_COMPONENT24_OES || format == GL_DEPTH_COMPONENT32_OES)
+    if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_COMPONENT24_OES)
         return GL_UNSIGNED_INT;
     else if (format == GL_DEPTH_COMPONENT16)
         return GL_UNSIGNED_SHORT;

+ 0 - 4
Engine/Graphics/OpenGL/OGLTexture.h

@@ -71,8 +71,6 @@ public:
     bool IsCompressed() const;
     /// Return number of mipmap levels.
     unsigned GetLevels() const { return levels_; }
-    /// Return OpenGL depth bits.
-    int GetDepthBits() const { return depthBits_; }
     /// Return width.
     int GetWidth() const { return width_; }
     /// Return height.
@@ -127,8 +125,6 @@ protected:
     unsigned levels_;
     /// Requested mipmap levels.
     unsigned requestedLevels_;
-    /// Texture's OpenGL depth bits (depth textures only.)
-    int depthBits_;
     /// Texture width.
     int width_;
     /// Texture height.

+ 0 - 9
Engine/Graphics/OpenGL/OGLTexture2D.cpp

@@ -382,7 +382,6 @@ bool Texture2D::Create()
         if (renderSurface_)
         {
             renderSurface_->CreateRenderBuffer(width_, height_, format_);
-            depthBits_ = 24;
             return true;
         }
         else
@@ -407,14 +406,6 @@ bool Texture2D::Create()
         }
     }
     
-    // If depth format, get the depth size
-    #ifndef GL_ES_VERSION_2_0
-    if (externalFormat == GL_DEPTH_COMPONENT)
-        glGetTexLevelParameteriv(target_, 0, GL_TEXTURE_DEPTH_SIZE, &depthBits_);
-    #else
-    depthBits_ = 24;
-    #endif
-    
     // Set mipmapping
     levels_ = requestedLevels_;
     if (!levels_)

+ 17 - 10
Engine/IO/FileSystem.cpp

@@ -46,13 +46,16 @@
 #define MAX_PATH 256
 #endif
 
-#ifdef __APPLE__
+#if defined(__APPLE__)
 #include <mach-o/dyld.h>
 #endif
 
 #ifdef ANDROID
 extern "C" const char* SDL_Android_GetFilesDir();
 #endif
+#ifdef IOS
+extern "C" const char* SDL_IOS_GetResourceDir();
+#endif
 
 #include "DebugNew.h"
 
@@ -373,7 +376,13 @@ void FileSystem::ScanDir(Vector<String>& result, const String& pathName, const S
 
 String FileSystem::GetProgramDir()
 {
-    #if defined(WIN32)
+    #if defined(ANDROID)
+    // This is an internal directory specifier pointing to the assets in the .apk
+    // Files from this directory will be opened using special handling
+    return "/apk/";
+    #elif defined(IOS)
+    return AddTrailingSlash(SDL_IOS_GetResourceDir());
+    #elif defined(WIN32)
     wchar_t exeName[MAX_PATH];
     exeName[0] = 0;
     GetModuleFileNameW(0, exeName, MAX_PATH);
@@ -384,10 +393,6 @@ String FileSystem::GetProgramDir()
     unsigned size = MAX_PATH;
     _NSGetExecutablePath(exeName, &size);
     return GetPath(String(exeName));
-    #elif defined(ANDROID)
-    // This is an internal directory specifier pointing to the assets in the .apk
-    // Files from this directory will be opened using special handling
-    return "/apk/";
     #elif defined(__linux__)
     char exeName[MAX_PATH];
     memset(exeName, 0, MAX_PATH);
@@ -401,14 +406,16 @@ String FileSystem::GetProgramDir()
 }
 
 String FileSystem::GetUserDocumentsDir()
-{
-    #if defined(WIN32)
+{          
+    #if defined(ANDROID)
+    return AddTrailingSlash(SDL_Android_GetFilesDir());
+    #elif defined(IOS)
+    return AddTrailingSlash(SDL_IOS_GetResourceDir());
+    #elif defined(WIN32)
     wchar_t pathName[MAX_PATH];
     pathName[0] = 0;
     SHGetSpecialFolderPathW(0, pathName, CSIDL_PERSONAL, 0);
     return AddTrailingSlash(String(pathName));
-    #elif defined(ANDROID)
-    return AddTrailingSlash(String(SDL_Android_GetFilesDir()));
     #else
     char pathName[MAX_PATH];
     pathName[0] = 0;

+ 16 - 9
Engine/IO/Log.cpp

@@ -34,6 +34,9 @@
 #ifdef ANDROID
 #include <android/log.h>
 #endif
+#ifdef IOS
+extern "C" void SDL_IOS_LogMessage(const char* message);
+#endif
 
 #include "DebugNew.h"
 
@@ -49,7 +52,7 @@ OBJECTTYPESTATIC(Log);
 
 Log::Log(Context* context) :
     Object(context),
-    #ifdef _DEBUG
+    #if defined(_DEBUG) || defined(XCODE_DEBUG_CONFIGURATION)
     level_(LOG_DEBUG),
     #else
     level_(LOG_INFO),
@@ -64,7 +67,7 @@ Log::~Log()
 
 void Log::Open(const String& fileName)
 {
-    #ifndef ANDROID
+    #if !defined(ANDROID) && !defined(IOS)
     if (fileName.Empty())
         return;
     
@@ -98,11 +101,13 @@ void Log::Write(int level, const String& message)
     String dateTimeString = String(dateTime).Replaced("\n", "");
     String formattedMessage = "[" + dateTimeString + "] " + levelPrefixes[level] + ": " + message;
     
-    #ifndef ANDROID
-    PrintUnicodeLine(formattedMessage);
+    #if defined(ANDROID)
+    int androidLevel = ANDROID_LOG_DEBUG + level;
+    __android_log_print(androidLevel, "Urho3D", "%s", message.CString());
+    #elif defined(IOS)
+    SDL_IOS_LogMessage(message.CString());
     #else
-    /// \todo Use proper log levels
-    __android_log_print(ANDROID_LOG_INFO, "Urho3D", formattedMessage.CString());
+    PrintUnicodeLine(formattedMessage);
     #endif
     
     if (logFile_)
@@ -126,10 +131,12 @@ void Log::WriteRaw(const String& message)
     inWrite_ = true;
     lastMessage_ = message;
     
-    #ifndef ANDROID
-    PrintUnicode(message);
-    #else
+    #if defined(ANDROID)
     __android_log_print(ANDROID_LOG_INFO, "Urho3D", message.CString());
+    #elif defined(IOS)
+    SDL_IOS_LogMessage(message.CString());
+    #else
+    PrintUnicode(message);
     #endif
     
     if (logFile_)

+ 2 - 2
Engine/Input/Input.cpp

@@ -44,10 +44,10 @@ static HashMap<unsigned, Input*> inputInstances;
 /// Return the Input subsystem instance corresponding to an SDL window ID.
 Input* GetInputInstance(unsigned windowID)
 {
-    #ifndef ANDROID
+    #if !defined(ANDROID) && !defined(IOS)
     return windowID ? inputInstances[windowID] : 0;
     #else
-    // On Android we support only a single instance of Urho3D in the process, and the window ID can not be relied on.
+    // On mobile devices only a single Urho3D instance within a process is supported, and the window ID can not be relied on.
     return inputInstances.Size() ? inputInstances.Begin()->second_ : 0;
     #endif
 }

+ 20 - 0
Engine/Math/Matrix3.h

@@ -241,6 +241,26 @@ public:
     float m21_;
     float m22_;
     
+    /// Bulk transpose matrices.
+    static void BulkTranspose(float* dest, const float* src, unsigned count)
+    {
+        for (unsigned i = 0; i < count; ++i)
+        {
+            dest[0] = src[0];
+            dest[1] = src[3];
+            dest[2] = src[6];
+            dest[3] = src[1];
+            dest[4] = src[4];
+            dest[5] = src[7];
+            dest[6] = src[2];
+            dest[7] = src[5];
+            dest[8] = src[8];
+            
+            dest += 9;
+            src += 9;
+        }
+    }
+    
     /// Zero matrix.
     static const Matrix3 ZERO;
     /// Identity matrix.

+ 27 - 0
Engine/Math/Matrix4.h

@@ -418,6 +418,33 @@ public:
     float m32_;
     float m33_;
     
+    /// Bulk transpose matrices.
+    static void BulkTranspose(float* dest, const float* src, unsigned count)
+    {
+        for (unsigned i = 0; i < count; ++i)
+        {
+            dest[0] = src[0];
+            dest[1] = src[4];
+            dest[2] = src[8];
+            dest[3] = src[12];
+            dest[4] = src[1];
+            dest[5] = src[5];
+            dest[6] = src[9];
+            dest[7] = src[13];
+            dest[8] = src[2];
+            dest[9] = src[6];
+            dest[10] = src[10];
+            dest[11] = src[14];
+            dest[12] = src[3];
+            dest[13] = src[7];
+            dest[14] = src[11];
+            dest[15] = src[15];
+            
+            dest += 16;
+            src += 16;
+        }
+    }
+    
     /// Zero matrix.
     static const Matrix4 ZERO;
     /// Identity matrix.

+ 26 - 3
Readme.txt

@@ -99,7 +99,9 @@ To run Urho3D, the minimum system requirements are:
 - Linux & Mac OS X: GPU with OpenGL 2.0 support and EXT_framebuffer_object,
   EXT_packed_depth_stencil and EXT_texture_filter_anisotropic extensions.
 
-- Android: OS version 2.2 or newer, OpenGL ES 2 capable GPU.
+- Android: OS version 2.2 or newer, OpenGL ES 2.0 capable GPU.
+
+- iOS: OpenGL ES 2.0 capable GPU.
 
 For Windows, SSE and Windows XP requirements can be eliminated by disabling SSE,
 crash dump support and file watcher from the root CMakeLists.txt. Windows 2000
@@ -146,8 +148,8 @@ following arguments: Scripts/TestScene.as -w
 Android build process
 ---------------------
 
-First build Urho3D for desktop OpenGL to make sure the GLSL shaders are 
-generated. For Windows this requires forcing OpenGL mode from the root 
+First build Urho3D for desktop OpenGL to make sure the GLSL shaders are
+generated. For Windows this requires forcing OpenGL mode from the root
 CMakeLists.txt. Then copy Bin/Data and Bin/CoreData directories to the
 Android/assets directory. Finally execute the following commands in the
 Android directory:
@@ -174,6 +176,27 @@ name has to be replaced in several files:
   macro
 
 
+iOS build process
+-----------------
+
+First build desktop Urho3D to generate the OgreImporter and GLShaderProcessor
+utilities into the Bin directory. Then run cmake_ios.sh. This generates an Xcode
+project named Urho3D.xcodeproj.
+
+Open the Xcode project and check the properties for the Urho3D project (topmost
+in the Project Navigator.) In Architectures -> Base SDK, choose your iOS SDK.
+In Code Signing, enter your developer identity as necessary.
+
+The Urho3D target will actually build the application bundle and copy resources
+from Bin/Data and Bin/CoreData directories. Edit its build scheme to choose
+debug or release mode.
+
+Note that due to a CMake / Xcode bug, you may need to modify and save Urho3D.cpp
+after modifying any of the libraries to get Xcode to re-link the executable.
+Do this also if you modify the data files and get an error about resources
+having been added or modified after signing.
+
+
 History
 -------
 

+ 7 - 2
ThirdParty/AngelScript/CMakeLists.txt

@@ -9,8 +9,13 @@ file (GLOB CPP_FILES
 file (GLOB H_FILES
     include/*.h source/*.h
 )
-
-set (SOURCE_FILES ${CPP_FILES} ${H_FILES})
+
+if (NOT IOS)
+    set (SOURCE_FILES ${CPP_FILES} ${H_FILES})
+else ()
+    set (ASM_FILES source/as_callfunc_arm_xcode.S)
+    set (SOURCE_FILES ${CPP_FILES} ${ASM_FILES} ${H_FILES})
+endif ()
 
 # Include directories
 include_directories (

+ 3 - 1
ThirdParty/AngelScript/source/as_atomic.cpp

@@ -27,6 +27,8 @@
    Andreas Jonsson
    [email protected]
 */
+
+// Modified by Lasse Öörni for Urho3D
  
 //
 // as_gc.cpp
@@ -145,7 +147,7 @@ asDWORD asCAtomic::atomicDec()
 	return __sync_sub_and_fetch(&value, 1);
 }
 
-#elif defined(AS_MAC)
+#elif defined(AS_MAC) || defined(AS_IPHONE)
 
 END_AS_NAMESPACE
 #include <libkern/OSAtomic.h>

+ 3 - 2
ThirdParty/AngelScript/source/as_config.h

@@ -549,6 +549,7 @@
 
 	// MacOSX and IPhone
 	#ifdef __APPLE__
+		#include <TargetConditionals.h>
 
 		// Is this a Mac or an IPhone?
 		#ifdef TARGET_OS_IPHONE
@@ -622,9 +623,9 @@
 			#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2
 			#define COMPLEX_OBJS_PASSED_BY_REF
 			#undef COMPLEX_MASK
-			#define COMPLEX_MASK asOBJ_APP_CLASS_DESTRUCTOR
+			#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
 			#undef COMPLEX_RETURN_MASK
-			#define COMPLEX_RETURN_MASK asOBJ_APP_CLASS_DESTRUCTOR
+			#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
 			
 			// STDCALL is not available on ARM
 			#undef STDCALL

+ 2 - 1
ThirdParty/FreeType/src/base/ftbase.c

@@ -15,6 +15,7 @@
 /*                                                                         */
 /***************************************************************************/
 
+// Modified by Lasse Öörni for Urho3D
 
 #include <ft2build.h>
 
@@ -34,7 +35,7 @@
 #include "fttrigon.c"
 #include "ftutil.c"
 
-#if defined( FT_MACINTOSH ) && !defined ( DARWIN_NO_CARBON )
+#if defined( FT_MACINTOSH ) && !defined ( DARWIN_NO_CARBON ) && !defined(IOS)
 #include "ftmac.c"
 #endif
 

+ 6 - 9
ThirdParty/SDL/CMakeLists.txt

@@ -10,6 +10,10 @@ if (WIN32)
     file (GLOB SYS_C_FILES
         src/audio/directsound/*.c src/joystick/windows/*.c src/core/windows/*.c src/loadso/windows/*.c src/thread/windows/*.c src/timer/windows/*.c src/video/windows/*.c
     )
+elseif (IOS)
+    file (GLOB SYS_C_FILES
+        src/audio/coreaudio/*.c src/file/cocoa/*.m src/joystick/iphoneos/*.m src/loadso/dlopen/*.c src/thread/pthread/*.c src/timer/unix/*.c src/video/uikit/*.m src/video/uikit/*.c
+    )
 elseif (APPLE)
     file (GLOB SYS_C_FILES
         src/audio/coreaudio/*.c src/joystick/darwin/*.c src/loadso/dlopen/*.c src/thread/pthread/*.c src/timer/unix/*.c src/video/cocoa/*.m
@@ -35,15 +39,8 @@ if (WIN32)
     else ()
         target_link_libraries (${TARGET_NAME} winmm.lib)
     endif ()
-elseif (APPLE)
-    FIND_LIBRARY (AUDIOUNIT_FW AudioUnit)
-    FIND_LIBRARY (CARBON_FW Carbon)
-    FIND_LIBRARY (COCOA_FW Cocoa)
-    FIND_LIBRARY (COREAUDIO_FW CoreAudio)
-    FIND_LIBRARY (FORCEFEEDBACK_FW ForceFeedback)
-    FIND_LIBRARY (IOKIT_FW IOKit)
-    FIND_LIBRARY (OPENGL_FW OpenGL)
-    target_link_libraries (${TARGET_NAME} dl pthread ${AUDIOUNIT_FW} ${CARBON_FW} ${COCOA_FW} ${COREAUDIO_FW} ${FORCEFEEDBACK_FW} ${IOKIT_FW} ${OPENGL_FW})
+elseif (APPLE)
+    target_link_libraries (${TARGET_NAME} dl pthread)
 else ()
     target_link_libraries (${TARGET_NAME} dl pthread GL)
 endif ()

+ 3 - 1
ThirdParty/SDL/include/SDL_config_iphoneos.h

@@ -19,6 +19,8 @@
   3. This notice may not be removed or altered from any source distribution.
 */
 
+// Modified by Lasse Öörni for Urho3D
+
 #ifndef _SDL_config_iphoneos_h
 #define _SDL_config_iphoneos_h
 
@@ -135,7 +137,7 @@
 #define SDL_VIDEO_RENDER_OGL_ES2	1
 
 /* Enable system power support */
-#define SDL_POWER_UIKIT 1
+// #define SDL_POWER_UIKIT 1
 
 /* enable iPhone keyboard support */
 #define SDL_IPHONE_KEYBOARD 1

+ 120 - 96
ThirdParty/SDL/src/video/uikit/SDL_uikitappdelegate.m

@@ -18,6 +18,9 @@
      misrepresented as being the original software.
   3. This notice may not be removed or altered from any source distribution.
 */
+
+// Modified by Lasse Öörni for Urho3D
+
 #include "SDL_config.h"
 
 #if SDL_VIDEO_DRIVER_UIKIT
@@ -29,7 +32,7 @@
 
 #import "SDL_uikitappdelegate.h"
 #import "SDL_uikitopenglview.h"
-#import "SDL_events_c.h"
+#import "../../events/SDL_events_c.h"
 #import "jumphack.h"
 
 #ifdef main
@@ -40,6 +43,7 @@ extern int SDL_main(int argc, char *argv[]);
 static int forward_argc;
 static char **forward_argv;
 static int exit_status;
+static char *resource_dir = 0;
 
 int main(int argc, char **argv)
 {
@@ -68,6 +72,27 @@ int main(int argc, char **argv)
     return exit_status;
 }
 
+// Urho3D: added function
+void SDL_IOS_LogMessage(const char *message)
+{   
+    #ifdef XCODE_DEBUG_CONFIGURATION
+    NSLog(@"%@", [NSString stringWithUTF8String: message]);
+    #endif
+}
+
+// Urho3D: added function
+const char* SDL_IOS_GetResourceDir()
+{
+    if (!resource_dir)
+    {
+        const char *temp = [[[NSBundle mainBundle] resourcePath] UTF8String];
+        resource_dir = malloc(strlen(temp + 1));
+        strcpy(resource_dir, temp);
+    }
+    
+    return resource_dir;
+}
+
 static void SDL_IdleTimerDisabledChanged(const char *name, const char *oldValue, const char *newValue)
 {
     SDL_assert(SDL_strcmp(name, SDL_HINT_IDLE_TIMER_DISABLED) == 0);
@@ -120,100 +145,99 @@ static void SDL_IdleTimerDisabledChanged(const char *name, const char *oldValue,
 
     return YES;
 }
-
-- (void)applicationWillTerminate:(UIApplication *)application
-{
-    SDL_Event event;
-    event.type=SDL_SYSEVENT_TERMINATE;
-    event.sysevent.data=NULL;
-    if (SDL_SysEventHandler)
-        SDL_SysEventHandler(&event);
-    else SDL_SendQuit();
-     /* hack to prevent automatic termination.  See SDL_uikitevents.m for details */
-    longjmp(*(jump_env()), 1);
-}
-
-- (void) applicationWillResignActive:(UIApplication*)application
-{
-    //NSLog(@"%@", NSStringFromSelector(_cmd));
-    SDL_Event event;
-    event.type=SDL_SYSEVENT_WILL_SUSPEND;
-    event.sysevent.data=NULL;
-    if (SDL_SysEventHandler)
-        SDL_SysEventHandler(&event);
-    else {
-    // Send every window on every screen a MINIMIZED event.
-        SDL_VideoDevice *_this = SDL_GetVideoDevice();
-        if (!_this) {
-            return;
-        }
-
-        SDL_Window *window;
-        for (window = _this->windows; window != nil; window = window->next) {
-            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
-            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
-        }
-    }
-}
-
-- (void)applicationDidEnterBackground:(UIApplication*)application
-{
-    //NSLog(@"%@", NSStringFromSelector(_cmd));
-	
-    SDL_Event event;
-    event.type=SDL_SYSEVENT_SUSPEND;
-    event.sysevent.data=NULL;
-    if (SDL_SysEventHandler)
-        SDL_SysEventHandler(&event);
-}
-
-- (void)applicationWillEnterForeground:(UIApplication*)application
-{
-    //NSLog(@"%@", NSStringFromSelector(_cmd));
-	
-    SDL_Event event;
-    event.type=SDL_SYSEVENT_WILL_RESUME;
-    event.sysevent.data=NULL;
-    if (SDL_SysEventHandler)
-        SDL_SysEventHandler(&event);
-}
-
-- (void) applicationDidBecomeActive:(UIApplication*)application
-{
-    //NSLog(@"%@", NSStringFromSelector(_cmd));
-
-    SDL_Event event;
-    event.type=SDL_SYSEVENT_RESUME;
-    event.sysevent.data=NULL;
-    if (SDL_SysEventHandler)
-        SDL_SysEventHandler(&event);
-    else {
-        // Send every window on every screen a RESTORED event.
-        SDL_VideoDevice *_this = SDL_GetVideoDevice();
-        if (!_this) {
-            return;
-        }
-
-        SDL_Window *window;
-        for (window = _this->windows; window != nil; window = window->next) {
-            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
-            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
-        }
-    }
-}
-
-- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application
-{
-    //NSLog(@"%@", NSStringFromSelector(_cmd));
-	
-    SDL_Event event;
-    event.type=SDL_SYSEVENT_LOWMEMORY;
-    event.sysevent.data=NULL;
-    if (SDL_SysEventHandler)
-        SDL_SysEventHandler(&event);
-}
-@end
-
-#endif /* SDL_VIDEO_DRIVER_UIKIT */
+
+- (void)applicationWillTerminate:(UIApplication *)application
+{
+    SDL_Event event;
+    event.type=SDL_SYSEVENT_TERMINATE;
+    event.sysevent.data=NULL;
+    if (SDL_SysEventHandler)
+        SDL_SysEventHandler(&event);
+    else 
+        SDL_SendQuit();
+}
+
+- (void) applicationWillResignActive:(UIApplication*)application
+{
+    //NSLog(@"%@", NSStringFromSelector(_cmd));
+    SDL_Event event;
+    event.type=SDL_SYSEVENT_WILL_SUSPEND;
+    event.sysevent.data=NULL;
+    if (SDL_SysEventHandler)
+        SDL_SysEventHandler(&event);
+    else {
+    // Send every window on every screen a MINIMIZED event.
+        SDL_VideoDevice *_this = SDL_GetVideoDevice();
+        if (!_this) {
+            return;
+        }
+
+        SDL_Window *window;
+        for (window = _this->windows; window != nil; window = window->next) {
+            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
+            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
+        }
+    }
+}
+
+- (void)applicationDidEnterBackground:(UIApplication*)application
+{
+    //NSLog(@"%@", NSStringFromSelector(_cmd));
+	
+    SDL_Event event;
+    event.type=SDL_SYSEVENT_SUSPEND;
+    event.sysevent.data=NULL;
+    if (SDL_SysEventHandler)
+        SDL_SysEventHandler(&event);
+}
+
+- (void)applicationWillEnterForeground:(UIApplication*)application
+{
+    //NSLog(@"%@", NSStringFromSelector(_cmd));
+	
+    SDL_Event event;
+    event.type=SDL_SYSEVENT_WILL_RESUME;
+    event.sysevent.data=NULL;
+    if (SDL_SysEventHandler)
+        SDL_SysEventHandler(&event);
+}
+
+- (void) applicationDidBecomeActive:(UIApplication*)application
+{
+    //NSLog(@"%@", NSStringFromSelector(_cmd));
+
+    SDL_Event event;
+    event.type=SDL_SYSEVENT_RESUME;
+    event.sysevent.data=NULL;
+    if (SDL_SysEventHandler)
+        SDL_SysEventHandler(&event);
+    else {
+        // Send every window on every screen a RESTORED event.
+        SDL_VideoDevice *_this = SDL_GetVideoDevice();
+        if (!_this) {
+            return;
+        }
+
+        SDL_Window *window;
+        for (window = _this->windows; window != nil; window = window->next) {
+            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
+            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
+        }
+    }
+}
+
+- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application
+{
+    //NSLog(@"%@", NSStringFromSelector(_cmd));
+	
+    SDL_Event event;
+    event.type=SDL_SYSEVENT_LOWMEMORY;
+    event.sysevent.data=NULL;
+    if (SDL_SysEventHandler)
+        SDL_SysEventHandler(&event);
+}
+@end
+
+#endif /* SDL_VIDEO_DRIVER_UIKIT */
 
 /* vi: set ts=4 sw=4 expandtab: */

+ 7 - 18
ThirdParty/SDL/src/video/uikit/SDL_uikitevents.m

@@ -18,6 +18,9 @@
      misrepresented as being the original software.
   3. This notice may not be removed or altered from any source distribution.
 */
+
+// Modified by Lasse Öörni for Urho3D
+
 #include "SDL_config.h"
 
 #if SDL_VIDEO_DRIVER_UIKIT
@@ -33,24 +36,10 @@
 void
 UIKit_PumpEvents(_THIS)
 {
-    /*
-        When the user presses the 'home' button on the iPod
-        the application exits -- immediatly.
-
-        Unlike in Mac OS X, it appears there is no way to cancel the termination.
-
-        This doesn't give the SDL user's application time to respond to an SDL_Quit event.
-        So what we do is that in the UIApplicationDelegate class (SDLUIApplicationDelegate),
-        when the delegate receives the ApplicationWillTerminate message, we execute
-        a longjmp statement to get back here, preventing an immediate exit.
-     */
-    if (setjmp(*jump_env()) == 0) {
-        /* if we're setting the jump, rather than jumping back */
-        SInt32 result;
-        do {
-            result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE);
-        } while (result == kCFRunLoopRunHandledSource);
-    }
+    SInt32 result;
+    do {
+        result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE);
+    } while (result == kCFRunLoopRunHandledSource);
 }
 
 #endif /* SDL_VIDEO_DRIVER_UIKIT */

+ 4 - 1
ThirdParty/SDL/src/video/uikit/SDL_uikitopengles.m

@@ -18,6 +18,9 @@
      misrepresented as being the original software.
   3. This notice may not be removed or altered from any source distribution.
 */
+
+// Modified by Lasse Öörni for Urho3D
+
 #include "SDL_config.h"
 
 #if SDL_VIDEO_DRIVER_UIKIT
@@ -27,7 +30,7 @@
 #include "SDL_uikitappdelegate.h"
 #include "SDL_uikitwindow.h"
 #include "jumphack.h"
-#include "SDL_sysvideo.h"
+#include "../../video/SDL_sysvideo.h"
 #include "../../events/SDL_keyboard_c.h"
 #include "../../events/SDL_mouse_c.h"
 #include "../../power/uikit/SDL_syspower.h"

+ 12 - 4
ThirdParty/SDL/src/video/uikit/SDL_uikitview.m

@@ -18,6 +18,9 @@
      misrepresented as being the original software.
   3. This notice may not be removed or altered from any source distribution.
 */
+
+// Modified by Lasse Öörni for Urho3D
+
 #include "SDL_config.h"
 
 #if SDL_VIDEO_DRIVER_UIKIT
@@ -93,15 +96,16 @@
     NSEnumerator *enumerator = [touches objectEnumerator];
     UITouch *touch = (UITouch*)[enumerator nextObject];
 
+    // Urho3D: do not send mouse events for touch to be consistent with Android
+    /*
     if (touch) {
         CGPoint locationInView = [touch locationInView: self];
 
-        /* send moved event */
         SDL_SendMouseMotion(NULL, 0, locationInView.x, locationInView.y);
 
-        /* send mouse down event */
         SDL_SendMouseButton(NULL, SDL_PRESSED, SDL_BUTTON_LEFT);
     }
+    */
 
 #ifdef FIXED_MULTITOUCH
     while(touch) {
@@ -137,10 +141,12 @@
     NSEnumerator *enumerator = [touches objectEnumerator];
     UITouch *touch = (UITouch*)[enumerator nextObject];
 
+    // Urho3D: do not send mouse events for touch to be consistent with Android
+    /*
     if (touch) {
-        /* send mouse up */
         SDL_SendMouseButton(NULL, SDL_RELEASED, SDL_BUTTON_LEFT);
     }
+    */
 
 #ifdef FIXED_MULTITOUCH
     while(touch) {
@@ -183,12 +189,14 @@
     NSEnumerator *enumerator = [touches objectEnumerator];
     UITouch *touch = (UITouch*)[enumerator nextObject];
 
+    // Urho3D: do not send mouse events for touch to be consistent with Android
+    /*
     if (touch) {
         CGPoint locationInView = [touch locationInView: self];
 
-        /* send moved event */
         SDL_SendMouseMotion(NULL, 0, locationInView.x, locationInView.y);
     }
+    */
 
 #ifdef FIXED_MULTITOUCH
     while(touch) {

+ 4 - 1
Tools/AssetImporter/CMakeLists.txt

@@ -13,7 +13,10 @@ include_directories (
     ../../ThirdParty/Bullet/src
 )
 
-# Define target & libraries to link
+# Define target & libraries to link
+if (APPLE)
+    set (CMAKE_EXE_LINKER_FLAGS "-framework AudioUnit -framework Carbon -framework Cocoa -framework CoreAudio -framework ForceFeedback -framework IOKit -framework OpenGL")
+endif ()
 add_executable (${TARGET_NAME} ${SOURCE_FILES})
 target_link_libraries (${TARGET_NAME} Assimp Container Core Graphics IO Math Physics Scene Resource)
 finalize_exe ()

+ 14 - 1
Urho3D/CMakeLists.txt

@@ -15,9 +15,22 @@ include_directories (
 # Define target & libraries to link
 if (WIN32)
     add_executable (${TARGET_NAME} WIN32 ${SOURCE_FILES})
+elseif (IOS)
+    set (RESOURCE_DIR \${TARGET_BUILD_DIR}/\${FULL_PRODUCT_NAME})
+    set (CMAKE_EXE_LINKER_FLAGS "-framework AudioToolbox -framework CoreAudio -framework CoreGraphics -framework Foundation -framework OpenGLES -framework QuartzCore -framework UIKit")
+    add_executable (${TARGET_NAME} MACOSX_BUNDLE ${SOURCE_FILES})
+    add_dependencies (${TARGET_NAME} Models Shaders)
+    add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
+        COMMAND /Developer/Library/PrivateFrameworks/DevToolsCore.framework/Resources/pbxcp -exclude .svn -exclude .rule -resolve-src-symlinks ${CMAKE_SOURCE_DIR}/Bin/CoreData ${RESOURCE_DIR}
+        COMMAND /Developer/Library/PrivateFrameworks/DevToolsCore.framework/Resources/pbxcp -exclude .svn -exclude .rule -resolve-src-symlinks ${CMAKE_SOURCE_DIR}/Bin/Data ${RESOURCE_DIR}
+    )
+    set_target_properties(${TARGET_NAME} PROPERTIES XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2")
+elseif (APPLE)
+    set (CMAKE_EXE_LINKER_FLAGS "-framework AudioUnit -framework Carbon -framework Cocoa -framework CoreAudio -framework ForceFeedback -framework IOKit -framework OpenGL")
+    add_executable (${TARGET_NAME} ${SOURCE_FILES})
 else ()
     add_executable (${TARGET_NAME} ${SOURCE_FILES})
 endif ()
 
-target_link_libraries (${TARGET_NAME} Container Core Engine IO Math Resource Script ${DBGHELP_LIB})
+target_link_libraries (${TARGET_NAME} Container Core Engine IO Math Resource Script)
 finalize_exe ()

+ 5 - 5
Urho3D/Urho3D.cpp

@@ -64,12 +64,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, in
     return 0;
 }
 #else
-#ifndef ANDROID
-int main(int argc, char** argv)
-#else
+#if defined(ANDROID) || defined(IOS)
 extern "C" int SDL_main(int argc, char** argv);
 
 int SDL_main(int argc, char** argv)
+#else
+int main(int argc, char** argv)
 #endif
 {
     ParseArguments(argc, argv);
@@ -94,8 +94,8 @@ void Run()
             }
         }
         
-        #ifdef ANDROID
-        // Can not pass script name on Android, so choose a hardcoded default
+        #if defined(ANDROID) || defined(IOS)
+        // Can not pass script name on mobile devices, so choose a hardcoded default
         scriptFileName = "Scripts/NinjaSnowWar.as";
         #endif
         

+ 2 - 0
cmake_ios.sh

@@ -0,0 +1,2 @@
+cmake -G "Xcode" -DIOS=1
+sed -i.bak 's/lastKnownFileType = sourcecode; name = "as_callfunc_arm_xcode.S"/lastKnownFileType = sourcecode.asm; name = "as_callfunc_arm_xcode.S"/g' Urho3D.xcodeproj/project.pbxproj