Explorar el Código

Merge pull request #2411 from joliver82/ios-2024_2

iOS support
Ryan McDonough hace 4 días
padre
commit
574da1a07a

+ 60 - 1
.github/workflows/main.yml

@@ -51,6 +51,7 @@ on:
       - v3.5
       - v3.5
       - v3.4
       - v3.4
       - v3.3
       - v3.3
+      - ios-2024_2
   pull_request:
   pull_request:
   release:
   release:
     types: [published]
     types: [published]
@@ -94,6 +95,46 @@ jobs:
             **/build/reports/**
             **/build/reports/**
             **/build/changed-images/**
             **/build/changed-images/**
             **/build/test-results/**
             **/build/test-results/**
+
+  # Build iOS natives
+  BuildIosNatives:
+    name: Build natives for iOS
+    runs-on: macOS-14
+
+    steps:
+      - name: Check default JAVAs 
+        run: echo $JAVA_HOME --- $JAVA_HOME_8_X64 --- $JAVA_HOME_11_X64 --- $JAVA_HOME_17_X64 --- $JAVA_HOME_21_X64 ---
+
+      - name: Setup the java environment
+        uses: actions/setup-java@v4
+        with:
+          distribution: 'temurin'
+          java-version: '11.0.26+4'
+
+      - name: Setup the XCode version to 15.1.0 
+        uses: maxim-lobanov/setup-xcode@v1
+        with:
+          xcode-version: '15.1.0'
+
+      - name: Clone the repo
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 1
+
+      - name: Validate the Gradle wrapper
+        uses: gradle/actions/wrapper-validation@v3
+
+      - name: Build
+        run: |
+          ./gradlew -PuseCommitHashAsVersionName=true --no-daemon -PbuildNativeProjects=true \
+          :jme3-ios-native:build
+
+      - name: Upload natives
+        uses: actions/upload-artifact@master
+        with:
+          name: ios-natives
+          path: jme3-ios-native/template/META-INF/robovm/ios/libs/jme3-ios-native.xcframework
+
   # Build the natives on android
   # Build the natives on android
   BuildAndroidNatives:
   BuildAndroidNatives:
     name: Build natives for android
     name: Build natives for android
@@ -139,7 +180,7 @@ jobs:
 
 
   # Build the engine, we only deploy from ubuntu-latest jdk21
   # Build the engine, we only deploy from ubuntu-latest jdk21
   BuildJMonkey:
   BuildJMonkey:
-    needs: [BuildAndroidNatives]
+    needs: [BuildAndroidNatives, BuildIosNatives]
     name: Build on ${{ matrix.osName }} jdk${{ matrix.jdk }}
     name: Build on ${{ matrix.osName }} jdk${{ matrix.jdk }}
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
     strategy:
     strategy:
@@ -180,6 +221,12 @@ jobs:
           name: android-natives
           name: android-natives
           path: build/native
           path: build/native
 
 
+      - name: Download natives for iOS
+        uses: actions/download-artifact@master
+        with:
+          name: ios-natives
+          path: jme3-ios-native/template/META-INF/robovm/ios/libs/jme3-ios-native.xcframework
+
       - name: Validate the Gradle wrapper
       - name: Validate the Gradle wrapper
         uses: gradle/actions/wrapper-validation@v3
         uses: gradle/actions/wrapper-validation@v3
       - name: Build Engine
       - name: Build Engine
@@ -372,6 +419,12 @@ jobs:
           name: android-natives
           name: android-natives
           path: build/native
           path: build/native
 
 
+      - name: Download natives for iOS
+        uses: actions/download-artifact@master
+        with:
+          name: ios-natives
+          path: jme3-ios-native/template/META-INF/robovm/ios/libs/jme3-ios-native.xcframework
+
       - name: Rebuild the maven artifacts and upload them to Sonatype's maven-snapshots repo
       - name: Rebuild the maven artifacts and upload them to Sonatype's maven-snapshots repo
         run: |
         run: |
           if [ "${{ secrets.CENTRAL_PASSWORD }}" = "" ];
           if [ "${{ secrets.CENTRAL_PASSWORD }}" = "" ];
@@ -429,6 +482,12 @@ jobs:
           name: android-natives
           name: android-natives
           path: build/native
           path: build/native
 
 
+      - name: Download natives for iOS
+        uses: actions/download-artifact@master
+        with:
+          name: ios-natives
+          path: jme3-ios-native/template/META-INF/robovm/ios/libs/jme3-ios-native.xcframework
+
       - name: Rebuild the maven artifacts and upload them to Sonatype's Central Publisher Portal
       - name: Rebuild the maven artifacts and upload them to Sonatype's Central Publisher Portal
         run: |
         run: |
           if [ "${{ secrets.CENTRAL_PASSWORD }}" = "" ];
           if [ "${{ secrets.CENTRAL_PASSWORD }}" = "" ];

+ 35 - 0
jme3-ios-native/build.gradle

@@ -0,0 +1,35 @@
+import org.apache.tools.ant.taskdefs.condition.Os
+
+task deleteXcframework(type: Delete) {
+    delete 'template/META-INF/robovm/ios/libs/jme3-ios-native.xcframework'
+}
+
+task buildNativeLibIos(type: Exec) {
+    executable "xcodebuild"
+    args 'archive', '-project', 'jme3-ios-native.xcodeproj', '-scheme', 'jme3-ios-native', '-configuration', 'release', '-destination', 'generic/platform=iOS', '-archivePath', 'build/archives/jme3-ios-native_iOS', 'SKIP_INSTALL=NO', 'BUILD_LIBRARY_FOR_DISTRIBUTION=YES'
+}
+
+task buildNativeLibSimulator(type: Exec) {
+    executable "xcodebuild"
+    args 'archive', '-project', 'jme3-ios-native.xcodeproj', '-scheme', 'jme3-ios-native', '-configuration', 'release', '-destination', 'generic/platform=iOS Simulator', '-archivePath', 'build/archives/jme3-ios-native_iOS-Simulator', 'SKIP_INSTALL=NO', 'BUILD_LIBRARY_FOR_DISTRIBUTION=YES'
+}
+
+task buildNativeLib(type: Exec) {
+    dependsOn 'deleteXcframework'
+    dependsOn 'buildNativeLibIos'
+    dependsOn 'buildNativeLibSimulator'
+    executable "xcodebuild"
+    args '-create-xcframework', '-framework', 'build/archives/jme3-ios-native_iOS.xcarchive/Products/Library/Frameworks/jme3_ios_native.framework', '-framework', 'build/archives/jme3-ios-native_iOS-Simulator.xcarchive/Products/Library/Frameworks/jme3_ios_native.framework', '-output', 'template/META-INF/robovm/ios/libs/jme3-ios-native.xcframework'
+}
+
+// buildNativeProjects is a string set to "true"
+if (Os.isFamily(Os.FAMILY_MAC) && buildNativeProjects == "true") {
+    // build native libs and update stored pre-compiled libs to commit
+    compileJava.dependsOn { buildNativeLib }
+} else {
+    // TODO: (like android natives?) use pre-compiled native libs (not building new ones)
+    // compileJava.dependsOn { copyPreCompiledLibs }
+    println "Native build disable or not running on OSX"
+}
+
+jar.into("") { from "template" }

+ 11 - 0
jme3-ios-native/export.sh

@@ -0,0 +1,11 @@
+rm -rf intermediate-builds release template/META-INF/robovm/ios/libs/jme3-ios-native.xcframework
+mkdir intermediate-builds release
+xcodebuild archive -project jme3-ios-native.xcodeproj -scheme jme3-ios-native -destination generic/platform=iOS -archivePath intermediate-builds/jme3-ios-native_iOS SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
+xcodebuild archive -project jme3-ios-native.xcodeproj -scheme jme3-ios-native -destination generic/platform="iOS Simulator" -archivePath intermediate-builds/jme3-ios-native_iOS-Simulator SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
+
+xcodebuild -create-xcframework -framework intermediate-builds/jme3-ios-native_iOS.xcarchive/Products/Library/Frameworks/jme3_ios_native.framework -framework intermediate-builds/jme3-ios-native_iOS-Simulator.xcarchive/Products/Library/Frameworks/jme3_ios_native.framework -output template/META-INF/robovm/ios/libs/jme3-ios-native.xcframework
+
+cd template
+zip -r ../release/jme3-ios-native.jar META-INF
+cd ..
+

+ 416 - 0
jme3-ios-native/jme3-ios-native.xcodeproj/project.pbxproj

@@ -0,0 +1,416 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 52;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		BB0987B82CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.c in Sources */ = {isa = PBXBuildFile; fileRef = BB0987B62CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.c */; };
+		BB0987B92CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = BB0987B72CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BBAA18642C9CC9B40015DF5E /* jme3_ios_native.h in Headers */ = {isa = PBXBuildFile; fileRef = BBAA18622C9CC9B40015DF5E /* jme3_ios_native.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BBAA18752C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.c in Sources */ = {isa = PBXBuildFile; fileRef = BBAA186A2C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.c */; };
+		BBAA18762C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.c in Sources */ = {isa = PBXBuildFile; fileRef = BBAA186B2C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.c */; };
+		BBAA18772C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.h in Headers */ = {isa = PBXBuildFile; fileRef = BBAA186C2C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BBAA18782C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.h in Headers */ = {isa = PBXBuildFile; fileRef = BBAA186D2C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BBAA18792C9CCACB0015DF5E /* JmeAppHarness.m in Sources */ = {isa = PBXBuildFile; fileRef = BBAA186E2C9CCACB0015DF5E /* JmeAppHarness.m */; };
+		BBAA187A2C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.h in Headers */ = {isa = PBXBuildFile; fileRef = BBAA186F2C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BBAA187B2C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.c in Sources */ = {isa = PBXBuildFile; fileRef = BBAA18702C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.c */; };
+		BBAA187C2C9CCACB0015DF5E /* JmeIosGLES.m in Sources */ = {isa = PBXBuildFile; fileRef = BBAA18712C9CCACB0015DF5E /* JmeIosGLES.m */; };
+		BBAA187D2C9CCACB0015DF5E /* JmeAppHarness.java in Sources */ = {isa = PBXBuildFile; fileRef = BBAA18722C9CCACB0015DF5E /* JmeAppHarness.java */; };
+		BBAA187E2C9CCACB0015DF5E /* jme-ios.m in Sources */ = {isa = PBXBuildFile; fileRef = BBAA18732C9CCACB0015DF5E /* jme-ios.m */; };
+		BBAA18822C9CCB720015DF5E /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBAA18812C9CCB720015DF5E /* OpenGLES.framework */; platformFilter = ios; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		BB0987B62CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = com_jme3_util_IosNativeBufferAllocator.c; sourceTree = "<group>"; };
+		BB0987B72CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = com_jme3_util_IosNativeBufferAllocator.h; sourceTree = "<group>"; };
+		BBAA185F2C9CC9B40015DF5E /* jme3_ios_native.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = jme3_ios_native.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		BBAA18622C9CC9B40015DF5E /* jme3_ios_native.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = jme3_ios_native.h; sourceTree = "<group>"; };
+		BBAA18632C9CC9B40015DF5E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		BBAA186A2C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = com_jme3_audio_ios_IosEFX.c; sourceTree = "<group>"; };
+		BBAA186B2C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = com_jme3_audio_ios_IosALC.c; sourceTree = "<group>"; };
+		BBAA186C2C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = com_jme3_audio_ios_IosEFX.h; sourceTree = "<group>"; };
+		BBAA186D2C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = com_jme3_audio_ios_IosALC.h; sourceTree = "<group>"; };
+		BBAA186E2C9CCACB0015DF5E /* JmeAppHarness.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JmeAppHarness.m; sourceTree = "<group>"; };
+		BBAA186F2C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = com_jme3_audio_ios_IosAL.h; sourceTree = "<group>"; };
+		BBAA18702C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = com_jme3_audio_ios_IosAL.c; sourceTree = "<group>"; };
+		BBAA18712C9CCACB0015DF5E /* JmeIosGLES.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JmeIosGLES.m; sourceTree = "<group>"; };
+		BBAA18722C9CCACB0015DF5E /* JmeAppHarness.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; path = JmeAppHarness.java; sourceTree = "<group>"; };
+		BBAA18732C9CCACB0015DF5E /* jme-ios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "jme-ios.m"; sourceTree = "<group>"; };
+		BBAA18812C9CCB720015DF5E /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		BBAA185C2C9CC9B40015DF5E /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				BBAA18822C9CCB720015DF5E /* OpenGLES.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		BBAA18552C9CC9B40015DF5E = {
+			isa = PBXGroup;
+			children = (
+				BBAA18612C9CC9B40015DF5E /* src */,
+				BBAA18602C9CC9B40015DF5E /* Products */,
+				BBAA18802C9CCB710015DF5E /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		BBAA18602C9CC9B40015DF5E /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				BBAA185F2C9CC9B40015DF5E /* jme3_ios_native.framework */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		BBAA18612C9CC9B40015DF5E /* src */ = {
+			isa = PBXGroup;
+			children = (
+				BB0987B62CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.c */,
+				BB0987B72CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.h */,
+				BBAA18702C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.c */,
+				BBAA186F2C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.h */,
+				BBAA186B2C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.c */,
+				BBAA186D2C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.h */,
+				BBAA186A2C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.c */,
+				BBAA186C2C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.h */,
+				BBAA18732C9CCACB0015DF5E /* jme-ios.m */,
+				BBAA18722C9CCACB0015DF5E /* JmeAppHarness.java */,
+				BBAA186E2C9CCACB0015DF5E /* JmeAppHarness.m */,
+				BBAA18712C9CCACB0015DF5E /* JmeIosGLES.m */,
+				BBAA18622C9CC9B40015DF5E /* jme3_ios_native.h */,
+				BBAA18632C9CC9B40015DF5E /* Info.plist */,
+			);
+			path = src;
+			sourceTree = "<group>";
+		};
+		BBAA18802C9CCB710015DF5E /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				BBAA18812C9CCB720015DF5E /* OpenGLES.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		BBAA185A2C9CC9B40015DF5E /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				BBAA18772C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.h in Headers */,
+				BBAA187A2C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.h in Headers */,
+				BB0987B92CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.h in Headers */,
+				BBAA18782C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.h in Headers */,
+				BBAA18642C9CC9B40015DF5E /* jme3_ios_native.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+		BBAA185E2C9CC9B40015DF5E /* jme3-ios-native */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = BBAA18672C9CC9B40015DF5E /* Build configuration list for PBXNativeTarget "jme3-ios-native" */;
+			buildPhases = (
+				BBAA185A2C9CC9B40015DF5E /* Headers */,
+				BBAA185B2C9CC9B40015DF5E /* Sources */,
+				BBAA185C2C9CC9B40015DF5E /* Frameworks */,
+				BBAA185D2C9CC9B40015DF5E /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "jme3-ios-native";
+			productName = "jme3-ios-native";
+			productReference = BBAA185F2C9CC9B40015DF5E /* jme3_ios_native.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		BBAA18562C9CC9B40015DF5E /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 1130;
+				TargetAttributes = {
+					BBAA185E2C9CC9B40015DF5E = {
+						CreatedOnToolsVersion = 11.3.1;
+					};
+				};
+			};
+			buildConfigurationList = BBAA18592C9CC9B40015DF5E /* Build configuration list for PBXProject "jme3-ios-native" */;
+			compatibilityVersion = "Xcode 9.3";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = BBAA18552C9CC9B40015DF5E;
+			productRefGroup = BBAA18602C9CC9B40015DF5E /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				BBAA185E2C9CC9B40015DF5E /* jme3-ios-native */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		BBAA185D2C9CC9B40015DF5E /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		BBAA185B2C9CC9B40015DF5E /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				BBAA18762C9CCACB0015DF5E /* com_jme3_audio_ios_IosALC.c in Sources */,
+				BBAA187E2C9CCACB0015DF5E /* jme-ios.m in Sources */,
+				BBAA187D2C9CCACB0015DF5E /* JmeAppHarness.java in Sources */,
+				BBAA18752C9CCACB0015DF5E /* com_jme3_audio_ios_IosEFX.c in Sources */,
+				BBAA187B2C9CCACB0015DF5E /* com_jme3_audio_ios_IosAL.c in Sources */,
+				BBAA18792C9CCACB0015DF5E /* JmeAppHarness.m in Sources */,
+				BBAA187C2C9CCACB0015DF5E /* JmeIosGLES.m in Sources */,
+				BB0987B82CA2B31900AF4C26 /* com_jme3_util_IosNativeBufferAllocator.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		BBAA18652C9CC9B40015DF5E /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = NO;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.15;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		BBAA18662C9CC9B40015DF5E /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = NO;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				CURRENT_PROJECT_VERSION = 1;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.15;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+		BBAA18682C9CC9B40015DF5E /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				HEADER_SEARCH_PATHS = (
+					/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/JavaVM.framework/Headers/,
+					"/Library/Java/JavaVirtualMachines/jdk-11.0.6.jdk/Contents/Home/include/**",
+					"/Users/runner/hostedtoolcache/Java_Temurin-Hotspot_jdk/11.0.26-4/arm64/Contents/Home/include/**",
+				);
+				INFOPLIST_FILE = src/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/../Frameworks",
+					"@loader_path/Frameworks",
+				);
+				OTHER_CFLAGS = (
+					"-fno-stack-check",
+					"-fno-stack-protector",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = "jme3.jme3-ios-native";
+				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+				SKIP_INSTALL = YES;
+				SUPPORTS_MACCATALYST = YES;
+				USER_HEADER_SEARCH_PATHS = (
+					/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/JavaVM.framework/Headers/,
+					"/Library/Java/JavaVirtualMachines/jdk-11.0.6.jdk/Contents/Home/include/**",
+					"/Users/runner/hostedtoolcache/Java_Temurin-Hotspot_jdk/11.0.26-4/arm64/Contents/Home/include/**",
+				);
+			};
+			name = Debug;
+		};
+		BBAA18692C9CC9B40015DF5E /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				DEFINES_MODULE = YES;
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				HEADER_SEARCH_PATHS = (
+					/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/JavaVM.framework/Headers/,
+					"/Library/Java/JavaVirtualMachines/jdk-11.0.6.jdk/Contents/Home/include/**",
+					"/Users/runner/hostedtoolcache/Java_Temurin-Hotspot_jdk/11.0.26-4/arm64/Contents/Home/include/**",
+				);
+				INFOPLIST_FILE = src/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/../Frameworks",
+					"@loader_path/Frameworks",
+				);
+				OTHER_CFLAGS = (
+					"-fno-stack-check",
+					"-fno-stack-protector",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = "jme3.jme3-ios-native";
+				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+				SKIP_INSTALL = YES;
+				SUPPORTS_MACCATALYST = YES;
+				USER_HEADER_SEARCH_PATHS = (
+					/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/JavaVM.framework/Headers/,
+					"/Library/Java/JavaVirtualMachines/jdk-11.0.6.jdk/Contents/Home/include/**",
+					"/Users/runner/hostedtoolcache/Java_Temurin-Hotspot_jdk/11.0.26-4/arm64/Contents/Home/include/**",
+				);
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		BBAA18592C9CC9B40015DF5E /* Build configuration list for PBXProject "jme3-ios-native" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				BBAA18652C9CC9B40015DF5E /* Debug */,
+				BBAA18662C9CC9B40015DF5E /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		BBAA18672C9CC9B40015DF5E /* Build configuration list for PBXNativeTarget "jme3-ios-native" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				BBAA18682C9CC9B40015DF5E /* Debug */,
+				BBAA18692C9CC9B40015DF5E /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = BBAA18562C9CC9B40015DF5E /* Project object */;
+}

+ 22 - 0
jme3-ios-native/src/Info.plist

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>$(CURRENT_PROJECT_VERSION)</string>
+</dict>
+</plist>

+ 130 - 0
jme3-ios-native/src/JmeAppHarness.java

@@ -0,0 +1,130 @@
+import com.jme3.system.ios.IosHarness;
+import com.jme3.input.ios.IosInputHandler;
+import com.jme3.math.Vector2f;
+import com.jme3.renderer.opengl.GLRenderer;
+import com.jme3.system.JmeContext;
+import com.jme3.system.AppSettings;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * You can extend this class to perform iOS-only operations from java,
+ * native methods can reside either in .c/.m files in this directory
+ * or in the XCode project itself.
+ * @author normenhansen
+ */
+public class JmeAppHarness extends IosHarness{
+
+    private static final Logger logger = Logger.getLogger(JmeAppHarness.class.getName());
+	protected Renderer renderer;
+	protected IosInputHandler input;
+	protected boolean autoFlush = true;
+	protected Vector2f resizePending = null;
+
+
+    /**
+     * An instance of this object is created when your application
+     * has started on the iOS side.
+     * You can e.g. attach special AppStates or do similar things here. You can
+     * access classes from this source directory as well as your main projects
+     * sources and classpath.
+     */
+    public JmeAppHarness(long id) {
+        super(id);
+        app = new mygame.Main();
+        AppSettings settings = new AppSettings(true);
+        this.app.setSettings(settings);
+        app.start();
+        logger.log(Level.FINE, "JmeAppHarness constructor");
+        app.gainFocus();
+    }
+
+    @Override
+    public void appPaused() {
+        logger.log(Level.FINE, "JmeAppHarness appPaused");
+    }
+
+    @Override
+    public void appReactivated() {
+        logger.log(Level.FINE, "JmeAppHarness appReactivated");
+    }
+
+    @Override
+    public void appClosed() {
+        logger.log(Level.FINE, "JmeAppHarness appClosed");
+        app.stop();
+    }
+
+    @Override
+    public void appUpdate() {
+        logger.log(Level.FINE, "JmeAppHarness appUpdate");
+       //app.update();
+    }
+
+    @Override
+    public void appDraw() {
+        logger.log(Level.FINE, "JmeAppHarness appDraw");
+        if (renderer == null) {
+            JmeContext iosContext = app.getContext();
+            renderer = iosContext.getRenderer();
+            renderer.initialize();
+            input = (IosInputHandler)iosContext.getTouchInput();
+            input.initialize();
+        } else {
+            if(resizePending != null) {
+                appReshape((int)resizePending.x, (int)resizePending.y);
+                resizePending = null;
+            }
+            app.update();
+    	    if (autoFlush) {
+                renderer.postFrame();
+            }
+        }
+    }
+    
+    @Override
+    public void appReshape(int width, int height) {
+        logger.log(Level.FINE, "JmeAppHarness reshape");
+        AppSettings settings = app.getContext().getSettings();
+        settings.setResolution(width, height);
+        if (renderer != null) {
+            app.reshape(width, height);
+            resizePending = null;
+        } else {
+            resizePending = new Vector2f(width, height);
+        }
+
+        if (input != null) {
+            input.loadSettings(settings);
+        }
+    }
+    
+    public void injectTouchBegin(int pointerId, long time, float x, float y) {
+    	if (input != null) {
+        	logger.log(Level.FINE, "JmeAppHarness injectTouchBegin");
+    		input.injectTouchDown(pointerId, time, x, y);
+    	}
+    }
+    
+    public void injectTouchMove(int pointerId, long time, float x, float y) {
+    	if (input != null) {
+        	logger.log(Level.FINE, "JmeAppHarness injectTouchMove");
+    		input.injectTouchMove(pointerId, time, x, y);
+    	}
+    }
+    
+    public void injectTouchEnd(int pointerId, long time, float x, float y) {
+    	if (input != null) {
+        	logger.log(Level.FINE, "JmeAppHarness injectTouchEnd");
+    		input.injectTouchUp(pointerId, time, x, y);
+    	}
+    }
+    
+    /**
+     * Example of a native method calling iOS code.
+     * See the native code in IosHarness.m
+     * @param text The message to display
+     */
+    public native void showDialog(String text);
+
+}

+ 60 - 0
jme3-ios-native/src/JmeAppHarness.m

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009-2013 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <jni.h>
+#import <UIKit/UIKit.h>
+
+/**
+ * Author: Normen Hansen
+ */
+
+#ifndef JNIEXPORT
+#define JNIEXPORT __attribute__ ((visibility("default"))) \
+  __attribute__ ((used))
+#endif
+
+#ifndef _Included_JmeAppHarness
+#define _Included_JmeAppHarness
+#endif
+
+JNIEXPORT void JNICALL
+Java_JmeAppHarness_showDialog(JNIEnv* e, jobject c, jstring text) {
+    const char* chars = (*e)->GetStringUTFChars(e, text, 0);
+    NSString* string = [[NSString alloc] initWithUTF8String : chars];
+    (*e)->ReleaseStringUTFChars(e, text, chars);
+    UIAlertView *alert = [[UIAlertView alloc] initWithTitle : @"Message"
+            message : string
+            delegate : nil
+            cancelButtonTitle : @"OK"
+            otherButtonTitles : nil];
+    [alert show];
+    [alert release];
+}

+ 2392 - 0
jme3-ios-native/src/JmeIosGLES.m

@@ -0,0 +1,2392 @@
+#import <stdlib.h>
+#define __LP64__ 1
+#import <jni.h>
+#import <OpenGLES/ES2/gl.h>
+#import <OpenGLES/ES2/glext.h>
+#import <OpenGLES/ES3/gl.h>
+#import <OpenGLES/ES3/glext.h>
+
+/**
+ * Author: Kostyantyn Hushchyn, Jesus Oliver
+ */
+
+#ifndef JNIEXPORT
+#define JNIEXPORT __attribute__ ((visibility("default"))) \
+  __attribute__ ((used))
+#endif
+
+#ifndef _Included_JmeIosGLES
+#define _Included_JmeIosGLES
+#endif
+
+#define glBindVertexArray glBindVertexArrayOES
+
+static int initialized = 0;
+
+static jclass bufferClass = (jclass)0;
+static jclass byteBufferClass = (jclass)0;
+static jclass shortBufferClass = (jclass)0;
+static jclass intBufferClass = (jclass)0;
+static jclass floatBufferClass = (jclass)0;
+static jfieldID positionID;
+static jfieldID limitID;
+
+
+static void
+nativeClassInit(JNIEnv *e);
+
+static int
+allowIndirectBuffers(JNIEnv *e);
+
+static void *
+getDirectBufferPointer(JNIEnv *e, jobject buffer);
+
+static void *
+getPointer(JNIEnv *e, jobject buffer, jarray *array, jint *remaining, jint *offset);
+
+static void
+releasePointer(JNIEnv *e, jarray array, void *data, jboolean commit);
+
+static void
+jniThrowException(JNIEnv *e, const char* type, const char* message);
+
+static jint
+getBufferElementSize(JNIEnv *e, jobject buffer);
+
+static int getNeededCount(GLint pname);
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glActiveTexture(JNIEnv* e, jobject c, jint texture) {
+    glActiveTexture(
+        (GLenum)texture
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glAttachShader(JNIEnv* e, jobject c, jint program, jint shader) {
+    glAttachShader(
+        (GLuint)program,
+        (GLuint)shader
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBindBuffer(JNIEnv* e, jobject c, jint target, jint buffer) {
+    glBindBuffer(
+        (GLenum)target,
+        (GLuint)buffer
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBindFramebuffer(JNIEnv* e, jobject c, jint target, jint framebuffer) {
+    glBindFramebuffer(
+        (GLenum)target,
+        (GLuint)framebuffer
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBindRenderbuffer(JNIEnv* e, jobject c, jint target, jint renderbuffer) {
+    glBindRenderbuffer(
+        (GLenum)target,
+        (GLuint)renderbuffer
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBindTexture(JNIEnv* e, jobject c, jint target, jint texture) {
+    glBindTexture(
+        (GLenum)target,
+        (GLuint)texture
+    );
+}
+
+ // TODO: Investigate this
+ /*
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBindVertexArray(JNIEnv* e, jobject c, jint array) {
+	glBindVertexArray(array);
+}
+*/
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBlendFunc(JNIEnv* e, jobject c, jint sfactor, jint dfactor) {
+    glBlendFunc(
+        (GLenum)sfactor,
+        (GLenum)dfactor
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBufferData(JNIEnv* e, jobject c, jint target, jint size, jobject data_buf, jint usage) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *data = (GLvoid *) 0;
+
+    if (data_buf) {
+        data = (GLvoid *)getPointer(e, data_buf, &_array, &_remaining, &_bufferOffset);
+        if (_remaining < size) {
+            _exception = 1;
+            _exceptionType = "java/lang/IllegalArgumentException";
+            _exceptionMessage = "remaining() < size < needed";
+            goto exit;
+        }
+    }
+    if (data_buf && data == NULL) {
+        char * _dataBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        data = (GLvoid *) (_dataBase + _bufferOffset);
+    }
+    glBufferData(
+        (GLenum)target,
+        (GLsizeiptr)size,
+        (GLvoid *)data,
+        (GLenum)usage
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, data, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBufferData2(JNIEnv* e, jobject c, jint target, jint size, jbyteArray data, jint offset, jint usage) {
+	jbyte *dataNative = (*e)->GetByteArrayElements(e, data, NULL);
+	
+    glBufferData(
+        (GLenum)target,
+        (GLsizeiptr)size,
+        (GLvoid *)dataNative,
+        (GLenum)(usage + offset)
+    );
+	
+	(*e)->ReleaseByteArrayElements(e, data, dataNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBufferSubData(JNIEnv* e, jobject c, jint target, jint offset, jint size, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *data = (GLvoid *) 0;
+
+    data = (GLvoid *)getPointer(e, data_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < size) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < size < needed";
+        goto exit;
+    }
+    if (data == NULL) {
+        char * _dataBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        data = (GLvoid *) (_dataBase + _bufferOffset);
+    }
+    glBufferSubData(
+        (GLenum)target,
+        (GLintptr)offset,
+        (GLsizeiptr)size,
+        (GLvoid *)data
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, data, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glBufferSubData2(JNIEnv* e, jobject c, jint target, jint offset, jint size, jbyteArray data, jint dataoffset) {
+	jbyte *dataNative = (*e)->GetByteArrayElements(e, data, NULL);
+	
+    glBufferSubData(
+        (GLenum)target,
+        (GLintptr)offset,
+        (GLsizeiptr)size,
+        (GLvoid *)(dataNative + dataoffset)
+    );
+	
+	(*e)->ReleaseByteArrayElements(e, data, dataNative, 0);
+}
+
+JNIEXPORT jint JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glCheckFramebufferStatus(JNIEnv* e, jobject c, jint target) {
+    GLenum _returnValue;
+    _returnValue = glCheckFramebufferStatus(
+        (GLenum)target
+    );
+    return (jint)_returnValue;
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glClear(JNIEnv* e, jobject c, jint mask) {
+    glClear(
+        (GLbitfield)mask
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glClearColor(JNIEnv* e, jobject c, jfloat red, jfloat green, jfloat blue, jfloat alpha) {
+    glClearColor(
+        (GLclampf)red,
+        (GLclampf)green,
+        (GLclampf)blue,
+        (GLclampf)alpha
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glColorMask(JNIEnv* e, jobject c, jboolean red, jboolean green, jboolean blue, jboolean alpha) {
+    glColorMask(
+        (GLboolean)red,
+        (GLboolean)green,
+        (GLboolean)blue,
+        (GLboolean)alpha
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glCompileShader(JNIEnv* e, jobject c, jint shader) {
+    glCompileShader(
+        (GLuint)shader
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glCompressedTexImage2D(JNIEnv* e, jobject c, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint imageSize, jobject pixels_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    if (pixels_buf) {
+        pixels = (GLvoid *)getPointer(e, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    }
+    if (pixels_buf && pixels == NULL) {
+        char * _pixelsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+    glCompressedTexImage2D(
+        (GLenum)target,
+        (GLint)level,
+        (GLenum)internalformat,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLint)border,
+        (GLsizei)imageSize,
+        (GLvoid *)pixels
+    );
+    if (_array) {
+        releasePointer(e, _array, pixels, JNI_FALSE);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glCompressedTexSubImage2D(JNIEnv* e, jobject c, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint imageSize, jobject pixels_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    if (pixels_buf) {
+        pixels = (GLvoid *)getPointer(e, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    }
+    if (pixels_buf && pixels == NULL) {
+        char * _pixelsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+    glCompressedTexSubImage2D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)xoffset,
+        (GLint)yoffset,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLenum)format,
+        (GLsizei)imageSize,
+        (GLvoid *)pixels
+    );
+    if (_array) {
+        releasePointer(e, _array, pixels, JNI_FALSE);
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glCreateProgram(JNIEnv* e, jobject c) {
+    GLuint _returnValue;
+    _returnValue = glCreateProgram();
+    return (jint)_returnValue;
+}
+
+JNIEXPORT jint JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glCreateShader(JNIEnv* e, jobject c, jint shaderType) {
+    GLuint _returnValue;
+    _returnValue = glCreateShader(
+        (GLenum)shaderType
+    );
+    return (jint)_returnValue;
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glCullFace(JNIEnv* e, jobject c, jint mode) {
+    glCullFace(
+        (GLenum)mode
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDeleteBuffers(JNIEnv* e, jobject c, jint n, jintArray buffers, jint offset) {
+	jint *buffersNative = (*e)->GetIntArrayElements(e, buffers, NULL);
+	
+    glDeleteBuffers(
+        (GLsizei)n,
+        (GLuint *)buffersNative
+    );
+	
+	(*e)->ReleaseIntArrayElements(e, buffers, buffersNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDeleteFramebuffers(JNIEnv* e, jobject c, jint n, jintArray framebuffers, jint offset) {
+	jint *buffersNative = (*e)->GetIntArrayElements(e, framebuffers, NULL);
+	
+    glDeleteFramebuffers(
+        (GLsizei)n,
+        (GLuint *)buffersNative
+    );
+	
+	(*e)->ReleaseIntArrayElements(e, framebuffers, buffersNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDeleteProgram(JNIEnv* e, jobject c, jint program) {
+    glDeleteProgram(
+        (GLuint)program
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDeleteRenderbuffers(JNIEnv* e, jobject c, jint n, jintArray renderbuffers, jint offset) {
+	jint *buffersNative = (*e)->GetIntArrayElements(e, renderbuffers, NULL);
+	
+    glDeleteRenderbuffers(
+        (GLsizei)n,
+        (GLuint *)buffersNative
+    );
+	
+	(*e)->ReleaseIntArrayElements(e, renderbuffers, buffersNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDeleteShader(JNIEnv* e, jobject c, jint shader) {
+    glDeleteShader(
+        (GLuint)shader
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDeleteTextures(JNIEnv* e, jobject c, jint n, jintArray textures_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *textures_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *textures = (GLuint *) 0;
+
+    if (!textures_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "textures == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = (*e)->GetArrayLength(e, textures_ref) - offset;
+    if (_remaining < n) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < n < needed";
+        goto exit;
+    }
+    textures_base = (GLuint *)
+        (*e)->GetPrimitiveArrayCritical(e, textures_ref, (jboolean *)0);
+    textures = textures_base + offset;
+
+    glDeleteTextures(
+        (GLsizei)n,
+        (GLuint *)textures
+    );
+
+exit:
+    if (textures_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, textures_ref, textures_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDepthFunc(JNIEnv* e, jobject c, jint func) {
+    glDepthFunc(
+        (GLenum)func
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDepthMask(JNIEnv* e, jobject c, jboolean flag) {
+    glDepthMask(
+        (GLboolean)flag
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDepthRangef(JNIEnv* e, jobject c, jfloat zNear, jfloat zFar) {
+    glDepthRangef(
+        (GLclampf)zNear,
+        (GLclampf)zFar
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDetachShader(JNIEnv* e, jobject c, jint program, jint shader) {
+    glDetachShader(
+        (GLuint)program,
+        (GLuint)shader
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDisable(JNIEnv* e, jobject c, jint cap) {
+    glDisable(
+        (GLenum)cap
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDisableVertexAttribArray(JNIEnv* e, jobject c, jint index) {
+    glDisableVertexAttribArray(
+        (GLuint)index
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDrawArrays(JNIEnv* e, jobject c, jint mode, jint first, jint count) {
+    glDrawArrays(
+        (GLenum)mode,
+        (GLint)first,
+        (GLsizei)count
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDrawElements(JNIEnv* e, jobject c, jint mode, jint count, jint type, jobject indices_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *indices = (GLvoid *) 0;
+
+    indices = (GLvoid *)getPointer(e, indices_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count) {
+        _exception = 1;
+        _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+        _exceptionMessage = "remaining() < count < needed";
+        goto exit;
+    }
+    if (indices == NULL) {
+        char * _indicesBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        indices = (GLvoid *) (_indicesBase + _bufferOffset);
+    }
+    glDrawElements(
+        (GLenum)mode,
+        (GLsizei)count,
+        (GLenum)type,
+        (GLvoid *)indices
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, indices, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDrawElements2(JNIEnv* e, jobject c, jint mode, jint count, jint type, jbyteArray indices, jint offset) {
+	jbyte *indicesNative = (*e)->GetByteArrayElements(e, indices, NULL);
+	
+    glDrawElements(
+        (GLenum)mode,
+        (GLsizei)count,
+        (GLenum)type,
+        (GLvoid *)(indicesNative + offset)
+    );
+	
+	(*e)->ReleaseByteArrayElements(e, indices, indicesNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glDrawElementsIndex(JNIEnv* e, jobject c, jint mode, jint count, jint type, jint offset) {
+    glDrawElements(
+        (GLenum)mode,
+        (GLsizei)count,
+        (GLenum)type,
+        (GLvoid *)offset
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glEnable(JNIEnv* e, jobject c, jint cap) {
+    glEnable(
+        (GLenum)cap
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glEnableVertexAttribArray(JNIEnv* e, jobject c, jint index) {
+    glEnableVertexAttribArray(
+        (GLuint)index
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glFramebufferRenderbuffer(JNIEnv* e, jobject c, jint target, jint attachment, jint renderbuffertarget, jint renderbuffer) {
+    glFramebufferRenderbuffer(
+        (GLenum)target,
+        (GLenum)attachment,
+        (GLenum)renderbuffertarget,
+        (GLuint)renderbuffer
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glFramebufferTexture2D(JNIEnv* e, jobject c, jint target, jint attachment, jint textarget, jint texture, jint level) {
+    glFramebufferTexture2D(
+        (GLenum)target,
+        (GLenum)attachment,
+        (GLenum)textarget,
+        (GLuint)texture,
+        (GLint)level
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGenBuffers(JNIEnv* e, jobject c, jint n, jintArray buffers_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *buffers_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *buffers = (GLuint *) 0;
+
+    if (!buffers_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = (*e)->GetArrayLength(e, buffers_ref) - offset;
+    if (_remaining < n) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < n < needed";
+        goto exit;
+    }
+    buffers_base = (GLuint *)
+        (*e)->GetPrimitiveArrayCritical(e, buffers_ref, (jboolean *)0);
+    buffers = buffers_base + offset;
+
+    glGenBuffers(
+        (GLsizei)n,
+        (GLuint *)buffers
+    );
+
+exit:
+    if (buffers_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, buffers_ref, buffers_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGenFramebuffers(JNIEnv* e, jobject c, jint n, jintArray framebuffers_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *buffers_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *buffers = (GLuint *) 0;
+
+    if (!framebuffers_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = (*e)->GetArrayLength(e, framebuffers_ref) - offset;
+    if (_remaining < n) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < n < needed";
+        goto exit;
+    }
+    buffers_base = (GLuint *)
+        (*e)->GetPrimitiveArrayCritical(e, framebuffers_ref, (jboolean *)0);
+    buffers = buffers_base + offset;
+
+    glGenFramebuffers(
+        (GLsizei)n,
+        (GLuint *)buffers
+    );
+
+exit:
+    if (buffers_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, framebuffers_ref, buffers_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGenRenderbuffers(JNIEnv* e, jobject c, jint n, jintArray renderbuffers_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *buffers_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *buffers = (GLuint *) 0;
+
+    if (!renderbuffers_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = (*e)->GetArrayLength(e, renderbuffers_ref) - offset;
+    if (_remaining < n) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < n < needed";
+        goto exit;
+    }
+    buffers_base = (GLuint *)
+        (*e)->GetPrimitiveArrayCritical(e, renderbuffers_ref, (jboolean *)0);
+    buffers = buffers_base + offset;
+
+    glGenRenderbuffers(
+        (GLsizei)n,
+        (GLuint *)buffers
+    );
+
+exit:
+    if (buffers_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, renderbuffers_ref, buffers_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGenTextures(JNIEnv* e, jobject c, jint n, jintArray textures_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *buffers_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *buffers = (GLuint *) 0;
+
+    if (!textures_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buffers == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = (*e)->GetArrayLength(e, textures_ref) - offset;
+    if (_remaining < n) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < n < needed";
+        goto exit;
+    }
+    buffers_base = (GLuint *)
+        (*e)->GetPrimitiveArrayCritical(e, textures_ref, (jboolean *)0);
+    buffers = buffers_base + offset;
+
+    glGenTextures(
+        (GLsizei)n,
+        (GLuint *)buffers
+    );
+
+exit:
+    if (buffers_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, textures_ref, buffers_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGenerateMipmap(JNIEnv* e, jobject c, jint target) {
+    glGenerateMipmap(
+        (GLenum)target
+    );
+}
+
+JNIEXPORT jint JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetAttribLocation(JNIEnv* e, jobject c, jint program, jstring name) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint _returnValue = 0;
+    const char* _nativename = 0;
+
+    if (!name) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "name == null";
+        goto exit;
+    }
+    _nativename = (*e)->GetStringUTFChars(e, name, 0);
+
+    _returnValue = glGetAttribLocation(
+        (GLuint)program,
+        (char *)_nativename
+    );
+
+exit:
+    if (_nativename) {
+        (*e)->ReleaseStringUTFChars(e, name, _nativename);
+    }
+
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+    return (jint)_returnValue;
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetBoolean(JNIEnv* e, jobject c, jint pname, jobject params_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *params = (GLvoid *) 0;
+
+    if (params_buf) {
+        params = (GLvoid *)getPointer(e, params_buf, &_array, &_remaining, &_bufferOffset);
+    }
+    if (params_buf && params == NULL) {
+        char * _paramsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        params = (GLvoid *) (_paramsBase + _bufferOffset);
+    }
+      
+    glGetBooleanv(
+        (GLenum) pname,
+        (GLboolean *) params
+    );
+}
+
+
+JNIEXPORT jint JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetError(JNIEnv* e, jobject c) {
+    GLenum _returnValue;
+    _returnValue = glGetError();
+    return (jint)_returnValue;
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetFramebufferAttachmentParameteriv(JNIEnv* e, jobject c, jint target, jint attachment, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = (*e)->GetArrayLength(e, params_ref) - offset;
+    params_base = (GLint *)
+        (*e)->GetPrimitiveArrayCritical(e, params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetFramebufferAttachmentParameteriv(
+        (GLenum)target,
+        (GLenum)attachment,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetIntegerv(JNIEnv* e, jobject c, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType;
+    const char * _exceptionMessage;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+    int _needed = 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = (*e)->GetArrayLength(e, params_ref) - offset;
+    _needed = getNeededCount(pname);
+    // if we didn't find this pname, we just assume the user passed
+    // an array of the right size -- this might happen with extensions
+    // or if we forget an enum here.
+    if (_remaining < _needed) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < needed";
+        goto exit;
+    }
+    params_base = (GLint *)
+        (*e)->GetPrimitiveArrayCritical(e, params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetIntegerv(
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT jstring JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetProgramInfoLog(JNIEnv* e, jobject c, jint program) {
+	GLsizei size = 0;
+	glGetProgramiv((GLuint)program, GL_INFO_LOG_LENGTH, &size);
+	
+	GLchar *infoLog;
+
+	if (!size) {
+		return  (*e)->NewStringUTF(e, "");
+	}
+	
+	infoLog = malloc(sizeof(GLchar) * size);
+    if (infoLog == NULL) {
+        jniThrowException(e, "java/lang/IllegalArgumentException", "out of memory");
+        return NULL;
+    }
+	
+	glGetProgramInfoLog((GLuint)program, size, NULL, infoLog);
+	jstring log = (*e)->NewStringUTF(e, infoLog);
+	free(infoLog);
+
+	return log; 
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetProgramiv(JNIEnv* e, jobject c, jint program, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = (*e)->GetArrayLength(e, params_ref) - offset;
+    if (_remaining < 1) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < 1 < needed";
+        goto exit;
+    }
+    params_base = (GLint *)
+        (*e)->GetPrimitiveArrayCritical(e, params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetProgramiv(
+        (GLuint)program,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT jstring JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetShaderInfoLog(JNIEnv* e, jobject c, jint shader) {
+	GLsizei size = 0;
+	glGetShaderiv((GLuint)shader, GL_INFO_LOG_LENGTH, &size);
+	
+	GLchar *infoLog;
+
+	if (!size) {
+		return  (*e)->NewStringUTF(e, "");
+	}
+	
+	infoLog = malloc(sizeof(GLchar) * size);
+    if (infoLog == NULL) {
+        jniThrowException(e, "java/lang/IllegalArgumentException", "out of memory");
+        return NULL;
+    }
+	
+	glGetShaderInfoLog((GLuint)shader, size, NULL, infoLog);
+	jstring log = (*e)->NewStringUTF(e, infoLog);
+	free(infoLog);
+
+	return log; 
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetShaderiv(JNIEnv* e, jobject c, jint shader, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = (*e)->GetArrayLength(e, params_ref) - offset;
+    if (_remaining < 1) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < 1 < needed";
+        goto exit;
+    }
+    params_base = (GLint *)
+        (*e)->GetPrimitiveArrayCritical(e, params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetShaderiv(
+        (GLuint)shader,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT jstring JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetString(JNIEnv* e, jobject c, jint name) {
+	const GLubyte* value = glGetString((GLenum) name);
+
+	return (*e)->NewStringUTF(e, (const char*)value); 
+}
+
+JNIEXPORT jint JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetUniformLocation(JNIEnv* e, jobject c, jint program, jstring name) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint _returnValue = 0;
+    const char* _nativename = 0;
+
+    if (!name) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "name == null";
+        goto exit;
+    }
+    _nativename = (*e)->GetStringUTFChars(e, name, 0);
+
+    _returnValue = glGetUniformLocation(
+        (GLuint)program,
+        (char *)_nativename
+    );
+
+exit:
+    if (_nativename) {
+        (*e)->ReleaseStringUTFChars(e, name, _nativename);
+    }
+
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+    return (jint)_returnValue;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glIsEnabled(JNIEnv* e, jobject c, jint cap) {
+    GLboolean _returnValue;
+    _returnValue = glIsEnabled(
+        (GLenum)cap
+    );
+    return (jboolean)_returnValue;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glIsFramebuffer(JNIEnv* e, jobject c, jint framebuffer) {
+    GLboolean _returnValue;
+    _returnValue = glIsFramebuffer(
+        (GLuint)framebuffer
+    );
+    return (jboolean)_returnValue;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glIsRenderbuffer(JNIEnv* e, jobject c, jint renderbuffer) {
+    GLboolean _returnValue;
+    _returnValue = glIsRenderbuffer(
+        (GLuint)renderbuffer
+    );
+    return (jboolean)_returnValue;
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glLineWidth(JNIEnv* e, jobject c, jfloat width) {
+    glLineWidth(
+        (GLfloat)width
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glLinkProgram(JNIEnv* e, jobject c, jint program) {
+    glLinkProgram(
+        (GLuint)program
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glPixelStorei(JNIEnv* e, jobject c, jint pname, jint param) {
+    glPixelStorei(
+        (GLenum)pname,
+        (GLint)param
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glPolygonOffset(JNIEnv* e, jobject c, jfloat factor, jfloat units) {
+    glPolygonOffset(
+        (GLfloat)factor,
+        (GLfloat)units
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glReadPixels(JNIEnv* e, jobject c, jint vpX, jint vpY, jint vpW, jint vpH, jint format, jint type, jobject pixels_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    pixels = (GLvoid *)getPointer(e, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    if (pixels == NULL) {
+        char * _pixelsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+    glReadPixels(
+        (GLint)vpX,
+        (GLint)vpY,
+        (GLsizei)vpW,
+        (GLsizei)vpH,
+        (GLenum)format,
+        (GLenum)type,
+        (GLvoid *)pixels
+    );
+    if (_array) {
+        releasePointer(e, _array, pixels, JNI_TRUE);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glReadPixels2(JNIEnv* e, jobject c, jint vpX, jint vpY, jint vpW, jint vpH, jint format, jint type, jintArray pixels, jint offset, jint size) {
+	GLint* bufferNative = malloc(size);
+	
+    glReadPixels(
+        (GLint)vpX,
+        (GLint)vpY,
+        (GLsizei)vpW,
+        (GLsizei)vpH,
+        (GLenum)format,
+        (GLenum)type,
+        (GLvoid *)bufferNative
+    );
+	
+	(*e)->SetIntArrayRegion(e, pixels, offset, size, bufferNative);
+	
+	free(bufferNative);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glRenderbufferStorage(JNIEnv* e, jobject c, jint target, jint internalformat, jint width, jint height) {
+    glRenderbufferStorage(
+        (GLenum)target,
+        (GLenum)internalformat,
+        (GLsizei)width,
+        (GLsizei)height
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glScissor(JNIEnv* e, jobject c, jint x, jint y, jint width, jint height) {
+    glScissor(
+        (GLint)x,
+        (GLint)y,
+        (GLsizei)width,
+        (GLsizei)height
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glShaderSource(JNIEnv* e, jobject c, jint shader, jstring string) {
+	const char *stringNative = (*e)->GetStringUTFChars(e, string, NULL);
+	glShaderSource(shader, 1, &stringNative, NULL);
+	//jsize stringLen = (*e)->GetStringUTFLength(e, string);
+	//const char** code = { stringNative };
+	//const GLint* length = { stringLen };
+	
+	printf("upload shader source: %s", stringNative);
+
+	//glShaderSource(shader, 1, code, length);
+	
+	(*e)->ReleaseStringUTFChars(e, string, stringNative);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glStencilFuncSeparate(JNIEnv* e, jobject c, jint face, jint func, jint ref, jint mask) {
+    glStencilFuncSeparate(
+        (GLenum) face,
+        (GLenum) func,
+        (GLint) ref,
+        (GLuint) mask
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glStencilOpSeparate(JNIEnv* e, jobject c, jint face, jint sfail, jint dpfail, jint dppass) {
+    glStencilOpSeparate(
+        (GLenum) face,
+        (GLenum) sfail,
+        (GLenum) dpfail,
+        (GLenum) dppass
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glTexImage2D(JNIEnv* e, jobject c, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint format, jint type, jobject pixels_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    if (pixels_buf) {
+        pixels = (GLvoid *)getPointer(e, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    }
+    if (pixels_buf && pixels == NULL) {
+        char * _pixelsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+    glTexImage2D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)internalformat,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLint)border,
+        (GLenum)format,
+        (GLenum)type,
+        (GLvoid *)pixels
+    );
+    if (_array) {
+        releasePointer(e, _array, pixels, JNI_FALSE);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glTexParameteri(JNIEnv* e, jobject c, jint target, jint pname, jint param) {
+    glTexParameteri(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint)param
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glTexParameterf(JNIEnv* e, jobject c, jint target, jint pname, jfloat param) {
+    glTexParameterf(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLfloat)param
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glTexSubImage2D(JNIEnv* e, jobject c, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint type, jobject pixels_buf) {
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    if (pixels_buf) {
+        pixels = (GLvoid *)getPointer(e, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    }
+    if (pixels_buf && pixels == NULL) {
+        char * _pixelsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+    glTexSubImage2D(
+        (GLenum)target,
+        (GLint)level,
+        (GLint)xoffset,
+        (GLint)yoffset,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLenum)format,
+        (GLenum)type,
+        (GLvoid *)pixels
+    );
+    if (_array) {
+        releasePointer(e, _array, pixels, JNI_FALSE);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform1f(JNIEnv* e, jobject c, jint location, jfloat x) {
+    glUniform1f(
+        (GLint)location,
+        (GLfloat)x
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform1fv(JNIEnv* e, jobject c, jint location, jint count, jobject v_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *v = (GLfloat *) 0;
+
+    v = (GLfloat *)getPointer(e, v_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count < needed";
+        goto exit;
+    }
+    if (v == NULL) {
+        char * _vBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        v = (GLfloat *) (_vBase + _bufferOffset);
+    }
+    glUniform1fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLfloat *)v
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, v, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform1fv2(JNIEnv* e, jobject c, jint location, jint count, jfloatArray v, jint offset) {
+	jfloat *vNative = (*e)->GetFloatArrayElements(e, v, NULL);
+	
+    glUniform1fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLfloat *)(vNative + offset * sizeof(GLfloat))
+    );
+	
+	(*e)->ReleaseFloatArrayElements(e, v, vNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform1i(JNIEnv* e, jobject c, jint location, jint x) {
+    glUniform1i(
+        (GLint)location,
+        (GLint)x
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform1iv(JNIEnv* e, jobject c, jint location, jint count, jobject v_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *v = (GLint *) 0;
+
+    v = (GLint *)getPointer(e, v_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count < needed";
+        goto exit;
+    }
+    if (v == NULL) {
+        char * _vBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        v = (GLint *) (_vBase + _bufferOffset);
+    }
+    glUniform1iv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLint *)v
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, v, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform1iv2(JNIEnv* e, jobject c, jint location, jint count, jintArray v, jint offset) {
+	jint *vNative = (*e)->GetIntArrayElements(e, v, NULL);
+	
+    glUniform1iv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLint *)(vNative + offset * sizeof(GLint))
+    );
+	glUniform1iv(location, count, vNative + offset);
+	
+	(*e)->ReleaseIntArrayElements(e, v, vNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform2f(JNIEnv* e, jobject c, jint location, jfloat x, jfloat y) {
+    glUniform2f(
+        (GLint)location,
+        (GLfloat)x,
+        (GLfloat)y
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform2fv(JNIEnv* e, jobject c, jint location, jint count, jobject v_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *v = (GLfloat *) 0;
+
+    v = (GLfloat *)getPointer(e, v_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count*2) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count*2 < needed";
+        goto exit;
+    }
+    if (v == NULL) {
+        char * _vBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        v = (GLfloat *) (_vBase + _bufferOffset);
+    }
+    glUniform2fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLfloat *)v
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, v, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform2fv2(JNIEnv* e, jobject c, jint location, jint count, jfloatArray v, jint offset) {
+	jfloat *vNative = (*e)->GetFloatArrayElements(e, v, NULL);
+	
+    glUniform2fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLfloat *)(vNative + offset * sizeof(GLfloat))
+    );
+	
+	(*e)->ReleaseFloatArrayElements(e, v, vNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform3f(JNIEnv* e, jobject c, jint location, jfloat x, jfloat y, jfloat z) {
+    glUniform3f(
+        (GLint)location,
+        (GLfloat)x,
+        (GLfloat)y,
+        (GLfloat)z
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform3fv(JNIEnv* e, jobject c, jint location, jint count, jobject v_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *v = (GLfloat *) 0;
+
+    v = (GLfloat *)getPointer(e, v_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count * 3) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count*3 < needed";
+        goto exit;
+    }
+    if (v == NULL) {
+        char * _vBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        v = (GLfloat *) (_vBase + _bufferOffset);
+    }
+    glUniform3fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLfloat *)v
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, v, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform3fv2(JNIEnv* e, jobject c, jint location, jint count, jfloatArray v, jint offset) {
+	jfloat *vNative = (*e)->GetFloatArrayElements(e, v, NULL);
+	
+    glUniform3fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLfloat *)(vNative + offset * sizeof(GLfloat))
+    );
+	
+	(*e)->ReleaseFloatArrayElements(e, v, vNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform4f(JNIEnv* e, jobject c, jint location, jfloat x, jfloat y, jfloat z, jfloat w) {
+    glUniform4f(
+        (GLint)location,
+        (GLfloat)x,
+        (GLfloat)y,
+        (GLfloat)z,
+        (GLfloat)w
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform4fv(JNIEnv* e, jobject c, jint location, jint count, jobject v_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *v = (GLfloat *) 0;
+
+    v = (GLfloat *)getPointer(e, v_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count * 4) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count*4 < needed";
+        goto exit;
+    }
+    if (v == NULL) {
+        char * _vBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        v = (GLfloat *) (_vBase + _bufferOffset);
+    }
+    glUniform4fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLfloat *)v
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, v, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniform4fv2(JNIEnv* e, jobject c, jint location, jint count, jfloatArray v, jint offset) {
+	jfloat *vNative = (*e)->GetFloatArrayElements(e, v, NULL);
+	
+    glUniform4fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLfloat *)(vNative + offset * sizeof(GLfloat))
+    );
+	
+	(*e)->ReleaseFloatArrayElements(e, v, vNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniformMatrix3fv(JNIEnv* e, jobject c, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    value = (GLfloat *)getPointer(e, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count*9) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count*9 < needed";
+        goto exit;
+    }
+    if (value == NULL) {
+        char * _valueBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        value = (GLfloat *) (_valueBase + _bufferOffset);
+    }
+    glUniformMatrix3fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, value, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniformMatrix3fv2(JNIEnv* e, jobject c, jint location, jint count, jboolean transpose, jfloatArray value, jint offset) {
+	jfloat *vNative = (*e)->GetFloatArrayElements(e, value, NULL);
+	
+    glUniformMatrix3fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)(vNative + offset * sizeof(GLfloat))
+    );
+	
+	(*e)->ReleaseFloatArrayElements(e, value, vNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniformMatrix4fv(JNIEnv* e, jobject c, jint location, jint count, jboolean transpose, jobject value_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *value = (GLfloat *) 0;
+
+    value = (GLfloat *)getPointer(e, value_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count * 16) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count*16 < needed";
+        goto exit;
+    }
+    if (value == NULL) {
+        char * _valueBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        value = (GLfloat *) (_valueBase + _bufferOffset);
+    }
+    glUniformMatrix4fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)value
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, value, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUniformMatrix4fv2(JNIEnv* e, jobject c, jint location, jint count, jboolean transpose, jfloatArray value, jint offset) {
+	jfloat *vNative = (*e)->GetFloatArrayElements(e, value, NULL);
+	
+    glUniformMatrix4fv(
+        (GLint)location,
+        (GLsizei)count,
+        (GLboolean)transpose,
+        (GLfloat *)(vNative + offset * sizeof(GLfloat))
+    );
+	
+	(*e)->ReleaseFloatArrayElements(e, value, vNative, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glUseProgram(JNIEnv* e, jobject c, jint program) {
+    glUseProgram(
+        (GLuint)program
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glVertexAttribPointer(JNIEnv* e, jobject c, jint indx, jint size, jint type, jboolean normalized, jint stride, jobject buffer) {
+    GLvoid *ptr = (GLvoid *) 0;
+
+    if (buffer) {
+        ptr = (GLvoid *) getDirectBufferPointer(e, buffer);
+        if (!ptr) {
+            return;
+        }
+    }
+    glVertexAttribPointer(
+        (GLuint)indx,
+        (GLint)size,
+        (GLenum)type,
+        (GLboolean)normalized,
+        (GLsizei)stride,
+        (GLvoid *)ptr
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glVertexAttribPointer2(JNIEnv* e, jclass c, jint indx, jint size, jint type, jboolean normalized, jint stride, jint offset) {
+	
+    glVertexAttribPointer(
+        (GLuint)indx,
+        (GLint)size,
+        (GLenum)type,
+        (GLboolean)normalized,
+        (GLsizei)stride,
+        (GLvoid *)(offset)
+    );
+}
+
+JNIEXPORT void JNICALL
+Java_com_jme3_renderer_ios_JmeIosGLES_glViewport(JNIEnv* e, jobject c, jint x, jint y, jint width, jint height) {
+    glViewport(
+        (GLint)x,
+        (GLint)y,
+        (GLsizei)width,
+        (GLsizei)height
+    );
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glBeginQuery(JNIEnv* e, jobject c, jint target, jint query) {
+    glBeginQuery(
+        (GLint) target,
+        (GLint) query
+    );
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glEndQuery(JNIEnv* e, jobject c, jint target)
+{
+    glEndQuery((GLint)target);
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glGenQueries(JNIEnv* e, jobject c, jint count, jobject v_buf)
+{
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *v = (GLint *) 0;
+
+    v = (GLint *)getPointer(e, v_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count < needed";
+        goto exit;
+    }
+    if (v == NULL) {
+        char * _vBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        v = (GLint *) (_vBase + _bufferOffset);
+    }
+    glGenQueries(
+        (GLsizei)count,
+        (GLint *)v
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, v, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetQueryObjectuiv(JNIEnv* e, jobject c, jint query, jint pname, jintArray params_ref)
+{
+    jint _exception = 0;
+    const char * _exceptionType;
+    const char * _exceptionMessage;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+    int _needed = 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+
+    _remaining = (*e)->GetArrayLength(e, params_ref);
+    _needed = getNeededCount(pname);
+    // if we didn't find this pname, we just assume the user passed
+    // an array of the right size -- this might happen with extensions
+    // or if we forget an enum here.
+    if (_remaining < _needed) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length < needed";
+        goto exit;
+    }
+    params_base = (GLint *)
+        (*e)->GetPrimitiveArrayCritical(e, params_ref, (jboolean *)0);
+    params = params_base;
+
+    glGetQueryObjectuiv(
+        (GLint)query,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glGetQueryiv(JNIEnv* e, jobject c, jint target, jint pname, jintArray params_ref)
+{
+    jint _exception = 0;
+    const char * _exceptionType;
+    const char * _exceptionMessage;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+    int _needed = 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+
+    _remaining = (*e)->GetArrayLength(e, params_ref);
+    _needed = getNeededCount(pname);
+    // if we didn't find this pname, we just assume the user passed
+    // an array of the right size -- this might happen with extensions
+    // or if we forget an enum here.
+    if (_remaining < _needed) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length < needed";
+        goto exit;
+    }
+    params_base = (GLint *)
+        (*e)->GetPrimitiveArrayCritical(e, params_ref, (jboolean *)0);
+    params = params_base;
+
+    glGetQueryiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        (*e)->ReleasePrimitiveArrayCritical(e, params_ref, params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glBlitFramebuffer(JNIEnv* e, jobject c, jint srcX0, jint srcY0, jint srcX1, jint srcY1, jint dstX0, jint dstY0, jint dstX1, jint dstY1, jint mask, jint filter)
+{
+    glBlitFramebuffer( 	
+        (GLint) srcX0,
+        (GLint) srcY0,
+        (GLint) srcX1,
+        (GLint) srcY1,
+        (GLint) dstX0,
+        (GLint) dstY0,
+        (GLint) dstX1,
+        (GLint) dstY1,
+        (GLbitfield) mask,
+        (GLenum) filter
+    );
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glDrawArraysInstanced(JNIEnv* e, jobject c, jint mode, jint first, jint count, jint primcount)
+{
+    glDrawArraysInstanced(
+        (GLenum) mode,
+        (GLint) first,
+        (GLsizei) count,
+        (GLsizei) primcount
+    );
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glDrawBuffers(JNIEnv* e, jobject c, jint count, jobject v_buf)
+{
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *v = (GLint *) 0;
+
+    v = (GLint *)getPointer(e, v_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count < needed";
+        goto exit;
+    }
+    if (v == NULL) {
+        char * _vBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        v = (GLint *) (_vBase + _bufferOffset);
+    }
+    glDrawBuffers(
+        (GLsizei)count,
+        (GLint *)v
+    );
+
+exit:
+    if (_array) {
+        releasePointer(e, _array, v, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(e, _exceptionType, _exceptionMessage);
+    }
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glDrawElementsInstanced(JNIEnv* e, jobject c, jint mode, jint count, jint type, jlong indices, jint primcount)
+{
+    glDrawElementsInstanced(
+        (GLenum) mode,
+        (GLsizei) count,
+        (GLenum) type,
+        (const void *) indices,
+        (GLsizei) primcount
+    );
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glVertexAttribDivisor(JNIEnv* e, jobject c, jint index, jint divisor)
+{
+    glVertexAttribDivisor(
+        (GLint) index,
+        (GLint) divisor
+    );
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glFramebufferTextureLayer(JNIEnv* e, jobject c, jint target, jint attachment, jint texture, jint level, jint layer)
+{
+    glFramebufferTextureLayer(
+        (GLenum) target,
+        (GLenum) attachment,
+        (GLuint) texture,
+        (GLint) level,
+        (GLint) layer
+    );
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glReadBuffer(JNIEnv* e, jobject c, jint src)
+{
+    glReadBuffer((GLenum) src);
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glCompressedTexImage3D(JNIEnv* e, jobject c, jint target, jint level, jint internalFormat, jint width, jint height, jint depth, jint border, jint imageSize, jobject pixels_buf)
+{
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    if (pixels_buf) {
+        pixels = (GLvoid *)getPointer(e, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    }
+    if (pixels_buf && pixels == NULL) {
+        char * _pixelsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+        
+    glCompressedTexImage3D(
+        (GLenum) target,
+        (GLint) level,
+        (GLenum) internalFormat,
+        (GLsizei) width,
+        (GLsizei) height,
+        (GLsizei) depth,
+        (GLint) border,
+        (GLsizei) imageSize,
+        (GLvoid *)pixels
+    );
+
+    if (_array) {
+        releasePointer(e, _array, pixels, JNI_FALSE);
+    }
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glCompressedTexSubImage3D(JNIEnv* e, jobject c, jint target, jint level, jint xoffset, jint yoffset, jint zoffset, jint width, jint height, jint depth, jint format, jint imageSize, jobject pixels_buf)
+{
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    if (pixels_buf) {
+        pixels = (GLvoid *)getPointer(e, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    }
+    if (pixels_buf && pixels == NULL) {
+        char * _pixelsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+        
+    glCompressedTexSubImage3D(
+        (GLenum) target,
+        (GLint) level,
+        (GLint) xoffset,
+        (GLint) yoffset,
+        (GLint) zoffset,
+        (GLsizei) width,
+        (GLsizei) height,
+        (GLsizei) depth,
+        (GLenum) format,
+        (GLsizei) imageSize,
+        (GLvoid *)pixels
+    );
+
+    if (_array) {
+        releasePointer(e, _array, pixels, JNI_FALSE);
+    }
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glTexImage3D(JNIEnv* e, jobject c, jint target, jint level, jint internalFormat, jint width, jint height, jint depth, jint border, jint format, jint type, jobject pixels_buf)
+{
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    if (pixels_buf) {
+        pixels = (GLvoid *)getPointer(e, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    }
+    if (pixels_buf && pixels == NULL) {
+        char * _pixelsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+        
+    glTexImage3D(
+        (GLenum) target,
+        (GLint) level,
+        (GLint) internalFormat,
+        (GLsizei) width,
+        (GLsizei) height,
+        (GLsizei) depth,
+        (GLint) border,
+        (GLenum) format,
+        (GLenum) type,
+        (GLvoid *)pixels
+    );
+
+    if (_array) {
+        releasePointer(e, _array, pixels, JNI_FALSE);
+    }
+}
+
+JNIEXPORT void JNICALL 
+Java_com_jme3_renderer_ios_JmeIosGLES_glTexSubImage3D(JNIEnv* e, jobject c, jint target, jint level, jint xoffset, jint yoffset, jint zoffset, jint width, jint height, jint depth, jint format, jint type, jobject pixels_buf)
+{
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLvoid *pixels = (GLvoid *) 0;
+
+    if (pixels_buf) {
+        pixels = (GLvoid *)getPointer(e, pixels_buf, &_array, &_remaining, &_bufferOffset);
+    }
+    if (pixels_buf && pixels == NULL) {
+        char * _pixelsBase = (char *)(*e)->GetPrimitiveArrayCritical(e, _array, (jboolean *) 0);
+        pixels = (GLvoid *) (_pixelsBase + _bufferOffset);
+    }
+        
+    glTexSubImage3D(
+        (GLenum) target,
+        (GLint) level,
+        (GLint) xoffset,
+        (GLint) yoffset,
+        (GLint) zoffset,
+        (GLsizei) width,
+        (GLsizei) height,
+        (GLsizei) depth,
+        (GLenum) format,
+        (GLenum) type,
+        (GLvoid *)pixels
+    );
+
+    if (_array) {
+        releasePointer(e, _array, pixels, JNI_FALSE);
+    }
+}
+
+
+static int
+allowIndirectBuffers(JNIEnv *e) {
+    return 0;
+}
+
+static void *
+getDirectBufferPointer(JNIEnv *e, jobject buffer) {
+    if (!buffer) {
+        return NULL;
+    }
+    
+    if (!initialized) {
+    	nativeClassInit(e);
+    }
+
+    void* buf = (*e)->GetDirectBufferAddress(e, buffer);
+    if (buf) {
+        jint position = (*e)->GetIntField(e, buffer, positionID);
+        jint elementSizeShift = getBufferElementSize(e, buffer);
+        buf = ((char*) buf) + (position << elementSizeShift);
+    } else {
+            jniThrowException(e, "java/lang/IllegalArgumentException",
+                              "Must use a native order direct Buffer");
+    }
+    return buf;
+}
+
+static void *
+getPointer(JNIEnv *e, jobject buffer, jarray *array, jint *remaining, jint *offset) {
+    jint position;
+    jint limit;
+    jint elementSizeShift;
+    jlong pointer;
+    
+    if (!buffer) {
+        return NULL;
+    }
+    
+    if (!initialized) {
+    	nativeClassInit(e);
+    }
+
+    position = (*e)->GetIntField(e, buffer, positionID);
+    limit = (*e)->GetIntField(e, buffer, limitID);
+    elementSizeShift = getBufferElementSize(e, buffer);
+    
+    array = (void*) NULL;
+    *remaining = (limit - position) << elementSizeShift; 
+    *offset = position;
+    
+    return getDirectBufferPointer(e, buffer);
+}
+
+
+static void
+nativeClassInit(JNIEnv *e) {
+    if (!byteBufferClass) {
+    	jclass byteBufferClassLocal = (*e)->FindClass(e, "java/nio/ByteBuffer");
+    	byteBufferClass = (jclass) (*e)->NewGlobalRef(e, byteBufferClassLocal);
+    }
+    
+    if (!shortBufferClass) {
+    	jclass shortBufferClassLocal = (*e)->FindClass(e, "java/nio/ShortBuffer");
+    	shortBufferClass = (jclass) (*e)->NewGlobalRef(e, shortBufferClassLocal);
+    }
+    
+    if (!intBufferClass) {
+    	jclass intBufferClassLocal = (*e)->FindClass(e, "java/nio/IntBuffer");
+    	intBufferClass = (jclass) (*e)->NewGlobalRef(e, intBufferClassLocal);
+    }
+    
+    if (!floatBufferClass) {
+    	jclass floatBufferClassLocal = (*e)->FindClass(e, "java/nio/FloatBuffer");
+    	floatBufferClass = (jclass) (*e)->NewGlobalRef(e, floatBufferClassLocal);
+    }
+    
+    if (!bufferClass) {
+        jclass bufferClassLocal = (*e)->FindClass(e, "java/nio/Buffer");
+        bufferClass = (jclass) (*e)->NewGlobalRef(e, bufferClassLocal);
+    }
+
+    if (!positionID && bufferClass) {
+	    positionID = (*e)->GetFieldID(e, bufferClass, "position", "I");
+	}
+
+    if (!limitID && bufferClass) {
+	    limitID = (*e)->GetFieldID(e, bufferClass, "limit", "I");
+	}
+
+	initialized = floatBufferClass && bufferClass && shortBufferClass && byteBufferClass
+			&& intBufferClass && positionID && limitID;
+			
+	printf("Initializion of java.nio.Buffer access functionality %s\n", initialized ? "succeeded" : "failed");
+}
+
+static void
+releasePointer(JNIEnv *e, jarray array, void *data, jboolean commit) {
+    (*e)->ReleasePrimitiveArrayCritical(e, array, data,
+					   commit ? 0 : JNI_ABORT);
+}
+
+static void
+jniThrowException(JNIEnv *e, const char* type, const char* message) {
+	jclass excCls = (*e)->FindClass(e, type);
+	if (excCls != 0) {
+    	(*e)->ThrowNew(e, excCls, message);
+    }
+}
+
+static jint
+getBufferElementSize(JNIEnv *e, jobject buffer) {
+    if (!buffer) {
+        return 0;
+    }
+
+	if ((*e)->IsInstanceOf(e, buffer, floatBufferClass) == JNI_TRUE) {
+		return 2;
+	} else if ((*e)->IsInstanceOf(e, buffer, intBufferClass) == JNI_TRUE) {
+		return 2;
+	} else if ((*e)->IsInstanceOf(e, buffer, shortBufferClass) == JNI_TRUE) {
+		return 1;
+	}
+	
+	//TODO: check other buffer types
+	return 0;
+}
+
+static int getNeededCount(GLint pname) {
+    int needed = 1;
+#ifdef GL_ES_VERSION_2_0
+    // GLES 2.x pnames
+    switch (pname) {
+        case GL_ALIASED_LINE_WIDTH_RANGE:
+        case GL_ALIASED_POINT_SIZE_RANGE:
+            needed = 2;
+            break;
+
+        case GL_BLEND_COLOR:
+        case GL_COLOR_CLEAR_VALUE:
+        case GL_COLOR_WRITEMASK:
+        case GL_SCISSOR_BOX:
+        case GL_VIEWPORT:
+            needed = 4;
+            break;
+
+        case GL_COMPRESSED_TEXTURE_FORMATS:
+            glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
+            break;
+
+        case GL_SHADER_BINARY_FORMATS:
+            glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &needed);
+            break;
+    }
+#endif
+
+#ifdef GL_VERSION_ES_CM_1_1
+    // GLES 1.x pnames
+    switch (pname) {
+        case GL_ALIASED_LINE_WIDTH_RANGE:
+        case GL_ALIASED_POINT_SIZE_RANGE:
+        case GL_DEPTH_RANGE:
+        case GL_SMOOTH_LINE_WIDTH_RANGE:
+        case GL_SMOOTH_POINT_SIZE_RANGE:
+            needed = 2;
+            break;
+
+        case GL_CURRENT_NORMAL:
+        case GL_POINT_DISTANCE_ATTENUATION:
+            needed = 3;
+            break;
+
+        case GL_COLOR_CLEAR_VALUE:
+        case GL_COLOR_WRITEMASK:
+        case GL_CURRENT_COLOR:
+        case GL_CURRENT_TEXTURE_COORDS:
+        case GL_FOG_COLOR:
+        case GL_LIGHT_MODEL_AMBIENT:
+        case GL_SCISSOR_BOX:
+        case GL_VIEWPORT:
+            needed = 4;
+            break;
+
+        case GL_MODELVIEW_MATRIX:
+        case GL_PROJECTION_MATRIX:
+        case GL_TEXTURE_MATRIX:
+            needed = 16;
+            break;
+
+        case GL_COMPRESSED_TEXTURE_FORMATS:
+            glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
+            break;
+    }
+#endif
+    return needed;
+}

+ 138 - 0
jme3-ios-native/src/com_jme3_audio_ios_IosAL.c

@@ -0,0 +1,138 @@
+#include "com_jme3_audio_ios_IosAL.h"
+//#include "AL/al.h"
+//#include "AL/alext.h"
+
+#include "OpenAL/al.h"
+#include "OpenAL/alc.h"
+#include "OpenAL/oalMacOSX_OALExtensions.h"
+
+JNIEXPORT jstring JNICALL Java_com_jme3_audio_ios_IosAL_alGetString
+  (JNIEnv* env, jobject obj, jint param)
+{
+    return (*env)->NewStringUTF(env, alGetString(param));
+}
+
+JNIEXPORT jint JNICALL Java_com_jme3_audio_ios_IosAL_alGenSources
+  (JNIEnv *env, jobject obj)
+{
+    ALuint source;
+    alGenSources(1, &source);
+    return source;
+}
+
+JNIEXPORT jint JNICALL Java_com_jme3_audio_ios_IosAL_alGetError
+  (JNIEnv *env, jobject obj)
+{
+    return alGetError();
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alDeleteSources
+  (JNIEnv* env, jobject obj, jint numSources, jobject intbufSources)
+{
+    ALuint* pIntBufSources = (ALuint*) (*env)->GetDirectBufferAddress(env, intbufSources);
+    alDeleteSources((ALsizei)numSources, pIntBufSources);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alGenBuffers
+  (JNIEnv* env, jobject obj, jint numBuffers, jobject intbufBuffers)
+{
+    ALuint* pIntBufBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, intbufBuffers);
+    alGenBuffers((ALsizei)numBuffers, pIntBufBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alDeleteBuffers
+  (JNIEnv* env, jobject obj, jint numBuffers, jobject intbufBuffers)
+{
+    ALuint* pIntBufBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, intbufBuffers);
+    alDeleteBuffers((ALsizei)numBuffers, pIntBufBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourceStop
+  (JNIEnv *env, jobject obj, jint source)
+{
+    alSourceStop((ALuint)source);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourcei
+  (JNIEnv *env, jobject obj, jint source, jint param, jint value)
+{
+    alSourcei((ALuint)source, (ALenum)param, (ALint)value);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alBufferData
+  (JNIEnv* env, jobject obj, jint buffer, jint format, jobject bufferData, jint bufferSize, jint frequency)
+{
+    ALuint* pBufferData = (ALuint*) (*env)->GetDirectBufferAddress(env, bufferData);
+    alBufferData((ALuint)buffer, (ALenum)format, pBufferData, (ALsizei)bufferSize, (ALsizei)frequency);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourcePlay
+  (JNIEnv *env, jobject obj, jint source)
+{
+    alSourcePlay((ALuint)source);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourcePause
+  (JNIEnv *env, jobject obj, jint source)
+{
+    alSourcePause((ALuint)source);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourcef
+  (JNIEnv *env, jobject obj, jint source, jint param, jfloat value)
+{
+    alSourcef((ALuint)source, (ALenum)param, (ALfloat)value);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSource3f
+  (JNIEnv *env, jobject obj, jint source, jint param, jfloat value1, jfloat value2, jfloat value3)
+{
+    alSource3f((ALuint)source, (ALenum)param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
+}
+
+JNIEXPORT jint JNICALL Java_com_jme3_audio_ios_IosAL_alGetSourcei
+  (JNIEnv *env, jobject obj, jint source, jint param)
+{
+    ALint result;
+    alGetSourcei((ALuint)source, (ALenum)param, &result);
+    return (jint)result;
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourceUnqueueBuffers
+  (JNIEnv* env, jobject obj, jint source, jint numBuffers, jobject buffers)
+{
+    ALuint* pBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, buffers);
+    alSourceUnqueueBuffers((ALuint)source, (ALsizei)numBuffers, pBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourceQueueBuffers
+  (JNIEnv* env, jobject obj, jint source, jint numBuffers, jobject buffers)
+{
+    ALuint* pBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, buffers);
+    alSourceQueueBuffers((ALuint)source, (ALsizei)numBuffers, pBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alListener
+  (JNIEnv* env, jobject obj, jint param, jobject bufferData)
+{
+    ALfloat* pBufferData = (ALfloat*) (*env)->GetDirectBufferAddress(env, bufferData);
+    alListenerfv((ALenum)param, pBufferData);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alListenerf
+  (JNIEnv *env, jobject obj, jint param, jfloat value)
+{
+    alListenerf((ALenum)param, (ALfloat)value);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alListener3f
+  (JNIEnv *env, jobject obj, jint param, jfloat value1, jfloat value2, jfloat value3)
+{
+    alListener3f((ALenum)param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSource3i
+  (JNIEnv *env, jobject obj, jint source, jint param, jint value1, jint value2, jint value3)
+{
+    alSource3i((ALuint)source, (ALenum)param, (ALint)value1, (ALint)value2, (ALint)value3);
+}

+ 173 - 0
jme3-ios-native/src/com_jme3_audio_ios_IosAL.h

@@ -0,0 +1,173 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_jme3_audio_ios_IosAL */
+
+#ifndef _Included_com_jme3_audio_ios_IosAL
+#define _Included_com_jme3_audio_ios_IosAL
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alGetString
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_jme3_audio_ios_IosAL_alGetString
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alGenSources
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_jme3_audio_ios_IosAL_alGenSources
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alGetError
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_jme3_audio_ios_IosAL_alGetError
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alDeleteSources
+ * Signature: (ILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alDeleteSources
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alGenBuffers
+ * Signature: (ILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alGenBuffers
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alDeleteBuffers
+ * Signature: (ILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alDeleteBuffers
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alSourceStop
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourceStop
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alSourcei
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourcei
+  (JNIEnv *, jobject, jint, jint, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alBufferData
+ * Signature: (IILjava/nio/ByteBuffer;II)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alBufferData
+  (JNIEnv *, jobject, jint, jint, jobject, jint, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alSourcePlay
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourcePlay
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alSourcePause
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourcePause
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alSourcef
+ * Signature: (IIF)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourcef
+  (JNIEnv *, jobject, jint, jint, jfloat);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alSource3f
+ * Signature: (IIFFF)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSource3f
+  (JNIEnv *, jobject, jint, jint, jfloat, jfloat, jfloat);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alGetSourcei
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL Java_com_jme3_audio_ios_IosAL_alGetSourcei
+  (JNIEnv *, jobject, jint, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alSourceUnqueueBuffers
+ * Signature: (IILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourceUnqueueBuffers
+  (JNIEnv *, jobject, jint, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alSourceQueueBuffers
+ * Signature: (IILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSourceQueueBuffers
+  (JNIEnv *, jobject, jint, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alListener
+ * Signature: (ILjava/nio/FloatBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alListener
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alListenerf
+ * Signature: (IF)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alListenerf
+  (JNIEnv *, jobject, jint, jfloat);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alListener3f
+ * Signature: (IFFF)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alListener3f
+  (JNIEnv *, jobject, jint, jfloat, jfloat, jfloat);
+
+/*
+ * Class:     com_jme3_audio_ios_IosAL
+ * Method:    alSource3i
+ * Signature: (IIIII)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosAL_alSource3i
+  (JNIEnv *, jobject, jint, jint, jint, jint, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 178 - 0
jme3-ios-native/src/com_jme3_audio_ios_IosALC.c

@@ -0,0 +1,178 @@
+//#include "util.h"
+#include "com_jme3_audio_ios_IosALC.h"
+//#include "AL/alc.h"
+//#include "AL/alext.h"
+
+#include "OpenAL/al.h"
+#include "OpenAL/alc.h"
+#include "OpenAL/oalMacOSX_OALExtensions.h"
+
+static jboolean created = JNI_FALSE;
+
+/* InitAL opens the default device and sets up a context using default
+ * attributes, making the program ready to call OpenAL functions. */
+static int InitAL()
+{
+    ALCdevice *device = NULL;
+    ALCcontext *ctx = NULL;
+
+    /* Open and initialize a device with default settings */
+    device = alcOpenDevice(NULL);
+    
+    if(device == NULL)
+    {
+        fprintf(stderr, "Could not open a device!\n");
+        goto cleanup;
+    }
+
+    ctx = alcCreateContext(device, NULL);
+    
+    if (ctx == NULL)
+    {
+        fprintf(stderr, "Could not create context!\n");
+        goto cleanup;
+    }
+    
+    if (!alcMakeContextCurrent(ctx)) 
+    {
+        fprintf(stderr, "Could not make context current!\n");
+        goto cleanup;
+    }
+
+    return 0;
+    
+cleanup:
+    if (ctx != NULL) alcDestroyContext(ctx);
+    if (device != NULL) alcCloseDevice(device);
+    return 1;
+}
+
+/* CloseAL closes the device belonging to the current context, and destroys the
+ * context. */
+static void CloseAL()
+{
+    ALCdevice *device;
+    ALCcontext *ctx;
+
+    ctx = alcGetCurrentContext();
+    
+    if (ctx == NULL) 
+    {
+        return;
+    }
+
+    device = alcGetContextsDevice(ctx);
+    
+    if (device == NULL) 
+    {
+        return;
+    }
+
+    if(!alcMakeContextCurrent(NULL)) {
+        return;
+    }
+
+    alcDestroyContext(ctx);
+    alcCloseDevice(device);
+}
+
+static ALCdevice* GetALCDevice()
+{
+    ALCdevice *device;
+    ALCcontext *ctx;
+
+    ctx = alcGetCurrentContext();
+    
+    if (ctx != NULL) 
+    {
+        device = alcGetContextsDevice(ctx);
+        
+        if (device != NULL)
+        {
+            return device;
+        }
+    }
+    
+    return NULL;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_jme3_audio_ios_IosALC_isCreated
+  (JNIEnv* env, jobject obj)
+{
+    return created;
+}
+
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_createALC
+  (JNIEnv* env, jobject obj)
+{
+    created = (InitAL() == 0);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_destroyALC
+  (JNIEnv* env, jobject obj)
+{
+    CloseAL();
+    created = JNI_FALSE;
+}
+
+JNIEXPORT jstring JNICALL Java_com_jme3_audio_ios_IosALC_alcGetString
+  (JNIEnv* env, jobject obj, jint param)
+{
+    ALCdevice* device = GetALCDevice();
+    if (device == NULL) return NULL;
+    return (*env)->NewStringUTF(env, alcGetString(device, param));
+}
+
+JNIEXPORT jboolean JNICALL Java_com_jme3_audio_ios_IosALC_alcIsExtensionPresent
+  (JNIEnv* env, jobject obj, jstring extension)
+{
+    ALCdevice* device = GetALCDevice();
+    
+    if (device == NULL) return JNI_FALSE;
+    
+    const char* strExtension = (*env)->GetStringUTFChars(env, extension, NULL);
+    
+    if (strExtension == NULL)
+    {
+        return JNI_FALSE;
+    }
+    
+    jboolean result = alcIsExtensionPresent(device, strExtension);
+    
+    (*env)->ReleaseStringUTFChars(env, extension, strExtension);
+    
+    return result;
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_alcGetInteger
+  (JNIEnv* env, jobject obj, jint param, jobject buffer, jint bufferSize)
+{
+    ALCdevice* device = GetALCDevice();
+    
+    if (device == NULL) return;
+
+    ALCint* pBuffers = (ALCint*) (*env)->GetDirectBufferAddress(env, buffer);
+
+    alcGetIntegerv(device, (ALCenum)param, (ALCsizei)bufferSize, pBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_alcDevicePauseSOFT
+  (JNIEnv* env, jobject obj)
+{
+    ALCdevice* device = GetALCDevice();
+    
+    if (device == NULL) return;
+    
+//    alcDevicePauseSOFT(device);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_alcDeviceResumeSOFT
+  (JNIEnv* env, jobject obj)
+{
+    ALCdevice* device = GetALCDevice();
+    
+    if (device == NULL) return;
+    
+//    alcDeviceResumeSOFT(device);
+}

+ 77 - 0
jme3-ios-native/src/com_jme3_audio_ios_IosALC.h

@@ -0,0 +1,77 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_jme3_audio_ios_IosALC */
+
+#ifndef _Included_com_jme3_audio_ios_IosALC
+#define _Included_com_jme3_audio_ios_IosALC
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_jme3_audio_ios_IosALC
+ * Method:    createALC
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_createALC
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosALC
+ * Method:    destroyALC
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_destroyALC
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosALC
+ * Method:    isCreated
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_jme3_audio_ios_IosALC_isCreated
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosALC
+ * Method:    alcGetString
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_jme3_audio_ios_IosALC_alcGetString
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosALC
+ * Method:    alcIsExtensionPresent
+ * Signature: (Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_jme3_audio_ios_IosALC_alcIsExtensionPresent
+  (JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     com_jme3_audio_ios_IosALC
+ * Method:    alcGetInteger
+ * Signature: (ILjava/nio/IntBuffer;I)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_alcGetInteger
+  (JNIEnv *, jobject, jint, jobject, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosALC
+ * Method:    alcDevicePauseSOFT
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_alcDevicePauseSOFT
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosALC
+ * Method:    alcDeviceResumeSOFT
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosALC_alcDeviceResumeSOFT
+  (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 79 - 0
jme3-ios-native/src/com_jme3_audio_ios_IosEFX.c

@@ -0,0 +1,79 @@
+//#include "util.h"
+#include "com_jme3_audio_ios_IosEFX.h"
+//#include "AL/alext.h"
+
+#include "OpenAL/al.h"
+#include "OpenAL/alc.h"
+#include "OpenAL/oalMacOSX_OALExtensions.h"
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alGenAuxiliaryEffectSlots
+  (JNIEnv* env, jobject obj, jint numSlots, jobject buffer)
+{
+    ALuint* pBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, buffer);
+//    alGenAuxiliaryEffectSlots((ALsizei)numSlots, pBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alGenEffects
+  (JNIEnv* env, jobject obj, jint numEffects, jobject buffer)
+{
+    ALuint* pBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, buffer);
+//    alGenEffects((ALsizei)numEffects, pBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alEffecti
+  (JNIEnv* env, jobject obj, jint effect, jint param, jint value)
+{
+//    alEffecti((ALuint)effect, (ALenum)param, (ALint)value);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alAuxiliaryEffectSloti
+  (JNIEnv* env, jobject obj, jint effectSlot, jint param, jint value)
+{
+//    alAuxiliaryEffectSloti((ALuint)effectSlot, (ALenum)param, (ALint)value);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alDeleteEffects
+  (JNIEnv* env, jobject obj, jint numEffects, jobject buffer)
+{
+    ALuint* pBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, buffer);
+//    alDeleteEffects((ALsizei)numEffects, pBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alDeleteAuxiliaryEffectSlots
+  (JNIEnv* env, jobject obj, jint numEffectSlots, jobject buffer)
+{
+    ALuint* pBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, buffer);
+//    alDeleteAuxiliaryEffectSlots((ALsizei)numEffectSlots, pBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alGenFilters
+  (JNIEnv* env, jobject obj, jint numFilters, jobject buffer)
+{
+    ALuint* pBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, buffer);
+//    alGenFilters((ALsizei)numFilters, pBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alFilteri
+  (JNIEnv* env, jobject obj, jint filter, jint param, jint value)
+{
+//    alFilteri((ALuint)filter, (ALenum)param, (ALint)value);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alFilterf
+  (JNIEnv* env, jobject obj, jint filter, jint param, jfloat value)
+{
+//    alFilterf((ALuint)filter, (ALenum)param, (ALfloat)value);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alDeleteFilters
+  (JNIEnv* env, jobject obj, jint numFilters, jobject buffer)
+{
+    ALuint* pBuffers = (ALuint*) (*env)->GetDirectBufferAddress(env, buffer);
+//    alDeleteFilters((ALsizei)numFilters, pBuffers);
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alEffectf
+  (JNIEnv* env, jobject obj, jint effect, jint param, jfloat value)
+{
+//    alEffectf((ALuint)effect, (ALenum)param, (ALfloat)value);
+}

+ 101 - 0
jme3-ios-native/src/com_jme3_audio_ios_IosEFX.h

@@ -0,0 +1,101 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_jme3_audio_ios_IosEFX */
+
+#ifndef _Included_com_jme3_audio_ios_IosEFX
+#define _Included_com_jme3_audio_ios_IosEFX
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alGenAuxiliaryEffectSlots
+ * Signature: (ILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alGenAuxiliaryEffectSlots
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alGenEffects
+ * Signature: (ILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alGenEffects
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alEffecti
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alEffecti
+  (JNIEnv *, jobject, jint, jint, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alAuxiliaryEffectSloti
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alAuxiliaryEffectSloti
+  (JNIEnv *, jobject, jint, jint, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alDeleteEffects
+ * Signature: (ILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alDeleteEffects
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alDeleteAuxiliaryEffectSlots
+ * Signature: (ILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alDeleteAuxiliaryEffectSlots
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alGenFilters
+ * Signature: (ILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alGenFilters
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alFilteri
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alFilteri
+  (JNIEnv *, jobject, jint, jint, jint);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alFilterf
+ * Signature: (IIF)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alFilterf
+  (JNIEnv *, jobject, jint, jint, jfloat);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alDeleteFilters
+ * Signature: (ILjava/nio/IntBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alDeleteFilters
+  (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class:     com_jme3_audio_ios_IosEFX
+ * Method:    alEffectf
+ * Signature: (IIF)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_audio_ios_IosEFX_alEffectf
+  (JNIEnv *, jobject, jint, jint, jfloat);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 94 - 0
jme3-ios-native/src/com_jme3_util_IosNativeBufferAllocator.c

@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2009-2024 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file com_jme3_util_IosNativeBufferAllocator.c
+ * @author Jesus Oliver, taken from pavl_g's AndroidNativeBufferAllocator.
+ * @brief Creates and releases direct byte buffers for {com.jme3.util.IosNativeBufferAllocator}.
+ * @date 2024-09-24.
+ * @note
+ * Find more at :
+ * - JNI Direct byte buffers : https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#NewDirectByteBuffer.
+ * - JNI Get Direct byte buffer : https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#GetDirectBufferAddress.
+ * - GNU Basic allocation : https://www.gnu.org/software/libc/manual/html_node/Basic-Allocation.html.
+ * - GNU Allocating Cleared Space : https://www.gnu.org/software/libc/manual/html_node/Allocating-Cleared-Space.html.
+ * - GNU No Memory error : https://www.gnu.org/software/libc/manual/html_node/Error-Codes.html#index-ENOMEM.
+ * - GNU Freeing memory : https://www.gnu.org/software/libc/manual/html_node/Freeing-after-Malloc.html.
+ * - iOS logging : 
+ */
+
+#include "com_jme3_util_IosNativeBufferAllocator.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+
+// TODO: iOS log
+
+bool isDeviceOutOfMemory(void*);
+
+/**
+ * @brief Tests if the device is out of memory.
+ *
+ * @return true if the buffer to allocate is a NULL pointer and the errno is ENOMEM (Error-no-memory).
+ * @return false otherwise.
+ */
+bool isDeviceOutOfMemory(void* buffer) {
+    return buffer == NULL && errno == ENOMEM;
+}
+
+JNIEXPORT void JNICALL Java_com_jme3_util_IosNativeBufferAllocator_releaseDirectByteBuffer
+(JNIEnv * env, jobject object, jobject bufferObject)
+{
+    void* buffer = (*env)->GetDirectBufferAddress(env, bufferObject);
+    // deallocates the buffer pointer
+    free(buffer);
+    // log the destruction by mem address
+    //LOG(ANDROID_LOG_INFO, "Buffer released (mem_address, size) -> (%p, %lu)", buffer, sizeof(buffer));
+    // avoid accessing this memory space by resetting the memory address
+    buffer = NULL;
+    //LOG(ANDROID_LOG_INFO, "Buffer mem_address formatted (mem_address, size) -> (%p, %u)", buffer, sizeof(buffer));
+}
+
+JNIEXPORT jobject JNICALL Java_com_jme3_util_IosNativeBufferAllocator_createDirectByteBuffer
+(JNIEnv * env, jobject object, jlong size)
+{
+    void* buffer = calloc(1, size);
+    if (isDeviceOutOfMemory(buffer)) {
+       //LOG(ANDROID_LOG_FATAL, "Device is out of memory exiting with %u", errno);
+       exit(errno);
+    } else {
+       //LOG(ANDROID_LOG_INFO, "Buffer created successfully (mem_address, size) -> (%p %lli)", buffer, size);
+    }
+    return (*env)->NewDirectByteBuffer(env, buffer, size);
+}
+
+

+ 29 - 0
jme3-ios-native/src/com_jme3_util_IosNativeBufferAllocator.h

@@ -0,0 +1,29 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_jme3_util_IosNativeBufferAllocator */
+
+#ifndef _Included_com_jme3_util_IosNativeBufferAllocator
+#define _Included_com_jme3_util_IosNativeBufferAllocator
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_jme3_util_IosNativeBufferAllocator
+ * Method:    releaseDirectByteBuffer
+ * Signature: (Ljava/nio/Buffer;)V
+ */
+JNIEXPORT void JNICALL Java_com_jme3_util_IosNativeBufferAllocator_releaseDirectByteBuffer
+  (JNIEnv *, jobject, jobject);
+
+/*
+ * Class:     com_jme3_util_IosNativeBufferAllocator
+ * Method:    createDirectByteBuffer
+ * Signature: (J)Ljava/nio/ByteBuffer;
+ */
+JNIEXPORT jobject JNICALL Java_com_jme3_util_IosNativeBufferAllocator_createDirectByteBuffer
+  (JNIEnv *, jobject, jlong);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 192 - 0
jme3-ios-native/src/jme-ios.m

@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2009-2013 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <jni.h>
+#import <UIKit/UIKit.h>
+
+/**
+ * Author: Normen Hansen
+ */
+
+#ifndef JNIEXPORT
+#define JNIEXPORT __attribute__ ((visibility("default"))) \
+  __attribute__ ((used))
+#endif
+
+BOOL checkJNIException(JNIEnv *e){
+    if ((*e)->ExceptionCheck(e)) {
+        (*e)->ExceptionDescribe(e);
+        (*e)->ExceptionClear(e);
+        return YES;
+    }
+    return NO;
+}
+
+#ifndef _Included_com_jme3_system_ios_IosImageLoader
+#define _Included_com_jme3_system_ios_IosImageLoader
+#endif
+
+
+static void flipImage(int scanline, int height, char* data)
+{
+    char tmp[scanline];
+    
+    for (int y = 0; y < height / 2; y++)
+    {
+        int oppY = height - y - 1;
+        int yOff  = y * scanline;
+        int oyOff = oppY * scanline;
+        // Copy scanline at Y to tmp
+        memcpy(tmp, &data[yOff], scanline);
+        // Copy data at opposite Y to Y
+        memcpy(&data[yOff], &data[oyOff], scanline);
+        // Copy tmp to opposite Y
+        memcpy(&data[oyOff], tmp, scanline);
+    }
+}
+
+JNIEXPORT jobject JNICALL
+Java_com_jme3_system_ios_IosImageLoader_loadImageData(JNIEnv* e, jclass obj, jobject imageFormat, jboolean flipY, jobject inputStream){
+    // prepare java classes and method pointers
+    jclass imageClass = (*e)->FindClass(e, "com/jme3/texture/Image");
+    jclass imageFormatClass = (*e)->FindClass(e, "com/jme3/texture/Image$Format");
+    jclass inputStreamClass = (*e)->FindClass(e, "java/io/InputStream");
+    jclass bufferUtilsClass = (*e)->FindClass(e, "com/jme3/util/BufferUtils");
+    jclass colorSpaceClass = (*e)->FindClass(e, "com/jme3/texture/image/ColorSpace");
+    
+    jmethodID imageConstructor = (*e)->GetMethodID(e, imageClass, "<init>", "(Lcom/jme3/texture/Image$Format;IILjava/nio/ByteBuffer;Lcom/jme3/texture/image/ColorSpace;)V");
+    jmethodID readMethod = (*e)->GetMethodID(e, inputStreamClass, "read", "([B)I");
+    jmethodID newBufferMethod = (*e)->GetStaticMethodID(e, bufferUtilsClass, "createByteBuffer", "(I)Ljava/nio/ByteBuffer;");
+    jmethodID bitsPerPixel = (*e)->GetMethodID(e, imageFormatClass, "getBitsPerPixel", "()I");
+    jfieldID sRGBFieldID = (*e)->GetStaticFieldID(e, colorSpaceClass, "sRGB", "Lcom/jme3/texture/image/ColorSpace;");
+    jobject sRGBVal = (*e)->GetStaticObjectField(e, colorSpaceClass, sRGBFieldID);
+    
+    if (checkJNIException(e)) {
+        return nil;
+    }
+
+    int bpp = (*e)->CallIntMethod(e, imageFormat, bitsPerPixel);
+    int comps = 4; // Components (Bytes) per Pixel
+    
+    if ((bpp % 8) == 0)
+    {
+        comps = bpp / 8;
+    } else {
+        jclass assetExClazz = (*e)->FindClass(e, "com/jme3/asset/AssetLoadException");
+        (*e)->ThrowNew(e, assetExClazz, "Unsupported ImageFormat: Bits per Pixel is not multiple of 8");
+    }
+    
+    // read data from inputstream via byteArray to NSMutableData
+    jbyteArray tempArray = (*e)->NewByteArray (e, 1000);
+    if (checkJNIException(e)) {
+        return nil;
+    }
+    
+    NSMutableData *inData = [[NSMutableData alloc] init];
+    jint size = (*e)->CallIntMethod(e, inputStream, readMethod, tempArray);
+    if (checkJNIException(e)) {
+        [inData release];
+        return nil;
+    }
+    while (size != -1) {
+        jbyte *data;
+        data = (*e)->GetByteArrayElements(e, tempArray, false);
+        [inData appendBytes:data length:size];
+        (*e)->ReleaseByteArrayElements(e, tempArray, data, JNI_ABORT);
+        size = (*e)->CallIntMethod(e, inputStream, readMethod, tempArray);
+        if (checkJNIException(e)) {
+            [inData release];
+            return nil;
+        }
+    }
+    (*e)->DeleteLocalRef(e, tempArray);
+    if (checkJNIException(e)) {
+        [inData release];
+        return nil;
+    }
+    
+    // decode image data
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    UIImage* inputImage = [UIImage imageWithData:inData];
+    if(inputImage == nil){
+        [inData release];
+        [pool release];
+        return nil;
+    }
+    CGImageRef inImage = [inputImage CGImage];
+    int wdth = CGImageGetWidth(inImage);
+    int ht = CGImageGetHeight(inImage);
+    
+    // NewDirectByteBuffer seems to fail? -> Creating ByteBuffer in java
+    jobject nativeBuffer = (*e)->CallStaticObjectMethod(e, bufferUtilsClass, newBufferMethod, ht*wdth*comps);
+    if (checkJNIException(e)) {
+        [inData release];
+        [pool release];
+        return nil;
+    }
+    void *rawData = (*e)->GetDirectBufferAddress(e, nativeBuffer);
+    NSUInteger bytesPerRowImg = CGImageGetBytesPerRow(inImage);
+    NSUInteger bitsPerComponentImg = CGImageGetBitsPerComponent(inImage);
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    CGContextRef context = CGBitmapContextCreate(rawData,wdth,ht,bitsPerComponentImg,bytesPerRowImg,colorSpace,kCGImageAlphaPremultipliedLast| kCGBitmapByteOrder32Big);
+    CGColorSpaceRelease(colorSpace);
+    CGContextDrawImage(context,CGRectMake(0,0,wdth,ht), inImage);
+    CGContextRelease(context);
+    [inData release];
+    [pool release];
+    
+    if (flipY) {
+        flipImage(wdth * comps, ht, rawData);
+    }
+    
+    //create image
+    jobject imageObject = (*e)->NewObject(e, imageClass, imageConstructor, imageFormat, wdth, ht, nativeBuffer, sRGBVal);
+    return imageObject;
+}
+
+#ifndef _Included_com_jme3_system_ios_JmeIosSystem
+#define _Included_com_jme3_system_ios_JmeIosSystem
+#endif
+
+JNIEXPORT void JNICALL
+Java_com_jme3_system_ios_JmeIosSystem_showDialog(JNIEnv* e, jobject c, jstring text) {
+    const char* chars = (*e)->GetStringUTFChars(e, text, 0);
+    NSString* string = [[NSString alloc] initWithUTF8String : chars];
+    (*e)->ReleaseStringUTFChars(e, text, chars);
+    UIAlertView *alert = [[UIAlertView alloc] initWithTitle : @"Error"
+                                                    message : string
+                                                   delegate : nil
+                                          cancelButtonTitle : @"OK"
+                                          otherButtonTitles : nil];
+    [alert show];
+    [alert release];
+    [string release];
+}

+ 18 - 0
jme3-ios-native/src/jme3_ios_native.h

@@ -0,0 +1,18 @@
+//
+//  jme3_ios_native.h
+//  jme3-ios-native
+//
+//  Created by joliver82 on 19/09/2024.
+//
+
+#import <Foundation/Foundation.h>
+
+//! Project version number for jme3_ios_native_lib.
+FOUNDATION_EXPORT double jme3_ios_nativeVersionNumber;
+
+//! Project version string for jme3_ios_native_lib.
+FOUNDATION_EXPORT const unsigned char jme3_ios_nativeVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <jme3_ios_native_lib/PublicHeader.h>
+
+

+ 9 - 0
jme3-ios-native/template/META-INF/robovm/ios/robovm.xml

@@ -0,0 +1,9 @@
+<config>
+    <frameworkPaths>
+        <path>libs</path>
+    </frameworkPaths>
+    <frameworks>
+        <framework>jme3-ios-native</framework>
+    </frameworks>
+</config>
+

+ 11 - 0
jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java

@@ -42,6 +42,9 @@ import com.jme3.opencl.Context;
 import com.jme3.renderer.ios.IosGL;
 import com.jme3.renderer.ios.IosGL;
 import com.jme3.renderer.opengl.*;
 import com.jme3.renderer.opengl.*;
 import com.jme3.system.*;
 import com.jme3.system.*;
+import com.jme3.util.IosNativeBufferAllocator;
+import com.jme3.util.BufferAllocatorFactory;
+
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
@@ -64,6 +67,14 @@ public class IGLESContext implements JmeContext {
     protected IosInputHandler input;
     protected IosInputHandler input;
     protected int minFrameDuration = 0; // No FPS cap
     protected int minFrameDuration = 0; // No FPS cap
 
 
+    static {
+        final String implementation = BufferAllocatorFactory.PROPERTY_BUFFER_ALLOCATOR_IMPLEMENTATION;
+
+        if (System.getProperty(implementation) == null) {
+            System.setProperty(implementation, IosNativeBufferAllocator.class.getName());
+        }
+    }
+
     public IGLESContext() {
     public IGLESContext() {
         logger.log(Level.FINE, "IGLESContext constructor");
         logger.log(Level.FINE, "IGLESContext constructor");
     }
     }

+ 14 - 1
jme3-ios/src/main/java/com/jme3/system/ios/JmeIosSystem.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2024 jMonkeyEngine
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@ import com.jme3.system.AppSettings;
 import com.jme3.system.JmeContext;
 import com.jme3.system.JmeContext;
 import com.jme3.system.JmeSystemDelegate;
 import com.jme3.system.JmeSystemDelegate;
 import com.jme3.system.NullContext;
 import com.jme3.system.NullContext;
+import com.jme3.system.Platform;
 import com.jme3.util.res.Resources;
 import com.jme3.util.res.Resources;
 import com.jme3.audio.AudioRenderer;
 import com.jme3.audio.AudioRenderer;
 import com.jme3.audio.ios.IosAL;
 import com.jme3.audio.ios.IosAL;
@@ -108,6 +109,18 @@ public class JmeIosSystem extends JmeSystemDelegate {
 //                throw new UnsupportedOperationException("Not supported yet.");
 //                throw new UnsupportedOperationException("Not supported yet.");
     }
     }
 
 
+    @Override
+    public Platform getPlatform() {
+        String arch = System.getProperty("os.arch").toLowerCase();
+        if (arch.contains("arm")) {
+            return Platform.iOS_ARM;
+        } else if (arch.contains("aarch")) {
+            return Platform.iOS_ARM;
+        } else {
+            return Platform.iOS_X86;
+        }
+    }
+
     @Override
     @Override
     public void showSoftKeyboard(boolean show) {
     public void showSoftKeyboard(boolean show) {
         throw new UnsupportedOperationException("Not supported yet.");
         throw new UnsupportedOperationException("Not supported yet.");

+ 71 - 0
jme3-ios/src/main/java/com/jme3/util/IosNativeBufferAllocator.java

@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2009-2024 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.util;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
+/**
+ * Allocates and destroys direct byte buffers using native code.
+ *
+ * @author Jesus Oliver based on pavl_g's AndroidNativeBufferAllocator.
+ */
+public final class IosNativeBufferAllocator implements BufferAllocator {
+
+    @Override
+    public void destroyDirectBuffer(Buffer toBeDestroyed) {
+        releaseDirectByteBuffer(toBeDestroyed);
+    }
+
+    @Override
+    public ByteBuffer allocate(int size) {
+        return createDirectByteBuffer(size);
+    }
+
+    /**
+     * Releases the memory of a direct buffer using a buffer object reference.
+     *
+     * @param buffer the buffer reference to release its memory.
+     * @see IosNativeBufferAllocator#destroyDirectBuffer(Buffer)
+     */
+    private native void releaseDirectByteBuffer(Buffer buffer);
+
+    /**
+     * Creates a new direct byte buffer explicitly with a specific size.
+     *
+     * @param size the byte buffer size used for allocating the buffer.
+     * @return a new direct byte buffer object.
+     * @see IosNativeBufferAllocator#allocate(int)
+     */
+    private native ByteBuffer createDirectByteBuffer(long size);
+}
+

+ 1 - 0
settings.gradle

@@ -30,6 +30,7 @@ include 'jme3-ios'
 
 
 //native builds
 //native builds
 include 'jme3-android-native' //cpp
 include 'jme3-android-native' //cpp
+include 'jme3-ios-native' //cpp
 
 
 // Test Data project
 // Test Data project
 include 'jme3-testdata'
 include 'jme3-testdata'