gamnit: intro core gamnit graphics services for iOS
authorAlexis Laferrière <alexis.laf@xymus.net>
Mon, 11 Dec 2017 03:32:15 +0000 (22:32 -0500)
committerAlexis Laferrière <alexis.laf@xymus.net>
Wed, 17 Jan 2018 20:30:10 +0000 (15:30 -0500)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

lib/gamnit/display.nit
lib/gamnit/display_ios.nit [new file with mode: 0644]
lib/gamnit/gamnit.nit
lib/gamnit/gamnit_ios.nit [new file with mode: 0644]

index 868b359..0d78907 100644 (file)
@@ -20,6 +20,7 @@ import mnit::input
 
 import display_linux is conditional(linux)
 import display_android is conditional(android)
+import display_ios is conditional(ios)
 
 # Should Gamnit be more verbose?
 fun debug_gamnit: Bool do return false
diff --git a/lib/gamnit/display_ios.nit b/lib/gamnit/display_ios.nit
new file mode 100644 (file)
index 0000000..3b8cfdb
--- /dev/null
@@ -0,0 +1,111 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Gamnit display implementation for iOS
+module display_ios
+
+import ios
+import ios::glkit
+intrude import ios::assets
+intrude import textures
+
+in "ObjC" `{
+       #import <GLKit/GLKit.h>
+       #import <OpenGLES/ES2/gl.h>
+`}
+
+redef class GamnitDisplay
+
+       redef var width = 200
+       redef var height = 300
+
+       # Underlying GLKit game controller and view
+       var glk_view: NitGLKView is noautoinit
+
+       redef fun setup
+       do
+               var view = new GamnitGLKView
+               view.multiple_touch_enabled = true
+               self.glk_view = view
+               self.width = view.drawable_width
+               self.height = view.drawable_height
+       end
+end
+
+# View controller implemented by gamnit
+class GamnitGLKView
+       super NitGLKView
+end
+
+redef class TextureAsset
+       redef fun load_from_platform
+       do
+               var error = glGetError
+               assert error == gl_NO_ERROR else print_error error
+
+               # Find file
+               var ns_path = ("assets"/path).to_nsstring
+               var path_in_bundle = asset_path(ns_path)
+               if path_in_bundle.address_is_null then
+                       self.error = new Error("Texture at '{path}' not found")
+                       return
+               end
+
+               # Load texture
+               var glk_texture = glkit_load(path_in_bundle, premultiply_alpha)
+               if glk_texture.address_is_null then
+                       self.error = new Error("Failed to load texture at '{self.path}'")
+                       return
+               end
+
+               gl_texture = glk_texture.name
+               width = glk_texture.width.to_f
+               height = glk_texture.height.to_f
+               loaded = true
+
+               error = glGetError
+               assert error == gl_NO_ERROR
+       end
+
+       # Load image at `path` with GLKit services
+       private fun glkit_load(path: NSString, premultiply: Bool): GLKTextureInfo
+       in "ObjC" `{
+
+               // The premultiplication flag has been inverted between iOS 9 and 10
+               NSNumber *premultiply_opt;
+               NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare: @"10.0.0" options: NSNumericSearch];
+               if (order == NSOrderedSame || order == NSOrderedDescending) {
+                       // >= 10
+                       premultiply_opt = premultiply? @NO: @YES;
+               } else {
+                       // < 10
+                       premultiply_opt = premultiply? @YES: @NO;
+               }
+
+               NSDictionary *options = @{GLKTextureLoaderApplyPremultiplication: premultiply_opt};
+               NSError *error;
+               GLKTextureInfo *spriteTexture = [GLKTextureLoader textureWithContentsOfFile: path options: options error: &error];
+               if (error != nil) NSLog(@"Failed to load texture: %@", [error localizedDescription]); // TODO return details to Nit
+
+               return spriteTexture;
+       `}
+end
+
+private extern class GLKTextureInfo in "ObjC" `{ GLKTextureInfo * `}
+       super NSObject
+
+       fun name: Int in "ObjC" `{ return self.name; `}
+       fun width: Int in "ObjC" `{ return self.width; `}
+       fun height: Int in "ObjC" `{ return self.height; `}
+end
index 05bd122..d4f6830 100644 (file)
@@ -23,6 +23,7 @@ import programs
 
 import gamnit_android is conditional(android)
 import gamnit_linux is conditional(linux)
+import gamnit_ios is conditional(ios)
 
 redef class App
 
diff --git a/lib/gamnit/gamnit_ios.nit b/lib/gamnit/gamnit_ios.nit
new file mode 100644 (file)
index 0000000..1a678f1
--- /dev/null
@@ -0,0 +1,44 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Support services for gamnit on iOS
+module gamnit_ios
+
+import ios
+import gamnit
+
+redef class App
+       redef fun did_finish_launching_with_options
+       do
+               create_gamnit
+               create_scene
+               return super
+       end
+
+       # Disable the game loop to rely on the GLKView callbacks on each frame instead
+       redef fun run do end
+
+       private fun frame_full_indirect do frame_full
+end
+
+redef class GamnitGLKView
+       redef fun update do app.frame_full_indirect
+end
+
+redef fun bind_screen_framebuffer(fbo)
+do
+       var display = app.display
+       assert display != null
+       display.glk_view.bind_drawable
+end