merged with muzei
This commit is contained in:
parent
1d4b103f06
commit
2c51ab0cc6
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
Debug
|
||||
Release
|
||||
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(${EIGEN_PATH})
|
||||
include_directories(${SOL2_PATH})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../)
|
||||
include_directories(${BOOST_PATH})
|
||||
include_directories(${LIBPNG_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: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.0"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "fishrungames.mountainwallpaper"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 28
|
||||
versionCode 2
|
||||
versionName "1.1"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++11 -frtti -fexceptions -fsigned-char -Wno-c++11-narrowing"
|
||||
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "CMakeLists.txt"
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), file('proguard-project.txt')
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
assets.srcDirs = ['../../assets/']
|
||||
}
|
||||
}
|
||||
|
||||
splits {
|
||||
abi {
|
||||
enable true
|
||||
reset()
|
||||
include 'arm64-v8a', 'armeabi-v7a', 'x86'
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path 'CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="fishrungames.mountainwallpaper"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0.0">
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="fishrungames.mountainwallpaper">
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
android:required="true"/>
|
||||
<uses-feature
|
||||
android:name="android.software.live_wallpaper"
|
||||
android:required="true"/>
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
android:required="true"/>
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
android:icon="@drawable/icon" >
|
||||
<!-- <uses-permission android:name="android.permission.WAKE_LOCK"/> -->
|
||||
|
||||
<activity
|
||||
android:name=".Prefs">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- 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"/>-->
|
||||
|
||||
<service
|
||||
android:name=".MountainWallpaperService"
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.service.wallpaper.WallpaperService" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/wallpaper"/>
|
||||
</service>
|
||||
<application
|
||||
android:supportsRtl="true"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@drawable/icon"
|
||||
android:allowBackup="false">
|
||||
<!--tools:ignore="GoogleAppIndexingWarning"-->
|
||||
|
||||
</application>
|
||||
<!-- 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
|
||||
android:name=".WallpaperPreferences"
|
||||
android:launchMode="singleTop">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<!--<intent-filter>-->
|
||||
<!--<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>-->
|
||||
<!--</intent-filter>-->
|
||||
</activity>
|
||||
|
||||
<!--android:directBootAware="true"-->
|
||||
<!--tools:targetApi="n"-->
|
||||
|
||||
<service
|
||||
android:name=".MountainWallpaper"
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.wallpaper.WallpaperService"/>
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/wallpaper"/>
|
||||
</service>
|
||||
|
||||
<!--<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>
|
@ -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;
|
||||
|
||||
public class JniWrapper
|
||||
class JniWrapper
|
||||
{
|
||||
|
||||
static
|
||||
{
|
||||
System.loadLibrary("MountainWallpaper");
|
||||
}
|
||||
|
||||
public static void LoadLibrary()
|
||||
{
|
||||
//To force loading libraries
|
||||
}
|
||||
|
||||
public static native void SetTimeOfDayPref(int timeofday);
|
||||
|
||||
public static native void SetSnowPref(boolean snow);
|
||||
|
||||
|
||||
public static native void Init(int width, int height);
|
||||
|
||||
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
|
||||
android:key="Timeofday" android:summary="@string/p_stimeofday"
|
||||
android:title="@string/p_timeofday" android:entries="@array/timeofday_id"
|
||||
android:entryValues="@array/timeofday_value" android:defaultValue="0"/>
|
||||
<CheckBoxPreference android:summaryOn="@string/p_snow_on"
|
||||
android:entryValues="@array/timeofday_value" android:defaultValue="0"
|
||||
/>
|
||||
<CheckBoxPreference android:summaryOn="@string/p_snow_on"
|
||||
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>
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<wallpaper
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:thumbnail="@drawable/thumb"
|
||||
android:thumbnail="@drawable/icon"
|
||||
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.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.2.70'
|
||||
ext {
|
||||
compileSdkVersion = 28
|
||||
targetSdkVersion = 28
|
||||
|
||||
kotlin_version = "1.3.10"
|
||||
supportLibraryVersion = "28.0.0"
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
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"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
Loading…
Reference in New Issue
Block a user