diff --git a/.github/disabled/build-android.yml b/.github/disabled/build-android.yml index f16050548e0..26ec0d76072 100644 --- a/.github/disabled/build-android.yml +++ b/.github/disabled/build-android.yml @@ -22,11 +22,13 @@ jobs: cfg: - {target: android, gradle_target: compileArm7DebugSources} - {target: android, gradle_target: compileX86DebugSources} + - {target: android, gradle_target: compileArm64DebugSources} + - {target: android, gradle_target: compileX8664DebugSources} env: TARGET: ${{matrix.cfg.target}} GRADLE_TARGET: ${{matrix.cfg.gradle_target}} - NDK_DIR: android-ndk-r15c + NDK_DIR: android-ndk-r23b steps: - uses: actions/checkout@v3 - name: Cache projectGenerator folder @@ -37,7 +39,7 @@ jobs: - name: Cache NDK uses: actions/cache@v3 with: - path: '~/android-ndk-r15c' + path: '~/android-ndk-r23b' key: ${{ runner.os }}-android-ndk-${{matrix.cfg.gradle_target}} - name: install run: ./scripts/ci/$TARGET/install.sh diff --git a/.github/workflows/of.yml b/.github/workflows/of.yml index 54c041ebc78..5bb244372a1 100644 --- a/.github/workflows/of.yml +++ b/.github/workflows/of.yml @@ -454,3 +454,23 @@ jobs: DEVELOPER_DIR: "/Applications/Xcode.app/Contents/Developer" SDKROOT: "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + build-android: + runs-on: ubuntu-24.04 + strategy: + matrix: + cfg: + - { target: android, opt: arm64 } + env: + TARGET: ${{matrix.cfg.target}} + steps: + + - uses: actions/checkout@v4 + # - name: ccache + # uses: hendrikmuhs/ccache-action@v1.2.14 + # with: + # key: ${{ matrix.cfg.target }}-${{ matrix.cfg.libs }} + + - name: Download libs + run: ./scripts/android/download_libs.sh -t $RELEASE + diff --git a/.gitignore b/.gitignore index d0d2b76ec35..d4f4aad5ab1 100644 --- a/.gitignore +++ b/.gitignore @@ -169,3 +169,4 @@ libs/openFrameworksCompiled/project/vs/openframeworksLib.vcxproj.user libs/openFrameworksCompiled/project/vs2019/openframeworksLib.vcxproj.user scripts/templates/vs/bin/emptyExample_debug.exe scripts/templates/vs2019/emptyExample.vcxproj.user +libs/openFrameworksCompiled/project/android/build-*/ diff --git a/addons/ofxAndroid/Java/cc/openframeworks/OFActivity.java b/addons/ofxAndroid/Java/cc/openframeworks/OFActivity.java new file mode 100644 index 00000000000..233481b6673 --- /dev/null +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFActivity.java @@ -0,0 +1,1267 @@ +package cc.openframeworks; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Insets; +import android.graphics.Point; +import android.graphics.Rect; +import android.hardware.display.DisplayManager; +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; + +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.InputDevice; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.Surface; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowInsets; +import android.view.WindowManager; +import android.view.WindowMetrics; +import android.view.accessibility.AccessibilityEvent; + +import java.util.ArrayList; + +import static android.opengl.EGL14.EGL_NO_CONTEXT; + +import static cc.openframeworks.OFAndroidObject.activity; + +import com.getkeepsafe.relinker.ReLinker; + +public abstract class OFActivity extends Activity implements DisplayManager.DisplayListener{ + + private static final String TAG = "OF"; + private DisplayManager displayManager; + private Display display; + private Display presentationDisplay; + public static final boolean LOG_INPUT = false; + public static final boolean LOG_ENGINE = false; + + public float currentRefreshRate = 0; + public float highestRefreshRate = 0; + + public static final String KEY_SAMPLES = "samples"; + public static final String KEY_TARGET_SAMPLES = "targetmsaa"; + public static final String KEY_HIGHEST = "highest"; + public static final String KEY_TARGET_FPS = "fpstarget"; + + public boolean hasPaused = false; + public boolean hasSetup = false; + + public void onGLSurfaceCreated(){ + Log.v("OF","onGLSurfaceCreated"); + } + public void onLoadPercent(float percent){} + public void onUnpackingResourcesDone(){} + + //gesture handler member + private ViewGroup mOFGlSurfaceContainer; + public ViewGroup getSurfaceContainer(){ + return mOFGlSurfaceContainer; + } + + public static String packageName = null; + + public void initView(){ + if(packageName == null) { + packageName = this.getPackageName(); + } + try { + if(LOG_ENGINE) Log.v("OF","trying to find class: "+packageName+".R$layout"); + // Get the resource ID of the layout dynamically + int layoutResID = getResources().getIdentifier("main_layout", "layout", packageName); + + // Check if the resource ID is valid + if (layoutResID == 0) { + Log.e("TAG", "Could not find main_layout.xml."); + throw new Exception(); + } + // Inflate the layout using its resource ID + View view = getLayoutInflater().inflate(layoutResID, null); + // Check if the view was successfully inflated + if (view == null) { + Log.e("TAG", "Could not find main_layout.xml."); + throw new Exception(); + } + if(view == null) { + Log.e("OF", "Could not find main_layout.xml."); + throw new Exception(); + } + this.setContentView(view); + // Find the ViewGroup by its ID + int containerID = getResources().getIdentifier("of_gl_surface_container", "id", packageName); + mOFGlSurfaceContainer = null; + mOFGlSurfaceContainer = findViewById(containerID); + if (mOFGlSurfaceContainer == null) { + Log.e(TAG, "Could not find of_gl_surface_container in main_layout.xml. Copy main_layout.xml from the latest empty example to fix this warning."); + throw new Exception(); + } + + } catch (Exception e) { + Log.w(TAG, "couldn't create view from layout falling back to GL only",e); + mOFGlSurfaceContainer = new ConstraintLayout(this); + this.setContentView(mOFGlSurfaceContainer); + } + + if(mOFGlSurfaceContainer != null) { + mOFGlSurfaceContainer.requestLayout(); + } + } + + public void resetView(){ + String packageName = this.getPackageName(); + try { + if(LOG_ENGINE) Log.v(TAG,"trying to find class: "+packageName+".R$layout"); + Class layout = Class.forName(packageName+".R$layout"); + View view = this.getLayoutInflater().inflate(layout.getField("main_layout").getInt(null),null); + if(view == null) { + Log.e(TAG, "Could not find main_layout.xml."); + throw new Exception(); + } + this.setContentView(view); + + Class id = Class.forName(packageName+".R$id"); + mOFGlSurfaceContainer = (ViewGroup)this.findViewById(id.getField("of_gl_surface_container").getInt(null)); + + if(mOFGlSurfaceContainer == null) { + Log.e(TAG, "Could not find of_gl_surface_container in main_layout.xml. Copy main_layout.xml from latest empty example to fix this warning."); + throw new Exception(); + } + + } catch (Exception e) { + Log.w(TAG, "couldn't create view from layout falling back to GL only",e); + mOFGlSurfaceContainer = new ConstraintLayout(this); + this.setContentView(mOFGlSurfaceContainer); + } + } + + @Override + protected void onCreate(Bundle arg0) { + super.onCreate(arg0); + + try { + OFAndroid.packageName = getPackageName(); + } catch (Exception ex) { + Log.e(TAG, "Failure to getPackageName" + ex.getMessage()); + } + + if(LOG_ENGINE) Log.i(TAG, "onCreate:" + OFAndroid.packageName); + + try { + SharedPreferences settings = getPreferences(); + int samples = OFAndroid.samples; + int maxSamples = OFAndroid.maxSamples; + int maximumFrameRate = OFAndroid.maximumFrameRate; + int targetFrameRate = OFAndroid.targetFrameRate; + if(settings != null) { + maxSamples = settings.getInt(KEY_SAMPLES, OFAndroid.maxSamples); + samples = settings.getInt(KEY_TARGET_SAMPLES, OFAndroid.samples); + maximumFrameRate = settings.getInt(KEY_HIGHEST, OFAndroid.maximumFrameRate); + targetFrameRate = settings.getInt(KEY_TARGET_FPS, OFAndroid.targetFrameRate); + } + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + Log.i(TAG, "SDK < N (24) : MSAA off by default "); + samples = 1; // force no MSAA old devices + maxSamples = 1; + } + else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O && (samples >= 2 && maxSamples >= 2)) { + Log.i(TAG, "SDK < O (26): AAx2 by default"); + maxSamples=2; // force 2xMSAA old devices + samples=2; // force 2xMSAA old devices + } + + OFAndroid.maximumFrameRate = maximumFrameRate; // Restrict Android FPS to 144 FPS - 144 to 240 Hz displays will default to rendering at 120 Hz + OFAndroid.targetFrameRate = targetFrameRate; + OFAndroid.samples = samples; + OFAndroid.maxSamples = maxSamples; + + } catch (Exception ex) { + Log.e(TAG, "onCreate: SharedPreferences:getPreferences Failed!" + ex.getMessage()); + } + + try { + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); // https://developer.android.com/training/gestures/edge-to-edge#lay-out-in-full-screen + }catch (Exception ex) { + Log.e(TAG, "onCreate: setDecorFitsSystemWindows: Failed!" + ex.getMessage()); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + displayManager = getSystemService(DisplayManager.class); + displayManager.registerDisplayListener(this, null); + } + try { + Log.i(TAG, "onCreate: Device:" + Build.MANUFACTURER.toLowerCase()); + if(OFAndroid.isHTCDevice()) OFAndroid.isDeviceHTC = true; + if(OFAndroid.isSamsungDevice()) OFAndroid.isDeviceSamsung = true; + if(OFAndroid.isHuaweiDevice()) OFAndroid.isDeviceHuawei = true; + if(OFAndroid.isAmazonDevice()) OFAndroid.isDeviceAmazon = true; + Log.i(TAG, "onCreate: Device: isDeviceSamsung:" + OFAndroid.isDeviceSamsung + " isDeviceHuawei:" + OFAndroid.isDeviceHuawei + " OFAndroid.isDeviceAmazon:" + OFAndroid.isDeviceAmazon); + } catch (Exception ex) { + Log.e(TAG, "onCreate: Device: Failed!" + ex.getMessage()); + } + + OFAndroidLifeCycle.setActivity(this); + if(OFAndroidLifeCycle.coreLibraryLoaded == false) { + LoadCoreStatic(); + } else { + //Setup(); + } + + clearViewGroup(); + initView(); + + } + + SharedPreferences getPreferences() { + try { + if(getApplicationContext() != null) { + SharedPreferences settings = getApplicationContext().getSharedPreferences("of_settings", 0); + return settings; + } else { + Log.e(TAG, "getPreferences() getApplicationContext == null"); + return null; + } + } catch(Exception ex) { + Log.e(TAG, ex.getMessage()); + return null; + } + } + + public void savePreferences() { + if(OFAndroidLifeCycle.coreLibraryLoaded == false || OFAndroidLifeCycle.getGLView() == null) { + Log.e(TAG, "savePreferences() environment not setup"); + return; + } + try { + SharedPreferences settings = getApplicationContext().getSharedPreferences("of_settings", 0); + SharedPreferences.Editor prefsEditor = settings.edit(); + prefsEditor.putInt(KEY_SAMPLES, OFAndroid.maxSamples); + prefsEditor.putInt(KEY_HIGHEST, OFAndroid.maximumFrameRate); + prefsEditor.putInt(KEY_TARGET_FPS, OFAndroid.targetFrameRate); + prefsEditor.putInt(KEY_TARGET_SAMPLES, OFAndroid.samples); + prefsEditor.apply(); + Log.e(TAG, "savePreferences() done!"); + } catch (Exception ex){ + Log.d(TAG, "savePreferences() -> Exception saving pref" + ex.getMessage()); + } + } + + void clearViewGroup() { + + + ViewGroup glContainer = getSurfaceContainer(); + if(glContainer != null ) { + if (glContainer.getChildCount() > 0) { + if (LOG_ENGINE) Log.i(TAG, "clearViewGroup:views:" + glContainer.getChildCount()); + runOnUiThread(new Runnable() { + @Override + public void run() { + ViewGroup glContainer = getSurfaceContainer(); + + if (glContainer.getChildCount() > 1) { + for (int i = glContainer.getChildCount() - 1; i >= 0; i--) { + View view = glContainer.getChildAt(i); + if (view != null) { + glContainer.removeViewAt(i); + Log.w(OFAndroidLifeCycle.class.getSimpleName(), "SetFirstFrameDrawn::Removing Extra View at Index " + i); + } + } + } + } + }); + } + } + } + + public void LoadCoreStatic() { + if(OFAndroidLifeCycle.coreLibraryLoaded == false) { + ReLinker.loadLibrary(this, "openFrameworksAndroid", new ReLinker.LoadListener() { + @Override + public void success() { + OFAndroidLifeCycle.coreLibraryLoaded = true; + Setup(); + } + @Override + public void failure(Throwable t) { + Log.e(TAG, "Failure to Load Core Static Library: " + t.getMessage()); + } + }); + } + } + + public void Setup() { + if(LOG_ENGINE) Log.i(TAG, "OFAndroid.Setup:" + hasSetup + " | OFAndroidLifeCycle.coreLibraryLoaded:" + OFAndroidLifeCycle.coreLibraryLoaded + "| OFAndroidLifeCycle.appLibraryLoaded :" + OFAndroidLifeCycle.appLibraryLoaded); + + if(!hasSetup && + OFAndroidLifeCycle.appLibraryLoaded && + OFAndroidLifeCycle.coreLibraryLoaded + ) { + hasSetup = true; + + this.runOnUiThread(new Runnable() { + @Override + public void run() { + if(OFAndroid.assetManager == null) + OFAndroid.assetManager = activity.getApplicationContext().getAssets(); + OFAndroid.setAssetManager(OFAndroid.assetManager); + OFAndroidLifeCycle.init(); + OFAndroidLifeCycle.glCreate(); + + DetermineDisplayConfiguration(true); + DetermineDisplayDimensions(); + } + }); + + + } else if(!hasSetup && !OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded == true) { + LoadCoreStatic(); + } else if(hasSetup) { + if(LOG_ENGINE) Log.i(TAG, "OFAndroid.Setup:true | OFAndroidLifeCycle.coreLibraryLoaded:" + OFAndroidLifeCycle.coreLibraryLoaded + "| OFAndroidLifeCycle.appLibraryLoaded :" + OFAndroidLifeCycle.appLibraryLoaded); + } + } + + + public void DetermineDisplayDimensions() { + + try { + OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); + OFAndroid.enableOrientationChangeEvents(); + if(glView != null) { + DisplayMetrics displayMetrics = new DisplayMetrics(); + WindowManager windowManager = getWindowManager(); + if(windowManager != null && getWindowManager().getDefaultDisplay() != null) { + getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics); + int height = displayMetrics.heightPixels; + int width = displayMetrics.widthPixels; + int width_px = Resources.getSystem().getDisplayMetrics().widthPixels; + int height_px = Resources.getSystem().getDisplayMetrics().heightPixels; + int pixeldpi = Resources.getSystem().getDisplayMetrics().densityDpi; + float density = Resources.getSystem().getDisplayMetrics().density; + + + Point point = new Point(); + getWindowManager().getDefaultDisplay().getRealSize(point); + + double x = Math.pow(point.x/ displayMetrics.xdpi, 2); + double y = Math.pow(point.y / displayMetrics.ydpi, 2); + double screenInches = Math.sqrt(x + y); + Log.d(TAG, "Screen inches : " + screenInches +" with realSize:" + point.x +" height:" + point.y); + + //Log.i("OF", "DisplayMetrics: w/h:" +width + "x" + height + " barHeight:" + heightBar + "x barWidth:" + widthBar + " bar:" + bar + " widthBar:" + barWidth + " densityDPI:" +pixeldpi); + if(LOG_ENGINE) Log.i("OF", "DisplayRealMetrics: w/h:" + width_px + "x" + height_px + " pixeldpi:" + pixeldpi + " density:" + density); + //if(hasSetup) + glView.setWindowResize(width, height); + } else { + throw new Exception("Display window problem"); + } + } + } catch (Exception exception) { + Log.w("OF", "Could not get Window for Display ", exception); + } + } + + + public static int getScreenWidth(@NonNull Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics(); + Rect bounds = windowMetrics.getBounds(); + Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility( + WindowInsets.Type.systemBars() + ); + + if (activity.getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE + && activity.getResources().getConfiguration().smallestScreenWidthDp < 600 + ) { // landscape and phone + int navigationBarSize = insets.right + insets.left; + return bounds.width() - navigationBarSize; + } else { // portrait or tablet + return bounds.width(); + } + } else { + DisplayMetrics outMetrics = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(outMetrics); + return outMetrics.widthPixels; + } + } + + public static int getScreenHeight(@NonNull Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics(); + Rect bounds = windowMetrics.getBounds(); + Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility( + WindowInsets.Type.systemBars() + ); + + if (activity.getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE + && activity.getResources().getConfiguration().smallestScreenWidthDp < 600 + ) { // landscape and phone + return bounds.height(); + } else { // portrait or tablet + int navigationBarSize = insets.bottom; + return bounds.height() - navigationBarSize; + } + } else { + DisplayMetrics outMetrics = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(outMetrics); + return outMetrics.heightPixels; + } + } + + + public void DetermineDisplayDimensionsConfigChange(Configuration config) { + + try { + OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); + OFAndroid.enableOrientationChangeEvents(); + //DisplayMetrics systemDisplayMetrics = Resources.getSystem().getDisplayMetrics(); + if(glView != null) { + DisplayMetrics displayMetrics = new DisplayMetrics(); + WindowManager windowManager = getWindowManager(); + if(windowManager != null && getWindowManager().getDefaultDisplay() != null) { + getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics); + int height = displayMetrics.heightPixels; + int width = displayMetrics.widthPixels; + + float density = displayMetrics.density; + //int width = (int)(config.screenWidthDp * density); + //int height = (int)(config.screenHeightDp * density); + if(LOG_ENGINE) Log.i("OF", "DetermineDisplayDimensionsConfigChange: w/h:" + width + "x" + height + " density:" + density); + + glView.setWindowResize(getScreenWidth(this), getScreenHeight(this)); + } else { + throw new Exception("Display window problem"); + } + } + } catch (Exception exception) { + Log.w("OF", "Could not get Window for Display ", exception); + } + } + + public void DetermineDisplayConfiguration(boolean allowSetFrameRate) { + if(LOG_ENGINE) Log.i("OF", "DetermineDisplayConfiguration RefreshRate :" + currentRefreshRate); + + int modeID = 0; + int highestModeID = 0; + try { + display = getWindowManager().getDefaultDisplay(); + if(display.isValid()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + boolean isWideColorGamut = display.isWideColorGamut(); + if(LOG_ENGINE) Log.i("OF", "Display WideColor Gamut Supported:" + isWideColorGamut); + OFAndroid.wideGamut = isWideColorGamut; + boolean isHDR = display.isHdr(); + Log.i("OF", "Display is HDR Supported:" + isHDR); + OFAndroid.hdrScreen = isHDR; + } + currentRefreshRate = display.getRefreshRate(); + if(LOG_ENGINE) Log.i("OF", "Display Current RefreshRate :" + currentRefreshRate); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + try { + Display.Mode[] modes = display.getSupportedModes(); + Display.Mode currentMode = display.getMode(); + modeID = currentMode.getModeId(); + if(LOG_ENGINE) Log.i("OF", "Display Mode: CurrentMode:" + currentMode + " refreshRate: [" + currentMode.getRefreshRate() + "] mode PhysicalWidth:[" + currentMode.getPhysicalWidth() + "] mode PhysicalHeight:[" + currentMode.getPhysicalHeight() + "]"); + + if (currentRefreshRate != currentMode.getRefreshRate()) { + Log.e("OF", "Display Mode: Current Display Mode Refresh Rate not equal to current :" + currentMode + " refreshRate: [" + currentMode.getRefreshRate() + "] displayRefreshRate: " + currentRefreshRate); + } + currentRefreshRate = currentMode.getRefreshRate(); + for (Display.Mode mode : modes) { + if(LOG_ENGINE) Log.i("OF", "Display Mode: Supported:" + mode + " refreshRate: [" + mode.getRefreshRate() + "] mode PhysicalWidth:[" + mode.getPhysicalWidth() + "] mode PhysicalHeight:[" + mode.getPhysicalHeight() + "]" + " <=Max:"+OFAndroid.maximumFrameRate + ":" + ( mode.getRefreshRate() <= OFAndroid.maximumFrameRate)); + if (mode.getRefreshRate() >= highestRefreshRate && mode.getRefreshRate() <= OFAndroid.maximumFrameRate ) { + highestRefreshRate = mode.getRefreshRate(); + if (highestRefreshRate <= OFAndroid.maximumFrameRate) { + highestModeID = mode.getModeId(); + Log.i("OF", "Display Mode Refresh Rate: Supported:" + mode + " refreshRate: [" + mode.getRefreshRate() + "]"); + } + } + } + } catch (Exception ex) { + Log.e("OF", "Display Mode Exception:", ex); + } + } else { // pre 23 Display Mode + try { + float[] refreshRates = display.getSupportedRefreshRates(); + for (float refreshRate : refreshRates) { + if(LOG_ENGINE) Log.i("OF", "Display RefreshRate Supported:" + refreshRate + " <=Max:" + (refreshRate <= OFAndroid.maximumFrameRate)); + if (refreshRate >= highestRefreshRate && (refreshRate <= OFAndroid.maximumFrameRate)) { + highestRefreshRate = refreshRate; + } + } + } catch (Exception ex) { + Log.e("OF", "Display Mode Exception:", ex); + } + } + + if(currentRefreshRate >= highestRefreshRate) { + highestRefreshRate = currentRefreshRate; + highestModeID = modeID; + } + + if(allowSetFrameRate) { + OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); + if (glView != null) { + + if (highestRefreshRate > OFAndroid.maximumFrameRate) { + highestRefreshRate = OFAndroid.maximumFrameRate; // allow capping + } + + try { + Window window = activity.getWindow(); + WindowManager.LayoutParams params = window.getAttributes(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + params.preferredDisplayModeId = highestModeID; + } + window.setAttributes(params); + }catch(Exception ex) { + Log.w("OF", "Setting ModeID:"+ ex.getMessage()); + } + + glView.setFrameRate(highestRefreshRate); + currentRefreshRate = highestRefreshRate; + } + } else { + highestRefreshRate = currentRefreshRate; + } + + } + } else { + Log.w("OF", "Display is not valid yet"); + } + + } catch (Exception ex) { + Log.w("OF", "Could not get Window for Display ", ex); + } + + if(hasSetup) { + OFAndroid.targetFrameRate = (int)currentRefreshRate; + OFAndroid.deviceRefreshRate((int) currentRefreshRate); + OFAndroid.deviceHighestRefreshRate((int) highestRefreshRate); + OFAndroid.setSampleSize(OFAndroid.samples); + } + } + + + @Override + public void onDisplayAdded(int i) { + checkForPresentationDisplays(); + } + + @Override + public void onDisplayRemoved(int i) { + checkForPresentationDisplays(); + } + + @Override + public void onDisplayChanged(int i) { + //if(hasPaused) return; + Log.w("OF", "onDisplayChanged:" + i); + checkForPresentationDisplays(); + try { + display = getWindowManager().getDefaultDisplay(); + if (display != null && display.isValid()) { + boolean allowFPSChange = i != 0; + DetermineDisplayConfiguration(allowFPSChange); + DetermineDisplayDimensions(); + } + } catch(Exception exception) { + Log.w("OF", "onDisplayChanged Display Could not get Window for Display ", exception); + } + } + + private void checkForPresentationDisplays() { + if (displayManager!=null) { + Display[] displays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); + if (displays.length>0) { + presentationDisplay=displays[0]; + if(presentationDisplay != null) { + DisplayMetrics metrics = new DisplayMetrics(); + presentationDisplay.getRealMetrics(metrics); + int realHeight = metrics.heightPixels; + int realWidth = metrics.heightPixels; + if(LOG_ENGINE) Log.i("OF", "checkForPresentationDisplays found external display: isValid:" + presentationDisplay.isValid() + " name:" + presentationDisplay.getName() + " refreshRate:" + presentationDisplay.getRefreshRate() + " Resolution:" + realWidth + "x" + realHeight); + } + } + else { + presentationDisplay=null; + } + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + + super.onConfigurationChanged(newConfig); + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if(LOG_ENGINE) Log.i("OF", "onConfigurationChanged() " + getRequestedOrientation() + " newConfig dpi:" + newConfig.densityDpi + " screenLayout:" + newConfig.screenLayout + " screenWidthDp:" + newConfig.screenWidthDp + " screenHeightDp:" + newConfig.screenHeightDp + " isScreenWideColorGamut:" + newConfig.isScreenWideColorGamut()); + } else { + Log.i("OF", "onConfigurationChanged() " + getRequestedOrientation() + " newConfig dpi:" + newConfig.densityDpi + " screenLayout:" + newConfig.screenLayout + " screenWidthDp:" + newConfig.screenWidthDp + " screenHeightDp:" + newConfig.screenHeightDp + " isScreenWideColorGamut:" + false); + } + if(newConfig.locale != OFAndroid.locale) { + if(LOG_ENGINE) Log.i("OF", "onConfigurationChanged() Locale has changed to:" + newConfig.locale.getDisplayLanguage()); + } + } catch (Exception ex) { + Log.e("OF", "Display Mode Exception:", ex); + } + int ofOrientation = 0; + switch (display.getRotation()) { + case Surface.ROTATION_90: + ofOrientation = 3; + break; + case Surface.ROTATION_180: + ofOrientation = 2; + break; + case Surface.ROTATION_270: + ofOrientation = 4; + break; + case Surface.ROTATION_0: + default: + ofOrientation = 1; + break; + } + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { + ofOrientation = 3; + } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ + ofOrientation = 0; + } + + if(hasSetup) { + OFAndroid.deviceOrientationChanged(ofOrientation); + DetermineDisplayConfiguration(false); + DetermineDisplayDimensions(); + DetermineDisplayDimensionsConfigChange(newConfig); + } + + } + + public boolean showNavigationBar(Resources resources) { + int id = resources.getIdentifier("config_showNavigationBar", "bool", "android"); + return id > 0 && resources.getBoolean(id); + } + + + // These are handled in the View + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return true; + } + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + + return true; + + } + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + return true; + } + @Override + public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { + return true; + } + // -- View + + + @Override + protected void onStart() { + if(LOG_ENGINE) Log.i("OF", "onStart"); + super.onStart(); + //OFAndroidLifeCycle.glStart(); + + try { + display = getWindowManager().getDefaultDisplay(); + if (display.isValid()) { + DetermineDisplayConfiguration(true); + } + + } catch(Exception exception) { + Log.w("OF", "onStart Display Could not get Window for Display ", exception); + } + + } + + @Override + protected void onStop() { + if(LOG_ENGINE) Log.i("OF", "onStop"); + hasPaused = true; + + OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); + if(glView != null) { + if (Build.VERSION.SDK_INT != Build.VERSION_CODES.P) { + Log.i("OF", "onStop GLView setVisibility GONE"); + //glView.setVisibility(View.GONE); + } + } + + + super.onStop(); + + } + + public void OnBackPressed() { + onBackPressed(); + } + + @Override + protected void onRestart() { + OFAndroidLifeCycle.setActivity(this); + if(LOG_ENGINE) Log.i("OF", "onRestart"); + super.onRestart(); + OFAndroidLifeCycle.glRestart(); + DetermineDisplayConfiguration(true); + } + + public void onForceRestart() { + if(LOG_ENGINE) Log.i("OF", "onForceRestart"); + savePreferences(); + OFAndroid.setupGL(OFAndroid.eglVersion, true); + DetermineDisplayConfiguration(true); + DetermineDisplayDimensions(); + if(mOFGlSurfaceContainer == null) { + Log.e("OF", "onResume mOFGlSurfaceContainer is null - glCreateSurface"); + } + OFAndroidLifeCycle.glResume(mOFGlSurfaceContainer); + } + + + @Override + protected void onResume() { + if(LOG_ENGINE)Log.i("OF", "onResume"); + OFAndroidLifeCycle.setActivity(this); + + super.onResume(); + + if(hasSetup == false) { + Log.i("OF", "onResume hasSetup == false"); + return; + } + + if(OFAndroidLifeCycle.isInit() == true && OFAndroidLifeCycle.firstFrameDrawn() == true && + android.opengl.EGL14.eglGetCurrentContext() == EGL_NO_CONTEXT) { + hasPaused = true; + } + + if(OFAndroidLifeCycle.firstFrameDrawn()) { + Log.i("OF", "onResume firstFrameDrawn"); + } + + if( hasPaused == false) { + Log.i("OF", "onResume hasPaused == false"); + return; + } + + if(OFAndroid.assetManager == null) + OFAndroid.assetManager = activity.getApplicationContext().getAssets(); + OFAndroid.setAssetManager(OFAndroid.assetManager); + + if(android.opengl.EGL14.eglGetCurrentContext() == EGL_NO_CONTEXT){ + Log.e("OF", "onResume eglGetCurrentContext = EGL_NO_CONTEXT BAD"); + OFAndroid.setupGL(OFAndroid.eglVersion, true); + } + if(OFAndroidLifeCycle.isInit() && mOFGlSurfaceContainer == null) { + if(LOG_ENGINE) Log.i("OF", "onResume mOFGlSurfaceContainer is null"); + } + // + if(OFAndroidLifeCycle.isInit() && OFAndroidLifeCycle.getGLView() == null) { + if(LOG_ENGINE) Log.i("OF", "onResume getGLView is null - glCreateSurface"); + //OFAndroidWindow.exit(); + OFAndroid.setupGL(OFAndroid.eglVersion, true); + } + + if(OFAndroidLifeCycle.isInit() && OFAndroidLifeCycle.getGLView() != null && OFAndroidLifeCycle.getGLView().getDisplay() == null) { + if(LOG_ENGINE) Log.i("OF", "onResume getGLView is null - glCreateSurface"); +// OFAndroidWindow.exit(); + OFAndroid.setupGL(OFAndroid.eglVersion, true); + } + + DetermineDisplayConfiguration(true); + DetermineDisplayDimensions(); + if(mOFGlSurfaceContainer == null) { + Log.e("OF", "onResume mOFGlSurfaceContainer is null - glCreateSurface"); + } + OFAndroidLifeCycle.glResume(mOFGlSurfaceContainer); + + hasPaused = false; + + } + @Override + protected void onPause() { + if(LOG_ENGINE) Log.i("OF", "onPause"); + hasPaused = true; + OFAndroidLifeCycle.glPause(); + + super.onPause(); + } + + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); + if (hasFocus && glView != null && glView.getVisibility() == View.GONE) { + if(LOG_ENGINE) Log.i("OF", "onWindowFocusChanged GLView setVisibility VISIBLE"); + OFAndroidLifeCycle.glResume(mOFGlSurfaceContainer); + glView.setVisibility(View.VISIBLE); + DetermineDisplayConfiguration(true); + DetermineDisplayDimensions(); + } + } + + @Override + protected void onDestroy() { + if(LOG_ENGINE) Log.e("OF", "onDestroy"); + hasPaused = true; + OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); + if(glView != null) { + //glView.setVisibility(View.GONE); + } + OFAndroidLifeCycle.glDestroy(); + if (displayManager!=null) { + displayManager.unregisterDisplayListener(this); + } + OFAndroidLifeCycle.coreLibraryLoaded = false; + OFAndroidLifeCycle.appLibraryLoaded = false; + super.onDestroy(); + } + + + + @RequiresApi(28) + private static class OnUnhandledKeyEventListenerWrapper implements View.OnUnhandledKeyEventListener { + private ViewCompat.OnUnhandledKeyEventListenerCompat mCompatListener; + + OnUnhandledKeyEventListenerWrapper(ViewCompat.OnUnhandledKeyEventListenerCompat listener) { + this.mCompatListener = listener; + } + + public boolean onUnhandledKeyEvent(View v, KeyEvent event) { + if(LOG_ENGINE) Log.i("OF", "OFActivity:onUnhandledKeyEvent" + " event:" + event.toString()); + if ((event.getKeyCode() == KeyEvent.KEYCODE_BACK || event.getKeyCode() == KeyEvent.KEYCODE_MENU || event.getKeyCode() == KeyEvent.KEYCODE_BUTTON_MODE)) { + return true; + } + return this.mCompatListener.onUnhandledKeyEvent(v, event); + } + } + + + public ArrayList getGameControllerIds() { + ArrayList gameControllerDeviceIds = new ArrayList(); + int[] deviceIds = InputDevice.getDeviceIds(); + for (int deviceId : deviceIds) { + InputDevice dev = InputDevice.getDevice(deviceId); + int sources = dev.getSources(); + + // Verify that the device has gamepad buttons, control sticks, or both. + if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) + || ((sources & InputDevice.SOURCE_JOYSTICK) + == InputDevice.SOURCE_JOYSTICK)) { + // This device is a game controller. Store its device ID. + if (!gameControllerDeviceIds.contains(deviceId)) { + gameControllerDeviceIds.add(deviceId); + } + } + } + return gameControllerDeviceIds; + } + + + @Override + public boolean dispatchGenericMotionEvent(MotionEvent ev) { + if(LOG_ENGINE) Log.i("OF", "dispatchGenericMotionEvent" + " event:" + ev.toString()); + return OFAndroidController.genericMotionEvent(ev); + } + + + + + @Override + public boolean dispatchKeyEvent (KeyEvent event){ + if(!hasSetup) return true; + int deviceId = event.getDeviceId(); + if(LOG_INPUT) Log.i("OF", "dispatchKeyEvent" + " event:" + event.toString() + " deviceID:" + deviceId + " source:" + event.getSource()); + boolean returnValue = true; + int sourceID = event.getSource(); + if ((event.getSource() & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD && + (event.getSource() & InputDevice.SOURCE_GAMEPAD) != InputDevice.SOURCE_GAMEPAD && + (event.getSource() & InputDevice.SOURCE_JOYSTICK) != InputDevice.SOURCE_JOYSTICK && + (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != InputDevice.SOURCE_CLASS_JOYSTICK && + (event.getSource() & InputDevice.SOURCE_TOUCHPAD) != InputDevice.SOURCE_TOUCHPAD && + (event.getSource() & InputDevice.SOURCE_DPAD) != InputDevice.SOURCE_DPAD && + (event.getDevice() != null && event.getDevice().getVendorId() != OFAndroidController.VendorValve)){ + + if (event.getAction() == KeyEvent.ACTION_DOWN && (event.getKeyCode() == KeyEvent.KEYCODE_BACK || event.getKeyCode() == KeyEvent.KEYCODE_MENU || event.getKeyCode() == KeyEvent.KEYCODE_BUTTON_MODE) && event.getRepeatCount() == 0) { + if( OFAndroid.onBackPressed() ) { + returnValue = true; + } else { + Log.w("OF", "dispatchKeyEvent" + " event KEYCODE_BACK - Exiting"); + //super.onBackPressed(); + hasSetup = false; + finishAffinity(); + System.exit(0); + return false; + } + } + + if((event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP || (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN)) || (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_MUTE) || (event.getKeyCode() == KeyEvent.KEYCODE_FOCUS) || event.getKeyCode() == KeyEvent.KEYCODE_CAMERA || event.getKeyCode() == 287) { + return false; + } + + if(OFAndroid.lastInputID == -1 && event.getDevice() != null || + event.getDevice() != null && OFAndroid.lastInputID != event.getDeviceId() && + OFAndroid.lastInputVendorID != event.getDevice().getVendorId()) { + OFAndroid.lastInputDevice = event.getDevice(); // not sure why this happens + OFAndroid.lastInputDescriptor = event.getDevice().getDescriptor(); + OFAndroid.lastControllerType = OFAndroidController.getControllerType(event.getDevice()); + OFAndroid.lastInputVendorID = OFAndroid.lastInputDevice.getVendorId(); + OFAndroid.lastInputProductID = OFAndroid.lastInputDevice.getProductId(); + if(OFAndroid.lastInputVendorID == 0 && OFAndroid.lastInputProductID == 0 ) { + OFAndroid.lastInputProductID = OFAndroidController.ProductID_PS5; + OFAndroid.lastInputVendorID = OFAndroidController.VendorPS; + } + } + if(LOG_INPUT && OFAndroid.lastInputDevice != null) { + OFAndroid.toast("KB:" + OFAndroid.lastInputDevice.getName() + " keycode:" + event.getKeyCode() + "vendor: " + OFAndroid.lastInputDevice.getVendorId() + "PID:" + OFAndroid.lastInputProductID); + Log.i("OF", "Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + "PID:" + OFAndroid.lastInputProductID); + } + + if(event.getAction() == KeyEvent.ACTION_DOWN) + returnValue = OFAndroid.keyDown(event.getKeyCode(), event); + else if(event.getAction() == KeyEvent.ACTION_UP) + returnValue = OFAndroid.keyUp(event.getKeyCode(), event); + else if(event.getAction() == KeyEvent.ACTION_MULTIPLE) + returnValue = OFAndroid.keyDown(event.getKeyCode(), event); + else if(event.getAction() == KeyEvent.FLAG_CANCELED) + returnValue = OFAndroid.keyUp(event.getKeyCode(), event); + else + returnValue = true; + + } + else if ((event.getSource() & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || + (event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD || + (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK || + (event.getSource() & InputDevice.SOURCE_CLASS_BUTTON) == InputDevice.SOURCE_CLASS_BUTTON || + (event.getSource() & InputDevice.SOURCE_DPAD) > InputDevice.SOURCE_DPAD - 13 && (event.getSource() & InputDevice.SOURCE_DPAD) < InputDevice.SOURCE_GAMEPAD + 500 + ) { + int keyCode = event.getKeyCode(); + if(OFAndroid.lastInputID == -1 && event.getDevice() != null || + event.getDevice() != null && OFAndroid.lastDeviceID != event.getDeviceId() && + OFAndroid.lastInputVendorID != event.getDevice().getVendorId()) { + OFAndroid.lastInputDevice = event.getDevice(); // not sure why this happens + OFAndroid.lastInputID = event.getSource(); + OFAndroid.lastDeviceID = event.getDeviceId(); + OFAndroid.lastInputDescriptor = event.getDevice().getDescriptor(); + OFAndroid.lastControllerType = OFAndroidController.getControllerType(event.getDevice()); + OFAndroid.lastInputVendorID = OFAndroid.lastInputDevice.getVendorId(); + OFAndroid.lastInputProductID = OFAndroid.lastInputDevice.getProductId(); + if(OFAndroid.lastInputVendorID == 0 && OFAndroid.lastInputProductID == 0 ) { + OFAndroid.lastInputProductID = OFAndroidController.ProductID_PS5; + OFAndroid.lastInputVendorID = OFAndroidController.VendorPS; + } + } + if(event.getDevice() == null && OFAndroid.lastInputDevice == null) { + OFAndroid.lastInputDevice = OFAndroidController.getGameControllerForID(event.getDeviceId()); // fall back + OFAndroid.lastControllerType = OFAndroidController.getControllerType(event.getDevice()); + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && + !OFAndroid.isDeviceAmazon && !OFAndroid.isHuaweiDevice() && !OFAndroid.isHTCDevice() + || + Build.VERSION.SDK_INT == Build.VERSION_CODES.S + && OFAndroid.isDeviceSamsung + && !OFAndroid.isDeviceAmazon + ) { // Android 12 fixes PS5 bug + if(LOG_INPUT && OFAndroid.lastInputDevice != null) { + OFAndroid.toast(OFAndroid.lastInputDevice.getName() + " keycode:" + keyCode + "vendor: " + OFAndroid.lastInputDevice.getVendorId() + "PID:" + OFAndroid.lastInputProductID); + Log.i("OF", "Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + "PID:" + OFAndroid.lastInputProductID); + + } + if (OFAndroid.lastInputDevice != null && + OFAndroid.lastInputProductID == OFAndroidController.ProductID_PS5 || + !(OFAndroid.lastInputProductID == OFAndroidController.ProductID_PS4_2) && !(OFAndroid.lastInputProductID == OFAndroidController.ProductID_PS4) && + (OFAndroid.lastInputVendorID == OFAndroidController.VendorPS && + (OFAndroid.lastInputDevice.getName().equals(OFAndroidController.PS5_Controller_NAME) || OFAndroid.lastInputDevice.getName().equals(OFAndroidController.PS5_Controller_NAME_GENERIC)) + )) { + if (keyCode == 97) { // flips X to Square to fix HID issues for PS5 + keyCode = 96; + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 97->96"); + } else if (keyCode == 96) { + keyCode = 99; + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 96->97"); + } else if (keyCode == 100) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 100->102"); + keyCode = 102; + } else if (keyCode == 102) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 102->100"); + keyCode = 100; + } else if (keyCode == 101) { + keyCode = 103; + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 101->103"); + } else if (keyCode == 103) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 103->101"); + keyCode = 101; + } else if (keyCode == 99) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 99->100"); + keyCode = 100; + } else if (keyCode == 104) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 99->100"); + keyCode = 109; + } else if (keyCode == 105) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 99->100"); + keyCode = 108; + } + } else { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) { + OFAndroid.toast(OFAndroid.lastInputDevice.getName() + "| keycode:" + keyCode); + Log.i("OF", "Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + "PID:" + OFAndroid.lastInputProductID); + + } + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "Not PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId()); + else + Log.i("OF", "Not PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId()); + + } + } else if(OFAndroid.isHuaweiDevice() && !OFAndroid.isAmazonDevice()) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + OFAndroid.toast(OFAndroid.lastInputDevice.getName() + " keycode:" + keyCode); + + if (OFAndroid.lastInputDevice != null && + OFAndroid.lastInputProductID == OFAndroidController.ProductID_PS5 || + !(OFAndroid.lastInputProductID == OFAndroidController.ProductID_PS4_2) && !(OFAndroid.lastInputProductID == OFAndroidController.ProductID_PS4) && + (OFAndroid.lastInputVendorID == OFAndroidController.VendorPS && (OFAndroid.lastInputDevice.getName().equals(OFAndroidController.PS5_Controller_NAME) || OFAndroid.lastInputDevice.getName().equals(OFAndroidController.PS5_Controller_NAME_GENERIC) + ))) { + if (keyCode == 102) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 102->100"); + keyCode = 100; + } else if (keyCode == 101) { + keyCode = 103; + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 101->103"); + } else if (keyCode == 103) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + " 103->101"); + keyCode = 101; + } + } + } else if(OFAndroid.isAmazonDevice()) { + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + OFAndroid.toast(OFAndroid.lastInputDevice.getName() + " keycode:" + keyCode); + + if(OFAndroid.lastInputProductID == OFAndroidController.ProductID_PS5 || + !(OFAndroid.lastInputProductID == OFAndroidController.ProductID_PS4_2) && + (OFAndroid.lastInputVendorID == OFAndroidController.VendorPS && + (OFAndroid.lastInputDevice.getName().equals(OFAndroidController.PS5_Controller_NAME) || OFAndroid.lastInputDevice.getName().equals(OFAndroidController.PS5_Controller_NAME_GENERIC)) + )) { +// if (keyCode == 96) { // X on Amazon +// if(LOG_INPUT && OFAndroid.lastInputDevice != null) +// Log.i("OF", "AMAZON PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" +// + OFAndroid.lastInputDevice.getVendorId() + " 96->97"); +// keyCode = 97; // to X +// } else if (keyCode == 99) { // ▢ on Amazon +// if(LOG_INPUT && OFAndroid.lastInputDevice != null) +// Log.i("OF", "AMAZON PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" +// + OFAndroid.lastInputDevice.getVendorId() + " 99->96"); +// keyCode = 96; // ▢ +// } + if (keyCode == 100) { // △ on Amazon + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + + OFAndroid.lastInputDevice.getVendorId() + " 100->99"); + keyCode = 99; + } +// else if (keyCode == 102) { +// if(LOG_INPUT && OFAndroid.lastInputDevice != null) +// Log.i("OF", "AMAZON PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" +// + OFAndroid.lastInputDevice.getVendorId() + " 102->100"); +// keyCode = 100; +// } + else if (keyCode == 101) { + keyCode = 103; + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "AMAZON PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + + OFAndroid.lastInputDevice.getVendorId() + " 101->103"); + } +// else if (keyCode == 103) { +// if(LOG_INPUT && OFAndroid.lastInputDevice != null) +// Log.i("OF", "AMAZON PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" +// + OFAndroid.lastInputDevice.getVendorId() + " 103->101"); +// keyCode = 101; +// } + else if (keyCode == 4) { // share + if(LOG_INPUT && OFAndroid.lastInputDevice != null) + Log.i("OF", "AMAZON PS5 Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + + OFAndroid.lastInputDevice.getVendorId() + " 4->109"); + keyCode = 109; + } + } + } + if(OFAndroid.lastInputID == -1 && event.getDevice() != null || + event.getDevice() != null && OFAndroid.lastDeviceID != event.getDeviceId() && + OFAndroid.lastInputVendorID != event.getDevice().getVendorId()) { + OFAndroid.lastInputDevice = event.getDevice(); // not sure why this happens + OFAndroid.lastInputID = event.getSource(); + OFAndroid.lastDeviceID = event.getDeviceId(); + OFAndroid.lastInputDescriptor = event.getDevice().getDescriptor(); + OFAndroid.lastControllerType = OFAndroidController.getControllerType(event.getDevice()); + OFAndroid.lastInputVendorID = OFAndroid.lastInputDevice.getVendorId(); + OFAndroid.lastInputProductID = OFAndroid.lastInputDevice.getProductId(); + if(OFAndroid.lastInputVendorID == 0 && OFAndroid.lastInputProductID == 0 ) { + OFAndroid.lastInputProductID = OFAndroidController.ProductID_PS5; + OFAndroid.lastInputVendorID = OFAndroidController.VendorPS; + } + } + if (event.getAction() == KeyEvent.ACTION_DOWN && (event.getKeyCode() == KeyEvent.KEYCODE_BACK || event.getKeyCode() == KeyEvent.KEYCODE_MENU || event.getKeyCode() == KeyEvent.KEYCODE_BUTTON_MODE || event.getKeyCode() == 0 ) && event.getRepeatCount() == 0) { + if( OFAndroid.onBackPressed() ) { + returnValue = true; + } else { + Log.w("OF", "dispatchKeyEvent" + " event KEYCODE_BACK - Exiting"); + //super.onBackPressed(); + hasSetup = false; + finishAffinity(); + System.exit(0); + return false; + } + } + if(event.getAction() == KeyEvent.ACTION_DOWN) + returnValue = OFAndroid.keyDown(keyCode+400, event); + else if(event.getAction() == KeyEvent.ACTION_UP) + returnValue = OFAndroid.keyUp(keyCode+400, event); + else if(event.getAction() == KeyEvent.FLAG_CANCELED) + returnValue = OFAndroid.keyUp(keyCode+400, event); + else + returnValue = true; + + + + } else if ((event.getSource() & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) { + returnValue = true; + } else { + + if(OFAndroid.lastInputID == -1 && event.getDevice() != null || + event.getDevice() != null && OFAndroid.lastDeviceID != event.getDeviceId() && + OFAndroid.lastInputVendorID != event.getDevice().getVendorId() ) { + OFAndroid.lastInputDevice = event.getDevice(); // not sure why this happens + OFAndroid.lastInputID = event.getSource(); + OFAndroid.lastDeviceID = event.getDeviceId(); + OFAndroid.lastInputDescriptor = event.getDevice().getDescriptor(); + OFAndroid.lastControllerType = OFAndroidController.getControllerType(event.getDevice()); + OFAndroid.lastInputVendorID = OFAndroid.lastInputDevice.getVendorId(); + OFAndroid.lastInputProductID = OFAndroid.lastInputDevice.getProductId(); + if(OFAndroid.lastInputVendorID == 0 && OFAndroid.lastInputProductID == 0 ) { // Fix for Samsung PS5 + OFAndroid.lastInputProductID = OFAndroidController.ProductID_PS5; + OFAndroid.lastInputVendorID = OFAndroidController.VendorPS; + } + } + if(LOG_INPUT && OFAndroid.lastInputDevice != null) { + OFAndroid.toast("OTHER:" + OFAndroid.lastInputDevice.getName() + " keycode:" + event.getKeyCode() + "vendor: " + OFAndroid.lastInputDevice.getVendorId() + "PID:" + OFAndroid.lastInputProductID); + Log.i("OF", "Controller: name:" + OFAndroid.lastInputDevice.getName() + " vendor:" + OFAndroid.lastInputDevice.getVendorId() + "PID:" + OFAndroid.lastInputProductID); + } + if(event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() != KeyEvent.KEYCODE_UNKNOWN) + returnValue = OFAndroid.keyDown(event.getKeyCode(), event); + else if(event.getAction() == KeyEvent.ACTION_UP && event.getKeyCode() != KeyEvent.KEYCODE_UNKNOWN) + returnValue = OFAndroid.keyUp(event.getKeyCode(), event); + else if(event.getAction() == KeyEvent.FLAG_CANCELED && event.getKeyCode() != KeyEvent.KEYCODE_UNKNOWN) + returnValue = OFAndroid.keyUp(event.getKeyCode(), event); + else + returnValue = super.dispatchKeyEvent(event); + } + return returnValue; + } + + @Override + public boolean dispatchKeyShortcutEvent(KeyEvent event){ + if(LOG_INPUT) Log.i("OF", "dispatchKeyShortcutEvent" + " event:" + event.toString()); + return true; + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + if(LOG_INPUT) Log.i("OF", "dispatchPopulateAccessibilityEvent" + " event:" + event.toString()); + return true; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if(LOG_INPUT) Log.i("OF", "dispatchTouchEvent" + " event:" + ev.toString()); + if(OFAndroid.gestureListener != null) { + OFAndroid.gestureListener.onTouch(ev); + } + return true; + } + + @Override + public boolean dispatchTrackballEvent(MotionEvent ev) { + if(LOG_INPUT) Log.i("OF", "dispatchTrackballEvent" + " event:" + ev.toString()); + if(OFAndroid.gestureListener != null) { + OFAndroid.gestureListener.onTouch(ev); + } + return true; + } + + @Override + public boolean onNavigateUp(){ + if(LOG_INPUT) Log.i("OF", "onNavigateUp"); + return true; + } + + @Override + public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) { + if(LOG_ENGINE) Log.i("OF", "onMultiWindowModeChanged:isInMultiWindowMode:" + isInMultiWindowMode); + OFAndroid.setMultiWindowMode(isInMultiWindowMode); + + //if(hasPaused) return; + + if(LOG_ENGINE) Log.i("OF", "onMultiWindowModeChanged() " + getRequestedOrientation() + " newConfig dpi:" + newConfig.densityDpi + " screenLayout:" + newConfig.screenLayout + " screenWidthDp:" + newConfig.screenWidthDp + " screenHeightDp:" + newConfig.screenHeightDp + " isScreenWideColorGamut:" + false); + + DetermineDisplayConfiguration(true); + DetermineDisplayDimensions(); + } + + @Override + public boolean onKeyShortcut(int keyCode, KeyEvent event) { + if(LOG_INPUT) Log.i("OF", "onKeyShortcut:isInMultiWindowMode:" + keyCode); + return true; + } + + @Override + public boolean isLaunchedFromBubble () { + if(LOG_ENGINE) Log.i("OF", "isLaunchedFromBubble"); + DetermineDisplayConfiguration(true); + DetermineDisplayDimensions(); + return true; + } + + @Override + public void onAttachedToWindow() { + if(LOG_ENGINE) Log.i("OF", "onAttachedToWindow"); + super.onAttachedToWindow(); + } + + +} diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroid.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroid.java similarity index 64% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroid.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFAndroid.java index 83f2ab5fcc3..db0d40634da 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroid.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroid.java @@ -3,10 +3,11 @@ import java.io.File; import java.lang.reflect.Field; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.UUID; -import android.Manifest; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; @@ -17,6 +18,9 @@ import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; import android.hardware.SensorManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -25,11 +29,15 @@ import android.net.wifi.WifiManager.MulticastLock; import android.os.Build; import android.os.Environment; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import android.provider.MediaStore; import android.util.Log; +import android.view.InputDevice; import android.view.KeyEvent; import android.view.ScaleGestureDetector; +import android.view.View; import android.view.WindowManager.LayoutParams; import android.widget.ArrayAdapter; import android.widget.CompoundButton; @@ -38,22 +46,103 @@ import android.widget.ListView; import android.widget.Toast; import java.util.concurrent.Semaphore; +import androidx.annotation.Keep; +@Keep public class OFAndroid { public static String packageName; + public static int eglVersion = 2; + public static int samples = 8; + public static int maxSamples = 8; + public static int maximumFrameRate = 144; + public static int targetFrameRate = 144; + public static int width; + public static int height; + public static Locale locale; + + public static int lastInputID = -1; + public static int lastDeviceID = -1; + public static int lastInputVendorID = -1; + public static int lastInputProductID = -1; + public static String lastInputDescriptor = ""; + public static OFAndroidController.ControllerType lastControllerType = OFAndroidController.ControllerType.NONE; + public static InputDevice lastInputDevice = null; + public static AssetManager assetManager; + + public static boolean isDeviceSamsung = false; + public static boolean isDeviceHTC = false; + public static boolean isDeviceHuawei = false; + public static boolean isDeviceAmazon = false; + + public static boolean isHTCDevice() + { + String manufacturer = android.os.Build.MANUFACTURER; + return manufacturer.toLowerCase(Locale.ENGLISH).contains("htc"); + } + + public static boolean isSamsungDevice() + { + String manufacturer = android.os.Build.MANUFACTURER; + return manufacturer.toLowerCase(Locale.ENGLISH).contains("samsung"); + } + + public static boolean isHuaweiDevice() + { + String manufacturer = android.os.Build.MANUFACTURER; + return manufacturer.toLowerCase(Locale.ENGLISH).contains("huawei"); + } + + public static boolean isAmazonDevice() + { + String manufacturer = android.os.Build.MANUFACTURER; + return manufacturer.toLowerCase(Locale.ENGLISH).contains("amazon"); + } + // List based on http://bit.ly/NpkL4Q + @SuppressLint("SdCardPath") // the following list is fall back 3 private static final String[] mExternalStorageDirectories = new String[] { - "/mnt/sdcard-ext", + + "/mnt/Removable/MicroSD", + "/storage/removable/sdcard1", // !< Sony Xperia Z1 + "/Removable/MicroSD", // Asus ZenPad C + "/removable/microsd", + "/external_sd", // Samsung + "/_ExternalSD", // some LGs + "/storage/extSdCard", // later Samsung + "/storage/extsdcard", // Main filesystem is case-sensitive; FAT isn't. + "/mnt/extsd", // some Chinese tablets, e.g. Zeki + "/storage/sdcard1", // If this exists it's more likely than sdcard0 to be removable. + "/mnt/extSdCard", "/mnt/sdcard/external_sd", - "/sdcard/sd", "/mnt/external_sd", + "/storage/external_SD", + "/storage/ext_sd", // HTC One Max + "/mnt/sdcard/_ExternalSD", + "/mnt/sdcard-ext", + "/sdcard2", // HTC One M8s + "/sdcard1", // Sony Xperia Z + "/mnt/media_rw/sdcard1", // 4.4.2 on CyanogenMod S3 + "/mnt/sdcard", // This can be built-in storage (non-removable). + "/sdcard", + "/storage/sdcard0", "/emmc", + "/mnt/emmc", + "/sdcard/sd", "/mnt/sdcard/bpemmctest", - "/mnt/sdcard/_ExternalSD", - "/mnt/Removable/MicroSD", - "/Removable/MicroSD", - "/sdcard"}; + "/mnt/external1", + "/data/sdext4", + "/data/sdext3", + "/data/sdext2", + "/data/sdext", + "/storage/microsd", //ASUS ZenFone 2 + // If we ever decide to support USB OTG storage, the following paths could be helpful: + // An LG Nexus 5 apparently uses usb://1002/UsbStorage/ as a URI to access an SD + // card over OTG cable. Other models, like Galaxy S5, use /storage/UsbDriveA + // "/mnt/usb_storage", + // "/mnt/UsbDriveA", + // "/mnt/UsbDrsdcard-extiveB", + }; private static String getPackageName(){ return OFAndroidLifeCycle.getActivity().getPackageName(); @@ -77,20 +166,94 @@ public static void requestPermission(String permission){ } } - public static String getRealExternalStorageDirectory(Context context) - { + public static void savePreferences() { + Activity activity = OFAndroidLifeCycle.getActivity(); + if(activity != null && OFActivity.class.isInstance(activity)) + ((OFActivity)activity).savePreferences(); + } + + private boolean isExternalStorageWritable() { + return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); + } + + public static Bitmap screenShot(View view) { + Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),view.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + view.draw(canvas); + return bitmap; + } + + @SuppressWarnings("unused") + private String getPictureDirectoryPath() { + return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath(); + } + + + @SuppressWarnings("unused") + private void addScreenshotToGallery(String filepath) { + Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + File f = new File(filepath); + Uri contentUri = Uri.fromFile(f); + mediaScanIntent.setData(contentUri); + OFAndroidLifeCycle.getActivity().sendBroadcast(mediaScanIntent); + } + + public static Bitmap screenShot(OFGLSurfaceView view) { + Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),view.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + view.draw(canvas); + return bitmap; + } + + public static void share(Context context, Bitmap bitmap, String subject, String text){ + String pathofBmp= + MediaStore.Images.Media.insertImage(context.getContentResolver(), + bitmap,"title", null); + Uri uri = Uri.parse(pathofBmp); + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("image/*"); + shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject); + shareIntent.putExtra(Intent.EXTRA_TEXT, text); + shareIntent.putExtra(Intent.EXTRA_STREAM, uri); + context.startActivity(Intent.createChooser(shareIntent, subject)); + } + + + // Checks if a volume containing external storage is available to at least read. + private boolean isExternalStorageReadable() { + return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) || + Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY); + } + + public static String getDirectoryPictures() { + return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath(); + } + + public static String getRealExternalStorageDirectory(Context context) { + + + + // Standard way to get the external storage directory + File externalPathFile = Environment.getExternalStorageDirectory(); + if (externalPathFile.exists()) { + File externalPathFileInternal = new File(externalPathFile.getPath() + "/Android/data/"+packageName); + if(externalPathFileInternal.exists() && externalPathFileInternal.canWrite()) + return externalPathFileInternal.getPath(); + } + // Standard way to get the external storage directory String externalPath = context.getExternalFilesDir(null).getPath(); - File SDCardDir = new File(externalPath); - if(SDCardDir.exists() && SDCardDir.canWrite()) { - return externalPath; - } + if(externalPath.endsWith("/files")) externalPath = externalPath.replace("/files", ""); + File externalCardDir = new File(externalPath); + if(externalCardDir.exists() && externalCardDir.canWrite()) { + return externalCardDir.getPath(); + } // This checks if any of the directories from mExternalStorageDirectories exist, if it does, it uses that one instead for(int i = 0; i < mExternalStorageDirectories.length; i++) { //Log.i("OF", "Checking: " + mExternalStorageDirectories[i]); - SDCardDir = new File(mExternalStorageDirectories[i]); + File SDCardDir = new File(mExternalStorageDirectories[i]); if(SDCardDir.exists() && SDCardDir.canWrite()) { externalPath = mExternalStorageDirectories[i]; // Found writable location break; @@ -116,7 +279,7 @@ public static String getOldExternalStorageDirectory(String packageName) //Log.i("OF", "Checking: " + mExternalStorageDirectories[i]); SDCardDir = new File(mExternalStorageDirectories[i]); if(SDCardDir.exists() && SDCardDir.canWrite()) { - externalPath = mExternalStorageDirectories[i]; // Found writable location + externalPath = mExternalStorageDirectories[i] + "/Android/data/"+packageName; // Found writable location break; } } @@ -125,6 +288,37 @@ public static String getOldExternalStorageDirectory(String packageName) return externalPath + "/Android/data/"+packageName; } + public static void moveOldDataFrom(String fromFolder, String dst){ + + // This checks if any of the directories from mExternalStorageDirectories exist, if it does, it uses that one instead + for(int i = 0; i < mExternalStorageDirectories.length; i++) + { + //Log.i("OF", "Checking: " + mExternalStorageDirectories[i]); + try { + File SDCardDir = new File(mExternalStorageDirectories[i]); + if (SDCardDir.exists()) { // sd cart mount location exists could have been used + File appDataDir = new File(SDCardDir.getPath() + "/Android/data/" + packageName + fromFolder); + if (appDataDir.exists() && appDataDir.canWrite()) { + String externalPath = appDataDir.getPath(); // Found writable location + File dstFile = new File(dst); + if (appDataDir.equals(dstFile)) { + Log.i("OF", "moveOldData appDataDir same as new location:" + appDataDir.getPath() + " newLocation:" + dst); + continue; + } + if (appDataDir.isDirectory() && appDataDir.listFiles().length > 1) { + Log.i("OF", "moveOldData from:" + appDataDir.getPath() + " to:" + dst); + moveOldData(appDataDir.getPath(), dst); + } + } else { + Log.i("OF", "SDCardDir found however no app directory so skipping for" + SDCardDir.getPath()); + } + } + } catch(Exception ex) { + + } + } + } + public static void moveOldData(String src, String dst){ File srcFile = new File(src); File dstFile = new File(dst); @@ -132,11 +326,14 @@ public static void moveOldData(String src, String dst){ if(srcFile.equals(dstFile)) return; if(srcFile.isDirectory() && srcFile.listFiles().length>1){ + Log.i("OF", "moveOldData " + srcFile.getName()); for(File f: srcFile.listFiles()){ if(f.equals(dstFile)){ + Log.i("OF", "movingOldData " + f.getName() + " equals" + dstFile.getPath()); moveOldData(f.getAbsolutePath(),dst+"/"+f.getName()); continue; } + Log.i("OF", "movingOldData " + f.getName()); f.renameTo(new File(dst+"/"+f.getName())); } } @@ -163,18 +360,19 @@ static void runOnMainThread(Runnable runnable) static void runOnGLThread(Runnable runnable) { - OFAndroidLifeCycle.getGLView().queueEvent(runnable); + if(OFAndroidLifeCycle.getGLView() != null) + OFAndroidLifeCycle.getGLView().queueEvent(runnable); } - static void reportPrecentage(float precent) + public static void reportPrecentage(float precent) { Activity activity = OFAndroidLifeCycle.getActivity(); if(activity != null && OFActivity.class.isInstance(activity)) ((OFActivity)activity).onLoadPercent(precent); } - static void fatalErrorDialog(final Activity activity, final String msg){ + public static void fatalErrorDialog(final Activity activity, final String msg){ activity.runOnUiThread(new Runnable(){ public void run() { new AlertDialog.Builder(activity) @@ -351,9 +549,27 @@ public void onReceive(Context context, Intent intent) { } static public void launchBrowser(String url){ - OFAndroidLifeCycle.getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); + + if (!url.startsWith("http") && !url.startsWith("https")) { // fix crash due to missing http/https + url = "https" + url; //force https if missing, it's 2021 + } + try { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.addCategory(Intent.CATEGORY_BROWSABLE); + //intent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + + Log.v("OF", "launchBrowser: " + url); + + Intent.createChooser(intent, "Choose browser"); + intent.setData(Uri.parse(url)); + //OFAndroidLifeCycle.getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); + OFAndroidLifeCycle.getActivity().startActivity(intent); + } catch (Exception ex) { + Log.w("launchBrowser", "Intent to Launch Browser Failed. likely no browser for handling Exception:" + ex.getMessage()); + } } - + static Map progressDialogs = new HashMap(); static int lastProgressID=0; @@ -423,12 +639,17 @@ public static void onActivityResult(int requestCode, int resultCode,Intent inten public static native void resize(int w, int h); public static native void render(); public static native void exit(); + public static native void setAssetManager(AssetManager assetManager); + public static native boolean isWindowReady(); public static native void onTouchDown(int id,float x,float y,float pressure,float majoraxis,float minoraxis,float angle); public static native void onTouchDoubleTap(int id,float x,float y,float pressure); public static native void onTouchUp(int id,float x,float y,float pressure,float majoraxis,float minoraxis,float angle); public static native void onTouchMoved(int id,float x,float y,float pressure,float majoraxis,float minoraxis,float angle); public static native void onTouchCancelled(int id,float x,float y); + + + public static native void onAxisMoved(int id, int deviceid, int productid, float x, float y); public static native void onSwipe(int id, int swipeDir); @@ -450,6 +671,13 @@ public static void onActivityResult(int requestCode, int resultCode,Intent inten public static native void deviceOrientationChanged(int orientation); + public static native void deviceHighestRefreshRate(int refreshRate); + public static native void deviceRefreshRate(int refreshRate); + + public static native void setSampleSize(int samples); + + public static native void setMultiWindowMode(boolean multiWindow); + // static methods to be called from OF c++ code public static void setFullscreen(boolean fs){ //ofActivity.requestWindowFeature(Window.FEATURE_NO_TITLE); @@ -779,36 +1007,61 @@ public void run() { }); } } + + public static void updateRefreshRates(){ + runOnMainThread(new Runnable() { + @Override + public void run() { + try{ + OFAndroidLifeCycle.getActivity().DetermineDisplayConfiguration(true); + }catch(Exception e){ + + } + } + }); + } public static String getRandomUUID(){ return UUID.randomUUID().toString(); } + public static boolean isApplicationSetup(){ + if(OFAndroidLifeCycle.getGLView() == null) return false; return OFAndroidLifeCycle.getGLView().isSetup(); } private static OFAndroidAccelerometer accelerometer; private static OFAndroidGPS gps; - private static OFGestureListener gestureListener; + public static OFGestureListener gestureListener; private static OFOrientationListener orientationListener; private static String dataPath; - public static boolean unpackingDone; + public static boolean unpackingDone = false; + + public static boolean wideGamut = false; + public static boolean hdrScreen = false; - public static native boolean hasNeon(); - public static void disableTouchEvents(){ OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); - glView.setOnClickListener(null); - glView.setOnTouchListener(null); + if(glView != null) { + glView.setOnClickListener(null); + glView.setOnTouchListener(null); + if(gestureListener != null) gestureListener.enableTouchEvents = false; + } + gestureListener = null; } public static void enableTouchEvents(){ OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); - if(gestureListener == null) - gestureListener = new OFGestureListener(OFAndroidLifeCycle.getActivity()); - glView.setOnClickListener(gestureListener); - glView.setOnTouchListener(gestureListener.touchListener); + if(glView != null) { + if (gestureListener == null) + gestureListener = new OFGestureListener(OFAndroidLifeCycle.getActivity()); + glView.setOnClickListener(gestureListener); + gestureListener.enableTouchEvents = true; + + } else { + Log.w( "OF", "enableTouchEvents GLView is null"); + } } public static void enableOrientationChangeEvents(){ @@ -826,6 +1079,8 @@ public static void setupGL(int version, boolean preserveContextOnPause){ final int finalversion = version; final boolean finalPreserveContextOnPause = preserveContextOnPause; final Semaphore mutex = new Semaphore( 0 ); + + OFAndroid.eglVersion = finalversion; runOnMainThread(new Runnable() { @Override @@ -846,23 +1101,56 @@ public void run() { /** * * @param keyCode - * @param event + * @param keyCodeSource * @return true to say we handled this, false to tell Android to handle it */ + + public static boolean keyDown(int keyCode, int keyCodeSource) { + int unicodeChar = keyCodeSource; + if(unicodeChar == 0 && keyCode < 714 && keyCode > 0) { + unicodeChar = keyCode; + if(OFActivity.LOG_INPUT) Log.i( "OF", "keyDown :" + keyCode + " unicodeChar:" + unicodeChar); + return onKeyDown(keyCode, unicodeChar); + } else { + if(OFActivity.LOG_INPUT) Log.i( "OF", "keyDown :" + keyCode + " unicodeChar:" + unicodeChar); + return onKeyDown(keyCode, unicodeChar); + } + } + + public static boolean keyUp(int keyCode, int keyCodeSource) { + int unicodeChar = keyCodeSource; + if(unicodeChar == 0 && keyCode < 714 && keyCode > 0) { + unicodeChar = keyCode; + if(OFActivity.LOG_INPUT) Log.i( "OF", "keyUp :" + keyCode + " unicodeChar:" + unicodeChar); + return onKeyUp(keyCode, unicodeChar); + } else { + if(OFActivity.LOG_INPUT) Log.i( "OF", "keyUp :" + keyCode + " unicodeChar:" + unicodeChar); + return onKeyUp(keyCode, unicodeChar); + } + } + public static boolean keyDown(int keyCode, KeyEvent event) { - if ((keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)) { + if ((event.getKeyCode() == KeyEvent.KEYCODE_BACK || event.getKeyCode() == KeyEvent.KEYCODE_MENU || event.getKeyCode() == KeyEvent.KEYCODE_BUTTON_MODE) && event.getRepeatCount() == 0) { if( onBackPressed() ) { return true; } else { - // let the Android system handle the back button return false; } } + if((event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP || (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN)) || (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_MUTE) || (event.getKeyCode() == KeyEvent.KEYCODE_FOCUS) || event.getKeyCode() == KeyEvent.KEYCODE_CAMERA || event.getKeyCode() == 287) return false; + if((keyCode == KeyEvent.KEYCODE_VOLUME_UP || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) || (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) || (keyCode == KeyEvent.KEYCODE_FOCUS) || keyCode == KeyEvent.KEYCODE_CAMERA || keyCode == 287) return false; + + int unicodeChar = event.getUnicodeChar(); - if(unicodeChar == 0 && keyCode < 256 && keyCode > 0) { + if(unicodeChar == 0 && keyCode < 714 && keyCode > 0) { unicodeChar = keyCode; + if(OFActivity.LOG_INPUT) Log.i( "OF", "keyDown :" + keyCode + " unicodeChar:" + unicodeChar + " sourceID:" + event.getSource()); + return onKeyDown(keyCode, unicodeChar); + } else { + if(OFActivity.LOG_INPUT) Log.i( "OF", "keyDown :" + keyCode + " unicodeChar:" + unicodeChar + " sourceID:" + event.getSource()); + return onKeyDown(keyCode, unicodeChar); } - return onKeyDown(keyCode, unicodeChar); + } /** @@ -872,11 +1160,23 @@ public static boolean keyDown(int keyCode, KeyEvent event) { * @return true to say we handled this, false to tell Android to handle it */ public static boolean keyUp(int keyCode, KeyEvent event) { + if ((event.getKeyCode() == KeyEvent.KEYCODE_BACK || event.getKeyCode() == KeyEvent.KEYCODE_MENU || event.getKeyCode() == KeyEvent.KEYCODE_BUTTON_MODE) && event.getRepeatCount() == 0) { + return true; // handled event + } + if((event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP || (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN)) || (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_MUTE) || (event.getKeyCode() == KeyEvent.KEYCODE_FOCUS) || event.getKeyCode() == KeyEvent.KEYCODE_CAMERA || event.getKeyCode() == 287) return false; + if((keyCode == KeyEvent.KEYCODE_VOLUME_UP || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) || (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) || (keyCode == KeyEvent.KEYCODE_FOCUS) || keyCode == KeyEvent.KEYCODE_CAMERA || keyCode == 287) return false; + + int unicodeChar = event.getUnicodeChar(); - if(unicodeChar == 0 && keyCode < 256 && keyCode > 0) { + //toast("keyUp:" + keyCode); + if(unicodeChar == 0 && keyCode < 714 && keyCode > 0) { unicodeChar = keyCode; + if(OFActivity.LOG_INPUT) Log.i( "OF", "keyUp :" + keyCode + " unicodeChar:" + unicodeChar + " sourceID:" + event.getSource()); + return onKeyUp(keyCode, unicodeChar); + } else { + if(OFActivity.LOG_INPUT) Log.i( "OF", "keyUp :" + keyCode + " unicodeChar:" + unicodeChar + " sourceID:" + event.getSource()); + return onKeyUp(keyCode, unicodeChar); } - return onKeyUp(keyCode, unicodeChar); } diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidAccelerometer.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidAccelerometer.java similarity index 98% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidAccelerometer.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFAndroidAccelerometer.java index 8618f50f4b4..fd3c26ecd0e 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidAccelerometer.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidAccelerometer.java @@ -11,7 +11,9 @@ import android.view.Display; import android.view.Surface; import android.view.WindowManager; +import androidx.annotation.Keep; +@Keep public class OFAndroidAccelerometer extends OFAndroidObject { private SensorManager sensorManager; private Sensor accelerometer; diff --git a/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidController.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidController.java new file mode 100644 index 00000000000..cfc7459b2a2 --- /dev/null +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidController.java @@ -0,0 +1,464 @@ +package cc.openframeworks; + +import android.util.Log; +import android.view.InputDevice; +import android.view.InputEvent; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import java.util.ArrayList; + +public class OFAndroidController { + + public static final String PS5_Controller_NAME = "Sony Interactive Entertainment Wireless Controller"; + public static final String PS5_Controller_NAME_GENERIC = "Wireless Controller"; + public static final String PS4_Controller_NAME = "Sony Interactive Entertainment Wireless Controller Touchpad"; + public static final String XBOX_Controller_NAME = "Microsoft X-Box One pad (Firmware 2015)"; + public static final String STEAM_Controller_NAME = "Valve Software Wired Controller"; + public static final String NINTENDO_Controller_NAME = "Nintendo Wired Controller"; + + + public static final int VendorERROR = 0; + public static final int VendorPS = 1356; + public static final int VendorMS = 1118; + public static final int VendorNS = 1406; + public static final int VendorValve = 10462; + + public static final int ProductID_PS5 = 3302; + public static final int ProductID_PS4 = 2508; + public static final int ProductID_PS4_2 = 1476; + public static final int ProductID_XBOX = 765; + public static final int ProductID_STEAM = 4354; + + public enum ControllerType { + NOT_SET, + NONE, + ACTION_DPAD, + ACTION_X, + ACTION_A, + ACTION_B + } + + public enum Keys { + KEYCODE_BUTTON_A, + KEYCODE_BUTTON_B, + KEYCODE_BUTTON_C, + KEYCODE_BUTTON_Y, + KEYCODE_BUTTON_X, + KEYCODE_BUTTON_Z, + KEYCODE_BUTTON_L1, + KEYCODE_BUTTON_R1, + KEYCODE_BUTTON_L2, + KEYCODE_BUTTON_R2, + KEYCODE_DPAD_UP, + KEYCODE_DPAD_LEFT, + KEYCODE_DPAD_RIGHT, + KEYCODE_DPAD_DOWN, + KEYCODE_DPAD_CENTER + + } + + public static ControllerType getControllerType(InputDevice device) { + + + if(OFActivity.LOG_INPUT) Log.i( "OF", "getControllerType number:" + device.getControllerNumber() + + + " vendorid:" + device.getVendorId() + + " descriptor:" + device.getDescriptor() + " name:" + device.getName()); + + int[] keyMap = new int[15]; + keyMap[0] = (int)KeyEvent.KEYCODE_BUTTON_A; + keyMap[1] = (int)KeyEvent.KEYCODE_BUTTON_B; + keyMap[2] = (int)KeyEvent.KEYCODE_BUTTON_C; + keyMap[3] = (int)KeyEvent.KEYCODE_BUTTON_Y; + + keyMap[4] = (int)KeyEvent.KEYCODE_BUTTON_X; + keyMap[5] = (int)KeyEvent.KEYCODE_BUTTON_Z; + + keyMap[6] = (int)KeyEvent.KEYCODE_BUTTON_L1; + keyMap[7] = (int)KeyEvent.KEYCODE_BUTTON_R1; + keyMap[8] = (int)KeyEvent.KEYCODE_BUTTON_L2; + keyMap[9] = (int)KeyEvent.KEYCODE_BUTTON_R2; + + keyMap[10] = (int)KeyEvent.KEYCODE_DPAD_UP; + keyMap[11] = (int)KeyEvent.KEYCODE_DPAD_LEFT; + keyMap[12] = (int)KeyEvent.KEYCODE_DPAD_RIGHT; + keyMap[13] = (int)KeyEvent.KEYCODE_DPAD_DOWN; + keyMap[14] = (int) KeyEvent.KEYCODE_DPAD_CENTER; + + + boolean[] hasMap = device.hasKeys(keyMap); + + if(device.getVendorId() == 0 && device.getProductId() == 0 ) { + return ControllerType.ACTION_X; + } + if(device.getVendorId() == VendorPS) { + return ControllerType.ACTION_X; + }else if(device.getVendorId() == VendorNS) { + return ControllerType.ACTION_B; + } else { + return ControllerType.ACTION_A; + } + +// if(!hasMap[0] && // A +// hasMap[1] && // B +// hasMap[4] && // X // Y +// hasMap[3]) { +// return ControllerType.ACTION_A; +// } + + } + + final static int UP = 0; + final static int LEFT = 1; + final static int RIGHT = 2; + final static int DOWN = 3; + final static int CENTER = 4; + + + public int getDirectionPressed(InputEvent event) { + if (!isDpadDevice(event)) { + return -1; + } + + // If the input event is a MotionEvent, check its hat axis values. + if (event instanceof MotionEvent) { + + // Use the hat axis value to find the D-pad direction + MotionEvent motionEvent = (MotionEvent) event; + float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X); + float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y); + + // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad + // LEFT and RIGHT direction accordingly. + if (Float.compare(xaxis, -1.0f) == 0) { + directionPressed = OFAndroidController.LEFT; + } else if (Float.compare(xaxis, 1.0f) == 0) { + directionPressed = OFAndroidController.RIGHT; + } + // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad + // UP and DOWN direction accordingly. + else if (Float.compare(yaxis, -1.0f) == 0) { + directionPressed = OFAndroidController.UP; + } else if (Float.compare(yaxis, 1.0f) == 0) { + directionPressed = OFAndroidController.DOWN; + } + } + // If the input event is a KeyEvent, check its key code. + else if (event instanceof KeyEvent) { + + // Use the key code to find the D-pad direction. + KeyEvent keyEvent = (KeyEvent) event; + if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) { + directionPressed = OFAndroidController.LEFT; + } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) { + directionPressed = OFAndroidController.RIGHT; + } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) { + directionPressed = OFAndroidController.UP; + } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) { + directionPressed = OFAndroidController.DOWN; + } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) { + directionPressed = OFAndroidController.CENTER; + } + } + return directionPressed; + } + + public static boolean isDpadDevice(InputEvent event) { + // Check that input comes from a device with directional pads. + if ((event.getSource() & InputDevice.SOURCE_DPAD) + != InputDevice.SOURCE_DPAD) { + return true; + } else { + return false; + } + } + + public static int CONTROLLER_OFFSET = 400; + + public static boolean isActionKey(int keyCode) { + // Here we treat Button_A and DPAD_CENTER as the primary action + // keys for the game. + return keyCode == KeyEvent.KEYCODE_DPAD_CENTER + || keyCode == KeyEvent.KEYCODE_BUTTON_A; + } + + public static boolean isControllerBackKey(int keyCode) { + // Here we treat Button_A and DPAD_CENTER as the primary action + // keys for the game. + return keyCode == KeyEvent.KEYCODE_DPAD_CENTER + || keyCode == KeyEvent.KEYCODE_BUTTON_A; + } + + public static float getCenteredAxis(MotionEvent event, + InputDevice device, int axis, int historyPos) { + final InputDevice.MotionRange range = + device.getMotionRange(axis, event.getSource()); + + // A joystick at rest does not always report an absolute position of + // (0,0). Use the getFlat() method to determine the range of values + // bounding the joystick axis center. + if (range != null) { + final float flat = range.getFlat(); + final float value = + historyPos < 0 ? event.getAxisValue(axis): + event.getHistoricalAxisValue(axis, historyPos); + + // Ignore axis values that are within the 'flat' region of the + // joystick axis center. + if (Math.abs(value) > flat) { + return value; + } + } + return 0; + } + + public static void processJoystickInput(MotionEvent event, + int historyPos) { + + InputDevice inputDevice = event.getDevice(); + + // Calculate the horizontal distance to move by + // using the input value from one of these physical controls: + // the left control stick, hat axis, or the right control stick. + float x = getCenteredAxis(event, inputDevice, + MotionEvent.AXIS_X, historyPos); + if (x == 0) { + x = getCenteredAxis(event, inputDevice, + MotionEvent.AXIS_HAT_X, historyPos); + } + if (x == 0) { + x = getCenteredAxis(event, inputDevice, + MotionEvent.AXIS_Z, historyPos); + } + + // Calculate the vertical distance to move by + // using the input value from one of these physical controls: + // the left control stick, hat switch, or the right control stick. + float y = getCenteredAxis(event, inputDevice, + MotionEvent.AXIS_Y, historyPos); + if (y == 0) { + y = getCenteredAxis(event, inputDevice, + MotionEvent.AXIS_HAT_Y, historyPos); + } + if (y == 0) { + y = getCenteredAxis(event, inputDevice, + MotionEvent.AXIS_RZ, historyPos); + } + if(OFActivity.LOG_INPUT) + Log.i("OF", "processJoystickInput: " + " x:" + x + " y::" + y); + OFAndroid.onAxisMoved(inputDevice.getId(), event.getDeviceId(), inputDevice.getProductId(), x, y); + } + + + final static int DPAD_UP = 0; + final static int DPAD_LEFT = 1; + final static int DPAD_RIGHT = 2; + final static int DPAD_DOWN = 3; + final static int DPAD_CENTER = 4; + static int directionPressed = -1; + static int keyCode = -1; + static int lastKeyCode = -1; + static int deviceCode = -1; + + static boolean DPAD_UP_DOWN = false; + static boolean DPAD_LEFT_DOWN = false; + static boolean DPAD_RIGHT_DOWN = false; + static boolean DPAD_DOWN_DOWN = false; + static boolean DPAD_CENTER_DOWN = false; + + public static boolean genericMotionEvent (MotionEvent event){ + if(OFActivity.LOG_INPUT) Log.i("OF", "dispatchGenericMotionEvent" + " event:" + event.toString() + " deviceId:" + event.getDeviceId()); + + if(deviceCode == -1) + deviceCode = event.getDeviceId(); + + if (OFAndroidController.isDpadDevice(event)) { + return false; +// int press = dpad.getDirectionPressed(event); +// int action = event.getAction(); +// switch (press) { +// case Dpad.LEFT: +// if (event.getActionMasked() == MotionEvent.ACTION_MOVE || event.getActionMasked() == MotionEvent.ACTION_BUTTON_PRESS || event.getActionMasked() == MotionEvent.ACTION_DOWN) { +// return OFAndroid.keyDown(KeyEvent.KEYCODE_DPAD_LEFT + CONTROLLER_OFFSET, KeyEvent.KEYCODE_DPAD_LEFT); +// } +// else if (event.getActionMasked() == MotionEvent.ACTION_BUTTON_RELEASE || event.getActionMasked() == MotionEvent.ACTION_CANCEL || event.getActionMasked() == MotionEvent.ACTION_UP) { +// return OFAndroid.keyUp(KeyEvent.KEYCODE_DPAD_LEFT + CONTROLLER_OFFSET, KeyEvent.KEYCODE_DPAD_LEFT); +// } +// return true; +// case Dpad.RIGHT: +// if (event.getActionMasked() == MotionEvent.ACTION_MOVE || event.getActionMasked() == MotionEvent.ACTION_BUTTON_PRESS || event.getActionMasked() == MotionEvent.ACTION_DOWN) { +// return OFAndroid.keyDown(KeyEvent.KEYCODE_DPAD_RIGHT + CONTROLLER_OFFSET, KeyEvent.KEYCODE_DPAD_RIGHT); +// } +// else if (event.getActionMasked() == MotionEvent.ACTION_BUTTON_RELEASE || event.getActionMasked() == MotionEvent.ACTION_CANCEL || event.getActionMasked() == MotionEvent.ACTION_UP) { +// return OFAndroid.keyUp(KeyEvent.KEYCODE_DPAD_RIGHT + CONTROLLER_OFFSET, KeyEvent.KEYCODE_DPAD_RIGHT); +// } +// return true; +// case Dpad.UP: +// if (event.getActionMasked() == MotionEvent.ACTION_MOVE || event.getActionMasked() == MotionEvent.ACTION_BUTTON_PRESS || event.getActionMasked() == MotionEvent.ACTION_DOWN) { +// return OFAndroid.keyDown(KeyEvent.KEYCODE_DPAD_UP + CONTROLLER_OFFSET, KeyEvent.KEYCODE_DPAD_UP); +// } +// else if (event.getActionMasked() == MotionEvent.ACTION_BUTTON_RELEASE || event.getActionMasked() == MotionEvent.ACTION_CANCEL || event.getActionMasked() == MotionEvent.ACTION_UP) { +// return OFAndroid.keyUp(KeyEvent.KEYCODE_DPAD_UP + CONTROLLER_OFFSET, KeyEvent.KEYCODE_DPAD_UP); +// } +// case Dpad.DOWN: +// if (event.getActionMasked() == MotionEvent.ACTION_MOVE || event.getActionMasked() == MotionEvent.ACTION_BUTTON_PRESS || event.getActionMasked() == MotionEvent.ACTION_DOWN) { +// return OFAndroid.keyDown(KeyEvent.KEYCODE_DPAD_DOWN + CONTROLLER_OFFSET, KeyEvent.KEYCODE_DPAD_DOWN); +// } +// else if (event.getActionMasked() == MotionEvent.ACTION_BUTTON_RELEASE || event.getActionMasked() == MotionEvent.ACTION_CANCEL || event.getActionMasked() == MotionEvent.ACTION_UP) { +// return OFAndroid.keyUp(KeyEvent.KEYCODE_DPAD_DOWN + CONTROLLER_OFFSET, KeyEvent.KEYCODE_DPAD_DOWN); +// } +// return true; +// +// } + } + //if(event.getDeviceId() != deviceCode) return true; + try { + if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == + InputDevice.SOURCE_JOYSTICK && + event.getAction() == MotionEvent.ACTION_MOVE) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + // process the joystick movement... + final int historySize = event.getHistorySize(); + // Process the movements starting from the + // earliest historical position in the batch + for (int i = 0; i < historySize; i++) { + // Process the event at historical position i + OFAndroidController.processJoystickInput(event, i); + } + OFAndroidController.processJoystickInput(event, -1); + return true; + } + + } + if ((event.getSource() & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || + (event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD || + (event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || + (event.getSource() & InputDevice.SOURCE_CLASS_BUTTON) == InputDevice.SOURCE_CLASS_BUTTON || + (event.getSource() & InputDevice.SOURCE_DPAD) > InputDevice.SOURCE_DPAD - 13 && (event.getSource() & InputDevice.SOURCE_DPAD) < InputDevice.SOURCE_GAMEPAD + 500 + ) { + // If the input event is a MotionEvent, check its hat axis values. + directionPressed = -1; +// if ((InputEvent) event instanceof KeyEvent) { // If the input event is a KeyEvent, check its key code. +// +// // Use the key code to find the D-pad direction. +// KeyEvent keyEvent = (KeyEvent) (InputEvent) event; +// boolean isKeyDown = event.getActionMasked() == MotionEvent.ACTION_MOVE || event.getActionMasked() == MotionEvent.ACTION_BUTTON_PRESS; +// if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) { +// directionPressed = DPAD_LEFT; +// keyCode = KeyEvent.KEYCODE_DPAD_LEFT; +// DPAD_LEFT_DOWN = isKeyDown; +// } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) { +// directionPressed = DPAD_RIGHT; +// keyCode = KeyEvent.KEYCODE_DPAD_RIGHT; +// DPAD_RIGHT_DOWN = isKeyDown; +// } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) { +// directionPressed = DPAD_UP; +// keyCode = KeyEvent.KEYCODE_DPAD_UP; +// DPAD_UP_DOWN = isKeyDown; +// } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) { +// directionPressed = DPAD_DOWN; +// keyCode = KeyEvent.KEYCODE_DPAD_DOWN; +// DPAD_DOWN_DOWN = isKeyDown; +// } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) { +// directionPressed = DPAD_CENTER; +// keyCode = KeyEvent.KEYCODE_DPAD_CENTER; +// DPAD_CENTER_DOWN = isKeyDown; +// } +// if (event.getActionMasked() == MotionEvent.ACTION_MOVE || event.getActionMasked() == MotionEvent.ACTION_BUTTON_PRESS) { +// return OFAndroid.keyDown(keyCode + 400, keyCode); +// } +// else if (event.getActionMasked() == MotionEvent.ACTION_BUTTON_RELEASE || event.getActionMasked() == MotionEvent.ACTION_CANCEL) { +// return OFAndroid.keyUp(keyCode + 400, keyCode); +// } +// else { +// return true; +// } +// } else + + if (event instanceof MotionEvent) { + + // Use the hat axis value to find the D-pad direction + MotionEvent motionEvent = (MotionEvent) event; + Log.i("OF", "onGenericMotionEvent motionEvent:" + motionEvent); + float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X); + float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y); + boolean isKeyDown = true; + // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad + // LEFT and RIGHT direction accordingly. + if (Float.compare(xaxis, -1.0f) == 0) { + directionPressed = DPAD_LEFT; + keyCode = KeyEvent.KEYCODE_DPAD_LEFT; + } else if (Float.compare(xaxis, 1.0f) == 0) { + directionPressed = DPAD_RIGHT; + keyCode = KeyEvent.KEYCODE_DPAD_RIGHT; + } + // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad + // UP and DOWN direction accordingly. + else if (Float.compare(yaxis, -1.0f) == 0) { + directionPressed = DPAD_UP; + keyCode = KeyEvent.KEYCODE_DPAD_UP; + } else if (Float.compare(yaxis, 1.0f) == 0) { + directionPressed = DPAD_DOWN; + keyCode = KeyEvent.KEYCODE_DPAD_DOWN; + } else if(Float.compare(xaxis, 0.0f) == 0 && Float.compare(yaxis, 0.0f) == 0) { + boolean value = true; + if(keyCode != -10) + value = OFAndroid.keyUp(keyCode + CONTROLLER_OFFSET, keyCode); + keyCode = -1; lastKeyCode = -1; + return value; + } + if (event.getActionMasked() == MotionEvent.ACTION_MOVE || event.getActionMasked() == MotionEvent.ACTION_BUTTON_PRESS) { + return OFAndroid.keyDown(keyCode + CONTROLLER_OFFSET, keyCode); + } + else if (event.getActionMasked() == MotionEvent.ACTION_BUTTON_RELEASE || event.getActionMasked() == MotionEvent.ACTION_CANCEL) { + boolean value = OFAndroid.keyUp(keyCode + CONTROLLER_OFFSET, keyCode); + keyCode = -1; + return value; + } + else + return true; + + } + } else if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // PS4 Touch Pad + switch (event.getAction()) { + case MotionEvent.ACTION_HOVER_MOVE: + if(OFAndroid.gestureListener != null) return OFAndroid.gestureListener.onTouch(event); + return true; + case MotionEvent.ACTION_SCROLL: + if(OFAndroid.gestureListener != null) return OFAndroid.gestureListener.onScroll(event); + return true; + } + } + } catch(Exception exeception) { + Log.i("OF", "onGenericMotionEvent Exception:" + exeception.getMessage()); + } + return true; + } + + public ArrayList getGameControllerIds() { + ArrayList gameControllerDeviceIds = new ArrayList(); + int[] deviceIds = InputDevice.getDeviceIds(); + for (int deviceId : deviceIds) { + InputDevice dev = InputDevice.getDevice(deviceId); + int sources = dev.getSources(); + + // Verify that the device has gamepad buttons, control sticks, or both. + if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) + || ((sources & InputDevice.SOURCE_JOYSTICK) + == InputDevice.SOURCE_JOYSTICK)) { + // This device is a game controller. Store its device ID. + if (!gameControllerDeviceIds.contains(deviceId)) { + gameControllerDeviceIds.add(deviceId); + } + } + } + return gameControllerDeviceIds; + } + + public static InputDevice getGameControllerForID(int deviceID) { + InputDevice dev = InputDevice.getDevice(deviceID); + return dev; + } + +} diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidGPS.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidGPS.java similarity index 99% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidGPS.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFAndroidGPS.java index 957a69482b7..9fb473eea5b 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidGPS.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidGPS.java @@ -9,7 +9,9 @@ import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; +import androidx.annotation.Keep; +@Keep public class OFAndroidGPS extends OFAndroidObject implements LocationListener, SensorEventListener { private static OFAndroidGPS m_instance = null; diff --git a/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidLifeCycle.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidLifeCycle.java new file mode 100644 index 00000000000..86f61cd98df --- /dev/null +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidLifeCycle.java @@ -0,0 +1,541 @@ +package cc.openframeworks; + +import java.util.ArrayList; +import java.util.Vector; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; + +import android.app.Activity; +import android.media.AudioManager; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.widget.RelativeLayout; + +import static android.opengl.EGL14.EGL_NO_CONTEXT; + +public class OFAndroidLifeCycle +{ + public static Boolean coreLibraryLoaded = false; + public static Boolean appLibraryLoaded = false; + + private static Vector m_statesStack = new Vector(); + private static State m_currentState = null; + private static Semaphore m_semaphor = new Semaphore(1, false); + private static AtomicBoolean m_isWorkerDone = new AtomicBoolean(true); + private static AtomicBoolean m_isInit = new AtomicBoolean(false); + private static AtomicBoolean m_isStateInit = new AtomicBoolean(false); + private static AtomicBoolean m_isSurfaceCreated = new AtomicBoolean(false); + private static AtomicBoolean m_isFirstFrameDrawn = new AtomicBoolean(false); + private static AtomicBoolean m_hasSetup = new AtomicBoolean(false); + private static OFActivity m_activity = null; + + private static int m_countActivities = 0; + private static ArrayList m_initializers = new ArrayList(); + + private static OFGLSurfaceView mGLView = null; + private static OFGLSurfaceView pausedGLView = null; + + private static void pushState(State state) + { + try { + m_semaphor.acquire(); + m_statesStack.add(state); + m_semaphor.release(); + startWorkerThread(); + } + catch (InterruptedException ex) + { + Log.e(OFAndroidLifeCycle.class.getSimpleName(), "pushState exception message: "+ex.getMessage(), ex); + throw new RuntimeException("pushState state: "+ state +" exception message: "+ex.getMessage()); + } + } + + private static boolean isNextStateLegal(State next) + { + boolean isLegal = true; + if(next == null) return false; + if(m_currentState == null) return true; + + switch(next) + { + case init: + if(m_currentState != null) + isLegal = false; + break; + case create: + if(!(m_currentState.equals(State.init)||m_currentState.equals(State.destroy))) + isLegal = false; + break; + case start: + if(!(m_currentState.equals(State.create)||m_currentState.equals(State.stop))) + isLegal = false; + break; + case stop: + if(!(m_currentState.equals(State.start)||m_currentState.equals(State.pause))) + isLegal = false; + break; + case resume: + if(!(m_currentState.equals(State.pause)|| m_currentState.equals(State.start))) + isLegal = false; + break; + case pause: + if(!m_currentState.equals(State.resume)) + isLegal = false; + break; + case destroy: + if(!(m_currentState.equals(State.stop)||m_currentState.equals(State.create))) + isLegal = false; + break; + case exit: + if(!(m_currentState.equals(State.init)||m_currentState.equals(State.destroy))) + isLegal = false; + break; + } + return isLegal; + } + + private static void startWorkerThread() throws IllegalStateException + { + synchronized (m_isWorkerDone) + { + if(!m_isWorkerDone.get()) + return; + m_isWorkerDone.set(false); + } + Thread worker = new Thread(new Runnable() { + + @Override + public void run() + { + try { + m_semaphor.acquire(); + while (!m_statesStack.isEmpty()) { + State next = m_statesStack.firstElement(); + m_statesStack.removeElement(next); + m_semaphor.release(); + if (next != null && !isNextStateLegal(next)) + { + if(m_currentState != null) + Log.e(OFAndroidLifeCycle.class.getSimpleName(), "Illegal next state! when current state " + m_currentState.toString() + " next state: " + next.toString()); + else + Log.e(OFAndroidLifeCycle.class.getSimpleName(), "Illegal next state! when current state null and next state: " + next.toString()); + + //break; + //throw new IllegalStateException("Illegal next state! when current state " + m_currentState.toString() + " next state: " + next.toString()); + } + if(next != null) { + m_currentState = next; + + switch (next) { + case init: + OFAndroidLifeCycleHelper.appInit(m_activity); + coreInitialized(); + break; + case create: + OFAndroidLifeCycleHelper.onCreate(); + break; + case start: + synchronized (m_isSurfaceCreated) { + m_isSurfaceCreated.set(true); + } + OFAndroidLifeCycleHelper.onStart(); + synchronized (m_isSurfaceCreated) { + m_hasSetup.set(true); + } + break; + case stop: + OFAndroidLifeCycleHelper.onStop(); + break; + case pause: + OFAndroidLifeCycleHelper.onPause(); + break; + case resume: + synchronized (m_isSurfaceCreated) { + if (m_hasSetup.get() == true) + OFAndroidLifeCycleHelper.onResume(); + else + Log.e(OFAndroidLifeCycle.class.getSimpleName(), "state:resume hasSetup == false"); + } + break; + case destroy: + OFAndroidLifeCycleHelper.onDestroy(); + break; + case exit: + OFAndroidLifeCycleHelper.exit(); + m_currentState = null; + break; + + default: + break; + } + } + m_semaphor.acquire(); + } + } + catch (InterruptedException ex) + { + Log.e(OFAndroidLifeCycle.class.getSimpleName(), "startWorkerThread: stack size: "+m_statesStack.size() + "exception message: "+ex.getMessage(), ex); + m_semaphor.release(); + } + m_semaphor.release(); + synchronized (m_isWorkerDone) { + m_isWorkerDone.set(true); + } + } + }); + worker.start(); + } + + private static void coreInitialized() + { + synchronized (m_isInit) { + m_isInit.set(true); + } + if(m_activity != null) { + m_activity.runOnUiThread(new Runnable() { + + @Override + public void run() { + for (Runnable init : m_initializers) { + init.run(); + } + m_initializers.clear(); + } + }); + } + } + + public static void HasSetup() { + ViewGroup glContainer = getActivity().getSurfaceContainer(); + if(glContainer != null && pausedGLView != null ) { + if (glContainer.getChildCount() > 0) { + + m_activity.runOnUiThread(new Runnable() { + + @Override + public void run() { + ViewGroup glContainer = getActivity().getSurfaceContainer(); + + //if(pausedGLView != null) + //glContainer.removeView(pausedGLView); + } + }); + } + } + + // ViewGroup glContainer = getActivity().getSurfaceContainer(); + //glContainer.removeAllViews(); +// if(surfaceView != null && pausedGLView == surfaceView) { +// Log.d(TAG, "SetFirstFrameDrawn removing pausedGLView"); +// glContainer.removeView(pausedGLView); +// pausedGLView = null; +// if (mGLView != null) + //glContainer.removeView(pausedGLView); +// if(mGLView != null){ +// glContainer.addView(mGLView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); +// } else { +// Log.d(TAG, "HasSetup removing pausedGLView"); +// pausedGLView = null; +// }} +// }); +// } +// } + //glContainer.removeAllViews(); + //} +// if(mGLView != null) { +// ViewGroup parent = (ViewGroup) mGLView.getParent(); +// if (parent == null) +// glContainer.addView(mGLView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); +// } + //} + } + + public static void SetFirstFrameDrawn() + { + synchronized (m_isFirstFrameDrawn) { + m_isFirstFrameDrawn.set(true); + } + ViewGroup glContainer = getActivity().getSurfaceContainer(); + if(glContainer != null && pausedGLView != null ) { + if (glContainer.getChildCount() > 0) { + + m_activity.runOnUiThread(new Runnable() { + + @Override + public void run() { + + ViewGroup glContainer = getActivity().getSurfaceContainer(); + if(mGLView != null) { + glContainer.bringChildToFront(mGLView); + } + if(pausedGLView != null) + glContainer.removeView(pausedGLView); + + if (glContainer.getChildCount() > 1) { + for(int i=glContainer.getChildCount()-1; i>=0;i--) { + View view = glContainer.getChildAt(i); + if(view != null && view != mGLView) { + glContainer.removeViewAt(i); + Log.w(OFAndroidLifeCycle.class.getSimpleName(), "SetFirstFrameDrawn::Removing Extra View at Index " + i); + } + } + } + if(isSurfaceValid() == false ) { + // Exception whereFrame broken + Log.w(OFAndroidLifeCycle.class.getSimpleName(), "SetFirstFrameDrawn::surface is not valid - Width:0 Height:0 - Recreate"); + glResume(glContainer); + } + } + }); + } + } + } + + static boolean isSurfaceValid() { + if(mGLView != null && + (mGLView.getHeight() >= 1 || mGLView.getWidth() >= 1)) { + return true; + } else { + return false; + } + } + + static OFActivity getActivity(){ + return OFAndroidLifeCycle.m_activity; + } + + static OFGLSurfaceView getGLView(){ + return mGLView; + } + + static void clearGLView(){ + mGLView = null; + } + + public static void setActivity(OFActivity activity){ + m_activity = activity; + activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); + OFAndroidObject.setActivity(activity); + } + +//============================ Life Cycle Functions ===================// + + public static void addPostInit(Runnable runnable) + { + if(isInit()) + runnable.run(); + else + { + m_initializers.add(runnable); + } + } + + public static void clearPostInit(){ + m_initializers.clear(); + } + + public static boolean isInit() + { + synchronized (m_isInit) { + return m_isInit.get(); + } + } + + public static boolean firstFrameDrawn() + { + synchronized (m_isFirstFrameDrawn) { + return m_isFirstFrameDrawn.get(); + } + } + + public static void reset() + { + coreLibraryLoaded = false; + appLibraryLoaded = false; + m_statesStack.clear(); + m_initializers.clear(); + mGLView = null; + pausedGLView = null; + + synchronized (m_isFirstFrameDrawn) { + m_isFirstFrameDrawn.set(false); + } + synchronized (m_isSurfaceCreated) { + m_isSurfaceCreated.set(false); + } + synchronized (m_isStateInit) { + m_isStateInit.set(false); + } + synchronized (m_isFirstFrameDrawn) { + m_isFirstFrameDrawn.set(false); + } + } + + public static boolean isSurfaceCreated() + { + synchronized (m_isSurfaceCreated) { + return m_isSurfaceCreated.get(); + } + } + + public static void init() + { + Log.i("OF","OFAndroid init..."); + + synchronized (m_isStateInit) { + if(m_isStateInit.get() == false) { + m_isStateInit.set(true); + pushState(State.init); + + } + + } + } + + static String TAG = "OF"; + + public static void glCreate() + { + Log.d(TAG, "glCreate"); + if(m_countActivities == 0) + pushState(State.create); + m_countActivities++; + } + + public static void glCreateSurface( boolean preserveContextOnPause ) + { + if(mGLView == null) + { + Log.d(TAG, "Create surface"); + mGLView = new OFGLSurfaceView(m_activity); + + ViewGroup glContainer = getActivity().getSurfaceContainer(); + OFGLSurfaceView glView = getGLView(); + if(glView != null) { + if (preserveContextOnPause) + glView.setPreserveEGLContextOnPause(true); + ViewGroup parent = (ViewGroup) glView.getParent(); + + if(glContainer != null) { + if (glContainer.getChildCount() > 0) { + View view = glContainer.getChildAt(0); + if (pausedGLView == null) + pausedGLView = (OFGLSurfaceView) view; + if (pausedGLView != null) pausedGLView.setDoNotDraw(); + //glContainer.removeAllViews(); + } + if (parent == null) + glContainer.addView(glView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + + if (pausedGLView != null) { + //glContainer.removeView(pausedGLView); // make ontop + //glContainer.addView(pausedGLView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + //LayoutParams top = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + //top.addRule(RelativeLayout.ALIGN_PARENT_TOP); +// RelativeLayout relativePause = (RelativeLayout)pausedGLView; +// pausedGLView.addRule(); + glContainer.bringChildToFront(pausedGLView); + } + } else { + Log.e(TAG, "OFAndroidLifeCycle glCreateSurface glContainer is null"); + } + } + } + } + + public static void glStart() + { + Log.d(TAG, "glStart"); + OFGLSurfaceView glView = getGLView(); + if( glView != null ) { + if(glView.isSetup()) { + glView.onResume(); + } + } + + pushState(State.start); + } + + public static void glStop() + { + Log.d(TAG, "glStop"); + OFGLSurfaceView glView = getGLView(); + if( glView != null ) + glView.onPause(); + + pushState(State.stop); + } + + public static void glRestart() + { + if(OFActivity.LOG_ENGINE) Log.d(TAG, "glRestart"); + } + + public static void glResume(ViewGroup glContainer) + { + if(OFActivity.LOG_ENGINE) Log.d(TAG, "glResume"); + OFGLSurfaceView glView = getGLView(); + boolean offScreenLayoutParamFix = false; + if(glView.getWidth() <= 1|| glView.getHeight() <= 1) { + offScreenLayoutParamFix = true; + Log.d(TAG, "glResume:: offScreenLayoutParamFix required"); + } + if( glView != null && glView.getRenderer() != null && offScreenLayoutParamFix == false) { + + glView.onResume(); + } else { + if( glView != null ) { + glView.onResume(); + } + pausedGLView = mGLView; + clearGLView(); // mGLView = null; + Log.d(TAG, "glResume setGLESVersion"); + OFEGLConfigChooser.setGLESVersion(OFAndroid.eglVersion); + glCreateSurface(true); + } + +// if(mGLView != null) { +// glContainer.removeView(mGLView); +// glContainer.addView(mGLView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); +// } +// if(pausedGLView != null) { +// glContainer.removeView(pausedGLView); +// glContainer.addView(pausedGLView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); +// } + pushState(State.resume); + } + + public static void glPause() + { + if(OFActivity.LOG_ENGINE) Log.d(TAG, "glPause"); + OFGLSurfaceView glView = getGLView(); + if( glView != null ) { + glView.onPause(); + } + OFAndroidLifeCycleHelper.onPause(); + pushState(State.pause); + } + + public static void glDestroy() + { + if(OFActivity.LOG_ENGINE) Log.d(TAG, "glDestroy"); + m_countActivities--; + if(m_countActivities == 0){ + Log.d(TAG, "glDestroy destroy ofApp"); + pushState(State.destroy); + } + + } + + public static void exit() + { + pushState(State.exit); + } + + public enum State + { + init, create, start, stop, destroy, exit, pause, resume; + } +} diff --git a/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidLifeCycleHelper.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidLifeCycleHelper.java new file mode 100644 index 00000000000..402236d9def --- /dev/null +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidLifeCycleHelper.java @@ -0,0 +1,453 @@ +package cc.openframeworks; + +import static cc.openframeworks.OFAndroidObject.activity; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.Locale; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.AssetManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.StatFs; +import android.util.Log; +import androidx.annotation.Keep; + +@Keep +public class OFAndroidLifeCycleHelper +{ + private static final String TAG = OFAndroidLifeCycleHelper.class.getSimpleName(); + private static boolean appInitFlag = false; + private static boolean started; + + private static boolean copyAssets = true; + private static boolean copyOldAssets = true; + private static String copyOldAssetsFolder = ""; + + public static void appInit(Activity activity) + { + if(appInitFlag) + return; + appInitFlag = true; + + + copyAssetsToDataPath(activity); + + OFAndroid.init(); + } + + public static void setCopyAssets(boolean toCopyAssets) { + copyAssets = toCopyAssets; + } + + public static void setCopyOldAssets(boolean toCopyOldAssets, String path) { + copyOldAssets = toCopyOldAssets; + copyOldAssetsFolder = path; + } + + private static void copyAssetsToDataPath(Activity activity) { + OFAndroid.packageName = activity.getPackageName(); + + Log.i(TAG,"starting resources extractor"); + boolean copydata = false; + String[] files = new String[0]; + if(OFAndroid.assetManager == null) + OFAndroid.assetManager = activity.getApplicationContext().getAssets(); + boolean restored = false; + try { + SharedPreferences preferences = activity.getPreferences(Context.MODE_PRIVATE); + + long lastInstalled = preferences.getLong("installed", 0); + restored = preferences.getBoolean("restored", false); + + PackageManager pm = activity.getPackageManager(); + + ApplicationInfo appInfo = pm.getApplicationInfo(OFAndroid.packageName, 0); + + String appFile = appInfo.sourceDir; + long installed = new File(appFile).lastModified(); + if(installed>lastInstalled){ + Editor editor = preferences.edit(); + editor.putLong("installed", installed); + editor.apply(); + copydata = true; + } + files = OFAndroid.assetManager.list(""); + + } catch (NameNotFoundException e1) { + copydata = false; + } catch (IOException e) { + e.printStackTrace(); + } + + if(copyAssets == false) { + copydata = copyAssets; + } + + + OFAndroid.reportPrecentage(.05f); + + String dataPath=""; + try{ + Log.i(TAG, "sd mounted: " + OFAndroid.checkSDCardMounted()); + OFAndroid.initAppDataDirectory(activity); + dataPath = OFAndroid.getAppDataDirectory(); + Log.i(TAG,"creating app directory: " + dataPath); + OFAndroid.setAppDataDir(dataPath); + try{ + File dir = new File(dataPath); + if(!dir.isDirectory()){ + copydata = true; + if(!dir.mkdirs()){ + OFAndroid.fatalErrorDialog(activity, "Error while copying resources to sdcard:\nCouldn't create directory " + dataPath); + Log.e(TAG,"error creating dir " + dataPath); + return; + } + } + } catch(Exception e){ + OFAndroid.fatalErrorDialog(activity, "Error while copying resources to sdcard:\nCouldn't create directory " + dataPath + "\n"+e.getMessage()); + Log.e(TAG,"error creating dir " + dataPath,e); + } + if(copyOldAssets && !restored) { + OFAndroid.moveOldDataFrom(copyOldAssetsFolder, dataPath); + try { + SharedPreferences preferences = activity.getPreferences(Context.MODE_PRIVATE); + Editor editor = preferences.edit(); + editor.putBoolean("restored", true); + editor.apply(); + } catch (Exception ex) { + Log.e(TAG,"Exception saving preferences:" + ex.getMessage()); + } + OFAndroid.reportPrecentage(.10f); + } else { + OFAndroid.reportPrecentage(.10f); + } + + OFAndroid.reportPrecentage(.10f); + } catch(Exception e){ + Log.e(TAG,"couldn't move app resources to data directory " + dataPath,e); + } + + + try { + if(copydata){ + for (String file : files) { + try { + copyAssetFolder( OFAndroid.assetManager, file, dataPath+"/"+file); + } catch (Exception e) { + Log.e("OF", "error copying file", e); + } + + } + + }else{ + OFAndroid.reportPrecentage(.70f); + } + } catch (Exception e) { + Log.e(TAG,"error retrieving app name",e); + } + } + + private static boolean DoNotCopyFile(String file) { + if(file == null || file.startsWith("license") || file.startsWith("device_features") ) + return false; + return true; + } + + private static void copyAssetFolder(AssetManager am, String src, String dest) throws IOException { + + if(OFActivity.LOG_ENGINE) Log.i("Copy ",src); + InputStream srcIS = null; + File destfh; + + // this is the only way we can tell if this is a file or a + // folder - we have to open the asset, and if the open fails, + // it's a folder... + boolean isDir = false; + try { + srcIS = am.open(src); + } catch (FileNotFoundException e) { + isDir = true; + } + + // either way, we'll use the dest as a File + destfh = new File(dest); + + // and now, depending on .. + if(isDir) { + + // If the directory doesn't yet exist, create it + if( !destfh.exists() ){ + destfh.mkdir(); + } + + // list the assets in the directory... + String assets[] = am.list(src); + + // and copy them all using same. + for(String asset : assets) { + copyAssetFolder(am, src + "/" + asset, dest + "/" + asset); + } + + } else { + int count, buffer_len = 2048; + byte[] data = new byte[buffer_len]; + + // copy the file from the assets subsystem to the filesystem + FileOutputStream destOS = new FileOutputStream(destfh); + + //copy the file content in bytes + while( (count = srcIS.read(data, 0, buffer_len)) != -1) { + destOS.write(data, 0, count); + } + + // and close the two files + srcIS.close(); + destOS.close(); + + data = null; + } + destfh = null; + } + + + + public static void onCreate() + { + if(OFActivity.LOG_ENGINE) Log.i(TAG,"onCreate"); + if(OFAndroid.assetManager == null) + OFAndroid.assetManager = activity.getApplicationContext().getAssets(); + OFAndroid.setAssetManager(OFAndroid.assetManager); + OFAndroid.onCreate(); + OFAndroid.onUnpackingResourcesDone(); + OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); + if(OFAndroidLifeCycle.isSurfaceCreated() == false && glView == null){ + Log.i(TAG,"onCreate glView is null or not setup"); + + OFAndroid.setupGL(OFAndroid.eglVersion, true); + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.onStart(); + } + } + + OFAndroid.runOnMainThread(new Runnable() { + @Override + public void run() { + OFAndroid.enableTouchEvents(); + OFAndroid.enableOrientationChangeEvents(); + } + }); + } + + public static void onForceRestart() { + if(OFActivity.LOG_ENGINE) Log.i(TAG,"onForceRestart"); + OFAndroid.setupGL(OFAndroid.eglVersion, true); + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.onStart(); + } + } + + public static void onResume(){ + if(OFActivity.LOG_ENGINE) Log.i(TAG,"onResume"); + + OFAndroid.enableOrientationChangeEvents(); + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.onResume(); + } + OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); + if(OFAndroidLifeCycle.isSurfaceCreated() == true && glView == null){ + Log.w(TAG,"onResume glView is null or not setup"); + OFAndroid.setupGL(OFAndroid.eglVersion, true); + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.onStart(); + } + } + else if( glView.getRenderer() == null){ + Log.w(TAG,"onResume glView is null or not setup"); + OFAndroid.setupGL(OFAndroid.eglVersion, true); + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.onStart(); + } + } + else if( glView != null && glView.getDisplay() == null) { + Log.w(TAG,"onResume glView has a null display"); + OFAndroid.setupGL(OFAndroid.eglVersion, true); + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.onStart(); + } + } + OFAndroid.runOnMainThread(new Runnable() { + @Override + public void run() { + OFAndroid.enableTouchEvents(); + OFAndroid.registerNetworkStateReceiver(); + } + }); + if(OFAndroidLifeCycle.isSurfaceCreated() == true && OFAndroidLifeCycle.isInit()) { + synchronized (OFAndroidObject.ofObjects) { + for (OFAndroidObject object : OFAndroidObject.ofObjects) { + if(object != null) { + object.onResume(); + object.appResume(); + } + } + } + OFAndroid.runOnMainThread(new Runnable() { + @Override + public void run() { + if (OFAndroid.getOrientation() != -1) + OFAndroid.setScreenOrientation(OFAndroid.getOrientation()); + } + }); + } else { + Log.e(TAG,"onResume not ready yet"); + } + } + + public static void onPause(){ + Log.i(TAG,"onPause"); + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.onPause(); + } + OFAndroid.runOnMainThread(new Runnable() { + @Override + public void run() { + OFAndroid.disableTouchEvents(); + OFAndroid.unregisterNetworkStateReceiver(); + synchronized (OFAndroidObject.ofObjects) { + for(OFAndroidObject object : OFAndroidObject.ofObjects){ + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + if (object != null) { + object.onPause(); + } + } + } + } + + } + }); + + } + + public static void onStart(){ + if(OFActivity.LOG_ENGINE) Log.i(TAG,"onStart"); + final OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); + if(started) { + if(glView == null || glView != null && !glView.isSetup()){ + Log.i(TAG,"resume view and native"); + OFAndroid.onStart(); + } + else + return; + } + started = true; + OFAndroid.onStart(); + OFAndroid.runOnMainThread(new Runnable() { + @Override + public void run() { + OFAndroid.registerNetworkStateReceiver(); + OFAndroid.enableTouchEvents(); + OFAndroid.enableOrientationChangeEvents(); + synchronized (OFAndroidObject.ofObjects) { + for(OFAndroidObject object : OFAndroidObject.ofObjects){ + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + if (object != null) { + object.onResume(); + object.appResume(); + } + } + } + + } + } + }); + +// if(OFAndroid.getOrientation()!=-1) { +// Log.i(TAG,"setScreenOrientation " + OFAndroid.getOrientation()); +// OFAndroid.setScreenOrientation(OFAndroid.getOrientation()); +// } else { +// Log.i(TAG,"not setScreenOrientation " + OFAndroid.getOrientation()); +// } + + + } + + public static void onStop(){ + if(OFActivity.LOG_ENGINE) Log.i(TAG,"onStop"); + OFAndroid.runOnMainThread(new Runnable() { + @Override + public void run() { + OFAndroid.disableTouchEvents(); + OFAndroid.unregisterNetworkStateReceiver(); + synchronized (OFAndroidObject.ofObjects) { + for(OFAndroidObject object : OFAndroidObject.ofObjects){ + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + if (object != null) { + object.onPause(); + } + } + } + } + } + }); + + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.onStop(); + } + + OFAndroid.sleepLocked=false; + started = false; + } + + public static void onDestroy(){ + started = false; + if(OFActivity.LOG_ENGINE) Log.i(TAG,"onDestroy"); + OFAndroid.runOnMainThread(new Runnable() { + + @Override + public void run() { + OFAndroid.disableTouchEvents(); + OFAndroid.disableOrientationChangeEvents(); + OFAndroid.unregisterNetworkStateReceiver(); + synchronized (OFAndroidObject.ofObjects) { + for(OFAndroidObject object : OFAndroidObject.ofObjects){ + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + if (object != null) { + object.onStop(); + object.onDestroy(); + } + } + } + } + } + }); + OFAndroid.sleepLocked=false; + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.onStop(); + OFAndroid.onDestroy(); + } + + //OFAndroidWindow.exit(); + OFAndroidLifeCycle.coreLibraryLoaded = false; + } + + public static void exit() + { + if(OFActivity.LOG_ENGINE) Log.i(TAG,"exit"); + + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.exit(); + } + } +} diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidObject.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidObject.java similarity index 89% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidObject.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFAndroidObject.java index 919b067a61e..4812fc6eb5b 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidObject.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidObject.java @@ -5,15 +5,17 @@ import android.app.Activity; import android.content.Intent; +import androidx.annotation.Keep; - +@Keep public abstract class OFAndroidObject { public enum State{ Created, Running, Paused, - Stopped + Stopped, + Destroyed } protected State state; @@ -39,10 +41,17 @@ public void onStop(){ appStop(); state = State.Stopped; } + + public void onDestroy(){ + state = State.Destroyed; + } + + public void release(){ synchronized (OFAndroidObject.ofObjects) { ofObjects.remove(this); } + ofObjects.clear(); } public void onActivityResult(int requestCode, int resultCode,Intent intent){ diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidSoundPlayer.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidSoundPlayer.java similarity index 92% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidSoundPlayer.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFAndroidSoundPlayer.java index bbea4dfcf63..f92e875b50b 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidSoundPlayer.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidSoundPlayer.java @@ -18,8 +18,6 @@ public class OFAndroidSoundPlayer extends OFAndroidObject implements MediaPlayer soundID = -1; streamID = -1; multiPlay = false; - - } public void onDestroy() { @@ -124,11 +122,17 @@ void setVolume(float vol){ // calculates left/right volumes from pan-value (constant panning law) // see: Curtis Roads: Computer Music Tutorial p 460 // thanks to jasch - float angle = pan * 0.7853981633974483f; // in radians from -45. to +45. - float cosAngle = (float) Math.cos(angle); - float sinAngle = (float) Math.sin(angle); - leftVolume = (float)((cosAngle - sinAngle) * 0.7071067811865475) * vol; // multiplied by sqrt(2)/2 - rightVolume = (float)((cosAngle + sinAngle) * 0.7071067811865475) * vol; // multiplied by sqrt(2)/2 + if(Math.signum(pan) != 0) { // mastering this causes issues if not panning - + float angle = pan * 0.7853981633974483f; // in radians from -45. to +45. + float cosAngle = (float) Math.cos(angle); + float sinAngle = (float) Math.sin(angle); + leftVolume = (float) ((cosAngle - sinAngle) * 0.7071067811865475) * vol; // multiplied by sqrt(2)/2 + rightVolume = (float) ((cosAngle + sinAngle) * 0.7071067811865475) * vol; // multiplied by sqrt(2)/2 + } + else { + leftVolume = vol; + rightVolume = vol; + } if(stream){ if(player!=null) player.setVolume(leftVolume, rightVolume); }else if(streamID!=-1){ @@ -294,7 +298,4 @@ public boolean onError(MediaPlayer mp, int what, int extra) { private boolean loop; private float speed; private boolean stream; - int contentType; - - } diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidSoundStream.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidSoundStream.java similarity index 98% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidSoundStream.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFAndroidSoundStream.java index 8e1ab432e7d..2c3f23b6cb5 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidSoundStream.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidSoundStream.java @@ -12,11 +12,13 @@ import android.media.AudioTrack.OnPlaybackPositionUpdateListener; import android.media.MediaRecorder; import android.util.Log; +import androidx.annotation.Keep; // NOTE: the OFAndroidSoundStream class is controlled from the JNI layer (ofxAndroidSoundStream.cpp / h) +@Keep public class OFAndroidSoundStream extends OFAndroidObject implements Runnable, OnRecordPositionUpdateListener, OnPlaybackPositionUpdateListener{ - boolean threadRunning; + boolean threadRunning = false; public OFAndroidSoundStream(){ } @@ -128,7 +130,9 @@ public void appStop(){ } try { - thread.join(); + if (thread!=null) { + thread.join(); + } } catch (InterruptedException e) { Log.e("OF", "error finishing audio thread ", e); } diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoGrabber.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidVideoGrabber.java similarity index 99% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoGrabber.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFAndroidVideoGrabber.java index 66f5157fabd..5873e46ed16 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoGrabber.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidVideoGrabber.java @@ -12,7 +12,9 @@ import android.os.Build; import android.util.Log; import android.view.OrientationEventListener; +import androidx.annotation.Keep; +@Keep public class OFAndroidVideoGrabber extends OFAndroidObject implements Runnable, Camera.PreviewCallback { diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoPlayer.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidVideoPlayer.java similarity index 99% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoPlayer.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFAndroidVideoPlayer.java index c0f496e1b74..a3ca3abd6c4 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidVideoPlayer.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidVideoPlayer.java @@ -11,8 +11,9 @@ import android.util.FloatMath; import android.util.Log; import android.view.Surface; +import androidx.annotation.Keep; - +@Keep @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class OFAndroidVideoPlayer extends OFAndroidObject implements OnFrameAvailableListener { diff --git a/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidWindow.java b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidWindow.java new file mode 100644 index 00000000000..b8e1fdce506 --- /dev/null +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFAndroidWindow.java @@ -0,0 +1,257 @@ +package cc.openframeworks; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; +import javax.microedition.khronos.opengles.GL10; +//import javax.microedition.khronos.egl.EGL15; +//import javax.microedition.khronos.egl.EGL14; +import javax.microedition.khronos.egl.EGL11; +import javax.microedition.khronos.egl.EGL; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.ColorSpace; +import android.graphics.PixelFormat; +import android.opengl.EGL14; +import android.opengl.GLES10; +import android.opengl.GLES20; +import android.opengl.GLSurfaceView; +import android.os.Build; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.WindowManager; + +import static android.opengl.EGL14.EGL_NO_CONTEXT; + +class OFAndroidWindow implements GLSurfaceView.Renderer { + + public OFAndroidWindow(int w, int h){ + if( OFActivity.LOG_ENGINE) Log.i("OF","OFAndroidWindow():width:" + w + " height:" + h); + setResolution(w,h, true); + } + + public void setResolution(int w, int h, boolean updateSurface) { + if( OFActivity.LOG_ENGINE) Log.i("OFAndroidWindow","setResolution:width:" + w + " height:" + h + "update:" + updateSurface); + if(w == this.w && h == this.h && updateSurface == false) return; + + + + this.w = w; + this.h = h; + + if(w != 0 && h != 0 && setup == true){ + resolutionSetup = true; + if(updateSurface) onSurfaceChanged(w,h); + } + } + + public void surfaceHasBeenDestroyed() { + if( OFActivity.LOG_ENGINE) Log.i("OF","surfaceHasBeenDestroyed"); + OFAndroid.onSurfaceDestroyed(); + has_surface = false; + exit(); + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + + if( OFActivity.LOG_ENGINE) Log.i("OF","onSurfaceCreated"); + // notify that old surface was destroyed + boolean hasDestroyed = false; + if(this.has_surface) { + if( OFActivity.LOG_ENGINE) Log.i("OF","onSurfaceCreated - has_surface destroy"); + surfaceHasBeenDestroyed(); + hasDestroyed = true; + } + + // notify that new surface was created + this.has_surface = true; + OFAndroid.onSurfaceCreated(); + Activity activity = OFAndroidLifeCycle.getActivity(); + if(OFActivity.class.isInstance(activity)) { + ((OFActivity) activity).onGLSurfaceCreated(); + } + else { + try { + Log.e("OF", "setup OFActivity.class.is NOT Instance(activity)" + activity.getLocalClassName()); + } catch (Exception e) { + + } + } + + if(hasDestroyed) { + if( OFActivity.LOG_ENGINE) Log.i("OF", "hasDestroyed calling setup"); + setup(); + } + OFAndroid.updateRefreshRates(); + gl.glClearColor(0f, 0f, 0, 1); + return; + } + + @Override + public void onSurfaceChanged(GL10 gl, int w, int h) { + onSurfaceChanged(w,h); + } + + public void onSurfaceChanged(int w, int h) { + + if( OFActivity.LOG_ENGINE) Log.i("OF","onSurfaceChanged width:" + w + " height:" + h); + if(doNotDraw == true) return; // fix for strange case + if(firstFrameDrawn == false) { + Log.i("OF","onSurfaceChanged firstFrameDrawn not drawn"); + //return; + } + setResolution(w,h, false); + if(!setup && OFAndroid.unpackingDone && firstFrameDrawn){ + if( OFActivity.LOG_ENGINE) Log.i("OF","onSurfaceChanged && OFAndroid.unpackingDone"); + setup(); + } else if(!setup && !OFAndroid.unpackingDone && firstFrameDrawn) { + if( OFActivity.LOG_ENGINE) Log.i("OF","onSurfaceChanged not setup however !OFAndroid.unpackingDone"); + setup(); + } else if(setup && OFAndroid.unpackingDone) { + if( OFActivity.LOG_ENGINE) Log.i("OF","onSurfaceChanged setup already"); + } + OFGestureListener.swipe_Min_Distance = (int)(Math.max(w, h)*.04); + OFGestureListener.swipe_Max_Distance = (int)(Math.max(w, h)*.6); + GLES10.glViewport(0, 0, w, h); + OFAndroid.resize(w, h); + } + + private void setup(){ + boolean isContext = true; + if(android.opengl.EGL14.eglGetCurrentContext() == EGL_NO_CONTEXT) { + isContext = false; + } + + if(doNotDraw == true) return; // fix for strange case + if( OFActivity.LOG_ENGINE) Log.i("OF","OFAndroidWindow::setup context:" + isContext); + if(w <= 0 || h <= 0) { + Log.e("OF","setup width or height is <=0. Will cause strange effects"); + } + if(isContext == true) { + OFAndroid.setup(w, h); + setup = true; + } + try { + android.os.Process.setThreadPriority(8); + OFGestureListener.swipe_Min_Distance = (int)(Math.max(w, h)*.04); + OFGestureListener.swipe_Max_Distance = (int)(Math.max(w, h)*.6); + + } catch (Exception e) { + Log.e("OF", "setup OFAndroidWindow setup OFGestureListener:Exception:" + e.getMessage()); + } + + Activity activity = OFAndroidLifeCycle.getActivity(); + if(activity != null) { + try { + ((OFActivity) activity).onGLSurfaceCreated(); + } catch (Exception e) { + Log.e("OF", "setup OFAndroidWindow setup OFGestureListener:Exception:" + e.getMessage()); + } + } + else { + try { + Log.e("OF", "setup OFActivity.class.is NOT Instance(activity)" + activity.getLocalClassName()); + } catch (Exception e) { + + } + } + + OFAndroidLifeCycle.HasSetup(); + + } + + public void exit() { + setup = false; + } + + public void setDoNotDraw() { + doNotDraw = true; + } + + private int drawFrame = 0; + @Override + public void onDrawFrame(GL10 gl) { + drawFrame++; + //Log.i("OF","onDrawFrame" + drawFrame); + // Remove the initial background + if (!initialRender) { + initialRender = true; + drawClear = true; + if( OFActivity.LOG_ENGINE) Log.i("OFAndroidWindow", "onDrawFrame initialRenderFrame!"); + if( OFAndroidLifeCycle.getGLView() != null) + OFAndroidLifeCycle.getGLView().setBackgroundResourceClear(); + } else { + if(isWindowReady == false) + if(OFAndroid.isWindowReady()) isWindowReady = true; + } + if(setup && OFAndroid.unpackingDone && !doNotDraw && isWindowReady){ + if(android.opengl.EGL14.eglGetCurrentContext() != EGL_NO_CONTEXT) { + + if(firstFrameDrawn == false) { + firstFrameDrawn = true; + drawClear = false; + OFAndroidLifeCycle.glStart(); + OFAndroidLifeCycle.SetFirstFrameDrawn(); + // gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); + //gl.glClearColor(0f, 0f, 0f, 0.0f); + if( OFActivity.LOG_ENGINE) Log.i("OFAndroidWindow", "onDrawFrame setup and unpacking done SetFirstFrameDrawn"); + } + OFAndroid.render(); + } + else { + Log.e("OFAndroidWindow", "ofAndroidWindow::onDrawFrame GLContext = EGL_NO_CONTEXT BAD. Restarting Window"); + setup = false; + setup(); + drawClear = true; + } + }else if(doNotDraw){ + drawClear = false; + Log.i("OFAndroidWindow", "onDrawFrame DoNotDraw"); + } else if(isWindowReady == false) { + Log.w("OFAndroidWindow", "ofAndroidWindow::onDrawFrame isWindowReady:" + isWindowReady); + drawClear = true; + } else if(!setup && OFAndroid.unpackingDone){ + Log.i("OFAndroidWindow", "onDrawFrame !setup and unpacking done"); + setup(); + drawClear = true; + }else{ + drawClear = true; + Log.e("OFAndroidWindow", "onDrawFrame draw clear"); + } + if(drawClear) { + Log.e("OFAndroidWindow", "onDrawFrame draw clear"); + gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); + gl.glClear(GL10.GL_COLOR_BUFFER_BIT); + gl.glClearColor(0f, 0f, 0f, 1.0f); + + } + } + + + public boolean isSetup(){ + return setup; + } + + public boolean isResolutionSetup(){ + return resolutionSetup; + } + + private boolean setup = false; + private boolean isWindowReady = false; + private boolean doNotDraw = false; + private boolean resolutionSetup = false; + private boolean initialRender = false; + private boolean firstFrameDrawn = false; + private int w,h = 0; + public boolean has_surface = false; + + private boolean drawClear = false; +} diff --git a/addons/ofxAndroid/Java/cc/openframeworks/OFEGLConfigChooser.java b/addons/ofxAndroid/Java/cc/openframeworks/OFEGLConfigChooser.java new file mode 100644 index 00000000000..f8ce17da285 --- /dev/null +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFEGLConfigChooser.java @@ -0,0 +1,1150 @@ +package cc.openframeworks; + +import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT; +import static android.opengl.EGL15.EGL_OPENGL_ES3_BIT; + +import static javax.microedition.khronos.egl.EGL10.EGL_RENDERABLE_TYPE; + +import android.opengl.GLSurfaceView; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLDisplay; +import android.util.Log; +import javax.microedition.khronos.egl.EGLContext; + +import android.opengl.EGL14; +import android.os.Build; + +import androidx.annotation.Keep; +import androidx.annotation.RequiresApi; + +@Keep +class ContextFactory implements GLSurfaceView.EGLContextFactory { + + private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + + public static int OPENGLES_VERSION = 2; + + public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { + Log.w("OFContextFactory", "creating OpenGL ES context"); + //checkEglError("Before eglCreateContext", egl); + int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, OPENGLES_VERSION, EGL10.EGL_NONE }; + + if(eglConfig == null) { + Log.e("OFContextFactory", "eglConfig is null"); + return null; + } + try { + EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); + return context; + } catch(Exception ex) { + Log.e("OFContextFactory", "egl.eglCreateContext error:" + ex.getMessage()); + } + return null; + } + + + public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { + egl.eglDestroyContext(display, context); + } + + + private static void checkEglError(String prompt, EGL10 egl) { + int error; + while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { + Log.e("OFContextFactory", String.format("%s: EGL error: 0x%x", prompt, error)); + } + } +} + + +@Keep +class OFEGLConfigChooser implements GLSurfaceView.EGLConfigChooser { + + + public OFEGLConfigChooser(int r, int g, int b, int a, int depth, int stencil, int samples, boolean wideGamut) { + mRedSize = r; + mGreenSize = g; + mBlueSize = b; + mAlphaSize = a; + mDepthSize = depth; + mStencilSize = stencil; + mSampleSize = samples; + mWideGamut = wideGamut; + if(mSampleSize > 1) MSAA = true; + } + + public static void setGLESVersion(int version) { + GLES_VERSION = version; + + if (version == 1) { + EGL_OPENGL_ES_BIT = 1; + ContextFactory.OPENGLES_VERSION = 1; + } else if (version == 2) { + EGL_OPENGL_ES_BIT = 4; + ContextFactory.OPENGLES_VERSION = 2; + } +// else if(version==3) { +// EGL_OPENGL_ES_BIT=EGL_OPENGL_ES3_BIT; +// ContextFactory.OPENGLES_VERSION = 3; +// } + } + + public void setWideGamutRGB(){ + mRedSize = 10; + mGreenSize = 10; + mBlueSize = 10; + mAlphaSize = 2; + mDepthSize = 8; + mStencilSize = 1; + mWideGamut = true; + } + + public void setRGB(){ + mWideGamut = false; + } + + public static int getGLESVersion(){ + return GLES_VERSION; + } + + public int getSampleSize(){ + return mSampleSize; + } + + public boolean IsAntiAliasing(){ + return mSampleSize > 1; + } + + public boolean IsWideGamut(){ // es3 / vulkan + return mWideGamut; + } + + + + /* This EGL config specification is used to specify 1.x rendering. + * We use a minimum size of 4 bits for red/green/blue, but will + * perform actual matching in chooseConfig() below. + */ + private static boolean DEBUG = true; + private static boolean MSAA = false; + private static int EGL_OPENGL_ES_BIT = 1; + private static int GLES_VERSION = 1; + + + public static final int EGL_GL_COLORSPACE_KHR = 0x309D; + public static final int EGL_COLOR_COMPONENT_TYPE_EXT = 0x3339; + public static final int EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT = 0x333B; + public static final int EGL_GL_COLORSPACE_BT2020_PQ_EXT = 0x3340; + public static final int EGL_COVERAGE_BUFFERS_NV = 0x30E0; + public static final int EGL_COVERAGE_SAMPLES_NV = 0x30E1; + public static final int EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490; + + public static final int EGL_RENDERBUFFER_SAMPLES_ANGLE = 0x8CAB; + public static final int EGL_MAX_SAMPLES_ANGLE = 0x8D57; + +// private static int[] s_configAttribsMSAA_P3 = +// { +// EGL10.EGL_RED_SIZE, 10, +// EGL10.EGL_GREEN_SIZE, 10, +// EGL10.EGL_BLUE_SIZE, 10, +// EGL10.EGL_DEPTH_SIZE, 8, +// EGL10.EGL_ALPHA_SIZE, 2, +// EGL_COLOR_COMPONENT_TYPE_EXT, +// // Requires that setEGLContextClientVersion(2) is called on the view. +// EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT /* EGL_OPENGL_ES2_BIT */, +// EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */, +// EGL10.EGL_SAMPLES, 4, +// EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT, +// EGL10.EGL_NONE +// }; + + private static final int[] s_configAttribsMSAA16Angle = + { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 16, + // Requires that setEGLContextClientVersion(2) is called on the view. + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT /* EGL_OPENGL_ES2_BIT */, + EGL_MAX_SAMPLES_ANGLE, 4, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsMSAA16 = + { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 16, + // Requires that setEGLContextClientVersion(2) is called on the view. + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */, + EGL10.EGL_SAMPLES, 16, + EGL10.EGL_NONE + }; + + + private static final int[] s_configAttribsMSAA8 = + { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 24, + // Requires that setEGLContextClientVersion(2) is called on the view. + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */, + EGL10.EGL_SAMPLES, 4, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsMSAA = + { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 16, + // Requires that setEGLContextClientVersion(2) is called on the view. + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */, + EGL10.EGL_SAMPLES, 4, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsMSAA4 = + { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 16, + // Requires that setEGLContextClientVersion(2) is called on the view. + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */, + EGL10.EGL_SAMPLES, 4, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsMSAA2 = + { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 16, + // Requires that setEGLContextClientVersion(2) is called on the view. + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */, + EGL10.EGL_SAMPLES, 2, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsNoSample = + { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 24, + // Requires that setEGLContextClientVersion(2) is called on the view. + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsMSAAFallBack = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 24, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL_COVERAGE_BUFFERS_NV, 1 /* true */, + EGL_COVERAGE_SAMPLES_NV, 2, // always 5 in practice on tegra 2 + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsMSAAFallBack2 = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 16, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL_COVERAGE_BUFFERS_NV, 1 /* true */, + EGL_COVERAGE_SAMPLES_NV, 5, // always 5 in practice on tegra 2 + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsDefault8 = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 24, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsDefault8Depth16 = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 16, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsDefault8DepthNone = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_DEPTH_SIZE, 0, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsDefault = { + EGL10.EGL_RED_SIZE, 5, + EGL10.EGL_GREEN_SIZE, 6, + EGL10.EGL_BLUE_SIZE, 5, + EGL10.EGL_DEPTH_SIZE, 0, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_NONE + }; + + private static final int[] s_configAttribsDefaultES = { + EGL10.EGL_RED_SIZE, 5, + EGL10.EGL_GREEN_SIZE, 6, + EGL10.EGL_BLUE_SIZE, 5, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT /* EGL_OPENGL_ES2_BIT */, + EGL10.EGL_NONE + }; + + + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + + try { + Log.i("OF", String.format("eglChooseConfig: DEVICE:" + android.os.Build.DEVICE + " MODEL:"+ Build.MODEL)); + if (android.os.Build.DEVICE.contains("cactus")) { + OFAndroid.samples = 1; + } + } catch (Exception ex) { + + } + + /* Get the number of minimally matching EGL configurations + */ + int[] num_config = new int[1]; + EGLConfig[] configs = null; + num_config[0] = 0; + +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && mWideGamut == true) { +// if (!egl.eglChooseConfig(display, s_configAttribsMSAA, null, 0, +// num_config)) { +// Log.w("OF", String.format("s_configAttribsMSAA_P3 MSAA with P3 failed")); +// } +// } + + boolean workingConfig = false; + boolean tryMSAA = OFAndroid.maxSamples > 1; + int numConfigs = num_config[0]; + + if (!workingConfig) { + setRGB(); + if(tryMSAA && OFAndroid.maxSamples >= 8) { + Log.i("OF", String.format("eglChooseConfig MSAAx8")); + if (tryMSAA && !egl.eglChooseConfig(display, s_configAttribsMSAA8, null, 0, + num_config)) { + Log.w("OF", String.format("eglChooseConfig MSAAx8 failed")); + } + numConfigs = num_config[0]; + if (tryMSAA && OFAndroid.maxSamples >= 8 && numConfigs > 0) { + configs = new EGLConfig[numConfigs]; + try { + if (egl.eglChooseConfig(display, s_configAttribsMSAA8, configs, numConfigs, num_config)) { + numConfigs = num_config[0]; + Log.v("OF", String.format("eglChooseConfig MSAA8 Success")); + EGLConfig testConfig = chooseConfig(egl, display, configs, true); + if(numConfigs > 0 && configs != null && testConfig != null) { + workingConfig = true; + } else { + workingConfig = false; + numConfigs = 0; + } + } else { + workingConfig = false; + numConfigs = 0; + } + + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig MSAAx8 failed with EXCEPTION:") + ex.getMessage()); + } + } + } + if (numConfigs <= 0 || !workingConfig) { + setRGB(); + configs = new EGLConfig[numConfigs]; + try { + if (tryMSAA && OFAndroid.maxSamples >=4 && !egl.eglChooseConfig(display, s_configAttribsMSAA4, null, 0, + num_config)) { + Log.w("OF", String.format("eglChooseConfig MSAA failed")); + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig MSAAx4 failed with EXCEPTION:") + ex.getMessage()); + } + numConfigs = num_config[0]; + if(tryMSAA && OFAndroid.maxSamples >=4 && numConfigs > 0) { + configs = new EGLConfig[numConfigs]; + try { + if (tryMSAA && OFAndroid.maxSamples >=4 && !egl.eglChooseConfig(display, s_configAttribsMSAA4, null, 0, + num_config)) { + Log.w("OF", String.format("eglChooseConfig MSAA failed")); + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig MSAAx4 failed with EXCEPTION:") + ex.getMessage()); + } + numConfigs = num_config[0]; + configs = new EGLConfig[numConfigs]; + try { + if(egl.eglChooseConfig(display, s_configAttribsMSAA4, configs, numConfigs, num_config)){ + numConfigs = num_config[0]; + Log.v("OF", String.format("eglChooseConfig MSAA Success")); + EGLConfig testConfig = chooseConfig(egl, display, configs, true); + if(numConfigs > 0 && configs != null && testConfig != null) { + workingConfig = true; + } else { + workingConfig = false; + numConfigs = 0; + } + } else { + workingConfig = false; + numConfigs = 0; + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig MSAA failed with EXCEPTION:") + ex.getMessage()); + } + } + if (numConfigs <= 0 || !workingConfig) { + configs = new EGLConfig[numConfigs]; + + numConfigs = num_config[0]; + if(tryMSAA && numConfigs > 0) { + configs = new EGLConfig[numConfigs]; + try { + + if(egl.eglChooseConfig(display, s_configAttribsMSAAFallBack, configs, numConfigs, num_config)){ + numConfigs = num_config[0]; + Log.v("OF", String.format("eglChooseConfig MSAA Tegra Success")); + EGLConfig testConfig = chooseConfig(egl, display, configs, true); + if(numConfigs > 0 && configs != null && testConfig != null) { + workingConfig = true; + } else { + workingConfig = false; + numConfigs = 0; + } + } else { + workingConfig = false; + numConfigs = 0; + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig MSAA Fallback failed with EXCEPTION:") + ex.getMessage()); + } + } + if (numConfigs <= 0 && !workingConfig) { + if(tryMSAA) Log.i("OF", String.format("try eglChooseConfig MSAAx4 TEGRA2")); + if (tryMSAA && !egl.eglChooseConfig(display, s_configAttribsMSAAFallBack2, null, 0, + num_config)) { + Log.w("OF", String.format("eglChooseConfig MSAA Fallback failed")); + } + numConfigs = num_config[0]; + if(tryMSAA && numConfigs > 0) { + configs = new EGLConfig[numConfigs]; + try { + if(egl.eglChooseConfig(display, s_configAttribsMSAAFallBack2, configs, numConfigs, num_config)){ + numConfigs = num_config[0]; + EGLConfig testConfig = chooseConfig(egl, display, configs, true); + if(numConfigs > 0 && configs != null && testConfig != null) { + workingConfig = true; + } else { + workingConfig = false; + numConfigs = 0; + } + } else { + workingConfig = false; + numConfigs = 0; + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig MSAA Fallback2 failed with EXCEPTION:") + ex.getMessage()); + } + } + + if (numConfigs <= 0 || !workingConfig) { + mSampleSize = 0; + Log.i("OF", String.format("eglChooseConfig Default8")); + if (!egl.eglChooseConfig(display, s_configAttribsDefault8, null, 0, + num_config)) { + Log.w("OF", String.format("s_configAttribsDefault8 Fallback failed")); + } + numConfigs = num_config[0]; + if(numConfigs > 0) { + int numberConfigurations = numConfigs; + for(int i = 0; i<7; i++) { + switch (i) { + case 0: + mSampleSize = 0; + mAlphaSize = 8; + break; + case 1: + mSampleSize = 0; + mAlphaSize = 8; + mStencilSize = 0; + mDepthSize = 24; + break; + case 2: + mBlueSize = 8; + mRedSize = 8; + mGreenSize = 8; + mStencilSize = 0; + mDepthSize = 16; + break; + case 3: + mBlueSize = 8; + mRedSize = 8; + mGreenSize = 8; + mStencilSize = 8; + mDepthSize = 24; + mAlphaSize = 8; + mSampleSize = OFAndroid.samples; + break; + case 4: + mBlueSize = 8; + mRedSize = 8; + mGreenSize = 8; + mStencilSize = 8; + mDepthSize = 16; + mAlphaSize = 8; + mSampleSize = OFAndroid.samples; + break; + case 5: + mBlueSize = 8; + mRedSize = 8; + mGreenSize = 8; + mStencilSize = 8; + mDepthSize = 8; + mSampleSize = 0; + mAlphaSize = 0; + break; + case 6: + mBlueSize = 8; + mRedSize = 8; + mGreenSize = 8; + mStencilSize = 0; + mDepthSize = 0; + mSampleSize = 0; + mAlphaSize = 0; + break; + case 7: + mBlueSize = 5; + mRedSize = 5; + mGreenSize = 6; + mStencilSize = 8; + mDepthSize = 16; + mAlphaSize = 0; + mSampleSize = OFAndroid.samples; + break; + + } + configs = new EGLConfig[numberConfigurations]; + try { + + if (egl.eglChooseConfig(display, s_configAttribsDefault8, configs, numberConfigurations, num_config)) { + numConfigs = num_config[0]; + EGLConfig testConfig = chooseConfig(egl, display, configs, true); + if(numConfigs > 0 && configs != null && testConfig != null) { + workingConfig = true; + numConfigs = numberConfigurations; + Log.i("OF", String.format("eglChooseConfig Default8 Found on iteration:" + i)); + break; + } else { + workingConfig = false; + numConfigs = 0; + Log.w("OF", String.format("eglChooseConfig Default8 failed to find iteration:" + i)); + } + } else { + workingConfig = false; + numConfigs = 0; + Log.w("OF", String.format("eglChooseConfig Default8 failed to find iteration:" + i)); + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig Default8 failed with EXCEPTION:") + ex.getMessage() +" iteration:" + i); + } + } + } + if (numConfigs <= 0 || !workingConfig) { + numConfigs = num_config[0]; + if (numConfigs > 0) { + configs = new EGLConfig[numConfigs]; + try { + mDepthSize = 16; + mAlphaSize = 0; + if (egl.eglChooseConfig(display, s_configAttribsDefault8Depth16, configs, numConfigs, num_config)) { + numConfigs = num_config[0]; + EGLConfig testConfig = chooseConfig(egl, display, configs, true); + if(numConfigs > 0 && configs != null && testConfig != null) { + workingConfig = true; + } else { + workingConfig = false; + numConfigs = 0; + } + } else { + workingConfig = false; + numConfigs = 0; + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig Default8Depth16 failed with EXCEPTION:") + ex.getMessage()); + } + } + } + if (numConfigs <= 0 || !workingConfig) { + numConfigs = num_config[0]; + if (numConfigs > 0) { + configs = new EGLConfig[numConfigs]; + try { + mDepthSize = 0; + if (egl.eglChooseConfig(display, s_configAttribsDefault8DepthNone, configs, numConfigs, num_config)) { + numConfigs = num_config[0]; + + EGLConfig testConfig = chooseConfig(egl, display, configs, true); + if(numConfigs > 0 && configs != null && testConfig != null) { + workingConfig = true; + } else { + workingConfig = false; + numConfigs = 0; + } + } else { + workingConfig = false; + numConfigs = 0; + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig Default8DepthNone failed with EXCEPTION:") + ex.getMessage()); + } + } + } + if (numConfigs <= 0 || !workingConfig) { + Log.i("OF", String.format("eglChooseConfig Default")); + try { + mBlueSize = 5; + mRedSize = 5; + mGreenSize = 6; + mStencilSize = 1; + mDepthSize = 24; + if (!egl.eglChooseConfig(display, s_configAttribsDefault, null, 0, + num_config)) { + Log.w("OF", String.format("eglChooseConfig Default failed")); + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig s_configAttribsDefault failed with EXCEPTION:") + ex.getMessage()); + } + numConfigs = num_config[0]; + if(numConfigs > 0) { + configs = new EGLConfig[numConfigs]; + try { + mBlueSize = 5; + mRedSize = 5; + mGreenSize = 6; + mStencilSize = 1; + mDepthSize = 0; + if(egl.eglChooseConfig(display, s_configAttribsDefault, configs, numConfigs, num_config)){ + numConfigs = num_config[0]; + EGLConfig testConfig = chooseConfig(egl, display, configs, true); + if(numConfigs > 0 && configs != null && testConfig != null) { + workingConfig = true; + } else { + workingConfig = false; + numConfigs = 0; + } + } else { + workingConfig = false; + numConfigs = 0; + } + } catch (Exception ex) { + numConfigs = 0; + workingConfig = false; + Log.e("OF", String.format("eglChooseConfig s_configAttribsDefault failed with EXCEPTION:") + ex.getMessage()); + } + } + if (numConfigs <= 0 || !workingConfig) { + Log.i("OF", String.format("eglChooseConfig DefaultES")); + try { + if (!egl.eglChooseConfig(display, s_configAttribsDefaultES, null, 0, + num_config)) { + Log.w("OF", String.format("s_configAttribsDefaultES Default failed")); + } + } catch (Exception ex) { + Log.e("OF", String.format("eglChooseConfig s_configAttribsDefaultES failed with EXCEPTION:") + ex.getMessage()); + } + numConfigs = num_config[0]; + if (numConfigs <= 0) { + Log.e("OF", String.format("eglChooseConfig No configs match configSpec")); + throw new IllegalArgumentException("No configs match configSpec"); + } + } + } + } + } + } + } + } + /* Allocate then read the array of minimally matching EGL configs + */ + +// if(configs == null) { +// Log.w("OF", String.format("configs=null eglChooseConfig Default NO MSAA")); +// try { +// if (!egl.eglChooseConfig(display, s_configAttribsNoSample, null, 0, +// num_config)) { +// Log.w("OF", String.format("eglChooseConfig Default failed")); +// } +// } catch (Exception ex) { +// Log.e("OF", String.format("eglChooseConfig s_configAttribsNoSample failed with EXCEPTION:") + ex.getMessage()); +// } +// numConfigs = num_config[0]; +// if(numConfigs > 0) { +// configs = new EGLConfig[numConfigs]; +// try { +// if(egl.eglChooseConfig(display, s_configAttribsNoSample, configs, numConfigs, num_config)){ +// numConfigs = num_config[0]; +// if(numConfigs > 0) workingConfig = true; +// } +// } catch (Exception ex) { +// Log.e("OF", String.format("eglChooseConfig s_configAttribsNoSample failed with EXCEPTION:") + ex.getMessage()); +// } +// } +// if(configs != null) { +// Log.i("OF", String.format("eglChooseConfig Default NO MSAA - worked")); +// } +// } + + + if (DEBUG && configs != null) { + printConfigs(egl, display, configs); + } + + + + /* Now return the "best" one + */ + + EGLConfig finalConfig = null; + try { + finalConfig = chooseConfig(egl, display, configs, false); + } catch(Exception exception) + { + Log.e("OF", String.format("finalConfig choose exception: ") + exception.getMessage()); + + } + + mSampleSize = mFinalSampleSize; + + if(mFinalSampleSize != OFAndroid.samples) { + Log.w("OF", String.format("MSAA FinalConfig Final Samples: %d - target:%d - saving max for device", mFinalSampleSize, mSampleSize)); + OFAndroid.samples = mFinalSampleSize; + OFAndroid.savePreferences(); + } + + if (DEBUG && finalConfig != null) { + printConfig(egl, display, finalConfig); + } + return finalConfig; + + } + + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, + EGLConfig[] configs, boolean validate) { + + EGLConfig foundConfig = null; + EGLConfig lastConfig = null; + + int foundMSAA = 0; + int foundDepth = 0; + int foundStencil = 0; + + String targetOutput = String.format("Config Row: r%d g:%d b%d a:%d d:%d s%d aa:%d", mRedSize, mGreenSize, mBlueSize, mAlphaSize, mDepthSize, mStencilSize, mSampleSize); + + + for(EGLConfig config : configs) { + + //Log.i("OF", String.format("Loop Config Row:", config.toString())); + // We want an *exact* match for red/green/blue/alpha + int r = findConfigAttrib(egl, display, config, + EGL10.EGL_RED_SIZE, 0); + int g = findConfigAttrib(egl, display, config, + EGL10.EGL_GREEN_SIZE, 0); + int b = findConfigAttrib(egl, display, config, + EGL10.EGL_BLUE_SIZE, 0); + int a = findConfigAttrib(egl, display, config, + EGL10.EGL_ALPHA_SIZE, 0); + + int depth = findConfigAttrib(egl, display, config, + EGL10.EGL_DEPTH_SIZE, 0); + + int stencil = findConfigAttrib(egl, display, config, + EGL10.EGL_STENCIL_SIZE, 0); + + int sampleBuffers = 0; + int samples = 0; + int configID = findConfigAttrib(egl, display, config, + EGL10.EGL_CONFIG_ID, 0); + if(mSampleSize > 1) { + sampleBuffers = findConfigAttrib(egl, display, config, + EGL10.EGL_SAMPLE_BUFFERS, 0); + samples = findConfigAttrib(egl, display, config, + EGL10.EGL_SAMPLES, 0); + + } + + String output = String.format("Config Row: r%d g:%d b%d a:%d d:%d s%d aa:%d configID:%d", r, g, b, a, depth,stencil, samples, configID); + + + // We need at least mDepthSize and mStencilSize bits + if (depth < mDepthSize || stencil < mStencilSize) { + if(!validate) Log.i("OF", String.format("Skipping Config Row: %s - target:depth:%d stencil:%d", output, mDepthSize, mStencilSize)); + continue; + } + else if (samples < mSampleSize) { + if(!validate) Log.i("OF", String.format("Skipping Config Row: %s - target:samples:%d", output, mSampleSize)); + continue; + } + else if (samples > OFAndroid.maxSamples) { + if(!validate) Log.i("OF", String.format("Skipping Config Row: %s - target:maxSamples:%d", output, OFAndroid.maxSamples)); + continue; + } + else if (r < mRedSize || g < mGreenSize || b < mBlueSize ) { + if(!validate) Log.i("OF", String.format("Skipping Config Row: %s - target:r:%d g%d b%d", output, mRedSize, mGreenSize, mBlueSize)); + continue; + } + else if (a < mAlphaSize ) { + if(!validate) Log.i("OF", String.format("Skipping Config Row: %s - target:alpha%d", output, mAlphaSize)); + continue; + } + else { + if(!validate) Log.i("OF", String.format("Loop Config Row:", config.toString())); + } + +// int gamut = findConfigAttrib(egl, display, config, +// EGL_GL_COLORSPACE_KHR, 0); +// +// if(gamut != 0) { +// Log.w("OF", String.format("WideGamut: is ", gamut)); +// } + if(OFAndroid.samples > 1) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + int anglesamples = findConfigAttrib(egl, display, config, + EGL_MAX_SAMPLES_ANGLE, 0); + // check for ANGLE Lib EGL Samples + if (foundConfig == null && r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && depth == mDepthSize && stencil == mStencilSize && anglesamples == mSampleSize) { + if (foundConfig == null) { + foundConfig = config; + foundMSAA = anglesamples; + foundDepth = depth; + Log.i("OF", "MSAA - ANGLE MSAA - Found and Set:" + output); + } else { + foundConfig = config; + Log.i("OF", "Override Already Found and Set:" + output); + } + } else { + Log.v("OF", "No Angle Samples - Else Config: " + output); + } + + } + int nvsamples = findConfigAttrib(egl, display, config, + EGL_COVERAGE_SAMPLES_NV, 0); + + if ((foundConfig == null || foundMSAA != 0 && foundMSAA != mSampleSize && nvsamples >= foundMSAA) && r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && depth == mDepthSize && stencil == mStencilSize && nvsamples == mSampleSize) { + + foundConfig = config; + foundMSAA = nvsamples; + foundDepth = depth; + if(!validate) Log.i("OF", "MSAA - NV samples Found and Set:nvsamples:" + nvsamples + " output:" + output); + + } else { + if(!validate) Log.v("OF", "No MSAA - NV samples - Else Config: " + output); + } + + if ((foundConfig == null || foundMSAA != 0 && foundMSAA != mSampleSize && nvsamples >= foundMSAA) && r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && depth == mDepthSize && stencil == mStencilSize && nvsamples == 5) { + + foundConfig = config; + foundMSAA = nvsamples; + foundDepth = depth; + if(!validate) Log.i("OF", "MSAA - NV 5 samples Found and Set:nvsamples:" + nvsamples + " output:" + output); + + } else { + if(!validate) Log.v("OF", "No MSAA - NV samples - Else Config: " + output); + } + + if ((foundConfig == null || foundMSAA != 0 && foundMSAA != mSampleSize && samples >= foundMSAA && samples >= mSampleSize) && r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && depth == mDepthSize && stencil == mStencilSize && samples == mSampleSize) { + + foundConfig = config; + foundMSAA = samples; + foundDepth = depth; + if(!validate) Log.i("OF", "MSAA Found and Set:" + output); + + } else { + if(!validate) Log.v("OF", "NO MSAA - Else Config: " + output); + } + + if ((foundConfig == null || foundMSAA != 0 && foundMSAA != mSampleSize && samples >= foundMSAA && samples < OFAndroid.maxSamples && mSampleSize >= samples) && r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && depth == mDepthSize && stencil == mStencilSize && samples == mSampleSize / 2) { + + foundConfig = config; + foundMSAA = samples; + foundDepth = depth; + if(!validate) Log.i("OF", "MSAA/2 Found and Set:" + output); + + } else { + if(!validate) Log.v("OF", "NO MSAA/2 Else Config: " + output); + } + + if((foundConfig == null || foundMSAA != 0 && foundMSAA != mSampleSize && samples >= foundMSAA && samples >= mSampleSize) && r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && depth == mDepthSize && stencil == mStencilSize && samples == mSampleSize / 4) { + + foundConfig = config; + foundMSAA = samples; + foundDepth = depth; + if(!validate) Log.i("OF", "MSAA/4 Found and Set:" + output); + + } else { + if(!validate) Log.v("OF", "NO MSAA/4 Else Config: " + output); + } + + + if (foundConfig == null && r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && depth == mDepthSize && stencil == mStencilSize && mSampleSize <= 1 && samples <= 1) { + foundConfig = config; + foundMSAA = samples; + foundDepth = depth; + if(!validate) Log.i("OF", "Found and Set :" + output); + + } else { + if(!validate) Log.v("OF", "NO MSAA - other issue - Else Config: " + output); + } + } else { + if ((foundConfig == null || foundMSAA != mSampleSize && samples == mSampleSize && samples <= OFAndroid.maxSamples) && r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && depth == mDepthSize && stencil == mStencilSize && samples == mSampleSize) { + + foundConfig = config; + foundMSAA = samples; + foundDepth = depth; + if(!validate) Log.i("OF", "Config Found - NO MSAA and All other parameters are Set:" + output); + + } else { + if(!validate) Log.v("OF", "Not searching for MSAA - Else Config: " + output); + } + } + + if ( foundConfig == null && r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && samples != 0 && mSampleSize >= 1 && samples <= OFAndroid.maxSamples) { + + foundConfig = config; + foundMSAA = samples; + if(!validate) Log.i("OF", "MSAA Any Found and Set :Depth Size and Stencil any:" + output); + + } else { + if(!validate) Log.v("OF", "Else Config: " + output); + } + + if (foundConfig == null && r == mRedSize && g == mGreenSize && b == mBlueSize && depth == mDepthSize && samples == 1 && mSampleSize == 0) { + + foundConfig = config; + foundMSAA = samples; + if(!validate) Log.i("OF", "MSAA Off - Last Resort Found and Set:" + output); + + } else { + if(!validate) Log.v("OF", "Else Config: " + output); + } + + } + if(foundConfig == null && lastConfig != null) { + if(!validate) Log.v("OF", "Using Last Resort Config" + lastConfig.toString()); + foundConfig = lastConfig; + } else if(foundConfig != null) { + if(!validate) + Log.v("OF", "Using Config: " + foundConfig.toString()); + else + Log.v("OF", "Validated Config for FinalConfig: " + foundConfig.toString()); + + if(foundMSAA == 1) + mFinalSampleSize = mSampleSize; + else + mFinalSampleSize = foundMSAA; + if(DEBUG) printConfig(egl, display, foundConfig); + } + if(validate && foundConfig == null) { + Log.v("OF", "GL Config not found for: " + targetOutput); + } + return foundConfig; + } + + private int findConfigAttrib(EGL10 egl, EGLDisplay display, + EGLConfig config, int attribute, int defaultValue) { + + if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { + return mValue[0]; + } + return defaultValue; + } + + private void printConfigs(EGL10 egl, EGLDisplay display, + EGLConfig[] configs) { + if(configs != null) { + int numConfigs = configs.length; + Log.w("OF", String.format("%d configurations", numConfigs)); + for (int i = 0; i < numConfigs; i++) { + Log.w("OF", String.format("Configuration %d:\n", i)); + printConfig(egl, display, configs[i]); + } + } else { + Log.w("OF", String.format("printConfigs - no configs - %d configurations", 0)); + } + } + + private void printConfig(EGL10 egl, EGLDisplay display, + EGLConfig config) { + int[] attributes = { + EGL10.EGL_BUFFER_SIZE, + EGL10.EGL_ALPHA_SIZE, + EGL10.EGL_BLUE_SIZE, + EGL10.EGL_GREEN_SIZE, + EGL10.EGL_RED_SIZE, + EGL10.EGL_DEPTH_SIZE, + EGL10.EGL_STENCIL_SIZE, + EGL10.EGL_CONFIG_CAVEAT, + EGL10.EGL_CONFIG_ID, +// EGL10.EGL_LEVEL, +// EGL10.EGL_MAX_PBUFFER_HEIGHT, +// EGL10.EGL_MAX_PBUFFER_PIXELS, +// EGL10.EGL_MAX_PBUFFER_WIDTH, +// EGL10.EGL_NATIVE_RENDERABLE, + EGL10.EGL_NATIVE_VISUAL_ID, +// EGL10.EGL_NATIVE_VISUAL_TYPE, +// 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, + EGL10.EGL_SAMPLES, + EGL10.EGL_SAMPLE_BUFFERS, + EGL10.EGL_SURFACE_TYPE, +// EGL10.EGL_TRANSPARENT_TYPE, +// EGL10.EGL_TRANSPARENT_RED_VALUE, +// EGL10.EGL_TRANSPARENT_GREEN_VALUE, +// EGL10.EGL_TRANSPARENT_BLUE_VALUE, +// 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, +// 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, +// 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, +// 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, +// EGL10.EGL_LUMINANCE_SIZE, +// EGL10.EGL_ALPHA_MASK_SIZE, +// EGL10.EGL_COLOR_BUFFER_TYPE, + EGL_RENDERABLE_TYPE, +// 0x3042, // EGL10.EGL_CONFORMANT +// 0x309D, // EGL_GL_COLORSPACE_KHR +// 0x3339, // EGL_COLOR_COMPONENT_TYPE_EXT +// 0x333B, //EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT +// 0x3340, // EGL_GL_COLORSPACE_BT2020_PQ_EXT +// 0x30E0, //EGL_COVERAGE_BUFFERS_NV +// 0x30E1, //EGL_COVERAGE_SAMPLES_NV +// 0x3490, //EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT +// EGL_COVERAGE_BUFFERS_NV, // +// EGL_COVERAGE_SAMPLES_NV, // always 5 in practice on tegra 2 + }; + String[] names = { + "EGL_BUFFER_SIZE", + "EGL_ALPHA_SIZE", + "EGL_BLUE_SIZE", + "EGL_GREEN_SIZE", + "EGL_RED_SIZE", + "EGL_DEPTH_SIZE", + "EGL_STENCIL_SIZE", + "EGL_CONFIG_CAVEAT", + "EGL_CONFIG_ID", +// "EGL_LEVEL", +// "EGL_MAX_PBUFFER_HEIGHT", +// "EGL_MAX_PBUFFER_PIXELS", +// "EGL_MAX_PBUFFER_WIDTH", +// "EGL_NATIVE_RENDERABLE", + "EGL_NATIVE_VISUAL_ID", + "EGL_NATIVE_VISUAL_TYPE", +// "EGL_PRESERVED_RESOURCES", + "EGL_SAMPLES", + "EGL_SAMPLE_BUFFERS", + "EGL_SURFACE_TYPE", +// "EGL_TRANSPARENT_TYPE", +// "EGL_TRANSPARENT_RED_VALUE", +// "EGL_TRANSPARENT_GREEN_VALUE", +// "EGL_TRANSPARENT_BLUE_VALUE", +// "EGL_BIND_TO_TEXTURE_RGB", +// "EGL_BIND_TO_TEXTURE_RGBA", +// "EGL_MIN_SWAP_INTERVAL", +// "EGL_MAX_SWAP_INTERVAL", +// "EGL_LUMINANCE_SIZE", +// "EGL_ALPHA_MASK_SIZE", +// "EGL_COLOR_BUFFER_TYPE", + "EGL_RENDERABLE_TYPE", + "EGL_CONFORMANT", +// "EGL_GL_COLORSPACE_KHR", +// "EGL_COLOR_COMPONENT_TYPE_EXT", +// "EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT", +// "EGL_GL_COLORSPACE_BT2020_PQ_EXT", +// "EGL_COVERAGE_BUFFERS_NV", +// "EGL_COVERAGE_SAMPLES_NV", +// "EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT", +// "EGL_COVERAGE_BUFFERS_NV", +// "EGL_COVERAGE_SAMPLES_NV" + }; + int[] value = new int[1]; + if(attributes != null) { + for (int i = 0; i < attributes.length; i++) { + int attribute = attributes[i]; + String name = names[i]; + if (egl.eglGetConfigAttrib(display, config, attribute, value)) { + if (value != null) + Log.w("OF", String.format(" %s: %d\n", name, value[0])); + } else { + // Log.w(TAG, String.format(" %s: failed\n", name)); + while (egl.eglGetError() != EGL10.EGL_SUCCESS); + } + } + } else { + while (egl.eglGetError() != EGL10.EGL_SUCCESS); + } + } + + // Subclasses can adjust these values: + protected int mRedSize; + protected int mGreenSize; + protected int mBlueSize; + protected int mAlphaSize; + protected int mDepthSize; + protected int mStencilSize; + protected int mSampleSize; + + protected int mFinalSampleSize = 1; + protected boolean mWideGamut; + private int[] mValue = new int[1]; +} + diff --git a/addons/ofxAndroid/Java/cc/openframeworks/OFGLSurfaceView.java b/addons/ofxAndroid/Java/cc/openframeworks/OFGLSurfaceView.java new file mode 100644 index 00000000000..1305920c772 --- /dev/null +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFGLSurfaceView.java @@ -0,0 +1,528 @@ +package cc.openframeworks; + +import android.app.Activity; +import android.content.Context; +import android.graphics.PixelFormat; +import android.opengl.GLSurfaceView; +import android.os.Build; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.InputDevice; +import android.view.InputEvent; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.Surface; +import android.view.SurfaceControl; +import android.view.SurfaceHolder; +import android.view.View; + +import androidx.annotation.Keep; + +import static android.opengl.EGL14.EGL_NO_CONTEXT; +import static android.view.Surface.CHANGE_FRAME_RATE_ALWAYS; +import static android.view.Surface.FRAME_RATE_COMPATIBILITY_DEFAULT; + +@Keep +class OFGLSurfaceView extends GLSurfaceView implements View.OnFocusChangeListener { + + ContextFactory factory; + + public OFGLSurfaceView(Context context) { + super(context); + Log.i("OF","OFGLSurfaceView():" + context.toString()); + init(false, 24, 8); + setFocusable(true); + setFocusableInTouchMode(true); + requestFocus(); + } + + public OFGLSurfaceView(Context context, boolean translucent, int depth, int stencil) { + super(context); + Log.i("OF","OFGLSurfaceView():" + context.toString()); + init(translucent, depth, stencil); + } + + private void init(boolean translucent, int depth, int stencil) { + + Log.i("OF","OFGLSurfaceView():init translucent:" + translucent + " | depth:" + depth + " | stencil:" + stencil + " | msaa:" + OFAndroid.samples + "| Max FPS:" + OFAndroid.maximumFrameRate); + if (translucent) { + this.getHolder().setFormat(PixelFormat.TRANSLUCENT); + } else { + this.getHolder().setFormat(PixelFormat.OPAQUE); + } + + try { + factory = new ContextFactory(); + setEGLContextFactory(factory); + } catch (Exception exception){ + Log.w("OF", "Could not set ContextFactory ", exception); + } + setClientVersion(); + int width = getWidth(); + int height = getHeight(); + + if(width <= 0 || height <= 0 ) { + try { + DisplayMetrics displayMetrics = new DisplayMetrics(); + Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); + display.getRealMetrics(displayMetrics); + height = displayMetrics.heightPixels; + width = displayMetrics.widthPixels; + } catch (Exception exception){ + Log.w("OF", "Could not get Window for Display ", exception); + } + } + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + OFAndroid.samples=1; // force no AA old devices + depth = 24; + } + if(OFAndroid.maxSamples <= OFAndroid.samples) + OFAndroid.samples = OFAndroid.maxSamples; + + OFEGLConfigChooser configChooser = getConfigChooser(8, 8, 8, 8, depth, 8, OFAndroid.samples, false); + + try { + setEGLConfigChooser(configChooser); + } catch (Exception ex) { + Log.e("OF", "setEGLConfigChooser failed 8,8,8,8,depth,1 ", ex); + try { + configChooser = getConfigChooser(8, 8, 8, 8, 16, 1, OFAndroid.samples, false); + setEGLConfigChooser(configChooser); + } catch (Exception exOne) { + Log.e("OF", "setEGLConfigChooser failed exOne: Trying 5, 6, 5, 1, 16, 1 ", ex); + try { + configChooser = getConfigChooser(5, 6, 5, 1, 16, 1, OFAndroid.samples, false); + setEGLConfigChooser(configChooser); + } catch (Exception exceptionTwo) { + try { + Log.e("OF", "setEGLConfigChooser failed exOne: Trying 10, 10, 10, 10, 16, 1 ", exceptionTwo); + configChooser = getConfigChooser(10, 10, 10, 10, 16, 1, OFAndroid.samples, false); + setEGLConfigChooser(configChooser); + + } catch (Exception exceptionThree) { + configChooser = getConfigChooser(8, 8, 8, 1, 16, 1, 0, false); + setEGLConfigChooser(configChooser); + } + } + } + } + + mRenderer = new OFAndroidWindow(width, height); + OFAndroid.samples = configChooser.getSampleSize(); + if(OFAndroid.samples > OFAndroid.maxSamples) + OFAndroid.samples = OFAndroid.maxSamples; + OFAndroid.setSampleSize(OFAndroid.samples); + setRenderer(mRenderer); + setRenderMode(OFGLSurfaceView.RENDERMODE_CONTINUOUSLY); + display = getDisplay(); + post(new Runnable() { + @Override + public void run() { + + mRenderer.setResolution(getWidth(), getHeight(), true); + + } + }); + } + + @Override + public boolean onCapturedPointerEvent(MotionEvent motionEvent) { + // Get the coordinates required by your app + float verticalOffset = motionEvent.getY(); + // Use the coordinates to update your view and return true if the event was + // successfully processed + return true; + } + + @Override + public void setRenderer(GLSurfaceView.Renderer renderer) { + Log.i("OF","setRenderer:" + renderer.toString()); + super.setRenderer(renderer); + } + + public OFAndroidWindow getRenderer() { + return mRenderer; + } + + @Override + public void setRenderMode(int renderMode) { + + super.setRenderMode(renderMode); + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + if(v != null) + Log.i("OF","view onFocusChange:" + v.toString() + " hasFocus:" + hasFocus); + if(doNotDraw) return; + requestFocus(); + } + + public void setFrameRate(float frameRate) { +// if(doNotDraw) return; + + //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.) { + Log.i("OF","setFrameRate:" + frameRate); + try { + if(mSurface != null && mSurface.isValid()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + mSurface.setFrameRate(frameRate, + FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); + } else { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + mSurface.setFrameRate(frameRate, + FRAME_RATE_COMPATIBILITY_DEFAULT); + } + } + // https://developer.android.com/reference/android/view/Surface#CHANGE_FRAME_RATE_ALWAYS + } else { + Log.i("OF","setFrameRate called and no Surface"); + } + } catch (Exception ex) { + Log.e("OF", "setFrameRate Exception:", ex); + } + // } + + // SurfaceControl Fallback for OnePlus Phones + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + SurfaceControl sc = this.getSurfaceControl(); + SurfaceControl.Transaction transaction = null; + transaction = new SurfaceControl.Transaction(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if(transaction != null && sc != null && sc.isValid()) { + transaction.setFrameRate(sc, frameRate, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); + transaction.apply(); + } + } + } + } catch (Exception ex) { + Log.e("OF", "SurfaceControl setFrameRate Exception:", ex); + } + + } + + public void OnResume() { + if(doNotDraw) return; + if(mRenderer != null && mRenderer.isSetup()) { + + int width = getWidth(); + int height = getHeight(); + + Log.i("OF","OnResume w:" + width + " h:" + height); + mRenderer.setResolution(width, height, true); + } else{ + Log.i("OF","OnResume no mRenderer:" + (mRenderer!=null &&mRenderer.isSetup())); + } + } + + @Override + public void setDebugFlags(int debugFlags) { + super.setDebugFlags(debugFlags); + } + + @Override + public void setPreserveEGLContextOnPause(boolean preserveOnPause) { + super.setPreserveEGLContextOnPause(preserveOnPause); + } + + @Override + public void setEGLContextFactory(EGLContextFactory factory) { + super.setEGLContextFactory(factory); + Log.i("OF","setEGLContextFactory"); + } + + @Override + public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) { + super.setEGLWindowSurfaceFactory(factory); + Log.i("OF","setEGLWindowSurfaceFactory"); + } + + @Override + public void setEGLConfigChooser(EGLConfigChooser configChooser) { + super.setEGLConfigChooser(configChooser); + Log.i("OF","setEGLConfigChooser"); + } + + @Override + public void setEGLContextClientVersion(int version) { + super.setEGLContextClientVersion(version); + Log.i("OF","setEGLContextClientVersion:" + version); + } + + public void setBackgroundResourceClear() { + post(new Runnable() { + @Override + public void run() { + setBackgroundColor(0); + } + }); + } + + public OFEGLConfigChooser getConfigChooser() { + return getConfigChooser(8,8,8,8,8,1,OFAndroid.samples,false); + } + + public OFEGLConfigChooser getConfigChooser(int r, int g, int b, int a, int depth, int stencil, int samples, boolean gamut) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Log.i("OF","getConfigChooser::WideGamut Config Chooser"); + return new OFEGLConfigChooser(r, g, b, a, depth, stencil, samples, gamut); + } + Log.i("OF","getConfigChooser::sRGB Config"); + return new OFEGLConfigChooser(r, g, b, a, depth, stencil, samples, false); + } + + public void setClientVersion() { + if(OFEGLConfigChooser.getGLESVersion()>=2){ + Log.i("OF","SetClientVersion::setClientVersion setEGLContextClientVersion " + OFEGLConfigChooser.getGLESVersion()); + setEGLContextClientVersion(OFEGLConfigChooser.getGLESVersion()); + } else { + Log.i("OF","OFGLSurfaceView::setClientVersion setEGLContextClientVersion " + OFEGLConfigChooser.getGLESVersion()); + } + } + + + + @Override + public void onPause() { + /* + * We call a "pause" function in our Renderer class, which tells it to save state and + * go to sleep. Because it's running in the Renderer thread, we call it through + * queueEvent(), which doesn't wait for the code to actually execute. In theory the + * application could be killed shortly after we return from here, which would be bad if + * it happened while the Renderer thread was still saving off important state. We need + * to wait for it to finish. + */ + + //setRenderMode(OFGLSurfaceView.RENDERMODE_WHEN_DIRTY); + + super.onPause(); + + //Log.d(TAG, "asking renderer to pause"); +// queueEvent(new Runnable() { +// @Override public void run() { +// if(mRenderer != null) +// mRenderer.onViewPause(syncObj); +// }}); + + //Log.d(TAG, "renderer pause complete"); + } + + + @Override + public void onResume() { + if(doNotDraw) return; + Log.i("OF","OFGLSurfaceView::onResume"); + if(mRenderer != null) + { + if(android.opengl.EGL14.eglGetCurrentContext() == EGL_NO_CONTEXT) { + Log.w("OF", "OFGLSurfaceView::onResume however no CONTEXT"); + // surfaceDestroyed(this.mHolder); + + display = getDisplay(); + getHolder().setFormat(PixelFormat.OPAQUE); + + setRenderMode(OFGLSurfaceView.RENDERMODE_CONTINUOUSLY); + + post(new Runnable() { + @Override + public void run() { + int width = getWidth(); + int height = getHeight(); + if (mRenderer != null){ + if(OFAndroid.maxSamples <= OFAndroid.samples) + OFAndroid.samples = OFAndroid.maxSamples; + OFAndroid.setSampleSize(OFAndroid.samples); + mRenderer.setResolution(width, height, true); + } + } + }); + } + } else if(mRenderer == null) { + Log.e("OF", "OFGLSurfaceView::onResume however mRenderer is NULL"); + surfaceDestroyed(this.mHolder); + + mRenderer = new OFAndroidWindow(getWidth(), getHeight()); + getHolder().setFormat(PixelFormat.OPAQUE); + if(OFAndroid.maxSamples <= OFAndroid.samples) + OFAndroid.samples = OFAndroid.maxSamples; + OFAndroid.setSampleSize(OFAndroid.samples); + + setRenderer(mRenderer); + setRenderMode(OFGLSurfaceView.RENDERMODE_CONTINUOUSLY); + display = getDisplay(); + } + super.onResume(); + + } + + @Override + public void queueEvent(Runnable r) { + super.queueEvent(r); + } + +// NOTE - The following has been removed because it is not a good way to determine that the opengl context was destroyed with its resources. +// The Android SurfaceView source code is a bit confusing - there are many times when some kind of surface is beign destroyed (eg. during window resize), +// so it is not that surprising, that not every surfaceDestoyed callback means what we might think it means. +// We don't need this callback that much anyways, the renderer does not call render callbacks when gl context is invalid, so the OFAndroidWindow.onSurfaceCreated callback should be enought for us to make things work. + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + Log.i("OF","surfaceDestroyed"); + if(holder != null) + super.surfaceDestroyed(holder); + +// mHolder = null; +// mSurface = null; + //OFAndroid.onSurfaceDestroyed(); + //mRenderer.exit(); + //mRenderer = null; + } + + @Override + public void finalize() { + Log.i("OF","finalize"); + } + + public void setDoNotDraw() { + Log.i("OF","setDoNotDraw"); + doNotDraw = true; + if(mRenderer != null) { + setRenderMode(OFGLSurfaceView.RENDERMODE_WHEN_DIRTY); + mRenderer.setDoNotDraw(); + } + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + Log.i("OF","surfaceCreated"); + if(doNotDraw) return; + if(holder != null && holder.getSurface() != null && holder.getSurface().isValid()) { + mHolder = holder; + mSurface = holder.getSurface(); + } + super.surfaceCreated(holder); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + Log.i("OF","surfaceChanged format:" + format + " w:" + w + " h:" + h); + super.surfaceChanged(holder, format, w, h); + if(doNotDraw) return; + if(holder != null && holder.getSurface() != null && holder.getSurface().isValid()) { + mHolder = holder; + mSurface = holder.getSurface(); + } + if(mRenderer != null) { + mRenderer.setResolution(w,h, true); + } + } + + boolean isSetup(){ + return mRenderer != null && mRenderer.isSetup(); + } + + void setWindowResize(int w, int h){ + if(doNotDraw) return; + Log.i("OF","setWindowResize mRenderer:" + " w:" + w + " h:" + h ); + if(mRenderer != null && mRenderer.isSetup()) { + mRenderer.setResolution(w,h, true); + } else if(mRenderer != null) { + mRenderer.setResolution(w,h, true); + } + } + private boolean doNotDraw = false; + private OFAndroidWindow mRenderer; + private SurfaceHolder mHolder; + private Surface mSurface; + private Display display; + +// @Override +// public boolean onKeyDown(int keyCode, KeyEvent event) { +// return true; +// } +// @Override +// public boolean onKeyUp(int keyCode, KeyEvent event) { +// return true; +// } +// @Override +// public boolean onGenericMotionEvent(MotionEvent event) { +// return true; +// } +// @Override +// public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { +// return true; +// } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + Log.i("OF", "onKeyDown" + keyCode + " event:" + event.toString()); + if(doNotDraw) return true; + if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) + == InputDevice.SOURCE_GAMEPAD) { + int deviceId = event.getDeviceId(); + OFAndroid.keyDown(keyCode+400, event); + return true; + } + else if (OFAndroid.keyDown(keyCode, event)) { + return true; + } else { + return super.onKeyDown(keyCode, event); + } + } + + @Override + public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { + Log.i("OF", "onKeyDown" + keyCode + " event:" + event.toString()); + if(doNotDraw) return true; + int keyOffset = 0; + if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) + == InputDevice.SOURCE_GAMEPAD) { + keyOffset = 400; + } + int deviceId = event.getDeviceId(); + if(event.getAction() == KeyEvent.ACTION_DOWN) + return OFAndroid.keyDown(event.getKeyCode()+keyOffset, event); + else if(event.getAction() == KeyEvent.ACTION_UP) + return OFAndroid.keyUp(event.getKeyCode()+keyOffset, event); + else + return true; + + } + + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if(doNotDraw) return true; + Log.i("OF", "onKeyUp" + keyCode + " event:" + event.toString()); + + if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) + == InputDevice.SOURCE_GAMEPAD) { + int deviceId = event.getDeviceId(); + return OFAndroid.keyUp(keyCode+400, event); + } + else if (OFAndroid.keyUp(keyCode, event)) { + return true; + } else { + return super.onKeyUp(keyCode, event); + } + } + + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if(doNotDraw) return true; + return OFAndroidController.genericMotionEvent(event); + } + + + + + + + +} diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFGestureListener.java b/addons/ofxAndroid/Java/cc/openframeworks/OFGestureListener.java similarity index 62% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFGestureListener.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFGestureListener.java index 1bbe2955126..a9e14414e4a 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFGestureListener.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFGestureListener.java @@ -1,6 +1,7 @@ package cc.openframeworks; import android.app.Activity; +import android.os.Build; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; @@ -9,54 +10,57 @@ import android.view.View; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.View.OnClickListener; +import androidx.annotation.Keep; +import androidx.annotation.RequiresApi; +@Keep class OFGestureListener extends SimpleOnGestureListener implements OnClickListener, OnScaleGestureListener { - OFGestureListener(Activity activity){ gestureDetector = new GestureDetector(activity,this); scaleDetector = new ScaleGestureDetector(activity, this); - touchListener = new View.OnTouchListener() { - - public boolean onTouch(View v, MotionEvent event) { - final int action = event.getAction(); - final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - final int pointerId = event.getPointerId(pointerIndex); - switch((action & MotionEvent.ACTION_MASK)){ - case MotionEvent.ACTION_MOVE: - { - for(int i=0; i> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + final int pointerId = event.getPointerId(pointerIndex); + switch((action & MotionEvent.ACTION_MASK)){ + case MotionEvent.ACTION_MOVE: + { + for(int i=0; i= Build.VERSION_CODES.O) { + view.releasePointerCapture(); // fix focus issues on controllers + } } @Override @@ -83,6 +87,7 @@ public boolean onSingleTapConfirmed(MotionEvent event) { @Override public boolean onDown(MotionEvent event) { + return true; } @@ -91,6 +96,8 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve /*boolean res = super.onFling(e1, e2, velocityX, velocityY); return res;*/ if(e1==null || e2==null) return false; + + if(!OFAndroid.isApplicationSetup()) return false; final float xDistance = Math.abs(e1.getX() - e2.getX()); final float yDistance = Math.abs(e1.getY() - e2.getY()); @@ -123,6 +130,11 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve @Override public void onLongPress(MotionEvent arg0) { + + } + + public boolean onScroll(MotionEvent arg0) { + return true; } @Override @@ -157,7 +169,11 @@ public void onScaleEnd(ScaleGestureDetector detector) { private GestureDetector gestureDetector; private ScaleGestureDetector scaleDetector; - View.OnTouchListener touchListener; + + public boolean enableTouchEvents = true; + public boolean enableScaleEvents = true; + public boolean enableGestureEvents = true; + public static int swipe_Min_Distance = 100; public static int swipe_Max_Distance = 350; public static int swipe_Min_Velocity = 100; diff --git a/addons/ofxAndroid/Java/cc/openframeworks/OFOrientationListener.java b/addons/ofxAndroid/Java/cc/openframeworks/OFOrientationListener.java new file mode 100644 index 00000000000..6bf51d7fcb3 --- /dev/null +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFOrientationListener.java @@ -0,0 +1,75 @@ +package cc.openframeworks; + +import android.content.Context; +import android.util.Log; +import android.view.Display; +import android.view.OrientationEventListener; +import android.view.Surface; +import android.view.WindowManager; +import androidx.annotation.Keep; + +@Keep +public class OFOrientationListener extends OrientationEventListener { + OFOrientationListener(Context context){ + super(context); + } + + private int lastOrientation; + private boolean firstCheck = true; + + @Override + public void enable() { + checkOrientation(-1); + super.enable(); + } + + @Override + public void disable() { + firstCheck = false; + super.disable(); + } + + @Override + public void onOrientationChanged(int orientation) { + checkOrientation(orientation); + } + + private void checkOrientation(int newOrientation) { + + try { + + WindowManager windowManager = (WindowManager) OFAndroidLifeCycle.getActivity().getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + + if (lastOrientation != display.getRotation() || firstCheck) { + lastOrientation = display.getRotation(); + firstCheck = false; + + int ofOrientation; + switch (display.getRotation()) { + case Surface.ROTATION_90: + ofOrientation = 3; + break; + case Surface.ROTATION_180: + ofOrientation = 2; + break; + case Surface.ROTATION_270: + ofOrientation = 4; + break; + case Surface.ROTATION_0: + default: + ofOrientation = 1; + break; + } + if(OFAndroidLifeCycle.coreLibraryLoaded && OFAndroidLifeCycle.appLibraryLoaded) { + OFAndroid.deviceOrientationChanged(ofOrientation); + } else { + firstCheck = true; + } + } + + } catch (Exception ex) { + + } + } +} \ No newline at end of file diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFZipUtil.java b/addons/ofxAndroid/Java/cc/openframeworks/OFZipUtil.java similarity index 98% rename from addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFZipUtil.java rename to addons/ofxAndroid/Java/cc/openframeworks/OFZipUtil.java index 455011830ac..bf288d0f591 100644 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFZipUtil.java +++ b/addons/ofxAndroid/Java/cc/openframeworks/OFZipUtil.java @@ -9,8 +9,9 @@ import java.util.zip.ZipInputStream; import android.util.Log; +import androidx.annotation.Keep; - +@Keep public class OFZipUtil { private static final int BUFFER_SIZE = 4096; diff --git a/addons/ofxAndroid/ofAndroidLib/.classpath b/addons/ofxAndroid/ofAndroidLib/.classpath deleted file mode 100644 index 7bc01d9a9c6..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/addons/ofxAndroid/ofAndroidLib/.project b/addons/ofxAndroid/ofAndroidLib/.project deleted file mode 100644 index 4ee0f36d7a4..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - ofAndroidLib - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/addons/ofxAndroid/ofAndroidLib/build.gradle b/addons/ofxAndroid/ofAndroidLib/build.gradle deleted file mode 100644 index 4420067f5ae..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/build.gradle +++ /dev/null @@ -1,45 +0,0 @@ -apply plugin: 'com.android.model.library' - -model { - android { - compileSdkVersion = 25 - buildToolsVersion = "25.0.3" - defaultConfig.with { - minSdkVersion.apiLevel 19 - targetSdkVersion.apiLevel 25 - versionCode 1 - versionName "1.0" - } - } - android.sources { - main { - manifest { - source { - srcDirs = [ "." ] - } - } - res { - source { - srcDirs = [ "res" ] - } - } - assets { - source { - srcDirs = [ "assets" ] - } - } - java { - source { - srcDirs = [ "src" ] - } - } - } - } -} - - -dependencies { - compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:support-v4:25.+' -} - diff --git a/addons/ofxAndroid/ofAndroidLib/build.xml b/addons/ofxAndroid/ofAndroidLib/build.xml deleted file mode 100644 index 097698dfa33..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/build.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/ofxAndroid/ofAndroidLib/proguard-project.txt b/addons/ofxAndroid/ofAndroidLib/proguard-project.txt deleted file mode 100644 index f2fe1559a21..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/proguard-project.txt +++ /dev/null @@ -1,20 +0,0 @@ -# To enable ProGuard in your project, edit project.properties -# to define the proguard.config property as described in that file. -# -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in ${sdk.dir}/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/addons/ofxAndroid/ofAndroidLib/res/drawable-hdpi/icon.png b/addons/ofxAndroid/ofAndroidLib/res/drawable-hdpi/icon.png deleted file mode 100644 index 8074c4c571b..00000000000 Binary files a/addons/ofxAndroid/ofAndroidLib/res/drawable-hdpi/icon.png and /dev/null differ diff --git a/addons/ofxAndroid/ofAndroidLib/res/drawable-ldpi/icon.png b/addons/ofxAndroid/ofAndroidLib/res/drawable-ldpi/icon.png deleted file mode 100644 index 1095584ec21..00000000000 Binary files a/addons/ofxAndroid/ofAndroidLib/res/drawable-ldpi/icon.png and /dev/null differ diff --git a/addons/ofxAndroid/ofAndroidLib/res/drawable-mdpi/icon.png b/addons/ofxAndroid/ofAndroidLib/res/drawable-mdpi/icon.png deleted file mode 100644 index a07c69fa5a0..00000000000 Binary files a/addons/ofxAndroid/ofAndroidLib/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/addons/ofxAndroid/ofAndroidLib/res/layout/main.xml b/addons/ofxAndroid/ofAndroidLib/res/layout/main.xml deleted file mode 100644 index 3a5f117d3cb..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/res/layout/main.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/addons/ofxAndroid/ofAndroidLib/res/values/strings.xml b/addons/ofxAndroid/ofAndroidLib/res/values/strings.xml deleted file mode 100644 index a44c5ab1583..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/res/values/strings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - Hello World! - ofAndroidLib - diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFActivity.java b/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFActivity.java deleted file mode 100644 index 9a1e8c796f7..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFActivity.java +++ /dev/null @@ -1,120 +0,0 @@ -package cc.openframeworks; - -import android.Manifest; -import android.app.Activity; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -public abstract class OFActivity extends Activity{ - public void onGLSurfaceCreated(){} - public void onLoadPercent(float percent){} - public void onUnpackingResourcesDone(){} - - //gesture handler member - private ViewGroup mOFGlSurfaceContainer; - - public ViewGroup getSurfaceContainer(){ - return mOFGlSurfaceContainer; - } - - public void initView(){ - String packageName = this.getPackageName(); - try { - Log.v("OF","trying to find class: "+packageName+".R$layout"); - Class layout = Class.forName(packageName+".R$layout"); - View view = this.getLayoutInflater().inflate(layout.getField("main_layout").getInt(null),null); - if(view == null) { - Log.w("OF", "Could not find main_layout.xml."); - throw new Exception(); - } - this.setContentView(view); - - Class id = Class.forName(packageName+".R$id"); - mOFGlSurfaceContainer = (ViewGroup)this.findViewById(id.getField("of_gl_surface_container").getInt(null)); - - if(mOFGlSurfaceContainer == null) { - Log.w("OF", "Could not find of_gl_surface_container in main_layout.xml. Copy main_layout.xml from latest empty example to fix this warning."); - throw new Exception(); - } - - } catch (Exception e) { - Log.w("OF", "couldn't create view from layout falling back to GL only",e); - mOFGlSurfaceContainer = new FrameLayout(this); - this.setContentView(mOFGlSurfaceContainer); - } - } - - - private boolean create_first = true; - - @Override - protected void onCreate(Bundle arg0) { - super.onCreate(arg0); - OFAndroidLifeCycle.setActivity(this); - OFAndroidLifeCycle.init(); - OFAndroidLifeCycle.glCreate(); - //create gesture listener - //register the two events - initView(); - } - - @Override - protected void onStart() { - super.onStart(); - OFAndroidLifeCycle.glStart(); - } - - @Override - protected void onStop() { - super.onStop(); - OFAndroidLifeCycle.glStop(); - } - - @Override - protected void onRestart() { - super.onRestart(); - OFAndroidLifeCycle.glRestart(); - } - - @Override - protected void onResume() { - super.onResume(); - OFAndroidLifeCycle.setActivity(this); - OFAndroidLifeCycle.glResume(mOFGlSurfaceContainer); - } - @Override - protected void onPause() { - super.onPause(); - OFAndroidLifeCycle.glPause(); - } - @Override - protected void onDestroy() { - OFAndroidLifeCycle.glDestroy(); - super.onDestroy(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (OFAndroid.keyDown(keyCode, event)) { - return true; - } else { - return super.onKeyDown(keyCode, event); - } - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (OFAndroid.keyUp(keyCode, event)) { - return true; - } else { - return super.onKeyUp(keyCode, event); - } - } -} diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidLifeCycle.java b/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidLifeCycle.java deleted file mode 100644 index bca3cbae3c2..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidLifeCycle.java +++ /dev/null @@ -1,349 +0,0 @@ -package cc.openframeworks; - -import java.util.ArrayList; -import java.util.Vector; -import java.util.concurrent.Semaphore; -import java.util.concurrent.atomic.AtomicBoolean; - -import android.app.Activity; -import android.media.AudioManager; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; - -public class OFAndroidLifeCycle -{ - - static { - - Log.i("OF","static init"); - - try { - Log.i("OF","loading x86 library"); - System.loadLibrary("OFAndroidApp_x86"); - } - catch(Throwable ex) { - Log.i("OF","failed x86 loading, trying neon detection",ex); - - try{ - System.loadLibrary("neondetection"); - if(OFAndroid.hasNeon()){ - Log.i("OF","loading neon optimized library"); - System.loadLibrary("OFAndroidApp_neon"); - } - else{ - Log.i("OF","loading not-neon optimized library"); - System.loadLibrary("OFAndroidApp"); - } - }catch(Throwable ex2){ - Log.i("OF","failed neon detection, loading not-neon library",ex2); - System.loadLibrary("OFAndroidApp"); - } - } - Log.i("OF","initializing app"); - } - - private static Vector m_statesStack = new Vector(); - private static State m_currentState = null; - private static Semaphore m_semaphor = new Semaphore(1, false); - private static AtomicBoolean m_isWorkerDone = new AtomicBoolean(true); - private static AtomicBoolean m_isInit = new AtomicBoolean(false); - - private static OFActivity m_activity = null; - - private static int m_countActivities = 0; - private static ArrayList m_initializers = new ArrayList(); - - private static OFGLSurfaceView mGLView = null; - - private static void pushState(State state) - { -// close - try { - m_semaphor.acquire(); - m_statesStack.add(state); -// release - m_semaphor.release(); - startWorkerThread(); - } - catch (InterruptedException ex) - { - Log.e(OFAndroidLifeCycle.class.getSimpleName(), "pushState exception message: "+ex.getMessage(), ex); - throw new RuntimeException("pushState state: "+ state +" exception message: "+ex.getMessage()); - } - } - - private static boolean isNextStateLegal(State next) - { - boolean isLegal = true; - - switch(next) - { - case init: - if(m_currentState != null) - isLegal = false; - break; - case create: - if(!(m_currentState.equals(State.init)||m_currentState.equals(State.destroy))) - isLegal = false; - break; - case start: - if(!(m_currentState.equals(State.create)||m_currentState.equals(State.stop))) - isLegal = false; - break; - case stop: - if(!(m_currentState.equals(State.start)||m_currentState.equals(State.pause))) - isLegal = false; - break; - case resume: - if(!(m_currentState.equals(State.pause)||m_currentState.equals(State.start))) - isLegal = false; - break; - case pause: - if(!m_currentState.equals(State.resume)) - isLegal = false; - break; - case destroy: - if(!(m_currentState.equals(State.stop)||m_currentState.equals(State.create))) - isLegal = false; - break; - case exit: - if(!(m_currentState.equals(State.init)||m_currentState.equals(State.destroy))) - isLegal = false; - break; - } - return isLegal; - } - - private static void startWorkerThread() throws IllegalStateException - { - synchronized (m_isWorkerDone) - { - if(!m_isWorkerDone.get()) - return; - m_isWorkerDone.set(false); - } - Thread worker = new Thread(new Runnable() { - - @Override - public void run() - { -//close - try { - m_semaphor.acquire(); - while (!m_statesStack.isEmpty()) { - State next = m_statesStack.firstElement(); - m_statesStack.removeElement(next); -// release - m_semaphor.release(); - if (!isNextStateLegal(next)) - { - throw new IllegalStateException("Illegal next state! when current state " + m_currentState.toString() + " next state: " + next.toString()); - } - - m_currentState = next; - - switch (next) { - case init: - OFAndroidLifeCycleHelper.appInit(m_activity); - coreInitialized(); - break; - case create: - OFAndroidLifeCycleHelper.onCreate(); - break; - case start: - OFAndroidLifeCycleHelper.onStart(); - break; - case stop: - OFAndroidLifeCycleHelper.onStop(); - break; - case pause: - OFAndroidLifeCycleHelper.onPause(); - break; - case resume: - OFAndroidLifeCycleHelper.onResume(); - break; - case destroy: - OFAndroidLifeCycleHelper.onDestroy(); - break; - case exit: - OFAndroidLifeCycleHelper.exit(); - m_currentState = null; - break; - - default: - break; - } - //close - m_semaphor.acquire(); - } - } - catch (InterruptedException ex) - { - Log.e(OFAndroidLifeCycle.class.getSimpleName(), "startWorkerThread: stack size: "+m_statesStack.size() + "exception message: "+ex.getMessage(), ex); - m_semaphor.release(); - } -// release - m_semaphor.release(); - synchronized (m_isWorkerDone) { - m_isWorkerDone.set(true); - } - } - }); - worker.start(); - } - - private static void coreInitialized() - { - synchronized (m_isInit) { - m_isInit.set(true); - } - if(m_activity != null) - m_activity.runOnUiThread(new Runnable() { - - @Override - public void run() { - for (Runnable init : m_initializers) - { - init.run(); - } - m_initializers.clear(); - } - }); - } - - static OFActivity getActivity(){ - return OFAndroidLifeCycle.m_activity; - } - - static OFGLSurfaceView getGLView(){ - return mGLView; - } - - static void clearGLView(){ - mGLView = null; - } - - public static void setActivity(OFActivity activity){ - m_activity = activity; - activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); - OFAndroidObject.setActivity(activity); - } - -//============================ Life Cycle Functions ===================// - - public static void addPostInit(Runnable runnable) - { - if(isInit()) - runnable.run(); - else - { - m_initializers.add(runnable); - } - } - - public static void clearPostInit(){ - m_initializers.clear(); - } - - public static boolean isInit() - { - synchronized (m_isInit) { - return m_isInit.get(); - } - } - - public static void init() - { - if(m_currentState != null) - { - return; - } - Log.i("OF","OFAndroid init..."); - pushState(State.init); - } - - static String TAG = "OF"; - - public static void glCreate() - { - Log.d(TAG, "glCreate"); - if(m_countActivities == 0) - pushState(State.create); - m_countActivities++; - } - - public static void glCreateSurface( boolean preserveContextOnPause ) - { - if(mGLView == null) - { - Log.d(TAG, "Create surface"); - mGLView = new OFGLSurfaceView(m_activity); - - ViewGroup glContainer = getActivity().getSurfaceContainer(); - OFGLSurfaceView glView = getGLView(); - if( preserveContextOnPause ) - glView.setPreserveEGLContextOnPause( true ); - ViewGroup parent = (ViewGroup)glView.getParent(); - if( parent == null ) - glContainer.addView(glView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - } - } - - public static void glStart() - { - Log.d(TAG, "glStart"); - OFGLSurfaceView glView = getGLView(); - if( glView != null ) - glView.onResume(); - - pushState(State.start); - } - - public static void glStop() - { - Log.d(TAG, "glStop"); - OFGLSurfaceView glView = getGLView(); - if( glView != null ) - glView.onPause(); - - pushState(State.stop); - } - - public static void glRestart() - { - } - - public static void glResume(ViewGroup glContainer) - { - Log.d(TAG, "glResume"); - pushState(State.resume); - } - - public static void glPause() - { - Log.d(TAG, "glPause"); - pushState(State.pause); - } - - public static void glDestroy() - { - Log.d(TAG, "glDestroy"); - m_countActivities--; - if(m_countActivities == 0){ - Log.d(TAG, "glDestroy destroy ofApp"); - pushState(State.destroy); - } - } - - public static void exit() - { - pushState(State.exit); - } - - public enum State - { - init, create, start, stop, destroy, exit, pause, resume; - } -} diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidLifeCycleHelper.java b/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidLifeCycleHelper.java deleted file mode 100644 index 503e55f6b32..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidLifeCycleHelper.java +++ /dev/null @@ -1,286 +0,0 @@ -package cc.openframeworks; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.util.Locale; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.res.AssetManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.StatFs; -import android.util.Log; - -public class OFAndroidLifeCycleHelper -{ - private static final String TAG = OFAndroidLifeCycleHelper.class.getSimpleName(); - private static boolean appInitFlag = false; - private static boolean started; - - public static void appInit(Activity activity) - { - if(appInitFlag) - return; - appInitFlag = true; - - copyAssetsToDataPath(activity); - - OFAndroid.init(); - } - - private static void copyAssetsToDataPath(Activity activity) { - OFAndroid.packageName = activity.getPackageName(); - - Log.i(TAG,"starting resources extractor"); - boolean copydata = false; - String[] files = new String[0]; - AssetManager am = activity.getApplicationContext().getAssets(); - - try { - SharedPreferences preferences = activity.getPreferences(Context.MODE_PRIVATE); - - long lastInstalled = preferences.getLong("installed", 0); - - PackageManager pm = activity.getPackageManager(); - - ApplicationInfo appInfo = pm.getApplicationInfo(OFAndroid.packageName, 0); - - String appFile = appInfo.sourceDir; - long installed = new File(appFile).lastModified(); - if(installed>lastInstalled){ - Editor editor = preferences.edit(); - editor.putLong("installed", installed); - editor.apply(); - copydata = true; - } - files = am.list(""); - - } catch (NameNotFoundException e1) { - copydata = false; - } catch (IOException e) { - e.printStackTrace(); - } - - - OFAndroid.reportPrecentage(.05f); - - String dataPath=""; - try{ - Log.i(TAG, "sd mounted: " + OFAndroid.checkSDCardMounted()); - OFAndroid.initAppDataDirectory(activity); - dataPath = OFAndroid.getAppDataDirectory(); - - Log.i(TAG,"creating app directory: " + dataPath); - try{ - File dir = new File(dataPath); - if(!dir.isDirectory()){ - copydata = true; - if(!dir.mkdirs()){ - OFAndroid.fatalErrorDialog(activity, "Error while copying resources to sdcard:\nCouldn't create directory " + dataPath); - Log.e(TAG,"error creating dir " + dataPath); - return; - } - } - } catch(Exception e){ - OFAndroid.fatalErrorDialog(activity, "Error while copying resources to sdcard:\nCouldn't create directory " + dataPath + "\n"+e.getMessage()); - Log.e(TAG,"error creating dir " + dataPath,e); - } - OFAndroid.moveOldData(OFAndroid.getOldExternalStorageDirectory(OFAndroid.packageName), dataPath); - OFAndroid.setAppDataDir(dataPath); - OFAndroid.reportPrecentage(.10f); - } catch(Exception e){ - Log.e(TAG,"couldn't move app resources to data directory " + dataPath,e); - } - - - try { - if(copydata){ - for (String file : files) { - try { - copyAssetFolder(am, file, dataPath+"/"+file); - } catch (Exception e) { - Log.e("OF", "error copying file", e); - } - - } - - }else{ - OFAndroid.reportPrecentage(.80f); - } - } catch (Exception e) { - Log.e(TAG,"error retrieving app name",e); - } - } - - private static void copyAssetFolder(AssetManager am, String src, String dest) throws IOException { - - Log.i("Copy ",src); - InputStream srcIS = null; - File destfh; - - // this is the only way we can tell if this is a file or a - // folder - we have to open the asset, and if the open fails, - // it's a folder... - boolean isDir = false; - try { - srcIS = am.open(src); - } catch (FileNotFoundException e) { - isDir = true; - } - - // either way, we'll use the dest as a File - destfh = new File(dest); - - // and now, depending on .. - if(isDir) { - - // If the directory doesn't yet exist, create it - if( !destfh.exists() ){ - destfh.mkdir(); - } - - // list the assets in the directory... - String assets[] = am.list(src); - - // and copy them all using same. - for(String asset : assets) { - copyAssetFolder(am, src + "/" + asset, dest + "/" + asset); - } - - } else { - int count, buffer_len = 2048; - byte[] data = new byte[buffer_len]; - - // copy the file from the assets subsystem to the filesystem - FileOutputStream destOS = new FileOutputStream(destfh); - - //copy the file content in bytes - while( (count = srcIS.read(data, 0, buffer_len)) != -1) { - destOS.write(data, 0, count); - } - - // and close the two files - srcIS.close(); - destOS.close(); - } - } - - - - public static void onCreate() - { - OFAndroid.onCreate(); - OFAndroid.onUnpackingResourcesDone(); - - OFAndroid.runOnMainThread(new Runnable() { - @Override - public void run() { - OFAndroid.enableTouchEvents(); - OFAndroid.enableOrientationChangeEvents(); - } - }); - } - - public static void onResume(){ - OFAndroid.onResume(); - } - - public static void onPause(){ - OFAndroid.onPause(); - } - - public static void onStart(){ - Log.i(TAG,"onStart"); - - final OFGLSurfaceView glView = OFAndroidLifeCycle.getGLView(); - if(started) return; - started = true; - - OFAndroid.runOnMainThread(new Runnable() { - @Override - public void run() { - OFAndroid.enableTouchEvents(); - OFAndroid.enableOrientationChangeEvents(); - synchronized (OFAndroidObject.ofObjects) { - for(OFAndroidObject object : OFAndroidObject.ofObjects){ - object.onResume(); - } - - } - } - }); - - if(glView.isSetup()){ - Log.i(TAG,"resume view and native"); - OFAndroid.onStart(); - } - - if(OFAndroid.getOrientation()!=-1) OFAndroid.setScreenOrientation(OFAndroid.getOrientation()); - - OFAndroid.registerNetworkStateReceiver(); - } - - public static void onStop(){ - Log.i(TAG,"onStop"); - - OFAndroid.runOnMainThread(new Runnable() { - @Override - public void run() { - OFAndroid.disableTouchEvents(); - OFAndroid.disableOrientationChangeEvents(); - - synchronized (OFAndroidObject.ofObjects) { - for(OFAndroidObject object : OFAndroidObject.ofObjects){ - object.onPause(); - } - } - } - }); - - OFAndroid.onStop(); - OFAndroid.unregisterNetworkStateReceiver(); - - OFAndroid.sleepLocked=false; - started = false; - } - - public static void onDestroy(){ - started = false; - OFAndroid.runOnMainThread(new Runnable() { - - @Override - public void run() { - OFAndroid.disableTouchEvents(); - OFAndroid.disableOrientationChangeEvents(); - - synchronized (OFAndroidObject.ofObjects) { - for(OFAndroidObject object : OFAndroidObject.ofObjects){ - object.onStop(); - } - } - } - }); - OFAndroid.onStop(); - OFAndroid.unregisterNetworkStateReceiver(); - - OFAndroid.sleepLocked=false; - - OFAndroid.onDestroy(); - OFAndroidWindow.exit(); - } - - public static void exit() - { - OFAndroid.exit(); - } -} diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidWindow.java b/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidWindow.java deleted file mode 100644 index ac50ef0c7a0..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidWindow.java +++ /dev/null @@ -1,427 +0,0 @@ -package cc.openframeworks; - -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLDisplay; -import javax.microedition.khronos.opengles.GL10; - -import android.app.Activity; -import android.content.Context; -import android.graphics.PixelFormat; -import android.opengl.GLSurfaceView; -import android.util.AttributeSet; -import android.util.Log; -import android.view.SurfaceHolder; - -class OFEGLConfigChooser implements GLSurfaceView.EGLConfigChooser { - - public OFEGLConfigChooser(int r, int g, int b, int a, int depth, int stencil, int samples) { - mRedSize = r; - mGreenSize = g; - mBlueSize = b; - mAlphaSize = a; - mDepthSize = depth; - mStencilSize = stencil; - mSampleSize = samples; - } - - public static void setGLESVersion(int version){ - GLES_VERSION = version; - - if(version==1) EGL_OPENGL_ES_BIT=1; - else EGL_OPENGL_ES_BIT=4; - } - - public static int getGLESVersion(){ - return GLES_VERSION; - } - - /* This EGL config specification is used to specify 1.x rendering. - * We use a minimum size of 4 bits for red/green/blue, but will - * perform actual matching in chooseConfig() below. - */ - private static boolean DEBUG = false; - private static int EGL_OPENGL_ES_BIT = 1; - private static int GLES_VERSION = 1; - private static int[] s_configAttribsMSAA = - { - EGL10.EGL_RED_SIZE, 8, - EGL10.EGL_GREEN_SIZE, 8, - EGL10.EGL_BLUE_SIZE, 8, - EGL10.EGL_DEPTH_SIZE, 16, - // Requires that setEGLContextClientVersion(2) is called on the view. - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT /* EGL_OPENGL_ES2_BIT */, - EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */, - EGL10.EGL_SAMPLES, 4, - EGL10.EGL_NONE - }; - - private static final int EGL_COVERAGE_BUFFERS_NV = 0x30E0; - private static final int EGL_COVERAGE_SAMPLES_NV = 0x30E1; - private static int[] s_configAttribsMSAAFallBack = { - EGL10.EGL_RED_SIZE, 8, - EGL10.EGL_GREEN_SIZE, 8, - EGL10.EGL_BLUE_SIZE, 8, - EGL10.EGL_DEPTH_SIZE, 16, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT /* EGL_OPENGL_ES2_BIT */, - EGL_COVERAGE_BUFFERS_NV, 1 /* true */, - EGL_COVERAGE_SAMPLES_NV, 2, // always 5 in practice on tegra 2 - EGL10.EGL_NONE - }; - private static int[] s_configAttribsDefault = { - EGL10.EGL_RED_SIZE, 5, - EGL10.EGL_GREEN_SIZE, 6, - EGL10.EGL_BLUE_SIZE, 5, - EGL10.EGL_DEPTH_SIZE, 16, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT /* EGL_OPENGL_ES2_BIT */, - EGL10.EGL_NONE - }; - - private static int[] s_configAttribsDefaultES = { - EGL10.EGL_RED_SIZE, 5, - EGL10.EGL_GREEN_SIZE, 6, - EGL10.EGL_BLUE_SIZE, 5, -// EGL10.EGL_DEPTH_SIZE, 16, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT /* EGL_OPENGL_ES2_BIT */, - EGL10.EGL_NONE - }; - - - public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { - - /* Get the number of minimally matching EGL configurations - */ - int[] num_config = new int[1]; - EGLConfig[] configs = null; - - if (!egl.eglChooseConfig(display, s_configAttribsMSAA, null, 0, - num_config)) { - Log.w("OF", String.format("eglChooseConfig MSAA failed")); - } - int numConfigs = num_config[0]; - if (numConfigs <= 0) { - if (!egl.eglChooseConfig(display, s_configAttribsMSAAFallBack, null, 0, - num_config)) { - Log.w("OF", String.format("eglChooseConfig MSAA Fallback failed")); - } - numConfigs = num_config[0]; - if (numConfigs <= 0) { - if (!egl.eglChooseConfig(display, s_configAttribsDefault, null, 0, - num_config)) { - Log.w("OF", String.format("eglChooseConfig Default failed")); - } - numConfigs = num_config[0]; - if (numConfigs <= 0) { - if (!egl.eglChooseConfig(display, s_configAttribsDefaultES, null, 0, - num_config)) { - Log.w("OF", String.format("s_configAttribsDefaultES Default failed")); - } - numConfigs = num_config[0]; - if (numConfigs <= 0) { - throw new IllegalArgumentException("No configs match configSpec"); - } - } else { - configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(display, s_configAttribsDefault, configs, numConfigs, num_config); - } - } else { - configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(display, s_configAttribsMSAAFallBack, configs, numConfigs, num_config); - } - } else { - configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(display, s_configAttribsMSAA, configs, numConfigs, num_config); - } - /* Allocate then read the array of minimally matching EGL configs - */ - - - if (DEBUG) { - printConfigs(egl, display, configs); - } - /* Now return the "best" one - */ - EGLConfig finalConfig = chooseConfig(egl, display, configs); - if (DEBUG) { - printConfig(egl, display, finalConfig); - } - return finalConfig; - - } - - public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, - EGLConfig[] configs) { - for(EGLConfig config : configs) { - int d = findConfigAttrib(egl, display, config, - EGL10.EGL_DEPTH_SIZE, 0); - int s = findConfigAttrib(egl, display, config, - EGL10.EGL_STENCIL_SIZE, 0); - - // We need at least mDepthSize and mStencilSize bits - if (d < mDepthSize || s < mStencilSize) - continue; - - // We want an *exact* match for red/green/blue/alpha - int r = findConfigAttrib(egl, display, config, - EGL10.EGL_RED_SIZE, 0); - int g = findConfigAttrib(egl, display, config, - EGL10.EGL_GREEN_SIZE, 0); - int b = findConfigAttrib(egl, display, config, - EGL10.EGL_BLUE_SIZE, 0); - int a = findConfigAttrib(egl, display, config, - EGL10.EGL_ALPHA_SIZE, 0); - - int sb = findConfigAttrib(egl, display, config, - EGL10.EGL_SAMPLE_BUFFERS, 1); - int samples = findConfigAttrib(egl, display, config, - EGL10.EGL_SAMPLES, 0); - - if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && samples == mSampleSize) { - Log.w("OF", String.format("Enabled MSAAx%d", mSampleSize)); - return config; - } - - if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize && samples == 2 && mSampleSize > 2) { - Log.w("OF", String.format("Enabled MSAAx%d ", mSampleSize)); - return config; - } - - if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) - return config; - } - return null; - } - - private int findConfigAttrib(EGL10 egl, EGLDisplay display, - EGLConfig config, int attribute, int defaultValue) { - - if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { - return mValue[0]; - } - return defaultValue; - } - - private void printConfigs(EGL10 egl, EGLDisplay display, - EGLConfig[] configs) { - int numConfigs = configs.length; - Log.w("OF", String.format("%d configurations", numConfigs)); - for (int i = 0; i < numConfigs; i++) { - Log.w("OF", String.format("Configuration %d:\n", i)); - printConfig(egl, display, configs[i]); - } - } - - private void printConfig(EGL10 egl, EGLDisplay display, - EGLConfig config) { - int[] attributes = { - EGL10.EGL_BUFFER_SIZE, - EGL10.EGL_ALPHA_SIZE, - EGL10.EGL_BLUE_SIZE, - EGL10.EGL_GREEN_SIZE, - EGL10.EGL_RED_SIZE, - EGL10.EGL_DEPTH_SIZE, - EGL10.EGL_STENCIL_SIZE, - EGL10.EGL_CONFIG_CAVEAT, - EGL10.EGL_CONFIG_ID, - EGL10.EGL_LEVEL, - EGL10.EGL_MAX_PBUFFER_HEIGHT, - EGL10.EGL_MAX_PBUFFER_PIXELS, - EGL10.EGL_MAX_PBUFFER_WIDTH, - EGL10.EGL_NATIVE_RENDERABLE, - EGL10.EGL_NATIVE_VISUAL_ID, - EGL10.EGL_NATIVE_VISUAL_TYPE, - 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, - EGL10.EGL_SAMPLES, - EGL10.EGL_SAMPLE_BUFFERS, - EGL10.EGL_SURFACE_TYPE, - EGL10.EGL_TRANSPARENT_TYPE, - EGL10.EGL_TRANSPARENT_RED_VALUE, - EGL10.EGL_TRANSPARENT_GREEN_VALUE, - EGL10.EGL_TRANSPARENT_BLUE_VALUE, - 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, - 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, - 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, - 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, - EGL10.EGL_LUMINANCE_SIZE, - EGL10.EGL_ALPHA_MASK_SIZE, - EGL10.EGL_COLOR_BUFFER_TYPE, - EGL10.EGL_RENDERABLE_TYPE, - 0x3042 // EGL10.EGL_CONFORMANT - }; - String[] names = { - "EGL_BUFFER_SIZE", - "EGL_ALPHA_SIZE", - "EGL_BLUE_SIZE", - "EGL_GREEN_SIZE", - "EGL_RED_SIZE", - "EGL_DEPTH_SIZE", - "EGL_STENCIL_SIZE", - "EGL_CONFIG_CAVEAT", - "EGL_CONFIG_ID", - "EGL_LEVEL", - "EGL_MAX_PBUFFER_HEIGHT", - "EGL_MAX_PBUFFER_PIXELS", - "EGL_MAX_PBUFFER_WIDTH", - "EGL_NATIVE_RENDERABLE", - "EGL_NATIVE_VISUAL_ID", - "EGL_NATIVE_VISUAL_TYPE", - "EGL_PRESERVED_RESOURCES", - "EGL_SAMPLES", - "EGL_SAMPLE_BUFFERS", - "EGL_SURFACE_TYPE", - "EGL_TRANSPARENT_TYPE", - "EGL_TRANSPARENT_RED_VALUE", - "EGL_TRANSPARENT_GREEN_VALUE", - "EGL_TRANSPARENT_BLUE_VALUE", - "EGL_BIND_TO_TEXTURE_RGB", - "EGL_BIND_TO_TEXTURE_RGBA", - "EGL_MIN_SWAP_INTERVAL", - "EGL_MAX_SWAP_INTERVAL", - "EGL_LUMINANCE_SIZE", - "EGL_ALPHA_MASK_SIZE", - "EGL_COLOR_BUFFER_TYPE", - "EGL_RENDERABLE_TYPE", - "EGL_CONFORMANT" - }; - int[] value = new int[1]; - for (int i = 0; i < attributes.length; i++) { - int attribute = attributes[i]; - String name = names[i]; - if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { - Log.w("OF", String.format(" %s: %d\n", name, value[0])); - } else { - // Log.w(TAG, String.format(" %s: failed\n", name)); - while (egl.eglGetError() != EGL10.EGL_SUCCESS); - } - } - } - - // Subclasses can adjust these values: - protected int mRedSize; - protected int mGreenSize; - protected int mBlueSize; - protected int mAlphaSize; - protected int mDepthSize; - protected int mStencilSize; - protected int mSampleSize; - private int[] mValue = new int[1]; -} - -class OFGLSurfaceView extends GLSurfaceView{ - public OFGLSurfaceView(Context context) { - super(context); - mRenderer = new OFAndroidWindow(getWidth(),getHeight()); - if(OFEGLConfigChooser.getGLESVersion()>=2){ - setEGLContextClientVersion(OFEGLConfigChooser.getGLESVersion()); - } - getHolder().setFormat( PixelFormat.OPAQUE ); - OFEGLConfigChooser configChooser = new OFEGLConfigChooser(8,8,8,0,16,0, 4); - setEGLConfigChooser(configChooser); - setRenderer(mRenderer); - } - - @Deprecated - public OFGLSurfaceView(Context context,AttributeSet attributes) { - super(context,attributes); - mRenderer = new OFAndroidWindow(getWidth(),getHeight()); - if(OFEGLConfigChooser.getGLESVersion()>=2){ - setEGLContextClientVersion(OFEGLConfigChooser.getGLESVersion()); - } - getHolder().setFormat( PixelFormat.OPAQUE ); - OFEGLConfigChooser configChooser = new OFEGLConfigChooser(8,8,8,0,16,0, 4); - setEGLConfigChooser(configChooser); - setRenderer(mRenderer); - } - -// NOTE - The following has been removed because it is not a good way to determine that the opengl context was destroyed with its resources. -// The Android SurfaceView source code is a bit confusing - there are many times when some kind of surface is beign destroyed (eg. during window resize), -// so it is not that surprising, that not every surfaceDestoyed callback means what we might think it means. -// We don't need this callback that much anyways, the renderer does not call render callbacks when gl context is invalid, so the OFAndroidWindow.onSurfaceCreated callback should be enought for us to make things work. - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - super.surfaceDestroyed(holder); - OFAndroid.onSurfaceDestroyed(); - } - - - boolean isSetup(){ - return mRenderer.isSetup(); - } - - private OFAndroidWindow mRenderer; -} - -class OFAndroidWindow implements GLSurfaceView.Renderer { - - public OFAndroidWindow(int w, int h){ - this.w = w; - this.h = h; - } - - @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - Log.i("OF","onSurfaceCreated"); - // notify that old surface was destroyed - if(this.has_surface) { - OFAndroid.onSurfaceDestroyed(); - this.has_surface = false; - } - - // notify that new surface was created - this.has_surface = true; - OFAndroid.onSurfaceCreated(); - Activity activity = OFAndroidLifeCycle.getActivity(); - if(OFActivity.class.isInstance(activity)) - ((OFActivity)activity).onGLSurfaceCreated(); - - return; - } - - @Override - public void onSurfaceChanged(GL10 gl, int w, int h) { - this.w = w; - this.h = h; - if(!setup && OFAndroid.unpackingDone){ - setup(); - } - OFGestureListener.swipe_Min_Distance = (int)(Math.max(w, h)*.04); - OFGestureListener.swipe_Max_Distance = (int)(Math.max(w, h)*.6); - OFAndroid.resize(w, h); - } - - private void setup(){ - OFAndroid.setup(w,h); - setup = true; - android.os.Process.setThreadPriority(8); - OFGestureListener.swipe_Min_Distance = (int)(Math.max(w, h)*.04); - OFGestureListener.swipe_Max_Distance = (int)(Math.max(w, h)*.6); - Activity activity = OFAndroidLifeCycle.getActivity(); - if(OFActivity.class.isInstance(activity)) - ((OFActivity)activity).onGLSurfaceCreated(); - } - - public static void exit() { - setup = false; - } - - @Override - public void onDrawFrame(GL10 gl) { - if(setup && OFAndroid.unpackingDone){ - OFAndroid.render(); - }else if(!setup && OFAndroid.unpackingDone){ - setup(); - }else{ - gl.glClear(GL10.GL_COLOR_BUFFER_BIT); - gl.glClearColor(.5f, .5f, .5f, 1.f); - } - } - - public boolean isSetup(){ - return setup; - } - - private static boolean setup; - private int w,h; - private boolean has_surface = false; -} diff --git a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFOrientationListener.java b/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFOrientationListener.java deleted file mode 100644 index 87878baaf58..00000000000 --- a/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFOrientationListener.java +++ /dev/null @@ -1,56 +0,0 @@ -package cc.openframeworks; - -import android.content.Context; -import android.util.Log; -import android.view.Display; -import android.view.OrientationEventListener; -import android.view.Surface; -import android.view.WindowManager; - -public class OFOrientationListener extends OrientationEventListener { - OFOrientationListener(Context context){ - super(context); - } - - private int lastOrientation; - private boolean firstCheck = true; - - @Override - public void enable() { - checkOrientation(); - super.enable(); - } - - @Override - public void onOrientationChanged(int orientation) { - checkOrientation(); - } - - private void checkOrientation(){ - WindowManager windowManager = (WindowManager)OFAndroidLifeCycle.getActivity().getSystemService(Context.WINDOW_SERVICE); - Display display = windowManager.getDefaultDisplay(); - - if(lastOrientation != display.getRotation() || firstCheck){ - lastOrientation = display.getRotation(); - firstCheck = false; - - int ofOrientation; - switch (display.getRotation()) { - case Surface.ROTATION_90: - ofOrientation = 3; - break; - case Surface.ROTATION_180: - ofOrientation = 2; - break; - case Surface.ROTATION_270: - ofOrientation = 4; - break; - case Surface.ROTATION_0: - default: - ofOrientation = 1; - break; - } - OFAndroid.deviceOrientationChanged(ofOrientation); - } - } -} \ No newline at end of file diff --git a/addons/ofxAndroid/src/ofAppAndroidWindow.cpp b/addons/ofxAndroid/src/ofAppAndroidWindow.cpp index 0dc98723fc8..72e47e93fa1 100644 --- a/addons/ofxAndroid/src/ofAppAndroidWindow.cpp +++ b/addons/ofxAndroid/src/ofAppAndroidWindow.cpp @@ -30,50 +30,63 @@ static int sWindowHeight = 800; static bool bSetupScreen = true; -static JavaVM *ofJavaVM=0; +static JavaVM *ofJavaVM=nullptr; static ofAppAndroidWindow * window; static ofOrientation orientation = OF_ORIENTATION_DEFAULT; static queue touchEventArgsQueue; -static std::mutex mtx; -static bool threadedTouchEvents = false; +static queue keyEventArgsQueue; +static queue axisEventArgsQueue; + +static std::mutex mtx, keyMtx, controllerMtx; + static bool appSetup = false; + +static bool threadedKeyEvents = false; +static bool threadedTouchEvents = false; +static bool threadedAxisEvents = false; + static bool accumulateTouchEvents = false; +static bool accumulateAxisEvents = false; +static bool multiWindowMode = false; + +AAssetManager* assetManager; void ofExitCallback(); //----- define in main.cpp---// -void ofAndroidApplicationInit(); -void ofAndroidActivityInit(); +//JNIEXPORT void JNICALL ofAndroidApplicationInit(); +//JNIEXPORT void JNICALL ofAndroidActivityInit(); //static ofAppAndroidWindow window; - -JavaVM * ofGetJavaVMPtr(){ +JNIEXPORT JavaVM * JNICALL +ofGetJavaVMPtr(){ return ofJavaVM; } -JNIEnv * ofGetJNIEnv(){ +JNIEXPORT JNIEnv * JNICALL + ofGetJNIEnv(){ JNIEnv *env; JavaVM * vm = ofGetJavaVMPtr(); if(!vm){ ofLogError("ofAppAndroidWindow") << "couldn't get java virtual machine"; - return NULL; + return nullptr; } - int getEnvStat = vm->GetEnv((void**) &env, JNI_VERSION_1_4); + int getEnvStat = vm->GetEnv((void**) &env, JNI_VERSION_1_6); if (getEnvStat == JNI_EDETACHED) { - if (vm->AttachCurrentThread(&env, NULL) != 0) { + if (vm->AttachCurrentThread(&env, nullptr) != 0) { ofLogError("ofAppAndroidWindow") << "couldn't get environment using GetEnv()"; - return NULL; + return nullptr; } } else if (getEnvStat != JNI_OK) { ofLogError("ofAppAndroidWindow") << "couldn't get environment using GetEnv()"; - return NULL; + return nullptr; } return env; @@ -89,30 +102,65 @@ jclass ofGetOFLifeCycle(){ jobject ofGetOFActivityObject(){ JNIEnv * env = ofGetJNIEnv(); - if(!env) return NULL; + if(!env) return nullptr; jclass OFLifeCycle = ofGetOFLifeCycle(); - if(!OFLifeCycle) return NULL; + if(!OFLifeCycle) return nullptr; jfieldID ofActivityID = env->GetStaticFieldID(OFLifeCycle,"m_activity","Lcc/openframeworks/OFActivity;"); if(!ofActivityID){ ofLogError("ofAppAndroidWindow") << "couldn't get field ID for ofActivity"; - return NULL; + return nullptr; } return env->GetStaticObjectField(OFLifeCycle,ofActivityID); } +ofAppAndroidWindow::ofAppAndroidWindow() { + //ofLogError("ofAppAndroidWindow") << "ofAppAndroidWindow() the window is this"; + window = this; + msaaSamples = 1; + glesVersion = 2; + + ofGetMainLoop()->setCurrentWindow(this); +} +ofAppAndroidWindow::ofAppAndroidWindow(ofAppBaseWindow & other) { + window = this; + msaaSamples = 1; + glesVersion = 2; + setMultiWindowMode(other.getWindowMode()); + ofGetMainLoop()->setCurrentWindow(this); +} -ofAppAndroidWindow::ofAppAndroidWindow() -:currentRenderer(new ofGLRenderer(this)) -,glesVersion(1){ +void ofAppAndroidWindow::setCurrentWindow() { + ofLogVerbose("ofAppAndroidWindow") << "setCurrentWindow the window is this"; window = this; + ofGetMainLoop()->setCurrentWindow(this); +} + +void ofAppAndroidWindow::setSampleSize(int samples) { + msaaSamples = samples; +} + +int ofAppAndroidWindow::getSamples() { + return msaaSamples; +} + +AAssetManager& ofAppAndroidWindow::getAssetManager() { + return *assetManager; +} + +void ofAppAndroidWindow::setAssetManager(AAssetManager* aaAssetManager) { + assetManager = aaAssetManager; } ofAppAndroidWindow::~ofAppAndroidWindow() { + if(window != nullptr && window == this) { + window = nullptr; + ofLogError("ofAppAndroidWindow") << "~ofAppAndroidWindow destroyed"; + } // TODO Auto-generated destructor stub } @@ -126,8 +174,13 @@ void ofAppAndroidWindow::setup(const ofGLESWindowSettings & settings) } void ofAppAndroidWindow::setup(const ofxAndroidWindowSettings & settings){ + + if(window == nullptr) { + ofLogError("ofAppAndroidWindow") << "Setup and Window is nullptr ! Fixing"; + setCurrentWindow(); + } glesVersion = settings.glesVersion; - ofLogError() << "setup gles" << glesVersion; + ofLogError("ofAppAndroidWindow") << "Setup OpenGLES:" << glesVersion; if(glesVersion<2){ currentRenderer = std::make_shared(this); }else{ @@ -136,11 +189,13 @@ void ofAppAndroidWindow::setup(const ofxAndroidWindowSettings & settings){ jclass javaClass = ofGetJNIEnv()->FindClass("cc/openframeworks/OFAndroid"); - if(javaClass==0){ + if(javaClass==nullptr){ ofLogError("ofAppAndroidWindow") << "setupOpenGL(): couldn't find OFAndroid java class"; return; } + makeCurrent(); + jmethodID method = ofGetJNIEnv()->GetStaticMethodID(javaClass,"setupGL","(IZ)V"); if(!method){ ofLogError("ofAppAndroidWindow") << "setupOpenGL(): couldn't find OFAndroid setupGL method"; @@ -148,6 +203,8 @@ void ofAppAndroidWindow::setup(const ofxAndroidWindowSettings & settings){ } ofGetJNIEnv()->CallStaticVoidMethod(javaClass,method,glesVersion,settings.preserveContextOnPause); + + } void ofAppAndroidWindow::update(){ @@ -183,11 +240,13 @@ void ofAppAndroidWindow::setOrientation(ofOrientation _orientation){ orientation = _orientation; jclass javaClass = ofGetJNIEnv()->FindClass("cc/openframeworks/OFAndroid"); - if(javaClass==0){ + if(javaClass==nullptr){ ofLogError("ofAppAndroidWindow") << "setOrientation(): couldn't find OFAndroid java class"; return; } + bSetupScreen = true; + jmethodID setScreenOrientation = ofGetJNIEnv()->GetStaticMethodID(javaClass,"setScreenOrientation","(I)V"); if(!setScreenOrientation){ ofLogError("ofAppAndroidWindow") << "setOrientation(): couldn't find OFAndroid setScreenOrientation method"; @@ -203,10 +262,18 @@ ofOrientation ofAppAndroidWindow::getOrientation(){ return orientation; } + +void ofAppAndroidWindow::makeCurrent(){ + shared_ptr mainLoop = ofGetMainLoop(); + if(mainLoop){ + mainLoop->setCurrentWindow(this); + } +} + void ofAppAndroidWindow::setFullscreen(bool fullscreen){ jclass javaClass = ofGetJNIEnv()->FindClass("cc/openframeworks/OFAndroid"); - if(javaClass==0){ + if(javaClass==nullptr){ ofLogError("ofAppAndroidWindow") << "setFullscreen(): couldn't find OFAndroid java class"; return; } @@ -225,6 +292,8 @@ void ofAppAndroidWindow::toggleFullscreen(){ void ofAppAndroidWindow::setThreadedEvents(bool threadedEvents){ threadedTouchEvents = threadedEvents; + threadedKeyEvents = threadedEvents; + threadedAxisEvents = threadedEvents; } @@ -232,6 +301,21 @@ void ofAppAndroidWindow::setAccumulateTouchEvents(bool accumEvents){ accumulateTouchEvents = accumEvents; } +void ofAppAndroidWindow::setMultiWindowMode(bool multiWindow) { + multiWindowMode = multiWindow; +} + +bool ofAppAndroidWindow::getIsThreadedEvents() { + return threadedTouchEvents; +} +bool ofAppAndroidWindow::getIsAccumulateTouchEvents() { + return accumulateTouchEvents; +} + +bool ofAppAndroidWindow::getIsMultiWindowMode() { + return multiWindowMode; +} + ofCoreEvents & ofAppAndroidWindow::events(){ return coreEvents; @@ -246,9 +330,11 @@ int ofAppAndroidWindow::getGlesVersion() return glesVersion; } + extern "C"{ -jint JNI_OnLoad(JavaVM* vm, void* reserved) +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv *env; ofJavaVM = vm; @@ -260,73 +346,104 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) return JNI_VERSION_1_4; } -void -Java_cc_openframeworks_OFAndroid_setAppDataDir( JNIEnv* env, jobject thiz, jstring data_dir) +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_setAppDataDir( JNIEnv* env, jclass thiz, jstring data_dir) { jboolean iscopy; const char *mfile = env->GetStringUTFChars(data_dir, &iscopy); - __android_log_print(ANDROID_LOG_INFO,"ofAppAndroidWindow",("setting app dir name to: \"" + string(mfile) + "\"").c_str()); - ofSetDataPathRoot({ string(mfile)+"/" }); + ofLogVerbose("ofAppAndroidWindow") << "setting app dir name to: " << string(mfile); + ofSetDataPathRoot(string(mfile)+"/"); env->ReleaseStringUTFChars(data_dir, mfile); } -void Java_cc_openframeworks_OFAndroid_init( JNIEnv* env, jclass clazz) -{ - ofAndroidApplicationInit(); -} - -void Java_cc_openframeworks_OFAndroid_onCreate( JNIEnv* env, jclass clazz) -{ - ofAndroidActivityInit(); -} - -void -Java_cc_openframeworks_OFAndroid_onRestart( JNIEnv* env, jobject thiz ){ +//JNIEXPORT void JNICALL +//Java_cc_openframeworks_OFAndroid_init( JNIEnv* env, jclass clazz) +//{ +// ofLogVerbose("ofAppAndroidWindow") << "OFAndroid_init"; +// //ofAndroidApplicationInit(); +//} +// +//JNIEXPORT void JNICALL +//Java_cc_openframeworks_OFAndroid_onCreate( JNIEnv* env, jclass clazz) +//{ +// ofLogVerbose("ofAppAndroidWindow") << "OFAndroid_onCreate"; +// ofAndroidActivityInit(); +//} +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onRestart( JNIEnv* env, jclass thiz){ + ofLogVerbose("ofAppAndroidWindow") << "onRestart"; } -void -Java_cc_openframeworks_OFAndroid_onStart( JNIEnv* env, jobject thiz ){ +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onStart( JNIEnv* env, jclass thiz){ ofLogVerbose("ofAppAndroidWindow") << "onStart"; stopped = false; + bSetupScreen = true; ofNotifyEvent(ofxAndroidEvents().start); } -void -Java_cc_openframeworks_OFAndroid_onStop( JNIEnv* env, jobject thiz ){ +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onStop( JNIEnv* env, jclass thiz){ ofLogVerbose("ofAppAndroidWindow") << "onStop"; ofNotifyEvent( ofxAndroidEvents().stop ); stopped = true; } -void -Java_cc_openframeworks_OFAndroid_onResume( JNIEnv* env, jobject thiz ){ +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onResume( JNIEnv* env, jclass thiz){ ofLogVerbose("ofAppAndroidWindow") << "onResume"; + bSetupScreen = true; + stopped = false; + + if(!threadedTouchEvents){ + mtx.lock(); + while (!touchEventArgsQueue.empty()) + { + touchEventArgsQueue.pop(); + } + mtx.unlock(); + } + if(!threadedKeyEvents){ + keyMtx.lock(); + while (!keyEventArgsQueue.empty()) + { + keyEventArgsQueue.pop(); + } + keyMtx.unlock(); + } ofNotifyEvent(ofxAndroidEvents().resume); } -void -Java_cc_openframeworks_OFAndroid_onPause( JNIEnv* env, jobject thiz ){ + +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onPause( JNIEnv* env, jclass thiz){ ofLogVerbose("ofAppAndroidWindow") << "onPause"; ofNotifyEvent(ofxAndroidEvents().pause); } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onDestroy( JNIEnv* env, jclass thiz ){ appSetup = false; + stopped = true; ofEvents().notifyExit(); ofExitCallback(); } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onSurfaceDestroyed( JNIEnv* env, jclass thiz ){ - surfaceDestroyed = true; - ofLogVerbose("ofAppAndroidWindow") << "onSurfaceDestroyed"; - ofNotifyEvent(ofxAndroidEvents().unloadGL); + if(!surfaceDestroyed) { + surfaceDestroyed = true; + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceDestroyed"; + ofNotifyEvent(ofxAndroidEvents().unloadGL); + bSetupScreen = true; + } else { + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceDestroyed already destroyed though"; + } } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onSurfaceCreated( JNIEnv* env, jclass thiz ){ if(appSetup){ ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated"; @@ -337,66 +454,145 @@ Java_cc_openframeworks_OFAndroid_onSurfaceCreated( JNIEnv* env, jclass thiz ){ window->renderer()->pushStyle(); window->renderer()->setupGraphicDefaults(); window->renderer()->popStyle(); - - }else{ - int glesVersion = window->getGlesVersion(); + window->setThreadedEvents(false); + int glesVersion = window->getGlesVersion(); + bSetupScreen = true; if( glesVersion < 2 ) { - static_cast(window->renderer().get())->setup(); + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 1"; + dynamic_cast(window->renderer().get())->setup(); } else { - static_cast(window->renderer().get())->setup(glesVersion,0); + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 2.0"; + dynamic_cast(window->renderer().get())->setup(glesVersion,0); + } + + }else{ + if(window != nullptr) { + int glesVersion = window->getGlesVersion(); + bSetupScreen = true; + if (glesVersion < 2) { + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 1"; + dynamic_cast(window->renderer().get())->setup(); + } else { + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 2.0"; + dynamic_cast(window->renderer().get())->setup( + glesVersion, 0); + } } } surfaceDestroyed = false; } -void +JNIEXPORT jboolean JNICALL +Java_cc_openframeworks_OFAndroid_isWindowReady( JNIEnv* env, jclass thiz) { + + if(window != nullptr && window->renderer() != nullptr) { + return true; + } else { + return false; + } +} + +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_setup( JNIEnv* env, jclass thiz, jint w, jint h ) { - ofLogVerbose("ofAppAndroidWindow") << "setup " << w << "x" << h; + ofLogNotice("ofAppAndroidWindow") << "setup " << w << "x" << h; stopped = false; sWindowWidth = w; sWindowHeight = h; - window->renderer()->startRender(); - if(bSetupScreen) window->renderer()->setupScreen(); - window->events().notifySetup(); - window->renderer()->finishRender(); + if(window != nullptr && window->renderer() != nullptr) + window->renderer()->startRender(); + if(bSetupScreen) { + if(window != nullptr && window->renderer() != nullptr) { + ofLogNotice("ofAppAndroidWindow") << "setupScreen - Logical Resolution:" << w << "x" << h << " Rendering at Resolution:" << w * window->getSamples() << "x" << h * window->getSamples() << " with MSAA:" << window->getSamples(); + window->renderer()->setupScreen(); + bSetupScreen = false; + } else { + ofLogError("ofAppAndroidWindow") << "No Window or Renderer for Logical Resolution:" << w << "x" << h; + } + } + + if(window != nullptr) { + window->makeCurrent(); + if(assetManager != nullptr) + window->setAssetManager(assetManager); + window->events().notifySetup(); + + } + if(window != nullptr && window->renderer() != nullptr) + window->renderer()->finishRender(); appSetup = true; } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_resize( JNIEnv* env, jclass thiz, jint w, jint h ) { sWindowWidth = w; sWindowHeight = h; - ofLogNotice("ofAppAndroidWindow") << "resize " << w << "x" << h; - window->events().notifyWindowResized(w,h); + bSetupScreen = true; + if(window != nullptr) { + ofLogNotice("ofAppAndroidWindow") << "resize to Logical Resolution:" << w << "x" << h << " Hardware Resolution: " << w * window->getSamples() << "x" << h * window->getSamples() << " with MSAA:" << window->getSamples(); + window->events().notifyWindowResized(w,h); + } } /* Call to finalize the graphics state */ -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_exit( JNIEnv* env, jclass thiz ) { + ofLogVerbose("ofAppAndroidWindow") << "OFAndroid_exit"; exit(0); //window->events().notifyExit(); +} + +// +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_setAssetManager(JNIEnv *env, jclass thiz, + jobject jAssetManager) { + + env->NewGlobalRef(jAssetManager); + + AAssetManager *aaAssetManager = AAssetManager_fromJava(env, jAssetManager); + if (aaAssetManager == nullptr) { + ofLogError("ofAppAndroidWindow") << "Could not obtain the AAssetManager"; + return; + } + + assetManager = aaAssetManager; + + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) { + ofLogVerbose("ofAppAndroidWindow") << "setAssetManager window is null"; + return; + } + + window->setAssetManager(assetManager); + + + + } /* Call to render the next GL frame */ -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_render( JNIEnv* env, jclass thiz ) { + if(stopped || surfaceDestroyed) { + ofLogVerbose("ofAppAndroidWindow") << "OFAndroid_render stopped:" << stopped << "surfaceDestroyed" << surfaceDestroyed; + return; + } - if(stopped || surfaceDestroyed) return; - - if(!threadedTouchEvents){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) { + ofLogVerbose("ofAppAndroidWindow") << "OFAndroid_render window is null"; + return; + } + if(!threadedTouchEvents){ // process touch events in render loop thread to prevent latency mtx.lock(); queue events = touchEventArgsQueue; while(!touchEventArgsQueue.empty()) touchEventArgsQueue.pop(); mtx.unlock(); - while(!events.empty()){ switch(events.front().type){ case ofTouchEventArgs::down: @@ -423,17 +619,56 @@ Java_cc_openframeworks_OFAndroid_render( JNIEnv* env, jclass thiz ) } } + if(!threadedKeyEvents) { // process key events in render loop thread to prevent latency + keyMtx.lock(); + queue keyEvents = keyEventArgsQueue; + while (!keyEventArgsQueue.empty()) keyEventArgsQueue.pop(); + keyMtx.unlock(); + + while (!keyEvents.empty()) { + switch (keyEvents.front().type) { + case ofKeyEventArgs::Type::Pressed: + ofNotifyEvent(window->events().keyPressed, keyEvents.front()); + break; + case ofKeyEventArgs::Type::Released: + ofNotifyEvent(window->events().keyReleased, keyEvents.front()); + break; + } + keyEvents.pop(); + } + } + + if(!threadedAxisEvents) { +// axisMtx.lock(); +// queue keyEvents = keyEventArgsQueue; +// while (!keyEventArgsQueue.empty()) keyEventArgsQueue.pop(); +// axisMtx.unlock(); + } + - window->renderer()->startRender(); - window->events().notifyUpdate(); - if(bSetupScreen) window->renderer()->setupScreen(); - window->events().notifyDraw(); - window->renderer()->finishRender(); + if (bSetupScreen) { + window->renderer()->startRender(); + window->renderer()->setupScreen(); + window->events().notifyUpdate(); + window->events().notifyDraw(); + window->renderer()->finishRender(); + bSetupScreen = false; + } else { + window->renderer()->startRender(); + window->events().notifyUpdate(); + window->events().notifyDraw(); + window->renderer()->finishRender(); + } } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onTouchDown(JNIEnv* env, jclass thiz, jint id,jfloat x,jfloat y,jfloat pressure,jfloat majoraxis,jfloat minoraxis,jfloat angle){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) { + ofLogNotice("oF") << "Java_cc_openframeworks_OFAndroid_onTouchDown no window or renderer"; + return; + } + ofTouchEventArgs touch; touch.id = id; touch.x = x; @@ -453,8 +688,9 @@ Java_cc_openframeworks_OFAndroid_onTouchDown(JNIEnv* env, jclass thiz, jint id } } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onTouchUp(JNIEnv* env, jclass thiz, jint id,jfloat x,jfloat y,jfloat pressure,jfloat majoraxis,jfloat minoraxis,jfloat angle){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; ofTouchEventArgs touch; touch.id = id; touch.x = x; @@ -474,8 +710,9 @@ Java_cc_openframeworks_OFAndroid_onTouchUp(JNIEnv* env, jclass thiz, jint id,j } } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onTouchCancelled(JNIEnv* env, jclass thiz, jint id,jfloat x,jfloat y){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; ofTouchEventArgs touch; touch.id = id; touch.x = x; @@ -491,8 +728,9 @@ Java_cc_openframeworks_OFAndroid_onTouchCancelled(JNIEnv* env, jclass thiz, ji } } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onTouchMoved(JNIEnv* env, jclass thiz, jint id,jfloat x,jfloat y,jfloat pressure,jfloat majoraxis,jfloat minoraxis,jfloat angle){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; ofTouchEventArgs touch; touch.id = id; touch.x = x; @@ -517,8 +755,9 @@ Java_cc_openframeworks_OFAndroid_onTouchMoved(JNIEnv* env, jclass thiz, jint i } } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onTouchDoubleTap(JNIEnv* env, jclass thiz, jint id,jfloat x,jfloat y,jfloat pressure){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; ofTouchEventArgs touch; touch.id = id; touch.x = x; @@ -535,59 +774,80 @@ Java_cc_openframeworks_OFAndroid_onTouchDoubleTap(JNIEnv* env, jclass thiz, ji } } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onSwipe(JNIEnv* env, jclass thiz, jint id, jint swipeDir){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; ofxAndroidSwipeEventArgs swipe{(ofxAndroidSwipeDir)swipeDir,id}; ofNotifyEvent(ofxAndroidEvents().swipe,swipe); } -jboolean +JNIEXPORT jboolean JNICALL Java_cc_openframeworks_OFAndroid_onScale(JNIEnv* env, jclass thiz, jobject detector){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return false; ofxAndroidScaleEventArgs scale(detector); return ofxAndroidEvents().scale.notify(nullptr,scale); } -jboolean +JNIEXPORT jboolean JNICALL Java_cc_openframeworks_OFAndroid_onScaleBegin(JNIEnv* env, jclass thiz, jobject detector){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return false; ofxAndroidScaleEventArgs scale(detector); return ofxAndroidEvents().scaleBegin.notify(nullptr,scale); } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_onScaleEnd(JNIEnv* env, jclass thiz, jobject detector){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; ofxAndroidScaleEventArgs scale(detector); ofxAndroidEvents().scaleEnd.notify(nullptr,scale); } -jboolean -Java_cc_openframeworks_OFAndroid_onKeyDown(JNIEnv* env, jobject thiz, jint keyCode, jint unicode){ +JNIEXPORT jboolean JNICALL +Java_cc_openframeworks_OFAndroid_onKeyDown(JNIEnv* env, jclass thiz, jint keyCode, jint unicode){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return true; ofKeyEventArgs key; key.type = ofKeyEventArgs::Pressed; key.key = unicode; key.keycode = keyCode; key.scancode = keyCode; key.codepoint = unicode; - return window->events().notifyKeyEvent(key); + if(threadedKeyEvents){ + return window->events().notifyKeyEvent(key); + }else{ + keyMtx.lock(); + keyEventArgsQueue.push(key); + keyMtx.unlock(); + return true; // returning key states always true in non-threaded + } + } -jboolean -Java_cc_openframeworks_OFAndroid_onKeyUp(JNIEnv* env, jobject thiz, jint keyCode, jint unicode){ +JNIEXPORT jboolean JNICALL +Java_cc_openframeworks_OFAndroid_onKeyUp(JNIEnv* env, jclass thiz, jint keyCode, jint unicode){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return true; ofKeyEventArgs key; key.type = ofKeyEventArgs::Released; key.key = unicode; key.keycode = keyCode; key.scancode = keyCode; key.codepoint = unicode; - return window->events().notifyKeyEvent(key); + if(threadedKeyEvents){ + return window->events().notifyKeyEvent(key); + }else{ + keyMtx.lock(); + keyEventArgsQueue.push(key); + keyMtx.unlock(); + return true; // returning key states always true in non-threaded + } } -jboolean -Java_cc_openframeworks_OFAndroid_onBackPressed(){ +JNIEXPORT jboolean JNICALL +Java_cc_openframeworks_OFAndroid_onBackPressed(JNIEnv *env, jclass clazz){ return ofxAndroidEvents().backPressed.notify(nullptr); } -jboolean -Java_cc_openframeworks_OFAndroid_onMenuItemSelected( JNIEnv* env, jobject thiz, jstring menu_id){ +JNIEXPORT jboolean JNICALL +Java_cc_openframeworks_OFAndroid_onMenuItemSelected( JNIEnv* env, jclass thiz, jstring menu_id){ jboolean iscopy; const char * menu_id_str = env->GetStringUTFChars(menu_id, &iscopy); if(!menu_id_str) return false; @@ -595,8 +855,8 @@ Java_cc_openframeworks_OFAndroid_onMenuItemSelected( JNIEnv* env, jobject thiz return ofxAndroidEvents().menuItemSelected.notify(nullptr,id_str); } -jboolean -Java_cc_openframeworks_OFAndroid_onMenuItemChecked( JNIEnv* env, jobject thiz, jstring menu_id, jboolean checked){ +JNIEXPORT jboolean JNICALL +Java_cc_openframeworks_OFAndroid_onMenuItemChecked( JNIEnv* env, jclass thiz, jstring menu_id, jboolean checked){ jboolean iscopy; const char *menu_id_str = env->GetStringUTFChars(menu_id, &iscopy); if(!menu_id_str) return false; @@ -604,25 +864,68 @@ Java_cc_openframeworks_OFAndroid_onMenuItemChecked( JNIEnv* env, jobject thiz, return ofxAndroidEvents().menuItemChecked.notify(nullptr,id_str); } -void -Java_cc_openframeworks_OFAndroid_okPressed( JNIEnv* env, jobject thiz ){ +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_okPressed( JNIEnv* env, jclass thiz){ ofNotifyEvent(ofxAndroidEvents().okPressed); } -void -Java_cc_openframeworks_OFAndroid_cancelPressed( JNIEnv* env, jobject thiz ){ +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_cancelPressed( JNIEnv* env, jclass thiz){ ofNotifyEvent(ofxAndroidEvents().cancelPressed); } -void -Java_cc_openframeworks_OFAndroid_networkConnected( JNIEnv* env, jobject thiz, jboolean connected){ +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_networkConnected( JNIEnv* env, jclass thiz, jboolean connected){ bool bConnected = (bool)connected; ofNotifyEvent(ofxAndroidEvents().networkConnected,bConnected); } -void +JNIEXPORT void JNICALL Java_cc_openframeworks_OFAndroid_deviceOrientationChanged(JNIEnv* env, jclass thiz, jint orientation){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; ofOrientation _orientation = (ofOrientation) orientation; ofNotifyEvent(ofxAndroidEvents().deviceOrientationChanged,_orientation ); } + +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_deviceHighestRefreshRate(JNIEnv* env, jclass thiz, jint refreshRate){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; + int _refreshRate = (int) refreshRate; + ofLogNotice("oF") << "deviceHighestRefreshRate:" << _refreshRate; + // ofNotifyEvent(ofxAndroidEvents().deviceHighestRefreshRate,_refreshRate ); +} + + +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_deviceRefreshRate(JNIEnv* env, jclass thiz, jint refreshRate){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; + ofLogNotice("oF") << "deviceRefreshRateChanged:" << refreshRate; + int _refreshRate = (int) refreshRate; + //ofNotifyEvent(ofxAndroidEvents().deviceRefreshRate,_refreshRate ); +} + +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_setSampleSize(JNIEnv* env, jclass thiz, jint sampleSize){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; + ofLogNotice("oF") << "setSampleSize:" << sampleSize; + window->setSampleSize(sampleSize); +} + +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onAxisMoved(JNIEnv* env, jclass thiz, jint id, jint deviceid, jint productid, jfloat x, jfloat y){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; + //ofLogNotice("oF") << "axisMoved:[" << id << "] x:" << x << " y:" << y; + +} + + +JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_setMultiWindowMode(JNIEnv* env, jclass thiz, jboolean multiWindow){ + if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) return; + bool bMultiWindow = (bool)multiWindow; + ofLogNotice("oF") << "setMultiWindowMode:" << bMultiWindow; + window->setMultiWindowMode(bMultiWindow); +} + + } diff --git a/addons/ofxAndroid/src/ofAppAndroidWindow.h b/addons/ofxAndroid/src/ofAppAndroidWindow.h index 870cf39930d..cae62bac8c0 100644 --- a/addons/ofxAndroid/src/ofAppAndroidWindow.h +++ b/addons/ofxAndroid/src/ofAppAndroidWindow.h @@ -11,6 +11,8 @@ #include "ofEvents.h" #include "ofConstants.h" #include "ofTypes.h" +#include +#include class ofxAndroidWindowSettings : public ofGLESWindowSettings { @@ -37,12 +39,13 @@ class ofxAndroidWindowSettings : public ofGLESWindowSettings preserveContextOnPause = preserve; } - bool preserveContextOnPause; + bool preserveContextOnPause = true; }; class ofAppAndroidWindow: public ofAppBaseGLESWindow { public: ofAppAndroidWindow(); + ofAppAndroidWindow(ofAppBaseWindow &other); virtual ~ofAppAndroidWindow(); static bool doesLoop(){ return true; } @@ -58,6 +61,8 @@ class ofAppAndroidWindow: public ofAppBaseGLESWindow { void update(); void draw(); + void setCurrentWindow(); + void hideCursor() {} void showCursor() {} @@ -76,6 +81,7 @@ class ofAppAndroidWindow: public ofAppBaseGLESWindow { void setWindowTitle(std::string title){} ofWindowMode getWindowMode() {return OF_WINDOW;} + void makeCurrent(); void setFullscreen(bool fullscreen); void toggleFullscreen(); @@ -86,16 +92,35 @@ class ofAppAndroidWindow: public ofAppBaseGLESWindow { void setOrientation(ofOrientation orientation); ofOrientation getOrientation(); + void setSampleSize(int samples); + int getSamples(); + ofCoreEvents & events(); std::shared_ptr & renderer(); void setThreadedEvents(bool threadedEvents); void setAccumulateTouchEvents(bool accumEvents); + void setMultiWindowMode(bool multiWindowMode); + + bool getIsThreadedEvents(); + bool getIsAccumulateTouchEvents(); + + bool getIsMultiWindowMode(); + + int getGlesVersion(); + AAssetManager& getAssetManager(); + void setAssetManager(AAssetManager* assetManager); + + + private: ofCoreEvents coreEvents; std::shared_ptr currentRenderer; int glesVersion; + int msaaSamples; + AAssetManager* assetManager = nullptr; + }; diff --git a/addons/ofxAndroid/src/ofxAndroidAccelerometer.cpp b/addons/ofxAndroid/src/ofxAndroidAccelerometer.cpp index dd061c70883..d6ae038e558 100644 --- a/addons/ofxAndroid/src/ofxAndroidAccelerometer.cpp +++ b/addons/ofxAndroid/src/ofxAndroidAccelerometer.cpp @@ -5,6 +5,7 @@ * Author: arturo */ + #include #include "ofxAccelerometer.h" #include "ofxAndroidUtils.h" diff --git a/addons/ofxAndroid/src/ofxAndroidApp.h b/addons/ofxAndroid/src/ofxAndroidApp.h index 82516ffdcb1..714d1a4e107 100644 --- a/addons/ofxAndroid/src/ofxAndroidApp.h +++ b/addons/ofxAndroid/src/ofxAndroidApp.h @@ -14,13 +14,19 @@ class ofxAndroidApp: public ofBaseApp{ public: + + virtual void setup(){} virtual void pause(){}; virtual void stop(){}; virtual void resume(){}; virtual void reloadTextures(){} virtual void unloadTextures(){} - virtual void reloadGL(){reloadTextures();} - virtual void unloadGL(){unloadTextures();} + virtual void reloadGL(){ + reloadTextures(); + } + virtual void unloadGL(){ + unloadTextures(); + } virtual void swipe(ofxAndroidSwipeDir swipeDir, int id){ } @@ -43,4 +49,30 @@ class ofxAndroidApp: public ofBaseApp{ virtual void deviceOrientationChangedEvent(ofOrientation & newOrientation){ deviceOrientationChanged(newOrientation); }; + + virtual void deviceRefreshRateChanged(int refreshRate){ + + } + + virtual void deviceHighestRefreshRateChanged(int refreshRate){ + + } + + virtual void deviceRefreshRateChangedEvent(int &refreshRate){ + deviceRefreshRateChanged(refreshRate); + } + + virtual void deviceHighestRefreshRateChangedEvent(int & refreshRate){ + deviceHighestRefreshRateChanged(refreshRate); + } + + virtual void audioIn( ofSoundBuffer& buffer ) { + + } + + virtual void audioOut( ofSoundBuffer& buffer ) { + + } }; + + diff --git a/addons/ofxAndroid/src/ofxAndroidLogChannel.cpp b/addons/ofxAndroid/src/ofxAndroidLogChannel.cpp index 76bcda1d865..60d737e54e5 100644 --- a/addons/ofxAndroid/src/ofxAndroidLogChannel.cpp +++ b/addons/ofxAndroid/src/ofxAndroidLogChannel.cpp @@ -37,5 +37,5 @@ void ofxAndroidLogChannel::log(ofLogLevel level, const string & module, const st androidPrio=ANDROID_LOG_INFO; break; } - __android_log_print(androidPrio,module.c_str(),msg.c_str()); + __android_log_print(androidPrio,module.c_str(),"%s", msg.c_str()); } diff --git a/addons/ofxAndroid/src/ofxAndroidSoundPlayer.cpp b/addons/ofxAndroid/src/ofxAndroidSoundPlayer.cpp index 747495e69c1..60a79b6f884 100644 --- a/addons/ofxAndroid/src/ofxAndroidSoundPlayer.cpp +++ b/addons/ofxAndroid/src/ofxAndroidSoundPlayer.cpp @@ -473,3 +473,13 @@ bool ofxAndroidSoundPlayer::isLoaded() const{ return env->CallBooleanMethod(javaSoundPlayer,javaIsLoadedMethod); } + +float ofxAndroidSoundPlayer::getDuration() const { + ofLogError("ofxAndroidSoundPlayer") << "getDuration(): not implemented"; + return 0.0f; +} + +unsigned int ofxAndroidSoundPlayer::getDurationMS() const { + ofLogError("ofxAndroidSoundPlayer") << "getDurationMS(): not implemented"; + return 0; +} diff --git a/addons/ofxAndroid/src/ofxAndroidSoundPlayer.h b/addons/ofxAndroid/src/ofxAndroidSoundPlayer.h index d077bc21f9d..d11e149bdb0 100644 --- a/addons/ofxAndroid/src/ofxAndroidSoundPlayer.h +++ b/addons/ofxAndroid/src/ofxAndroidSoundPlayer.h @@ -6,30 +6,32 @@ class ofxAndroidSoundPlayer: public ofBaseSoundPlayer{ public: ofxAndroidSoundPlayer(); - virtual ~ofxAndroidSoundPlayer(); + ~ofxAndroidSoundPlayer() override; - bool load(const of::filesystem::path& fileName, bool stream = false); - void unload(); - void play(); - void stop(); + bool load(const of::filesystem::path& fileName, bool stream) override; + void unload() override; + void play() override; + void stop() override; - void setVolume(float vol); - void setPan(float vol); - void setSpeed(float spd); - void setPaused(bool bP); - void setLoop(bool bLp); - void setMultiPlay(bool bMp); - void setPosition(float pct); // 0 = start, 1 = end; - void setPositionMS(int ms); + void setVolume(float vol) override; + void setPan(float vol) override; + void setSpeed(float spd) override; + void setPaused(bool bP) override; + void setLoop(bool bLp) override; + void setMultiPlay(bool bMp) override; + void setPosition(float pct) override; // 0 = start, 1 = end; + void setPositionMS(int ms) override; - float getPosition() const; - int getPositionMS() const; - bool isPlaying() const; - float getSpeed() const; - float getPan() const; + float getPosition() const override; + int getPositionMS() const override; + bool isPlaying() const override; + float getSpeed() const override; + float getPan() const override; bool isPaused() const; - float getVolume() const; - bool isLoaded() const; + float getVolume() const override; + bool isLoaded() const override; + float getDuration() const override; + unsigned int getDurationMS() const override; private: jobject javaSoundPlayer; diff --git a/addons/ofxAndroid/src/ofxAndroidSoundStream.cpp b/addons/ofxAndroid/src/ofxAndroidSoundStream.cpp index ed90517f7f0..4ecc37c638d 100644 --- a/addons/ofxAndroid/src/ofxAndroidSoundStream.cpp +++ b/addons/ofxAndroid/src/ofxAndroidSoundStream.cpp @@ -19,12 +19,12 @@ using namespace std; // Global pointer used to implement the singletomn pattern for ofxAndroidSoundStream class -static ofxAndroidSoundStream* instance = NULL; +static ofxAndroidSoundStream* instance = nullptr; static bool headphonesConnected = false; ofxAndroidSoundStream::ofxAndroidSoundStream(){ - out_buffer = NULL; - in_buffer = NULL; + out_buffer = nullptr; + in_buffer = nullptr; isPaused = false; totalOutRequestedBufferSize = totalInRequestedBufferSize = 0; @@ -37,7 +37,7 @@ ofxAndroidSoundStream::ofxAndroidSoundStream(){ ofxAndroidSoundStream::~ofxAndroidSoundStream(){ if(instance==this){ - instance = NULL; + instance = nullptr; } ofRemoveListener(ofxAndroidEvents().pause,this,&ofxAndroidSoundStream::pause); @@ -62,7 +62,7 @@ void ofxAndroidSoundStream::setOutput(ofBaseSoundOutput * _soundOutput){ } bool ofxAndroidSoundStream::setup(const ofSoundStreamSettings & settings){ - if(instance!=NULL && instance!=this){ + if(instance!=nullptr && instance!=this){ ofLogError("ofxAndroidSoundStream") << "setup(): multiple instances detected, only one instance allowed"; return false; } @@ -324,10 +324,22 @@ bool ofxAndroidSoundStream::isHeadPhonesConnected() const{ return headphonesConnected; } +void ofxAndroidSoundStreamPause() { + +} + +void ofxAndroidSoundStreamResume() { + +} + +void ofxAndroidSoundStream::printDeviceList() const { + +} + extern "C"{ jint -Java_cc_openframeworks_OFAndroidSoundStream_audioOut(JNIEnv* env, jobject thiz, jshortArray array, jint numChannels, jint bufferSize){ +Java_cc_openframeworks_OFAndroidSoundStream_audioOut(JNIEnv* env, jclass thiz, jshortArray array, jint numChannels, jint bufferSize){ if(instance){ return instance->androidOutputAudioCallback(env,thiz,array,numChannels,bufferSize); }else{ @@ -338,7 +350,7 @@ Java_cc_openframeworks_OFAndroidSoundStream_audioOut(JNIEnv* env, jobject thiz jint -Java_cc_openframeworks_OFAndroidSoundStream_audioIn(JNIEnv* env, jobject thiz, jshortArray array, jint numChannels, jint bufferSize){ +Java_cc_openframeworks_OFAndroidSoundStream_audioIn(JNIEnv* env, jclass thiz, jshortArray array, jint numChannels, jint bufferSize){ if(instance){ return instance->androidInputAudioCallback(env,thiz,array,numChannels,bufferSize); }else{ @@ -347,7 +359,7 @@ Java_cc_openframeworks_OFAndroidSoundStream_audioIn(JNIEnv* env, jobject thiz, return 0; } -void Java_cc_openframeworks_OFAndroidSoundStream_headphonesConnected(JNIEnv* env, jobject thiz, jboolean connected){ +void Java_cc_openframeworks_OFAndroidSoundStream_headphonesConnected(JNIEnv* env, jclass thiz, jboolean connected){ headphonesConnected = connected; if(instance) ofNotifyEvent(instance->headphonesConnectedE,headphonesConnected); } diff --git a/addons/ofxAndroid/src/ofxAndroidSoundStream.h b/addons/ofxAndroid/src/ofxAndroidSoundStream.h index cd00a9a22f9..692eb9db21b 100644 --- a/addons/ofxAndroid/src/ofxAndroidSoundStream.h +++ b/addons/ofxAndroid/src/ofxAndroidSoundStream.h @@ -41,6 +41,8 @@ class ofxAndroidSoundStream : public ofBaseSoundStream{ bool isHeadPhonesConnected() const; + void printDeviceList() const; + ofEvent headphonesConnectedE; private: diff --git a/addons/ofxAndroid/src/ofxAndroidUtils.cpp b/addons/ofxAndroid/src/ofxAndroidUtils.cpp index 4d0ca13e2e2..a351cb7f3e7 100644 --- a/addons/ofxAndroid/src/ofxAndroidUtils.cpp +++ b/addons/ofxAndroid/src/ofxAndroidUtils.cpp @@ -445,13 +445,13 @@ void ofxAndroidSetViewItemChecked(string item_name, bool checked){ jclass javaClass = ofGetJavaOFAndroid(); if(javaClass==0){ - ofLog(OF_LOG_ERROR,"ofxAndroidSetViewItemChecked: cannot find OFAndroid java class"); + ofLogError("ofxAndroidUtils") <<"ofxAndroidSetViewItemChecked: cannot find OFAndroid java class"; return; } jmethodID setViewItemChecked = ofGetJNIEnv()->GetStaticMethodID(javaClass,"setViewItemChecked","(Ljava/lang/String;Z)V"); if(!setViewItemChecked){ - ofLog(OF_LOG_ERROR,"cannot find OFAndroid setViewItemChecked method"); + ofLogError("ofxAndroidUtils") <<"cannot find OFAndroid setViewItemChecked method"; return; } ofGetJNIEnv()->CallStaticVoidMethod(javaClass,setViewItemChecked,ofGetJNIEnv()->NewStringUTF(item_name.c_str()),checked); diff --git a/addons/ofxAndroid/src/ofxAndroidUtils.h b/addons/ofxAndroid/src/ofxAndroidUtils.h index f56cddffa40..6dc931d0dfa 100644 --- a/addons/ofxAndroid/src/ofxAndroidUtils.h +++ b/addons/ofxAndroid/src/ofxAndroidUtils.h @@ -181,6 +181,8 @@ class ofxAndroidEventsClass{ ofEvent backPressed; ofEvent networkConnected; ofEvent deviceOrientationChanged; + ofEvent deviceRefreshRate; + ofEvent deviceHighestRefreshRate; /** The names start, stop, resume and pause correspond to Android Activity class lifecycle callbacks. diff --git a/addons/ofxAndroid/src/ofxAndroidVibrator.cpp b/addons/ofxAndroid/src/ofxAndroidVibrator.cpp index 6f166d228f7..e634db3fb42 100644 --- a/addons/ofxAndroid/src/ofxAndroidVibrator.cpp +++ b/addons/ofxAndroid/src/ofxAndroidVibrator.cpp @@ -10,7 +10,6 @@ #include "ofLog.h" #include -using namespace std; ofxAndroidVibrator::ofxAndroidVibrator() { // TODO Auto-generated constructor stub @@ -25,7 +24,7 @@ jobject ofxAndroidVibrator::getVibratorService(){ jobject activity = ofGetOFActivityObject(); jclass contextClass = ofGetJNIEnv()->FindClass("android/content/Context"); if(!contextClass){ - ofLogError("ofxAndroidVibrator") << "getVibratorService(): couldn't get Context class"; + ofLog(OF_LOG_ERROR) << "getVibratorService(): couldn't get Context class"; return 0; } jmethodID method = ofGetJNIEnv()->GetMethodID(contextClass,"getSystemService","(Ljava/lang/String;)Ljava/lang/Object;"); @@ -52,7 +51,7 @@ jobject ofxAndroidVibrator::getVibratorService(){ return vibratorService; } -jmethodID ofxAndroidVibrator::getVibratorMethodID(string name, string signature){ +jmethodID ofxAndroidVibrator::getVibratorMethodID(std::string name, std::string signature){ jclass vibratorClass = ofGetJNIEnv()->FindClass("android/os/Vibrator"); if(!vibratorClass){ ofLogError("ofxAndroidVibrator") << "getVibratorMethodID(): couldn't get Vibrator class"; diff --git a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp index 94348754a1e..f5201c37fb8 100644 --- a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp +++ b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp @@ -66,11 +66,11 @@ static void ConvertYUV2toRGB565(unsigned char* yuvs, unsigned char* rgbs, int wi ofxAndroidVideoGrabber::Data::Data() :bIsFrameNew(false) ,bGrabberInited(false) +,bUsePixels(true) ,cameraId(-1) ,appPaused(false) ,newPixels(false) ,attemptFramerate(-1) -,bUsePixels(true) ,javaVideoGrabber(nullptr){ JNIEnv *env = ofGetJNIEnv(); @@ -538,10 +538,10 @@ ofPixelFormat ofxAndroidVideoGrabber::getPixelFormat() const{ void ConvertYUV2RGB(unsigned char *src0,unsigned char *src1,unsigned char *dst_ori, int width,int height) { - register int y1,y2,u,v; - register unsigned char *py1,*py2; - register int i,j, c1, c2, c3, c4; - register unsigned char *d1, *d2; + int y1,y2,u,v; + unsigned char *py1,*py2; + int i,j, c1, c2, c3, c4; + unsigned char *d1, *d2; int width3 = 3*width; py1=src0; @@ -614,11 +614,11 @@ void ConvertYUV2toRGB565(unsigned char* yuvs, unsigned char* rgbs, int width, in int outPtr = 0; //the end of the current luminance scanline int lineEnd = width; - register int R, G, B; - register int Y1; - register int Y2; - register int Cr; - register int Cb; + int R, G, B; + int Y1; + int Y2; + int Cr; + int Cb; while (true) { @@ -662,11 +662,11 @@ void ConvertYUV2toRGB565(unsigned char* yuvs, unsigned char* rgbs, int width, in void ConvertYUV2toRGB565_2(unsigned char *src0,unsigned char *src1,unsigned char *dst_ori, int width,int height) { - register int y1,y2,u,v; - register unsigned char *py1,*py2; - register int i,j, c1, c2, c3, c4; - register unsigned char *d1, *d2; - register int R,G,B; + int y1,y2,u,v; + unsigned char *py1,*py2; + int i,j, c1, c2, c3, c4; + unsigned char *d1, *d2; + int R,G,B; int width2 = 2*width; py1=src0; py2=py1+width; diff --git a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.h b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.h index 6beab76cf86..65c0875df24 100644 --- a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.h +++ b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.h @@ -89,6 +89,6 @@ class ofxAndroidVideoGrabber: public ofBaseVideoGrabber{ bool initCamera(); // only to be used internally to resize; - ofPixelsRef getAuxBuffer(); + //ofPixelsRef getAuxBuffer(); std::shared_ptr data; }; diff --git a/addons/ofxXmlSettings/src/ofxXmlSettings.cpp b/addons/ofxXmlSettings/src/ofxXmlSettings.cpp index 2cf16dfb5a2..1f413364fc0 100644 --- a/addons/ofxXmlSettings/src/ofxXmlSettings.cpp +++ b/addons/ofxXmlSettings/src/ofxXmlSettings.cpp @@ -565,7 +565,7 @@ string ofxXmlSettings::getAttribute(const string& tag, const string& attribute, //--------------------------------------------------------- int ofxXmlSettings::setAttribute(const string& tag, const string& attribute, int value, int which){ char valueStr[255]; - sprintf(valueStr, "%i", value); + snprintf(valueStr, 255, "%i", value); int tagID = writeAttribute(tag, attribute, valueStr, which) -1; return tagID; } @@ -573,7 +573,7 @@ int ofxXmlSettings::setAttribute(const string& tag, const string& attribute, int //--------------------------------------------------------- int ofxXmlSettings::setAttribute(const string& tag, const string& attribute, double value, int which){ char valueStr[255]; - sprintf(valueStr, "%lf", value); + snprintf(valueStr, 255, "%lf", value); int tagID = writeAttribute(tag, attribute, valueStr, which) -1; return tagID; } diff --git a/addons/ofxiOS/src/sound/AVSoundPlayer.m b/addons/ofxiOS/src/sound/AVSoundPlayer.m index abe00af3eca..ae155558387 100644 --- a/addons/ofxiOS/src/sound/AVSoundPlayer.m +++ b/addons/ofxiOS/src/sound/AVSoundPlayer.m @@ -39,18 +39,13 @@ - (void) setupSharedSession { NSError * err = nil; // need to configure set the audio category, and override to it route the audio to the speaker if([audioSession respondsToSelector:@selector(setCategory:withOptions:error:)]) { -#if defined (TARGET_OS_TV) || defined (TARGET_OS_WATCH) - if(![audioSession setCategory:playbackCategory - withOptions:(AVAudioSessionCategoryOptionMixWithOthers) - error:&err]) { err = nil; } -#else + if(![audioSession setCategory:playbackCategory withOptions:(AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionAllowAirPlay | AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowBluetoothA2DP) error:&err]) { err = nil; } -#endif } [[AVAudioSession sharedInstance] setActive: YES error: nil]; audioSessionSetup = YES; @@ -262,7 +257,7 @@ - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player - (void) audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags { #if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) - if(flags == AVAudioSessionInterruptionFlags_ShouldResume) { + if(flags == AVAudioSessionInterruptionOptionShouldResume) { [self.player play]; } #elif TARGET_OS_TV diff --git a/examples/android/androidCameraExample/AndroidManifest.xml b/examples/android/androidCameraExample/AndroidManifest.xml deleted file mode 100644 index 22149eaa59c..00000000000 --- a/examples/android/androidCameraExample/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/android/androidCameraExample/build.gradle b/examples/android/androidCameraExample/build.gradle new file mode 100644 index 00000000000..7cbc7eb6714 --- /dev/null +++ b/examples/android/androidCameraExample/build.gradle @@ -0,0 +1,22 @@ +ext { + //var = 'signExample.keystore' +}// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.4.2' + } +} + +allprojects { + repositories { + google() + mavenCentral() + } + ext { + + } +} diff --git a/examples/android/androidCameraExample/gradle.properties b/examples/android/androidCameraExample/gradle.properties new file mode 100644 index 00000000000..43f9ef9e1c3 --- /dev/null +++ b/examples/android/androidCameraExample/gradle.properties @@ -0,0 +1,10 @@ +android.useAndroidX=true +android.enableJetifier=false +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +kotlin.code.style=official +android.prefabVersion=1.0.+ +android.buildFeatures.prefab=true +#ndkBuild=false +# https://issuetracker.google.com/149575364 +android.enableParallelJsonGen=false +#googleplay=true \ No newline at end of file diff --git a/examples/android/androidCameraExample/gradle/wrapper/gradle-wrapper.jar b/examples/android/androidCameraExample/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..13372aef5e2 Binary files /dev/null and b/examples/android/androidCameraExample/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/android/androidCameraExample/gradle/wrapper/gradle-wrapper.properties b/examples/android/androidCameraExample/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..2dd5ee8c795 --- /dev/null +++ b/examples/android/androidCameraExample/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Jun 12 01:17:57 AEST 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/android/androidCameraExample/gradlew b/examples/android/androidCameraExample/gradlew new file mode 100755 index 00000000000..9d82f789151 --- /dev/null +++ b/examples/android/androidCameraExample/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/examples/android/androidCameraExample/gradlew.bat b/examples/android/androidCameraExample/gradlew.bat new file mode 100644 index 00000000000..8a0b282aa68 --- /dev/null +++ b/examples/android/androidCameraExample/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/android/androidCameraExample/ofApp/build.gradle b/examples/android/androidCameraExample/ofApp/build.gradle new file mode 100644 index 00000000000..50b511c1c1f --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/build.gradle @@ -0,0 +1,182 @@ +plugins { + id 'com.android.application' +} + +def CMAKELIST_PATH = './src/main/cpp' +def CPP_SOURCE = './src/main/cpp' +def JAVA_SOURCE = './src/main/java' + +// pointing to cmake's source code for the same project +def PRJ_SRC_ROOT = './src/main' +def ofRoot(){ return '../../../../' } +final ofSource = ofRoot() + 'libs/openFrameworks' +final ofLibs = ofRoot() + 'libs' +final addons = ofRoot() + 'addons' +final ofLibOutput = ofRoot() + 'libs/openFrameworksCompiled/lib/android' +def OFX_ANDROID = ofRoot() + 'addons/ofxAndroid' +//def OF_ADDONS_ARGUMENTS = "${OF_ADDONS}" +def enableProguardInReleaseBuilds = true +def enableProguardInDebugBuilds = false + +task wrapper(type: Wrapper) { + gradleVersion = '7.3.3' +} +tasks.register("prepareKotlinBuildScriptModel"){ +} + +evaluationDependsOn(':openFrameworksProject') + +tasks.whenTaskAdded { task -> + if (task.name == 'assemble') { + task.dependsOn(':openFrameworksProject:assemble') + } +} + + +android { + compileSdkVersion 34 + buildToolsVersion '32.0.0' + //ndkPath "/Users/x/android-ndk-r21e" // Point to your own NDK if needed + ndkVersion '24.0.8215888' // use android studio side loaded ndk + buildFeatures { + prefab true + } + signingConfigs { + debug { + } + release { + storeFile new File("${System.properties['user.home']}/.android/debug.keystore") + storePassword 'android' + storeType "jks" + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + defaultConfig { + applicationId "cc.openframeworks.androidCameraExample" // IMPORTANT : THIS DEFINES THE ID OF THE APK + minSdkVersion 21 + targetSdkVersion 34 + versionCode 12 + versionName '12.0' + ndk.abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86' //, 'x86_64' + + externalNativeBuild { + if (!project.hasProperty("ndkBuild")) { + cmake { + arguments "-DANDROID_STL=c++_shared", + "-DANDROID_ARM_NEON=TRUE", + "-DANDROID_TOOLCHAIN=clang", + //"${OF_ADDONS_ARGUMENTS}", + "-DTARGET_OPENGLES=TRUE" + + version '3.22.1' + } + } + } + multiDexEnabled false + } + buildTypes { + release { + signingConfig signingConfigs.release + jniDebuggable false + debuggable false + minifyEnabled false + shrinkResources false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + } + debug { + jniDebuggable true + debuggable true + minifyEnabled false + shrinkResources false + signingConfig signingConfigs.debug + } + } + flavorDimensions "version" + productFlavors { + playstore { + applicationIdSuffix "" + signingConfig signingConfigs.release + } +// humble { +// applicationIdSuffix ".humble" +// } +// amazon { +// applicationIdSuffix ".amazon" +// } +// samsung { +// applicationIdSuffix ".samsung" +// } +// oppo { +// applicationIdSuffix ".oppo" +// } + } + sourceSets { + main { + manifest.srcFile "${PRJ_SRC_ROOT}/AndroidManifest.xml" + java.srcDirs = ["${PRJ_SRC_ROOT}/java", + "${OFX_ANDROID}/Java"] + res.srcDirs = ["${PRJ_SRC_ROOT}/res"] +// jniLibs.srcDirs = ["${OF_ANDROID_OUTPUT}", "lib"] // Pre Android Studio 2022.2.1 + assets { + srcDirs 'src/main/assets', 'src/main/bin/data' + } + } + } + externalNativeBuild { + if (!project.hasProperty("ndkBuild")) { + cmake { + path "${CMAKELIST_PATH}/CMakeLists.txt" + } + } else { + ndkBuild { + path "${CMAKELIST_PATH}/Android.mk" + } + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + androidResources { + noCompress '' + } + dependenciesInfo { + includeInApk false + includeInBundle false + } +// testOptions { +// devices { +// pixel2api29 (com.android.build.api.dsl.ManagedVirtualDevice) { +// // Use device profiles you typically see in +// // Android Studio +// device = "Pixel 2" +// apiLevel = 29 +// // You can also specify "aosp" if you don’t require +// // Google Play Services. +// systemImageSource = "google" +// abi = "x86" +// } +// } +// } +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation "com.getkeepsafe.relinker:relinker:1.4.5" + implementation 'com.google.android.material:material:1.9.0' + if (project.hasProperty("googleplay")) { + implementation "com.google.android.gms:play-services-games:22.0.1" + implementation "com.google.android.gms:play-services-auth:20.0.1" + implementation "com.google.android.gms:play-services-base:18.0.1" + implementation "com.google.android.gms:play-services-basement:18.0.0" + implementation "com.google.android.gms:play-services-instantapps:18.0.1" + implementation "com.google.android.gms:play-services-appset:16.0.2" + } +} + diff --git a/examples/android/androidCameraExample/ofApp/proguard-rules.pro b/examples/android/androidCameraExample/ofApp/proguard-rules.pro new file mode 100644 index 00000000000..de8c62143ce --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/proguard-rules.pro @@ -0,0 +1,127 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +-dontoptimize +-dontshrink +#-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +#-verbose +# +-optimizationpasses 7 # use for final build +-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +-verbose + +# custom app activity proguard +-keep public class cc.openframeworks.android.OFActivity { public ; } +-keep public class cc.openframeworks.android.R { public ; } + + +#-dontobfuscate android classes +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference + +#-dontobfuscate openFrameworks android classes +-keep public class cc.openframeworks.OFAndroid { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycleHelper { public ; } +-keep public class cc.openframeworks.OFAndroidWindow { public ; } +-keep public class cc.openframeworks.OFAndroidSoundPlayer { public ; } +-keep public class cc.openframeworks.OFGLSurfaceView { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycle { public ; } +-keep public class cc.openframeworks.OFActivity { public ; } +-keep public class cc.openframeworks.ContextFactory { public ; } +-keep public class cc.openframeworks.OFEGLConfigChooser { public ; } +-keep public class cc.openframeworks.OFGestureListener { public ; } +-keep public class cc.openframeworks.OFAndroidController { public ; } + +#-dontobfuscate GooglePlay Games android classes if used +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +-keep class com.google.android.gms.common.api.** { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +# note that means any method +-keepclasseswithmembernames,includedescriptorclasses class * { + native ; +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/android/androidCameraExample/ofApp/src/main/AndroidManifest.xml b/examples/android/androidCameraExample/ofApp/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..d29c44958e7 --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/AndroidManifest.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/android/androidCameraExample/ofApp/src/main/cpp/CMakeLists.txt b/examples/android/androidCameraExample/ofApp/src/main/cpp/CMakeLists.txt new file mode 100644 index 00000000000..5b160ffa42d --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/cpp/CMakeLists.txt @@ -0,0 +1,142 @@ +# Sets the minimum version of CMake required to build the native +# library. +cmake_minimum_required(VERSION 3.22.1) + +project(ofapp LANGUAGES CXX) +set(TARGET_ANDROID TRUE) + +set(LOCAL_PATH ${CMAKE_SOURCE_DIR}) +set(PRJ_OF_ROOT ${LOCAL_PATH}/../../../../../../../) + +set(PURE_OF_ROOT ${LOCAL_PATH}/../../../../../../../) +set(CORE_OF_ROOT ${PURE_OF_ROOT}/libs/openFrameworks) +set(LIBS_ROOT ${PURE_OF_ROOT}/libs) + +set(PRJ_ADDONS_PATH ${PURE_OF_ROOT}/addons) +set(PRJ_SOURCE_PATH ${LIBS_ROOT}/openFrameworks) +set(PRJ_LIBS_ROOT ${PURE_OF_ROOT}/libs) + +set(OF_ANDROID ${PURE_OF_ROOT}/libs/openFrameworksCompiled/project/android) +set(OF_ANDROID_OUTPUT ${PURE_OF_ROOT}/libs/openFrameworksCompiled/lib/android) + +set(PRJ_OFX_ANDROID_PATH ${PRJ_ADDONS_PATH}/ofxAndroid) +set(PRJ_OFX_ANDROID_CPP_PATH ${PRJ_OFX_ANDROID_PATH}/src) + +macro(print_all_variables) + message(STATUS "print_all_variables------------------------------------------{") + get_cmake_property(_variableNames VARIABLES) + foreach (_variableName ${_variableNames}) + message(STATUS "${_variableName}=${${_variableName}}") + endforeach() + message(STATUS "print_all_variables------------------------------------------}") +endmacro() + +# Custom function to check if the library is built +function(check_library) + if (NOT TARGET openFrameworksAndroid) + message(STATUS "openFrameworksAndroid Library not found. Building library...") + + # Invoke the build process for the library + execute_process( + COMMAND ${CMAKE_COMMAND} --build ${OF_ANDROID}/ + RESULT_VARIABLE result + ) + if (result) + message(FATAL_ERROR "Failed to build the library.") + endif () + endif () +endfunction() + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS ON) +set(TARGET_ANDROID ON) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c17 -Oz -DNDEBUG -frtti --warn-uninitialized -fno-short-enums -Wextra -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") +set(CMAKE_CPP_FLAGS "${CMAKE_C_FLAGS} -std=c++17 -Oz -DNDEBUG -stdlib=libc++ --warn-uninitialized -frtti -Wextra -fno-short-enums -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-export-dynamic") + +print_all_variables() + +# Creates the project's shared lib: libnative-lib.so. +# The lib is loaded by this project's Java code in MainActivity.java: +# System.loadLibrary("native-lib"); +# The lib name in both places must match. +add_library( ofapp #name + SHARED # type of library + # src files for project (just c/cpp) + ${CMAKE_SOURCE_DIR}/main.cpp + ${CMAKE_SOURCE_DIR}/ofApp.cpp + ) + + +# Specifies a path to native header files +include_directories( + # openFrameworks headers + ${PRJ_SOURCE_PATH}/3d + ${PRJ_SOURCE_PATH}/app + ${PRJ_SOURCE_PATH}/communication + ${PRJ_SOURCE_PATH}/events + ${PRJ_SOURCE_PATH}/gl + ${PRJ_SOURCE_PATH}/graphics + ${PRJ_SOURCE_PATH}/math + ${PRJ_SOURCE_PATH}/sound + ${PRJ_SOURCE_PATH}/types + ${PRJ_SOURCE_PATH}/utils + ${PRJ_SOURCE_PATH}/video + ${PRJ_SOURCE_PATH} + # openFrameworks addons includes + ${PURE_OF_ROOT}/addons/ofxAndroid/src + ${PURE_OF_ROOT}/addons/ofxAccelerometer/src + ${PURE_OF_ROOT}/addons/ofxXmlSettings/src + ${PURE_OF_ROOT}/addons/ofxXmlSettings/libs + # openFrameworks Libs includes + ${PRJ_LIBS_ROOT}/FreeImage/include + ${PRJ_LIBS_ROOT}/freetype/include + ${PRJ_LIBS_ROOT}/freetype/include/freetype2 + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/config + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal/services + ${PRJ_LIBS_ROOT}/glm/include + ${PRJ_LIBS_ROOT}/pugixml/include + ${PRJ_LIBS_ROOT}/json/include + ${PRJ_LIBS_ROOT}/tess2/include + ${PRJ_LIBS_ROOT}/utf8/include + ${PRJ_LIBS_ROOT}/uriparser/include + ${CMAKE_SOURCE_DIR}/ + ${CMAKE_SOURCE_DIR}/ + ${OF_ANDROID} +) + +find_library(android-lib android) +find_library(log-lib log) +find_library(GLES2-lib GLESv2) + +#find_library(GLES1-lib GLESv1_CM) +#find_library(GLES3-lib GLESv3) + + +target_link_libraries(ofapp + EGL + GLESv2 + log + c + m + z + dl +# GLESv3 + ) + +target_link_libraries( ofapp + ${android-lib} ) +target_link_libraries( ofapp + ${GLES2-lib} ) +target_link_libraries( ofapp + ${log-lib} ) +#target_link_libraries( ofApp +# ${GLES3-lib} ) +#target_link_libraries( ofApp +# ${GLES1-lib} ) + +# Finally link in openFrameworks Library for each ABI +target_link_libraries( ofapp + ${OF_ANDROID_OUTPUT}/${ANDROID_ABI}/libopenFrameworksAndroid.so) diff --git a/examples/android/androidCameraExample/ofApp/src/main/cpp/main.cpp b/examples/android/androidCameraExample/ofApp/src/main/cpp/main.cpp new file mode 100644 index 00000000000..f98043c5a8c --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/cpp/main.cpp @@ -0,0 +1,49 @@ +#include "ofMain.h" +#include "ofApp.h" + +#ifdef TARGET_ANDROID + +#include "ofWindowSettings.h" +#include "ofGLProgrammableRenderer.h" + +shared_ptr *ofapp; +std::shared_ptr baseWindow; + +//-------------------------------------------------------------- +int main(int argc, char **argv) { + baseWindow = std::make_shared(); + ofxAndroidWindowSettings settings; + settings.glesVersion = 2; + settings.setSize(1920, 1080); + settings.windowMode = OF_WINDOW; + settings.preserveContextOnPause = true; + baseWindow = ofCreateWindow(settings); + ofapp = new shared_ptr(new ofApp()); + ofRunApp(baseWindow, *ofapp); + return 0; +} + +void ofAndroidApplicationInit() +{ + //application scope init +} +void ofAndroidActivityInit() +{ + //activity scope init - call main + main(0, nullptr); +} + +// Callbacks from Android Layer +extern "C" JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_init( JNIEnv* env, jclass clazz) +{ + ofAndroidApplicationInit(); +} + +extern "C" JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onCreate( JNIEnv* env, jclass clazz) +{ + ofAndroidActivityInit(); +} + +#endif diff --git a/examples/android/androidCameraExample/src/ofApp.cpp b/examples/android/androidCameraExample/ofApp/src/main/cpp/ofApp.cpp similarity index 92% rename from examples/android/androidCameraExample/src/ofApp.cpp rename to examples/android/androidCameraExample/ofApp/src/main/cpp/ofApp.cpp index f706cfb561c..89f4a751b0c 100644 --- a/examples/android/androidCameraExample/src/ofApp.cpp +++ b/examples/android/androidCameraExample/ofApp/src/main/cpp/ofApp.cpp @@ -3,7 +3,11 @@ //-------------------------------------------------------------- void ofApp::setup(){ - ofBackground(0,0,0); + + ofBackground(255,255,255); + ofSetVerticalSync(false); + ofEnableAlphaBlending(); + // List devices // The device name contains information about the direction of the camera @@ -29,6 +33,10 @@ void ofApp::setup(){ } } +void ofApp::exit(){ + +} + //-------------------------------------------------------------- void ofApp::update(){ grabber.update(); @@ -109,13 +117,13 @@ void ofApp::draw(){ } //-------------------------------------------------------------- -void ofApp::keyPressed (int key){ - +void ofApp::keyPressed (int key){ + } //-------------------------------------------------------------- -void ofApp::keyReleased(int key){ - +void ofApp::keyReleased(int key){ + } //-------------------------------------------------------------- @@ -205,3 +213,19 @@ void ofApp::okPressed(){ void ofApp::cancelPressed(){ } + +void ofApp::deviceRefreshRateChanged(int refreshRate) { + +} + +void ofApp::deviceHighestRefreshRateChanged(int refreshRate) { + +} + +void ofApp::deviceRefreshRateChangedEvent(int &refreshRate) { + +} + +void ofApp::deviceHighestRefreshRateChangedEvent(int &refreshRate) { + +} diff --git a/examples/android/androidCameraExample/src/ofApp.h b/examples/android/androidCameraExample/ofApp/src/main/cpp/ofApp.h similarity index 77% rename from examples/android/androidCameraExample/src/ofApp.h rename to examples/android/androidCameraExample/ofApp/src/main/cpp/ofApp.h index eaa053f9de1..6ae48afee1b 100644 --- a/examples/android/androidCameraExample/src/ofApp.h +++ b/examples/android/androidCameraExample/ofApp/src/main/cpp/ofApp.h @@ -8,9 +8,10 @@ class ofApp : public ofxAndroidApp{ public: void setup(); + void exit(); void update(); void draw(); - + void keyPressed(int key); void keyReleased(int key); void windowResized(int w, int h); @@ -32,6 +33,11 @@ class ofApp : public ofxAndroidApp{ void okPressed(); void cancelPressed(); + void deviceRefreshRateChanged(int refreshRate); + void deviceHighestRefreshRateChanged(int refreshRate); + void deviceRefreshRateChangedEvent(int &refreshRate); + void deviceHighestRefreshRateChangedEvent(int & refreshRate); + ofVideoGrabber grabber; // Image storing a clone of the grabber image @@ -42,5 +48,4 @@ class ofApp : public ofxAndroidApp{ int cameraOrientation; int appOrientation; - }; diff --git a/examples/android/androidCameraExample/ofApp/src/main/ic_launcher-playstore.png b/examples/android/androidCameraExample/ofApp/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000000..2a0df19f5e0 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/ic_launcher-playstore.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java b/examples/android/androidCameraExample/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java new file mode 100644 index 00000000000..598ee50bbf1 --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java @@ -0,0 +1,201 @@ +package cc.openframeworks.android; + +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; + +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; + +import cc.openframeworks.OFAndroid; +import cc.openframeworks.OFAndroidLifeCycle; + +import com.getkeepsafe.relinker.ReLinker; + + + +public class OFActivity extends cc.openframeworks.OFActivity { + + private static final String appName = "ofapp"; // modify this to target appName (ofApp etc) + private static final String LOG_TAG = appName + "::OFActivity"; + + private ReLinker.Logger logcatLogger = new ReLinker.Logger() { + @Override + public void log(String message) { + Log.d("ReLinker", message); + } + }; + private OFActivity thisActivity; + + + // Extremely important + public OFActivity() { + OFAndroidLifeCycle.coreLibraryLoaded = true; + + OFAndroid.maxSamples = 4; + OFAndroid.maximumFrameRate = 144; + + thisActivity = this; + ReLinker.log(logcatLogger) + .force() + .recursively() + .loadLibrary(this, appName, new ReLinker.LoadListener() { + @Override + public void success() { + Log.i(LOG_TAG, "loadLibrary success"); + OFAndroidLifeCycle.appLibraryLoaded = true; + Setup(); // very important - this will in turn call main + } + + @Override + public void failure(Throwable t) { + /* Boo */ + Log.i(LOG_TAG, "loadLibrary failure" + t.getMessage()); + } + }); + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + Log.i(LOG_TAG, "onCreate"); + super.onCreate(savedInstanceState); + + setFullscreen(); + hideSystemBars(); + } + + @Override + public void onStart() { + super.onStart(); + + } + + @Override + public void onDetachedFromWindow() { + + } + + // Menus + // http://developer.android.com/guide/topics/ui/menus.html + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Create settings menu options from here, one by one or infalting an xml + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // This passes the menu option string to OF + // you can add additional behavior from java modifying this method + // but keep the call to OFAndroid so OF is notified of menu events + if(OFAndroid.menuItemSelected(item.getItemId())){ + + return true; + } + return super.onOptionsItemSelected(item); + } + + + @Override + public boolean onPrepareOptionsMenu (Menu menu){ + // This method is called every time the menu is opened + // you can add or remove menu options from here + return super.onPrepareOptionsMenu(menu); + } + + public void onRestore() { + + if (!OFAndroidLifeCycle.appLibraryLoaded) return; + } + + private void hideSystemBars() { + WindowInsetsControllerCompat windowInsetsController = + ViewCompat.getWindowInsetsController(getWindow().getDecorView()); + if (windowInsetsController == null) { + return; + } + // Configure the behavior of the hidden system bars + windowInsetsController.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + ); + // Hide both the status bar and the navigation bar + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + + if (hasFocus) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + + setFullscreen(); + } else { + setFullscreen(); + } + } else { + + } + } + + private void handleException(Exception e, String details) { + Log.e(LOG_TAG, "Exception:", e); + + } + + public void setFullscreen() { + try { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + // No sticky immersive mode for devices pre-kitkat + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } else { + View decorView = getWindow().getDecorView(); +// int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; + int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + decorView.setSystemUiVisibility(uiOptions); + } + + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + + } catch (Exception ex) { + handleException(ex, "setFullscreen exception"); + } + + try { + View decorView = getWindow().getDecorView(); + int[] locations = new int[2]; + decorView.getLocationInWindow(locations); + int[] locations2 = new int[2]; + decorView.getLocationOnScreen(locations2); + + } catch (Exception ex) { + handleException(ex, "setFullscreen exception"); + } + + WindowInsetsControllerCompat windowInsetsController = + ViewCompat.getWindowInsetsController(getWindow().getDecorView()); + if (windowInsetsController == null) { + return; + } + // Hide both the status bar and the navigation bar + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); + windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars()); + windowInsetsController.hide(WindowInsetsCompat.Type.statusBars()); + } + + +} + diff --git a/scripts/templates/android/res/drawable/ic_launcher.png b/examples/android/androidCameraExample/ofApp/src/main/res/drawable-hdpi/icon.png similarity index 100% rename from scripts/templates/android/res/drawable/ic_launcher.png rename to examples/android/androidCameraExample/ofApp/src/main/res/drawable-hdpi/icon.png diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/drawable-mdpi/icon.png b/examples/android/androidCameraExample/ofApp/src/main/res/drawable-mdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/drawable-mdpi/icon.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/drawable-xhdpi/icon.png b/examples/android/androidCameraExample/ofApp/src/main/res/drawable-xhdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/drawable-xhdpi/icon.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/drawable/icon.png b/examples/android/androidCameraExample/ofApp/src/main/res/drawable/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/drawable/icon.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/layout/main_layout.xml b/examples/android/androidCameraExample/ofApp/src/main/res/layout/main_layout.xml new file mode 100644 index 00000000000..d1da461f079 --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/res/layout/main_layout.xml @@ -0,0 +1,24 @@ + + + + + + diff --git a/scripts/templates/android/res/menu/main_layout.xml b/examples/android/androidCameraExample/ofApp/src/main/res/menu/main_layout.xml similarity index 100% rename from scripts/templates/android/res/menu/main_layout.xml rename to examples/android/androidCameraExample/ofApp/src/main/res/menu/main_layout.xml diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000000..036d09bc5fd --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000000..036d09bc5fd --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000000..42b40d2fbec Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..648779fe415 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000000..a39d8826804 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000000..13e6dfef882 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..67b93c29890 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000000..93401eaf855 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000000..018f9b90738 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..fc64ec1c838 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..486c62f1f2a Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000000..cf6c612f8b1 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..07b98443e1b Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..b4024c5aa00 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000000..60b1a9e8332 Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..45bd0178fee Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..1b64c2ce02d Binary files /dev/null and b/examples/android/androidCameraExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/values-v11/strings.xml b/examples/android/androidCameraExample/ofApp/src/main/res/values-v11/strings.xml new file mode 100644 index 00000000000..34312396338 --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/res/values-v11/strings.xml @@ -0,0 +1,5 @@ + + + ofCameraEx + Menu + \ No newline at end of file diff --git a/scripts/templates/android/res/values-v11/styles.xml b/examples/android/androidCameraExample/ofApp/src/main/res/values-v11/styles.xml similarity index 100% rename from scripts/templates/android/res/values-v11/styles.xml rename to examples/android/androidCameraExample/ofApp/src/main/res/values-v11/styles.xml diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/values-v14/strings.xml b/examples/android/androidCameraExample/ofApp/src/main/res/values-v14/strings.xml new file mode 100644 index 00000000000..34312396338 --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/res/values-v14/strings.xml @@ -0,0 +1,5 @@ + + + ofCameraEx + Menu + \ No newline at end of file diff --git a/scripts/templates/android/res/values-v14/styles.xml b/examples/android/androidCameraExample/ofApp/src/main/res/values-v14/styles.xml similarity index 100% rename from scripts/templates/android/res/values-v14/styles.xml rename to examples/android/androidCameraExample/ofApp/src/main/res/values-v14/styles.xml diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/values/ic_launcher_background.xml b/examples/android/androidCameraExample/ofApp/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000000..c5d5899fdf0 --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/examples/android/androidCameraExample/ofApp/src/main/res/values/strings.xml b/examples/android/androidCameraExample/ofApp/src/main/res/values/strings.xml new file mode 100644 index 00000000000..34312396338 --- /dev/null +++ b/examples/android/androidCameraExample/ofApp/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + + ofCameraEx + Menu + \ No newline at end of file diff --git a/scripts/templates/android/res/values/styles.xml b/examples/android/androidCameraExample/ofApp/src/main/res/values/styles.xml similarity index 100% rename from scripts/templates/android/res/values/styles.xml rename to examples/android/androidCameraExample/ofApp/src/main/res/values/styles.xml diff --git a/addons/ofxAndroid/ofAndroidLib/proguard.cfg b/examples/android/androidCameraExample/proguard.cfg similarity index 55% rename from addons/ofxAndroid/ofAndroidLib/proguard.cfg rename to examples/android/androidCameraExample/proguard.cfg index b1cdf17b5bb..faee26e7f2b 100644 --- a/addons/ofxAndroid/ofAndroidLib/proguard.cfg +++ b/examples/android/androidCameraExample/proguard.cfg @@ -14,6 +14,25 @@ -keep public class * extends android.preference.Preference -keep public class com.android.vending.licensing.ILicensingService +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } + +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +-keep class com.google.android.gms.common.api.** { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } -keepclasseswithmembernames class * { native ; } diff --git a/examples/android/androidCameraExample/settings.gradle b/examples/android/androidCameraExample/settings.gradle new file mode 100644 index 00000000000..cb352f426c0 --- /dev/null +++ b/examples/android/androidCameraExample/settings.gradle @@ -0,0 +1,11 @@ +include ':ofApp' + +// Define the relative path to the openFrameworks project +def openFrameworksProjectPath = '../../../libs/openFrameworksCompiled/project' + +// Convert the relative path to an absolute path +def openFrameworksProjectAbsolutePath = new File(rootDir, openFrameworksProjectPath).absolutePath + +// Include the openFrameworks project +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(openFrameworksProjectAbsolutePath) diff --git a/examples/android/androidCameraExample/src/main.cpp b/examples/android/androidCameraExample/src/main.cpp deleted file mode 100644 index ef340ca94b8..00000000000 --- a/examples/android/androidCameraExample/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -int main(){ - ofSetupOpenGL(1024,768, OF_WINDOW); // <-------- setup the GL context - - // this kicks off the running of my app - // can be OF_WINDOW or OF_FULLSCREEN - // pass in width and height too: - ofRunApp( new ofApp() ); - return 0; -} - - -#ifdef TARGET_ANDROID -void ofAndroidApplicationInit() -{ - //application scope init -} - -void ofAndroidActivityInit() -{ - //activity scope init - main(); -} -#endif diff --git a/examples/android/androidCameraExample/bin/data/.gitkeep b/examples/android/androidCompositeExample/addons.make similarity index 100% rename from examples/android/androidCameraExample/bin/data/.gitkeep rename to examples/android/androidCompositeExample/addons.make diff --git a/examples/android/androidCompositeExample/build.gradle b/examples/android/androidCompositeExample/build.gradle new file mode 100644 index 00000000000..7cbc7eb6714 --- /dev/null +++ b/examples/android/androidCompositeExample/build.gradle @@ -0,0 +1,22 @@ +ext { + //var = 'signExample.keystore' +}// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.4.2' + } +} + +allprojects { + repositories { + google() + mavenCentral() + } + ext { + + } +} diff --git a/examples/android/androidCompositeExample/gradle.properties b/examples/android/androidCompositeExample/gradle.properties new file mode 100644 index 00000000000..43f9ef9e1c3 --- /dev/null +++ b/examples/android/androidCompositeExample/gradle.properties @@ -0,0 +1,10 @@ +android.useAndroidX=true +android.enableJetifier=false +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +kotlin.code.style=official +android.prefabVersion=1.0.+ +android.buildFeatures.prefab=true +#ndkBuild=false +# https://issuetracker.google.com/149575364 +android.enableParallelJsonGen=false +#googleplay=true \ No newline at end of file diff --git a/examples/android/androidCompositeExample/gradle/wrapper/gradle-wrapper.jar b/examples/android/androidCompositeExample/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..13372aef5e2 Binary files /dev/null and b/examples/android/androidCompositeExample/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/android/androidCompositeExample/gradle/wrapper/gradle-wrapper.properties b/examples/android/androidCompositeExample/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..2dd5ee8c795 --- /dev/null +++ b/examples/android/androidCompositeExample/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Jun 12 01:17:57 AEST 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/android/androidCompositeExample/ofApp/build.gradle b/examples/android/androidCompositeExample/ofApp/build.gradle new file mode 100644 index 00000000000..5bf1e3663e4 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/build.gradle @@ -0,0 +1,182 @@ +plugins { + id 'com.android.application' +} + +def CMAKELIST_PATH = './src/main/cpp' +def CPP_SOURCE = './src/main/cpp' +def JAVA_SOURCE = './src/main/java' + +// pointing to cmake's source code for the same project +def PRJ_SRC_ROOT = './src/main' +def ofRoot(){ return '../../../../' } +final ofSource = ofRoot() + 'libs/openFrameworks' +final ofLibs = ofRoot() + 'libs' +final addons = ofRoot() + 'addons' +final ofLibOutput = ofRoot() + 'libs/openFrameworksCompiled/lib/android' +def OFX_ANDROID = ofRoot() + 'addons/ofxAndroid' +//def OF_ADDONS_ARGUMENTS = "${OF_ADDONS}" +def enableProguardInReleaseBuilds = true +def enableProguardInDebugBuilds = false + +task wrapper(type: Wrapper) { + gradleVersion = '7.3.3' +} +tasks.register("prepareKotlinBuildScriptModel"){ +} + +evaluationDependsOn(':openFrameworksProject') + +tasks.whenTaskAdded { task -> + if (task.name == 'assemble') { + task.dependsOn(':openFrameworksProject:assemble') + } +} + + +android { + compileSdkVersion 34 + buildToolsVersion '32.0.0' + //ndkPath "/Users/x/android-ndk-r21e" // Point to your own NDK if needed + ndkVersion '24.0.8215888' // use android studio side loaded ndk + buildFeatures { + prefab true + } + signingConfigs { + debug { + } + release { + storeFile new File("${System.properties['user.home']}/.android/debug.keystore") + storePassword 'android' + storeType "jks" + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + defaultConfig { + applicationId "cc.openframeworks.ofCompositeExample" + minSdkVersion 21 + targetSdkVersion 34 + versionCode 12 + versionName '12.0' + ndk.abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86' //, 'x86_64' + + externalNativeBuild { + if (!project.hasProperty("ndkBuild")) { + cmake { + arguments "-DANDROID_STL=c++_shared", + "-DANDROID_ARM_NEON=TRUE", + "-DANDROID_TOOLCHAIN=clang", + //"${OF_ADDONS_ARGUMENTS}", + "-DTARGET_OPENGLES=TRUE" + + version '3.22.1' + } + } + } + multiDexEnabled false + } + buildTypes { + release { + signingConfig signingConfigs.release + jniDebuggable false + debuggable false + minifyEnabled false + shrinkResources false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + } + debug { + jniDebuggable true + debuggable true + minifyEnabled false + shrinkResources false + signingConfig signingConfigs.debug + } + } + flavorDimensions "version" + productFlavors { + playstore { + applicationIdSuffix "" + signingConfig signingConfigs.release + } +// humble { +// applicationIdSuffix ".humble" +// } +// amazon { +// applicationIdSuffix ".amazon" +// } +// samsung { +// applicationIdSuffix ".samsung" +// } +// oppo { +// applicationIdSuffix ".oppo" +// } + } + sourceSets { + main { + manifest.srcFile "${PRJ_SRC_ROOT}/AndroidManifest.xml" + java.srcDirs = ["${PRJ_SRC_ROOT}/java", + "${OFX_ANDROID}/Java"] + res.srcDirs = ["${PRJ_SRC_ROOT}/res"] +// jniLibs.srcDirs = ["${OF_ANDROID_OUTPUT}", "lib"] // Pre Android Studio 2022.2.1 + assets { + srcDirs 'src/main/assets', 'src/main/bin/data' + } + } + } + externalNativeBuild { + if (!project.hasProperty("ndkBuild")) { + cmake { + path "${CMAKELIST_PATH}/CMakeLists.txt" + } + } else { + ndkBuild { + path "${CMAKELIST_PATH}/Android.mk" + } + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + androidResources { + noCompress '' + } + dependenciesInfo { + includeInApk false + includeInBundle false + } +// testOptions { +// devices { +// pixel2api29 (com.android.build.api.dsl.ManagedVirtualDevice) { +// // Use device profiles you typically see in +// // Android Studio +// device = "Pixel 2" +// apiLevel = 29 +// // You can also specify "aosp" if you don’t require +// // Google Play Services. +// systemImageSource = "google" +// abi = "x86" +// } +// } +// } +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation "com.getkeepsafe.relinker:relinker:1.4.5" + implementation 'com.google.android.material:material:1.9.0' + if (project.hasProperty("googleplay")) { + implementation "com.google.android.gms:play-services-games:22.0.1" + implementation "com.google.android.gms:play-services-auth:20.0.1" + implementation "com.google.android.gms:play-services-base:18.0.1" + implementation "com.google.android.gms:play-services-basement:18.0.0" + implementation "com.google.android.gms:play-services-instantapps:18.0.1" + implementation "com.google.android.gms:play-services-appset:16.0.2" + } +} + diff --git a/examples/android/androidCompositeExample/ofApp/gradle.properties b/examples/android/androidCompositeExample/ofApp/gradle.properties new file mode 100644 index 00000000000..f96a9f246a0 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/gradle.properties @@ -0,0 +1,11 @@ +android.useAndroidX=true +android.enableJetifier=true +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +kotlin.code.style=official +android.prefabVersion=1.0.+ +# Workaround bug in AGP where the prefab dependency is being resolved from a +# non-Gradle thread when enableParallelJsonGen is enabled. +# https://issuetracker.google.com/149575364 +android.enableParallelJsonGen=false +android.buildFeatures.prefab = true +vectorDrawables.useSupportLibrary = true \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/gradle/wrapper/gradle-wrapper.jar b/examples/android/androidCompositeExample/ofApp/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..249e5832f09 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/android/androidCompositeExample/ofApp/gradle/wrapper/gradle-wrapper.properties b/examples/android/androidCompositeExample/ofApp/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..2e6e5897b52 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/android/androidCompositeExample/ofApp/gradlew b/examples/android/androidCompositeExample/ofApp/gradlew new file mode 100755 index 00000000000..a69d9cb6c20 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/examples/android/androidCompositeExample/ofApp/gradlew.bat b/examples/android/androidCompositeExample/ofApp/gradlew.bat new file mode 100644 index 00000000000..f127cfd49d4 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/android/androidCompositeExample/ofApp/proguard-rules.pro b/examples/android/androidCompositeExample/ofApp/proguard-rules.pro new file mode 100644 index 00000000000..de8c62143ce --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/proguard-rules.pro @@ -0,0 +1,127 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +-dontoptimize +-dontshrink +#-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +#-verbose +# +-optimizationpasses 7 # use for final build +-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +-verbose + +# custom app activity proguard +-keep public class cc.openframeworks.android.OFActivity { public ; } +-keep public class cc.openframeworks.android.R { public ; } + + +#-dontobfuscate android classes +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference + +#-dontobfuscate openFrameworks android classes +-keep public class cc.openframeworks.OFAndroid { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycleHelper { public ; } +-keep public class cc.openframeworks.OFAndroidWindow { public ; } +-keep public class cc.openframeworks.OFAndroidSoundPlayer { public ; } +-keep public class cc.openframeworks.OFGLSurfaceView { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycle { public ; } +-keep public class cc.openframeworks.OFActivity { public ; } +-keep public class cc.openframeworks.ContextFactory { public ; } +-keep public class cc.openframeworks.OFEGLConfigChooser { public ; } +-keep public class cc.openframeworks.OFGestureListener { public ; } +-keep public class cc.openframeworks.OFAndroidController { public ; } + +#-dontobfuscate GooglePlay Games android classes if used +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +-keep class com.google.android.gms.common.api.** { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +# note that means any method +-keepclasseswithmembernames,includedescriptorclasses class * { + native ; +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/src/main/AndroidManifest.xml b/examples/android/androidCompositeExample/ofApp/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..613fef8d108 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/AndroidManifest.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/src/main/bin/data/frabk.ttf b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/frabk.ttf new file mode 100644 index 00000000000..21c4ecfc553 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/frabk.ttf differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/bin/data/shaders/noise.frag b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/shaders/noise.frag new file mode 100644 index 00000000000..53f7d315155 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/shaders/noise.frag @@ -0,0 +1,24 @@ +#ifdef GL_ES +// define default precision for float, vec, mat. +precision highp float; +#endif + +uniform vec4 globalColor; + +void main(){ + //this is the fragment shader + //this is where the pixel level drawing happens + //gl_FragCoord gives us the x and y of the current pixel its drawing + + //we grab the x and y and store them in an int + float xVal = gl_FragCoord.x; + float yVal = gl_FragCoord.y; + + //we use the mod function to only draw pixels if they are every 2 in x or every 4 in y + if( mod(xVal, 2.0) == 0.5 && mod(yVal, 4.0) == 0.5 ){ + gl_FragColor = globalColor; + }else{ + discard; + } + +} diff --git a/examples/android/androidCompositeExample/ofApp/src/main/bin/data/shaders/noise.vert b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/shaders/noise.vert new file mode 100644 index 00000000000..34eb8cfc4f0 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/shaders/noise.vert @@ -0,0 +1,89 @@ +#ifdef GL_ES +// define default precision for float, vec, mat. +precision highp float; +#endif + +attribute vec4 position; + +uniform mat4 modelViewProjectionMatrix; + +uniform float timeValX; +uniform float timeValY; +uniform vec2 mouse; + +//generate a random value from four points +vec4 rand(vec2 A,vec2 B,vec2 C,vec2 D){ + + vec2 s=vec2(12.9898,78.233); + vec4 tmp=vec4(dot(A,s),dot(B,s),dot(C,s),dot(D,s)); + + return fract(sin(tmp) * 43758.5453)* 2.0 - 1.0; +} + +//this is similar to a perlin noise function +float noise(vec2 coord,float d){ + + vec2 C[4]; + + float d1 = 1.0/d; + + C[0]=floor(coord*d)*d1; + + C[1]=C[0]+vec2(d1,0.0); + + C[2]=C[0]+vec2(d1,d1); + + C[3]=C[0]+vec2(0.0,d1); + + + vec2 p=fract(coord*d); + + vec2 q=1.0-p; + + vec4 w=vec4(q.x*q.y,p.x*q.y,p.x*p.y,q.x*p.y); + + return dot(vec4(rand(C[0],C[1],C[2],C[3])),w); +} + + +void main(){ + + //get our current vertex position so we can modify it + vec4 pos = modelViewProjectionMatrix * position; + + //generate some noise values based on vertex position and the time value which comes in from our OF app + float noiseAmntX = noise( vec2(-timeValX + pos.x / 1000.0, 100.0), 20.0 ); + float noiseAmntY = noise( vec2(timeValY + pos.y / 1000.0, pos.x / 2000.0), 20.0 ); + + //generate noise for our blue pixel value + float noiseB = noise( vec2(timeValY * 0.25, pos.y / 2000.0), 20.0 ); + + //lets also figure out the distance between the mouse and the vertex and apply a repelling force away from the mouse + vec2 d = vec2(pos.x, pos.y) - mouse; + float len = sqrt(d.x*d.x + d.y*d.y); + if( len < 300.0 && len > 0.0 ){ + + //lets get the distance into 0-1 ranges + float pct = len / 300.0; + + //this turns our linear 0-1 value into a curved 0-1 value + pct *= pct; + + //flip it so the closer we are the greater the repulsion + pct = 1.0 - pct; + + //normalize our repulsion vector + d /= len; + + //apply the repulsion to our position + pos.x += d.x * pct * 90.0; + pos.y += d.y * pct * 90.0; + } + + //modify our position with the smooth noise + pos.x += noiseAmntX * 20.0; + pos.y += noiseAmntY * 10.0; + + //finally set the pos to be that actual position rendered + gl_Position = pos; +} diff --git a/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/1085.mp3 b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/1085.mp3 new file mode 100644 index 00000000000..f4389d44b13 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/1085.mp3 differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/Violet.mp3 b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/Violet.mp3 new file mode 100644 index 00000000000..8968982ac9b Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/Violet.mp3 differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/beat.wav b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/beat.wav new file mode 100644 index 00000000000..3384984d617 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/beat.wav differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/synth.wav b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/synth.wav new file mode 100644 index 00000000000..481d3d1efbd Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/sounds/synth.wav differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/bin/data/verdana.ttf b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/verdana.ttf new file mode 100644 index 00000000000..8f25a642311 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/bin/data/verdana.ttf differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/cpp/CMakeLists.txt b/examples/android/androidCompositeExample/ofApp/src/main/cpp/CMakeLists.txt new file mode 100644 index 00000000000..5b160ffa42d --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/cpp/CMakeLists.txt @@ -0,0 +1,142 @@ +# Sets the minimum version of CMake required to build the native +# library. +cmake_minimum_required(VERSION 3.22.1) + +project(ofapp LANGUAGES CXX) +set(TARGET_ANDROID TRUE) + +set(LOCAL_PATH ${CMAKE_SOURCE_DIR}) +set(PRJ_OF_ROOT ${LOCAL_PATH}/../../../../../../../) + +set(PURE_OF_ROOT ${LOCAL_PATH}/../../../../../../../) +set(CORE_OF_ROOT ${PURE_OF_ROOT}/libs/openFrameworks) +set(LIBS_ROOT ${PURE_OF_ROOT}/libs) + +set(PRJ_ADDONS_PATH ${PURE_OF_ROOT}/addons) +set(PRJ_SOURCE_PATH ${LIBS_ROOT}/openFrameworks) +set(PRJ_LIBS_ROOT ${PURE_OF_ROOT}/libs) + +set(OF_ANDROID ${PURE_OF_ROOT}/libs/openFrameworksCompiled/project/android) +set(OF_ANDROID_OUTPUT ${PURE_OF_ROOT}/libs/openFrameworksCompiled/lib/android) + +set(PRJ_OFX_ANDROID_PATH ${PRJ_ADDONS_PATH}/ofxAndroid) +set(PRJ_OFX_ANDROID_CPP_PATH ${PRJ_OFX_ANDROID_PATH}/src) + +macro(print_all_variables) + message(STATUS "print_all_variables------------------------------------------{") + get_cmake_property(_variableNames VARIABLES) + foreach (_variableName ${_variableNames}) + message(STATUS "${_variableName}=${${_variableName}}") + endforeach() + message(STATUS "print_all_variables------------------------------------------}") +endmacro() + +# Custom function to check if the library is built +function(check_library) + if (NOT TARGET openFrameworksAndroid) + message(STATUS "openFrameworksAndroid Library not found. Building library...") + + # Invoke the build process for the library + execute_process( + COMMAND ${CMAKE_COMMAND} --build ${OF_ANDROID}/ + RESULT_VARIABLE result + ) + if (result) + message(FATAL_ERROR "Failed to build the library.") + endif () + endif () +endfunction() + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS ON) +set(TARGET_ANDROID ON) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c17 -Oz -DNDEBUG -frtti --warn-uninitialized -fno-short-enums -Wextra -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") +set(CMAKE_CPP_FLAGS "${CMAKE_C_FLAGS} -std=c++17 -Oz -DNDEBUG -stdlib=libc++ --warn-uninitialized -frtti -Wextra -fno-short-enums -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-export-dynamic") + +print_all_variables() + +# Creates the project's shared lib: libnative-lib.so. +# The lib is loaded by this project's Java code in MainActivity.java: +# System.loadLibrary("native-lib"); +# The lib name in both places must match. +add_library( ofapp #name + SHARED # type of library + # src files for project (just c/cpp) + ${CMAKE_SOURCE_DIR}/main.cpp + ${CMAKE_SOURCE_DIR}/ofApp.cpp + ) + + +# Specifies a path to native header files +include_directories( + # openFrameworks headers + ${PRJ_SOURCE_PATH}/3d + ${PRJ_SOURCE_PATH}/app + ${PRJ_SOURCE_PATH}/communication + ${PRJ_SOURCE_PATH}/events + ${PRJ_SOURCE_PATH}/gl + ${PRJ_SOURCE_PATH}/graphics + ${PRJ_SOURCE_PATH}/math + ${PRJ_SOURCE_PATH}/sound + ${PRJ_SOURCE_PATH}/types + ${PRJ_SOURCE_PATH}/utils + ${PRJ_SOURCE_PATH}/video + ${PRJ_SOURCE_PATH} + # openFrameworks addons includes + ${PURE_OF_ROOT}/addons/ofxAndroid/src + ${PURE_OF_ROOT}/addons/ofxAccelerometer/src + ${PURE_OF_ROOT}/addons/ofxXmlSettings/src + ${PURE_OF_ROOT}/addons/ofxXmlSettings/libs + # openFrameworks Libs includes + ${PRJ_LIBS_ROOT}/FreeImage/include + ${PRJ_LIBS_ROOT}/freetype/include + ${PRJ_LIBS_ROOT}/freetype/include/freetype2 + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/config + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal/services + ${PRJ_LIBS_ROOT}/glm/include + ${PRJ_LIBS_ROOT}/pugixml/include + ${PRJ_LIBS_ROOT}/json/include + ${PRJ_LIBS_ROOT}/tess2/include + ${PRJ_LIBS_ROOT}/utf8/include + ${PRJ_LIBS_ROOT}/uriparser/include + ${CMAKE_SOURCE_DIR}/ + ${CMAKE_SOURCE_DIR}/ + ${OF_ANDROID} +) + +find_library(android-lib android) +find_library(log-lib log) +find_library(GLES2-lib GLESv2) + +#find_library(GLES1-lib GLESv1_CM) +#find_library(GLES3-lib GLESv3) + + +target_link_libraries(ofapp + EGL + GLESv2 + log + c + m + z + dl +# GLESv3 + ) + +target_link_libraries( ofapp + ${android-lib} ) +target_link_libraries( ofapp + ${GLES2-lib} ) +target_link_libraries( ofapp + ${log-lib} ) +#target_link_libraries( ofApp +# ${GLES3-lib} ) +#target_link_libraries( ofApp +# ${GLES1-lib} ) + +# Finally link in openFrameworks Library for each ABI +target_link_libraries( ofapp + ${OF_ANDROID_OUTPUT}/${ANDROID_ABI}/libopenFrameworksAndroid.so) diff --git a/examples/android/androidCompositeExample/ofApp/src/main/cpp/main.cpp b/examples/android/androidCompositeExample/ofApp/src/main/cpp/main.cpp new file mode 100644 index 00000000000..f98043c5a8c --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/cpp/main.cpp @@ -0,0 +1,49 @@ +#include "ofMain.h" +#include "ofApp.h" + +#ifdef TARGET_ANDROID + +#include "ofWindowSettings.h" +#include "ofGLProgrammableRenderer.h" + +shared_ptr *ofapp; +std::shared_ptr baseWindow; + +//-------------------------------------------------------------- +int main(int argc, char **argv) { + baseWindow = std::make_shared(); + ofxAndroidWindowSettings settings; + settings.glesVersion = 2; + settings.setSize(1920, 1080); + settings.windowMode = OF_WINDOW; + settings.preserveContextOnPause = true; + baseWindow = ofCreateWindow(settings); + ofapp = new shared_ptr(new ofApp()); + ofRunApp(baseWindow, *ofapp); + return 0; +} + +void ofAndroidApplicationInit() +{ + //application scope init +} +void ofAndroidActivityInit() +{ + //activity scope init - call main + main(0, nullptr); +} + +// Callbacks from Android Layer +extern "C" JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_init( JNIEnv* env, jclass clazz) +{ + ofAndroidApplicationInit(); +} + +extern "C" JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onCreate( JNIEnv* env, jclass clazz) +{ + ofAndroidActivityInit(); +} + +#endif diff --git a/examples/android/androidCompositeExample/ofApp/src/main/cpp/ofApp.cpp b/examples/android/androidCompositeExample/ofApp/src/main/cpp/ofApp.cpp new file mode 100644 index 00000000000..0f8de156767 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/cpp/ofApp.cpp @@ -0,0 +1,294 @@ +#include "ofApp.h" + +//-------------------------------------------------------------- +void ofApp::setup(){ + + ofBackground(255,255,255); + ofSetVerticalSync(false); + ofEnableAlphaBlending(); + + // ofSetOrientation(OF_ORIENTATION_90_LEFT); + + // SHADERS + bool loadok = font.load("verdana.ttf", 200, true, false, true, 0.4, 72); + shader.load("shaders/noise.vert", "shaders/noise.frag"); + + auto textShapes = font.getStringAsPoints("openFrameworks"); + for (auto glyph : textShapes) { + text.append(glyph); + } + + ofRectangle boundingBox; + for (auto outline : text.getOutline()) { + boundingBox = boundingBox.getUnion(outline.getBoundingBox()); + } + + boundingBox.alignTo(ofGetCurrentViewport(), OF_ALIGN_HORZ_CENTER, OF_ALIGN_VERT_CENTER); + glm::vec2 textPos(boundingBox.getX(), boundingBox.getMaxY()); + + text.translate(textPos); + text.setFillColor(ofColor(245, 58, 135)); + + doShader = false; + + + // SOUNDPLAYER + loadok = synth.loadSound("sounds/synth.wav"); + loadok = beats.loadSound("sounds/1085.mp3"); + loadok = vocals.loadSound("sounds/Violet.mp3"); + synth.setVolume(1.0f); + beats.setVolume(0.75f); + vocals.setVolume(1.0f); + synth.setMultiPlay(true); + beats.setMultiPlay(false); + vocals.setMultiPlay(true); + + + // SOUNDSTREAM + +// Ask for permission to record audio, +// not needed if no in channels used + ofxAndroidRequestPermission(OFX_ANDROID_PERMISSION_RECORD_AUDIO); + bool ok = ofxAndroidCheckPermission(OFX_ANDROID_PERMISSION_RECORD_AUDIO); + + sampleRate = 44100; + phase = 0; + phaseAdder = 0.0f; + phaseAdderTarget = 0.0f; + volume = 0.1f; + bNoise = false; + initialBufferSize = 256; + + lAudio = new float[initialBufferSize]; + rAudio = new float[initialBufferSize]; + + memset(lAudio, 0, initialBufferSize * sizeof(float)); + memset(rAudio, 0, initialBufferSize * sizeof(float)); + + + ofSoundStreamSettings settings; + settings.setOutListener(this); + settings.setInListener(this); + settings.numOutputChannels = 2; + settings.numInputChannels = 2; + settings.numBuffers = 4; + settings.bufferSize = initialBufferSize; + soundStream.setup(settings); + +} + +void ofApp::exit(){ + +} + +//-------------------------------------------------------------- +void ofApp::update(){ + // update the sound playing system: + //ofSoundUpdate(); +} + +//-------------------------------------------------------------- +void ofApp::draw(){ + + int r = 128 + 50 * cosf(ofGetElapsedTimef()); + int g = 0; + int b = 128 + 50 * sinf(ofGetElapsedTimef()); + + ofBackground(r,g,b); + + if( doShader ){ + shader.begin(); + //we want to pass in some varrying values to animate our type / color + shader.setUniform1f("timeValX", ofGetElapsedTimef() * 0.1 ); + shader.setUniform1f("timeValY", -ofGetElapsedTimef() * 0.18 ); + + //we also pass in the mouse position + //we have to transform the coords to what the shader is expecting which is 0,0 in the center and y axis flipped. + shader.setUniform2f("mouse", ofGetMouseX() - ofGetWidth()/2, ofGetHeight()/2-ofGetMouseY() ); + + } + + + // draw the SoudStream audio waves + // draw the left: + ofBeginShape(); + for (int i = 0; i < initialBufferSize; i++){ + ofVertex(20+i*10,ofGetHeight() / 2 - 250 + lAudio[i]*500.0f); + } + ofEndShape(false); + + ofBeginShape(); + for (int i = 0; i < initialBufferSize; i++){ + ofVertex(20+i*10,ofGetHeight() / 2 + 250 + rAudio[i]*500.0f); + } + ofEndShape(false); + + //finally draw our text + text.draw(); + + if( doShader ){ + shader.end(); + } + +} + +//-------------------------------------------------------------- +void ofApp::keyPressed (int key){ + +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ + +} + +//-------------------------------------------------------------- +void ofApp::touchDown(int x, int y, int id){ + doShader = true; + + float widthStep = ofGetWidth() / 3.0f; + if (x < widthStep){ + float pct = x / widthStep; + synth.play(); + synth.setSpeed( 0.1f + ((float)(ofGetHeight() - y) / (float)ofGetHeight())*2.0f); + synth.setPan(2.0*pct-1.0); + } + else if (x >= widthStep && x < widthStep*2){ + beats.play(); + } + else { + vocals.play(); + vocals.setSpeed( 0.1f + ((float)(ofGetHeight() - y) / (float)ofGetHeight())*2.0f); + vocals.setPan(2.0*(float)(x - widthStep*2) / (float)widthStep-1.0); + } +} + +//-------------------------------------------------------------- +void ofApp::touchMoved(int x, int y, int id){ + // continuously control the speed of the beat sample via drag, + // when in the "beat" region: + float widthStep = ofGetWidth() / 3.0f; + if (x >= widthStep && x < widthStep*2){ + beats.setSpeed( 0.5f + ((float)(ofGetHeight() - y) / (float)ofGetHeight())*1.0f); + } + + int width = ofGetWidth(); + pan = (float)x / (float)width; + float height = (float)ofGetHeight(); + float heightPct = ((height-y) / height); + targetFrequency = 2000.0f * heightPct; + phaseAdderTarget = (targetFrequency / (float) sampleRate) * TWO_PI; +} + +//-------------------------------------------------------------- +void ofApp::touchUp(int x, int y, int id){ + //doShader = false; + +} + +//-------------------------------------------------------------- +void ofApp::touchDoubleTap(int x, int y, int id){ + +} + +//-------------------------------------------------------------- +void ofApp::touchCancelled(int x, int y, int id){ + +} + +//-------------------------------------------------------------- +void ofApp::swipe(ofxAndroidSwipeDir swipeDir, int id){ + +} + +//-------------------------------------------------------------- +void ofApp::pause(){ + +} + +//-------------------------------------------------------------- +void ofApp::stop(){ + +} + +//-------------------------------------------------------------- +void ofApp::resume(){ + +} + +//-------------------------------------------------------------- +void ofApp::reloadTextures(){ + +} + +//-------------------------------------------------------------- +bool ofApp::backPressed(){ + return false; +} + +//-------------------------------------------------------------- +void ofApp::okPressed(){ + +} + +//-------------------------------------------------------------- +void ofApp::cancelPressed(){ + +} + +void ofApp::audioOut(ofSoundBuffer & buffer){ + //pan = 0.5f; + float leftScale = 1 - pan; + float rightScale = pan; + + // sin (n) seems to have trouble when n is very large, so we + // keep phase in the range of 0-TWO_PI like this: + while (phase > TWO_PI){ + phase -= TWO_PI; + } + + if ( bNoise == true){ + // ---------------------- noise -------------- + for (int i = 0; i < buffer.getNumFrames(); i++){ + lAudio[i] = buffer.getSample(i, 0) = ofRandomf() * volume * leftScale; + rAudio[i] = buffer.getSample(i, 1) = ofRandomf() * volume * rightScale; + } + } else { + + for (int i = 0; i < buffer.getNumFrames(); i++){ + phaseAdder = 0.6f * phaseAdder + 0.4f * phaseAdderTarget; + phase += phaseAdder; + float sample = sin(phase); + lAudio[i%256] = buffer.getSample(i, 0) = sample * volume * leftScale; + buffer.getSample(i, 1) = sample * volume * rightScale; + } + } +} + + +void ofApp::audioIn(ofSoundBuffer & buffer){ + for (int i = 0; i < buffer.getNumFrames(); i++){ + rAudio[i%256] = buffer.getSample(i, 0) + buffer.getSample(i, 1) ; + } +} + +void ofApp::deviceRefreshRateChanged(int refreshRate) { + +} + +void ofApp::deviceHighestRefreshRateChanged(int refreshRate) { + +} + +void ofApp::deviceRefreshRateChangedEvent(int &refreshRate) { + +} + +void ofApp::deviceHighestRefreshRateChangedEvent(int &refreshRate) { + +} diff --git a/examples/android/androidCompositeExample/ofApp/src/main/cpp/ofApp.h b/examples/android/androidCompositeExample/ofApp/src/main/cpp/ofApp.h new file mode 100644 index 00000000000..9d80d3ca91b --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/cpp/ofApp.h @@ -0,0 +1,70 @@ +#pragma once + +#include "ofMain.h" +#include "ofxAndroid.h" +#include + +class ofApp : public ofxAndroidApp{ + + public: + + void setup(); + void exit(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + void windowResized(int w, int h); + + void touchDown(int x, int y, int id); + void touchMoved(int x, int y, int id); + void touchUp(int x, int y, int id); + void touchDoubleTap(int x, int y, int id); + void touchCancelled(int x, int y, int id); + void swipe(ofxAndroidSwipeDir swipeDir, int id); + + void pause(); + void stop(); + void resume(); + void reloadTextures(); + + bool backPressed(); + void okPressed(); + void cancelPressed(); + + void deviceRefreshRateChanged(int refreshRate); + void deviceHighestRefreshRateChanged(int refreshRate); + void deviceRefreshRateChangedEvent(int &refreshRate); + void deviceHighestRefreshRateChangedEvent(int & refreshRate); + + // Using Shaders and fonts + ofPath text; + ofTrueTypeFont font; + ofShader shader; + bool doShader; + + // Using ofSoundPlayer + ofSoundPlayer beats; + ofSoundPlayer synth; + ofSoundPlayer vocals; + + // Using ofSoundStream + void audioOut(ofSoundBuffer & buffer); + void audioIn(ofSoundBuffer & buffer); + + float pan; + int sampleRate; + bool bNoise; + float volume; + int initialBufferSize; + float * lAudio; + float * rAudio; + // For the simple sine wave synthesis + float targetFrequency; + float phase; + float phaseAdder; + float phaseAdderTarget; + + ofSoundStream soundStream; +}; diff --git a/examples/android/androidCompositeExample/ofApp/src/main/ic_launcher-playstore.png b/examples/android/androidCompositeExample/ofApp/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000000..2a0df19f5e0 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/ic_launcher-playstore.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java b/examples/android/androidCompositeExample/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java new file mode 100644 index 00000000000..f0a6dc8d4e8 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java @@ -0,0 +1,204 @@ +package cc.openframeworks.android; + +import android.app.Activity; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; + +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; + +import cc.openframeworks.OFAndroid; +import cc.openframeworks.OFAndroidController; +import cc.openframeworks.OFAndroidLifeCycle; +import cc.openframeworks.OFAndroidLifeCycleHelper; + +import com.getkeepsafe.relinker.ReLinker; + + + +public class OFActivity extends cc.openframeworks.OFActivity { + + private static final String appName = "ofapp"; // modify this to target appName (ofApp etc) + private static final String LOG_TAG = appName + "::OFActivity"; + + private ReLinker.Logger logcatLogger = new ReLinker.Logger() { + @Override + public void log(String message) { + Log.d("ReLinker", message); + } + }; + private OFActivity thisActivity; + + + // Extremely important + public OFActivity() { + OFAndroidLifeCycle.coreLibraryLoaded = true; + + OFAndroid.maxSamples = 4; + OFAndroid.maximumFrameRate = 144; + + thisActivity = this; + ReLinker.log(logcatLogger) + .force() + .recursively() + .loadLibrary(this, appName, new ReLinker.LoadListener() { + @Override + public void success() { + Log.i(LOG_TAG, "loadLibrary success"); + OFAndroidLifeCycle.appLibraryLoaded = true; + Setup(); // very important - this will in turn call main + } + + @Override + public void failure(Throwable t) { + /* Boo */ + Log.i(LOG_TAG, "loadLibrary failure" + t.getMessage()); + } + }); + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + Log.i(LOG_TAG, "onCreate"); + super.onCreate(savedInstanceState); + + setFullscreen(); + hideSystemBars(); + } + + @Override + public void onStart() { + super.onStart(); + + } + + @Override + public void onDetachedFromWindow() { + + } + + // Menus + // http://developer.android.com/guide/topics/ui/menus.html + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Create settings menu options from here, one by one or infalting an xml + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // This passes the menu option string to OF + // you can add additional behavior from java modifying this method + // but keep the call to OFAndroid so OF is notified of menu events + if(OFAndroid.menuItemSelected(item.getItemId())){ + + return true; + } + return super.onOptionsItemSelected(item); + } + + + @Override + public boolean onPrepareOptionsMenu (Menu menu){ + // This method is called every time the menu is opened + // you can add or remove menu options from here + return super.onPrepareOptionsMenu(menu); + } + + public void onRestore() { + + if (!OFAndroidLifeCycle.appLibraryLoaded) return; + } + + private void hideSystemBars() { + WindowInsetsControllerCompat windowInsetsController = + ViewCompat.getWindowInsetsController(getWindow().getDecorView()); + if (windowInsetsController == null) { + return; + } + // Configure the behavior of the hidden system bars + windowInsetsController.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + ); + // Hide both the status bar and the navigation bar + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + + if (hasFocus) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + + setFullscreen(); + } else { + setFullscreen(); + } + } else { + + } + } + + private void handleException(Exception e, String details) { + Log.e(LOG_TAG, "Exception:", e); + + } + + public void setFullscreen() { + try { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + // No sticky immersive mode for devices pre-kitkat + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } else { + View decorView = getWindow().getDecorView(); +// int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; + int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + decorView.setSystemUiVisibility(uiOptions); + } + + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + + } catch (Exception ex) { + handleException(ex, "setFullscreen exception"); + } + + try { + View decorView = getWindow().getDecorView(); + int[] locations = new int[2]; + decorView.getLocationInWindow(locations); + int[] locations2 = new int[2]; + decorView.getLocationOnScreen(locations2); + + } catch (Exception ex) { + handleException(ex, "setFullscreen exception"); + } + + WindowInsetsControllerCompat windowInsetsController = + ViewCompat.getWindowInsetsController(getWindow().getDecorView()); + if (windowInsetsController == null) { + return; + } + // Hide both the status bar and the navigation bar + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); + windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars()); + windowInsetsController.hide(WindowInsetsCompat.Type.statusBars()); + } + + +} + diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/drawable-hdpi/icon.png b/examples/android/androidCompositeExample/ofApp/src/main/res/drawable-hdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/drawable-hdpi/icon.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/drawable-mdpi/icon.png b/examples/android/androidCompositeExample/ofApp/src/main/res/drawable-mdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/drawable-mdpi/icon.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/drawable-xhdpi/icon.png b/examples/android/androidCompositeExample/ofApp/src/main/res/drawable-xhdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/drawable-xhdpi/icon.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/drawable/icon.png b/examples/android/androidCompositeExample/ofApp/src/main/res/drawable/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/drawable/icon.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/layout/main_layout.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/layout/main_layout.xml new file mode 100644 index 00000000000..d1da461f079 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/layout/main_layout.xml @@ -0,0 +1,24 @@ + + + + + + diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/menu/main_layout.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/menu/main_layout.xml new file mode 100644 index 00000000000..7ddcfbee35e --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/menu/main_layout.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000000..036d09bc5fd --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000000..036d09bc5fd --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000000..42b40d2fbec Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..648779fe415 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000000..a39d8826804 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000000..13e6dfef882 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..67b93c29890 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000000..93401eaf855 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000000..018f9b90738 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..fc64ec1c838 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..486c62f1f2a Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000000..cf6c612f8b1 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..07b98443e1b Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..b4024c5aa00 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000000..60b1a9e8332 Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..45bd0178fee Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..1b64c2ce02d Binary files /dev/null and b/examples/android/androidCompositeExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/values-v11/strings.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/values-v11/strings.xml new file mode 100644 index 00000000000..29c67ba8fc4 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/values-v11/strings.xml @@ -0,0 +1,5 @@ + + + ofExample + Menu + \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/values-v11/styles.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/values-v11/styles.xml new file mode 100644 index 00000000000..febc4d0286b --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/values-v11/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/values-v14/strings.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/values-v14/strings.xml new file mode 100644 index 00000000000..29c67ba8fc4 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/values-v14/strings.xml @@ -0,0 +1,5 @@ + + + ofExample + Menu + \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/values-v14/styles.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/values-v14/styles.xml new file mode 100644 index 00000000000..928e0fd3d72 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/values-v14/styles.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/values/ic_launcher_background.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000000..c5d5899fdf0 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/values/strings.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/values/strings.xml new file mode 100644 index 00000000000..29c67ba8fc4 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + + ofExample + Menu + \ No newline at end of file diff --git a/examples/android/androidCompositeExample/ofApp/src/main/res/values/styles.xml b/examples/android/androidCompositeExample/ofApp/src/main/res/values/styles.xml new file mode 100644 index 00000000000..766a2c3f143 --- /dev/null +++ b/examples/android/androidCompositeExample/ofApp/src/main/res/values/styles.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/examples/android/androidCompositeExample/proguard.cfg b/examples/android/androidCompositeExample/proguard.cfg new file mode 100644 index 00000000000..faee26e7f2b --- /dev/null +++ b/examples/android/androidCompositeExample/proguard.cfg @@ -0,0 +1,59 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class com.android.vending.licensing.ILicensingService + +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } + +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +-keep class com.google.android.gms.common.api.** { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} diff --git a/examples/android/androidCompositeExample/settings.gradle b/examples/android/androidCompositeExample/settings.gradle new file mode 100644 index 00000000000..cb352f426c0 --- /dev/null +++ b/examples/android/androidCompositeExample/settings.gradle @@ -0,0 +1,11 @@ +include ':ofApp' + +// Define the relative path to the openFrameworks project +def openFrameworksProjectPath = '../../../libs/openFrameworksCompiled/project' + +// Convert the relative path to an absolute path +def openFrameworksProjectAbsolutePath = new File(rootDir, openFrameworksProjectPath).absolutePath + +// Include the openFrameworks project +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(openFrameworksProjectAbsolutePath) diff --git a/examples/android/androidEmptyExample/build.gradle b/examples/android/androidEmptyExample/build.gradle new file mode 100644 index 00000000000..7cbc7eb6714 --- /dev/null +++ b/examples/android/androidEmptyExample/build.gradle @@ -0,0 +1,22 @@ +ext { + //var = 'signExample.keystore' +}// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.4.2' + } +} + +allprojects { + repositories { + google() + mavenCentral() + } + ext { + + } +} diff --git a/examples/android/androidEmptyExample/gradle.properties b/examples/android/androidEmptyExample/gradle.properties new file mode 100644 index 00000000000..43f9ef9e1c3 --- /dev/null +++ b/examples/android/androidEmptyExample/gradle.properties @@ -0,0 +1,10 @@ +android.useAndroidX=true +android.enableJetifier=false +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +kotlin.code.style=official +android.prefabVersion=1.0.+ +android.buildFeatures.prefab=true +#ndkBuild=false +# https://issuetracker.google.com/149575364 +android.enableParallelJsonGen=false +#googleplay=true \ No newline at end of file diff --git a/examples/android/androidEmptyExample/gradle/wrapper/gradle-wrapper.jar b/examples/android/androidEmptyExample/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..13372aef5e2 Binary files /dev/null and b/examples/android/androidEmptyExample/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/android/androidEmptyExample/gradle/wrapper/gradle-wrapper.properties b/examples/android/androidEmptyExample/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..2dd5ee8c795 --- /dev/null +++ b/examples/android/androidEmptyExample/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Jun 12 01:17:57 AEST 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/android/androidEmptyExample/gradlew b/examples/android/androidEmptyExample/gradlew new file mode 100755 index 00000000000..9d82f789151 --- /dev/null +++ b/examples/android/androidEmptyExample/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/examples/android/androidEmptyExample/gradlew.bat b/examples/android/androidEmptyExample/gradlew.bat new file mode 100644 index 00000000000..8a0b282aa68 --- /dev/null +++ b/examples/android/androidEmptyExample/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/android/androidEmptyExample/local.properties b/examples/android/androidEmptyExample/local.properties new file mode 100644 index 00000000000..5ba01764b38 --- /dev/null +++ b/examples/android/androidEmptyExample/local.properties @@ -0,0 +1,8 @@ +## This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Wed May 08 13:54:16 CEST 2024 +sdk.dir=/Users/thierry/Library/Android/sdk diff --git a/examples/android/androidEmptyExample/ofApp/build.gradle b/examples/android/androidEmptyExample/ofApp/build.gradle new file mode 100644 index 00000000000..4ac7015c9c9 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/build.gradle @@ -0,0 +1,182 @@ +plugins { + id 'com.android.application' +} + +def CMAKELIST_PATH = './src/main/cpp' +def CPP_SOURCE = './src/main/cpp' +def JAVA_SOURCE = './src/main/java' + +// pointing to cmake's source code for the same project +def PRJ_SRC_ROOT = './src/main' +def ofRoot(){ return '../../../../' } +final ofSource = ofRoot() + 'libs/openFrameworks' +final ofLibs = ofRoot() + 'libs' +final addons = ofRoot() + 'addons' +final ofLibOutput = ofRoot() + 'libs/openFrameworksCompiled/lib/android' +def OFX_ANDROID = ofRoot() + 'addons/ofxAndroid' +//def OF_ADDONS_ARGUMENTS = "${OF_ADDONS}" +def enableProguardInReleaseBuilds = true +def enableProguardInDebugBuilds = false + +task wrapper(type: Wrapper) { + gradleVersion = '7.3.3' +} +tasks.register("prepareKotlinBuildScriptModel"){ +} + +evaluationDependsOn(':openFrameworksProject') + +tasks.whenTaskAdded { task -> + if (task.name == 'assemble') { + task.dependsOn(':openFrameworksProject:assemble') + } +} + + +android { + compileSdkVersion 34 + buildToolsVersion '32.0.0' + //ndkPath "/Users/x/android-ndk-r21e" // Point to your own NDK if needed + ndkVersion '24.0.8215888' // use android studio side loaded ndk + buildFeatures { + prefab true + } + signingConfigs { + debug { + } + release { + storeFile new File("${System.properties['user.home']}/.android/debug.keystore") + storePassword 'android' + storeType "jks" + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + defaultConfig { + applicationId "cc.openframeworks.androidEmptyExample" // IMPORTANT : THIS DEFINES THE ID OF THE APK + minSdkVersion 21 + targetSdkVersion 34 + versionCode 12 + versionName '12.0' + ndk.abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86' //, 'x86_64' + + externalNativeBuild { + if (!project.hasProperty("ndkBuild")) { + cmake { + arguments "-DANDROID_STL=c++_shared", + "-DANDROID_ARM_NEON=TRUE", + "-DANDROID_TOOLCHAIN=clang", + //"${OF_ADDONS_ARGUMENTS}", + "-DTARGET_OPENGLES=TRUE" + + version '3.22.1' + } + } + } + multiDexEnabled false + } + buildTypes { + release { + signingConfig signingConfigs.release + jniDebuggable false + debuggable false + minifyEnabled false + shrinkResources false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + } + debug { + jniDebuggable true + debuggable true + minifyEnabled false + shrinkResources false + signingConfig signingConfigs.debug + } + } + flavorDimensions "version" + productFlavors { + playstore { + applicationIdSuffix "" + signingConfig signingConfigs.release + } +// humble { +// applicationIdSuffix ".humble" +// } +// amazon { +// applicationIdSuffix ".amazon" +// } +// samsung { +// applicationIdSuffix ".samsung" +// } +// oppo { +// applicationIdSuffix ".oppo" +// } + } + sourceSets { + main { + manifest.srcFile "${PRJ_SRC_ROOT}/AndroidManifest.xml" + java.srcDirs = ["${PRJ_SRC_ROOT}/java", + "${OFX_ANDROID}/Java"] + res.srcDirs = ["${PRJ_SRC_ROOT}/res"] +// jniLibs.srcDirs = ["${OF_ANDROID_OUTPUT}", "lib"] // Pre Android Studio 2022.2.1 + assets { + srcDirs 'src/main/assets', 'src/main/bin/data' + } + } + } + externalNativeBuild { + if (!project.hasProperty("ndkBuild")) { + cmake { + path "${CMAKELIST_PATH}/CMakeLists.txt" + } + } else { + ndkBuild { + path "${CMAKELIST_PATH}/Android.mk" + } + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + androidResources { + noCompress '' + } + dependenciesInfo { + includeInApk false + includeInBundle false + } +// testOptions { +// devices { +// pixel2api29 (com.android.build.api.dsl.ManagedVirtualDevice) { +// // Use device profiles you typically see in +// // Android Studio +// device = "Pixel 2" +// apiLevel = 29 +// // You can also specify "aosp" if you don’t require +// // Google Play Services. +// systemImageSource = "google" +// abi = "x86" +// } +// } +// } +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation "com.getkeepsafe.relinker:relinker:1.4.5" + implementation 'com.google.android.material:material:1.9.0' + if (project.hasProperty("googleplay")) { + implementation "com.google.android.gms:play-services-games:22.0.1" + implementation "com.google.android.gms:play-services-auth:20.0.1" + implementation "com.google.android.gms:play-services-base:18.0.1" + implementation "com.google.android.gms:play-services-basement:18.0.0" + implementation "com.google.android.gms:play-services-instantapps:18.0.1" + implementation "com.google.android.gms:play-services-appset:16.0.2" + } +} + diff --git a/examples/android/androidEmptyExample/ofApp/gradle.properties b/examples/android/androidEmptyExample/ofApp/gradle.properties new file mode 100644 index 00000000000..f96a9f246a0 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/gradle.properties @@ -0,0 +1,11 @@ +android.useAndroidX=true +android.enableJetifier=true +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +kotlin.code.style=official +android.prefabVersion=1.0.+ +# Workaround bug in AGP where the prefab dependency is being resolved from a +# non-Gradle thread when enableParallelJsonGen is enabled. +# https://issuetracker.google.com/149575364 +android.enableParallelJsonGen=false +android.buildFeatures.prefab = true +vectorDrawables.useSupportLibrary = true \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/gradle/wrapper/gradle-wrapper.jar b/examples/android/androidEmptyExample/ofApp/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..249e5832f09 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/android/androidEmptyExample/ofApp/gradle/wrapper/gradle-wrapper.properties b/examples/android/androidEmptyExample/ofApp/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..2e6e5897b52 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/android/androidEmptyExample/ofApp/proguard-rules.pro b/examples/android/androidEmptyExample/ofApp/proguard-rules.pro new file mode 100644 index 00000000000..de8c62143ce --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/proguard-rules.pro @@ -0,0 +1,127 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +-dontoptimize +-dontshrink +#-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +#-verbose +# +-optimizationpasses 7 # use for final build +-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +-verbose + +# custom app activity proguard +-keep public class cc.openframeworks.android.OFActivity { public ; } +-keep public class cc.openframeworks.android.R { public ; } + + +#-dontobfuscate android classes +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference + +#-dontobfuscate openFrameworks android classes +-keep public class cc.openframeworks.OFAndroid { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycleHelper { public ; } +-keep public class cc.openframeworks.OFAndroidWindow { public ; } +-keep public class cc.openframeworks.OFAndroidSoundPlayer { public ; } +-keep public class cc.openframeworks.OFGLSurfaceView { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycle { public ; } +-keep public class cc.openframeworks.OFActivity { public ; } +-keep public class cc.openframeworks.ContextFactory { public ; } +-keep public class cc.openframeworks.OFEGLConfigChooser { public ; } +-keep public class cc.openframeworks.OFGestureListener { public ; } +-keep public class cc.openframeworks.OFAndroidController { public ; } + +#-dontobfuscate GooglePlay Games android classes if used +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +-keep class com.google.android.gms.common.api.** { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +# note that means any method +-keepclasseswithmembernames,includedescriptorclasses class * { + native ; +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/src/main/AndroidManifest.xml b/examples/android/androidEmptyExample/ofApp/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..aae67ceba1b --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/AndroidManifest.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/src/main/cpp/CMakeLists.txt b/examples/android/androidEmptyExample/ofApp/src/main/cpp/CMakeLists.txt new file mode 100644 index 00000000000..5b160ffa42d --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/cpp/CMakeLists.txt @@ -0,0 +1,142 @@ +# Sets the minimum version of CMake required to build the native +# library. +cmake_minimum_required(VERSION 3.22.1) + +project(ofapp LANGUAGES CXX) +set(TARGET_ANDROID TRUE) + +set(LOCAL_PATH ${CMAKE_SOURCE_DIR}) +set(PRJ_OF_ROOT ${LOCAL_PATH}/../../../../../../../) + +set(PURE_OF_ROOT ${LOCAL_PATH}/../../../../../../../) +set(CORE_OF_ROOT ${PURE_OF_ROOT}/libs/openFrameworks) +set(LIBS_ROOT ${PURE_OF_ROOT}/libs) + +set(PRJ_ADDONS_PATH ${PURE_OF_ROOT}/addons) +set(PRJ_SOURCE_PATH ${LIBS_ROOT}/openFrameworks) +set(PRJ_LIBS_ROOT ${PURE_OF_ROOT}/libs) + +set(OF_ANDROID ${PURE_OF_ROOT}/libs/openFrameworksCompiled/project/android) +set(OF_ANDROID_OUTPUT ${PURE_OF_ROOT}/libs/openFrameworksCompiled/lib/android) + +set(PRJ_OFX_ANDROID_PATH ${PRJ_ADDONS_PATH}/ofxAndroid) +set(PRJ_OFX_ANDROID_CPP_PATH ${PRJ_OFX_ANDROID_PATH}/src) + +macro(print_all_variables) + message(STATUS "print_all_variables------------------------------------------{") + get_cmake_property(_variableNames VARIABLES) + foreach (_variableName ${_variableNames}) + message(STATUS "${_variableName}=${${_variableName}}") + endforeach() + message(STATUS "print_all_variables------------------------------------------}") +endmacro() + +# Custom function to check if the library is built +function(check_library) + if (NOT TARGET openFrameworksAndroid) + message(STATUS "openFrameworksAndroid Library not found. Building library...") + + # Invoke the build process for the library + execute_process( + COMMAND ${CMAKE_COMMAND} --build ${OF_ANDROID}/ + RESULT_VARIABLE result + ) + if (result) + message(FATAL_ERROR "Failed to build the library.") + endif () + endif () +endfunction() + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS ON) +set(TARGET_ANDROID ON) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c17 -Oz -DNDEBUG -frtti --warn-uninitialized -fno-short-enums -Wextra -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") +set(CMAKE_CPP_FLAGS "${CMAKE_C_FLAGS} -std=c++17 -Oz -DNDEBUG -stdlib=libc++ --warn-uninitialized -frtti -Wextra -fno-short-enums -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-export-dynamic") + +print_all_variables() + +# Creates the project's shared lib: libnative-lib.so. +# The lib is loaded by this project's Java code in MainActivity.java: +# System.loadLibrary("native-lib"); +# The lib name in both places must match. +add_library( ofapp #name + SHARED # type of library + # src files for project (just c/cpp) + ${CMAKE_SOURCE_DIR}/main.cpp + ${CMAKE_SOURCE_DIR}/ofApp.cpp + ) + + +# Specifies a path to native header files +include_directories( + # openFrameworks headers + ${PRJ_SOURCE_PATH}/3d + ${PRJ_SOURCE_PATH}/app + ${PRJ_SOURCE_PATH}/communication + ${PRJ_SOURCE_PATH}/events + ${PRJ_SOURCE_PATH}/gl + ${PRJ_SOURCE_PATH}/graphics + ${PRJ_SOURCE_PATH}/math + ${PRJ_SOURCE_PATH}/sound + ${PRJ_SOURCE_PATH}/types + ${PRJ_SOURCE_PATH}/utils + ${PRJ_SOURCE_PATH}/video + ${PRJ_SOURCE_PATH} + # openFrameworks addons includes + ${PURE_OF_ROOT}/addons/ofxAndroid/src + ${PURE_OF_ROOT}/addons/ofxAccelerometer/src + ${PURE_OF_ROOT}/addons/ofxXmlSettings/src + ${PURE_OF_ROOT}/addons/ofxXmlSettings/libs + # openFrameworks Libs includes + ${PRJ_LIBS_ROOT}/FreeImage/include + ${PRJ_LIBS_ROOT}/freetype/include + ${PRJ_LIBS_ROOT}/freetype/include/freetype2 + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/config + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal/services + ${PRJ_LIBS_ROOT}/glm/include + ${PRJ_LIBS_ROOT}/pugixml/include + ${PRJ_LIBS_ROOT}/json/include + ${PRJ_LIBS_ROOT}/tess2/include + ${PRJ_LIBS_ROOT}/utf8/include + ${PRJ_LIBS_ROOT}/uriparser/include + ${CMAKE_SOURCE_DIR}/ + ${CMAKE_SOURCE_DIR}/ + ${OF_ANDROID} +) + +find_library(android-lib android) +find_library(log-lib log) +find_library(GLES2-lib GLESv2) + +#find_library(GLES1-lib GLESv1_CM) +#find_library(GLES3-lib GLESv3) + + +target_link_libraries(ofapp + EGL + GLESv2 + log + c + m + z + dl +# GLESv3 + ) + +target_link_libraries( ofapp + ${android-lib} ) +target_link_libraries( ofapp + ${GLES2-lib} ) +target_link_libraries( ofapp + ${log-lib} ) +#target_link_libraries( ofApp +# ${GLES3-lib} ) +#target_link_libraries( ofApp +# ${GLES1-lib} ) + +# Finally link in openFrameworks Library for each ABI +target_link_libraries( ofapp + ${OF_ANDROID_OUTPUT}/${ANDROID_ABI}/libopenFrameworksAndroid.so) diff --git a/examples/android/androidEmptyExample/ofApp/src/main/cpp/main.cpp b/examples/android/androidEmptyExample/ofApp/src/main/cpp/main.cpp new file mode 100644 index 00000000000..f98043c5a8c --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/cpp/main.cpp @@ -0,0 +1,49 @@ +#include "ofMain.h" +#include "ofApp.h" + +#ifdef TARGET_ANDROID + +#include "ofWindowSettings.h" +#include "ofGLProgrammableRenderer.h" + +shared_ptr *ofapp; +std::shared_ptr baseWindow; + +//-------------------------------------------------------------- +int main(int argc, char **argv) { + baseWindow = std::make_shared(); + ofxAndroidWindowSettings settings; + settings.glesVersion = 2; + settings.setSize(1920, 1080); + settings.windowMode = OF_WINDOW; + settings.preserveContextOnPause = true; + baseWindow = ofCreateWindow(settings); + ofapp = new shared_ptr(new ofApp()); + ofRunApp(baseWindow, *ofapp); + return 0; +} + +void ofAndroidApplicationInit() +{ + //application scope init +} +void ofAndroidActivityInit() +{ + //activity scope init - call main + main(0, nullptr); +} + +// Callbacks from Android Layer +extern "C" JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_init( JNIEnv* env, jclass clazz) +{ + ofAndroidApplicationInit(); +} + +extern "C" JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onCreate( JNIEnv* env, jclass clazz) +{ + ofAndroidActivityInit(); +} + +#endif diff --git a/scripts/templates/android/src/ofApp.cpp b/examples/android/androidEmptyExample/ofApp/src/main/cpp/ofApp.cpp similarity index 79% rename from scripts/templates/android/src/ofApp.cpp rename to examples/android/androidEmptyExample/ofApp/src/main/cpp/ofApp.cpp index 189c4aebe88..b3fa2c7dd15 100644 --- a/scripts/templates/android/src/ofApp.cpp +++ b/examples/android/androidEmptyExample/ofApp/src/main/cpp/ofApp.cpp @@ -3,6 +3,14 @@ //-------------------------------------------------------------- void ofApp::setup(){ + ofBackground(255,255,255); + ofSetVerticalSync(false); + ofEnableAlphaBlending(); + +} + +void ofApp::exit(){ + } //-------------------------------------------------------------- @@ -13,6 +21,12 @@ void ofApp::update(){ //-------------------------------------------------------------- void ofApp::draw(){ + int r = 128 + 127 * cosf(ofGetElapsedTimef()); + int g = 0; + int b = 128 + 127 * sinf(ofGetElapsedTimef()); + + ofBackground(r,g,b); + } //-------------------------------------------------------------- @@ -94,3 +108,19 @@ void ofApp::okPressed(){ void ofApp::cancelPressed(){ } + +void ofApp::deviceRefreshRateChanged(int refreshRate) { + +} + +void ofApp::deviceHighestRefreshRateChanged(int refreshRate) { + +} + +void ofApp::deviceRefreshRateChangedEvent(int &refreshRate) { + +} + +void ofApp::deviceHighestRefreshRateChangedEvent(int &refreshRate) { + +} diff --git a/examples/android/androidEmptyExample/src/ofApp.h b/examples/android/androidEmptyExample/ofApp/src/main/cpp/ofApp.h similarity index 71% rename from examples/android/androidEmptyExample/src/ofApp.h rename to examples/android/androidEmptyExample/ofApp/src/main/cpp/ofApp.h index 2fe90435ddb..fab21d73585 100644 --- a/examples/android/androidEmptyExample/src/ofApp.h +++ b/examples/android/androidEmptyExample/ofApp/src/main/cpp/ofApp.h @@ -8,6 +8,7 @@ class ofApp : public ofxAndroidApp{ public: void setup(); + void exit(); void update(); void draw(); @@ -30,4 +31,9 @@ class ofApp : public ofxAndroidApp{ bool backPressed(); void okPressed(); void cancelPressed(); + + void deviceRefreshRateChanged(int refreshRate); + void deviceHighestRefreshRateChanged(int refreshRate); + void deviceRefreshRateChangedEvent(int &refreshRate); + void deviceHighestRefreshRateChangedEvent(int & refreshRate); }; diff --git a/examples/android/androidEmptyExample/ofApp/src/main/ic_launcher-playstore.png b/examples/android/androidEmptyExample/ofApp/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000000..2a0df19f5e0 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/ic_launcher-playstore.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java b/examples/android/androidEmptyExample/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java new file mode 100644 index 00000000000..598ee50bbf1 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java @@ -0,0 +1,201 @@ +package cc.openframeworks.android; + +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; + +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; + +import cc.openframeworks.OFAndroid; +import cc.openframeworks.OFAndroidLifeCycle; + +import com.getkeepsafe.relinker.ReLinker; + + + +public class OFActivity extends cc.openframeworks.OFActivity { + + private static final String appName = "ofapp"; // modify this to target appName (ofApp etc) + private static final String LOG_TAG = appName + "::OFActivity"; + + private ReLinker.Logger logcatLogger = new ReLinker.Logger() { + @Override + public void log(String message) { + Log.d("ReLinker", message); + } + }; + private OFActivity thisActivity; + + + // Extremely important + public OFActivity() { + OFAndroidLifeCycle.coreLibraryLoaded = true; + + OFAndroid.maxSamples = 4; + OFAndroid.maximumFrameRate = 144; + + thisActivity = this; + ReLinker.log(logcatLogger) + .force() + .recursively() + .loadLibrary(this, appName, new ReLinker.LoadListener() { + @Override + public void success() { + Log.i(LOG_TAG, "loadLibrary success"); + OFAndroidLifeCycle.appLibraryLoaded = true; + Setup(); // very important - this will in turn call main + } + + @Override + public void failure(Throwable t) { + /* Boo */ + Log.i(LOG_TAG, "loadLibrary failure" + t.getMessage()); + } + }); + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + Log.i(LOG_TAG, "onCreate"); + super.onCreate(savedInstanceState); + + setFullscreen(); + hideSystemBars(); + } + + @Override + public void onStart() { + super.onStart(); + + } + + @Override + public void onDetachedFromWindow() { + + } + + // Menus + // http://developer.android.com/guide/topics/ui/menus.html + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Create settings menu options from here, one by one or infalting an xml + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // This passes the menu option string to OF + // you can add additional behavior from java modifying this method + // but keep the call to OFAndroid so OF is notified of menu events + if(OFAndroid.menuItemSelected(item.getItemId())){ + + return true; + } + return super.onOptionsItemSelected(item); + } + + + @Override + public boolean onPrepareOptionsMenu (Menu menu){ + // This method is called every time the menu is opened + // you can add or remove menu options from here + return super.onPrepareOptionsMenu(menu); + } + + public void onRestore() { + + if (!OFAndroidLifeCycle.appLibraryLoaded) return; + } + + private void hideSystemBars() { + WindowInsetsControllerCompat windowInsetsController = + ViewCompat.getWindowInsetsController(getWindow().getDecorView()); + if (windowInsetsController == null) { + return; + } + // Configure the behavior of the hidden system bars + windowInsetsController.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + ); + // Hide both the status bar and the navigation bar + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + + if (hasFocus) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + + setFullscreen(); + } else { + setFullscreen(); + } + } else { + + } + } + + private void handleException(Exception e, String details) { + Log.e(LOG_TAG, "Exception:", e); + + } + + public void setFullscreen() { + try { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + // No sticky immersive mode for devices pre-kitkat + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } else { + View decorView = getWindow().getDecorView(); +// int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; + int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + decorView.setSystemUiVisibility(uiOptions); + } + + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + + } catch (Exception ex) { + handleException(ex, "setFullscreen exception"); + } + + try { + View decorView = getWindow().getDecorView(); + int[] locations = new int[2]; + decorView.getLocationInWindow(locations); + int[] locations2 = new int[2]; + decorView.getLocationOnScreen(locations2); + + } catch (Exception ex) { + handleException(ex, "setFullscreen exception"); + } + + WindowInsetsControllerCompat windowInsetsController = + ViewCompat.getWindowInsetsController(getWindow().getDecorView()); + if (windowInsetsController == null) { + return; + } + // Hide both the status bar and the navigation bar + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); + windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars()); + windowInsetsController.hide(WindowInsetsCompat.Type.statusBars()); + } + + +} + diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/drawable-hdpi/icon.png b/examples/android/androidEmptyExample/ofApp/src/main/res/drawable-hdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/drawable-hdpi/icon.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/drawable-mdpi/icon.png b/examples/android/androidEmptyExample/ofApp/src/main/res/drawable-mdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/drawable-mdpi/icon.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/drawable-xhdpi/icon.png b/examples/android/androidEmptyExample/ofApp/src/main/res/drawable-xhdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/drawable-xhdpi/icon.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/drawable/icon.png b/examples/android/androidEmptyExample/ofApp/src/main/res/drawable/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/drawable/icon.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/layout/main_layout.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/layout/main_layout.xml new file mode 100644 index 00000000000..d1da461f079 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/layout/main_layout.xml @@ -0,0 +1,24 @@ + + + + + + diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/menu/main_layout.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/menu/main_layout.xml new file mode 100644 index 00000000000..7ddcfbee35e --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/menu/main_layout.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000000..036d09bc5fd --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000000..036d09bc5fd --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000000..42b40d2fbec Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..648779fe415 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000000..a39d8826804 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000000..13e6dfef882 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..67b93c29890 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000000..93401eaf855 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000000..018f9b90738 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..fc64ec1c838 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..486c62f1f2a Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000000..cf6c612f8b1 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..07b98443e1b Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..b4024c5aa00 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000000..60b1a9e8332 Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..45bd0178fee Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..1b64c2ce02d Binary files /dev/null and b/examples/android/androidEmptyExample/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/values-v11/strings.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/values-v11/strings.xml new file mode 100644 index 00000000000..5822f1306d1 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/values-v11/strings.xml @@ -0,0 +1,5 @@ + + + ofEmptyEx + Menu + \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/values-v11/styles.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/values-v11/styles.xml new file mode 100644 index 00000000000..febc4d0286b --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/values-v11/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/values-v14/strings.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/values-v14/strings.xml new file mode 100644 index 00000000000..5822f1306d1 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/values-v14/strings.xml @@ -0,0 +1,5 @@ + + + ofEmptyEx + Menu + \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/values-v14/styles.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/values-v14/styles.xml new file mode 100644 index 00000000000..928e0fd3d72 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/values-v14/styles.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/values/ic_launcher_background.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000000..c5d5899fdf0 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/values/strings.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/values/strings.xml new file mode 100644 index 00000000000..5822f1306d1 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + + ofEmptyEx + Menu + \ No newline at end of file diff --git a/examples/android/androidEmptyExample/ofApp/src/main/res/values/styles.xml b/examples/android/androidEmptyExample/ofApp/src/main/res/values/styles.xml new file mode 100644 index 00000000000..766a2c3f143 --- /dev/null +++ b/examples/android/androidEmptyExample/ofApp/src/main/res/values/styles.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/examples/android/androidEmptyExample/proguard.cfg b/examples/android/androidEmptyExample/proguard.cfg new file mode 100644 index 00000000000..faee26e7f2b --- /dev/null +++ b/examples/android/androidEmptyExample/proguard.cfg @@ -0,0 +1,59 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class com.android.vending.licensing.ILicensingService + +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } + +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +-keep class com.google.android.gms.common.api.** { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} diff --git a/examples/android/androidEmptyExample/settings.gradle b/examples/android/androidEmptyExample/settings.gradle new file mode 100644 index 00000000000..cb352f426c0 --- /dev/null +++ b/examples/android/androidEmptyExample/settings.gradle @@ -0,0 +1,11 @@ +include ':ofApp' + +// Define the relative path to the openFrameworks project +def openFrameworksProjectPath = '../../../libs/openFrameworksCompiled/project' + +// Convert the relative path to an absolute path +def openFrameworksProjectAbsolutePath = new File(rootDir, openFrameworksProjectPath).absolutePath + +// Include the openFrameworks project +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(openFrameworksProjectAbsolutePath) diff --git a/examples/android/androidEmptyExample/src/main.cpp b/examples/android/androidEmptyExample/src/main.cpp deleted file mode 100644 index 596b934783a..00000000000 --- a/examples/android/androidEmptyExample/src/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -int main(){ - ofSetupOpenGL(1024,768, OF_WINDOW); // <-------- setup the GL context - - // this kicks off the running of my app - // can be OF_WINDOW or OF_FULLSCREEN - // pass in width and height too: - ofRunApp( new ofApp() ); - return 0; -} - - -#ifdef TARGET_ANDROID -void ofAndroidApplicationInit() -{ - //application scope init -} - -void ofAndroidActivityInit() -{ - //activity scope init - main(); -} -#endif - - diff --git a/libs/openFrameworks/app/ofMainLoop.cpp b/libs/openFrameworks/app/ofMainLoop.cpp index 461a7f1c2e3..8e36fbae9d0 100644 --- a/libs/openFrameworks/app/ofMainLoop.cpp +++ b/libs/openFrameworks/app/ofMainLoop.cpp @@ -103,6 +103,8 @@ void ofMainLoop::run(const std::shared_ptr & window, std::share ofAddListener(ofxAndroidEvents().reloadGL,androidApp,&ofxAndroidApp::reloadGL,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().swipe,androidApp,&ofxAndroidApp::swipe,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().deviceOrientationChanged,androidApp,&ofxAndroidApp::deviceOrientationChangedEvent,OF_EVENT_ORDER_APP); + ofAddListener(ofxAndroidEvents().deviceHighestRefreshRate,androidApp,&ofxAndroidApp::deviceHighestRefreshRateChangedEvent,OF_EVENT_ORDER_APP); + ofAddListener(ofxAndroidEvents().deviceRefreshRate,androidApp,&ofxAndroidApp::deviceRefreshRateChangedEvent,OF_EVENT_ORDER_APP); } #endif } @@ -207,6 +209,8 @@ void ofMainLoop::exit(){ ofRemoveListener(ofxAndroidEvents().reloadGL,androidApp,&ofxAndroidApp::reloadGL,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().swipe,androidApp,&ofxAndroidApp::swipe,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().deviceOrientationChanged,androidApp,&ofxAndroidApp::deviceOrientationChangedEvent,OF_EVENT_ORDER_APP); + ofRemoveListener(ofxAndroidEvents().deviceHighestRefreshRate,androidApp,&ofxAndroidApp::deviceHighestRefreshRateChangedEvent,OF_EVENT_ORDER_APP); + ofRemoveListener(ofxAndroidEvents().deviceRefreshRate,androidApp,&ofxAndroidApp::deviceRefreshRateChangedEvent,OF_EVENT_ORDER_APP); } #endif } diff --git a/libs/openFrameworks/gl/ofFbo.cpp b/libs/openFrameworks/gl/ofFbo.cpp index fe9db48486d..edf6e842e5f 100644 --- a/libs/openFrameworks/gl/ofFbo.cpp +++ b/libs/openFrameworks/gl/ofFbo.cpp @@ -17,6 +17,7 @@ #include #endif #ifdef TARGET_ANDROID +#include "ofEventUtils.h" #include "ofxAndroidUtils.h" #endif @@ -35,7 +36,7 @@ using std::vector; #if defined(TARGET_OPENGLES) & !defined(TARGET_EMSCRIPTEN) bool ofFbo::bglFunctionsInitialized=false; - + typedef void (* glGenFramebuffersType) (GLsizei n, GLuint* framebuffers); glGenFramebuffersType glGenFramebuffersFunc; #define glGenFramebuffers glGenFramebuffersFunc @@ -496,7 +497,7 @@ void ofFbo::destroy() { //-------------------------------------------------------------- bool ofFbo::checkGLSupport() { #ifndef TARGET_OPENGLES - + if (!ofIsGLProgrammableRenderer()){ if(ofGLCheckExtension("GL_EXT_framebuffer_object")){ ofLogVerbose("ofFbo") << "GL frame buffer object supported"; @@ -535,7 +536,7 @@ void ofFbo::allocate(int width, int height, int internalformat, int numSamples) settings.height = height; settings.internalformat = internalformat; settings.numSamples = numSamples; - + #ifdef TARGET_OPENGLES settings.useDepth = false; settings.useStencil = false; @@ -544,10 +545,10 @@ void ofFbo::allocate(int width, int height, int internalformat, int numSamples) #else settings.useDepth = true; settings.useStencil = true; - //we do this as the fbo and the settings object it contains could be created before the user had the chance to disable or enable arb rect. - settings.textureTarget = ofGetUsingArbTex() ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D; -#endif - + //we do this as the fbo and the settings object it contains could be created before the user had the chance to disable or enable arb rect. + settings.textureTarget = ofGetUsingArbTex() ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D; +#endif + allocate(settings); } @@ -577,7 +578,7 @@ void ofFbo::allocate(ofFboSettings _settings) { _settings.numSamples = 0; } - //currently depth only works if stencil is enabled. + //currently depth only works if stencil is enabled. // http://forum.openframeworks.cc/index.php/topic,6837.0.html #ifdef TARGET_OPENGLES if(_settings.useDepth){ @@ -588,7 +589,7 @@ void ofFbo::allocate(ofFboSettings _settings) { ofLogWarning("ofFbo") << "allocate(): depthStencilAsTexture is not available for iOS"; } #endif - + GLenum depthAttachment = GL_DEPTH_ATTACHMENT; if( _settings.useDepth && _settings.useStencil ){ @@ -620,8 +621,8 @@ void ofFbo::allocate(ofFboSettings _settings) { GLint previousFboId = 0; // note that we are using a glGetInteger method here, which may stall the pipeline. - // in the allocate() method, this is not that tragic since this will not be called - // within the draw() loop. Here, we need not optimise for performance, but for + // in the allocate() method, this is not that tragic since this will not be called + // within the draw() loop. Here, we need not optimise for performance, but for // simplicity and readability . glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previousFboId); @@ -656,7 +657,7 @@ void ofFbo::allocate(ofFboSettings _settings) { #endif } } - + settings.useDepth = _settings.useDepth; settings.useStencil = _settings.useStencil; settings.depthStencilInternalFormat = _settings.depthStencilInternalFormat; @@ -696,7 +697,7 @@ void ofFbo::allocate(ofFboSettings _settings) { #endif } settings.internalformat = _settings.internalformat; - + dirty.resize(_settings.colorFormats.size(), true); // we start with all color buffers dirty. // if textures are attached to a different fbo (e.g. if using MSAA) check it's status @@ -711,10 +712,10 @@ void ofFbo::allocate(ofFboSettings _settings) { glBindFramebuffer(GL_FRAMEBUFFER, previousFboId); /* UNCOMMENT OUTSIDE OF DOING RELEASES - + // this should never happen if(settings != _settings) ofLogWarning("ofFbo") << "allocation not complete, passed settings not equal to created ones, this is an internal OF bug"; - + */ #ifdef TARGET_ANDROID ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); @@ -757,7 +758,7 @@ GLuint ofFbo::createAndAttachRenderbuffer(GLenum internalFormat, GLenum attachme //---------------------------------------------------------- void ofFbo::createAndAttachTexture(GLenum internalFormat, GLenum attachmentPoint) { - + ofTextureData texData; texData.textureTarget = settings.textureTarget; @@ -784,21 +785,21 @@ void ofFbo::attachTexture(ofTexture & tex, GLenum internalFormat, GLenum attachm GLint temp; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &temp); glBindFramebuffer(GL_FRAMEBUFFER, fboTextures); - + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachmentPoint, tex.texData.textureTarget, tex.texData.textureID, 0); if(attachmentPoint >= textures.size()) { textures.resize(attachmentPoint+1); } textures[attachmentPoint] = tex; - + settings.colorFormats.resize(attachmentPoint + 1); settings.colorFormats[attachmentPoint] = internalFormat; settings.numColorbuffers = settings.colorFormats.size(); - + // if MSAA, bind main fbo and attach renderbuffer if(settings.numSamples) { glBindFramebuffer(GL_FRAMEBUFFER, fbo); - + GLuint colorBuffer = createAndAttachRenderbuffer(internalFormat, GL_COLOR_ATTACHMENT0 + attachmentPoint); colorBuffers.push_back(colorBuffer); retainRB(colorBuffer); @@ -817,7 +818,7 @@ void ofFbo::createAndAttachDepthStencilTexture(GLenum target, GLint internalform depthBufferTex.texData.bFlipTexture = false; depthBufferTex.texData.width = settings.width; depthBufferTex.texData.height = settings.height; - + depthBufferTex.allocate(depthBufferTex.texData,transferFormat,transferType); glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, target, depthBufferTex.texData.textureID, 0); @@ -832,7 +833,7 @@ void ofFbo::createAndAttachDepthStencilTexture(GLenum target, GLint internalform depthBufferTex.texData.bFlipTexture = false; depthBufferTex.texData.width = settings.width; depthBufferTex.texData.height = settings.height; - + depthBufferTex.allocate(depthBufferTex.texData); glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, target, depthBufferTex.texData.textureID, 0); @@ -922,10 +923,10 @@ void ofFbo::flagDirty() const{ // // All currently active draw buffers need to be flagged dirty // - // If a draw buffer has been activated and then de-activated, it has been - // flagged dirty at activation, so we can be sure all buffers which have + // If a draw buffer has been activated and then de-activated, it has been + // flagged dirty at activation, so we can be sure all buffers which have // been rendered to are flagged dirty. - // + // int numBuffersToFlag = std::min(dirty.size(), activeDrawBuffers.size()); for(int i=0; i < numBuffersToFlag; i++){ dirty[i] = true; @@ -1020,7 +1021,7 @@ ofTexture& ofFbo::getTexture(){ //---------------------------------------------------------- ofTexture& ofFbo::getTexture(int attachmentPoint) { updateTexture(attachmentPoint); - + return textures[attachmentPoint]; } @@ -1111,7 +1112,7 @@ void ofFbo::updateTexture(int attachmentPoint) { if(!bIsAllocated) return; #ifndef TARGET_OPENGLES if(fbo != fboTextures && dirty[attachmentPoint]) { - + // if fbo != fboTextures, we are dealing with an MSAA enabled FBO. // and we need to blit one fbo into another to see get the texture // content @@ -1125,11 +1126,11 @@ void ofFbo::updateTexture(int attachmentPoint) { if(renderer){ GLint readBuffer; glGetIntegerv(GL_READ_BUFFER, &readBuffer); - + renderer->bindForBlitting(*this,*this,attachmentPoint); glBlitFramebuffer(0, 0, settings.width, settings.height, 0, 0, settings.width, settings.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); renderer->unbind(*this); - + glReadBuffer(readBuffer); } diff --git a/libs/openFrameworks/gl/ofVboMesh.cpp b/libs/openFrameworks/gl/ofVboMesh.cpp index c55083ce480..96d15abf5ae 100644 --- a/libs/openFrameworks/gl/ofVboMesh.cpp +++ b/libs/openFrameworks/gl/ofVboMesh.cpp @@ -24,6 +24,7 @@ ofVboMesh::ofVboMesh(const ofMesh & mom) vboNumColors = 0; vboNumTexCoords = 0; vboNumNormals = 0; + updateSet = false; } void ofVboMesh::operator=(const ofMesh & mom) diff --git a/libs/openFrameworks/graphics/ofPixels.cpp b/libs/openFrameworks/graphics/ofPixels.cpp index 134b40ef8cf..4a3b2273933 100644 --- a/libs/openFrameworks/graphics/ofPixels.cpp +++ b/libs/openFrameworks/graphics/ofPixels.cpp @@ -168,7 +168,7 @@ static size_t channelsFromPixelFormat(ofPixelFormat format){ return 2; break; default: - ofLog(OF_LOG_ERROR,"ofPixels: format doesn't support channels"); + ofLogError("ofPixels") << "format doesn't support channels"; return 1; } } @@ -185,7 +185,7 @@ static ofPixelFormat ofPixelFormatFromImageType(ofImageType type){ return OF_PIXELS_RGBA; break; default: - ofLog(OF_LOG_ERROR,"ofPixels: image type not supported"); + ofLogError("ofPixels") << "image type not supported"; return OF_PIXELS_UNKNOWN; } } @@ -207,7 +207,7 @@ static ofImageType ofImageTypeFromPixelFormat(ofPixelFormat pixelFormat){ case OF_PIXELS_UNKNOWN: return OF_IMAGE_UNDEFINED; default: - ofLog(OF_LOG_ERROR,"ofPixels: image type not supported"); + ofLogError("ofPixels") << "image type not supported"; return OF_IMAGE_UNDEFINED; } } diff --git a/libs/openFrameworks/utils/ofConstants.h b/libs/openFrameworks/utils/ofConstants.h index c8cee848cd8..28e03fdc64d 100644 --- a/libs/openFrameworks/utils/ofConstants.h +++ b/libs/openFrameworks/utils/ofConstants.h @@ -411,11 +411,11 @@ typedef TESSindex ofIndexType; #elif __has_include() // If we're compiling on Visual Studio and are not compiling with C++17, we need to use experimental #ifdef _MSC_VER - + // Check and include header that defines "_HAS_CXX17" #if __has_include() #include - + // Check for enabled C++17 support #if defined(_HAS_CXX17) && _HAS_CXX17 // We're using C++17, so let's use the normal version diff --git a/libs/openFrameworks/video/ofGstUtils.cpp b/libs/openFrameworks/video/ofGstUtils.cpp index c7dd974e8ac..4cc21f8811a 100644 --- a/libs/openFrameworks/video/ofGstUtils.cpp +++ b/libs/openFrameworks/video/ofGstUtils.cpp @@ -290,12 +290,12 @@ bool ofGstUtils::startPipeline(){ ofLogVerbose() << "Pipeline is PREROLLED"; break; } - + if(isAppSink){ ofLogVerbose("ofGstUtils") << "startPipeline(): attaching callbacks"; bool bSignals = false; - + #if GST_VERSION_MAJOR==0 GstAppSinkCallbacks gstCallbacks; @@ -303,15 +303,15 @@ bool ofGstUtils::startPipeline(){ gstCallbacks.new_preroll = &on_new_preroll_from_source; gstCallbacks.new_buffer = &on_new_buffer_from_source; gst_app_sink_set_callbacks(GST_APP_SINK(gstSink), &gstCallbacks, this, NULL); - -#elseif GST_VERSION_MINOR <= 18 + +#elif GST_VERSION_MINOR <= 18 GstAppSinkCallbacks gstCallbacks; gstCallbacks.eos = &on_eos_from_source; gstCallbacks.new_preroll = &on_new_preroll_from_source; gstCallbacks.new_sample = &on_new_buffer_from_source; gst_app_sink_set_callbacks(GST_APP_SINK(gstSink), &gstCallbacks, this, NULL); - + #else //GStreamer 1.20 onwards crashes with the callback approach above. @@ -319,7 +319,7 @@ bool ofGstUtils::startPipeline(){ g_signal_connect(GST_APP_SINK(gstSink), "eos", G_CALLBACK(on_eos_from_source), this); g_signal_connect(GST_APP_SINK(gstSink), "new-sample", G_CALLBACK(on_new_buffer_from_source), this); g_signal_connect(GST_APP_SINK(gstSink), "new-preroll", G_CALLBACK(on_new_preroll_from_source), this); - + bSignals = true; #endif @@ -330,7 +330,7 @@ bool ofGstUtils::startPipeline(){ gst_app_sink_set_max_buffers(GST_APP_SINK(gstSink),3); gst_app_sink_set_drop (GST_APP_SINK(gstSink),true); } - + // wait for paused state to query the duration if(!isStream){ bPlaying = true; @@ -524,7 +524,7 @@ void ofGstUtils::setSpeed(float _speed){ needPos = false; } #endif - + if(_speed > 1 || _speed < -1){ flags = (GstSeekFlags)(flags | GST_SEEK_FLAG_SKIP); } @@ -533,7 +533,7 @@ void ofGstUtils::setSpeed(float _speed){ gst_element_set_state (gstPipeline, GST_STATE_PAUSED); return; } - + gint64 pos = 0; GstSeekType seekType = GST_SEEK_TYPE_NONE; @@ -776,7 +776,7 @@ bool ofGstUtils::gstHandleMessage(GstBus * bus, GstMessage * msg){ g_free (name); break; } - + #if GST_VERSION_MAJOR==1 && GST_VERSION_MINOR>=2 case GST_MESSAGE_HAVE_CONTEXT:{ GstContext *context; @@ -880,7 +880,7 @@ void ofGstVideoUtils::close(){ bBackPixelsChanged = false; frontBuffer.reset(); backBuffer.reset(); - + #if GST_VERSION_MAJOR==1 while(!bufferQueue.empty()) bufferQueue.pop(); #endif diff --git a/libs/openFrameworks/video/ofVideoBaseTypes.cpp b/libs/openFrameworks/video/ofVideoBaseTypes.cpp new file mode 100644 index 00000000000..d8e0b63f72f --- /dev/null +++ b/libs/openFrameworks/video/ofVideoBaseTypes.cpp @@ -0,0 +1 @@ +#include "ofVideoBaseTypes.h" diff --git a/libs/openFrameworksCompiled/project/CMake/toolchain/android.toolchain.cmake b/libs/openFrameworksCompiled/project/CMake/toolchain/android.toolchain.cmake new file mode 100644 index 00000000000..10af96f156a --- /dev/null +++ b/libs/openFrameworksCompiled/project/CMake/toolchain/android.toolchain.cmake @@ -0,0 +1,166 @@ +# Android Toolchain CMake Configuration +cmake_minimum_required(VERSION 3.14) + +# Add additional flags or settings if needed +set(CMAKE_ANDROID_STL_TYPE "c++_shared") # Adjust STL type if needed + +if(NOT DEFINED C_STANDARD) + set(C_STANDARD 17) # Default to C17 +endif() +if(NOT DEFINED CPP_STANDARD) + set(CPP_STANDARD 17) # Default to C++17 +endif() +set(CMAKE_C_STANDARD ${C_STANDARD}) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_CXX_STANDARD ${CPP_STANDARD}) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + + +if(NOT DEFINED ANDROID_ABI) + if(DEFINED ENV{ANDROID_ABI}) + set(ANDROID_ABI $ENV{ANDROID_ABI}) + else() + message(FATAL_ERROR "ANDROID_ABI must be specified (e.g., armeabi-v7a, arm64-v8a, x86, x86_64)") + endif() +endif() + +if(NOT DEFINED ANDROID_NDK_ROOT) + if(DEFINED ENV{ANDROID_NDK_ROOT}) + set(ANDROID_NDK_ROOT $ENV{ANDROID_NDK_ROOT}) + else() + message(FATAL_ERROR "ANDROID_NDK_ROOT must be specified as the path to the Android NDK") + endif() +endif() + +if(NOT DEFINED ANDROID_API) + if(DEFINED ENV{ANDROID_API}) + set(ANDROID_API $ENV{ANDROID_API}) + else() + message(FATAL_ERROR "ANDROID_API must be specified as the path to the ANDROID_API") + endif() +endif() +set(ANDROID_NATIVE_API_LEVEL ${ANDROID_API}) + +# Detect Host Platform +if(NOT DEFINED HOST_PLATFORM) + if(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin") + if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm64") + set(HOST_PLATFORM "darwin-arm64") + else() + set(HOST_PLATFORM "darwin-x86_64") + endif() + elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Windows") + set(HOST_PLATFORM "windows-x86_64") # Windows ARM64 is rare, adjust if needed + elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux") + if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") + set(HOST_PLATFORM "linux-arm64") + else() + set(HOST_PLATFORM "linux-x86_64") + endif() + else() + message(FATAL_ERROR "Unsupported host platform: ${CMAKE_HOST_SYSTEM_NAME} (${CMAKE_HOST_SYSTEM_PROCESSOR})") + endif() +endif() + +message(STATUS "Android ABI: ${ANDROID_ABI}") +message(STATUS "Detected Host Platform: ${HOST_PLATFORM}") + +# NDK Configuration +set(TOOLCHAIN_TYPE "llvm") + +set(TOOLCHAIN "${ANDROID_NDK_ROOT}/toolchains/${TOOLCHAIN_TYPE}/prebuilt/${HOST_PLATFORM}") +set(SYSROOT "${TOOLCHAIN}/sysroot") + +# ABI-specific configuration +if(ANDROID_ABI STREQUAL "armeabi-v7a") + set(MACHINE "armv7") + set(ANDROID_PREFIX "armv7a-linux-androideabi") + set(ANDROID_TARGET "armv7a-none-linux-androideabi${ANDROID_NATIVE_API_LEVEL}") + set(CMAKE_ANDROID_ARM_MODE ON) + set(CMAKE_ANDROID_ARM_NEON ON) + set(CMAKE_SYSTEM_PROCESSOR "armv7-a") + set(CMAKE_C_FLAGS "-mfpu=neon -mfloat-abi=softfp -O3 -ffast-math -funroll-loops -funsafe-math-optimizations --target=${ANDROID_TARGET}") + set(CMAKE_CXX_FLAGS "-mfpu=neon -mfloat-abi=softfp -O3 -ffast-math -funroll-loops -funsafe-math-optimizations --target=${ANDROID_TARGET}") +elseif(ANDROID_ABI STREQUAL "arm64-v8a") + set(MACHINE "arm64") + set(ANDROID_PREFIX "aarch64-linux-android") + set(ANDROID_TARGET "aarch64-none-linux-android${ANDROID_NATIVE_API_LEVEL}") + set(CMAKE_SYSTEM_PROCESSOR "aarch64") + set(CMAKE_C_FLAGS "-O3 -ffast-math -funroll-loops -funsafe-math-optimizations --target=${ANDROID_TARGET}") + set(CMAKE_CXX_FLAGS "-O3 -ffast-math -funroll-loops -funsafe-math-optimizations --target=${ANDROID_TARGET}") +elseif(ANDROID_ABI STREQUAL "x86") + set(MACHINE "i686") + set(ANDROID_PREFIX "i686-linux-android") + set(ANDROID_TARGET "i686-none-linux-android${ANDROID_NATIVE_API_LEVEL}") + set(CMAKE_SYSTEM_PROCESSOR "i686") + set(CMAKE_C_FLAGS "-msse4.2 -mavx -O3 -ffast-math -funroll-loops") + set(CMAKE_CXX_FLAGS "-msse4.2 -mavx -O3 -ffast-math -funroll-loops") +elseif(ANDROID_ABI STREQUAL "x86_64") + set(MACHINE "x86_64") + set(ANDROID_PREFIX "x86_64-linux-android") + set(ANDROID_TARGET "x86_64-none-linux-android${ANDROID_NATIVE_API_LEVEL}") + set(CMAKE_SYSTEM_PROCESSOR "x86_64") + set(CMAKE_C_FLAGS "-msse4.2 -mavx -O3 -ffast-math -funroll-loops --target=${ANDROID_TARGET}") + set(CMAKE_CXX_FLAGS "-msse4.2 -mavx -O3 -ffast-math -funroll-loops --target=${ANDROID_TARGET}") +else() + message(FATAL_ERROR "Unsupported ANDROID_ABI: ${ANDROID_ABI}") +endif() + +message(STATUS "Configuring for ABI: ${ANDROID_ABI}") +message(STATUS "Machine: ${MACHINE}") +message(STATUS "Android Prefix: ${ANDROID_PREFIX}") + +message(STATUS "CMAKE_C_COMPILER: ${TOOLCHAIN}/bin/${ANDROID_PREFIX}${CMAKE_ANDROID_API}${ANDROID_API}-clang") +message(STATUS "CMAKE_CXX_COMPILER: ${TOOLCHAIN}/bin/${ANDROID_PREFIX}${CMAKE_ANDROID_API}${ANDROID_API}-clang++") + +# Set compilers +set(CMAKE_C_COMPILER "${TOOLCHAIN}/bin/${ANDROID_PREFIX}${CMAKE_ANDROID_API}${ANDROID_API}-clang") +set(CMAKE_CXX_COMPILER "${TOOLCHAIN}/bin/${ANDROID_PREFIX}${CMAKE_ANDROID_API}${ANDROID_API}-clang++") +set(CMAKE_LINKER "${TOOLCHAIN}/bin/ld.lld") + +# Paths +set(CMAKE_SYSROOT ${SYSROOT}) +set(CMAKE_FIND_ROOT_PATH ${SYSROOT}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +# Include and library paths +set(CMAKE_INCLUDE_PATH "${SYSROOT}/usr/include") +set(CMAKE_LIBRARY_PATH "${SYSROOT}/usr/lib/${ANDROID_PREFIX}/${CMAKE_ANDROID_API}") + +# Compiler Binary +set(BIN_PREFIX "${TOOLCHAIN_ROOT}/bin/") + +#find_program(CMAKE_C_COMPILER clang PATHS "${TOOLCHAIN_ROOT}/bin/") +##find_program(CMAKE_CXX_COMPILER clang++ PATHS "${TOOLCHAIN_ROOT}/bin/") +#find_program(CMAKE_LINKER ld.lld PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_AR llvm-ar PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_NM llvm-nm PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_RANLIB llvm-ranlib PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_STRIP llvm-strip PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_OBJCOPY llvm-objcopy PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_OBJDUMP llvm-objdump PATHS "${TOOLCHAIN_ROOT}/bin/") + +# Toolchain Debug Output +message(STATUS "---Android TOOLCHAIN CONFIGURATION") +message(STATUS "Host Platform: ${HOST_PLATFORM}") +message(STATUS "ANDROID_NDK_ROOT : ${ANDROID_NDK_ROOT}") +message(STATUS "Sysroot: ${SYSROOT}") +message(STATUS "Toolchain: ${TOOLCHAIN}") +message(STATUS "ABI: ${ANDROID_ABI}") +message(STATUS "C Compiler: ${CMAKE_C_COMPILER}") +message(STATUS "C++ Compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "Linker: ${CMAKE_LINKER}") + +# Finalize toolchain settings +set(CMAKE_SYSTEM_NAME "Android") +set(CMAKE_SYSTEM_VERSION ${CMAKE_ANDROID_API}) +set(CMAKE_ANDROID_NDK ${ANDROID_NDK_ROOT}) + +if(NOT EXISTS ${CMAKE_C_COMPILER}) + message(FATAL_ERROR "C Compiler not found: ${CMAKE_C_COMPILER}") +endif() +if(NOT EXISTS ${CMAKE_CXX_COMPILER}) + message(FATAL_ERROR "C++ Compiler not found: ${CMAKE_CXX_COMPILER}") +endif() diff --git a/libs/openFrameworksCompiled/project/CMake/toolchain/ios.toolchain.cmake b/libs/openFrameworksCompiled/project/CMake/toolchain/ios.toolchain.cmake new file mode 100644 index 00000000000..509ca4b008c --- /dev/null +++ b/libs/openFrameworksCompiled/project/CMake/toolchain/ios.toolchain.cmake @@ -0,0 +1,1116 @@ +# This file is part of the ios-cmake project. It was retrieved from +# https://github.com/leetal/ios-cmake.git, which is a fork of +# https://github.com/gerstrong/ios-cmake.git, which is a fork of +# https://github.com/cristeab/ios-cmake.git, which is a fork of +# https://code.google.com/p/ios-cmake/. Which in turn is based off of +# the Platform/Darwin.cmake and Platform/UnixPaths.cmake files which +# are included with CMake 2.8.4 +# +# The ios-cmake project is licensed under the new BSD license. +# +# Copyright (c) 2014, Bogdan Cristea and LTE Engineering Software, +# Kitware, Inc., Insight Software Consortium. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. 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. +# +# 3. Neither the name of the copyright holder 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 HOLDER 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. +# +# This file is based on the Platform/Darwin.cmake and +# Platform/UnixPaths.cmake files which are included with CMake 2.8.4 +# It has been altered for iOS development. +# +# Updated by Alex Stewart (alexs.mac@gmail.com) +# +# ***************************************************************************** +# Now maintained by Alexander Widerberg (widerbergaren [at] gmail.com) +# under the BSD-3-Clause license +# https://github.com/leetal/ios-cmake +# ***************************************************************************** +# +# INFORMATION / HELP +# +############################################################################### +# OPTIONS # +############################################################################### +# +# PLATFORM: (default "OS64") +# OS = Build for iPhoneOS. +# OS64 = Build for arm64 iphoneOS. +# OS64COMBINED = Build for arm64 x86_64 iphoneOS + iphoneOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR = Build for x86 i386 iphoneOS Simulator. +# SIMULATOR64 = Build for x86_64 iphoneOS Simulator. +# SIMULATORARM64 = Build for arm64 iphoneOS Simulator. +# SIMULATOR64COMBINED = Build for arm64 x86_64 iphoneOS Simulator. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) +# TVOS = Build for arm64 tvOS. +# TVOSCOMBINED = Build for arm64 x86_64 tvOS + tvOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR_TVOS = Build for x86_64 tvOS Simulator. +# SIMULATORARM64_TVOS = Build for arm64 tvOS Simulator. +# WATCHOS = Build for armv7k arm64_32 for watchOS. +# WATCHOSCOMBINED = Build for armv7k arm64_32 x86_64 watchOS + watchOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR_WATCHOS = Build for x86_64 for watchOS Simulator. +# SIMULATORARM64_WATCHOS = Build for arm64 for watchOS Simulator. +# MAC = Build for x86_64 macOS. +# MAC_ARM64 = Build for Apple Silicon macOS. +# MAC_UNIVERSAL = Combined build for x86_64 and Apple Silicon on macOS. +# MAC_CATALYST = Build for x86_64 macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# MAC_CATALYST_ARM64 = Build for Apple Silicon macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# +# CMAKE_OSX_SYSROOT: Path to the SDK to use. By default this is +# automatically determined from PLATFORM and xcodebuild, but +# can also be manually specified (although this should not be required). +# +# CMAKE_DEVELOPER_ROOT: Path to the Developer directory for the platform +# being compiled for. By default, this is automatically determined from +# CMAKE_OSX_SYSROOT, but can also be manually specified (although this should +# not be required). +# +# DEPLOYMENT_TARGET: Minimum SDK version to target. Default 6.0 on watchOS, 13.0 on tvOS+iOS/iPadOS, 11.0 on macOS, 1.0 on visionOS +# +# NAMED_LANGUAGE_SUPPORT: +# ON (default) = Will require "enable_language(OBJC) and/or enable_language(OBJCXX)" for full OBJC|OBJCXX support +# OFF = Will embed the OBJC and OBJCXX flags into the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS (legacy behavior, CMake version < 3.16) +# +# ENABLE_BITCODE: (ON|OFF) Enables or disables bitcode support. Default OFF +# +# ENABLE_ARC: (ON|OFF) Enables or disables ARC support. Default ON (ARC enabled by default) +# +# ENABLE_VISIBILITY: (ON|OFF) Enables or disables symbol visibility support. Default OFF (visibility hidden by default) +# +# ENABLE_STRICT_TRY_COMPILE: (ON|OFF) Enables or disables strict try_compile() on all Check* directives (will run linker +# to actually check if linking is possible). Default OFF (will set CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY) +# +# ARCHS: (armv7 armv7s armv7k arm64 arm64_32 i386 x86_64) If specified, will override the default architectures for the given PLATFORM +# OS = armv7 armv7s arm64 (if applicable) +# OS64 = arm64 (if applicable) +# SIMULATOR = i386 +# SIMULATOR64 = x86_64 +# SIMULATORARM64 = arm64 +# TVOS = arm64 +# SIMULATOR_TVOS = x86_64 (i386 has since long been deprecated) +# SIMULATORARM64_TVOS = arm64 +# WATCHOS = armv7k arm64_32 (if applicable) +# SIMULATOR_WATCHOS = x86_64 (i386 has since long been deprecated) +# SIMULATORARM64_WATCHOS = arm64 +# MAC = x86_64 +# MAC_ARM64 = arm64 +# MAC_UNIVERSAL = x86_64 arm64 +# MAC_CATALYST = x86_64 +# MAC_CATALYST_ARM64 = arm64 +# +# NOTE: When manually specifying ARCHS, put a semi-colon between the entries. E.g., -DARCHS="armv7;arm64" +# +############################################################################### +# END OPTIONS # +############################################################################### +# +# This toolchain defines the following properties (available via get_property()) for use externally: +# +# PLATFORM: The currently targeted platform. +# XCODE_VERSION: Version number (not including Build version) of Xcode detected. +# SDK_VERSION: Version of SDK being used. +# OSX_ARCHITECTURES: Architectures being compiled for (generated from PLATFORM). +# APPLE_TARGET_TRIPLE: Used by autoconf build systems. NOTE: If "ARCHS" is overridden, this will *NOT* be set! +# +# This toolchain defines the following macros for use externally: +# +# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE XCODE_VARIANT) +# A convenience macro for setting xcode specific properties on targets. +# Available variants are: All, Release, RelWithDebInfo, Debug, MinSizeRel +# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1" "all"). +# +# find_host_package (PROGRAM ARGS) +# A macro used to find executable programs on the host system, not within the +# environment. Thanks to the android-cmake project for providing the +# command. +# + +cmake_minimum_required(VERSION 3.8.0) + +# CMake invokes the toolchain file twice during the first build, but only once during subsequent rebuilds. +if(DEFINED ENV{_IOS_TOOLCHAIN_HAS_RUN}) + return() +endif() +set(ENV{_IOS_TOOLCHAIN_HAS_RUN} true) + +# List of supported platform values +list(APPEND _supported_platforms + "OS" "OS64" "OS64COMBINED" "SIMULATOR" "SIMULATOR64" "SIMULATORARM64" "SIMULATOR64COMBINED" + "TVOS" "TVOSCOMBINED" "SIMULATOR_TVOS" "SIMULATORARM64_TVOS" + "WATCHOS" "WATCHOSCOMBINED" "SIMULATOR_WATCHOS" "SIMULATORARM64_WATCHOS" + "MAC" "MAC_ARM64" "MAC_UNIVERSAL" + "VISIONOS" "SIMULATOR_VISIONOS" "SIMULATOR64_VISIONOS" + "MAC_CATALYST" "MAC_CATALYST_ARM64") + +# Cache what generator is used +set(USED_CMAKE_GENERATOR "${CMAKE_GENERATOR}") + +# Check if using a CMake version capable of building combined FAT builds (simulator and target slices combined in one static lib) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14") + set(MODERN_CMAKE YES) +endif() + +# Get the Xcode version being used. +# Problem: CMake runs toolchain files multiple times, but can't read cache variables on some runs. +# Workaround: On the first run (in which cache variables are always accessible), set an intermediary environment variable. +# +# NOTE: This pattern is used in many places in this toolchain to speed up checks of all sorts +if(DEFINED XCODE_VERSION_INT) + # Environment variables are always preserved. + set(ENV{_XCODE_VERSION_INT} "${XCODE_VERSION_INT}") +elseif(DEFINED ENV{_XCODE_VERSION_INT}) + set(XCODE_VERSION_INT "$ENV{_XCODE_VERSION_INT}") +elseif(NOT DEFINED XCODE_VERSION_INT) + find_program(XCODEBUILD_EXECUTABLE xcodebuild) + if(NOT XCODEBUILD_EXECUTABLE) + message(FATAL_ERROR "xcodebuild not found. Please install either the standalone commandline tools or Xcode.") + endif() + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version + OUTPUT_VARIABLE XCODE_VERSION_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCH "Xcode [0-9\\.]+" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + string(REGEX REPLACE "Xcode ([0-9\\.]+)" "\\1" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + set(XCODE_VERSION_INT "${XCODE_VERSION_INT}" CACHE INTERNAL "") +endif() + +# Assuming that xcode 12.0 is installed you most probably have ios sdk 14.0 or later installed (tested on Big Sur) +# if you don't set a deployment target it will be set the way you only get 64-bit builds +#if(NOT DEFINED DEPLOYMENT_TARGET AND XCODE_VERSION_INT VERSION_GREATER 12.0) +# Temporarily fix the arm64 issues in CMake install-combined by excluding arm64 for simulator builds (needed for Apple Silicon...) +# set(CMAKE_XCODE_ATTRIBUTE_EXCLUDED_ARCHS[sdk=iphonesimulator*] "arm64") +#endif() + +# Check if the platform variable is set +if(DEFINED PLATFORM) + # Environment variables are always preserved. + set(ENV{_PLATFORM} "${PLATFORM}") +elseif(DEFINED ENV{_PLATFORM}) + set(PLATFORM "$ENV{_PLATFORM}") +elseif(NOT DEFINED PLATFORM) + message(FATAL_ERROR "PLATFORM argument not set. Bailing configure since I don't know what target you want to build for!") +endif () + +if(PLATFORM MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The combined builds support requires Xcode to be used as a generator via '-G Xcode' command-line argument in CMake") +endif() + +# Safeguard that the platform value is set and is one of the supported values +list(FIND _supported_platforms ${PLATFORM} contains_PLATFORM) +if("${contains_PLATFORM}" EQUAL "-1") + string(REPLACE ";" "\n * " _supported_platforms_formatted "${_supported_platforms}") + message(FATAL_ERROR " Invalid PLATFORM specified! Current value: ${PLATFORM}.\n" + " Supported PLATFORM values: \n * ${_supported_platforms_formatted}") +endif() + +# Check if Apple Silicon is supported +if(PLATFORM MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$|^(MAC_UNIVERSAL)$" AND ${CMAKE_VERSION} VERSION_LESS "3.19.5") + message(FATAL_ERROR "Apple Silicon builds requires a minimum of CMake 3.19.5") +endif() + +# Touch the toolchain variable to suppress the "unused variable" warning. +# This happens if CMake is invoked with the same command line the second time. +if(CMAKE_TOOLCHAIN_FILE) +endif() + +# Fix for PThread library not in path +set(CMAKE_THREAD_LIBS_INIT "-lpthread") +set(CMAKE_HAVE_THREADS_LIBRARY 1) +set(CMAKE_USE_WIN32_THREADS_INIT 0) +set(CMAKE_USE_PTHREADS_INIT 1) + +# Specify named language support defaults. +if(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16") + set(NAMED_LANGUAGE_SUPPORT ON) + message(STATUS "[DEFAULTS] Using explicit named language support! E.g., enable_language(CXX) is needed in the project files.") +elseif(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") + set(NAMED_LANGUAGE_SUPPORT OFF) + message(STATUS "[DEFAULTS] Disabling explicit named language support. Falling back to legacy behavior.") +elseif(DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") + message(FATAL_ERROR "CMake named language support for OBJC and OBJCXX was added in CMake 3.16.") +endif() +set(NAMED_LANGUAGE_SUPPORT_INT ${NAMED_LANGUAGE_SUPPORT} CACHE BOOL + "Whether or not to enable explicit named language support" FORCE) + +# Specify the minimum version of the deployment target. +if(NOT DEFINED DEPLOYMENT_TARGET) + if (PLATFORM MATCHES "WATCHOS") + # Unless specified, SDK version 4.0 is used by default as minimum target version (watchOS). + set(DEPLOYMENT_TARGET "6.0") + elseif(PLATFORM STREQUAL "MAC") + # Unless specified, SDK version 10.13 (High Sierra) is used by default as the minimum target version (macos). + set(DEPLOYMENT_TARGET "10.15") + elseif(PLATFORM STREQUAL "VISIONOS" OR PLATFORM STREQUAL "SIMULATOR_VISIONOS" OR PLATFORM STREQUAL "SIMULATOR64_VISIONOS") + # Unless specified, SDK version 1.0 is used by default as minimum target version (visionOS). + set(DEPLOYMENT_TARGET "1.1") + elseif(PLATFORM STREQUAL "MAC_ARM64") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as the minimum target version (macOS on arm). + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "MAC_UNIVERSAL") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as minimum target version for universal builds. + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64") + # Unless specified, SDK version 13.0 is used by default as the minimum target version (mac catalyst minimum requirement). + set(DEPLOYMENT_TARGET "15.0") + else() + # Unless specified, SDK version 11.0 is used by default as the minimum target version (iOS, tvOS). + set(DEPLOYMENT_TARGET "15.0") + endif() + message(STATUS "[DEFAULTS] Using the default min-version since DEPLOYMENT_TARGET not provided!") +elseif(DEFINED DEPLOYMENT_TARGET AND PLATFORM MATCHES "^MAC_CATALYST" AND ${DEPLOYMENT_TARGET} VERSION_LESS "13.1") + message(FATAL_ERROR "Mac Catalyst builds requires a minimum deployment target of 13.1!") +endif() + +# Store the DEPLOYMENT_TARGET in the cache +set(DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}" CACHE INTERNAL "") + +# Handle the case where we are targeting iOS and a version above 10.3.4 (32-bit support dropped officially) +if(PLATFORM STREQUAL "OS" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "OS64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +elseif(PLATFORM STREQUAL "SIMULATOR" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "SIMULATOR64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +endif() + +set(PLATFORM_INT "${PLATFORM}") + +if(DEFINED ARCHS) + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") +endif() + +# Determine the platform name and architectures for use in xcodebuild commands +# from the specified PLATFORM_INT name. +if(PLATFORM_INT STREQUAL "OS") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + set(ARCHS armv7 armv7s arm64) + set(APPLE_TARGET_TRIPLE_INT arm-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS arm64) # FIXME: Add arm64e when Apple has fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example + else() + set(ARCHS arm64) + endif() + set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64COMBINED") + set(SDK_NAME iphoneos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + else() + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + endif() + set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the OS64COMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR64COMBINED") + set(SDK_NAME iphonesimulator) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) # FIXME: Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + else() + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + endif() + set(APPLE_TARGET_TRIPLE_INT aarch64-x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the SIMULATOR64COMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() + message(DEPRECATION "SIMULATOR IS DEPRECATED. Consider using SIMULATOR64 instead.") +elseif(PLATFORM_INT STREQUAL "SIMULATOR64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME appletvos) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() +elseif (PLATFORM_INT STREQUAL "TVOSCOMBINED") + set(SDK_NAME appletvos) + if(MODERN_CMAKE) + if(NOT ARCHS) + set(ARCHS arm64 x86_64) + set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-tvos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvsimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvsimulator*] "x86_64") + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the TVOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME appletvsimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-tvos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") + set(SDK_NAME appletvsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME watchos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32) + set(APPLE_TARGET_TRIPLE_INT arm64_32-apple-watchos${DEPLOYMENT_TARGET}) + else() + set(ARCHS armv7k) + set(APPLE_TARGET_TRIPLE_INT arm-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOSCOMBINED") + set(SDK_NAME watchos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32 i386) + set(APPLE_TARGET_TRIPLE_INT arm64_32-i386-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + else() + set(ARCHS armv7k i386) + set(APPLE_TARGET_TRIPLE_INT arm-i386-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the WATCHOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME watchsimulator) + if(NOT ARCHS) + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") + set(SDK_NAME watchsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR64_VISIONOS") + set(SDK_NAME xrsimulator) + set(ARCHS x86_64) +elseif(PLATFORM_INT STREQUAL "SIMULATOR_VISIONOS") + set(SDK_NAME xrsimulator) + set(ARCHS arm64) +elseif(PLATFORM_INT STREQUAL "VISIONOS") + set(SDK_NAME xros) + set(ARCHS arm64) +elseif(PLATFORM_INT STREQUAL "MAC" OR PLATFORM_INT STREQUAL "MAC_CATALYST") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS x86_64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +elseif(PLATFORM_INT MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS arm64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +elseif(PLATFORM_INT STREQUAL "MAC_UNIVERSAL") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS "x86_64;arm64") + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) +else() + message(FATAL_ERROR "Invalid PLATFORM: ${PLATFORM_INT}") +endif() + +string(REPLACE ";" " " ARCHS_SPACED "${ARCHS}") + +if(MODERN_CMAKE AND PLATFORM_INT MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The COMBINED options only work with Xcode generator, -G Xcode") +endif() + +if(CMAKE_GENERATOR MATCHES "Xcode" AND PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "macosx") + set(CMAKE_XCODE_ATTRIBUTE_SUPPORTS_MACCATALYST "YES") + if(NOT DEFINED MACOSX_DEPLOYMENT_TARGET) + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "10.15") + else() + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "${MACOSX_DEPLOYMENT_TARGET}") + endif() +elseif(CMAKE_GENERATOR MATCHES "Xcode") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}") + if(NOT PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") + endif() +endif() + +# If the user did not specify the SDK root to use, then query xcodebuild for it. +if(DEFINED CMAKE_OSX_SYSROOT_INT) + # Environment variables are always preserved. + set(ENV{_CMAKE_OSX_SYSROOT_INT} "${CMAKE_OSX_SYSROOT_INT}") +elseif(DEFINED ENV{_CMAKE_OSX_SYSROOT_INT}) + set(CMAKE_OSX_SYSROOT_INT "$ENV{_CMAKE_OSX_SYSROOT_INT}") +elseif(NOT DEFINED CMAKE_OSX_SYSROOT_INT) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version -sdk ${SDK_NAME} Path + OUTPUT_VARIABLE CMAKE_OSX_SYSROOT_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if (NOT DEFINED CMAKE_OSX_SYSROOT_INT AND NOT DEFINED CMAKE_OSX_SYSROOT) + message(SEND_ERROR "Please make sure that Xcode is installed and that the toolchain" + "is pointing to the correct path. Please run:" + "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" + "and see if that fixes the problem for you.") + message(FATAL_ERROR "Invalid CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT} " + "does not exist.") +elseif(DEFINED CMAKE_OSX_SYSROOT_INT) + set(CMAKE_OSX_SYSROOT_INT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + # Specify the location or name of the platform SDK to be used in CMAKE_OSX_SYSROOT. + set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") +endif() + +# Use bitcode or not +if(NOT DEFINED ENABLE_BITCODE) + message(STATUS "[DEFAULTS] Disabling bitcode support by default. ENABLE_BITCODE not provided for override!") + set(ENABLE_BITCODE OFF) +endif() +set(ENABLE_BITCODE_INT ${ENABLE_BITCODE} CACHE BOOL + "Whether or not to enable bitcode" FORCE) +# Use ARC or not +if(NOT DEFINED ENABLE_ARC) + # Unless specified, enable ARC support by default + set(ENABLE_ARC ON) + message(STATUS "[DEFAULTS] Enabling ARC support by default. ENABLE_ARC not provided!") +endif() +set(ENABLE_ARC_INT ${ENABLE_ARC} CACHE BOOL "Whether or not to enable ARC" FORCE) +# Use hidden visibility or not +if(NOT DEFINED ENABLE_VISIBILITY) + # Unless specified, disable symbols visibility by default + set(ENABLE_VISIBILITY OFF) + message(STATUS "[DEFAULTS] Hiding symbols visibility by default. ENABLE_VISIBILITY not provided!") +endif() +set(ENABLE_VISIBILITY_INT ${ENABLE_VISIBILITY} CACHE BOOL "Whether or not to hide symbols from the dynamic linker (-fvisibility=hidden)" FORCE) +# Set strict compiler checks or not +if(NOT DEFINED ENABLE_STRICT_TRY_COMPILE) + # Unless specified, disable strict try_compile() + set(ENABLE_STRICT_TRY_COMPILE OFF) + message(STATUS "[DEFAULTS] Using NON-strict compiler checks by default. ENABLE_STRICT_TRY_COMPILE not provided!") +endif() +set(ENABLE_STRICT_TRY_COMPILE_INT ${ENABLE_STRICT_TRY_COMPILE} CACHE BOOL + "Whether or not to use strict compiler checks" FORCE) + +# Get the SDK version information. +if(DEFINED SDK_VERSION) + # Environment variables are always preserved. + set(ENV{_SDK_VERSION} "${SDK_VERSION}") +elseif(DEFINED ENV{_SDK_VERSION}) + set(SDK_VERSION "$ENV{_SDK_VERSION}") +elseif(NOT DEFINED SDK_VERSION) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -sdk ${CMAKE_OSX_SYSROOT_INT} -version SDKVersion + OUTPUT_VARIABLE SDK_VERSION + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +# Find the Developer root for the specific iOS platform being compiled for +# from CMAKE_OSX_SYSROOT. Should be ../../ from SDK specified in +# CMAKE_OSX_SYSROOT. There does not appear to be a direct way to obtain +# this information from xcrun or xcodebuild. +if (NOT DEFINED CMAKE_DEVELOPER_ROOT AND NOT CMAKE_GENERATOR MATCHES "Xcode") + get_filename_component(PLATFORM_SDK_DIR ${CMAKE_OSX_SYSROOT_INT} PATH) + get_filename_component(CMAKE_DEVELOPER_ROOT ${PLATFORM_SDK_DIR} PATH) + if (NOT EXISTS "${CMAKE_DEVELOPER_ROOT}") + message(FATAL_ERROR "Invalid CMAKE_DEVELOPER_ROOT: ${CMAKE_DEVELOPER_ROOT} does not exist.") + endif() +endif() + +# Find the C & C++ compilers for the specified SDK. +if(DEFINED CMAKE_C_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_C_COMPILER} "${CMAKE_C_COMPILER}") +elseif(DEFINED ENV{_CMAKE_C_COMPILER}) + set(CMAKE_C_COMPILER "$ENV{_CMAKE_C_COMPILER}") + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +elseif(NOT DEFINED CMAKE_C_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang + OUTPUT_VARIABLE CMAKE_C_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +endif() +if(DEFINED CMAKE_CXX_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_CXX_COMPILER} "${CMAKE_CXX_COMPILER}") +elseif(DEFINED ENV{_CMAKE_CXX_COMPILER}) + set(CMAKE_CXX_COMPILER "$ENV{_CMAKE_CXX_COMPILER}") +elseif(NOT DEFINED CMAKE_CXX_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang++ + OUTPUT_VARIABLE CMAKE_CXX_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find (Apple's) libtool. +if(DEFINED BUILD_LIBTOOL) + # Environment variables are always preserved. + set(ENV{_BUILD_LIBTOOL} "${BUILD_LIBTOOL}") +elseif(DEFINED ENV{_BUILD_LIBTOOL}) + set(BUILD_LIBTOOL "$ENV{_BUILD_LIBTOOL}") +elseif(NOT DEFINED BUILD_LIBTOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find libtool + OUTPUT_VARIABLE BUILD_LIBTOOL + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find the toolchain's provided install_name_tool if none is found on the host +if(DEFINED CMAKE_INSTALL_NAME_TOOL) + # Environment variables are always preserved. + set(ENV{_CMAKE_INSTALL_NAME_TOOL} "${CMAKE_INSTALL_NAME_TOOL}") +elseif(DEFINED ENV{_CMAKE_INSTALL_NAME_TOOL}) + set(CMAKE_INSTALL_NAME_TOOL "$ENV{_CMAKE_INSTALL_NAME_TOOL}") +elseif(NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find install_name_tool + OUTPUT_VARIABLE CMAKE_INSTALL_NAME_TOOL_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_INSTALL_NAME_TOOL ${CMAKE_INSTALL_NAME_TOOL_INT} CACHE INTERNAL "") +endif() + +# Configure libtool to be used instead of ar + ranlib to build static libraries. +# This is required on Xcode 7+, but should also work on previous versions of +# Xcode. +get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(lang ${languages}) + set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "${BUILD_LIBTOOL} -static -o " CACHE INTERNAL "") +endforeach() + +# CMake 3.14+ support building for iOS, watchOS, and tvOS out of the box. +if(MODERN_CMAKE) + if(SDK_NAME MATCHES "iphone") + set(CMAKE_SYSTEM_NAME iOS) + elseif(SDK_NAME MATCHES "xros") + set(CMAKE_SYSTEM_NAME visionOS) + elseif(SDK_NAME MATCHES "xrsimulator") + set(CMAKE_SYSTEM_NAME visionOS) + elseif(SDK_NAME MATCHES "macosx") + set(CMAKE_SYSTEM_NAME Darwin) + elseif(SDK_NAME MATCHES "appletv") + set(CMAKE_SYSTEM_NAME tvOS) + elseif(SDK_NAME MATCHES "watch") + set(CMAKE_SYSTEM_NAME watchOS) + endif() + # Provide flags for a combined FAT library build on newer CMake versions + if(PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_IOS_INSTALL_COMBINED YES) + if(CMAKE_GENERATOR MATCHES "Xcode") + # Set the SDKROOT Xcode properties to a Xcode-friendly value (the SDK_NAME, E.g, iphoneos) + # This way, Xcode will automatically switch between the simulator and device SDK when building. + set(CMAKE_XCODE_ATTRIBUTE_SDKROOT "${SDK_NAME}") + # Force to not build just one ARCH, but all! + set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO") + endif() + endif() +elseif(NOT DEFINED CMAKE_SYSTEM_NAME AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10") + # Legacy code path prior to CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME iOS) +elseif(NOT DEFINED CMAKE_SYSTEM_NAME) + # Legacy code path before CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME Darwin) +endif() +# Standard settings. +set(CMAKE_SYSTEM_VERSION ${SDK_VERSION} CACHE INTERNAL "") +set(UNIX ON CACHE BOOL "") +set(APPLE ON CACHE BOOL "") +if(PLATFORM STREQUAL "MAC" OR PLATFORM STREQUAL "MAC_ARM64" OR PLATFORM STREQUAL "MAC_UNIVERSAL") + set(IOS OFF CACHE BOOL "") + set(MACOS ON CACHE BOOL "") +elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64") + set(IOS ON CACHE BOOL "") + set(MACOS ON CACHE BOOL "") +else() + set(IOS ON CACHE BOOL "") +endif() +# Set the architectures for which to build. +set(CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE INTERNAL "") +# Change the type of target generated for try_compile() so it'll work when cross-compiling, weak compiler checks +if(NOT ENABLE_STRICT_TRY_COMPILE_INT) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +endif() +# All iOS/Darwin specific settings - some may be redundant. +if (NOT DEFINED CMAKE_MACOSX_BUNDLE) + set(CMAKE_MACOSX_BUNDLE YES) +endif() +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") +set(CMAKE_SHARED_LIBRARY_PREFIX "lib") +set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") +set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".tbd" ".so") +set(CMAKE_SHARED_MODULE_PREFIX "lib") +set(CMAKE_SHARED_MODULE_SUFFIX ".so") +set(CMAKE_C_COMPILER_ABI ELF) +set(CMAKE_CXX_COMPILER_ABI ELF) +set(CMAKE_C_HAS_ISYSROOT 1) +set(CMAKE_CXX_HAS_ISYSROOT 1) +set(CMAKE_MODULE_EXISTS 1) +set(CMAKE_DL_LIBS "") +set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") +set(CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") +set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") +set(CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") + +if(ARCHS MATCHES "((^|;|, )(arm64|arm64e|x86_64))+") + set(CMAKE_C_SIZEOF_DATA_PTR 8) + set(CMAKE_CXX_SIZEOF_DATA_PTR 8) + if(ARCHS MATCHES "((^|;|, )(arm64|arm64e))+") + set(CMAKE_SYSTEM_PROCESSOR "aarch64") + else() + set(CMAKE_SYSTEM_PROCESSOR "x86_64") + endif() +else() + set(CMAKE_C_SIZEOF_DATA_PTR 4) + set(CMAKE_CXX_SIZEOF_DATA_PTR 4) + set(CMAKE_SYSTEM_PROCESSOR "arm") +endif() + +# Note that only Xcode 7+ supports the newer more specific: +# -m${SDK_NAME}-version-min flags, older versions of Xcode use: +# -m(ios/ios-simulator)-version-min instead. +if(${CMAKE_VERSION} VERSION_LESS "3.11") + if(PLATFORM_INT STREQUAL "OS" OR PLATFORM_INT STREQUAL "OS64") + if(XCODE_VERSION_INT VERSION_LESS 7.0) + set(SDK_NAME_VERSION_FLAGS + "-mios-version-min=${DEPLOYMENT_TARGET}") + else() + # Xcode 7.0+ uses flags we can build directly from SDK_NAME. + set(SDK_NAME_VERSION_FLAGS + "-m${SDK_NAME}-version-min=${DEPLOYMENT_TARGET}") + endif() + elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "VISIONOS") + set(SDK_NAME_VERSION_FLAGS + "--target=${ARCH}-apple-xros${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_VISIONOS") + set(SDK_NAME_VERSION_FLAGS + "--target=${ARCH}-apple-xros${DEPLOYMENT_TARGET}-simulator") + elseif(PLATFORM_INT STREQUAL "SIMULATOR64_VISIONOS") + set(SDK_NAME_VERSION_FLAGS + "--target=${ARCH}-apple-xros${DEPLOYMENT_TARGET}-simulator") + elseif(PLATFORM_INT STREQUAL "MAC") + set(SDK_NAME_VERSION_FLAGS + "-mmacosx-version-min=${DEPLOYMENT_TARGET}") + else() + # SIMULATOR or SIMULATOR64 both use -mios-simulator-version-min. + set(SDK_NAME_VERSION_FLAGS + "-mios-simulator-version-min=${DEPLOYMENT_TARGET}") + endif() +elseif(NOT PLATFORM_INT MATCHES "^MAC_CATALYST") + # Newer versions of CMake sets the version min flags correctly, skip this for Mac Catalyst targets + set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} CACHE INTERNAL "Minimum OS X deployment version") +endif() + +if(DEFINED APPLE_TARGET_TRIPLE_INT) + set(APPLE_TARGET_TRIPLE ${APPLE_TARGET_TRIPLE_INT} CACHE INTERNAL "") + set(CMAKE_C_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_CXX_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_ASM_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) +endif() + +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(C_TARGET_FLAGS "-isystem ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/usr/include -iframework ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks") +endif() + +if(ENABLE_BITCODE_INT) + set(BITCODE "-fembed-bitcode") + set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES") +else() + set(BITCODE "") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO") +endif() + +if(ENABLE_ARC_INT) + set(FOBJC_ARC "-fobjc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES") +else() + set(FOBJC_ARC "-fno-objc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "NO") +endif() + +if(NAMED_LANGUAGE_SUPPORT_INT) + set(OBJC_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") + set(OBJC_LEGACY_VARS "") +else() + set(OBJC_VARS "") + set(OBJC_LEGACY_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") +endif() + +if(NOT ENABLE_VISIBILITY_INT) + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "hidden" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "YES") + set(VISIBILITY "-fvisibility=hidden -fvisibility-inlines-hidden") +else() + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "default" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO") + set(VISIBILITY "-fvisibility=default") +endif() + +if(DEFINED APPLE_TARGET_TRIPLE) + set(APPLE_TARGET_TRIPLE_FLAG "-target ${APPLE_TARGET_TRIPLE}") +endif() + +#Check if Xcode generator is used since that will handle these flags automagically +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Not setting any manual command-line buildflags, since Xcode is selected as the generator. Modifying the Xcode build-settings directly instead.") +else() + set(CMAKE_C_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_C_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all C build types.") + set(CMAKE_C_FLAGS_DEBUG "-O0 -g ${CMAKE_C_FLAGS_DEBUG}") + set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_C_FLAGS_MINSIZEREL}") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_C_FLAGS_RELWITHDEBINFO}") + set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_C_FLAGS_RELEASE}") + set(CMAKE_CXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_CXX_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all CXX build types.") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g ${CMAKE_CXX_FLAGS_DEBUG}") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_CXX_FLAGS_MINSIZEREL}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_CXX_FLAGS_RELEASE}") + if(NAMED_LANGUAGE_SUPPORT_INT) + set(CMAKE_OBJC_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJC_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all OBJC build types.") + set(CMAKE_OBJC_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJC_FLAGS_DEBUG}") + set(CMAKE_OBJC_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJC_FLAGS_MINSIZEREL}") + set(CMAKE_OBJC_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJC_FLAGS_RELWITHDEBINFO}") + set(CMAKE_OBJC_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJC_FLAGS_RELEASE}") + set(CMAKE_OBJCXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJCXX_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all OBJCXX build types.") + set(CMAKE_OBJCXX_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJCXX_FLAGS_DEBUG}") + set(CMAKE_OBJCXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJCXX_FLAGS_MINSIZEREL}") + set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_OBJCXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJCXX_FLAGS_RELEASE}") + endif() + set(CMAKE_C_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all C link types.") + set(CMAKE_CXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all CXX link types.") + if(NAMED_LANGUAGE_SUPPORT_INT) + set(CMAKE_OBJC_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJC_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all OBJC link types.") + set(CMAKE_OBJCXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJCXX_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all OBJCXX link types.") + endif() + set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -arch ${CMAKE_OSX_ARCHITECTURES} ${APPLE_TARGET_TRIPLE_FLAG}" CACHE INTERNAL + "Flags used by the compiler for all ASM build types.") +endif() + +## Print status messages to inform of the current state +message(STATUS "Configuring ${SDK_NAME} build for platform: ${PLATFORM_INT}, architecture(s): ${ARCHS}") +message(STATUS "Using SDK: ${CMAKE_OSX_SYSROOT_INT}") +message(STATUS "Using C compiler: ${CMAKE_C_COMPILER}") +message(STATUS "Using CXX compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "Using libtool: ${BUILD_LIBTOOL}") +message(STATUS "Using install name tool: ${CMAKE_INSTALL_NAME_TOOL}") +if(DEFINED APPLE_TARGET_TRIPLE) + message(STATUS "Autoconf target triple: ${APPLE_TARGET_TRIPLE}") +endif() +message(STATUS "Using minimum deployment version: ${DEPLOYMENT_TARGET}" + " (SDK version: ${SDK_VERSION})") +if(MODERN_CMAKE) + message(STATUS "Merging integrated CMake 3.14+ iOS,tvOS,watchOS,macOS toolchain(s) with this toolchain!") + if(PLATFORM_INT MATCHES ".*COMBINED") + message(STATUS "Will combine built (static) artifacts into FAT lib...") + endif() +endif() +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Using Xcode version: ${XCODE_VERSION_INT}") +endif() +message(STATUS "CMake version: ${CMAKE_VERSION}") +if(DEFINED SDK_NAME_VERSION_FLAGS) + message(STATUS "Using version flags: ${SDK_NAME_VERSION_FLAGS}") +endif() +message(STATUS "Using a data_ptr size of: ${CMAKE_CXX_SIZEOF_DATA_PTR}") +if(ENABLE_BITCODE_INT) + message(STATUS "Bitcode: Enabled") +else() + message(STATUS "Bitcode: Disabled") +endif() + +if(ENABLE_ARC_INT) + message(STATUS "ARC: Enabled") +else() + message(STATUS "ARC: Disabled") +endif() + +if(ENABLE_VISIBILITY_INT) + message(STATUS "Hiding symbols: Disabled") +else() + message(STATUS "Hiding symbols: Enabled") +endif() + +# Set global properties +set_property(GLOBAL PROPERTY PLATFORM "${PLATFORM}") +set_property(GLOBAL PROPERTY APPLE_TARGET_TRIPLE "${APPLE_TARGET_TRIPLE_INT}") +set_property(GLOBAL PROPERTY SDK_VERSION "${SDK_VERSION}") +set_property(GLOBAL PROPERTY XCODE_VERSION "${XCODE_VERSION_INT}") +set_property(GLOBAL PROPERTY OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") + +# Export configurable variables for the try_compile() command. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + PLATFORM + XCODE_VERSION_INT + SDK_VERSION + NAMED_LANGUAGE_SUPPORT + DEPLOYMENT_TARGET + CMAKE_DEVELOPER_ROOT + CMAKE_OSX_SYSROOT_INT + ENABLE_BITCODE + ENABLE_ARC + CMAKE_ASM_COMPILER + CMAKE_C_COMPILER + CMAKE_C_COMPILER_TARGET + CMAKE_CXX_COMPILER + CMAKE_CXX_COMPILER_TARGET + BUILD_LIBTOOL + CMAKE_INSTALL_NAME_TOOL + CMAKE_C_FLAGS + CMAKE_C_DEBUG + CMAKE_C_MINSIZEREL + CMAKE_C_RELWITHDEBINFO + CMAKE_C_RELEASE + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_LINK_FLAGS + CMAKE_CXX_LINK_FLAGS + CMAKE_ASM_FLAGS +) + +if(NAMED_LANGUAGE_SUPPORT_INT) + list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + CMAKE_OBJC_FLAGS + CMAKE_OBJC_DEBUG + CMAKE_OBJC_MINSIZEREL + CMAKE_OBJC_RELWITHDEBINFO + CMAKE_OBJC_RELEASE + CMAKE_OBJCXX_FLAGS + CMAKE_OBJCXX_DEBUG + CMAKE_OBJCXX_MINSIZEREL + CMAKE_OBJCXX_RELWITHDEBINFO + CMAKE_OBJCXX_RELEASE + CMAKE_OBJC_LINK_FLAGS + CMAKE_OBJCXX_LINK_FLAGS + ) +endif() + +set(CMAKE_PLATFORM_HAS_INSTALLNAME 1) +set(CMAKE_SHARED_LINKER_FLAGS "-rpath @executable_path/Frameworks -rpath @loader_path/Frameworks") +set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") +set(CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") +set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a") +set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name") + +# Set the find root to the SDK developer roots. +# Note: CMAKE_FIND_ROOT_PATH is only useful when cross-compiling. Thus, do not set on macOS builds. +if(NOT PLATFORM_INT MATCHES "^MAC.*$") + list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + set(CMAKE_IGNORE_PATH "/System/Library/Frameworks;/usr/local/lib;/opt/homebrew" CACHE INTERNAL "") +endif() + +# Default to searching for frameworks first. +IF(NOT DEFINED CMAKE_FIND_FRAMEWORK) + set(CMAKE_FIND_FRAMEWORK FIRST) +ENDIF(NOT DEFINED CMAKE_FIND_FRAMEWORK) + +# Set up the default search directories for frameworks. +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +else() + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +endif() + +# By default, search both the specified iOS SDK and the remainder of the host filesystem. +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH CACHE INTERNAL "") +endif() + +# +# Some helper-macros below to simplify and beautify the CMakeFile +# + +# This little macro lets you set any Xcode specific property. +macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE XCODE_RELVERSION) + set(XCODE_RELVERSION_I "${XCODE_RELVERSION}") + if(XCODE_RELVERSION_I STREQUAL "All") + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} "${XCODE_VALUE}") + else() + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY}[variant=${XCODE_RELVERSION_I}] "${XCODE_VALUE}") + endif() +endmacro(set_xcode_property) + +# This macro lets you find executable programs on the host system. +macro(find_host_package) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER) + set(_TOOLCHAIN_IOS ${IOS}) + set(IOS OFF) + find_package(${ARGN}) + set(IOS ${_TOOLCHAIN_IOS}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) +endmacro(find_host_package) \ No newline at end of file diff --git a/libs/openFrameworksCompiled/project/CMake/toolchain/linux64.toolchain.cmake b/libs/openFrameworksCompiled/project/CMake/toolchain/linux64.toolchain.cmake new file mode 100644 index 00000000000..4f1e8330a37 --- /dev/null +++ b/libs/openFrameworksCompiled/project/CMake/toolchain/linux64.toolchain.cmake @@ -0,0 +1,99 @@ +# Linux Ubuntu 64-bit Toolchain File + +# Specify the system +set(CMAKE_SYSTEM_NAME Linux) # Cross-compilation target system +set(CMAKE_SYSTEM_PROCESSOR x86_64) # Architecture (64-bit) +set(CMAKE_VERBOSE_MAKEFILE ON) + +# GCC Version (Set this variable when invoking CMake) +if(NOT DEFINED GCC_VERSION) + if(DEFINED ENV{GCC_VERSION}) + set(GCC_VERSION $ENV{GCC_VERSION}) + else() + set(GCC_VERSION 14) # Default value + message(WARNING "GCC_VERSION not specified. Defaulting to GCC_VERSION=${GCC_VERSION}") + endif() +endif() + +if(NOT DEFINED SYSROOT) + if(DEFINED ENV{SYSROOT}) + set(SYSROOT $ENV{SYSROOT}) + else() + set(SYSROOT /) # Default value + endif() +endif() + +# Path to GCC +if(NOT DEFINED GCC_PATH) + if(DEFINED ENV{GCC_PATH}) + set(GCC_PATH $ENV{GCC_PATH}) # Use GCC_PATH from the env + else() + set(GCC_PATH "/usr/bin") # Default path + endif() +endif() + +if(NOT DEFINED C_STANDARD) + set(C_STANDARD 17 CACHE STRING "" FORCE) # Default to C17 +endif() +if(NOT DEFINED CPP_STANDARD) + set(CPP_STANDARD 17 CACHE STRING "" FORCE) # Default to C++17 +endif() + +set(CMAKE_C_STANDARD ${C_STANDARD} CACHE STRING "" FORCE) +set(CMAKE_C_STANDARD_REQUIRED ON ) +set(CMAKE_CXX_STANDARD ${CPP_STANDARD} CACHE STRING "" FORCE) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Compiler Binary Paths +set(CMAKE_C_COMPILER "${GCC_PATH}/gcc-${GCC_VERSION}") +set(CMAKE_CXX_COMPILER "${GCC_PATH}/g++-${GCC_VERSION}") +set(TOOLCHAIN_ROOT "${GCC_PATH}") + +# Paths to system libraries and includes +set(CMAKE_SYSROOT "/") +set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) +SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) + +find_program(CMAKE_C_COMPILER ${CMAKE_SYSTEM_PROCESSOR}-linux-gnu-gcc PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_CXX_COMPILER ${CMAKE_SYSTEM_PROCESSOR}-linux-gnu-g++ PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_LINKER ${CMAKE_SYSTEM_PROCESSOR}-linux-gnu-ld PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_AR ${CMAKE_SYSTEM_PROCESSOR}-linux-gnu-ar PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_NM ${CMAKE_SYSTEM_PROCESSOR}-linux-gnu-nm PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_RANLIB ${CMAKE_SYSTEM_PROCESSOR}-linux-gnu-ranlib PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_STRIP ${CMAKE_SYSTEM_PROCESSOR}-linux-gnu-strip PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_OBJCOPY ${CMAKE_SYSTEM_PROCESSOR}-linux-gnu-objcopy PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_OBJDUMP ${CMAKE_SYSTEM_PROCESSOR}-linux-gnu-objdump PATHS "${TOOLCHAIN_ROOT}/bin/") + +message(STATUS "Using GCC Version: ${GCC_VERSION}") +message(STATUS "C Compiler: ${CMAKE_C_COMPILER}") +message(STATUS "C++ Compiler: ${CMAKE_CXX_COMPILER}") + +# Check for the existence of the specified GCC version +if(NOT EXISTS ${CMAKE_C_COMPILER}) + message(WARNING "C Compiler not found: ${CMAKE_C_COMPILER}") +endif() +if(NOT EXISTS ${CMAKE_CXX_COMPILER}) + message(WARNING "C++ Compiler not found: ${CMAKE_CXX_COMPILER}") +endif() + +set(EXTRA_LINKS "-Wl,-rpath-link,${CMAKE_SYSROOT}/lib/ \ + -L${CMAKE_SYSROOT}/lib/ \ + -Wl,-rpath-link,${CMAKE_SYSROOT}/lib64/ \ + -L${CMAKE_SYSROOT}/lib64/ \ + -L${CMAKE_SYSROOT}/lib/x86_64-linux-gnu \ + -Wl,-rpath-link,${CMAKE_SYSROOT}/lib/x86_64-linux-gnu") + +# Compiler and linker flags +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --sysroot=${CMAKE_SYSROOT} -fPIC -O3 -Wall -Wextra -march=x86-64 -mtune=generic ${EXTRA_LINKS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --sysroot=${CMAKE_SYSROOT} -fPIC -O3 -Wall -Wextra -std=c++${CPP_STANDARD} -march=x86-64 -mtune=generic ${EXTRA_LINKS}") +set(CMAKE_EXE_LINKER_FLAGS "-fPIE -pie ${EXTRA_LINKS}") +set(CMAKE_SHARED_LINKER_FLAGS "-shared -fPIC") + + +message(STATUS "Using GCC Version: ${GCC_VERSION}") +message(STATUS "C Compiler: ${CMAKE_C_COMPILER}") +message(STATUS "C++ Compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "System Root: ${CMAKE_SYSROOT}") + diff --git a/libs/openFrameworksCompiled/project/CMake/toolchain/linuxarm64.toolchain.cmake b/libs/openFrameworksCompiled/project/CMake/toolchain/linuxarm64.toolchain.cmake new file mode 100644 index 00000000000..a9a310a2e98 --- /dev/null +++ b/libs/openFrameworksCompiled/project/CMake/toolchain/linuxarm64.toolchain.cmake @@ -0,0 +1,177 @@ +# Linux Ubuntu ARM64 Toolchain File + +# Specify the system +set(CMAKE_SYSTEM_NAME Linux) # Cross-compilation target system +set(CMAKE_SYSTEM_PROCESSOR aarch64) # Architecture (ARM64) +set(CMAKE_VERBOSE_MAKEFILE ON) + +# GCC Version (Set this variable when invoking CMake) +if(NOT DEFINED GCC_VERSION) + if(DEFINED ENV{GCC_VERSION}) + set(GCC_VERSION $ENV{GCC_VERSION}) + else() + set(GCC_VERSION 14) # Default value + message(STATUS "GCC_VERSION not specified. Defaulting to GCC_VERSION=${GCC_VERSION}") + endif() +endif() + +# Set CROSS_CPU to a default value if not provided +if(NOT DEFINED CROSS_CPU) + if(DEFINED ENV{CROSS_CPU}) + set(CROSS_CPU $ENV{CROSS_CPU}) + else() + set(CROSS_CPU "generic-armv8-a") + message(STATUS "CROSS_CPU not specified. Defaulting to CROSS_CPU=generic-armv8-a") + endif() +endif() + +# Set SYSROOT +if(NOT DEFINED SYSROOT) + if(DEFINED ENV{SYSROOT}) + set(SYSROOT $ENV{SYSROOT}) + else() + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set(SYSROOT "/") # Use native root + message(STATUS "Host is AArch64. Using native SYSROOT=${SYSROOT}") + else() + set(SYSROOT "/") # Use cross-compilation root + message(STATUS "SYSROOT not specified. Defaulting to SYSROOT=${SYSROOT} for cross-compilation") + endif() + endif() +endif() + +# Set TOOLCHAIN_ROOT +if(NOT DEFINED TOOLCHAIN_ROOT) + if(DEFINED ENV{TOOLCHAIN_ROOT}) + set(TOOLCHAIN_ROOT $ENV{TOOLCHAIN_ROOT}) + else() + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set(TOOLCHAIN_ROOT "/usr") # Native AArch64 toolchain + message(STATUS "Host is AArch64. Using native TOOLCHAIN_ROOT=${TOOLCHAIN_ROOT}") + else() + set(TOOLCHAIN_ROOT "/usr/aarch64-linux-gnu/") # Cross-compilation toolchain + message(STATUS "TOOLCHAIN_ROOT not specified. Defaulting to TOOLCHAIN_ROOT=${TOOLCHAIN_ROOT} for cross-compilation") + endif() + endif() +endif() + +# Default GCC path +if(NOT DEFINED GCC_PATH) + if(DEFINED ENV{GCC_PATH}) + set(GCC_PATH $ENV{GCC_PATH}) # Use GCC_PATH from env + else() + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set(GCC_PATH "/usr/bin") # Native AArch64 GCC + else() + set(GCC_PATH "/usr/bin/aarch64-linux-gnu") # Cross-compilation GCC + set(ENV{PKG_CONFIG_PATH} "/usr/aarch64-linux-gnu/lib/pkgconfig") + set(ENV{PKG_CONFIG_LIBDIR} "/usr/aarch64-linux-gnu/lib/pkgconfig") + set(PKG_CONFIG_PATH "/usr/aarch64-linux-gnu/lib/pkgconfig") + set(PKG_CONFIG_LIBDIR "/usr/aarch64-linux-gnu/lib/pkgconfig") + set(PKG_CONFIG_EXECUTABLE "/usr/aarch64-linux-gnu/bin/pkg-config") + endif() + message(STATUS "GCC_PATH not specified. Defaulting to GCC_PATH=${GCC_PATH}") + endif() +endif() + +# Compiler settings +set(CMAKE_C_COMPILER "${GCC_PATH}/aarch64-linux-gnu-gcc") +set(CMAKE_CXX_COMPILER "${GCC_PATH}/aarch64-linux-gnu-g++") +set(CMAKE_SYSROOT "${SYSROOT}") +set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) + +if(NOT DEFINED C_STANDARD) + set(C_STANDARD 17 CACHE STRING "" FORCE) # Default to C17 +endif() +if(NOT DEFINED CPP_STANDARD) + set(CPP_STANDARD 17 CACHE STRING "" FORCE) # Default to C++17 +endif() + +set(CMAKE_C_STANDARD ${C_STANDARD} CACHE STRING "" FORCE) +set(CMAKE_C_STANDARD_REQUIRED ON ) +set(CMAKE_CXX_STANDARD ${CPP_STANDARD} CACHE STRING "" FORCE) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Compiler Binary Paths +set(CMAKE_C_COMPILER "${GCC_PATH}/aarch64-linux-gnu-gcc") +set(CMAKE_CXX_COMPILER "${GCC_PATH}/aarch64-linux-gnu-g++") + + +find_program(CMAKE_C_COMPILER aarch64-linux-gnu-gcc PATHS "${TOOLCHAIN_ROOT}/bin" "/usr/bin" "/usr/aarch64-linux-gnu/bin" "/opt/aarch64-linux-gnu/bin" NO_DEFAULT_PATH) +find_program(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++ PATHS "${TOOLCHAIN_ROOT}/bin" "/usr/bin" "/usr/aarch64-linux-gnu/bin" "/opt/aarch64-linux-gnu/bin" NO_DEFAULT_PATH) + +find_program(CMAKE_LINKER aarch64-linux-gnu-ld PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_AR aarch64-linux-gnu-ar PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_NM aarch64-linux-gnu-nm PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_RANLIB aarch64-linux-gnu-ranlib PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_STRIP aarch64-linux-gnu-strip PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_OBJCOPY aarch64-linux-gnu-objcopy PATHS "${TOOLCHAIN_ROOT}/bin/") +find_program(CMAKE_OBJDUMP aarch64-linux-gnu-objdump PATHS "${TOOLCHAIN_ROOT}/bin/") + +message(STATUS "Using GCC Version: ${GCC_VERSION}") +message(STATUS "C Compiler: ${CMAKE_C_COMPILER}") +message(STATUS "C++ Compiler: ${CMAKE_CXX_COMPILER}") + +# Check for the existence of the specified GCC version +if(NOT EXISTS ${CMAKE_C_COMPILER}) + message(WARNING "C Compiler not found: ${CMAKE_C_COMPILER}") +endif() +if(NOT EXISTS ${CMAKE_CXX_COMPILER}) + message(WARNING "C++ Compiler not found: ${CMAKE_CXX_COMPILER}") +endif() + +set(EXTRA_LINKS "") +if (EXISTS "${CMAKE_SYSROOT}/lib/") + list(APPEND EXTRA_LINKS "-Wl,-rpath-link,${CMAKE_SYSROOT}/lib/" "-L${CMAKE_SYSROOT}/lib/") +endif() +if (EXISTS "${CMAKE_SYSROOT}/lib64/") + list(APPEND EXTRA_LINKS "-Wl,-rpath-link,${CMAKE_SYSROOT}/lib64/" "-L${CMAKE_SYSROOT}/lib64/") +endif() +if (EXISTS "${CMAKE_SYSROOT}/lib/aarch64-linux-gnu/") + list(APPEND EXTRA_LINKS "-Wl,-rpath-link,${CMAKE_SYSROOT}/lib/aarch64-linux-gnu" "-L${CMAKE_SYSROOT}/lib/aarch64-linux-gnu") +endif() +if (EXISTS "/usr/lib/aarch64-linux-gnu/") + list(APPEND EXTRA_LINKS "-Wl,-rpath-link,/usr/lib/aarch64-linux-gnu" "-L/usr/lib/aarch64-linux-gnu") +endif() + +set(CFLAGS "--sysroot=${SYSROOT} -I${TOOLCHAIN_ROOT}/${GCC_PREFIX}/libc/usr/include -I${TOOLCHAIN_ROOT}/lib/gcc/${GCC_PREFIX}/${GCC_VERSION}/include -I/usr/include -DSTANDALONE -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_LIBBCM_HOST -DUSE_EXTERNAL_LIBBCM_HOST") + +# Compiler and linker flags +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CFLAGS} -fPIC -O3 -Wall -Wextra -march=armv8-a") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CFLAGS} -fPIC -O3 -Wall -Wextra -std=c++${CPP_STANDARD} -march=armv8-a+simd+crypto") + +# Linker flags +set(CMAKE_EXE_LINKER_FLAGS "-fPIE -pie ${EXTRA_LINKS}") +set(CMAKE_SHARED_LINKER_FLAGS "-shared -fPIC ${EXTRA_LINKS}") + +set(CMAKE_LIBRARY_PATH /usr/aarch64-linux-gnu/lib) +set(CMAKE_INCLUDE_PATH /usr/aarch64-linux-gnu/include) + +set(OPENGL_FOUND TRUE) +set(OPENGL_gl_LIBRARY "/usr/lib/aarch64-linux-gnu/libGL.so") +set(OPENGL_opengl_LIBRARY "/usr/lib/aarch64-linux-gnu/libGL.so") +set(OPENGL_glx_LIBRARY "/usr/lib/aarch64-linux-gnu/libGLX.so") +set(GLES_LIBRARY "/usr/lib/aarch64-linux-gnu/libGLESv2.so") +set(EGL_LIBRARY "/usr/lib/aarch64-linux-gnu/libEGL.so") + +set(X11_INCLUDE_DIR "/usr/aarch64-linux-gnu/include") +set(X11_X11_LIB "/usr/lib/aarch64-linux-gnu/libX11.so") +set(X11_Xext_LIB "/usr/lib/aarch64-linux-gnu/libXext.so") +set(X11_Xrandr_LIB "/usr/lib/aarch64-linux-gnu/libXrandr.so") +set(X11_Xinerama_LIB "/usr/lib/aarch64-linux-gnu/libXinerama.so") +set(X11_Xcursor_LIB "/usr/lib/aarch64-linux-gnu/libXcursor.so") + +set(WAYLAND_INCLUDE_DIR "/usr/aarch64-linux-gnu/include") +set(WAYLAND_CLIENT_LIB "/usr/lib/aarch64-linux-gnu/libwayland-client.so") +set(WAYLAND_CURSOR_LIB "/usr/lib/aarch64-linux-gnu/libwayland-cursor.so") +set(WAYLAND_EGL_LIB "/usr/lib/aarch64-linux-gnu/libwayland-egl.so") +set(XKBCOMMON_LIB "/usr/lib/aarch64-linux-gnu/libxkbcommon.so") + +message(STATUS "Using GCC Version: ${GCC_VERSION}") +message(STATUS "C Compiler: ${CMAKE_C_COMPILER}") +message(STATUS "C++ Compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "System Root: ${CMAKE_SYSROOT}") diff --git a/libs/openFrameworksCompiled/project/android/.cproject b/libs/openFrameworksCompiled/project/android/.cproject deleted file mode 100644 index 2da1a94da0d..00000000000 --- a/libs/openFrameworksCompiled/project/android/.cproject +++ /dev/null @@ -1,4348 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/openFrameworksCompiled/project/android/.project b/libs/openFrameworksCompiled/project/android/.project deleted file mode 100644 index a9ed310416c..00000000000 --- a/libs/openFrameworksCompiled/project/android/.project +++ /dev/null @@ -1,83 +0,0 @@ - - - openFrameworks - - - libs - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.autoBuildTarget - all - - - org.eclipse.cdt.make.core.buildArguments - - - - org.eclipse.cdt.make.core.buildCommand - make - - - org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/androidGraphicsExample/Debug} - - - org.eclipse.cdt.make.core.cleanBuildTarget - clean -C../openFrameworksCompiled/project/linux64 - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - false - - - org.eclipse.cdt.make.core.enableCleanBuild - true - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.fullBuildTarget - all -C../openFrameworksCompiled/project/linux64 - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - true - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - - - - - - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.core.cnature - - diff --git a/libs/openFrameworksCompiled/project/android/build.gradle b/libs/openFrameworksCompiled/project/android/build.gradle index d5cc231dbf6..abed22fcb83 100644 --- a/libs/openFrameworksCompiled/project/android/build.gradle +++ b/libs/openFrameworksCompiled/project/android/build.gradle @@ -1,76 +1,23 @@ -def ofRoot(){ return '../../../../' } -final ofSource = ofRoot() + 'libs/openFrameworks' -final ofLibs = ofRoot() + 'libs' -final addons = ofRoot() + 'addons' - -// Load common functions -apply from: "common-functions.gradle" - -apply plugin: "com.android.model.native" - -model { - android { - compileSdkVersion 25 - - defaultConfig.with { - minSdkVersion.apiLevel 19 - targetSdkVersion.apiLevel 25 - } - - ndk { - platformVersion = "21" - moduleName "openFrameworksLib" - toolchain = buildToolchain() - stl = compilerStl() - } +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.9.0' + } +} - sources { - main { - jni { - source { - srcDirs = [ - ofSource - ] - excludes = ["**/ofGraphicsCairo.cpp", - "**/ofDirectShowGrabber.cpp", - "**/ofDirectShowPlayer.cpp", - "**/ofGstUtils.cpp", - "**/ofGstVideoGrabber.cpp", - "**/ofGstVideoPlayer.cpp", - "**/ofAppGlutWindow.cpp", - "**/ofAppEGLWindow.cpp", - "**/ofAppGLFWWindow.cpp", - "**/ofCairoRenderer.cpp", - "**/ofFmodSoundPlayer.cpp", - "**/ofOpenALSoundPlayer.cpp", - "**/ofRtAudioSoundStream.cpp", - "**/glew/**/*", - "**/videoInput/**/*", - "**/fmod/**/*", - "**/kiss/**/*", - "**/assimp/**/*", - "**/portaudio/**/*", - "**/rtAudio/**/*", - "**/poco/lib/**/*", - "**/openssl/lib/**/*", - "**/curl/**/*" - ] - } - } - } - } +allprojects { + repositories { + google() + mavenCentral() } + ext { - android.productFlavors { - getAbis().each { abi -> - create(getFlavorName(abi)) { - ndk { - abiFilters.add(abi) - cppFlags.addAll(coreCppFlags(abi, ofRoot())) - ldLibs.addAll(coreLdLibs(abi, ofRoot())) - ldFlags.addAll(coreLdFlags(abi, ofRoot())) - } - } - } } } + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/libs/openFrameworksCompiled/project/android/cmake.sh b/libs/openFrameworksCompiled/project/android/cmake.sh new file mode 100755 index 00000000000..318a24b1b6e --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/cmake.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +set -e + +ORIGINAL_DIR="$(pwd)" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd $SCRIPT_DIR +APOTHECARY_LEVEL="$(cd "$SCRIPT_DIR/../.." && pwd)" + +############################################ +# Configuration +############################################ + +TOOLCHAIN_FILE="$(pwd)/../CMake/toolchain/android.toolchain.cmake" +CMAKELISTS_DIR="$(pwd)/openframeworksAndroid" + +OUTPUT_DIR="$(pwd)/../../lib/android" + +export MAKE_TARGET="${MAKE_TARGET:-cmake}" +export NDK_VERSION_MAJOR="${NDK_VERSION_MAJOR:-27}" +export ANDROID_API="${ANDROID_API:-34}" #minimum Android API supported. 21 default + +# Usually must be >= 24 for modern libraries and NDKs. +ANDROID_PLATFORM="android-34" +C_STANDARD=17 +CPP_STANDARD=23 + +# Default architectures +DEFAULT_ARCHS="armeabi-v7a arm64-v8a x86_64" + +############################################ +# Parse Argument +############################################ + +ARCH="$1" + +# If user didn’t specify an arch or said "all", build for all +if [ -z "$ARCH" ] || [ "$ARCH" == "all" ]; then + ARCH="$DEFAULT_ARCHS" +fi + +if command -v sysctl &> /dev/null; then + PARALLEL_MAKE=$(sysctl -n hw.ncpu) +elif command -v nproc &> /dev/null; then + PARALLEL_MAKE=$(nproc) +else + PARALLEL_MAKE=1 +fi + +echo "Will build for architecture(s): $ARCHES" + +############################################ +# Build +############################################ + +for ARCHE in $ARCH; do + echo "-------------------------------------" + echo "Building for $ARCHE..." + echo "-------------------------------------" + + # Create a dedicated build folder for each architecture + BUILD_DIR="build-$ARCHE" + mkdir -p "$BUILD_DIR" + cd "$BUILD_DIR" + + cmake ../openframeworksAndroid \ + -G "Ninja" \ + -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \ + -DANDROID_ABI="$ARCH" \ + -DANDROID_PLATFORM="$ANDROID_PLATFORM" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_MAKE_PROGRAM=$(which ninja) \ + -DCONFIGURATION_BUILD_DIR="$OUTPUT_DIR" \ + "$CMAKELISTS_DIR" + + # Build using all available cores. + ninja -j "$NUM_CORES" + + # cmake ../openframeworksAndroid \ + # -DCMAKE_INSTALL_PREFIX=Release \ + # -DCMAKE_BUILD_TYPE=Release \ + # -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE \ + # -DPLATFORM=Android \ + # -DANDROID_PLATFORM=${ANDROID_PLATFORM} \ + # -DANDROID_ABI=${ARCHE} \ + # -DANDROID_API=${ANDROID_API} \ + # -DANDROID_TOOLCHAIN=clang \ + # -DANDROID_NDK_ROOT=$ANDROID_NDK_ROOT \ + # -DBUILD_SHARED_LIBS=OFF \ + # -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \ + # -DCMAKE_MINIMUM_REQUIRED_VERSION=3.22 \ + # -DCMAKE_CXX_FLAGS="-DUSE_PTHREADS=1 -fvisibility-inlines-hidden -std=c++${CPP_STANDARD} -frtti" \ + # -DCMAKE_C_FLAGS="-DUSE_PTHREADS=1 -fvisibility-inlines-hidden -std=c${C_STANDARD} -Wno-implicit-function-declaration -frtti" \ + # -DENABLE_VISIBILITY=OFF \ + # -DCMAKE_VERBOSE_MAKEFILE=ON \ + # -DCMAKE_CXX_EXTENSIONS=OFF + # cmake --build . --config Release -j${PARALLEL_MAKE} --target install + + # # Configure + # cmake \ + # -G "Ninja" \ + # -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \ + # -DANDROID_ABI="$ARCH" \ + # -DANDROID_PLATFORM="$ANDROID_PLATFORM" \ + # -DCMAKE_BUILD_TYPE=Release \ + # "$CMAKELISTS_DIR" + + + # # Build + # ninja -j $NUM_CORES + + cd .. +done + +echo -e "=========================================\n" + +cd "$ORIGINAL_DIR" diff --git a/libs/openFrameworksCompiled/project/android/common-functions.gradle b/libs/openFrameworksCompiled/project/android/common-functions.gradle index 5cdd9340d4b..11ba83a4473 100755 --- a/libs/openFrameworksCompiled/project/android/common-functions.gradle +++ b/libs/openFrameworksCompiled/project/android/common-functions.gradle @@ -1,430 +1,369 @@ - -def getFilesRecursive(path){ - FileTree tree = fileTree(dir: path) - def files = tree.matching({includes ["*.cpp"]}).toList() - return files -} - -def getFoldersRecursive(String path){ - def file = new File(path) - def ret = [path] - if(!file.exists()) return [] - - file.eachDirRecurse() { dir -> - ret.add(dir.getAbsolutePath()) - } - return ret - -} - - - -def addonPaths(ofRoot){ - def file = new File('addons.make') - if(!file.exists()) { - return [] - } - - def addonRoot = ofRoot+"addons/" - - def ret = [] - file.eachLine { line -> - def folder = new File(addonRoot+line) - if (!folder.exists()) { - throw new GradleException("Addon ${line} could not be found at ${folder.absolutePath}") - } - ret += folder.absolutePath - } - - return ret -} - - - -def parseAddonConfig(String addon, String param, String abi, defaultVal = []){ - def ret = defaultVal - - def file = new File(addon+"/addon_config.mk") - if(!file.exists()){ - println addon+"/addon_config.mk not found" - return defaultVal - } - - def mode = "" - - file.eachLine { line -> - def stripLine = line.replaceAll("^\\s*","").replaceAll("\\s*\$","") - if(stripLine.startsWith("#") || stripLine.length() == 0){ - return - } - - if(stripLine.endsWith(":")){ - mode = stripLine.replaceAll(":\$","") - } - - if(mode == "common" || mode == "android" || mode == "android/${abi}".toString()){ - def group = (stripLine =~ /^(\w+)\s*(\+?=)\s*(.+)$/) - if(group.hasGroup() && group.size() == 1 && group[0].size() == 4){ - if(group[0][1] == param) { - def _p = group[0][3].replaceAll("%", "*") - if (group[0][2] == '=') { - ret = [_p] - } else { - ret += _p - } - } - } - - } - } - - return ret -} - -def addonSources(String root, String abi=""){ - - def ret = [] - addonPaths(root).each { String addon -> - def config = parseAddonConfig( - addon, - "ADDON_SOURCES", - abi, - ["src", "libs"] - ) - - //ret += addon - config.each { String path -> - ret += addon+'/'+path - } - } - println "\n\n ADDON_SOURCES "+ret+"\n\n" - - return ret -} - -def addonIncludes(String root, String abi=""){ - def ret = [] - return ret -} - -def addonSourcesExclude(String root, String abi=""){ - def ret = [] - addonPaths(root).each { String addon -> - def config = parseAddonConfig( - addon, - "ADDON_SOURCES_EXCLUDE", - abi - ) - - config.each { String path -> - // TODO: Currently first part of path is stripped. Doesn't work otherwise - ret += path.replaceAll(/^\w+\//,"**/") - } - } - -// ret += "**/dlib/include/*" - println "\n EXCLUDE "+ret+"\n\n" - return ret -} - - -def addonLdFlags(abi, ofRoot){ - def ret = [] - addonPaths(ofRoot).each { String addon -> - def libs = []; - fileTree(dir: addon + "/libs", include: "**/lib/android/" + abi + "/*.a") - .each{ lib -> libs += lib.getAbsolutePath(); }; - - def config = parseAddonConfig( - addon, - "ADDON_LIBS", - abi, - libs - ) - - config.each { String path -> - def f = new File(addon+"/"+path) - if(f.exists()) { - ret += f.toString(); - } - } - } - println "\n ADDON_LIBS "+ret+"\n\n" - return ret -} - - - -def addonCppFlags(abi, ofRoot){ - def ret = [] - addonPaths(ofRoot).each { addon -> - def config = parseAddonConfig( - addon, - "ADDON_INCLUDES", - abi, - ["libs","src"] - ) - def excludeConfig = parseAddonConfig( - addon, - "ADDON_INCLUDES_EXCLUDE", - abi - ) - - config.each { String path -> - def flags = [] - getFoldersRecursive(addon+"/"+path).each{ String folder -> - def excluded = false - excludeConfig.each { ex -> - def _ex = ex.replaceAll(/\*/,".+") - if(folder ==~ /.*$addon\/$_ex/ ) { - excluded = true - } - } - - if(!excluded) { - flags += "-I${folder}".toString() - } - } - - ret += flags - } - - - def configFlags = parseAddonConfig(addon, "ADDON_CFLAGS", abi); - configFlags.each { String flag -> - ret += flag - } - - /* - ret += getFoldersRecursive(addon + "/libs").collect{ folder -> - return "-I${folder}".toString() - } - ret += getFoldersRecursive(addon + "/src").collect{ folder -> - return "-I${folder}".toString() - }*/ - } - println "\n ADDON_CFLAGS "+ret+"\n\n" - return ret -} - -def addonData(ofRoot){ - def ret = [] - addonPaths(ofRoot).each { addon -> - def configFlags = parseAddonConfig(addon, "ADDON_DATA", ""); - configFlags.each { String path -> - ret += addon + "/" + path - } - } - return ret -} - -def addonJavaDependencies(root,abi=""){ - def ret = [] - addonPaths(root).each { String addon -> - def config = parseAddonConfig( - addon, - "ADDON_ANDROID_LIBS", - abi - ) - - config.each { String path -> - def f = new File(addon+"/"+path) - if(f.exists()) { - ret += [[f.toString(), ':'+new File(addon).name]] - } - } - } - println "\n JAVA_LIBS "+ret+"\n\n" - return ret -} - -def javaDependencies(ofRoot){ - def ret = [] - ret += [[ofRoot+'addons/ofxAndroid/ofAndroidLib', ':ofAndroidLib']] - ret += [[ofRoot+'libs/openFrameworksCompiled/project/android', ':openFrameworksProject']] - return ret -} - - -def getFlavorName(abi) { - switch (abi) { - case "armeabi": - return "armeabi"; - case "armeabi-v7a": - return "arm7" - case "arm64-v8a": - return "arm64" - default: - return abi.replaceAll('-', '_') - } -} - -def getAbis(){ - return ["arm64-v8a", "armeabi-v7a", "x86"] -} - -def ofAppModuleName(){ - return "OFAndroidApp" -} - -def buildToolchain(){ - return "clang" -} - -def appSrcDirs(ofRoot){ - def ret = ['src', - ofRoot+"/addons/ofxAndroid/src", - ofRoot+"/addons/ofxAccelerometer/src" - ] - - ret += addonSources(ofRoot) - - return ret -} - -def srcExcludes(ofRoot){ - return addonSourcesExclude(ofRoot) -} - -def srcIncludes(ofRoot){ - return [] -} - - -def coreCppFlags(abi, ofRoot){ - def ofSource = ofRoot + 'libs/openFrameworks' - def libs = ofRoot + 'libs' - - def ret = ["-std=c++14", - "-Wall", - "-frtti", - "-fexceptions", - "-nostdlib ", - "-fno-short-enums", - "-ffunction-sections", - "-fdata-sections", - "-I${file(ofSource)}".toString(), - "-I${file(ofSource+"/3d")}".toString(), - "-I${file(ofSource+"/app")}".toString(), - "-I${file(ofSource+"/communication")}".toString(), - "-I${file(ofSource+"/events")}".toString(), - "-I${file(ofSource+"/gl")}".toString(), - "-I${file(ofSource+"/graphics")}".toString(), - "-I${file(ofSource+"/math")}".toString(), - "-I${file(ofSource+"/output")}".toString(), - "-I${file(ofSource+"/sound")}".toString(), - "-I${file(ofSource+"/types")}".toString(), - "-I${file(ofSource+"/utils")}".toString(), - "-I${file(ofSource+"/video")}".toString(), - "-I${file(ofRoot+"/addons/ofxAndroid/src")}".toString(), - "-I${file(ofRoot+"/addons/ofxAccelerometer/src")}".toString(), - "-I${file(libs+"/FreeImage/include")}".toString(), - "-I${file(libs+"/cairo/include")}".toString(), - "-I${file(libs+"/cairo/include/cairo")}".toString(), - "-I${file(libs+"/freetype/include")}".toString(), - "-I${file(libs+"/freetype/include/freetype2")}".toString(), - "-I${file(libs+"/freetype/include/freetype2/config")}".toString(), - "-I${file(libs+"/freetype/include/freetype2/internal")}".toString(), - "-I${file(libs+"/freetype/include/freetype2/internal/services")}".toString(), - "-I${file(libs+"/glfw/include")}".toString(), - "-I${file(libs+"/glfw/include/GLFW")}".toString(), - "-I${file(libs+"/openssl/include")}".toString(), - "-I${file(libs+"/openssl/include/openssl")}".toString(), - "-I${file(libs+"/poco/include")}".toString(), - "-I${file(libs+"/tess2/include")}".toString(), - "-I${file(libs+"/utf8cpp/include")}".toString(), - "-I${file(libs+"/json/include")}".toString(), - "-I${file(libs+'/kiss/include')}".toString(), - "-I${file(libs+'/glm/include')}".toString(), - "-I${file(libs+'/utf8/include')}".toString(), - "-I${file(libs+'/uriparser/include')}".toString(), - "-I${file(libs+'/curl/include')}".toString(), - "-I${file(libs+'/pugixml/include')}".toString(), - "-I${file(libs+'/libxml2/include')}".toString(), - "-I${file(libs+'/libs/glu/include_android')}".toString() - - ] - - println "\n CPP_FLAGS "+ret+"\n\n" - - return ret; -} - -def addonLdLibs(abi, ofRoot){ - return [] -} - -def addonLdCompilerFlags(abi, ofRoot){ - return [] -} - -def coreLdLibs(abi, ofRoot){ - return ["atomic","android", "OpenSLES", "z", "GLESv1_CM", "GLESv2", "log"] -} - - - -def getPrebuiltLibPaths(abi, ofRoot) { - def libs = ofRoot + 'libs' - - def paths = [] - paths += file(libs+"/FreeImage/lib/android/${abi}/libfreeimage.a").toString() - paths += file(libs+"/freetype/lib/android/${abi}/libfreetype.a").toString() - paths += file(libs+"/tess2/lib/android/${abi}/libtess2.a").toString() - paths += file(libs+"/curl/lib/android/${abi}/libcurl.a").toString() - paths += file(libs+"/openssl/lib/android/${abi}/libssl.a").toString() - paths += file(libs+"/openssl/lib/android/${abi}/libcrypto.a").toString() - paths += file(libs+"/pugixml/lib/android/${abi}/libpugixml.a").toString() - paths += file(libs+"/uriparser/lib/android/${abi}").toString() - return paths -} - - -def coreLdFlags(abi, ofRoot){ - def ret = [ - '-Wl,--exclude-libs,ALL', - '-Wl,--as-needed', - '-Wl,--gc-sections' - ] - - def prebuilt = getPrebuiltLibPaths(abi, ofRoot) - ret.addAll(prebuilt) - - return ret -} - - -def compilerStl(){ - return "c++_static" -} - - -// Export the functions -ext { - ofAppModuleName = this.&ofAppModuleName - - getFlavorName = this.&getFlavorName - buildToolchain= this.&buildToolchain - getAbis = this.&getAbis - compilerStl= this.&compilerStl - - appSrcDirs = this.&appSrcDirs - srcExcludes = this.&srcExcludes - srcIncludes = this.&srcIncludes - - coreCppFlags = this.&coreCppFlags - addonCppFlags = this.&addonCppFlags - - coreLdLibs= this.&coreLdLibs - addonLdLibs= this.&addonLdLibs - - coreLdFlags = this.&coreLdFlags - addonLdFlags = this.&addonLdFlags - - addonData = this.&addonData - - addonJavaDependencies = this.&addonJavaDependencies - javaDependencies = this.&javaDependencies - - -} +// +//def getFilesRecursive(path){ +// FileTree tree = fileTree(dir: path) +// def files = tree.matching({includes ["*.cpp"]}).toList() +// return files +//} +// +//def getFoldersRecursive(String path){ +// def file = new File(path) +// def ret = [path] +// if(!file.exists()) return [] +// +// file.eachDirRecurse() { dir -> +// ret.add(dir.getAbsolutePath()) +// } +// return ret +// +//} +// +// +// +//def addonPaths(ofRoot){ +// def file = new File('addons.make') +// if(!file.exists()) { +// return [] +// } +// +// def addonRoot = ofRoot+"addons/" +// +// def ret = [] +// file.eachLine { line -> +// def folder = new File(addonRoot+line) +// if (!folder.exists()) { +// throw new GradleException("Addon ${line} could not be found at ${folder.absolutePath}") +// } +// ret += folder.absolutePath +// } +// +// return ret +//} +// +// +// +//def parseAddonConfig(String addon, String param, String abi, defaultVal = []){ +// def ret = defaultVal +// +// def file = new File(addon+"/addon_config.mk") +// if(!file.exists()){ +// println addon+"/addon_config.mk not found" +// return defaultVal +// } +// +// def mode = "" +// +// file.eachLine { line -> +// def stripLine = line.replaceAll("^\\s*","").replaceAll("\\s*\$","") +// if(stripLine.startsWith("#") || stripLine.length() == 0){ +// return +// } +// +// if(stripLine.endsWith(":")){ +// mode = stripLine.replaceAll(":\$","") +// } +// +// if(mode == "common" || mode == "android" || mode == "android/${abi}".toString()){ +// def group = (stripLine =~ /^(\w+)\s*(\+?=)\s*(.+)$/) +// if(group.hasGroup() && group.size() == 1 && group[0].size() == 4){ +// if(group[0][1] == param) { +// def _p = group[0][3].replaceAll("%", "*") +// if (group[0][2] == '=') { +// ret = [_p] +// } else { +// ret += _p +// } +// } +// } +// +// } +// } +// +// return ret +//} +// +//def addonSources(String root, String abi=""){ +// +// def ret = [] +// addonPaths(root).each { String addon -> +// def config = parseAddonConfig( +// addon, +// "ADDON_SOURCES", +// abi, +// ["src", "libs"] +// ) +// +// //ret += addon +// config.each { String path -> +// ret += addon+'/'+path +// } +// } +// println "\n\n ADDON_SOURCES "+ret+"\n\n" +// +// return ret +//} +// +//def addonIncludes(String root, String abi=""){ +// def ret = [] +// return ret +//} +// +//def addonSourcesExclude(String root, String abi=""){ +// def ret = [] +// addonPaths(root).each { String addon -> +// def config = parseAddonConfig( +// addon, +// "ADDON_SOURCES_EXCLUDE", +// abi +// ) +// +// config.each { String path -> +// // TODO: Currently first part of path is stripped. Doesn't work otherwise +// ret += path.replaceAll(/^\w+\//,"**/") +// } +// } +// +//// ret += "**/dlib/include/*" +// println "\n EXCLUDE "+ret+"\n\n" +// return ret +//} +// +// +//def addonLdFlags(abi, ofRoot){ +// def ret = [] +// addonPaths(ofRoot).each { String addon -> +// def libs = []; +// fileTree(dir: addon + "/libs", include: "**/lib/android/" + abi + "/*.a") +// .each{ lib -> libs += lib.getAbsolutePath(); }; +// +// def config = parseAddonConfig( +// addon, +// "ADDON_LIBS", +// abi, +// libs +// ) +// +// config.each { String path -> +// def f = new File(addon+"/"+path) +// if(f.exists()) { +// ret += f.toString(); +// } +// } +// } +// println "\n ADDON_LIBS "+ret+"\n\n" +// return ret +//} +// +// +// +//def addonCppFlags(abi, ofRoot){ +// def ret = [] +// addonPaths(ofRoot).each { addon -> +// def config = parseAddonConfig( +// addon, +// "ADDON_INCLUDES", +// abi, +// ["libs","src"] +// ) +// def excludeConfig = parseAddonConfig( +// addon, +// "ADDON_INCLUDES_EXCLUDE", +// abi +// ) +// +// config.each { String path -> +// def flags = [] +// getFoldersRecursive(addon+"/"+path).each{ String folder -> +// def excluded = false +// excludeConfig.each { ex -> +// def _ex = ex.replaceAll(/\*/,".+") +// if(folder ==~ /.*$addon\/$_ex/ ) { +// excluded = true +// } +// } +// +// if(!excluded) { +// flags += "-I${folder}".toString() +// } +// } +// +// ret += flags +// } +// +// +// def configFlags = parseAddonConfig(addon, "ADDON_CFLAGS", abi); +// configFlags.each { String flag -> +// ret += flag +// } +// +// /* +// ret += getFoldersRecursive(addon + "/libs").collect{ folder -> +// return "-I${folder}".toString() +// } +// ret += getFoldersRecursive(addon + "/src").collect{ folder -> +// return "-I${folder}".toString() +// }*/ +// } +// println "\n ADDON_CFLAGS "+ret+"\n\n" +// return ret +//} +// +//def addonData(ofRoot){ +// def ret = [] +// addonPaths(ofRoot).each { addon -> +// def configFlags = parseAddonConfig(addon, "ADDON_DATA", ""); +// configFlags.each { String path -> +// ret += addon + "/" + path +// } +// } +// return ret +//} +// +//def addonJavaDependencies(root,abi=""){ +// def ret = [] +// addonPaths(root).each { String addon -> +// def config = parseAddonConfig( +// addon, +// "ADDON_ANDROID_LIBS", +// abi +// ) +// +// config.each { String path -> +// def f = new File(addon+"/"+path) +// if(f.exists()) { +// ret += [[f.toString(), ':'+new File(addon).name]] +// } +// } +// } +// println "\n JAVA_LIBS "+ret+"\n\n" +// return ret +//} +// +//def javaDependencies(ofRoot){ +// def ret = [] +// ret += [[ofRoot+'addons/ofxAndroid/ofAndroidLib', ':ofAndroidLib']] +// ret += [[ofRoot+'libs/openFrameworksCompiled/project/android', ':openFrameworksProject']] +// return ret +//} +// +// +//def getFlavorName(abi) { +// switch (abi) { +// case "armeabi": +// return "armeabi"; +// case "armeabi-v7a": +// return "arm7" +// case "arm64-v8a": +// return "arm64" +// default: +// return abi.replaceAll('-', '_') +// } +//} +// +//def getAbis(){ +// return ["arm64-v8a", "armeabi-v7a", "x86"] +//} +// +//def ofAppModuleName(){ +// return "OFAndroidApp" +//} +// +//def buildToolchain(){ +// return "clang" +//} +// +//def appSrcDirs(ofRoot){ +// def ret = ['src', +// ofRoot+"/addons/ofxAndroid/src", +// ofRoot+"/addons/ofxAccelerometer/src" +// ] +// +// ret += addonSources(ofRoot) +// +// return ret +//} +// +//def srcExcludes(ofRoot){ +// return addonSourcesExclude(ofRoot) +//} +// +//def srcIncludes(ofRoot){ +// return [] +//} +// +// +// +//def addonLdLibs(abi, ofRoot){ +// return [] +//} +// +//def addonLdCompilerFlags(abi, ofRoot){ +// return [] +//} +// +// +//// def getPrebuiltLibPaths(abi, ofRoot) { +//// def libs = ofRoot + 'libs' +// +//// def paths = [] +//// paths += file(libs+"/FreeImage/lib/android/${abi}/libfreeimage.a").toString() +//// paths += file(libs+"/boost/lib/android/${abi}/libboost_filesystem.a").toString() +//// paths += file(libs+"/boost/lib/android/${abi}/libboost_system.a").toString() +//// paths += file(libs+"/freetype/lib/android/${abi}/libfreetype.a").toString() +//// paths += file(libs+"/tess2/lib/android/${abi}/libtess2.a").toString() +//// paths += file(libs+"/curl/lib/android/${abi}/libcurl.a").toString() +//// paths += file(libs+"/openssl/lib/android/${abi}/libssl.a").toString() +//// paths += file(libs+"/openssl/lib/android/${abi}/libcrypto.a").toString() +//// paths += file(libs+"/pugixml/lib/android/${abi}/libpugixml.a").toString() +//// paths += file(libs+"/uriparser/lib/android/${abi}").toString() +//// return paths +//// } +// +// +//def coreLdFlags(abi, ofRoot){ +// def ret = [ +// '-Wl,--exclude-libs,ALL', +// '-Wl,--as-needed', +// '-Wl,--gc-sections' +// ] +// +// def prebuilt = getPrebuiltLibPaths(abi, ofRoot) +// ret.addAll(prebuilt) +// +// return ret +//} +// +// +//def compilerStl(){ +// return "c++_static" +//} +// +// +//// Export the functions +//ext { +// ofAppModuleName = this.&ofAppModuleName +// +// getFlavorName = this.&getFlavorName +// buildToolchain= this.&buildToolchain +// getAbis = this.&getAbis +// compilerStl= this.&compilerStl +// +// appSrcDirs = this.&appSrcDirs +// srcExcludes = this.&srcExcludes +// srcIncludes = this.&srcIncludes +// +// coreCppFlags = this.&coreCppFlags +// addonCppFlags = this.&addonCppFlags +// +// coreLdLibs= this.&coreLdLibs +// addonLdLibs= this.&addonLdLibs +// +// coreLdFlags = this.&coreLdFlags +// addonLdFlags = this.&addonLdFlags +// +// addonData = this.&addonData +// +// addonJavaDependencies = this.&addonJavaDependencies +// javaDependencies = this.&javaDependencies +// +// +//} diff --git a/libs/openFrameworksCompiled/project/android/config.android.default.mk b/libs/openFrameworksCompiled/project/android/config.android.default.mk deleted file mode 100644 index 8ad39c698a2..00000000000 --- a/libs/openFrameworksCompiled/project/android/config.android.default.mk +++ /dev/null @@ -1,612 +0,0 @@ -################################################################################ -# CONFIGURE CORE PLATFORM MAKEFILE -# This file is where we make platform and architecture specific -# configurations. This file can be specified for a generic architecture or can -# be defined as variants. For instance, normally this file will be located in -# a platform specific subpath such as -# -# $(OF_ROOT)/libs/openFrameworksComplied/linux64 -# -# This file will then be a generic platform file like: -# -# configure.core.linux64.default.make -# -# Or it can specify a specific platform variant like: -# -# configure.core.linuxarmv6l.raspberrypi.make -# -################################################################################ - -################################################################################ -# PLATFORM SPECIFIC CHECKS -# This is a platform defined section to create internal flags to enable or -# disable the addition of various features within this makefile. For -# instance, on Linux, we check to see if there GTK+-2.0 is defined, allowing -# us to include that library and generate DEFINES that are interpreted as -# ifdefs within the openFrameworks core source code. -################################################################################ - -#check if mpg123 exists and add it -#HAS_SYSTEM_MPG123 = $(shell pkg-config libmpg123 --exists; echo $$?) - -include $(OF_ROOT)/libs/openFrameworksCompiled/project/android/paths.make -ARCH = android - -ifndef ABIS_TO_COMPILE_RELEASE - ABIS_TO_COMPILE_RELEASE = armv7 neon x86 -endif - -ifndef ABIS_TO_COMPILE_DEBUG - ABIS_TO_COMPILE_DEBUG = armv7 -endif - - -################################################################################ -# PLATFORM DEFINES -# Create a list of DEFINES for this platform. The list will be converted into -# CFLAGS with the "-D" flag later in the makefile. An example of fully -# qualified flag might look something like this: -DTARGET_OPENGLES2 -# -# DEFINES are used throughout the openFrameworks code, especially when making -# #ifdef decisions for cross-platform compatibility. For instance, when -# choosing a video playback framework, the openFrameworks base classes look at -# the DEFINES to determine what source files to include or what default player -# to use. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -PLATFORM_DEFINES = -PLATFORM_DEFINES = ANDROID - -ifndef $(NDK_PLATFORM) - NDK_PLATFORM = android-19 -endif - -ifndef $(SDK_TARGET) - SDK_TARGET = android-21 -endif - -ifndef $(GCC_VERSION) - GCC_VERSION = 4.9 -endif - -ifndef $(CLANG_VERSION) - CLANG_VERSION = 3.6 -endif - -PROJECT_PATH=$(PWD) - - -ifeq ($(ABI),x86) -ANDROID_PREFIX=i686-linux-android- -TOOLCHAIN=llvm -GCC_TOOLCHAIN=$(NDK_ROOT)/toolchains/x86-4.9 -SYSROOT=$(NDK_ROOT)/platforms/$(NDK_PLATFORM)/arch-x86/ -else -ANDROID_PREFIX=arm-linux-androideabi- -TOOLCHAIN=llvm -GCC_TOOLCHAIN=$(NDK_ROOT)/toolchains/arm-linux-androideabi-4.9 -SYSROOT=$(NDK_ROOT)/platforms/$(NDK_PLATFORM)/arch-arm/ -endif - -ifeq ($(shell uname),Darwin) -ifneq ($(wildcard $(NDK_ROOT)/toolchains/$(TOOLCHAIN)/prebuilt/darwin-x86_64),) - HOST_PLATFORM = darwin-x86_64 -else - HOST_PLATFORM = darwin-x86 -endif -else ifneq (,$(findstring MINGW32_NT,$(shell uname))) -ifneq ($(wildcard $(NDK_ROOT)/toolchains/$(TOOLCHAIN)/prebuilt/windows-x86_64),) - HOST_PLATFORM = windows-x86_64 -else - HOST_PLATFORM = windows -endif - PWD = $(shell pwd) -else -ifneq ($(wildcard $(NDK_ROOT)/toolchains/$(TOOLCHAIN)/prebuilt/linux-x86_64),) - HOST_PLATFORM = linux-x86_64 -else - HOST_PLATFORM = linux-x86 -endif -endif - -TOOLCHAIN_PATH=$(NDK_ROOT)/toolchains/$(TOOLCHAIN)/prebuilt/$(HOST_PLATFORM)/bin/ - -DATA_FILES = $(shell find bin/data -type f 2>/dev/null) -RESNAME=ofdataresources -RESFILE=$(RESNAME).zip - -ifeq ($(ABI),armv7) - ABI_PATH = armeabi-v7a - PLATFORM_PROJECT_RELEASE_TARGET = libs/$(ABI_PATH)/libOFAndroidApp.so - PLATFORM_PROJECT_DEBUG_TARGET = libs/$(ABI_PATH)/libOFAndroidApp.so -endif - -ifeq ($(ABI),armv5) - ABI_PATH = armeabi - PLATFORM_PROJECT_RELEASE_TARGET = libs/$(ABI_PATH)/libOFAndroidApp.so - PLATFORM_PROJECT_DEBUG_TARGET = libs/$(ABI_PATH)/libOFAndroidApp.so -endif - -ifeq ($(ABI),neon) - ABI_PATH = armeabi-v7a - PLATFORM_PROJECT_RELEASE_TARGET = libs/$(ABI_PATH)/libOFAndroidApp_neon.so - PLATFORM_PROJECT_DEBUG_TARGET = libs/$(ABI_PATH)/libOFAndroidApp_neon.so -endif - -ifeq ($(ABI),x86) - ABI_PATH = x86 - PLATFORM_PROJECT_RELEASE_TARGET = libs/$(ABI_PATH)/libOFAndroidApp_x86.so - PLATFORM_PROJECT_DEBUG_TARGET = libs/$(ABI_PATH)/libOFAndroidApp_x86.so -endif - -PLATFORM_CORELIB_RELEASE_TARGET = $(OF_CORE_LIB_PATH)/$(ABI)/libopenFrameworks.a -PLATFORM_CORELIB_DEBUG_TARGET = $(OF_CORE_LIB_PATH)/$(ABI)/libopenFrameworksDebug.a - - -# add OF_USING_MPG123 define IF we have it defined as a system library -#ifeq ($(HAS_SYSTEM_MPG123),0) -# PLATFORM_DEFINES += OF_USING_MPG123 -#endif - -################################################################################ -# PLATFORM REQUIRED ADDON -# This is a list of addons required for this platform. This list is used to -# EXCLUDE addon source files when compiling projects, while INCLUDING their -# header files. During core library compilation, this is used to include -# required addon header files as needed within the core. -# -# For instance, if you are compiling for Android, you would add ofxAndroid -# here. If you are compiling for Raspberry Pi, you would add ofxRaspberryPi -# here. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -PLATFORM_REQUIRED_ADDONS = ofxAndroid ofxAccelerometer - -################################################################################ -# PLATFORM CFLAGS -# This is a list of fully qualified CFLAGS required when compiling for this -# platform. These flags will always be added when compiling a project or the -# core library. These flags are presented to the compiler AFTER the -# PLATFORM_OPTIMIZATION_CFLAGS below. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -# Warning Flags (http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html) -PLATFORM_CFLAGS = -Wall -std=c++14 - -# Code Generation Option Flags (http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html) -PLATFORM_CFLAGS += -nostdlib --sysroot=$(SYSROOT) -fpic \ - -ffunction-sections \ - -funwind-tables \ - -fstack-protector-strong \ - -Wno-invalid-command-line-argument \ - -Wno-unused-command-line-argument \ - -no-canonical-prefixes \ - -gcc-toolchain $(GCC_TOOLCHAIN)/prebuilt/$(HOST_PLATFORM) \ - -fno-integrated-as - - -ifeq ($(ABI),armv7) - PLATFORM_CFLAGS += -target armv7-none-linux-androideabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -endif - -ifeq ($(ABI),neon) - PLATFORM_CFLAGS += -target armv7-none-linux-androideabi -march=armv7-a -mfloat-abi=softfp -mfpu=neon -endif - -ifeq ($(ABI),x86) - PLATFORM_CFLAGS += -target i686-none-linux-android -march=i686 -msse3 -mstackrealign -mfpmath=sse -fno-stack-protector -endif - -################################################################################ -# PLATFORM LDFLAGS -# This is a list of fully qualified LDFLAGS required when linking for this -# platform. These flags will always be added when linking a project. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -PLATFORM_LDFLAGS = -PLATFORM_LDFLAGS += --sysroot=$(SYSROOT) --isystem=$(SYSROOT) -L"$(NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/$(ABI_PATH)" -PLATFORM_LDFLAGS += -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--gc-sections -Wl,--exclude-libs,ALL -gcc-toolchain $(GCC_TOOLCHAIN)/prebuilt/$(HOST_PLATFORM) - - -ifneq ($(ABI),x86) -PLATFORM_LDFLAGS += -target armv7-none-linux-androideabi -march=armv7-a -else -PLATFORM_LDFLAGS += -target i686-none-linux-android -march=i686 -endif - -################################################################################ -# PLATFORM OPTIMIZATION CFLAGS -# These are lists of CFLAGS that are target-specific. While any flags could -# be conditionally added, they are usually limited to optimization flags. -# These flags are added BEFORE the PLATFORM_CFLAGS. -# -# PLATFORM_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to -# RELEASE targets. -# -# PLATFORM_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to -# DEBUG targets. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -# RELEASE Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_RELEASE = -Os - -# RELEASE options -PLATFORM_OPTIMIZATION_LDFLAGS_RELEASE = -s - -# DEBUG Debugging options (http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html) -PLATFORM_OPTIMIZATION_CFLAGS_DEBUG = -O0 -g3 -DANDROID_NDK -D_DEBUG #-D_GLIBCXX_DEBUG - -################################################################################ -# PLATFORM CORE EXCLUSIONS -# During compilation, these makefiles will generate lists of sources, headers -# and third party libraries to be compiled and linked into a program or core -# library. The PLATFORM_CORE_EXCLUSIONS is a list of fully qualified file -# paths that will be used to exclude matching paths and files during list -# generation. -# -# Each item in the PLATFORM_CORE_EXCLUSIONS list will be treated as a complete -# string unless the user adds a wildcard (%) operator to match subdirectories. -# GNU make only allows one wildcard for matching. The second wildcard (%) is -# treated literally. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -# core sources -PLATFORM_CORE_EXCLUSIONS += %.mm -PLATFORM_CORE_EXCLUSIONS += %.m -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofDirectShowGrabber.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofDirectShowPlayer.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofGstUtils.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofGstVideoGrabber.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofGstVideoPlayer.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/video/ofMediaFoundationPlayer.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/app/ofAppGlutWindow.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/app/ofAppEGLWindow.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/app/ofAppGLFWWindow.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/graphics/ofCairoRenderer.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/sound/ofFmodSoundPlayer.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/sound/ofOpenALSoundPlayer.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/sound/ofRtAudioSoundStream.cpp -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openFrameworks/sound/ofMediaFoundationSoundPlayer.cpp - -# third party -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/glew/% -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/videoInput/% -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/fmod/% -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/kiss/% -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/assimp/% -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/portaudio/% -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/rtAudio/% -PLATFORM_CORE_EXCLUSIONS += $(OF_LIBS_PATH)/openssl/lib/% - -# android project folders -PROJECT_EXCLUSIONS += ./gen -PROJECT_EXCLUSIONS += ./gen/% -PROJECT_EXCLUSIONS += ./jni -PROJECT_EXCLUSIONS += ./srcJava -PROJECT_EXCLUSIONS += ./srcJava/% -PROJECT_EXCLUSIONS += ./res -PROJECT_EXCLUSIONS += ./res/% -PROJECT_EXCLUSIONS += ./assets -PROJECT_EXCLUSIONS += ./assets/% -PROJECT_EXCLUSIONS += ./libs - - - -################################################################################ -# PLATFORM HEADER SEARCH PATHS -# These are header search paths that are platform specific and are specified -# using fully-qualified paths. The include flag (i.e. -I) is prefixed -# automatically. These are usually not required, but may be required by some -# experimental platforms such as the raspberry pi or other other embedded -# architectures. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -PLATFORM_HEADER_SEARCH_PATHS = -PLATFORM_HEADER_SEARCH_PATHS += "$(SYSROOT)/usr/include/" -PLATFORM_HEADER_SEARCH_PATHS += "$(NDK_ROOT)/sources/cxx-stl/llvm-libc++/libcxx/include" -PLATFORM_HEADER_SEARCH_PATHS += "$(NDK_ROOT)/sources/cxx-stl/llvm-libc++/include" -PLATFORM_HEADER_SEARCH_PATHS += "$(NDK_ROOT)/sources/android/support/include" -#PLATFORM_HEADER_SEARCH_PATHS += "$(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/include" -#PLATFORM_HEADER_SEARCH_PATHS += "$(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(GCC_VERSION)/include" -#PLATFORM_HEADER_SEARCH_PATHS += "$(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/libs/$(ABI_PATH)/include" -#PLATFORM_HEADER_SEARCH_PATHS += "$(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(GCC_VERSION)/libs/$(ABI_PATH)/include" -#PLATFORM_HEADER_SEARCH_PATHS += "$(NDK_ROOT)/sources/crystax/include/" -PLATFORM_HEADER_SEARCH_PATHS += "$(OF_ROOT)/libs/glu/include_android" -PLATFORM_HEADER_SEARCH_PATHS += "$(OF_ROOT)/addons/ofxAndroid/src" - -################################################################################ -# PLATFORM LIBRARIES -# These are library names/paths that are platform specific and are specified -# using names or paths. The library flag (i.e. -l) is prefixed automatically. -# -# PLATFORM_LIBRARIES are libraries that can be found in the library search -# paths. -# PLATFORM_STATIC_LIBRARIES is a list of required static libraries. -# PLATFORM_SHARED_LIBRARIES is a list of required shared libraries. -# PLATFORM_PKG_CONFIG_LIBRARIES is a list of required libraries that are -# under system control and are easily accesible via the package -# configuration utility (i.e. pkg-config) -# -# See the helpfile for the -l flag here for more information: -# http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -PLATFORM_LIBRARIES = -PLATFORM_LIBRARIES += OpenSLES -#PLATFORM_LIBRARIES += supc++ -PLATFORM_LIBRARIES += z -PLATFORM_LIBRARIES += GLESv1_CM -PLATFORM_LIBRARIES += GLESv2 -PLATFORM_LIBRARIES += log -#PLATFORM_LIBRARIES += gnustl_static -#PLATFORM_LIBRARIES += stdc++ -PLATFORM_LIBRARIES += c++ -PLATFORM_LIBRARIES += c++abi -ifeq ($(ABI),armv7) - PLATFORM_LIBRARIES += unwind -endif -PLATFORM_LIBRARIES += c -PLATFORM_LIBRARIES += dl -PLATFORM_LIBRARIES += gcc -PLATFORM_LIBRARIES += m - -#static libraries (fully qualified paths) -PLATFORM_STATIC_LIBRARIES = -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/openssl/lib/$(ABI_LIB_SUBPATH)/libssl.a -PLATFORM_STATIC_LIBRARIES += $(OF_LIBS_PATH)/openssl/lib/$(ABI_LIB_SUBPATH)/libcrypto.a - -# shared libraries -PLATFORM_SHARED_LIBRARIES = - -#openframeworks core third party -PLATFORM_PKG_CONFIG_LIBRARIES = - -# conditionally add mpg123 -#ifeq ($(HAS_SYSTEM_MPG123),0) -# PLATFORM_PKG_CONFIG_LIBRARIES += libmpg123 -#endif - -################################################################################ -# PLATFORM LIBRARY SEARCH PATHS -# These are library search paths that are platform specific and are specified -# using fully-qualified paths. The lib search flag (i.e. -L) is prefixed -# automatically. The -L paths are used to find libraries defined above with -# the -l flag. -# -# See the the following link for more information on the -L flag: -# http://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ - -PLATFORM_LIBRARY_SEARCH_PATHS = - -################################################################################ -# PLATFORM FRAMEWORKS -# These are a list of platform frameworks. -# These are used exclusively with Darwin/OSX. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ -#PLATFORM_FRAMEWORKS = - -################################################################################ -# PLATFORM FRAMEWORK SEARCH PATHS -# These are a list of platform framework search paths. -# These are used exclusively with Darwin/OSX. -# -# Note: Leave a leading space when adding list items with the += operator -################################################################################ -#PLATFORM_FRAMEWORKS_SEARCH_PATHS = - -################################################################################ -# LOW LEVEL CONFIGURATION BELOW -# The following sections should only rarely be modified. They are meant for -# developers who need fine control when, for instance, creating a platform -# specific makefile for a new openFrameworks platform, such as raspberry pi. -################################################################################ - -################################################################################ -# PLATFORM CONFIGURATIONS -# These will override the architecture vars generated by configure.platform.make -################################################################################ -#PLATFORM_ARCH = -#PLATFORM_OS = -#PLATFORM_LIBS_PATH = - -################################################################################ -# PLATFORM CXX -# Don't want to use a default compiler? -################################################################################ -#PLATFORM_CXX= - -PLATFORM_CC=$(NDK_ROOT)/toolchains/$(TOOLCHAIN)/prebuilt/$(HOST_PLATFORM)/bin/clang -PLATFORM_CXX=$(NDK_ROOT)/toolchains/$(TOOLCHAIN)/prebuilt/$(HOST_PLATFORM)/bin/clang++ -PLATFORM_AR=$(NDK_ROOT)/toolchains/arm-linux-androideabi-4.9/prebuilt/$(HOST_PLATFORM)/arm-linux-androideabi/bin/ar -PLATFORM_LD=$(NDK_ROOT)/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin/ld - -#ifeq (,$(findstring MINGW32_NT,$(shell uname))) -ZIPWINDOWS=..\\..\\..\\..\\..\\libs\\openFrameworksCompiled\\project\\android\\windows\\zip -r ../../res/raw/$(RESFILE) -#endif - -afterplatform:$(RESFILE) - @if [ -f obj/$(BIN_NAME) ]; then rm obj/$(BIN_NAME); fi - - @echo copying debugging binaries for $(ABIS_TO_COMPILE) - @if [ "$(findstring neon,$(ABIS_TO_COMPILE))" = "neon" ]; then \ - cp $(OF_ROOT)/libs/openFrameworksCompiled/project/android/libneondetection.so libs/armeabi-v7a/; \ - cp $(NDK_ROOT)/prebuilt/android-arm/gdbserver/gdbserver libs/armeabi-v7a; \ - fi - - @if [ "$(findstring armv5,$(ABIS_TO_COMPILE))" = "armv5" ]; then \ - cp $(NDK_ROOT)/prebuilt/android-arm/gdbserver/gdbserver libs/armeabi; \ - fi - - @if [ "$(findstring armv7,$(ABIS_TO_COMPILE))" = "armv7" ]; then \ - cp $(NDK_ROOT)/prebuilt/android-arm/gdbserver/gdbserver libs/armeabi-v7a; \ - fi - - @if [ "$(findstring armv7,$(ABIS_TO_COMPILE))" = "x86" ]; then \ - cp $(NDK_ROOT)/prebuilt/android-x86/gdbserver/gdbserver libs/x86; \ - fi - - @cp $(NDK_ROOT)/prebuilt/android-arm/gdbserver/gdbserver libs; - - - @if [ "$(findstring armv5,$(ABIS_TO_COMPILE))" = "armv5" ]; then \ - echo create gdb.setup for armeabi; \ - echo "set solib-search-path $(PWD)/obj/local/armeabi:$(PWD)/libs/armeabi" > libs/armeabi/gdb.setup; \ - echo "set sysroot $(SYSROOT)" >> libs/armeabi/gdb.setup; \ - echo "directory $(NDK_ROOT)/platforms/$(NDK_PLATFORM)/arch-arm/usr/include" >> libs/armeabi/gdb.setup; \ - echo "directory $(PWD)/src" >> libs/armeabi/gdb.setup; \ - echo "directory $(NDK_ROOT)/sources/cxx-stl/system" >> libs/armeabi/gdb.setup; \ - echo "directory $(PWD)/libs/armeabi" >> libs/armeabi/gdb.setup; \ - echo "" >> libs/armeabi/gdb.setup; \ - fi - - @if [ "$(findstring armv7,$(ABIS_TO_COMPILE))" = "armv7" ]; then \ - echo create gdb.setup for armeabi-v7a; \ - echo "set solib-search-path $(PWD)/obj/local/armeabi-v7a:$(PWD)/libs/armeabi-v7a" > libs/armeabi-v7a/gdb.setup; \ - echo "set sysroot $(SYSROOT)" >> libs/armeabi-v7a/gdb.setup; \ - echo "directory $(NDK_ROOT)/platforms/$(NDK_PLATFORM)/arch-arm/usr/include" >> libs/armeabi-v7a/gdb.setup; \ - echo "directory $(PWD)/src" >> libs/armeabi-v7a/gdb.setup; \ - echo "directory $(NDK_ROOT)/sources/cxx-stl/system" >> libs/armeabi-v7a/gdb.setup; \ - echo "directory $(PWD)/libs/armeabi-v7a" >> libs/armeabi-v7a/gdb.setup ; \ - echo "" >> libs/armeabi-v7a/gdb.setup; \ - cp libs/armeabi-v7a/gdb.setup libs/gdb.setup; \ - fi - - @if [ "$(findstring x86,$(ABIS_TO_COMPILE))" = "x86" ]; then \ - echo create gdb.setup for x86; \ - echo "set solib-search-path $(PWD)/obj/local/x86:$(PWD)/libs/x86" > libs/x86/gdb.setup; \ - echo "set sysroot $(SYSROOT)" >> libs/x86/gdb.setup; \ - echo "directory $(NDK_ROOT)/platforms/$(NDK_PLATFORM)/arch-arm/usr/include" >> libs/x86/gdb.setup; \ - echo "directory $(PWD)/src" >> libs/x86/gdb.setup; \ - echo "directory $(NDK_ROOT)/sources/cxx-stl/system" >> libs/x86/gdb.setup; \ - echo "directory $(PWD)/libs/x86" >> libs/x86/gdb.setup ; \ - echo "" >> libs/x86/gdb.setup; \ - fi - - @echo creating Android.mk and Application.mk - @if [ ! -d jni ]; then mkdir jni; fi - @ABIS=""; \ - if [ "$(findstring armv5,$(ABIS_TO_COMPILE))" = "armv5" ]; then \ - ABIS="$$ABIS armeabi"; \ - else \ - rm -r libs/armeabi 2> /dev/null; \ - fi; \ - if [ "$(findstring armv7,$(ABIS_TO_COMPILE))" = "armv7" ] && [ "$(findstring neon,$(ABIS_TO_COMPILE))" = "neon" ]; then \ - ABIS="$$ABIS armeabi-v7a"; \ - elif [ "$(findstring armv7,$(ABIS_TO_COMPILE))" = "armv7" ]; then \ - ABIS="$$ABIS armeabi-v7a"; \ - rm libs/armeabi-v7a/libOFAndroidApp_neon.so 2> /dev/null; \ - rm libs/armeabi-v7a/libneondetection.so 2> /dev/null; \ - elif [ "$(findstring neon,$(ABIS_TO_COMPILE))" = "neon" ]; then \ - ABIS="$$ABIS armeabi-v7a"; \ - rm libs/armeabi-v7a/libOFAndroidApp.so 2> /dev/null; \ - else \ - rm -r libs/armeabi-v7a 2> /dev/null; \ - fi; \ - if [ "$(findstring x86,$(ABIS_TO_COMPILE))" = "x86" ]; then \ - ABIS="$$ABIS x86"; \ - else \ - rm -r libs/x86 2> /dev/null; \ - fi; \ - echo "APP_ABI := $$ABIS" > jni/Application.mk; \ - echo "APP_ABI := $$ABIS" > jni/Android.mk; \ - echo "LOCAL_MODULE := OFAndroidApp" >> jni/Android.mk - - - - #@echo updating ofAndroidLib project - #@cd $(OF_ROOT)/addons/ofxAndroid/ofAndroidLib; \ - #if [ "$(HOST_PLATFORM)" = "windows" ]; then \ - # cmd //c $(SDK_ROOT)/tools/android.bat update project --target $(SDK_TARGET) --path .; \ - #else \ - # $(SDK_ROOT)/tools/android update project --target $(SDK_TARGET) --path .; \ - #fi - - #@echo updating current project - #@cd $(PROJECT_PATH); \ - #if [ "$(HOST_PLATFORM)" = "windows" ]; then \ - # cmd //c $(SDK_ROOT)/tools/android.bat update project --target $(SDK_TARGET) --path .; \ - #else \ - # $(SDK_ROOT)/tools/android update project --target $(SDK_TARGET) --path .; \ - #fi - -$(RESFILE): $(DATA_FILES) - @echo compressing and copying resources from bin/data into res - cd "$(PROJECT_PATH)"; \ - if [ -d "bin/data" ]; then \ - mkdir -p res/raw; \ - rm res/raw/$(RESNAME).zip; \ - cd bin/data; \ - if [ "$(HOST_PLATFORM)" = "windows" ]; then \ - echo "Windows Platform. Running Zip..."; \ - cmd //c $(ZIPWINDOWS) * && exit; \ - else \ - zip -r ../../res/raw/$(RESNAME).zip *; \ - fi; \ - cd ../..; \ - fi - -install: - cd "$(OF_ROOT)/addons/ofxAndroid/ofAndroidLib"; \ - echo installing on $(HOST_PLATFORM); \ - if [ "$(HOST_PLATFORM)" = "windows" ]; then \ - cmd //c $(SDK_ROOT)/tools/android.bat update project --target $(SDK_TARGET) --path .; \ - else \ - $(SDK_ROOT)/tools/android update project --target $(SDK_TARGET) --path .; \ - fi - cd "$(PROJECT_PATH)"; \ - if [ -d "bin/data" ]; then \ - mkdir -p res/raw; \ - rm res/raw/$(RESNAME).zip; \ - cd bin/data; \ - if [ "$(HOST_PLATFORM)" = "windows" ]; then \ - echo "Windows Platform. Running Zip..."; \ - cmd //c $(ZIPWINDOWS) * && exit; \ - else \ - zip -r ../../res/raw/$(RESNAME).zip; *; \ - fi; \ - cd ../..; \ - fi - if [ -f obj/$(BIN_NAME) ]; then rm obj/$(BIN_NAME); fi - #touch AndroidManifest.xml - if [ "$(HOST_PLATFORM)" = "windows" ]; then \ - cmd //c $(SDK_ROOT)/tools/android.bat update project --target $(SDK_TARGET) --path .; \ - else \ - $(SDK_ROOT)/tools/android update project --target $(SDK_TARGET) --path .; \ - fi - - #rm -r $(addprefix bin/,$(shell ls bin/ | grep -v ^data$)) - - if [ "$(HOST_PLATFORM)" = "windows" ]; then \ - #$(ANT_BIN)/ant clean; \ - $(ANT_BIN)/ant debug install; \ - else \ - #ant clean; \ - ant debug install; \ - fi - cp bin/OFActivity-debug.apk bin/$(APPNAME).apk - #if [ "$(shell $(SDK_ROOT)/platform-tools/adb get-state)" = "device" ]; then - #$(SDK_ROOT)/platform-tools/adb uninstall $(PKGNAME) - $(SDK_ROOT)/platform-tools/adb install -r bin/$(APPNAME).apk; - #fi - $(SDK_ROOT)/platform-tools/adb shell am start -a android.intent.action.MAIN -n $(PKGNAME)/$(PKGNAME).OFActivity diff --git a/libs/openFrameworksCompiled/project/android/gradle.properties b/libs/openFrameworksCompiled/project/android/gradle.properties new file mode 100644 index 00000000000..85b58d381df --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/gradle.properties @@ -0,0 +1,10 @@ +# Project-wide Gradle settings. +android.useAndroidX=true +android.enableJetifier=false +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +kotlin.code.style=official +android.prefabVersion=2.1.+ +android.enableParallelJsonGen=false +android.buildFeatures.prefab = true +android.nonTransitiveRClass=false +android.nonFinalResIds=false diff --git a/libs/openFrameworksCompiled/project/android/libneondetection.so b/libs/openFrameworksCompiled/project/android/libneondetection.so deleted file mode 100644 index 231da3b2f07..00000000000 Binary files a/libs/openFrameworksCompiled/project/android/libneondetection.so and /dev/null differ diff --git a/libs/openFrameworksCompiled/project/android/ndk-verify.gradle b/libs/openFrameworksCompiled/project/android/ndk-verify.gradle deleted file mode 100644 index f3fc934a4ec..00000000000 --- a/libs/openFrameworksCompiled/project/android/ndk-verify.gradle +++ /dev/null @@ -1,28 +0,0 @@ -println "Verifying NDK version" - -def ndkPath = '' -def propertiesFile = new File(rootDir.absolutePath + "/local.properties") -if(propertiesFile.exists()) { - Properties localProperties = new Properties() - localProperties.load(propertiesFile.newDataInputStream()) - ndkPath = localProperties.getProperty('ndk.dir', null) -} else if (System.env.ANDROID_NDK_HOME != null) { - ndkPath = new File(System.env.ANDROID_NDK_HOME).getAbsolutePath() -} - -if (ndkPath == null || ndkPath.length() == 0) { - throw new GradleException("You havent set the path to the NDK library." + - "Please set the property 'ndk.dir' in "+ new File(rootDir.absolutePath + "/local.properties").getAbsolutePath() + - " to the root of the NDK library, or go to Project Structure and select the folder."+ - "\n\nMake sure to download NDK r15c, as that is the only version supported by openFrameworks") -} - -println "Using NDK from "+ndkPath - -Properties ndkProperties = new Properties() -ndkProperties.load(new File(ndkPath+ "/source.properties").newDataInputStream()) - -if(!ndkProperties.getProperty("Pkg.Revision").startsWith("15.2")) { - throw new GradleException("Wrong version of NDK library found. Found version " + ndkProperties.getProperty("Pkg.Revision") + - ", but openFrameworks requires version r15c") -} diff --git a/addons/ofxAndroid/ofAndroidLib/AndroidManifest.xml b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/AndroidManifest.xml similarity index 61% rename from addons/ofxAndroid/ofAndroidLib/AndroidManifest.xml rename to libs/openFrameworksCompiled/project/android/openframeworksAndroid/AndroidManifest.xml index 383447b6bfe..149bb1eaf7e 100644 --- a/addons/ofxAndroid/ofAndroidLib/AndroidManifest.xml +++ b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/AndroidManifest.xml @@ -1,9 +1,6 @@ + package="cc.openframeworks.android"> - diff --git a/libs/openFrameworksCompiled/project/android/openframeworksAndroid/CMakeLists.txt b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/CMakeLists.txt new file mode 100644 index 00000000000..8f3056a0368 --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/CMakeLists.txt @@ -0,0 +1,156 @@ +# Sets the minimum version of CMake required to build the native +# library. +cmake_minimum_required(VERSION 3.22.1) + +project(openFrameworksAndroid LANGUAGES CXX) +set(CMAKE_C_STANDARD 17) +set(CMAKE_CXX_STANDARD 23) +set(OF_LIBRARY_TYPE "SHARED") # or "STATIC" +set(CMAKE_VERBOSE_MAKEFILE ON) + +set(LOCAL_PATH ${CMAKE_SOURCE_DIR}) +set(PRJ_OF_ROOT ${LOCAL_PATH}/../../../../../) +set(PURE_OF_ROOT ${LOCAL_PATH}/../../../../../) +set(LIBS_ROOT ${PURE_OF_ROOT}/libs) +set(CORE_OF_ROOT ${PURE_OF_ROOT}/libs/openFrameworks) +set(PRJ_ADDONS_PATH ${PURE_OF_ROOT}/addons) +set(PRJ_SOURCE_PATH ${LIBS_ROOT}/openFrameworks) +set(OF_SOURCE_DIR ${PRJ_SOURCE_PATH}) +set(PRJ_LIBS_ROOT ${PURE_OF_ROOT}/libs) +set(OF_ANDROID ${PURE_OF_ROOT}/libs/openFrameworksCompiled/project/android) +set(OF_ANDROID_OUTPUT ${PURE_OF_ROOT}/libs/openFrameworksCompiled/lib/android) +set(PRJ_OFX_ANDROID_PATH ${PRJ_ADDONS_PATH}/ofxAndroid) +set(PRJ_OFX_ANDROID_CPP_PATH ${PRJ_ADDONS_PATH}/ofxAndroid/src) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CONFIGURATION_BUILD_DIR ${OF_ANDROID_OUTPUT}) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ferror-limit=0 -std=c17 -Oz -Wall -fno-short-enums -fPIE -fPIC -fexceptions -ffunction-sections -fdata-sections") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ferror-limit=0 -std=c++23 -Oz -stdlib=libc++ -Wall -fno-short-enums -fPIE -fPIC -fexceptions -ffunction-sections -fdata-sections") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-export-dynamic") +file(GLOB OF_SOURCES + ${OF_SOURCE_DIR}/*.cpp + ${OF_SOURCE_DIR}/3d/*.cpp + ${OF_SOURCE_DIR}/app/*.cpp + ${OF_SOURCE_DIR}/communication/*.cpp + ${OF_SOURCE_DIR}/events/*.cpp + ${OF_SOURCE_DIR}/gl/*.cpp + ${OF_SOURCE_DIR}/graphics/*.cpp + ${OF_SOURCE_DIR}/math/*.cpp + ${OF_SOURCE_DIR}/sound/*.cpp + ${OF_SOURCE_DIR}/types/*.cpp + ${OF_SOURCE_DIR}/utils/*.cpp + ${OF_SOURCE_DIR}/video/*.cpp + ${PRJ_OFX_ANDROID_CPP_PATH}/*.cpp + ${PRJ_ADDONS_PATH}/ofxAddons/src/*.cpp + ${PRJ_ADDONS_PATH}/ofxAccelerometer/src/ofxAccelerometer.cpp +) +# exclusions +list(REMOVE_ITEM OF_SOURCES + "${OF_SOURCE_DIR}/app/ofAppEGLWindow.cpp" + "${OF_SOURCE_DIR}/sound/ofMediaFoundationSoundPlayer.cpp" + "${OF_SOURCE_DIR}/video/ofGstVideoPlayer.cpp" + "${OF_SOURCE_DIR}/video/ofGstVideoGrabber.cpp" + "${OF_SOURCE_DIR}/video/ofMediaFoundationPlayer.cpp" + "${OF_SOURCE_DIR}/video/ofDirectShowPlayer.cpp" + "${OF_SOURCE_DIR}/video/ofDirectShowGrabber.cpp" +) + +add_library(openFrameworksAndroid ${OF_LIBRARY_TYPE} ${OF_SOURCES}) + +target_include_directories(openFrameworksAndroid PRIVATE + ${OF_SOURCE_DIR} + ${OF_SOURCE_DIR}/3d + ${OF_SOURCE_DIR}/app + ${OF_SOURCE_DIR}/communication + ${OF_SOURCE_DIR}/events + ${OF_SOURCE_DIR}/gl + ${OF_SOURCE_DIR}/graphics + ${OF_SOURCE_DIR}/math + ${OF_SOURCE_DIR}/sound + ${OF_SOURCE_DIR}/types + ${OF_SOURCE_DIR}/utils + ${OF_SOURCE_DIR}/video +) + +set_target_properties(openFrameworksAndroid + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY + "${CONFIGURATION_BUILD_DIR}/${ANDROID_ABI}") + +include_directories( + ${PRJ_SOURCE_PATH}/3d + ${PRJ_SOURCE_PATH}/app + ${PRJ_SOURCE_PATH}/communication + ${PRJ_SOURCE_PATH}/events + ${PRJ_SOURCE_PATH}/gl + ${PRJ_SOURCE_PATH}/graphics + ${PRJ_SOURCE_PATH}/math + ${PRJ_SOURCE_PATH}/sound + ${PRJ_SOURCE_PATH}/types + ${PRJ_SOURCE_PATH}/utils + ${PRJ_SOURCE_PATH}/video + ${PRJ_SOURCE_PATH} + ${PRJ_OFX_ANDROID_CPP_PATH}/ + ${PURE_OF_ROOT}/addons/ofxAndroid/src + ${PURE_OF_ROOT}/addons/ofxAccelerometer/src + ${PRJ_LIBS_ROOT}/FreeImage/include + ${PRJ_LIBS_ROOT}/freetype/include + ${PRJ_LIBS_ROOT}/freetype/include/freetype2 + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/config + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal/services + ${PRJ_LIBS_ROOT}/glm/include + ${PRJ_LIBS_ROOT}/brotli/include + ${PRJ_LIBS_ROOT}/json/include + ${PRJ_LIBS_ROOT}/libpng/include + ${PRJ_LIBS_ROOT}/fmt/include + ${PRJ_LIBS_ROOT}/pugixml/include + ${PRJ_LIBS_ROOT}/json/include + ${PRJ_LIBS_ROOT}/tess2/include + ${PRJ_LIBS_ROOT}/utf8/include + ${PRJ_LIBS_ROOT}/tess2/include + ${PRJ_LIBS_ROOT}/zlib/include + ${PRJ_LIBS_ROOT}/uriparser/include + ${PRJ_LIBS_ROOT}/openssl/include + ${PRJ_LIBS_ROOT}/curl/include +) + +find_library(ANDROID_LIB NAMES android) +find_library(LOG_LIB NAMES log) +find_library(GLES1_LIB NAMES GLESv1_CM) +find_library(GLES2_LIB NAMES GLESv2) +find_library(GLES3_LIB NAMES GLESv3) + +target_link_libraries(openFrameworksAndroid + android + log + m + z + dl + ) + +target_link_libraries(openFrameworksAndroid + ${ANDROID_LIB} + ${GLES2_LIB} + ${GLES3_LIB} + ${GLES1_LIB} + ${LOG_LIB} +) + + +target_link_libraries(openFrameworksAndroid + ${PRJ_LIBS_ROOT}/brotli/lib/android/${ANDROID_ABI}/libbrotlicommon.a + ${PRJ_LIBS_ROOT}/brotli/lib/android/${ANDROID_ABI}/libbrotlidec.a + ${PRJ_LIBS_ROOT}/brotli/lib/android/${ANDROID_ABI}/libbrotlienc.a + ${PRJ_LIBS_ROOT}/fmt/lib/android/${ANDROID_ABI}/libfmt.a + ${PRJ_LIBS_ROOT}/zlib/lib/android/${ANDROID_ABI}/zlib.a + ${PRJ_LIBS_ROOT}/libpng/lib/android/${ANDROID_ABI}/libpng.a + ${PRJ_LIBS_ROOT}/FreeImage/lib/android/${ANDROID_ABI}/libFreeImage.a + ${PRJ_LIBS_ROOT}/freetype/lib/android/${ANDROID_ABI}/libfreetype.a + ${PRJ_LIBS_ROOT}/pugixml/lib/android/${ANDROID_ABI}/libpugixml.a + ${PRJ_LIBS_ROOT}/tess2/lib/android/${ANDROID_ABI}/libtess2.a + ${PRJ_LIBS_ROOT}/uriparser/lib/android/${ANDROID_ABI}/liburiparser.a + ${PRJ_LIBS_ROOT}/openssl/lib/android/${ANDROID_ABI}/libssl.a + ${PRJ_LIBS_ROOT}/openssl/lib/android/${ANDROID_ABI}/libcrypto.a + ${PRJ_LIBS_ROOT}/curl/lib/android/${ANDROID_ABI}/libcurl.a +) diff --git a/libs/openFrameworksCompiled/project/android/openframeworksAndroid/build.gradle b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/build.gradle new file mode 100644 index 00000000000..54ad05af352 --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/build.gradle @@ -0,0 +1,91 @@ +plugins { + id 'com.android.library' +} + +def PRJ_SRC_ROOT = './' + +static def ofRoot() { return '../../../../' } +final ofSource = ofRoot() + 'libs/openFrameworks' +final ofLibs = ofRoot() + 'libs' +final addons = ofRoot() + 'addons' +def OFX_ANDROID = ofRoot() + 'addons/ofxAndroid' +final ofLibOutput = ofRoot() + 'libs/openFrameworksCompiled/lib/android' +def LIB_OUTPUT = ofRoot() + './../../../../libs/openFrameworksCompiled/lib/android' +def enableProguardInReleaseBuilds = true +def enableProguardInDebugBuilds = true +tasks.register("prepareKotlinBuildScriptModel"){} + +android { + namespace 'cc.openframeworks.android' + compileSdkVersion 34 + ndkVersion '28.0.13004108' + buildToolsVersion '35.0.0' // Updated from 35.0.1 to 34.0.0 + + defaultConfig { + minSdkVersion 34 + targetSdkVersion 34 + versionCode 12 + versionName "12" + ndk.abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64' + + externalNativeBuild { + cmake { + arguments "-DANDROID_STL=c++_shared", + "-DANDROID_ARM_NEON=TRUE", + "-DANDROID_TOOLCHAIN=clang", + "-DTARGET_OPENGLES=TRUE" + abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64' + } + } + multiDexEnabled false + } + buildTypes { + release { + minifyEnabled true + shrinkResources false + jniDebuggable false + debuggable false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), + 'proguard-rules.pro' + } + debug { + shrinkResources false + jniDebuggable true + debuggable true + } + } + sourceSets { + main { + manifest.srcFile "${PRJ_SRC_ROOT}/AndroidManifest.xml" + java.srcDirs = ["${OFX_ANDROID}/Java"] + } + } + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + prefab { + openFrameworksAndroid { + headers "src/main/cpp/include" + } + } + packagingOptions { + exclude("**/libopenFrameworksAndroid.so") + } + viewBinding { + enabled true + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'androidx.constraintlayout:constraintlayout:2.2.1' + implementation "com.getkeepsafe.relinker:relinker:1.4.4" + implementation "com.android.ndk.thirdparty:curl:7.68.0-alpha-1" +} diff --git a/libs/openFrameworksCompiled/project/android/openframeworksAndroid/common-functions.gradle b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/common-functions.gradle new file mode 100755 index 00000000000..6740e5b9990 --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/common-functions.gradle @@ -0,0 +1,434 @@ +// +////def getFilesRecursive(path){ +//// FileTree tree = fileTree(dir: path) +//// def files = tree.matching({includes ["*.cpp"]}).toList() +//// return files +////} +// +//def getFoldersRecursive(String path){ +// def file = new File(path) +// def ret = [path] +// if(!file.exists()) return [] +// +// file.eachDirRecurse() { dir -> +// ret.add(dir.getAbsolutePath()) +// } +// return ret +// +//} +// +// +// +//def addonPaths(ofRoot){ +// def file = new File('addons.make') +// if(!file.exists()) { +// return [] +// } +// +// def addonRoot = ofRoot+"addons/" +// +// def ret = [] +// file.eachLine { line -> +// def folder = new File(addonRoot+line) +// if (!folder.exists()) { +// //throw new GradleException("Addon ${line} could not be found at ${folder.absolutePath}") +// } +// ret += folder.absolutePath +// } +// +// return ret +//} +// +// +// +//def parseAddonConfig(String addon, String param, String abi, defaultVal = []){ +// def ret = defaultVal +// +// def file = new File(addon+"/addon_config.mk") +// if(!file.exists()){ +// println addon+"/addon_config.mk not found" +// return defaultVal +// } +// +// def mode = "" +// +// file.eachLine { line -> +// def stripLine = line.replaceAll("^\\s*","").replaceAll("\\s*\$","") +// if(stripLine.startsWith("#") || stripLine.length() == 0){ +// return +// } +// +// if(stripLine.endsWith(":")){ +// mode = stripLine.replaceAll(":\$","") +// } +// +// if(mode == "common" || mode == "android" || mode == "android/${abi}".toString()){ +// def group = (stripLine =~ /^(\w+)\s*(\+?=)\s*(.+)$/) +// if(group.hasGroup() && group.size() == 1 && group[0].size() == 4){ +// if(group[0][1] == param) { +// def _p = group[0][3].replaceAll("%", "*") +// if (group[0][2] == '=') { +// ret = [_p] +// } else { +// ret += _p +// } +// } +// } +// +// } +// } +// +// return ret +//} +// +//def addonSources(String root, String abi=""){ +// +// def ret = [] +// addonPaths(root).each { String addon -> +// def config = parseAddonConfig( +// addon, +// "ADDON_SOURCES", +// abi, +// ["src", "libs"] +// ) +// +// //ret += addon +// config.each { String path -> +// ret += addon+'/'+path +// } +// } +// println "\n\n ADDON_SOURCES "+ret+"\n\n" +// +// return ret +//} +// +//def addonIncludes(String root, String abi=""){ +// def ret = [] +// return ret +//} +// +//def addonSourcesExclude(String root, String abi=""){ +// def ret = [] +// addonPaths(root).each { String addon -> +// def config = parseAddonConfig( +// addon, +// "ADDON_SOURCES_EXCLUDE", +// abi +// ) +// +// config.each { String path -> +// // TODO: Currently first part of path is stripped. Doesn't work otherwise +// ret += path.replaceAll(/^\w+\//,"**/") +// } +// } +// +//// ret += "**/dlib/include/*" +// println "\n EXCLUDE "+ret+"\n\n" +// return ret +//} +// +// +//def addonLdFlags(abi, ofRoot){ +// def ret = [] +// addonPaths(ofRoot).each { String addon -> +// def libs = []; +// fileTree(dir: addon + "/libs", include: "**/lib/android/" + abi + "/*.a") +// .each{ lib -> libs += lib.getAbsolutePath(); }; +// +// def config = parseAddonConfig( +// addon, +// "ADDON_LIBS", +// abi, +// libs +// ) +// +// config.each { String path -> +// def f = new File(addon+"/"+path) +// if(f.exists()) { +// ret += f.toString(); +// } +// } +// } +// println "\n ADDON_LIBS "+ret+"\n\n" +// return ret +//} +// +// +// +//def addonCppFlags(abi, ofRoot){ +// def ret = [] +// addonPaths(ofRoot).each { addon -> +// def config = parseAddonConfig( +// addon, +// "ADDON_INCLUDES", +// abi, +// ["libs","src"] +// ) +// def excludeConfig = parseAddonConfig( +// addon, +// "ADDON_INCLUDES_EXCLUDE", +// abi +// ) +// +// config.each { String path -> +// def flags = [] +// getFoldersRecursive(addon+"/"+path).each{ String folder -> +// def excluded = false +// excludeConfig.each { ex -> +// def _ex = ex.replaceAll(/\*/,".+") +// if(folder ==~ /.*$addon\/$_ex/ ) { +// excluded = true +// } +// } +// +// if(!excluded) { +// flags += "-I${folder}".toString() +// } +// } +// +// ret += flags +// } +// +// +// def configFlags = parseAddonConfig(addon, "ADDON_CFLAGS", abi); +// configFlags.each { String flag -> +// ret += flag +// } +// +// /* +// ret += getFoldersRecursive(addon + "/libs").collect{ folder -> +// return "-I${folder}".toString() +// } +// ret += getFoldersRecursive(addon + "/src").collect{ folder -> +// return "-I${folder}".toString() +// }*/ +// } +// println "\n ADDON_CFLAGS "+ret+"\n\n" +// return ret +//} +// +//def addonData(ofRoot){ +// def ret = [] +// addonPaths(ofRoot).each { addon -> +// def configFlags = parseAddonConfig(addon, "ADDON_DATA", ""); +// configFlags.each { String path -> +// ret += addon + "/" + path +// } +// } +// return ret +//} +// +//def addonJavaDependencies(root,abi=""){ +// def ret = [] +// addonPaths(root).each { String addon -> +// def config = parseAddonConfig( +// addon, +// "ADDON_ANDROID_LIBS", +// abi +// ) +// +// config.each { String path -> +// def f = new File(addon+"/"+path) +// if(f.exists()) { +// ret += [[f.toString(), ':'+new File(addon).name]] +// } +// } +// } +// println "\n JAVA_LIBS "+ret+"\n\n" +// return ret +//} +// +//def javaDependencies(ofRoot){ +// def ret = [] +// ret += [[ofRoot+'addons/ofxAndroid/ofAndroidLib', ':ofAndroidLib']] +// ret += [[ofRoot+'libs/openFrameworksCompiled/project/android', ':openFrameworksProject']] +// return ret +//} +// +// +//def getFlavorName(abi) { +// switch (abi) { +// case "armeabi": +// return "armeabi"; +// case "armeabi-v7a": +// return "arm7" +// case "arm64-v8a": +// return "arm64" +// default: +// return abi.replaceAll('-', '_') +// } +//} +// +//def getAbis(){ +// return ["arm64-v8a", "armeabi-v7a", "x86", "x86-64"] +//} +// +//def ofAppModuleName(){ +// return "OFAndroidApp" +//} +// +//def buildToolchain(){ +// return "clang" +//} +// +//def appSrcDirs(ofRoot){ +// def ret = ['src', +// ofRoot+"/addons/ofxAndroid/ofxAndroidLib/src/main/cpp", +// ofRoot+"/addons/ofxAccelerometer/src" +// ] +// +// ret += addonSources(ofRoot) +// +// return ret +//} +// +//def srcExcludes(ofRoot){ +// return addonSourcesExclude(ofRoot) +//} +// +//def srcIncludes(ofRoot){ +// return [] +//} +// +// +//def coreCppFlags(abi, ofRoot){ +// def ofSource = ofRoot + 'libs/openFrameworks' +// def libs = ofRoot + 'libs' +// +// def ret = ["-std=c++17", +// "-Wall", +// "-frtti", +// "-fexceptions", +// "-nostdlib ", +// "-fno-short-enums", +// "-ffunction-sections", +// "-fdata-sections", +// "-I${file(ofSource)}".toString(), +// "-I${file(ofSource+"/3d")}".toString(), +// "-I${file(ofSource+"/app")}".toString(), +// "-I${file(ofSource+"/communication")}".toString(), +// "-I${file(ofSource+"/events")}".toString(), +// "-I${file(ofSource+"/gl")}".toString(), +// "-I${file(ofSource+"/graphics")}".toString(), +// "-I${file(ofSource+"/math")}".toString(), +// "-I${file(ofSource+"/output")}".toString(), +// "-I${file(ofSource+"/sound")}".toString(), +// "-I${file(ofSource+"/types")}".toString(), +// "-I${file(ofSource+"/utils")}".toString(), +// "-I${file(ofSource+"/video")}".toString(), +// "-I${file(ofRoot+"/addons/ofxAndroid/src")}".toString(), +// "-I${file(ofRoot+"/addons/ofxAccelerometer/src")}".toString(), +// "-I${file(libs+"/FreeImage/include")}".toString(), +//// "-I${file(libs+"/boost/include")}".toString(), +//// "-I${file(libs+"/boost/include/boost")}".toString(), +//// "-I${file(libs+"/cairo/include")}".toString(), +//// "-I${file(libs+"/cairo/include/cairo")}".toString(), +// "-I${file(libs+"/freetype/include")}".toString(), +// "-I${file(libs+"/freetype/include/freetype2")}".toString(), +// "-I${file(libs+"/freetype/include/freetype2/config")}".toString(), +// "-I${file(libs+"/freetype/include/freetype2/internal")}".toString(), +// "-I${file(libs+"/freetype/include/freetype2/internal/services")}".toString(), +//// "-I${file(libs+"/glfw/include")}".toString(), +//// "-I${file(libs+"/glfw/include/GLFW")}".toString(), +//// "-I${file(libs+"/openssl/include")}".toString(), +//// "-I${file(libs+"/openssl/include/openssl")}".toString(), +//// "-I${file(libs+"/poco/include")}".toString(), +// "-I${file(libs+"/tess2/include")}".toString(), +// "-I${file(libs+"/utf8cpp/include")}".toString(), +// "-I${file(libs+"/json/include")}".toString(), +// "-I${file(libs+'/kiss/include')}".toString(), +// "-I${file(libs+'/glm/include')}".toString(), +// "-I${file(libs+'/utf8/include')}".toString(), +// "-I${file(libs+'/uriparser/include')}".toString(), +//// "-I${file(libs+'/curl/include')}".toString(), +// "-I${file(libs+'/pugixml/include')}".toString() +//// "-I${file(libs+'/libxml2/include')}".toString(), +//// "-I${file(libs+'/libs/glu/include_android')}".toString() +// +// ] +// +// println "\n CPP_FLAGS "+ret+"\n\n" +// +// return ret; +//} +// +//def addonLdLibs(abi, ofRoot){ +// return [] +//} +// +//def addonLdCompilerFlags(abi, ofRoot){ +// return [] +//} +// +//def coreLdLibs(abi, ofRoot){ +// return ["atomic","android", "OpenSLES", "z", "GLESv1_CM", "GLESv2", "log"] +//} +// +// +// +//def getPrebuiltLibPaths(abi, ofRoot) { +// def libs = ofRoot + 'libs' +// +// def paths = [] +// paths += file(libs+"/FreeImage/lib/android/${abi}/libfreeimage.a").toString() +//// paths += file(libs+"/boost/lib/android/${abi}/libboost_filesystem.a").toString() +//// paths += file(libs+"/boost/lib/android/${abi}/libboost_system.a").toString() +// paths += file(libs+"/freetype/lib/android/${abi}/libfreetype.a").toString() +// paths += file(libs+"/tess2/lib/android/${abi}/libtess2.a").toString() +//// paths += file(libs+"/curl/lib/android/${abi}/libcurl.a").toString() +//// paths += file(libs+"/openssl/lib/android/${abi}/libssl.a").toString() +//// paths += file(libs+"/openssl/lib/android/${abi}/libcrypto.a").toString() +// paths += file(libs+"/pugixml/lib/android/${abi}/libpugixml.a").toString() +// paths += file(libs+"/uriparser/lib/android/${abi}").toString() +// return paths +//} +// +// +//def coreLdFlags(abi, ofRoot){ +// def ret = [ +// '-Wl,--exclude-libs,ALL', +// '-Wl,--as-needed', +// '-Wl,--gc-sections' +// ] +// +// def prebuilt = getPrebuiltLibPaths(abi, ofRoot) +// ret.addAll(prebuilt) +// +// return ret +//} +// +// +//def compilerStl(){ +// return "c++_static" +//} +// +// +//// Export the functions +//ext { +// ofAppModuleName = this.&ofAppModuleName +// +// getFlavorName = this.&getFlavorName +// buildToolchain= this.&buildToolchain +// getAbis = this.&getAbis +// compilerStl= this.&compilerStl +// +// appSrcDirs = this.&appSrcDirs +// srcExcludes = this.&srcExcludes +// srcIncludes = this.&srcIncludes +// +// coreCppFlags = this.&coreCppFlags +// addonCppFlags = this.&addonCppFlags +// +// coreLdLibs= this.&coreLdLibs +// addonLdLibs= this.&addonLdLibs +// +// coreLdFlags = this.&coreLdFlags +// addonLdFlags = this.&addonLdFlags +// +// addonData = this.&addonData +// +// addonJavaDependencies = this.&addonJavaDependencies +// javaDependencies = this.&javaDependencies +// +// +//} diff --git a/libs/openFrameworksCompiled/project/android/openframeworksAndroid/gradle.properties b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/gradle.properties new file mode 100644 index 00000000000..3b5ff074c6e --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/gradle.properties @@ -0,0 +1,12 @@ +android.useAndroidX=true +android.enableJetifier=false +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +kotlin.code.style=official +android.prefabVersion=2.1.+ +# Workaround bug in AGP where the prefab dependency is being resolved from a +# non-Gradle thread when enableParallelJsonGen is enabled. +# https://issuetracker.google.com/149575364 +android.enableParallelJsonGen=false +android.buildFeatures.prefab = true +android.nonTransitiveRClass=false +android.nonFinalResIds=false diff --git a/libs/openFrameworksCompiled/project/android/openframeworksAndroid/ndk-verify.gradle b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/ndk-verify.gradle new file mode 100644 index 00000000000..fe8040bca80 --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/ndk-verify.gradle @@ -0,0 +1,28 @@ +//println "Verifying NDK version" +// +//def ndkPath = '' +//def propertiesFile = new File(rootDir.absolutePath + "/local.properties") +//if(propertiesFile.exists()) { +// Properties localProperties = new Properties() +// localProperties.load(propertiesFile.newDataInputStream()) +// ndkPath = localProperties.getProperty('ndk.dir', null) +//} else if (System.env.ANDROID_NDK_HOME != null) { +// ndkPath = new File(System.env.ANDROID_NDK_HOME).getAbsolutePath() +//} +// +//if (ndkPath == null || ndkPath.length() == 0) { +// throw new GradleException("You havent set the path to the NDK library." + +// "Please set the property 'ndk.dir' in "+ new File(rootDir.absolutePath + "/local.properties").getAbsolutePath() + +// " to the root of the NDK library, or go to Project Structure and select the folder."+ +// "\n\nMake sure to download NDK r15c, as that is the only version supported by openFrameworks") +//} +// +//println "Using NDK from "+ndkPath +// +//Properties ndkProperties = new Properties() +//ndkProperties.load(new File(ndkPath+ "/source.properties").newDataInputStream()) +// +//if(!ndkProperties.getProperty("Pkg.Revision").startsWith("15.2")) { +// throw new GradleException("Wrong version of NDK library found. Found version " + ndkProperties.getProperty("Pkg.Revision") + +// ", but openFrameworks requires version r15c") +//} diff --git a/libs/openFrameworksCompiled/project/android/openframeworksAndroid/proguard-rules.pro b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/proguard-rules.pro new file mode 100644 index 00000000000..a0adad201ac --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/proguard-rules.pro @@ -0,0 +1,126 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +-dontoptimize +-dontshrink +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +# +#-optimizationpasses 5 +#-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +#-verbose + +-dontobfuscate + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference + +-keep public class cc.openframeworks.android.OFActivity { public ; } +-keep public class cc.openframeworks.OFAndroid { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycleHelper { public ; } +-keep public class cc.openframeworks.OFAndroidWindow { public ; } +-keep public class cc.openframeworks.OFAndroidSoundPlayer { public ; } +-keep public class cc.openframeworks.OFGLSurfaceView { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycle { public ; } +-keep public class cc.openframeworks.OFActivity { public ; } +-keep public class cc.openframeworks.ContextFactory { public ; } +-keep public class cc.openframeworks.OFEGLConfigChooser { public ; } +-keep public class cc.openframeworks.OFGestureListener { public ; } + +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } +#-keep class com.google.android.gms.common.api.ResultCallback { *; } +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +#-keep class com.google.android.gms.common.ConnectionResult { *; } +#-keep class com.google.android.gms.common.GooglePlayServicesUtil { *; } +-keep class com.google.android.gms.common.api.** { *; } +#-keep class com.google.android.gms.common.data.DataBufferUtils { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } + + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +# note that means any method +-keepclasseswithmembernames,includedescriptorclasses class * { + native ; +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/addons/ofxAndroid/ofAndroidLib/project.properties b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/project.properties similarity index 95% rename from addons/ofxAndroid/ofAndroidLib/project.properties rename to libs/openFrameworksCompiled/project/android/openframeworksAndroid/project.properties index c57400d008a..2d77c9e6eb5 100644 --- a/addons/ofxAndroid/ofAndroidLib/project.properties +++ b/libs/openFrameworksCompiled/project/android/openframeworksAndroid/project.properties @@ -9,4 +9,4 @@ android.library=true # Project target. -target=android-19 +target=android-34 diff --git a/libs/openFrameworksCompiled/project/android/proguard-rules.pro b/libs/openFrameworksCompiled/project/android/proguard-rules.pro new file mode 100644 index 00000000000..e5734ccb74b --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/proguard-rules.pro @@ -0,0 +1,115 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +-dontoptimize +-dontshrink +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +# +#-optimizationpasses 5 +#-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +#-verbose + +-dontobfuscate + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference + + +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } +#-keep class com.google.android.gms.common.api.ResultCallback { *; } +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +#-keep class com.google.android.gms.common.ConnectionResult { *; } +#-keep class com.google.android.gms.common.GooglePlayServicesUtil { *; } +-keep class com.google.android.gms.common.api.** { *; } +#-keep class com.google.android.gms.common.data.DataBufferUtils { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } + + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +# note that means any method +-keepclasseswithmembernames,includedescriptorclasses class * { + native ; +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/libs/openFrameworksCompiled/project/android/settings.gradle b/libs/openFrameworksCompiled/project/android/settings.gradle new file mode 100644 index 00000000000..78ca4bc8465 --- /dev/null +++ b/libs/openFrameworksCompiled/project/android/settings.gradle @@ -0,0 +1,2 @@ +include ':openframeworksAndroid' +project(':openframeworksAndroid').projectDir = file('openframeworksAndroid') diff --git a/libs/openFrameworksCompiled/project/android/windows/bzip2.dll b/libs/openFrameworksCompiled/project/android/windows/bzip2.dll deleted file mode 100755 index 174fd06c2cf..00000000000 Binary files a/libs/openFrameworksCompiled/project/android/windows/bzip2.dll and /dev/null differ diff --git a/libs/openFrameworksCompiled/project/android/windows/zip.exe b/libs/openFrameworksCompiled/project/android/windows/zip.exe deleted file mode 100755 index 3165202596c..00000000000 Binary files a/libs/openFrameworksCompiled/project/android/windows/zip.exe and /dev/null differ diff --git a/libs/openFrameworksCompiled/project/android/windows/zip32z64.dll b/libs/openFrameworksCompiled/project/android/windows/zip32z64.dll deleted file mode 100755 index 0f8ce8226b7..00000000000 Binary files a/libs/openFrameworksCompiled/project/android/windows/zip32z64.dll and /dev/null differ diff --git a/scripts/android/create_hierarchy_emptyExample.sh b/scripts/android/create_hierarchy_emptyExample.sh new file mode 100755 index 00000000000..dbb545b1000 --- /dev/null +++ b/scripts/android/create_hierarchy_emptyExample.sh @@ -0,0 +1,66 @@ + +DEST_DIR="apps/android/newApp/" + +SRC_DIR="examples/android/androidEmptyExample" + +rm -r $DEST_DIR + +mkdir -p $DEST_DIR/{gradle/wrapper,ofApp/{gradle/wrapper,src/main/{cpp,bin/data,java/cc/openframeworks/android,res/{drawable-hdpi,drawable-mdpi,drawable-xhdpi,drawable,layout,menu,mipmap-anydpi-v26,mipmap-hdpi,mipmap-mdpi,mipmap-xhdpi,mipmap-xxhdpi,mipmap-xxxhdpi,values-v11,values-v14,values}}}} + +tree $DEST_DIR + + +cp $SRC_DIR/addons.make $DEST_DIR +cp $SRC_DIR/build.gradle $DEST_DIR +cp $SRC_DIR/gradle.properties $DEST_DIR +cp $SRC_DIR/proguard.cfg $DEST_DIR +cp $SRC_DIR/settings.gradle $DEST_DIR +cp $SRC_DIR/gradlew $DEST_DIR +cp $SRC_DIR/gradlew.bat $DEST_DIR + +cp $SRC_DIR/gradle/wrapper/gradle-wrapper.jar $DEST_DIR/gradle/wrapper +cp $SRC_DIR/gradle/wrapper/gradle-wrapper.properties $DEST_DIR/gradle/wrapper + +cp $SRC_DIR/ofApp/build.gradle $DEST_DIR/ofApp +cp $SRC_DIR/ofApp/gradle.properties $DEST_DIR/ofApp +cp $SRC_DIR/ofApp/proguard-rules.pro $DEST_DIR/ofApp +cp $SRC_DIR/ofApp/gradlew $DEST_DIR/ofApp +cp $SRC_DIR/ofApp/gradlew.bat $DEST_DIR/ofApp + +cp $SRC_DIR/ofApp/gradle/wrapper/* $DEST_DIR/ofApp/gradle/wrapper + +cp $SRC_DIR/ofApp/src/main/AndroidManifest.xml $DEST_DIR/ofApp/src/main +cp $SRC_DIR/ofApp/src/main/ic_launcher-playstore.png $DEST_DIR/ofApp/src/main + +cp $SRC_DIR/ofApp/src/main/cpp/CMakeLists.txt $DEST_DIR/ofApp/src/main/cpp +cp $SRC_DIR/ofApp/src/main/cpp/main.cpp $DEST_DIR/ofApp/src/main/cpp +cp $SRC_DIR/ofApp/src/main/cpp/ofApp.cpp $DEST_DIR/ofApp/src/main/cpp +cp $SRC_DIR/ofApp/src/main/cpp/ofApp.h $DEST_DIR/ofApp/src/main/cpp + +cp $SRC_DIR/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java $DEST_DIR/ofApp/src/main/java/cc/openframeworks/android + +cp $SRC_DIR/ofApp/src/main/res/drawable-hdpi/icon.png $DEST_DIR/ofApp/src/main/res/drawable-hdpi +cp $SRC_DIR/ofApp/src/main/res/drawable-mdpi/icon.png $DEST_DIR/ofApp/src/main/res/drawable-mdpi +cp $SRC_DIR/ofApp/src/main/res/drawable-xhdpi/icon.png $DEST_DIR/ofApp/src/main/res/drawable-xhdpi + +cp $SRC_DIR/ofApp/src/main/res/drawable/icon.png $DEST_DIR/ofApp/src/main/res/drawable + +cp $SRC_DIR/ofApp/src/main/res/layout/main_layout.xml $DEST_DIR/ofApp/src/main/res/layout + +cp $SRC_DIR/ofApp/src/main/res/menu/main_layout.xml $DEST_DIR/ofApp/src/main/res/menu + +cp $SRC_DIR/ofApp/src/main/res/mipmap-anydpi-v26/* $DEST_DIR/ofApp/src/main/res/mipmap-anydpi-v26 + +cp $SRC_DIR/ofApp/src/main/res/mipmap-hdpi/* $DEST_DIR/ofApp/src/main/res/mipmap-hdpi +cp $SRC_DIR/ofApp/src/main/res/mipmap-mdpi/* $DEST_DIR/ofApp/src/main/res/mipmap-mdpi +cp $SRC_DIR/ofApp/src/main/res/mipmap-xhdpi/* $DEST_DIR/ofApp/src/main/res/mipmap-xhdpi +cp $SRC_DIR/ofApp/src/main/res/mipmap-xxhdpi/* $DEST_DIR/ofApp/src/main/res/mipmap-xxhdpi +cp $SRC_DIR/ofApp/src/main/res/mipmap-xxxhdpi/* $DEST_DIR/ofApp/src/main/res/mipmap-xxxhdpi + +cp $SRC_DIR/ofApp/src/main/res/values-v11/* $DEST_DIR/ofApp/src/main/res/values-v11 +cp $SRC_DIR/ofApp/src/main/res/values-v14/* $DEST_DIR/ofApp/src/main/res/values-v14 +cp $SRC_DIR/ofApp/src/main/res/values/* $DEST_DIR/ofApp/src/main/res/values + + +tree $DEST_DIR + diff --git a/scripts/ci/android/NDK_excludes.txt b/scripts/ci/android/NDK_excludes.txt index b263d8e8a89..5140904dea5 100644 --- a/scripts/ci/android/NDK_excludes.txt +++ b/scripts/ci/android/NDK_excludes.txt @@ -14,7 +14,10 @@ android-15 android-16 android-17 android-18 +android-19 +android-20 android-21 +android-22 *mips* *4.8* *4.6* diff --git a/scripts/ci/android/install.sh b/scripts/ci/android/install.sh index d4af8425166..cb4ea0503b8 100755 --- a/scripts/ci/android/install.sh +++ b/scripts/ci/android/install.sh @@ -34,9 +34,9 @@ if [ "$(ls -A ${NDK_DIR})" ]; then ls -A ${NDK_DIR} else echo "Downloading NDK" - downloader -q "https://dl.google.com/android/repository/$NDK_DIR-linux-x86_64.zip" + downloader -q "https://dl.google.com/android/repository/$NDK_DIR-linux.zip" echo "Uncompressing NDK" - unzip "$NDK_DIR-linux-x86_64.zip" > /dev/null 2>&1 + unzip "$NDK_DIR-linux.zip" > /dev/null 2>&1 fi # Build project generator diff --git a/scripts/templates/android/.gitignore b/scripts/templates/android/.gitignore index 06f74e3313a..52568b1a62e 100644 --- a/scripts/templates/android/.gitignore +++ b/scripts/templates/android/.gitignore @@ -1,9 +1,15 @@ ### Android ### +# Edit at https://www.toptal.com/developers/gitignore?templates=androidstudio + +### AndroidStudio ### +# Covers files to be ignored for android development using Android Studio. + # Built application files *.apk *.ap_ +*.aab -# Files for the Dalvik VM +# Files for the ART/Dalvik VM *.dex # Java class files @@ -12,11 +18,16 @@ # Generated files bin/ gen/ +out/ # Gradle files +.gradle .gradle/ build/ +# Signing files +.signing/ + # Local configuration file (sdk path, etc) local.properties @@ -26,8 +37,128 @@ proguard/ # Log Files *.log -# Android Studio Navigation editor temp files +# Android Studio +/*/build/ +/*/local.properties +/*/out +/*/*/build +/*/*/production +captures/ .navigation/ +*.ipr +*~ +*.swp +.cxx/ + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Android Patch +gen-external-apklibs + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# NDK +obj/ + +# IntelliJ IDEA +*.iml +*.iws +/out/ + +# User-specific configurations +.idea/caches/ +.idea/libraries/ +.idea/shelf/ +.idea/workspace.xml +.idea/tasks.xml +.idea/.name +.idea/compiler.xml +.idea/copyright/profiles_settings.xml +.idea/encodings.xml +.idea/misc.xml +.idea/modules.xml +.idea/scopes/scope_settings.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml +.idea/datasources.xml +.idea/dataSources.ids +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml +.idea/assetWizardSettings.xml +.idea/gradle.xml +.idea/jarRepositories.xml +.idea/navEditor.xml + +# OS-specific files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Legacy Eclipse project files +.classpath +.project +.cproject +.settings/ + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.war +*.ear + +# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) +hs_err_pid* + +## Plugin-specific files: + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Mongo Explorer plugin +.idea/mongoSettings.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### AndroidStudio Patch ### + +!/gradle/wrapper/gradle-wrapper.jar + +# End of androidstudio + +### Gradle Patch ### +**/build/ + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ ### Android Patch ### gen-external-apklibs diff --git a/scripts/templates/android/AndroidManifest.xml b/scripts/templates/android/AndroidManifest.xml deleted file mode 100644 index e48c4d9338e..00000000000 --- a/scripts/templates/android/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/scripts/templates/android/addons.make b/scripts/templates/android/addons.make new file mode 100644 index 00000000000..e69de29bb2d diff --git a/scripts/templates/android/build.gradle b/scripts/templates/android/build.gradle index bfa5ede4133..7cbc7eb6714 100644 --- a/scripts/templates/android/build.gradle +++ b/scripts/templates/android/build.gradle @@ -1,140 +1,22 @@ -def ofRoot(){ return '../../../' } - -// Load common functions -apply from: ofRoot()+"libs/openFrameworksCompiled/project/android/common-functions.gradle" - +ext { + //var = 'signExample.keystore' +}// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - apply from: "../../../libs/openFrameworksCompiled/project/android/ndk-verify.gradle" - repositories { - jcenter() + google() + mavenCentral() } dependencies { - // Using the gradle-experimental version that supports c++ - classpath 'com.android.tools.build:gradle-experimental:0.9.3' + classpath 'com.android.tools.build:gradle:7.4.2' } } allprojects { repositories { - jcenter() - maven{ url "https://maven.google.com" } - } -} - -apply plugin: 'com.android.model.application' - -model { - android { - // openFrameworks currently only supports compiling against SDK 19 or nweer - compileSdkVersion = 25 - buildToolsVersion = "25.0.3" - - defaultConfig.with { - minSdkVersion.apiLevel = 19 - targetSdkVersion.apiLevel = 25 - versionCode = 1 - versionName = "1.0" - } - } - - android.ndk { - moduleName = ofAppModuleName() - toolchain = buildToolchain() - stl = compilerStl() - platformVersion = "21" - } - - android.sources { - main { - jni { - source { - srcDirs= appSrcDirs(ofRoot()) - - includes = srcIncludes(ofRoot()) - excludes = srcExcludes(ofRoot()) - } - - // Link to openFrameworks - dependencies { - project ":openFrameworksProject" linkage "static" - } - } - - manifest { - source { - srcDirs = [ "." ] - } - } - res { - source { - srcDirs = [ "res" ] - } - } - java { - source { - srcDirs = [ "srcJava" ] - } - } - aidl { - source{ - srcDirs = ['srcJava'] - } - } - renderscript{ - source{ - srcDirs = ['srcJava'] - } - } - jniLibs { - source { - srcDirs = ['libs'] - } - } - assets { - source { - srcDirs = ['bin/data'] + addonData(ofRoot()) - } - } - } - } - - android.lintOptions { - abortOnError = false + google() + mavenCentral() } + ext { - android.buildTypes { - release { - minifyEnabled = false - } - } - - // Setup the different types of flavors (arm / x86), - // and add linker flags based on that - android.productFlavors { - getAbis().each { abi -> - create(getFlavorName(abi)) { - ndk { - abiFilters.add(abi) - - cppFlags.addAll(coreCppFlags(abi, ofRoot())) - cppFlags.addAll(addonCppFlags(abi, ofRoot())) - - ldLibs.addAll(coreLdLibs(abi, ofRoot())) - ldLibs.addAll(addonLdLibs(abi, ofRoot())) - - ldFlags.addAll(coreLdFlags(abi, ofRoot())) - ldFlags.addAll(addonLdFlags(abi, ofRoot())) - } - } - } - } -} - - -dependencies { - addonJavaDependencies(ofRoot()).each { dep -> - compile(project(path: dep[1] )) } - compile project(path: ':ofAndroidLib') } diff --git a/scripts/templates/android/gradle.properties b/scripts/templates/android/gradle.properties new file mode 100644 index 00000000000..43f9ef9e1c3 --- /dev/null +++ b/scripts/templates/android/gradle.properties @@ -0,0 +1,10 @@ +android.useAndroidX=true +android.enableJetifier=false +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +kotlin.code.style=official +android.prefabVersion=1.0.+ +android.buildFeatures.prefab=true +#ndkBuild=false +# https://issuetracker.google.com/149575364 +android.enableParallelJsonGen=false +#googleplay=true \ No newline at end of file diff --git a/scripts/templates/android/gradle/wrapper/gradle-wrapper.properties b/scripts/templates/android/gradle/wrapper/gradle-wrapper.properties index 8bd5f647616..2dd5ee8c795 100644 --- a/scripts/templates/android/gradle/wrapper/gradle-wrapper.properties +++ b/scripts/templates/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Feb 25 11:47:01 EST 2018 +#Mon Jun 12 01:17:57 AEST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/scripts/templates/android/ofApp/.gitignore b/scripts/templates/android/ofApp/.gitignore new file mode 100644 index 00000000000..4710c9e41ee --- /dev/null +++ b/scripts/templates/android/ofApp/.gitignore @@ -0,0 +1,167 @@ +### Android ### +# Edit at https://www.toptal.com/developers/gitignore?templates=androidstudio + +### AndroidStudio ### +# Covers files to be ignored for android development using Android Studio. + +# Built application files +*.apk +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +.cxx/ + +# Gradle files +.gradle +.gradle/ +build/ + +# Signing files +.signing/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio +/*/build/ +/*/local.properties +/*/out +/*/*/build +/*/*/production +captures/ +.navigation/ +*.ipr +*~ +*.swp + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Android Patch +gen-external-apklibs + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# NDK +obj/ + +# IntelliJ IDEA +*.iml +*.iws +/out/ + +# User-specific configurations +.idea/caches/ +.idea/libraries/ +.idea/shelf/ +.idea/workspace.xml +.idea/tasks.xml +.idea/.name +.idea/compiler.xml +.idea/copyright/profiles_settings.xml +.idea/encodings.xml +.idea/misc.xml +.idea/modules.xml +.idea/scopes/scope_settings.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml +.idea/datasources.xml +.idea/dataSources.ids +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml +.idea/assetWizardSettings.xml +.idea/gradle.xml +.idea/jarRepositories.xml +.idea/navEditor.xml + +# OS-specific files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Legacy Eclipse project files +.classpath +.project +.cproject +.settings/ + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.war +*.ear + +# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) +hs_err_pid* + +## Plugin-specific files: + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Mongo Explorer plugin +.idea/mongoSettings.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### AndroidStudio Patch ### + +!/gradle/wrapper/gradle-wrapper.jar + +# End of androidstudio + +### Gradle Patch ### +**/build/ + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +### Android Patch ### +gen-external-apklibs +reports +obj +assets diff --git a/scripts/templates/android/ofApp/AndroidManifest.xml b/scripts/templates/android/ofApp/AndroidManifest.xml new file mode 100644 index 00000000000..800cefe8ae5 --- /dev/null +++ b/scripts/templates/android/ofApp/AndroidManifest.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scripts/templates/android/ofApp/build.gradle b/scripts/templates/android/ofApp/build.gradle new file mode 100644 index 00000000000..7343b15e761 --- /dev/null +++ b/scripts/templates/android/ofApp/build.gradle @@ -0,0 +1,176 @@ +plugins { + id 'com.android.application' +} + +def CMAKELIST_PATH = './src/main/cpp' +def CPP_SOURCE = './src/main/cpp' +def JAVA_SOURCE = './src/main/java' + +// pointing to cmake's source code for the same project +def PRJ_SRC_ROOT = './src/main' +def ofRoot(){ return '../../../' } +final ofSource = ofRoot() + 'libs/openFrameworks' +final ofLibs = ofRoot() + 'libs' +final addons = ofRoot() + 'addons' +final ofLibOutput = ofRoot() + 'libs/openFrameworksCompiled/lib/android' +def OFX_ANDROID = ofRoot() + 'addons/ofxAndroid' +//def OF_ADDONS_ARGUMENTS = "${OF_ADDONS}" +def enableProguardInReleaseBuilds = true +def enableProguardInDebugBuilds = false + +task wrapper(type: Wrapper) { + gradleVersion = '7.3.3' +} +tasks.register("prepareKotlinBuildScriptModel"){ +} + +evaluationDependsOn(':openFrameworksProject') + +tasks.whenTaskAdded { task -> + if (task.name == 'assemble') { + task.dependsOn(':openFrameworksProject:assemble') + } +} + + +android { + compileSdkVersion 34 + buildToolsVersion '32.0.0' + //ndkPath "/Users/x/android-ndk-r21e" // Point to your own NDK if needed + ndkVersion '24.0.8215888' // use android studio side loaded ndk + buildFeatures { + prefab true + } + signingConfigs { + debug { + } + release { + } + } + defaultConfig { + applicationId "cc.openframeworks.ofapp" + minSdkVersion 21 + targetSdkVersion 34 + versionCode 12 + versionName '12.0' + ndk.abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' + + externalNativeBuild { + if (!project.hasProperty("ndkBuild")) { + cmake { + arguments "-DANDROID_STL=c++_shared", + "-DANDROID_ARM_NEON=TRUE", + "-DANDROID_TOOLCHAIN=clang", + //"${OF_ADDONS_ARGUMENTS}", + "-DTARGET_OPENGLES=TRUE" + + version '3.22.1' + } + } + } + multiDexEnabled false + } + buildTypes { + release { + jniDebuggable false + debuggable false + minifyEnabled false + shrinkResources false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + } + debug { + jniDebuggable true + debuggable true + minifyEnabled false + shrinkResources false + signingConfig signingConfigs.debug + } + } + flavorDimensions "version" + productFlavors { + playstore { + applicationIdSuffix "" + signingConfig signingConfigs.release + } +// humble { +// applicationIdSuffix ".humble" +// } +// amazon { +// applicationIdSuffix ".amazon" +// } +// samsung { +// applicationIdSuffix ".samsung" +// } +// oppo { +// applicationIdSuffix ".oppo" +// } + } + sourceSets { + main { + manifest.srcFile "${PRJ_SRC_ROOT}/AndroidManifest.xml" + java.srcDirs = ["${PRJ_SRC_ROOT}/java", + "${OFX_ANDROID}/Java"] + res.srcDirs = ["${PRJ_SRC_ROOT}/res"] +// jniLibs.srcDirs = ["${OF_ANDROID_OUTPUT}", "lib"] // Pre Android Studio 2022.2.1 + assets { + srcDirs 'src/main/assets', '../bin/data' + } + } + } + externalNativeBuild { + if (!project.hasProperty("ndkBuild")) { + cmake { + path "${CMAKELIST_PATH}/CMakeLists.txt" + } + } else { + ndkBuild { + path "${CMAKELIST_PATH}/Android.mk" + } + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + androidResources { + noCompress '' + } + dependenciesInfo { + includeInApk false + includeInBundle false + } +// testOptions { +// devices { +// pixel2api29 (com.android.build.api.dsl.ManagedVirtualDevice) { +// // Use device profiles you typically see in +// // Android Studio +// device = "Pixel 2" +// apiLevel = 29 +// // You can also specify "aosp" if you don’t require +// // Google Play Services. +// systemImageSource = "google" +// abi = "x86" +// } +// } +// } +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation "com.getkeepsafe.relinker:relinker:1.4.5" + implementation 'com.google.android.material:material:1.9.0' + if (project.hasProperty("googleplay")) { + implementation "com.google.android.gms:play-services-games:22.0.1" + implementation "com.google.android.gms:play-services-auth:20.0.1" + implementation "com.google.android.gms:play-services-base:18.0.1" + implementation "com.google.android.gms:play-services-basement:18.0.0" + implementation "com.google.android.gms:play-services-instantapps:18.0.1" + implementation "com.google.android.gms:play-services-appset:16.0.2" + } +} + diff --git a/scripts/templates/android/ofApp/gradle.properties b/scripts/templates/android/ofApp/gradle.properties new file mode 100644 index 00000000000..f96a9f246a0 --- /dev/null +++ b/scripts/templates/android/ofApp/gradle.properties @@ -0,0 +1,11 @@ +android.useAndroidX=true +android.enableJetifier=true +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +kotlin.code.style=official +android.prefabVersion=1.0.+ +# Workaround bug in AGP where the prefab dependency is being resolved from a +# non-Gradle thread when enableParallelJsonGen is enabled. +# https://issuetracker.google.com/149575364 +android.enableParallelJsonGen=false +android.buildFeatures.prefab = true +vectorDrawables.useSupportLibrary = true \ No newline at end of file diff --git a/scripts/templates/android/ofApp/proguard-rules.pro b/scripts/templates/android/ofApp/proguard-rules.pro new file mode 100644 index 00000000000..de8c62143ce --- /dev/null +++ b/scripts/templates/android/ofApp/proguard-rules.pro @@ -0,0 +1,127 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +-dontoptimize +-dontshrink +#-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +#-verbose +# +-optimizationpasses 7 # use for final build +-dontusemixedcaseclassnames +#-dontskipnonpubliclibraryclasses +#-dontpreverify +-verbose + +# custom app activity proguard +-keep public class cc.openframeworks.android.OFActivity { public ; } +-keep public class cc.openframeworks.android.R { public ; } + + +#-dontobfuscate android classes +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference + +#-dontobfuscate openFrameworks android classes +-keep public class cc.openframeworks.OFAndroid { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycleHelper { public ; } +-keep public class cc.openframeworks.OFAndroidWindow { public ; } +-keep public class cc.openframeworks.OFAndroidSoundPlayer { public ; } +-keep public class cc.openframeworks.OFGLSurfaceView { public ; } +-keep public class cc.openframeworks.OFAndroidLifeCycle { public ; } +-keep public class cc.openframeworks.OFActivity { public ; } +-keep public class cc.openframeworks.ContextFactory { public ; } +-keep public class cc.openframeworks.OFEGLConfigChooser { public ; } +-keep public class cc.openframeworks.OFGestureListener { public ; } +-keep public class cc.openframeworks.OFAndroidController { public ; } + +#-dontobfuscate GooglePlay Games android classes if used +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +-keep class com.google.android.gms.common.api.** { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } + +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +# note that means any method +-keepclasseswithmembernames,includedescriptorclasses class * { + native ; +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/scripts/templates/android/ofApp/src/main/AndroidManifest.xml b/scripts/templates/android/ofApp/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..61305a3e635 --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/AndroidManifest.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scripts/templates/android/ofApp/src/main/cpp/CMakeLists.txt b/scripts/templates/android/ofApp/src/main/cpp/CMakeLists.txt new file mode 100644 index 00000000000..314522a168b --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/cpp/CMakeLists.txt @@ -0,0 +1,142 @@ +# Sets the minimum version of CMake required to build the native +# library. +cmake_minimum_required(VERSION 3.22.1) + +project(ofapp LANGUAGES CXX) +set(TARGET_ANDROID TRUE) + +set(LOCAL_PATH ${CMAKE_SOURCE_DIR}) +set(PRJ_OF_ROOT ${LOCAL_PATH}/../../../../../../) + +set(PURE_OF_ROOT ${LOCAL_PATH}/../../../../../../) +set(CORE_OF_ROOT ${PURE_OF_ROOT}/libs/openFrameworks) +set(LIBS_ROOT ${PURE_OF_ROOT}/libs) + +set(PRJ_ADDONS_PATH ${PURE_OF_ROOT}/addons) +set(PRJ_SOURCE_PATH ${LIBS_ROOT}/openFrameworks) +set(PRJ_LIBS_ROOT ${PURE_OF_ROOT}/libs) + +set(OF_ANDROID ${PURE_OF_ROOT}/libs/openFrameworksCompiled/project/android) +set(OF_ANDROID_OUTPUT ${PURE_OF_ROOT}/libs/openFrameworksCompiled/lib/android) + +set(PRJ_OFX_ANDROID_PATH ${PRJ_ADDONS_PATH}/ofxAndroid) +set(PRJ_OFX_ANDROID_CPP_PATH ${PRJ_OFX_ANDROID_PATH}/src) + +macro(print_all_variables) + message(STATUS "print_all_variables------------------------------------------{") + get_cmake_property(_variableNames VARIABLES) + foreach (_variableName ${_variableNames}) + message(STATUS "${_variableName}=${${_variableName}}") + endforeach() + message(STATUS "print_all_variables------------------------------------------}") +endmacro() + +# Custom function to check if the library is built +function(check_library) + if (NOT TARGET openFrameworksAndroid) + message(STATUS "openFrameworksAndroid Library not found. Building library...") + + # Invoke the build process for the library + execute_process( + COMMAND ${CMAKE_COMMAND} --build ${OF_ANDROID}/ + RESULT_VARIABLE result + ) + if (result) + message(FATAL_ERROR "Failed to build the library.") + endif () + endif () +endfunction() + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS ON) +set(TARGET_ANDROID ON) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c17 -Oz -DNDEBUG -frtti --warn-uninitialized -fno-short-enums -Wextra -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") +set(CMAKE_CPP_FLAGS "${CMAKE_C_FLAGS} -std=c++17 -Oz -DNDEBUG -stdlib=libc++ --warn-uninitialized -frtti -Wextra -fno-short-enums -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-export-dynamic") + +print_all_variables() + +# Creates the project's shared lib: libnative-lib.so. +# The lib is loaded by this project's Java code in MainActivity.java: +# System.loadLibrary("native-lib"); +# The lib name in both places must match. +add_library( ofapp #name + SHARED # type of library + # src files for project (just c/cpp) + ${CMAKE_SOURCE_DIR}/main.cpp + ${CMAKE_SOURCE_DIR}/ofApp.cpp + ) + + +# Specifies a path to native header files +include_directories( + # openFrameworks headers + ${PRJ_SOURCE_PATH}/3d + ${PRJ_SOURCE_PATH}/app + ${PRJ_SOURCE_PATH}/communication + ${PRJ_SOURCE_PATH}/events + ${PRJ_SOURCE_PATH}/gl + ${PRJ_SOURCE_PATH}/graphics + ${PRJ_SOURCE_PATH}/math + ${PRJ_SOURCE_PATH}/sound + ${PRJ_SOURCE_PATH}/types + ${PRJ_SOURCE_PATH}/utils + ${PRJ_SOURCE_PATH}/video + ${PRJ_SOURCE_PATH} + # openFrameworks addons includes + ${PURE_OF_ROOT}/addons/ofxAndroid/src + ${PURE_OF_ROOT}/addons/ofxAccelerometer/src + ${PURE_OF_ROOT}/addons/ofxXmlSettings/src + ${PURE_OF_ROOT}/addons/ofxXmlSettings/libs + # openFrameworks Libs includes + ${PRJ_LIBS_ROOT}/FreeImage/include + ${PRJ_LIBS_ROOT}/freetype/include + ${PRJ_LIBS_ROOT}/freetype/include/freetype2 + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/config + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal + ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal/services + ${PRJ_LIBS_ROOT}/glm/include + ${PRJ_LIBS_ROOT}/pugixml/include + ${PRJ_LIBS_ROOT}/json/include + ${PRJ_LIBS_ROOT}/tess2/include + ${PRJ_LIBS_ROOT}/utf8/include + ${PRJ_LIBS_ROOT}/uriparser/include + ${CMAKE_SOURCE_DIR}/ + ${CMAKE_SOURCE_DIR}/ + ${OF_ANDROID} +) + +find_library(android-lib android) +find_library(log-lib log) +find_library(GLES2-lib GLESv2) + +#find_library(GLES1-lib GLESv1_CM) +#find_library(GLES3-lib GLESv3) + + +target_link_libraries(ofapp + EGL + GLESv2 + log + c + m + z + dl +# GLESv3 + ) + +target_link_libraries( ofapp + ${android-lib} ) +target_link_libraries( ofapp + ${GLES2-lib} ) +target_link_libraries( ofapp + ${log-lib} ) +#target_link_libraries( ofApp +# ${GLES3-lib} ) +#target_link_libraries( ofApp +# ${GLES1-lib} ) + +# Finally link in openFrameworks Library for each ABI +target_link_libraries( ofapp + ${OF_ANDROID_OUTPUT}/${ANDROID_ABI}/libopenFrameworksAndroid.so) diff --git a/scripts/templates/android/ofApp/src/main/cpp/main.cpp b/scripts/templates/android/ofApp/src/main/cpp/main.cpp new file mode 100644 index 00000000000..f98043c5a8c --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/cpp/main.cpp @@ -0,0 +1,49 @@ +#include "ofMain.h" +#include "ofApp.h" + +#ifdef TARGET_ANDROID + +#include "ofWindowSettings.h" +#include "ofGLProgrammableRenderer.h" + +shared_ptr *ofapp; +std::shared_ptr baseWindow; + +//-------------------------------------------------------------- +int main(int argc, char **argv) { + baseWindow = std::make_shared(); + ofxAndroidWindowSettings settings; + settings.glesVersion = 2; + settings.setSize(1920, 1080); + settings.windowMode = OF_WINDOW; + settings.preserveContextOnPause = true; + baseWindow = ofCreateWindow(settings); + ofapp = new shared_ptr(new ofApp()); + ofRunApp(baseWindow, *ofapp); + return 0; +} + +void ofAndroidApplicationInit() +{ + //application scope init +} +void ofAndroidActivityInit() +{ + //activity scope init - call main + main(0, nullptr); +} + +// Callbacks from Android Layer +extern "C" JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_init( JNIEnv* env, jclass clazz) +{ + ofAndroidApplicationInit(); +} + +extern "C" JNIEXPORT void JNICALL +Java_cc_openframeworks_OFAndroid_onCreate( JNIEnv* env, jclass clazz) +{ + ofAndroidActivityInit(); +} + +#endif diff --git a/examples/android/androidEmptyExample/src/ofApp.cpp b/scripts/templates/android/ofApp/src/main/cpp/ofApp.cpp similarity index 87% rename from examples/android/androidEmptyExample/src/ofApp.cpp rename to scripts/templates/android/ofApp/src/main/cpp/ofApp.cpp index 189c4aebe88..4c08f9bfc44 100644 --- a/examples/android/androidEmptyExample/src/ofApp.cpp +++ b/scripts/templates/android/ofApp/src/main/cpp/ofApp.cpp @@ -5,6 +5,10 @@ void ofApp::setup(){ } +void ofApp::exit(){ + +} + //-------------------------------------------------------------- void ofApp::update(){ @@ -94,3 +98,19 @@ void ofApp::okPressed(){ void ofApp::cancelPressed(){ } + +void ofApp::deviceRefreshRateChanged(int refreshRate) { + +} + +void ofApp::deviceHighestRefreshRateChanged(int refreshRate) { + +} + +void ofApp::deviceRefreshRateChangedEvent(int &refreshRate) { + +} + +void ofApp::deviceHighestRefreshRateChangedEvent(int &refreshRate) { + +} diff --git a/scripts/templates/android/src/ofApp.h b/scripts/templates/android/ofApp/src/main/cpp/ofApp.h similarity index 71% rename from scripts/templates/android/src/ofApp.h rename to scripts/templates/android/ofApp/src/main/cpp/ofApp.h index 2fe90435ddb..fab21d73585 100644 --- a/scripts/templates/android/src/ofApp.h +++ b/scripts/templates/android/ofApp/src/main/cpp/ofApp.h @@ -8,6 +8,7 @@ class ofApp : public ofxAndroidApp{ public: void setup(); + void exit(); void update(); void draw(); @@ -30,4 +31,9 @@ class ofApp : public ofxAndroidApp{ bool backPressed(); void okPressed(); void cancelPressed(); + + void deviceRefreshRateChanged(int refreshRate); + void deviceHighestRefreshRateChanged(int refreshRate); + void deviceRefreshRateChangedEvent(int &refreshRate); + void deviceHighestRefreshRateChangedEvent(int & refreshRate); }; diff --git a/scripts/templates/android/ofApp/src/main/ic_launcher-playstore.png b/scripts/templates/android/ofApp/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000000..2a0df19f5e0 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/ic_launcher-playstore.png differ diff --git a/scripts/templates/android/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java b/scripts/templates/android/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java new file mode 100644 index 00000000000..f0a6dc8d4e8 --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java @@ -0,0 +1,204 @@ +package cc.openframeworks.android; + +import android.app.Activity; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; + +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; + +import cc.openframeworks.OFAndroid; +import cc.openframeworks.OFAndroidController; +import cc.openframeworks.OFAndroidLifeCycle; +import cc.openframeworks.OFAndroidLifeCycleHelper; + +import com.getkeepsafe.relinker.ReLinker; + + + +public class OFActivity extends cc.openframeworks.OFActivity { + + private static final String appName = "ofapp"; // modify this to target appName (ofApp etc) + private static final String LOG_TAG = appName + "::OFActivity"; + + private ReLinker.Logger logcatLogger = new ReLinker.Logger() { + @Override + public void log(String message) { + Log.d("ReLinker", message); + } + }; + private OFActivity thisActivity; + + + // Extremely important + public OFActivity() { + OFAndroidLifeCycle.coreLibraryLoaded = true; + + OFAndroid.maxSamples = 4; + OFAndroid.maximumFrameRate = 144; + + thisActivity = this; + ReLinker.log(logcatLogger) + .force() + .recursively() + .loadLibrary(this, appName, new ReLinker.LoadListener() { + @Override + public void success() { + Log.i(LOG_TAG, "loadLibrary success"); + OFAndroidLifeCycle.appLibraryLoaded = true; + Setup(); // very important - this will in turn call main + } + + @Override + public void failure(Throwable t) { + /* Boo */ + Log.i(LOG_TAG, "loadLibrary failure" + t.getMessage()); + } + }); + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + Log.i(LOG_TAG, "onCreate"); + super.onCreate(savedInstanceState); + + setFullscreen(); + hideSystemBars(); + } + + @Override + public void onStart() { + super.onStart(); + + } + + @Override + public void onDetachedFromWindow() { + + } + + // Menus + // http://developer.android.com/guide/topics/ui/menus.html + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Create settings menu options from here, one by one or infalting an xml + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // This passes the menu option string to OF + // you can add additional behavior from java modifying this method + // but keep the call to OFAndroid so OF is notified of menu events + if(OFAndroid.menuItemSelected(item.getItemId())){ + + return true; + } + return super.onOptionsItemSelected(item); + } + + + @Override + public boolean onPrepareOptionsMenu (Menu menu){ + // This method is called every time the menu is opened + // you can add or remove menu options from here + return super.onPrepareOptionsMenu(menu); + } + + public void onRestore() { + + if (!OFAndroidLifeCycle.appLibraryLoaded) return; + } + + private void hideSystemBars() { + WindowInsetsControllerCompat windowInsetsController = + ViewCompat.getWindowInsetsController(getWindow().getDecorView()); + if (windowInsetsController == null) { + return; + } + // Configure the behavior of the hidden system bars + windowInsetsController.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + ); + // Hide both the status bar and the navigation bar + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + + if (hasFocus) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + + setFullscreen(); + } else { + setFullscreen(); + } + } else { + + } + } + + private void handleException(Exception e, String details) { + Log.e(LOG_TAG, "Exception:", e); + + } + + public void setFullscreen() { + try { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + // No sticky immersive mode for devices pre-kitkat + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } else { + View decorView = getWindow().getDecorView(); +// int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; + int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + decorView.setSystemUiVisibility(uiOptions); + } + + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + + } catch (Exception ex) { + handleException(ex, "setFullscreen exception"); + } + + try { + View decorView = getWindow().getDecorView(); + int[] locations = new int[2]; + decorView.getLocationInWindow(locations); + int[] locations2 = new int[2]; + decorView.getLocationOnScreen(locations2); + + } catch (Exception ex) { + handleException(ex, "setFullscreen exception"); + } + + WindowInsetsControllerCompat windowInsetsController = + ViewCompat.getWindowInsetsController(getWindow().getDecorView()); + if (windowInsetsController == null) { + return; + } + // Hide both the status bar and the navigation bar + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); + windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars()); + windowInsetsController.hide(WindowInsetsCompat.Type.statusBars()); + } + + +} + diff --git a/scripts/templates/android/ofApp/src/main/res/drawable-hdpi/icon.png b/scripts/templates/android/ofApp/src/main/res/drawable-hdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/drawable-hdpi/icon.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/drawable-mdpi/icon.png b/scripts/templates/android/ofApp/src/main/res/drawable-mdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/drawable-mdpi/icon.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/drawable-xhdpi/icon.png b/scripts/templates/android/ofApp/src/main/res/drawable-xhdpi/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/drawable-xhdpi/icon.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/drawable/icon.png b/scripts/templates/android/ofApp/src/main/res/drawable/icon.png new file mode 100644 index 00000000000..70b562fba01 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/drawable/icon.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/layout/main_layout.xml b/scripts/templates/android/ofApp/src/main/res/layout/main_layout.xml new file mode 100644 index 00000000000..d1da461f079 --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/layout/main_layout.xml @@ -0,0 +1,24 @@ + + + + + + diff --git a/scripts/templates/android/ofApp/src/main/res/menu/main_layout.xml b/scripts/templates/android/ofApp/src/main/res/menu/main_layout.xml new file mode 100644 index 00000000000..7ddcfbee35e --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/menu/main_layout.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/scripts/templates/android/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000000..036d09bc5fd --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/scripts/templates/android/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000000..036d09bc5fd --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png b/scripts/templates/android/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000000..42b40d2fbec Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/scripts/templates/android/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..648779fe415 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png b/scripts/templates/android/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000000..a39d8826804 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png b/scripts/templates/android/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000000..13e6dfef882 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/scripts/templates/android/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..67b93c29890 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png b/scripts/templates/android/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000000..93401eaf855 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png b/scripts/templates/android/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000000..018f9b90738 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/scripts/templates/android/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..fc64ec1c838 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/scripts/templates/android/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..486c62f1f2a Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png b/scripts/templates/android/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000000..cf6c612f8b1 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/scripts/templates/android/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..07b98443e1b Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/scripts/templates/android/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..b4024c5aa00 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/scripts/templates/android/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000000..60b1a9e8332 Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/scripts/templates/android/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000000..45bd0178fee Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/scripts/templates/android/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000000..1b64c2ce02d Binary files /dev/null and b/scripts/templates/android/ofApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/scripts/templates/android/ofApp/src/main/res/values-v11/strings.xml b/scripts/templates/android/ofApp/src/main/res/values-v11/strings.xml new file mode 100644 index 00000000000..427c772a3d9 --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/values-v11/strings.xml @@ -0,0 +1,5 @@ + + + ofApp + Menu + \ No newline at end of file diff --git a/scripts/templates/android/ofApp/src/main/res/values-v11/styles.xml b/scripts/templates/android/ofApp/src/main/res/values-v11/styles.xml new file mode 100644 index 00000000000..febc4d0286b --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/values-v11/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/scripts/templates/android/ofApp/src/main/res/values-v14/strings.xml b/scripts/templates/android/ofApp/src/main/res/values-v14/strings.xml new file mode 100644 index 00000000000..427c772a3d9 --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/values-v14/strings.xml @@ -0,0 +1,5 @@ + + + ofApp + Menu + \ No newline at end of file diff --git a/scripts/templates/android/ofApp/src/main/res/values-v14/styles.xml b/scripts/templates/android/ofApp/src/main/res/values-v14/styles.xml new file mode 100644 index 00000000000..928e0fd3d72 --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/values-v14/styles.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/scripts/templates/android/ofApp/src/main/res/values/ic_launcher_background.xml b/scripts/templates/android/ofApp/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000000..c5d5899fdf0 --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/scripts/templates/android/ofApp/src/main/res/values/strings.xml b/scripts/templates/android/ofApp/src/main/res/values/strings.xml new file mode 100644 index 00000000000..427c772a3d9 --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + + ofApp + Menu + \ No newline at end of file diff --git a/scripts/templates/android/ofApp/src/main/res/values/styles.xml b/scripts/templates/android/ofApp/src/main/res/values/styles.xml new file mode 100644 index 00000000000..766a2c3f143 --- /dev/null +++ b/scripts/templates/android/ofApp/src/main/res/values/styles.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/scripts/templates/android/proguard.cfg b/scripts/templates/android/proguard.cfg new file mode 100644 index 00000000000..faee26e7f2b --- /dev/null +++ b/scripts/templates/android/proguard.cfg @@ -0,0 +1,59 @@ +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontpreverify +-verbose +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class com.android.vending.licensing.ILicensingService + +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.video.** { *; } +-keep class com.google.android.gms.games.* { *; } + +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +-keep class com.google.android.gms.common.api.** { *; } +-keep class com.google.android.gms.games.quest.** { *; } +-keep class com.google.android.gms.nearby.** { *; } +-keepclasseswithmembernames class * { + native ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} diff --git a/scripts/templates/android/settings.gradle b/scripts/templates/android/settings.gradle index 0908d5d57f5..cb352f426c0 100644 --- a/scripts/templates/android/settings.gradle +++ b/scripts/templates/android/settings.gradle @@ -1,16 +1,11 @@ -// openFrameworks-relative root directories (don't touch) +include ':ofApp' -def ofRoot = '../../../' +// Define the relative path to the openFrameworks project +def openFrameworksProjectPath = '../../../libs/openFrameworksCompiled/project' -// Load common functions -apply from: ofRoot+"libs/openFrameworksCompiled/project/android/common-functions.gradle" +// Convert the relative path to an absolute path +def openFrameworksProjectAbsolutePath = new File(rootDir, openFrameworksProjectPath).absolutePath -javaDependencies( ofRoot ).each { dep -> - include(dep[1]) - project(dep[1]).projectDir = new File(dep[0]) -} - -addonJavaDependencies( ofRoot ).each { dep -> - include(dep[1]) - project(dep[1]).projectDir = new File(dep[0]) -} +// Include the openFrameworks project +include ':openFrameworksProject' +project(':openFrameworksProject').projectDir = new File(openFrameworksProjectAbsolutePath) diff --git a/scripts/templates/android/src/main.cpp b/scripts/templates/android/src/main.cpp deleted file mode 100644 index 2a410c552e3..00000000000 --- a/scripts/templates/android/src/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ofMain.h" -#include "ofApp.h" - -int main(){ - ofSetupOpenGL(1024,768, OF_WINDOW); // <-------- setup the GL context - - // this kicks off the running of my app - // can be OF_WINDOW or OF_FULLSCREEN - // pass in width and height too: - ofRunApp( new ofApp() ); - return 0; -} - - -#ifdef TARGET_ANDROID -void ofAndroidApplicationInit() -{ - //application scope init -} - -void ofAndroidActivityInit() -{ - //activity scope init - main(); -} -#endif diff --git a/scripts/templates/android/srcJava/cc/openframeworks/APP_NAME/OFActivity.java b/scripts/templates/android/srcJava/cc/openframeworks/APP_NAME/OFActivity.java deleted file mode 100644 index 0089dd5bcdf..00000000000 --- a/scripts/templates/android/srcJava/cc/openframeworks/APP_NAME/OFActivity.java +++ /dev/null @@ -1,48 +0,0 @@ -package cc.openframeworks.TEMPLATE_APP_NAME; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; -import cc.openframeworks.OFAndroid; - - -public class OFActivity extends cc.openframeworks.OFActivity{ - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - } - - @Override - public void onDetachedFromWindow() { - } - - // Menus - // http://developer.android.com/guide/topics/ui/menus.html - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Create settings menu options from here, one by one or infalting an xml - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // This passes the menu option string to OF - // you can add additional behavior from java modifying this method - // but keep the call to OFAndroid so OF is notified of menu events - if(OFAndroid.menuItemSelected(item.getItemId())){ - - return true; - } - return super.onOptionsItemSelected(item); - } - - - @Override - public boolean onPrepareOptionsMenu (Menu menu){ - // This method is called every time the menu is opened - // you can add or remove menu options from here - return super.onPrepareOptionsMenu(menu); - } -} - diff --git a/scripts/templates/android2024/build.gradle b/scripts/templates/android2024/build.gradle index 7cbc7eb6714..61a94fe6b7b 100644 --- a/scripts/templates/android2024/build.gradle +++ b/scripts/templates/android2024/build.gradle @@ -7,7 +7,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:8.9.0' } } diff --git a/scripts/templates/android2024/gradle.properties b/scripts/templates/android2024/gradle.properties index 43f9ef9e1c3..4bf1eab823a 100644 --- a/scripts/templates/android2024/gradle.properties +++ b/scripts/templates/android2024/gradle.properties @@ -2,9 +2,10 @@ android.useAndroidX=true android.enableJetifier=false org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 kotlin.code.style=official -android.prefabVersion=1.0.+ +android.prefabVersion=2.1.+ android.buildFeatures.prefab=true -#ndkBuild=false -# https://issuetracker.google.com/149575364 android.enableParallelJsonGen=false -#googleplay=true \ No newline at end of file +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false +googleplay=false diff --git a/scripts/templates/android2024/gradle/wrapper/gradle-wrapper.jar b/scripts/templates/android2024/gradle/wrapper/gradle-wrapper.jar index 13372aef5e2..a4b76b9530d 100644 Binary files a/scripts/templates/android2024/gradle/wrapper/gradle-wrapper.jar and b/scripts/templates/android2024/gradle/wrapper/gradle-wrapper.jar differ diff --git a/scripts/templates/android2024/gradle/wrapper/gradle-wrapper.properties b/scripts/templates/android2024/gradle/wrapper/gradle-wrapper.properties index 2dd5ee8c795..e2847c82004 100644 --- a/scripts/templates/android2024/gradle/wrapper/gradle-wrapper.properties +++ b/scripts/templates/android2024/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Mon Jun 12 01:17:57 AEST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/scripts/templates/android2024/local.properties b/scripts/templates/android2024/local.properties index 5ba01764b38..5ec9c39c34b 100644 --- a/scripts/templates/android2024/local.properties +++ b/scripts/templates/android2024/local.properties @@ -4,5 +4,5 @@ # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. -#Wed May 08 13:54:16 CEST 2024 -sdk.dir=/Users/thierry/Library/Android/sdk +#Thu Mar 06 00:08:45 AEDT 2025 +sdk.dir=/Users/one/Library/Android/sdk diff --git a/scripts/templates/android2024/ofApp/build.gradle b/scripts/templates/android2024/ofApp/build.gradle index 635a3e27577..ea57ef37d53 100644 --- a/scripts/templates/android2024/ofApp/build.gradle +++ b/scripts/templates/android2024/ofApp/build.gradle @@ -5,10 +5,8 @@ plugins { def CMAKELIST_PATH = './src/main/cpp' def CPP_SOURCE = './src/main/cpp' def JAVA_SOURCE = './src/main/java' - -// pointing to cmake's source code for the same project def PRJ_SRC_ROOT = './src/main' -def ofRoot(){ return '../../../../' } +static def ofRoot(){ return '../../../../' } final ofSource = ofRoot() + 'libs/openFrameworks' final ofLibs = ofRoot() + 'libs' final addons = ofRoot() + 'addons' @@ -19,7 +17,7 @@ def enableProguardInReleaseBuilds = true def enableProguardInDebugBuilds = false task wrapper(type: Wrapper) { - gradleVersion = '7.3.3' + gradleVersion = '8.9.0' } tasks.register("prepareKotlinBuildScriptModel"){ } @@ -32,12 +30,11 @@ tasks.whenTaskAdded { task -> } } - android { compileSdkVersion 34 - buildToolsVersion '32.0.0' + buildToolsVersion '35.0.0' //ndkPath "/Users/x/android-ndk-r21e" // Point to your own NDK if needed - ndkVersion '24.0.8215888' // use android studio side loaded ndk + ndkVersion '28.0.13004108' // use android studio side loaded ndk buildFeatures { prefab true } @@ -46,19 +43,19 @@ android { } release { storeFile new File("${System.properties['user.home']}/.android/debug.keystore") - storePassword 'android' storeType "jks" keyAlias 'androiddebugkey' - keyPassword 'android' +// storePassword 'android' // <- UPDATE THIS +// keyPassword 'android' // <- UPDATE THIS } } defaultConfig { applicationId "cc.openframeworks.emptyExample" // IMPORTANT : THIS DEFINES THE ID OF THE APK - minSdkVersion 21 + minSdkVersion 24 targetSdkVersion 34 versionCode 12 versionName '12.0' - ndk.abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86' //, 'x86_64' + ndk.abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64' externalNativeBuild { if (!project.hasProperty("ndkBuild")) { @@ -118,22 +115,16 @@ android { java.srcDirs = ["${PRJ_SRC_ROOT}/java", "${OFX_ANDROID}/Java"] res.srcDirs = ["${PRJ_SRC_ROOT}/res"] -// jniLibs.srcDirs = ["${OF_ANDROID_OUTPUT}", "lib"] // Pre Android Studio 2022.2.1 assets { srcDirs 'src/main/assets', 'src/main/bin/data' } } } externalNativeBuild { - if (!project.hasProperty("ndkBuild")) { - cmake { - path "${CMAKELIST_PATH}/CMakeLists.txt" - } - } else { - ndkBuild { - path "${CMAKELIST_PATH}/Android.mk" - } - } + cmake { + path "${CMAKELIST_PATH}/CMakeLists.txt" + } + } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -146,6 +137,7 @@ android { includeInApk false includeInBundle false } + namespace 'cc.openframeworks.android' // testOptions { // devices { // pixel2api29 (com.android.build.api.dsl.ManagedVirtualDevice) { @@ -165,11 +157,11 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'androidx.constraintlayout:constraintlayout:2.2.1' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation "com.getkeepsafe.relinker:relinker:1.4.5" - implementation 'com.google.android.material:material:1.9.0' + implementation 'com.google.android.material:material:1.12.0' if (project.hasProperty("googleplay")) { implementation "com.google.android.gms:play-services-games:22.0.1" implementation "com.google.android.gms:play-services-auth:20.0.1" diff --git a/scripts/templates/android2024/ofApp/src/main/AndroidManifest.xml b/scripts/templates/android2024/ofApp/src/main/AndroidManifest.xml index aae67ceba1b..8635b883084 100644 --- a/scripts/templates/android2024/ofApp/src/main/AndroidManifest.xml +++ b/scripts/templates/android2024/ofApp/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ @@ -58,7 +57,7 @@ - + @@ -86,4 +85,4 @@ - \ No newline at end of file + diff --git a/scripts/templates/android2024/ofApp/src/main/cpp/CMakeLists.txt b/scripts/templates/android2024/ofApp/src/main/cpp/CMakeLists.txt index 5b160ffa42d..6ecc1184538 100644 --- a/scripts/templates/android2024/ofApp/src/main/cpp/CMakeLists.txt +++ b/scripts/templates/android2024/ofApp/src/main/cpp/CMakeLists.txt @@ -2,23 +2,19 @@ # library. cmake_minimum_required(VERSION 3.22.1) -project(ofapp LANGUAGES CXX) +project(ofApp LANGUAGES CXX) set(TARGET_ANDROID TRUE) set(LOCAL_PATH ${CMAKE_SOURCE_DIR}) set(PRJ_OF_ROOT ${LOCAL_PATH}/../../../../../../../) - set(PURE_OF_ROOT ${LOCAL_PATH}/../../../../../../../) set(CORE_OF_ROOT ${PURE_OF_ROOT}/libs/openFrameworks) set(LIBS_ROOT ${PURE_OF_ROOT}/libs) - set(PRJ_ADDONS_PATH ${PURE_OF_ROOT}/addons) set(PRJ_SOURCE_PATH ${LIBS_ROOT}/openFrameworks) set(PRJ_LIBS_ROOT ${PURE_OF_ROOT}/libs) - set(OF_ANDROID ${PURE_OF_ROOT}/libs/openFrameworksCompiled/project/android) set(OF_ANDROID_OUTPUT ${PURE_OF_ROOT}/libs/openFrameworksCompiled/lib/android) - set(PRJ_OFX_ANDROID_PATH ${PRJ_ADDONS_PATH}/ofxAndroid) set(PRJ_OFX_ANDROID_CPP_PATH ${PRJ_OFX_ANDROID_PATH}/src) @@ -47,31 +43,30 @@ function(check_library) endif () endfunction() -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_C_STANDARD 17) +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS ON) +set(CMAKE_CXX_EXTENSIONS OFF) set(TARGET_ANDROID ON) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c17 -Oz -DNDEBUG -frtti --warn-uninitialized -fno-short-enums -Wextra -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") -set(CMAKE_CPP_FLAGS "${CMAKE_C_FLAGS} -std=c++17 -Oz -DNDEBUG -stdlib=libc++ --warn-uninitialized -frtti -Wextra -fno-short-enums -fPIE -fPIC -fuse-ld=gold -fexceptions -ffunction-sections -fdata-sections -Wall -Wextra -Wfloat-equal -Wundef -Werror -fverbose-asm -Wint-to-pointer-cast -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wcast-qual -Wmissing-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion --pedantic-errors") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ferror-limit=0 -std=c17 -Oz -Wall -fno-short-enums -fPIE -fPIC -fexceptions -ffunction-sections -fdata-sections") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ferror-limit=0 -std=c++23 -Oz -stdlib=libc++ -Wall -fno-short-enums -fPIE -fPIC -fexceptions -ffunction-sections -fdata-sections") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-export-dynamic") - print_all_variables() - -# Creates the project's shared lib: libnative-lib.so. -# The lib is loaded by this project's Java code in MainActivity.java: -# System.loadLibrary("native-lib"); -# The lib name in both places must match. -add_library( ofapp #name - SHARED # type of library +set(OF_LIBRARY_TYPE "SHARED") # or "STATIC" +if(OF_LIBRARY_TYPE STREQUAL "SHARED") + set(LIB_EXTENSION ".so") +elseif(OF_LIBRARY_TYPE STREQUAL "STATIC") + set(LIB_EXTENSION ".a") +endif() + +add_library( ofApp + ${OF_LIBRARY_TYPE} # src files for project (just c/cpp) ${CMAKE_SOURCE_DIR}/main.cpp ${CMAKE_SOURCE_DIR}/ofApp.cpp - ) - +) -# Specifies a path to native header files include_directories( - # openFrameworks headers ${PRJ_SOURCE_PATH}/3d ${PRJ_SOURCE_PATH}/app ${PRJ_SOURCE_PATH}/communication @@ -84,12 +79,9 @@ include_directories( ${PRJ_SOURCE_PATH}/utils ${PRJ_SOURCE_PATH}/video ${PRJ_SOURCE_PATH} - # openFrameworks addons includes + ${PRJ_OFX_ANDROID_CPP_PATH}/ ${PURE_OF_ROOT}/addons/ofxAndroid/src ${PURE_OF_ROOT}/addons/ofxAccelerometer/src - ${PURE_OF_ROOT}/addons/ofxXmlSettings/src - ${PURE_OF_ROOT}/addons/ofxXmlSettings/libs - # openFrameworks Libs includes ${PRJ_LIBS_ROOT}/FreeImage/include ${PRJ_LIBS_ROOT}/freetype/include ${PRJ_LIBS_ROOT}/freetype/include/freetype2 @@ -97,46 +89,44 @@ include_directories( ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal ${PRJ_LIBS_ROOT}/freetype/include/freetype2/freetype/internal/services ${PRJ_LIBS_ROOT}/glm/include + ${PRJ_LIBS_ROOT}/brotli/include + ${PRJ_LIBS_ROOT}/json/include + ${PRJ_LIBS_ROOT}/libpng/include + ${PRJ_LIBS_ROOT}/fmt/include ${PRJ_LIBS_ROOT}/pugixml/include ${PRJ_LIBS_ROOT}/json/include ${PRJ_LIBS_ROOT}/tess2/include ${PRJ_LIBS_ROOT}/utf8/include + ${PRJ_LIBS_ROOT}/tess2/include + ${PRJ_LIBS_ROOT}/zlib/include ${PRJ_LIBS_ROOT}/uriparser/include + ${PRJ_LIBS_ROOT}/openssl/include + ${PRJ_LIBS_ROOT}/curl/include ${CMAKE_SOURCE_DIR}/ ${CMAKE_SOURCE_DIR}/ ${OF_ANDROID} ) -find_library(android-lib android) -find_library(log-lib log) -find_library(GLES2-lib GLESv2) - -#find_library(GLES1-lib GLESv1_CM) -#find_library(GLES3-lib GLESv3) - +find_library(ANDROID_LIB NAMES android) +find_library(LOG_LIB NAMES log) +find_library(GLES1_LIB NAMES GLESv1_CM) +find_library(GLES2_LIB NAMES GLESv2) +find_library(GLES3_LIB NAMES GLESv3) -target_link_libraries(ofapp - EGL - GLESv2 +target_link_libraries(ofApp + android log - c m z dl -# GLESv3 - ) - -target_link_libraries( ofapp - ${android-lib} ) -target_link_libraries( ofapp - ${GLES2-lib} ) -target_link_libraries( ofapp - ${log-lib} ) -#target_link_libraries( ofApp -# ${GLES3-lib} ) -#target_link_libraries( ofApp -# ${GLES1-lib} ) +) +target_link_libraries(ofApp + ${ANDROID_LIB} + ${GLES2_LIB} + ${GLES3_LIB} + ${GLES1_LIB} + ${LOG_LIB} +) -# Finally link in openFrameworks Library for each ABI -target_link_libraries( ofapp - ${OF_ANDROID_OUTPUT}/${ANDROID_ABI}/libopenFrameworksAndroid.so) +target_link_libraries( ofApp + ${OF_ANDROID_OUTPUT}/${ANDROID_ABI}/libopenFrameworksAndroid${LIB_EXTENSION}) diff --git a/scripts/templates/android2024/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java b/scripts/templates/android2024/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java index 598ee50bbf1..a2d8b5f69a5 100644 --- a/scripts/templates/android2024/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java +++ b/scripts/templates/android2024/ofApp/src/main/java/cc/openframeworks/android/OFActivity.java @@ -22,27 +22,25 @@ public class OFActivity extends cc.openframeworks.OFActivity { - private static final String appName = "ofapp"; // modify this to target appName (ofApp etc) + private static final String appName = "ofApp"; // modify this to target appName (ofApp etc) private static final String LOG_TAG = appName + "::OFActivity"; - private ReLinker.Logger logcatLogger = new ReLinker.Logger() { - @Override - public void log(String message) { - Log.d("ReLinker", message); - } - }; - private OFActivity thisActivity; - - // Extremely important + // Extremely important public OFActivity() { OFAndroidLifeCycle.coreLibraryLoaded = true; OFAndroid.maxSamples = 4; OFAndroid.maximumFrameRate = 144; - thisActivity = this; - ReLinker.log(logcatLogger) + OFActivity thisActivity = this; + ReLinker.Logger logcatLogger = new ReLinker.Logger() { + @Override + public void log(String message) { + Log.d("ReLinker", message); + } + }; + ReLinker.log(logcatLogger) .force() .recursively() .loadLibrary(this, appName, new ReLinker.LoadListener() {