merged with muzei
This commit is contained in:
parent
1d4b103f06
commit
2c51ab0cc6
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
Debug
|
Debug
|
||||||
Release
|
Release
|
||||||
log.txt
|
log.txt
|
||||||
|
build
|
1
proj.android-studio/app/.gitignore
vendored
1
proj.android-studio/app/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/build
|
|
@ -20,7 +20,6 @@ include_directories(${LIBJPEG_PATH}/vc10)
|
|||||||
include_directories(${LUA_PATH})
|
include_directories(${LUA_PATH})
|
||||||
include_directories(${EIGEN_PATH})
|
include_directories(${EIGEN_PATH})
|
||||||
include_directories(${SOL2_PATH})
|
include_directories(${SOL2_PATH})
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../)
|
|
||||||
include_directories(${BOOST_PATH})
|
include_directories(${BOOST_PATH})
|
||||||
include_directories(${LIBPNG_PATH})
|
include_directories(${LIBPNG_PATH})
|
||||||
include_directories(${LIBJPEG_PATH})
|
include_directories(${LIBJPEG_PATH})
|
||||||
|
@ -1,43 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 28
|
||||||
buildToolsVersion "28.0.0"
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "fishrungames.mountainwallpaper"
|
applicationId "fishrungames.mountainwallpaper"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 2
|
versionCode 2
|
||||||
versionName "1.1"
|
versionName "1.1"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
cppFlags "-std=c++11 -frtti -fexceptions -fsigned-char -Wno-c++11-narrowing"
|
cppFlags "-std=c++11 -frtti -fexceptions -fsigned-char -Wno-c++11-narrowing"
|
||||||
|
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
shrinkResources true
|
||||||
}
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), file('proguard-project.txt')
|
||||||
}
|
|
||||||
externalNativeBuild {
|
|
||||||
cmake {
|
|
||||||
path "CMakeLists.txt"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
assets.srcDirs = ['../../assets/']
|
assets.srcDirs = ['../../assets/']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
splits {
|
||||||
|
abi {
|
||||||
|
enable true
|
||||||
|
reset()
|
||||||
|
include 'arm64-v8a', 'armeabi-v7a', 'x86'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path 'CMakeLists.txt'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
|
||||||
compile 'com.android.support:appcompat-v7:28+'
|
implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
|
||||||
|
implementation "com.android.support:preference-v7:$supportLibraryVersion"
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
|
|
||||||
compile project(':SalmonEngineAndroid')
|
implementation project(':SalmonEngineAndroid')
|
||||||
}
|
}
|
@ -1,26 +0,0 @@
|
|||||||
package fishrungames.salmonandroidtemplate;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.test.InstrumentationRegistry;
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instrumentation test, which will execute on an Android device.
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class ExampleInstrumentedTest {
|
|
||||||
@Test
|
|
||||||
public void useAppContext() throws Exception {
|
|
||||||
// Context of the app under test.
|
|
||||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
|
||||||
|
|
||||||
assertEquals("fishrungames.salmonandroidtemplate", appContext.getPackageName());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +1,90 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<!--
|
||||||
|
Copyright 2014 Google Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
<manifest
|
<manifest
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="fishrungames.mountainwallpaper"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:versionCode="1"
|
package="fishrungames.mountainwallpaper">
|
||||||
android:versionName="1.0.0">
|
|
||||||
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.software.live_wallpaper"
|
||||||
|
android:required="true"/>
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:glEsVersion="0x00020000"
|
android:glEsVersion="0x00020000"
|
||||||
android:required="true"/>
|
android:required="true"/>
|
||||||
|
|
||||||
|
<!-- <uses-permission android:name="android.permission.WAKE_LOCK"/> -->
|
||||||
|
|
||||||
|
<!-- Don't request this starting with Marshmallow (we only write to the app's cache folder) -->
|
||||||
|
<!-- <uses-permission
|
||||||
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="22"/>-->
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:supportsRtl="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:icon="@drawable/icon" >
|
android:icon="@drawable/icon"
|
||||||
|
android:allowBackup="false">
|
||||||
|
<!--tools:ignore="GoogleAppIndexingWarning"-->
|
||||||
|
|
||||||
|
<!-- Needed to support long aspect ratio devices as Muzei has resizeableActivity="false" -->
|
||||||
|
<!-- <meta-data
|
||||||
|
android:name="android.max_aspect"
|
||||||
|
android:value="2.1"/>-->
|
||||||
|
<!--android:theme="@style/Theme.MuzeiActivity"-->
|
||||||
|
<!--android:resizeableActivity="false"-->
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".Prefs">
|
android:name=".WallpaperPreferences"
|
||||||
|
android:launchMode="singleTop">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<!--<intent-filter>-->
|
||||||
|
<!--<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>-->
|
||||||
|
<!--</intent-filter>-->
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<!--android:directBootAware="true"-->
|
||||||
|
<!--tools:targetApi="n"-->
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".MountainWallpaperService"
|
android:name=".MountainWallpaper"
|
||||||
|
android:permission="android.permission.BIND_WALLPAPER"
|
||||||
android:icon="@drawable/icon"
|
android:icon="@drawable/icon"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name">
|
||||||
android:permission="android.permission.BIND_WALLPAPER">
|
<intent-filter>
|
||||||
<intent-filter android:priority="1">
|
<action android:name="android.service.wallpaper.WallpaperService"/>
|
||||||
<action android:name="android.service.wallpaper.WallpaperService" />
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.service.wallpaper"
|
android:name="android.service.wallpaper"
|
||||||
android:resource="@xml/wallpaper"/>
|
android:resource="@xml/wallpaper"/>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
</application>
|
<!--<activity-alias-->
|
||||||
|
<!--android:name="com.google.android.apps.muzei.settings.NotificationSettings"-->
|
||||||
|
<!--android:targetActivity="com.google.android.apps.muzei.WallpaperPreferences"-->
|
||||||
|
<!--android:enabled="@bool/enable_notification_settings">-->
|
||||||
|
<!--<intent-filter>-->
|
||||||
|
<!--<action android:name="android.intent.action.MAIN"/>-->
|
||||||
|
<!--<category android:name="android.intent.category.NOTIFICATION_PREFERENCES"/>-->
|
||||||
|
<!--</intent-filter>-->
|
||||||
|
<!--</activity-alias>-->
|
||||||
|
|
||||||
|
</application>
|
||||||
</manifest>
|
</manifest>
|
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fishrungames.mountainwallpaper
|
||||||
|
|
||||||
|
import android.opengl.GLSurfaceView
|
||||||
|
|
||||||
|
import javax.microedition.khronos.egl.EGL10
|
||||||
|
import javax.microedition.khronos.egl.EGLConfig
|
||||||
|
import javax.microedition.khronos.egl.EGLDisplay
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by romannurik on 11/6/13.
|
||||||
|
*/
|
||||||
|
internal abstract class BaseConfigChooser(configSpec: IntArray, private val eglContextClientVersion: Int) : GLSurfaceView.EGLConfigChooser {
|
||||||
|
|
||||||
|
protected var mConfigSpec: IntArray
|
||||||
|
|
||||||
|
init {
|
||||||
|
mConfigSpec = filterConfigSpec(configSpec)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chooseConfig(egl: EGL10, display: EGLDisplay): EGLConfig {
|
||||||
|
val num_config = IntArray(1)
|
||||||
|
if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
|
||||||
|
num_config)) {
|
||||||
|
throw IllegalArgumentException("eglChooseConfig failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
val numConfigs = num_config[0]
|
||||||
|
|
||||||
|
if (numConfigs <= 0) {
|
||||||
|
throw IllegalArgumentException(
|
||||||
|
"No configs match configSpec")
|
||||||
|
}
|
||||||
|
|
||||||
|
val configs = kotlin.arrayOfNulls<EGLConfig?>(numConfigs)
|
||||||
|
if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
|
||||||
|
num_config)) {
|
||||||
|
throw IllegalArgumentException("eglChooseConfig#2 failed")
|
||||||
|
}
|
||||||
|
return chooseConfig(egl, display, configs)
|
||||||
|
?: throw IllegalArgumentException("No config chosen")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract fun chooseConfig(egl: EGL10, display: EGLDisplay,
|
||||||
|
configs: Array<EGLConfig?>): EGLConfig?
|
||||||
|
|
||||||
|
private fun filterConfigSpec(configSpec: IntArray): IntArray {
|
||||||
|
if (eglContextClientVersion != 2) {
|
||||||
|
return configSpec
|
||||||
|
}
|
||||||
|
/* We know none of the subclasses define EGL_RENDERABLE_TYPE.
|
||||||
|
* And we know the configSpec is well formed.
|
||||||
|
*/
|
||||||
|
val len = configSpec.size
|
||||||
|
val newConfigSpec = IntArray(len + 2)
|
||||||
|
System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1)
|
||||||
|
newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE
|
||||||
|
newConfigSpec[len] = 4 /* EGL_OPENGL_ES2_BIT */
|
||||||
|
newConfigSpec[len + 1] = EGL10.EGL_NONE
|
||||||
|
return newConfigSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ComponentSizeChooser(// Subclasses can adjust these values:
|
||||||
|
protected var mRedSize: Int, protected var mGreenSize: Int, protected var mBlueSize: Int, protected var mAlphaSize: Int, protected var mDepthSize: Int,
|
||||||
|
protected var mStencilSize: Int, eglContextClientVersion: Int) : BaseConfigChooser(intArrayOf(EGL10.EGL_RED_SIZE, mRedSize, EGL10.EGL_GREEN_SIZE, mGreenSize, EGL10.EGL_BLUE_SIZE, mBlueSize, EGL10.EGL_ALPHA_SIZE, mAlphaSize, EGL10.EGL_DEPTH_SIZE, mDepthSize, EGL10.EGL_STENCIL_SIZE, mStencilSize, EGL10.EGL_NONE), eglContextClientVersion) {
|
||||||
|
|
||||||
|
private val mValue: IntArray
|
||||||
|
|
||||||
|
init {
|
||||||
|
mValue = IntArray(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun chooseConfig(egl: EGL10, display: EGLDisplay, configs: Array<EGLConfig?>): EGLConfig? {
|
||||||
|
var closestConfig: EGLConfig? = null
|
||||||
|
var closestDistance = 1000
|
||||||
|
for (config in configs) {
|
||||||
|
val d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE)
|
||||||
|
val s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE)
|
||||||
|
if (d >= mDepthSize && s >= mStencilSize) {
|
||||||
|
val r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE)
|
||||||
|
val g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE)
|
||||||
|
val b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE)
|
||||||
|
val a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE)
|
||||||
|
val distance = (Math.abs(r - mRedSize) + Math.abs(g - mGreenSize) + Math.abs(b - mBlueSize)
|
||||||
|
+ Math.abs(a - mAlphaSize))
|
||||||
|
if (distance < closestDistance) {
|
||||||
|
closestDistance = distance
|
||||||
|
closestConfig = config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return closestConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findConfigAttrib(egl: EGL10, display: EGLDisplay, config: EGLConfig?, attribute: Int): Int {
|
||||||
|
|
||||||
|
return if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
|
||||||
|
mValue[0]
|
||||||
|
} else 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class will choose a supported surface as close to RGB565 as possible, with or without a depth buffer.
|
||||||
|
*/
|
||||||
|
class SimpleEGLConfigChooser(withDepthBuffer: Boolean, eglContextClientVersion: Int) : ComponentSizeChooser(4, 4, 4, 0, if (withDepthBuffer) 16 else 0, 0, eglContextClientVersion) {
|
||||||
|
init {
|
||||||
|
// Adjust target values. This way we'll accept a 4444 or
|
||||||
|
// 555 buffer if there's no 565 buffer available.
|
||||||
|
mRedSize = 5
|
||||||
|
mGreenSize = 6
|
||||||
|
mBlueSize = 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,960 +0,0 @@
|
|||||||
package fishrungames.mountainwallpaper;
|
|
||||||
|
|
||||||
|
|
||||||
import fishrungames.mountainwallpaper.BaseConfigChooser.ComponentSizeChooser;
|
|
||||||
import fishrungames.mountainwallpaper.BaseConfigChooser.SimpleEGLConfigChooser;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
|
||||||
|
|
||||||
import javax.microedition.khronos.egl.EGL10;
|
|
||||||
import javax.microedition.khronos.egl.EGLConfig;
|
|
||||||
import javax.microedition.khronos.egl.EGLContext;
|
|
||||||
import javax.microedition.khronos.egl.EGLDisplay;
|
|
||||||
import javax.microedition.khronos.egl.EGLSurface;
|
|
||||||
|
|
||||||
|
|
||||||
import android.service.wallpaper.WallpaperService;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
|
|
||||||
import fishrungames.salmonengineandroid.EngineWrapper;
|
|
||||||
|
|
||||||
|
|
||||||
public class GLWallpaperService extends WallpaperService {
|
|
||||||
private static final String TAG = "GLWallpaperService";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Engine onCreateEngine() {
|
|
||||||
return new GLEngine();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GLEngine extends Engine {
|
|
||||||
public final static int RENDERMODE_WHEN_DIRTY = 0;
|
|
||||||
public final static int RENDERMODE_CONTINUOUSLY = 1;
|
|
||||||
|
|
||||||
private GLThread mGLThread;
|
|
||||||
private EGLConfigChooser mEGLConfigChooser;
|
|
||||||
private EGLContextFactory mEGLContextFactory;
|
|
||||||
private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
|
|
||||||
|
|
||||||
private int mDebugFlags;
|
|
||||||
|
|
||||||
public GLEngine() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onVisibilityChanged(boolean visible) {
|
|
||||||
if (visible) {
|
|
||||||
onResume();
|
|
||||||
} else {
|
|
||||||
onPause();
|
|
||||||
}
|
|
||||||
super.onVisibilityChanged(visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(SurfaceHolder surfaceHolder) {
|
|
||||||
super.onCreate(surfaceHolder);
|
|
||||||
// Log.d(TAG, "GLEngine.onCreate()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
// Log.d(TAG, "GLEngine.onDestroy()");
|
|
||||||
mGLThread.requestExitAndWait();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceChanged(SurfaceHolder holder, int format,
|
|
||||||
int width, int height) {
|
|
||||||
// Log.d(TAG, "onSurfaceChanged()");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mGLThread.onWindowResize(width, height);
|
|
||||||
|
|
||||||
super.onSurfaceChanged(holder, format, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceCreated(SurfaceHolder holder) {
|
|
||||||
Log.d(TAG, "onSurfaceCreated()");
|
|
||||||
mGLThread.surfaceCreated(holder);
|
|
||||||
super.onSurfaceCreated(holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceDestroyed(SurfaceHolder holder) {
|
|
||||||
Log.d(TAG, "onSurfaceDestroyed()");
|
|
||||||
mGLThread.surfaceDestroyed();
|
|
||||||
super.onSurfaceDestroyed(holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setDebugFlags(int debugFlags) {
|
|
||||||
mDebugFlags = debugFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDebugFlags() {
|
|
||||||
return mDebugFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRenderer() {
|
|
||||||
checkRenderThreadState();
|
|
||||||
if (mEGLConfigChooser == null) {
|
|
||||||
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
|
|
||||||
}
|
|
||||||
if (mEGLContextFactory == null) {
|
|
||||||
//mEGLContextFactory = new DefaultContextFactory();
|
|
||||||
mEGLContextFactory = new ES20ContextFactory();
|
|
||||||
}
|
|
||||||
if (mEGLWindowSurfaceFactory == null) {
|
|
||||||
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
|
|
||||||
}
|
|
||||||
mGLThread = new GLThread(mEGLConfigChooser,
|
|
||||||
mEGLContextFactory, mEGLWindowSurfaceFactory);
|
|
||||||
mGLThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEGLContextFactory(EGLContextFactory factory) {
|
|
||||||
checkRenderThreadState();
|
|
||||||
mEGLContextFactory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
|
|
||||||
checkRenderThreadState();
|
|
||||||
mEGLWindowSurfaceFactory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEGLConfigChooser(EGLConfigChooser configChooser) {
|
|
||||||
checkRenderThreadState();
|
|
||||||
mEGLConfigChooser = configChooser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEGLConfigChooser(boolean needDepth) {
|
|
||||||
setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEGLConfigChooser(int redSize, int greenSize,
|
|
||||||
int blueSize, int alphaSize, int depthSize, int stencilSize) {
|
|
||||||
setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
|
|
||||||
blueSize, alphaSize, depthSize, stencilSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRenderMode(int renderMode) {
|
|
||||||
mGLThread.setRenderMode(renderMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRenderMode() {
|
|
||||||
return mGLThread.getRenderMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestRender() {
|
|
||||||
mGLThread.requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onPause() {
|
|
||||||
mGLThread.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onResume() {
|
|
||||||
mGLThread.onResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void queueEvent(Runnable r) {
|
|
||||||
mGLThread.queueEvent(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkRenderThreadState() {
|
|
||||||
if (mGLThread != null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"setRenderer has already been called for this instance.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for customizing the eglCreateContext and eglDestroyContext
|
|
||||||
* calls.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This interface must be implemented by clients wishing to call
|
|
||||||
* {@link GLWallpaperService.GLEngine#setEGLContextFactory(EGLContextFactory)}
|
|
||||||
*/
|
|
||||||
interface EGLContextFactory {
|
|
||||||
EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
|
|
||||||
|
|
||||||
void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
|
|
||||||
}
|
|
||||||
|
|
||||||
class DefaultContextFactory implements EGLContextFactory {
|
|
||||||
|
|
||||||
public EGLContext createContext(EGL10 egl, EGLDisplay display,
|
|
||||||
EGLConfig config) {
|
|
||||||
return egl
|
|
||||||
.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
|
|
||||||
egl.eglDestroyContext(display, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ES20ContextFactory implements EGLContextFactory {
|
|
||||||
|
|
||||||
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
|
||||||
|
|
||||||
public EGLContext createContext(EGL10 egl, EGLDisplay display,
|
|
||||||
EGLConfig config) {
|
|
||||||
|
|
||||||
|
|
||||||
int[] attrib_list =
|
|
||||||
{ EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
|
|
||||||
|
|
||||||
return egl
|
|
||||||
.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, attrib_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
|
|
||||||
egl.eglDestroyContext(display, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for customizing the eglCreateWindowSurface and eglDestroySurface
|
|
||||||
* calls.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This interface must be implemented by clients wishing to call
|
|
||||||
* {@link GLWallpaperService.GLEngine#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
|
|
||||||
*/
|
|
||||||
interface EGLWindowSurfaceFactory {
|
|
||||||
EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
|
|
||||||
EGLConfig config, Object nativeWindow);
|
|
||||||
|
|
||||||
void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
|
|
||||||
|
|
||||||
public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
|
|
||||||
EGLConfig config, Object nativeWindow) {
|
|
||||||
// this is a bit of a hack to work around Droid init problems - if you
|
|
||||||
// don't have this, it'll get hung up on orientation changes
|
|
||||||
EGLSurface eglSurface = null;
|
|
||||||
while (eglSurface == null) {
|
|
||||||
try {
|
|
||||||
eglSurface = egl.eglCreateWindowSurface(display, config,
|
|
||||||
nativeWindow, null);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
} finally {
|
|
||||||
if (eglSurface == null) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(10);
|
|
||||||
} catch (InterruptedException t) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return eglSurface;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) {
|
|
||||||
egl.eglDestroySurface(display, surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class EglHelper {
|
|
||||||
|
|
||||||
private EGL10 mEgl;
|
|
||||||
private EGLDisplay mEglDisplay;
|
|
||||||
private EGLSurface mEglSurface;
|
|
||||||
private EGLContext mEglContext;
|
|
||||||
EGLConfig mEglConfig;
|
|
||||||
|
|
||||||
private EGLConfigChooser mEGLConfigChooser;
|
|
||||||
private EGLContextFactory mEGLContextFactory;
|
|
||||||
private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
|
|
||||||
|
|
||||||
|
|
||||||
public EglHelper(EGLConfigChooser chooser,
|
|
||||||
EGLContextFactory contextFactory,
|
|
||||||
EGLWindowSurfaceFactory surfaceFactory) {
|
|
||||||
this.mEGLConfigChooser = chooser;
|
|
||||||
this.mEGLContextFactory = contextFactory;
|
|
||||||
this.mEGLWindowSurfaceFactory = surfaceFactory;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize EGL for a given configuration spec.
|
|
||||||
*
|
|
||||||
* configSpec
|
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
String instanceId = "";
|
|
||||||
Log.d("EglHelper" + instanceId, "start()");
|
|
||||||
if (mEgl == null) {
|
|
||||||
Log.d("EglHelper" + instanceId, "getting new EGL");
|
|
||||||
/*
|
|
||||||
* Get an EGL instance
|
|
||||||
*/
|
|
||||||
mEgl = (EGL10) EGLContext.getEGL();
|
|
||||||
} else {
|
|
||||||
Log.d("EglHelper" + instanceId, "reusing EGL");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mEglDisplay == null) {
|
|
||||||
Log.d("EglHelper" + instanceId, "getting new display");
|
|
||||||
/*
|
|
||||||
* Get to the default display.
|
|
||||||
*/
|
|
||||||
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
|
||||||
} else {
|
|
||||||
Log.d("EglHelper" + instanceId, "reusing display");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mEglConfig == null) {
|
|
||||||
Log.d("EglHelper" + instanceId, "getting new config");
|
|
||||||
/*
|
|
||||||
* We can now initialize EGL for that display
|
|
||||||
*/
|
|
||||||
int[] version = new int[2];
|
|
||||||
mEgl.eglInitialize(mEglDisplay, version);
|
|
||||||
mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
|
|
||||||
} else {
|
|
||||||
Log.d("EglHelper" + instanceId, "reusing config");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mEglContext == null) {
|
|
||||||
Log.d("EglHelper" + instanceId, "creating new context");
|
|
||||||
/*
|
|
||||||
* Create an OpenGL ES context. This must be done only once, an
|
|
||||||
* OpenGL context is a somewhat heavy object.
|
|
||||||
*/
|
|
||||||
mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay,
|
|
||||||
mEglConfig);
|
|
||||||
if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
|
|
||||||
throw new RuntimeException("createContext failed");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d("EglHelper" + instanceId, "reusing context");
|
|
||||||
}
|
|
||||||
|
|
||||||
mEglSurface = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* React to the creation of a new surface by creating and returning an
|
|
||||||
* OpenGL interface that renders to that surface.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public void createSurface(SurfaceHolder holder) {
|
|
||||||
|
|
||||||
if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
|
|
||||||
|
|
||||||
|
|
||||||
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
|
|
||||||
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
|
|
||||||
mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay,
|
|
||||||
mEglSurface);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
|
|
||||||
mEglDisplay, mEglConfig, holder);
|
|
||||||
|
|
||||||
if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
|
|
||||||
throw new RuntimeException("createWindowSurface failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
|
|
||||||
mEglContext)) {
|
|
||||||
//throw new RuntimeException("eglMakeCurrent failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the current render surface.
|
|
||||||
*
|
|
||||||
* @return false if the context has been lost.
|
|
||||||
*/
|
|
||||||
public boolean swap() {
|
|
||||||
try {
|
|
||||||
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Always check for EGL_CONTEXT_LOST, which means the context and all
|
|
||||||
* associated data were lost (For instance because the device went to
|
|
||||||
* sleep). We need to sleep until we get a new surface.
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroySurface() {
|
|
||||||
if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
|
|
||||||
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
|
|
||||||
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
|
|
||||||
mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay,
|
|
||||||
mEglSurface);
|
|
||||||
mEglSurface = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void finish() {
|
|
||||||
if (mEglContext != null) {
|
|
||||||
mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
|
|
||||||
mEglContext = null;
|
|
||||||
}
|
|
||||||
if (mEglDisplay != null) {
|
|
||||||
mEgl.eglTerminate(mEglDisplay);
|
|
||||||
mEglDisplay = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GLThread extends Thread {
|
|
||||||
private final static boolean LOG_THREADS = false;
|
|
||||||
public final static int DEBUG_CHECK_GL_ERROR = 1;
|
|
||||||
public final static int DEBUG_LOG_GL_CALLS = 2;
|
|
||||||
|
|
||||||
private final GLThreadManager sGLThreadManager = new GLThreadManager();
|
|
||||||
private GLThread mEglOwner;
|
|
||||||
|
|
||||||
private EGLConfigChooser mEGLConfigChooser;
|
|
||||||
private EGLContextFactory mEGLContextFactory;
|
|
||||||
private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
|
|
||||||
|
|
||||||
|
|
||||||
public SurfaceHolder mHolder;
|
|
||||||
private boolean mSizeChanged = true;
|
|
||||||
|
|
||||||
// Once the thread is started, all accesses to the following member
|
|
||||||
// variables are protected by the sGLThreadManager monitor
|
|
||||||
public boolean mDone;
|
|
||||||
private boolean mPaused;
|
|
||||||
private boolean mHasSurface;
|
|
||||||
private boolean mWaitingForSurface;
|
|
||||||
private boolean mHaveEgl;
|
|
||||||
private int mWidth;
|
|
||||||
private int mHeight;
|
|
||||||
private int mRenderMode;
|
|
||||||
private boolean mRequestRender;
|
|
||||||
private boolean mEventsWaiting;
|
|
||||||
// End of member variables protected by the sGLThreadManager monitor.
|
|
||||||
|
|
||||||
//private GLWallpaperService.Renderer mRenderer;
|
|
||||||
|
|
||||||
private ArrayList mEventQueue = new ArrayList();
|
|
||||||
private EglHelper mEglHelper;
|
|
||||||
|
|
||||||
|
|
||||||
static long lastTimeStamp;
|
|
||||||
static boolean gameIsInited = false;
|
|
||||||
|
|
||||||
GLThread(EGLConfigChooser chooser,
|
|
||||||
EGLContextFactory contextFactory,
|
|
||||||
EGLWindowSurfaceFactory surfaceFactory) {
|
|
||||||
super();
|
|
||||||
mDone = false;
|
|
||||||
mWidth = 0;
|
|
||||||
mHeight = 0;
|
|
||||||
mRequestRender = true;
|
|
||||||
mRenderMode = GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY;
|
|
||||||
|
|
||||||
this.mEGLConfigChooser = chooser;
|
|
||||||
this.mEGLContextFactory = contextFactory;
|
|
||||||
this.mEGLWindowSurfaceFactory = surfaceFactory;
|
|
||||||
|
|
||||||
Calendar c = Calendar.getInstance();
|
|
||||||
lastTimeStamp = c.getTimeInMillis();
|
|
||||||
gameIsInited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
setName("GLThread " + getId());
|
|
||||||
if (LOG_THREADS) {
|
|
||||||
Log.i("GLThread", "starting tid=" + getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
guardedRun();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// fall thru and exit normally
|
|
||||||
} finally {
|
|
||||||
sGLThreadManager.threadExiting(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This private method should only be called inside a
|
|
||||||
* synchronized(sGLThreadManager) block.
|
|
||||||
*/
|
|
||||||
private void stopEglLocked() {
|
|
||||||
if (mHaveEgl) {
|
|
||||||
mHaveEgl = false;
|
|
||||||
mEglHelper.destroySurface();
|
|
||||||
sGLThreadManager.releaseEglSurface(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void guardedRun() throws InterruptedException {
|
|
||||||
mEglHelper = new EglHelper(mEGLConfigChooser, mEGLContextFactory,
|
|
||||||
mEGLWindowSurfaceFactory/*, mGLWrapper*/);
|
|
||||||
try {
|
|
||||||
|
|
||||||
boolean tellRendererSurfaceCreated = true;
|
|
||||||
boolean tellRendererSurfaceChanged = true;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is our main activity thread's loop, we go until asked to
|
|
||||||
* quit.
|
|
||||||
*/
|
|
||||||
while (!isDone()) {
|
|
||||||
/*
|
|
||||||
* Update the asynchronous state (window size)
|
|
||||||
*/
|
|
||||||
int w = 0;
|
|
||||||
int h = 0;
|
|
||||||
boolean changed = false;
|
|
||||||
boolean needStart = false;
|
|
||||||
boolean eventsWaiting = false;
|
|
||||||
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
while (true) {
|
|
||||||
// Manage acquiring and releasing the SurfaceView
|
|
||||||
// surface and the EGL surface.
|
|
||||||
if (mPaused) {
|
|
||||||
stopEglLocked();
|
|
||||||
}
|
|
||||||
if (!mHasSurface) {
|
|
||||||
if (!mWaitingForSurface) {
|
|
||||||
stopEglLocked();
|
|
||||||
mWaitingForSurface = true;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!mHaveEgl) {
|
|
||||||
if (sGLThreadManager.tryAcquireEglSurface(this)) {
|
|
||||||
mHaveEgl = true;
|
|
||||||
mEglHelper.start();
|
|
||||||
mRequestRender = true;
|
|
||||||
needStart = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we need to wait. If not, update any state
|
|
||||||
// that needs to be updated, copy any state that
|
|
||||||
// needs to be copied, and use "break" to exit the
|
|
||||||
// wait loop.
|
|
||||||
|
|
||||||
if (mDone) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mEventsWaiting) {
|
|
||||||
eventsWaiting = true;
|
|
||||||
mEventsWaiting = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!mPaused)
|
|
||||||
&& mHasSurface
|
|
||||||
&& mHaveEgl
|
|
||||||
&& (mWidth > 0)
|
|
||||||
&& (mHeight > 0)
|
|
||||||
&& (mRequestRender || (mRenderMode == GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY))) {
|
|
||||||
changed = mSizeChanged;
|
|
||||||
w = mWidth;
|
|
||||||
h = mHeight;
|
|
||||||
mSizeChanged = false;
|
|
||||||
mRequestRender = false;
|
|
||||||
if (mHasSurface && mWaitingForSurface) {
|
|
||||||
changed = true;
|
|
||||||
mWaitingForSurface = false;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// By design, this is the only place where we wait().
|
|
||||||
|
|
||||||
if (LOG_THREADS) {
|
|
||||||
Log.i("GLThread", "waiting tid=" + getId());
|
|
||||||
}
|
|
||||||
sGLThreadManager.wait();
|
|
||||||
}
|
|
||||||
} // end of synchronized(sGLThreadManager)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle queued events
|
|
||||||
*/
|
|
||||||
if (eventsWaiting) {
|
|
||||||
Runnable r;
|
|
||||||
while ((r = getEvent()) != null) {
|
|
||||||
r.run();
|
|
||||||
if (isDone()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Go back and see if we need to wait to render.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needStart) {
|
|
||||||
tellRendererSurfaceCreated = true;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (changed) {
|
|
||||||
mEglHelper.createSurface(mHolder);
|
|
||||||
tellRendererSurfaceChanged = true;
|
|
||||||
}
|
|
||||||
if (tellRendererSurfaceCreated) {
|
|
||||||
|
|
||||||
tellRendererSurfaceCreated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tellRendererSurfaceChanged) {
|
|
||||||
|
|
||||||
|
|
||||||
//Xperimental -- VLAD KHOREV
|
|
||||||
JniWrapper.Init(w, h);
|
|
||||||
|
|
||||||
tellRendererSurfaceChanged = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ((w > 0) && (h > 0)) {
|
|
||||||
/* draw a frame here */
|
|
||||||
|
|
||||||
if (gameIsInited)
|
|
||||||
{
|
|
||||||
Calendar c = Calendar.getInstance();
|
|
||||||
|
|
||||||
long currentTimeStamp = c.getTimeInMillis();
|
|
||||||
|
|
||||||
EngineWrapper.Update(currentTimeStamp - lastTimeStamp);
|
|
||||||
|
|
||||||
lastTimeStamp = currentTimeStamp;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Once we're done with GL, we need to call swapBuffers() to
|
|
||||||
* instruct the system to display the rendered frame
|
|
||||||
*/
|
|
||||||
mEglHelper.swap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
/*
|
|
||||||
* clean-up everything...
|
|
||||||
*/
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
stopEglLocked();
|
|
||||||
mEglHelper.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isDone() {
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
return mDone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRenderMode(int renderMode) {
|
|
||||||
if (!((GLWallpaperService.GLEngine.RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY))) {
|
|
||||||
throw new IllegalArgumentException("renderMode");
|
|
||||||
}
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
mRenderMode = renderMode;
|
|
||||||
if (renderMode == GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY) {
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRenderMode() {
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
return mRenderMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestRender() {
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
mRequestRender = true;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
|
||||||
mHolder = holder;
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
if (LOG_THREADS) {
|
|
||||||
Log.i("GLThread", "surfaceCreated tid=" + getId());
|
|
||||||
}
|
|
||||||
mHasSurface = true;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void surfaceDestroyed() {
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
if (LOG_THREADS) {
|
|
||||||
Log.i("GLThread", "surfaceDestroyed tid=" + getId());
|
|
||||||
}
|
|
||||||
mHasSurface = false;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
while (!mWaitingForSurface && isAlive() && !mDone) {
|
|
||||||
try {
|
|
||||||
sGLThreadManager.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onPause() {
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
mPaused = true;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onResume() {
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
mPaused = false;
|
|
||||||
mRequestRender = true;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onWindowResize(int w, int h) {
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
mWidth = w;
|
|
||||||
mHeight = h;
|
|
||||||
mSizeChanged = true;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestExitAndWait() {
|
|
||||||
// don't call this from GLThread thread or it is a guaranteed
|
|
||||||
// deadlock!
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
mDone = true;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
join();
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queue an "event" to be run on the GL rendering thread.
|
|
||||||
*
|
|
||||||
* @param r
|
|
||||||
* the runnable to be run on the GL rendering thread.
|
|
||||||
*/
|
|
||||||
public void queueEvent(Runnable r) {
|
|
||||||
synchronized (this) {
|
|
||||||
mEventQueue.add(r);
|
|
||||||
synchronized (sGLThreadManager) {
|
|
||||||
mEventsWaiting = true;
|
|
||||||
sGLThreadManager.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Runnable getEvent() {
|
|
||||||
synchronized (this) {
|
|
||||||
if (mEventQueue.size() > 0) {
|
|
||||||
return (Runnable) mEventQueue.remove(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class GLThreadManager {
|
|
||||||
|
|
||||||
public synchronized void threadExiting(GLThread thread) {
|
|
||||||
if (LOG_THREADS) {
|
|
||||||
Log.i("GLThread", "exiting tid=" + thread.getId());
|
|
||||||
}
|
|
||||||
thread.mDone = true;
|
|
||||||
if (mEglOwner == thread) {
|
|
||||||
mEglOwner = null;
|
|
||||||
}
|
|
||||||
notifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tries once to acquire the right to use an EGL surface. Does not
|
|
||||||
* block.
|
|
||||||
*
|
|
||||||
* @return true if the right to use an EGL surface was acquired.
|
|
||||||
*/
|
|
||||||
public synchronized boolean tryAcquireEglSurface(GLThread thread) {
|
|
||||||
if (mEglOwner == thread || mEglOwner == null) {
|
|
||||||
mEglOwner = thread;
|
|
||||||
notifyAll();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void releaseEglSurface(GLThread thread) {
|
|
||||||
if (mEglOwner == thread) {
|
|
||||||
mEglOwner = null;
|
|
||||||
}
|
|
||||||
notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EGLConfigChooser {
|
|
||||||
EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class BaseConfigChooser implements EGLConfigChooser {
|
|
||||||
public BaseConfigChooser(int[] configSpec) {
|
|
||||||
mConfigSpec = configSpec;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
|
|
||||||
int[] num_config = new int[1];
|
|
||||||
egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config);
|
|
||||||
|
|
||||||
int numConfigs = num_config[0];
|
|
||||||
|
|
||||||
if (numConfigs <= 0) {
|
|
||||||
throw new IllegalArgumentException("No configs match configSpec");
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLConfig[] configs = new EGLConfig[numConfigs];
|
|
||||||
egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
|
|
||||||
num_config);
|
|
||||||
EGLConfig config = chooseConfig(egl, display, configs);
|
|
||||||
if (config == null) {
|
|
||||||
throw new IllegalArgumentException("No config chosen");
|
|
||||||
}
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
|
|
||||||
EGLConfig[] configs);
|
|
||||||
|
|
||||||
protected int[] mConfigSpec;
|
|
||||||
|
|
||||||
public static class ComponentSizeChooser extends BaseConfigChooser {
|
|
||||||
public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
|
|
||||||
int alphaSize, int depthSize, int stencilSize) {
|
|
||||||
super(new int[] { EGL10.EGL_RED_SIZE, redSize,
|
|
||||||
EGL10.EGL_GREEN_SIZE, greenSize, EGL10.EGL_BLUE_SIZE,
|
|
||||||
blueSize, EGL10.EGL_ALPHA_SIZE, alphaSize,
|
|
||||||
EGL10.EGL_DEPTH_SIZE, depthSize, EGL10.EGL_STENCIL_SIZE,
|
|
||||||
stencilSize, EGL10.EGL_NONE });
|
|
||||||
mValue = new int[1];
|
|
||||||
mRedSize = redSize;
|
|
||||||
mGreenSize = greenSize;
|
|
||||||
mBlueSize = blueSize;
|
|
||||||
mAlphaSize = alphaSize;
|
|
||||||
mDepthSize = depthSize;
|
|
||||||
mStencilSize = stencilSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
|
|
||||||
EGLConfig[] configs) {
|
|
||||||
EGLConfig closestConfig = null;
|
|
||||||
int closestDistance = 1000;
|
|
||||||
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);
|
|
||||||
if (d >= mDepthSize && s >= mStencilSize) {
|
|
||||||
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 distance = Math.abs(r - mRedSize)
|
|
||||||
+ Math.abs(g - mGreenSize)
|
|
||||||
+ Math.abs(b - mBlueSize)
|
|
||||||
+ Math.abs(a - mAlphaSize);
|
|
||||||
if (distance < closestDistance) {
|
|
||||||
closestDistance = distance;
|
|
||||||
closestConfig = config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return closestConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 int[] mValue;
|
|
||||||
// Subclasses can adjust these values:
|
|
||||||
protected int mRedSize;
|
|
||||||
protected int mGreenSize;
|
|
||||||
protected int mBlueSize;
|
|
||||||
protected int mAlphaSize;
|
|
||||||
protected int mDepthSize;
|
|
||||||
protected int mStencilSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class will choose a supported surface as close to RGB565 as
|
|
||||||
* possible, with or without a depth buffer.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static class SimpleEGLConfigChooser extends ComponentSizeChooser {
|
|
||||||
public SimpleEGLConfigChooser(boolean withDepthBuffer) {
|
|
||||||
super(4, 4, 4, 0, withDepthBuffer ? 16 : 0, 0);
|
|
||||||
// Adjust target values. This way we'll accept a 4444 or
|
|
||||||
// 555 buffer if there's no 565 buffer available.
|
|
||||||
mRedSize = 5;
|
|
||||||
mGreenSize = 6;
|
|
||||||
mBlueSize = 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,764 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fishrungames.mountainwallpaper
|
||||||
|
|
||||||
|
import java.io.Writer
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
import javax.microedition.khronos.egl.EGL10
|
||||||
|
import javax.microedition.khronos.egl.EGL11
|
||||||
|
import javax.microedition.khronos.egl.EGLConfig
|
||||||
|
import javax.microedition.khronos.egl.EGLContext
|
||||||
|
import javax.microedition.khronos.egl.EGLDisplay
|
||||||
|
import javax.microedition.khronos.egl.EGLSurface
|
||||||
|
import javax.microedition.khronos.opengles.GL
|
||||||
|
import javax.microedition.khronos.opengles.GL10
|
||||||
|
|
||||||
|
import android.opengl.GLSurfaceView
|
||||||
|
import android.service.wallpaper.WallpaperService
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.SurfaceHolder
|
||||||
|
|
||||||
|
// Original code provided by Robert Green
|
||||||
|
// http://www.rbgrn.net/content/354-glsurfaceview-adapted-3d-live-wallpapers
|
||||||
|
|
||||||
|
open class GLWallpaperService : WallpaperService() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = "GLWallpaperService"
|
||||||
|
val RENDERMODE_WHEN_DIRTY = 0;
|
||||||
|
val RENDERMODE_CONTINUOUSLY = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateEngine(): WallpaperService.Engine {
|
||||||
|
return GLEngine()
|
||||||
|
}
|
||||||
|
|
||||||
|
open inner class GLEngine : WallpaperService.Engine() {
|
||||||
|
|
||||||
|
private var mGLThread: GLThread? = null
|
||||||
|
private var mEGLConfigChooser: GLSurfaceView.EGLConfigChooser? = null
|
||||||
|
private var mEGLContextFactory: GLSurfaceView.EGLContextFactory? = null
|
||||||
|
private var mEGLWindowSurfaceFactory: GLSurfaceView.EGLWindowSurfaceFactory? = null
|
||||||
|
private var mEGLContextClientVersion: Int = 0
|
||||||
|
var renderMode: Int
|
||||||
|
get() = mGLThread!!.renderMode
|
||||||
|
set(renderMode) {
|
||||||
|
mGLThread!!.renderMode = renderMode
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onVisibilityChanged(visible: Boolean) {
|
||||||
|
if (visible) {
|
||||||
|
onResume()
|
||||||
|
} else {
|
||||||
|
onPause()
|
||||||
|
}
|
||||||
|
super.onVisibilityChanged(visible)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
// Log.d(TAG, "GLEngine.onDestroy()");
|
||||||
|
mGLThread!!.requestExitAndWait()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSurfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||||
|
// Log.d(TAG, "onSurfaceChanged()");
|
||||||
|
mGLThread!!.onWindowResize(width, height)
|
||||||
|
super.onSurfaceChanged(holder, format, width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSurfaceCreated(holder: SurfaceHolder) {
|
||||||
|
Log.d(TAG, "onSurfaceCreated()")
|
||||||
|
mGLThread!!.surfaceCreated(holder)
|
||||||
|
super.onSurfaceCreated(holder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSurfaceDestroyed(holder: SurfaceHolder) {
|
||||||
|
Log.d(TAG, "onSurfaceDestroyed()")
|
||||||
|
mGLThread!!.surfaceDestroyed()
|
||||||
|
super.onSurfaceDestroyed(holder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setRenderer(renderer: GLSurfaceView.Renderer) {
|
||||||
|
checkRenderThreadState()
|
||||||
|
|
||||||
|
var mEGLConfigChooser = this.mEGLConfigChooser;
|
||||||
|
var mEGLContextFactory = this.mEGLContextFactory;
|
||||||
|
var mEGLWindowSurfaceFactory = this.mEGLWindowSurfaceFactory;
|
||||||
|
|
||||||
|
if (mEGLConfigChooser == null) {
|
||||||
|
mEGLConfigChooser = BaseConfigChooser.SimpleEGLConfigChooser(true, mEGLContextClientVersion)
|
||||||
|
}
|
||||||
|
if (mEGLContextFactory == null) {
|
||||||
|
mEGLContextFactory = DefaultContextFactory(mEGLContextClientVersion)
|
||||||
|
}
|
||||||
|
if (mEGLWindowSurfaceFactory == null) {
|
||||||
|
mEGLWindowSurfaceFactory = DefaultWindowSurfaceFactory()
|
||||||
|
}
|
||||||
|
mGLThread = GLThread(renderer, mEGLConfigChooser, mEGLContextFactory, mEGLWindowSurfaceFactory)
|
||||||
|
mGLThread!!.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEGLContextFactory(factory: GLSurfaceView.EGLContextFactory) {
|
||||||
|
checkRenderThreadState()
|
||||||
|
mEGLContextFactory = factory
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEGLWindowSurfaceFactory(factory: GLSurfaceView.EGLWindowSurfaceFactory) {
|
||||||
|
checkRenderThreadState()
|
||||||
|
mEGLWindowSurfaceFactory = factory
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEGLConfigChooser(configChooser: GLSurfaceView.EGLConfigChooser) {
|
||||||
|
checkRenderThreadState()
|
||||||
|
mEGLConfigChooser = configChooser
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEGLConfigChooser(needDepth: Boolean) {
|
||||||
|
setEGLConfigChooser(BaseConfigChooser.SimpleEGLConfigChooser(needDepth, mEGLContextClientVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEGLConfigChooser(redSize: Int, greenSize: Int, blueSize: Int, alphaSize: Int, depthSize: Int,
|
||||||
|
stencilSize: Int) {
|
||||||
|
setEGLConfigChooser(
|
||||||
|
BaseConfigChooser.ComponentSizeChooser(redSize, greenSize, blueSize, alphaSize,
|
||||||
|
depthSize,
|
||||||
|
stencilSize, mEGLContextClientVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEGLContextClientVersion(version: Int) {
|
||||||
|
checkRenderThreadState()
|
||||||
|
mEGLContextClientVersion = version
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun requestRender() {
|
||||||
|
mGLThread!!.requestRender()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPause() {
|
||||||
|
mGLThread!!.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onResume() {
|
||||||
|
mGLThread!!.onResume()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun queueEvent(r: Runnable) {
|
||||||
|
mGLThread!!.queueEvent(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkRenderThreadState() {
|
||||||
|
if (mGLThread != null) {
|
||||||
|
throw IllegalStateException("setRenderer has already been called for this instance.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LogWriter : Writer() {
|
||||||
|
private val mBuilder = StringBuilder()
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
flushBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun flush() {
|
||||||
|
flushBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(buf: CharArray, offset: Int, count: Int) {
|
||||||
|
for (i in 0 until count) {
|
||||||
|
val c = buf[offset + i]
|
||||||
|
if (c == '\n') {
|
||||||
|
flushBuilder()
|
||||||
|
} else {
|
||||||
|
mBuilder.append(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun flushBuilder() {
|
||||||
|
if (mBuilder.length > 0) {
|
||||||
|
Log.v("GLSurfaceView", mBuilder.toString())
|
||||||
|
mBuilder.delete(0, mBuilder.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
internal class DefaultContextFactory(val eglContextClientVersion : Int) : GLSurfaceView.EGLContextFactory {
|
||||||
|
|
||||||
|
private val EGL_CONTEXT_CLIENT_VERSION = 0x3098
|
||||||
|
|
||||||
|
override fun createContext(egl: EGL10, display: EGLDisplay, config: EGLConfig): EGLContext {
|
||||||
|
val attrib_list = intArrayOf(EGL_CONTEXT_CLIENT_VERSION, eglContextClientVersion, EGL10.EGL_NONE)
|
||||||
|
return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
|
||||||
|
if (eglContextClientVersion != 0) attrib_list else null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun destroyContext(egl: EGL10, display: EGLDisplay, context: EGLContext) {
|
||||||
|
egl.eglDestroyContext(display, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultWindowSurfaceFactory : GLSurfaceView.EGLWindowSurfaceFactory {
|
||||||
|
|
||||||
|
override fun createWindowSurface(egl: EGL10, display: EGLDisplay, config: EGLConfig, nativeWindow: Any): EGLSurface {
|
||||||
|
// this is a bit of a hack to work around Droid init problems - if you don't have this, it'll get hung up on orientation changes
|
||||||
|
var eglSurface: EGLSurface? = null
|
||||||
|
while (eglSurface == null) {
|
||||||
|
try {
|
||||||
|
eglSurface = egl.eglCreateWindowSurface(display,
|
||||||
|
config, nativeWindow, null)
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
} finally {
|
||||||
|
if (eglSurface == null) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10)
|
||||||
|
} catch (t: InterruptedException) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eglSurface
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun destroySurface(egl: EGL10, display: EGLDisplay, surface: EGLSurface) {
|
||||||
|
egl.eglDestroySurface(display, surface)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class EglHelper(private val mEGLConfigChooser: GLSurfaceView.EGLConfigChooser, private val mEGLContextFactory: GLSurfaceView.EGLContextFactory,
|
||||||
|
private val mEGLWindowSurfaceFactory: GLSurfaceView.EGLWindowSurfaceFactory) {
|
||||||
|
|
||||||
|
private var mEgl: EGL10? = null
|
||||||
|
private var mEglDisplay: EGLDisplay? = null
|
||||||
|
private var mEglSurface: EGLSurface? = null
|
||||||
|
private var mEglContext: EGLContext? = null
|
||||||
|
var mEglConfig: EGLConfig? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize EGL for a given configuration spec.
|
||||||
|
*
|
||||||
|
* @param configSpec
|
||||||
|
*/
|
||||||
|
fun start() {
|
||||||
|
// Log.d("EglHelper" + instanceId, "start()");
|
||||||
|
if (mEgl == null) {
|
||||||
|
// Log.d("EglHelper" + instanceId, "getting new EGL");
|
||||||
|
/*
|
||||||
|
* Get an EGL instance
|
||||||
|
*/
|
||||||
|
mEgl = EGLContext.getEGL() as EGL10
|
||||||
|
} else {
|
||||||
|
// Log.d("EglHelper" + instanceId, "reusing EGL");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEglDisplay == null) {
|
||||||
|
// Log.d("EglHelper" + instanceId, "getting new display");
|
||||||
|
/*
|
||||||
|
* Get to the default display.
|
||||||
|
*/
|
||||||
|
mEglDisplay = mEgl!!.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
|
||||||
|
} else {
|
||||||
|
// Log.d("EglHelper" + instanceId, "reusing display");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEglConfig == null) {
|
||||||
|
// Log.d("EglHelper" + instanceId, "getting new config");
|
||||||
|
/*
|
||||||
|
* We can now initialize EGL for that display
|
||||||
|
*/
|
||||||
|
val version = IntArray(2)
|
||||||
|
mEgl!!.eglInitialize(mEglDisplay, version)
|
||||||
|
mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay)
|
||||||
|
} else {
|
||||||
|
// Log.d("EglHelper" + instanceId, "reusing config");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEglContext == null) {
|
||||||
|
// Log.d("EglHelper" + instanceId, "creating new context");
|
||||||
|
/*
|
||||||
|
* Create an OpenGL ES context. This must be done only once, an OpenGL context is a somewhat heavy object.
|
||||||
|
*/
|
||||||
|
mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig)
|
||||||
|
if (mEglContext == null || mEglContext === EGL10.EGL_NO_CONTEXT) {
|
||||||
|
throw RuntimeException("createContext failed")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Log.d("EglHelper" + instanceId, "reusing context");
|
||||||
|
}
|
||||||
|
|
||||||
|
mEglSurface = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* React to the creation of a new surface by creating and returning an OpenGL interface that renders to that
|
||||||
|
* surface.
|
||||||
|
*/
|
||||||
|
fun createSurface(holder: SurfaceHolder): GL {
|
||||||
|
/*
|
||||||
|
* The window size has changed, so we need to create a new surface.
|
||||||
|
*/
|
||||||
|
if (mEglSurface != null && mEglSurface !== EGL10.EGL_NO_SURFACE) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unbind and destroy the old EGL surface, if there is one.
|
||||||
|
*/
|
||||||
|
mEgl!!.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)
|
||||||
|
mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an EGL surface we can render into.
|
||||||
|
*/
|
||||||
|
mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl, mEglDisplay, mEglConfig, holder)
|
||||||
|
|
||||||
|
if (mEglSurface == null || mEglSurface === EGL10.EGL_NO_SURFACE) {
|
||||||
|
throw RuntimeException("createWindowSurface failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Before we can issue GL commands, we need to make sure the context is current and bound to a surface.
|
||||||
|
*/
|
||||||
|
if (!mEgl!!.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
|
||||||
|
throw RuntimeException("eglMakeCurrent failed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
var gl = mEglContext!!.gl
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if ((mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS))!= 0) { int configFlags = 0; Writer log =
|
||||||
|
* null; if ((mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; }
|
||||||
|
* if ((mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { log = new LogWriter(); } gl = GLDebugHelper.wrap(gl,
|
||||||
|
* configFlags, log); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
return gl
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the current render surface.
|
||||||
|
*
|
||||||
|
* @return false if the context has been lost.
|
||||||
|
*/
|
||||||
|
fun swap(): Boolean {
|
||||||
|
mEgl!!.eglSwapBuffers(mEglDisplay, mEglSurface)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Always check for EGL_CONTEXT_LOST, which means the context and all associated data were lost (For instance
|
||||||
|
* because the device went to sleep). We need to sleep until we get a new surface.
|
||||||
|
*/
|
||||||
|
return mEgl!!.eglGetError() != EGL11.EGL_CONTEXT_LOST
|
||||||
|
}
|
||||||
|
|
||||||
|
fun destroySurface() {
|
||||||
|
if (mEglSurface != null && mEglSurface !== EGL10.EGL_NO_SURFACE) {
|
||||||
|
mEgl!!.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)
|
||||||
|
mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface)
|
||||||
|
mEglSurface = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun finish() {
|
||||||
|
if (mEglContext != null) {
|
||||||
|
mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext)
|
||||||
|
mEglContext = null
|
||||||
|
}
|
||||||
|
if (mEglDisplay != null) {
|
||||||
|
mEgl!!.eglTerminate(mEglDisplay)
|
||||||
|
mEglDisplay = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class GLThread
|
||||||
|
(
|
||||||
|
// End of member variables protected by the sGLThreadManager monitor.
|
||||||
|
|
||||||
|
private val mRenderer: GLSurfaceView.Renderer, private val mEGLConfigChooser: GLSurfaceView.EGLConfigChooser, private val mEGLContextFactory: GLSurfaceView.EGLContextFactory,
|
||||||
|
private val mEGLWindowSurfaceFactory: GLSurfaceView.EGLWindowSurfaceFactory) : Thread() {
|
||||||
|
|
||||||
|
private val sGLThreadManager = GLThreadManager()
|
||||||
|
private var mEglOwner: GLThread? = null
|
||||||
|
|
||||||
|
lateinit var mHolder: SurfaceHolder
|
||||||
|
private var mSizeChanged = true
|
||||||
|
|
||||||
|
// Once the thread is started, all accesses to the following member
|
||||||
|
// variables are protected by the sGLThreadManager monitor
|
||||||
|
var mDone: Boolean = false
|
||||||
|
private var mPaused: Boolean = false
|
||||||
|
private var mHasSurface: Boolean = false
|
||||||
|
private var mWaitingForSurface: Boolean = false
|
||||||
|
private var mHaveEgl: Boolean = false
|
||||||
|
private var mWidth: Int = 0
|
||||||
|
private var mHeight: Int = 0
|
||||||
|
private var mRenderMode: Int = 0
|
||||||
|
private var mRequestRender: Boolean = false
|
||||||
|
private var mEventsWaiting: Boolean = false
|
||||||
|
private val mEventQueue = ArrayList<Runnable>()
|
||||||
|
private var mEglHelper: EglHelper? = null
|
||||||
|
|
||||||
|
private val isDone: Boolean
|
||||||
|
get() = synchronized(sGLThreadManager.lockObject) {
|
||||||
|
return mDone
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderMode: Int
|
||||||
|
get() = synchronized(sGLThreadManager.lockObject) {
|
||||||
|
return mRenderMode
|
||||||
|
}
|
||||||
|
set(renderMode) {
|
||||||
|
if (!(GLWallpaperService.RENDERMODE_WHEN_DIRTY <= renderMode && renderMode <= GLWallpaperService.RENDERMODE_CONTINUOUSLY)) {
|
||||||
|
throw IllegalArgumentException("renderMode")
|
||||||
|
}
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
mRenderMode = renderMode
|
||||||
|
if (renderMode == GLWallpaperService.RENDERMODE_CONTINUOUSLY) {
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val event: Runnable?
|
||||||
|
get() {
|
||||||
|
synchronized(this) {
|
||||||
|
if (mEventQueue.size > 0) {
|
||||||
|
return mEventQueue.removeAt(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
mDone = false
|
||||||
|
mWidth = 0
|
||||||
|
mHeight = 0
|
||||||
|
mRequestRender = true
|
||||||
|
mRenderMode = GLWallpaperService.RENDERMODE_CONTINUOUSLY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
name = "GLThread $id"
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "starting tid=$id")
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
guardedRun()
|
||||||
|
} catch (e: InterruptedException) {
|
||||||
|
// fall thru and exit normally
|
||||||
|
} finally {
|
||||||
|
sGLThreadManager.threadExiting(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This private method should only be called inside a synchronized(sGLThreadManager.lockObject) block.
|
||||||
|
*/
|
||||||
|
private fun stopEglLocked() {
|
||||||
|
if (mHaveEgl) {
|
||||||
|
mHaveEgl = false
|
||||||
|
mEglHelper!!.destroySurface()
|
||||||
|
sGLThreadManager.releaseEglSurface(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(InterruptedException::class)
|
||||||
|
private fun guardedRun() {
|
||||||
|
mEglHelper = EglHelper(mEGLConfigChooser, mEGLContextFactory, mEGLWindowSurfaceFactory)
|
||||||
|
try {
|
||||||
|
var gl: GL10? = null
|
||||||
|
var tellRendererSurfaceCreated = true
|
||||||
|
var tellRendererSurfaceChanged = true
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is our main activity thread's loop, we go until asked to quit.
|
||||||
|
*/
|
||||||
|
while (!isDone) {
|
||||||
|
/*
|
||||||
|
* Update the asynchronous state (window size)
|
||||||
|
*/
|
||||||
|
var w = 0
|
||||||
|
var h = 0
|
||||||
|
var changed = false
|
||||||
|
var needStart = false
|
||||||
|
var eventsWaiting = false
|
||||||
|
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
while (true) {
|
||||||
|
// Manage acquiring and releasing the SurfaceView
|
||||||
|
// surface and the EGL surface.
|
||||||
|
if (mPaused) {
|
||||||
|
stopEglLocked()
|
||||||
|
}
|
||||||
|
if (!mHasSurface) {
|
||||||
|
if (!mWaitingForSurface) {
|
||||||
|
stopEglLocked()
|
||||||
|
mWaitingForSurface = true
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!mHaveEgl) {
|
||||||
|
if (sGLThreadManager.tryAcquireEglSurface(this)) {
|
||||||
|
mHaveEgl = true
|
||||||
|
mEglHelper!!.start()
|
||||||
|
mRequestRender = true
|
||||||
|
needStart = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we need to wait. If not, update any state
|
||||||
|
// that needs to be updated, copy any state that
|
||||||
|
// needs to be copied, and use "break" to exit the
|
||||||
|
// wait loop.
|
||||||
|
|
||||||
|
if (mDone) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEventsWaiting) {
|
||||||
|
eventsWaiting = true
|
||||||
|
mEventsWaiting = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mPaused && mHasSurface && mHaveEgl && mWidth > 0 && mHeight > 0
|
||||||
|
&& (mRequestRender || mRenderMode == GLWallpaperService.RENDERMODE_CONTINUOUSLY)) {
|
||||||
|
changed = mSizeChanged
|
||||||
|
w = mWidth
|
||||||
|
h = mHeight
|
||||||
|
mSizeChanged = false
|
||||||
|
mRequestRender = false
|
||||||
|
if (mHasSurface && mWaitingForSurface) {
|
||||||
|
changed = true
|
||||||
|
mWaitingForSurface = false
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// By design, this is the only place where we wait().
|
||||||
|
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "waiting tid=$id")
|
||||||
|
}
|
||||||
|
sGLThreadManager.lockObject.wait()
|
||||||
|
}
|
||||||
|
} // end of synchronized(sGLThreadManager.lockObject)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle queued events
|
||||||
|
*/
|
||||||
|
if (eventsWaiting) {
|
||||||
|
var r: Runnable? = event
|
||||||
|
while (r != null) {
|
||||||
|
r!!.run()
|
||||||
|
if (isDone) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Go back and see if we need to wait to render.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needStart) {
|
||||||
|
tellRendererSurfaceCreated = true
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
gl = mEglHelper!!.createSurface(mHolder) as GL10
|
||||||
|
tellRendererSurfaceChanged = true
|
||||||
|
}
|
||||||
|
if (tellRendererSurfaceCreated) {
|
||||||
|
mRenderer.onSurfaceCreated(gl, mEglHelper!!.mEglConfig)
|
||||||
|
tellRendererSurfaceCreated = false
|
||||||
|
}
|
||||||
|
if (tellRendererSurfaceChanged) {
|
||||||
|
mRenderer.onSurfaceChanged(gl, w, h)
|
||||||
|
tellRendererSurfaceChanged = false
|
||||||
|
}
|
||||||
|
if (w > 0 && h > 0) {
|
||||||
|
/* draw a frame here */
|
||||||
|
mRenderer.onDrawFrame(gl)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Once we're done with GL, we need to call swapBuffers() to instruct the system to display the
|
||||||
|
* rendered frame
|
||||||
|
*/
|
||||||
|
mEglHelper!!.swap()
|
||||||
|
Thread.sleep(10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
/*
|
||||||
|
* clean-up everything...
|
||||||
|
*/
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
stopEglLocked()
|
||||||
|
mEglHelper!!.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestRender() {
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
mRequestRender = true
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun surfaceCreated(holder: SurfaceHolder) {
|
||||||
|
mHolder = holder
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "surfaceCreated tid=$id")
|
||||||
|
}
|
||||||
|
mHasSurface = true
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun surfaceDestroyed() {
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "surfaceDestroyed tid=$id")
|
||||||
|
}
|
||||||
|
mHasSurface = false
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
while (!mWaitingForSurface && isAlive && !mDone) {
|
||||||
|
try {
|
||||||
|
sGLThreadManager.lockObject.wait()
|
||||||
|
} catch (e: InterruptedException) {
|
||||||
|
Thread.currentThread().interrupt()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPause() {
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
mPaused = true
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onResume() {
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
mPaused = false
|
||||||
|
mRequestRender = true
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onWindowResize(w: Int, h: Int) {
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
mWidth = w
|
||||||
|
mHeight = h
|
||||||
|
mSizeChanged = true
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestExitAndWait() {
|
||||||
|
// don't call this from GLThread thread or it is a guaranteed
|
||||||
|
// deadlock!
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
mDone = true
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
join()
|
||||||
|
} catch (ex: InterruptedException) {
|
||||||
|
Thread.currentThread().interrupt()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue an "event" to be run on the GL rendering thread.
|
||||||
|
*
|
||||||
|
* @param r
|
||||||
|
* the runnable to be run on the GL rendering thread.
|
||||||
|
*/
|
||||||
|
fun queueEvent(r: Runnable) {
|
||||||
|
synchronized(this) {
|
||||||
|
mEventQueue.add(r)
|
||||||
|
synchronized(sGLThreadManager.lockObject) {
|
||||||
|
mEventsWaiting = true
|
||||||
|
sGLThreadManager.lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class GLThreadManager {
|
||||||
|
|
||||||
|
val lockObject = Object()
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun threadExiting(thread: GLThread) {
|
||||||
|
synchronized(lockObject)
|
||||||
|
{
|
||||||
|
if (LOG_THREADS) {
|
||||||
|
Log.i("GLThread", "exiting tid=" + thread.id)
|
||||||
|
}
|
||||||
|
thread.mDone = true
|
||||||
|
if (mEglOwner === thread) {
|
||||||
|
mEglOwner = null
|
||||||
|
}
|
||||||
|
lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tries once to acquire the right to use an EGL surface. Does not block.
|
||||||
|
*
|
||||||
|
* @return true if the right to use an EGL surface was acquired.
|
||||||
|
*/
|
||||||
|
@Synchronized
|
||||||
|
fun tryAcquireEglSurface(thread: GLThread): Boolean {
|
||||||
|
if (mEglOwner === thread || mEglOwner == null) {
|
||||||
|
mEglOwner = thread
|
||||||
|
lockObject.notifyAll()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun releaseEglSurface(thread: GLThread) {
|
||||||
|
if (mEglOwner === thread) {
|
||||||
|
mEglOwner = null
|
||||||
|
}
|
||||||
|
lockObject.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOG_THREADS = false
|
||||||
|
val DEBUG_CHECK_GL_ERROR = 1
|
||||||
|
val DEBUG_LOG_GL_CALLS = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,25 +1,17 @@
|
|||||||
package fishrungames.mountainwallpaper;
|
package fishrungames.mountainwallpaper;
|
||||||
|
|
||||||
public class JniWrapper
|
class JniWrapper
|
||||||
{
|
{
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
System.loadLibrary("MountainWallpaper");
|
System.loadLibrary("MountainWallpaper");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LoadLibrary()
|
|
||||||
{
|
|
||||||
//To force loading libraries
|
|
||||||
}
|
|
||||||
|
|
||||||
public static native void SetTimeOfDayPref(int timeofday);
|
public static native void SetTimeOfDayPref(int timeofday);
|
||||||
|
|
||||||
public static native void SetSnowPref(boolean snow);
|
public static native void SetSnowPref(boolean snow);
|
||||||
|
|
||||||
|
|
||||||
public static native void Init(int width, int height);
|
public static native void Init(int width, int height);
|
||||||
|
|
||||||
public static native void SetOffset(float offsetX, float offsetY);
|
public static native void SetOffset(float offsetX, float offsetY);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fishrungames.mountainwallpaper
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.preference.PreferenceManager
|
||||||
|
import android.view.GestureDetector
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.SurfaceHolder
|
||||||
|
import fishrungames.salmonengineandroid.EngineWrapper
|
||||||
|
|
||||||
|
class MountainWallpaper : GLWallpaperService(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
|
init
|
||||||
|
{
|
||||||
|
EngineWrapper.LoadSalmonEngineLibrary();
|
||||||
|
//JniWrapper.LoadLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
|
||||||
|
|
||||||
|
EngineWrapper.SetActivityInstance(this)
|
||||||
|
EngineWrapper.SetupEnviroment()
|
||||||
|
|
||||||
|
var apkFilePath: String? = null
|
||||||
|
var appInfo: ApplicationInfo? = null
|
||||||
|
val packMgmr = this.packageManager
|
||||||
|
try {
|
||||||
|
appInfo = packMgmr.getApplicationInfo("fishrungames.mountainwallpaper", 0)
|
||||||
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
throw RuntimeException("Unable to locate assets, aborting...")
|
||||||
|
}
|
||||||
|
|
||||||
|
apkFilePath = appInfo!!.sourceDir
|
||||||
|
|
||||||
|
EngineWrapper.SetupApkFilePath(apkFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateEngine(): Engine {
|
||||||
|
return MuzeiWallpaperEngine()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
|
|
||||||
|
if (key.compareTo("Timeofday", ignoreCase = true) == 0) {
|
||||||
|
val time = Integer.parseInt(sharedPreferences.getString("Timeofday", "0")!!)
|
||||||
|
JniWrapper.SetTimeOfDayPref(time)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.compareTo("Snow", ignoreCase = true) == 0) {
|
||||||
|
|
||||||
|
JniWrapper.SetSnowPref(sharedPreferences.getBoolean("Snow", false))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class MuzeiWallpaperEngine : GLWallpaperService.GLEngine()
|
||||||
|
{
|
||||||
|
|
||||||
|
private lateinit var renderer: WallpaperRenderer
|
||||||
|
|
||||||
|
private val gestureListener = object : GestureDetector.SimpleOnGestureListener() {
|
||||||
|
override fun onDown(e: MotionEvent): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private val gestureDetector: GestureDetector = GestureDetector(this@MountainWallpaper,
|
||||||
|
gestureListener)
|
||||||
|
|
||||||
|
override fun onCreate(surfaceHolder: SurfaceHolder) {
|
||||||
|
super.onCreate(surfaceHolder)
|
||||||
|
|
||||||
|
setEGLContextClientVersion(2)
|
||||||
|
setRenderer(WallpaperRenderer())
|
||||||
|
renderMode = RENDERMODE_CONTINUOUSLY
|
||||||
|
requestRender()
|
||||||
|
|
||||||
|
// Use the MuzeiWallpaperService's lifecycle to wait for the user to unlock
|
||||||
|
|
||||||
|
setTouchEventsEnabled(true)
|
||||||
|
setOffsetNotificationsEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOffsetsChanged(
|
||||||
|
xOffset: Float,
|
||||||
|
yOffset: Float,
|
||||||
|
xOffsetStep: Float,
|
||||||
|
yOffsetStep: Float,
|
||||||
|
xPixelOffset: Int,
|
||||||
|
yPixelOffset: Int
|
||||||
|
) {
|
||||||
|
super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset,
|
||||||
|
yPixelOffset)
|
||||||
|
|
||||||
|
JniWrapper.SetOffset(xPixelOffset * xOffsetStep, yPixelOffset * yOffsetStep)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTouchEvent(event: MotionEvent) {
|
||||||
|
super.onTouchEvent(event)
|
||||||
|
gestureDetector.onTouchEvent(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,233 +0,0 @@
|
|||||||
package fishrungames.mountainwallpaper;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
|
||||||
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
|
|
||||||
//import com.seb.SLWP.SLWP.GlEngine.DownloadTask;
|
|
||||||
|
|
||||||
import fishrungames.salmonengineandroid.EngineWrapper;
|
|
||||||
|
|
||||||
public class MountainWallpaperService extends GLWallpaperService implements
|
|
||||||
OnSharedPreferenceChangeListener {
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
*
|
|
||||||
* @see android.app.Service#onLowMemory()
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
{
|
|
||||||
EngineWrapper.LoadSalmonEngineLibrary();
|
|
||||||
JniWrapper.LoadLibrary();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static final long SLEEPTIME = 1000 * 60 * 30; // 30 minutes
|
|
||||||
private GlEngine mGle;
|
|
||||||
|
|
||||||
public static Context mContext;
|
|
||||||
public static boolean ShowClouds;
|
|
||||||
public static boolean TouchRot;
|
|
||||||
|
|
||||||
public static int Bg;
|
|
||||||
public static boolean Usebg;
|
|
||||||
public static int Tex;
|
|
||||||
|
|
||||||
static long Synctime;
|
|
||||||
|
|
||||||
public boolean Slidedir;
|
|
||||||
public boolean Slideplanet;
|
|
||||||
public boolean Syncrot;
|
|
||||||
public static boolean Randomtex = true;
|
|
||||||
public static boolean visible = false;
|
|
||||||
|
|
||||||
public static boolean useCropper = true;
|
|
||||||
public static int Cropaspect;
|
|
||||||
public static boolean loading = false;
|
|
||||||
|
|
||||||
public static final Handler mHandler = new Handler();
|
|
||||||
public static final int RNDMAP = -1;
|
|
||||||
public static boolean destroyed;
|
|
||||||
public static String bgfile;
|
|
||||||
public ConnectivityManager cm;
|
|
||||||
public boolean needresume;
|
|
||||||
public boolean fstart;
|
|
||||||
public static String[] randlist;
|
|
||||||
public int curtexidx = -99;
|
|
||||||
|
|
||||||
static final String ACTION_FOREGROUND = "fishrungames.mountainwallpaper.FOREGROUND";
|
|
||||||
static final String ACTION_BACKGROUND = "fishrungames.mountainwallpaper.BACKGROUND";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onCreate();
|
|
||||||
|
|
||||||
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
|
|
||||||
|
|
||||||
EngineWrapper.SetActivityInstance(this);
|
|
||||||
EngineWrapper.SetupEnviroment();
|
|
||||||
|
|
||||||
String apkFilePath = null;
|
|
||||||
ApplicationInfo appInfo = null;
|
|
||||||
PackageManager packMgmr = this.getPackageManager();
|
|
||||||
try {
|
|
||||||
appInfo = packMgmr.getApplicationInfo("fishrungames.mountainwallpaper", 0);
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException("Unable to locate assets, aborting...");
|
|
||||||
}
|
|
||||||
apkFilePath = appInfo.sourceDir;
|
|
||||||
|
|
||||||
EngineWrapper.SetupApkFilePath(apkFilePath);
|
|
||||||
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
|
||||||
// handleCommand(intent);
|
|
||||||
// We want this service to continue running until it is explicitly
|
|
||||||
// stopped, so return sticky.
|
|
||||||
return START_STICKY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Init() {
|
|
||||||
try {
|
|
||||||
mContext = this;
|
|
||||||
cm = (ConnectivityManager) mContext
|
|
||||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
|
||||||
String key) {
|
|
||||||
|
|
||||||
if (key.compareToIgnoreCase("Timeofday") == 0)
|
|
||||||
{
|
|
||||||
int time = Integer.parseInt(sharedPreferences.getString("Timeofday", "0"));
|
|
||||||
JniWrapper.SetTimeOfDayPref(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key.compareToIgnoreCase("Snow") == 0) {
|
|
||||||
|
|
||||||
JniWrapper.SetSnowPref(sharedPreferences.getBoolean("Snow", false));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Engine onCreateEngine() {
|
|
||||||
if (mGle != null) {
|
|
||||||
mGle = null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
|
|
||||||
mGle = new GlEngine();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mGle;
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlEngine extends GLEngine {
|
|
||||||
|
|
||||||
public Handler mHandler = new Handler();
|
|
||||||
|
|
||||||
long NOW;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(SurfaceHolder surfaceHolder) {
|
|
||||||
super.onCreate(surfaceHolder);
|
|
||||||
try {
|
|
||||||
this.setTouchEventsEnabled(true);
|
|
||||||
fstart = true;
|
|
||||||
setRenderer();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTouchEvent(MotionEvent e) {
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOffsetsChanged(float xOffset, float yOffset,
|
|
||||||
float xOffsetStep, float yOffsetStep, int xPixelOffset,
|
|
||||||
int yPixelOffset) {
|
|
||||||
|
|
||||||
super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep,
|
|
||||||
xPixelOffset, yPixelOffset);
|
|
||||||
|
|
||||||
JniWrapper.SetOffset(xPixelOffset*xOffsetStep, yPixelOffset*yOffsetStep);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onVisibilityChanged(boolean visible) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onVisibilityChanged(visible);
|
|
||||||
MountainWallpaperService.visible = visible;
|
|
||||||
if (visible) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
|
|
||||||
super.onResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceChanged(SurfaceHolder holder, int format,
|
|
||||||
int width, int height) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onSurfaceChanged(holder, format, width, height);
|
|
||||||
fstart = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
package fishrungames.mountainwallpaper;
|
|
||||||
|
|
||||||
import fishrungames.mountainwallpaper.R;
|
|
||||||
import fishrungames.mountainwallpaper.JniWrapper;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.CheckBoxPreference;
|
|
||||||
import android.preference.ListPreference;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.preference.PreferenceActivity;
|
|
||||||
|
|
||||||
import android.preference.Preference.OnPreferenceChangeListener;
|
|
||||||
|
|
||||||
|
|
||||||
public class Prefs extends PreferenceActivity implements
|
|
||||||
OnPreferenceChangeListener {
|
|
||||||
|
|
||||||
|
|
||||||
private CheckBoxPreference snowPref;
|
|
||||||
private ListPreference timeOfDayPref;
|
|
||||||
|
|
||||||
|
|
||||||
public static Uri currImageURI;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.prefliste);
|
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
|
||||||
|
|
||||||
|
|
||||||
snowPref = (CheckBoxPreference)this.getPreferenceManager().findPreference("Snow");
|
|
||||||
timeOfDayPref = (ListPreference) findPreference("Timeofday");
|
|
||||||
|
|
||||||
if (timeOfDayPref.getKey().compareToIgnoreCase("Timeofday") == 0)
|
|
||||||
{
|
|
||||||
JniWrapper.SetTimeOfDayPref(Integer.parseInt((String) timeOfDayPref.getValue()));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snowPref.getKey().compareToIgnoreCase("Snow") == 0) {
|
|
||||||
if (!snowPref.isChecked())
|
|
||||||
{
|
|
||||||
JniWrapper.SetSnowPref(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
JniWrapper.SetSnowPref(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,11 @@
|
|||||||
|
package fishrungames.mountainwallpaper
|
||||||
|
|
||||||
|
import android.support.v7.preference.PreferenceFragmentCompat
|
||||||
|
import android.os.Bundle
|
||||||
|
|
||||||
|
class WallpaperPreferenceFragment : PreferenceFragmentCompat()
|
||||||
|
{
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fishrungames.mountainwallpaper
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v4.app.FragmentActivity
|
||||||
|
|
||||||
|
class WallpaperPreferences : FragmentActivity()
|
||||||
|
{
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.pref_activity)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fishrungames.mountainwallpaper
|
||||||
|
|
||||||
|
import android.opengl.GLES20
|
||||||
|
import android.opengl.GLSurfaceView
|
||||||
|
import android.util.Log
|
||||||
|
import fishrungames.salmonengineandroid.EngineWrapper
|
||||||
|
import java.util.*
|
||||||
|
import javax.microedition.khronos.egl.EGLConfig
|
||||||
|
import javax.microedition.khronos.opengles.GL10
|
||||||
|
|
||||||
|
class WallpaperRenderer() : GLSurfaceView.Renderer {
|
||||||
|
|
||||||
|
private var surfaceCreated: Boolean = false
|
||||||
|
private var lastTimeStamp: Long = 0
|
||||||
|
|
||||||
|
override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
|
||||||
|
surfaceCreated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
|
||||||
|
JniWrapper.Init(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDrawFrame(unused: GL10) {
|
||||||
|
val currentTimeStamp = Calendar.getInstance().timeInMillis
|
||||||
|
if (lastTimeStamp == 0L)
|
||||||
|
{
|
||||||
|
lastTimeStamp = currentTimeStamp
|
||||||
|
}
|
||||||
|
|
||||||
|
EngineWrapper.Update(currentTimeStamp - lastTimeStamp)
|
||||||
|
|
||||||
|
lastTimeStamp = currentTimeStamp
|
||||||
|
}
|
||||||
|
}
|
BIN
proj.android-studio/app/src/main/res/drawable-nodpi/icon.png
Executable file
BIN
proj.android-studio/app/src/main/res/drawable-nodpi/icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 108 KiB |
BIN
proj.android-studio/app/src/main/res/drawable/icon.png
Executable file
BIN
proj.android-studio/app/src/main/res/drawable/icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 151 KiB |
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
Binary file not shown.
Before Width: | Height: | Size: 28 KiB |
BIN
proj.android-studio/app/src/main/res/font/alegreya_black_italic.ttf
Executable file
BIN
proj.android-studio/app/src/main/res/font/alegreya_black_italic.ttf
Executable file
Binary file not shown.
BIN
proj.android-studio/app/src/main/res/font/alegreya_italic.ttf
Executable file
BIN
proj.android-studio/app/src/main/res/font/alegreya_italic.ttf
Executable file
Binary file not shown.
BIN
proj.android-studio/app/src/main/res/font/alegreya_sans_black.ttf
Executable file
BIN
proj.android-studio/app/src/main/res/font/alegreya_sans_black.ttf
Executable file
Binary file not shown.
BIN
proj.android-studio/app/src/main/res/font/alegreya_sans_medium.ttf
Executable file
BIN
proj.android-studio/app/src/main/res/font/alegreya_sans_medium.ttf
Executable file
Binary file not shown.
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
>
|
|
||||||
</LinearLayout>
|
|
29
proj.android-studio/app/src/main/res/layout/pref_activity.xml
Executable file
29
proj.android-studio/app/src/main/res/layout/pref_activity.xml
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_margin="20dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/icon">
|
||||||
|
</ImageView>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
class="fishrungames.mountainwallpaper.WallpaperPreferenceFragment"
|
||||||
|
android:id="@+id/preferences"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="true">
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:text="@string/feedback"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_parent">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/LinearLayout01"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="fill_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/ImageView01"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/icon"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_marginLeft="3dp">
|
|
||||||
</ImageView>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<ListView
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:id="@android:id/list"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
</ListView>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:id="@+id/android_text_feedback"
|
|
||||||
android:padding="20px"
|
|
||||||
android:text="@string/feedback"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
</TextView>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -5,9 +5,11 @@
|
|||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="Timeofday" android:summary="@string/p_stimeofday"
|
android:key="Timeofday" android:summary="@string/p_stimeofday"
|
||||||
android:title="@string/p_timeofday" android:entries="@array/timeofday_id"
|
android:title="@string/p_timeofday" android:entries="@array/timeofday_id"
|
||||||
android:entryValues="@array/timeofday_value" android:defaultValue="0"/>
|
android:entryValues="@array/timeofday_value" android:defaultValue="0"
|
||||||
|
/>
|
||||||
<CheckBoxPreference android:summaryOn="@string/p_snow_on"
|
<CheckBoxPreference android:summaryOn="@string/p_snow_on"
|
||||||
android:key="Snow" android:title="@string/p_snow"
|
android:key="Snow" android:title="@string/p_snow"
|
||||||
android:summaryOff="@string/p_snow_off" android:defaultValue="false" />
|
android:summaryOff="@string/p_snow_off" android:defaultValue="false"
|
||||||
|
/>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<wallpaper
|
<wallpaper
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:thumbnail="@drawable/thumb"
|
android:thumbnail="@drawable/icon"
|
||||||
android:description="@string/description"
|
android:description="@string/description"
|
||||||
android:settingsActivity="fishrungames.mountainwallpaper.Prefs"/>
|
android:settingsActivity="fishrungames.mountainwallpaper.WallpaperPreferences"
|
||||||
|
/>
|
@ -1,17 +0,0 @@
|
|||||||
package fishrungames.salmonandroidtemplate;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
public class ExampleUnitTest {
|
|
||||||
@Test
|
|
||||||
public void addition_isCorrect() throws Exception {
|
|
||||||
assertEquals(4, 2 + 2);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +1,20 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.2.70'
|
ext {
|
||||||
|
compileSdkVersion = 28
|
||||||
|
targetSdkVersion = 28
|
||||||
|
|
||||||
|
kotlin_version = "1.3.10"
|
||||||
|
supportLibraryVersion = "28.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.2.0-rc03'
|
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
Loading…
Reference in New Issue
Block a user