J'ai un fond d'écran animé avec un effet de parallaxe. J'ai basé le code de the openGL Tutorials.Android OpenGL Live Wallpaper créer deux moteurs de rendu
Il a fonctionné pour la plupart sauf lorsque le fond d'écran est prévisualisé alors qu'il est déjà défini comme fond d'écran. Après cela, ma méthode onOffsetsChanged() continue d'être appelée, mais la valeur de mon décalage de caméra dans ma classe de rendu ne change pas. Cela signifie que mon fond d'écran de parallaxe devient statique. L'effet de parallaxe fonctionne à nouveau dès que je définis un fond d'écran différent, puis je reviens à ce fond d'écran.
Mise à jour: Ainsi, il semble que le moteur de rendu soit dessiné et que le moteur de rendu qui reçoit les appels pour onOffsetsChanged soit deux moteurs de rendu distincts. Est-ce que quelqu'un sait pourquoi le nouveau est contrôlé par le WallpaperService pendant que l'ancien est dessiné ou comment résoudre ce problème?
GLWallpaperService:
public abstract class GLWallpaperService extends WallpaperService{
public class GLEngine extends Engine{
class WallpaperGLSurfaceView extends GLSurfaceView {
private static final String TAG = "WallpaperGLSurfaceView";
WallpaperGLSurfaceView(Context context)
{
super(context);
}
public SurfaceHolder getHolder()
{
return getSurfaceHolder();
}
public void onDestroy()
{
super.onDetachedFromWindow();
}
}
private WallpaperGLSurfaceView glSurfaceView;
private boolean rendererHasBeenSet;
@Override
public void onCreate(SurfaceHolder surfaceHolder)
{
super.onCreate(surfaceHolder);
glSurfaceView = new WallpaperGLSurfaceView(GLWallpaperService.this);
Log.d("onCreate", "was called");
}
@Override
public void onVisibilityChanged(boolean visible)
{
super.onVisibilityChanged(visible);
if(rendererHasBeenSet)
{
if (visible)
{
glSurfaceView.onResume();
//glSurfaceView.requestRender();
Log.d("onResume", "was called");
} else
{
glSurfaceView.onPause();
Log.d("onPause", "was called");
}
}
}
@Override
public void onDestroy()
{
super.onDestroy();
glSurfaceView.onDestroy();
Log.d("onDestroy", "was called");
}
protected void setRenderer(GLSurfaceView.Renderer renderer)
{
glSurfaceView.setRenderer(renderer);
rendererHasBeenSet = true;
Log.d("setRenderer", "was called");
}
protected void setPreserveEGLContextOnPause(boolean preserve)
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
{
glSurfaceView.setPreserveEGLContextOnPause(preserve);
}
}
protected void setEGLContextClientVersion(int version)
{
glSurfaceView.setEGLContextClientVersion(version);
}
}
}
OpenGLES2WallpaperService:
public class OpenGLES2WallpaperService extends GLWallpaperService
{
//set up our main_preferences
SharedPreferences preferences;
GLRenderer renderer;
private SharedPreferences.OnSharedPreferenceChangeListener prefListener;
@Override
public Engine onCreateEngine()
{
Log.d("GLES2 onCreateEngine", "engine was created");
return new OpenGLES2Engine();
}
class OpenGLES2Engine extends GLWallpaperService.GLEngine
{
@Override
public void onCreate(SurfaceHolder surfaceHolder)
{
super.onCreate(surfaceHolder);
Log.d("GLES2 onCreate", "surface was created");
preferences = PreferenceManager.getDefaultSharedPreferences(OpenGLES2WallpaperService.this);
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
if (supportsEs2)
{
setEGLContextClientVersion(2);
setPreserveEGLContextOnPause(true);
renderer = new GLRenderer(OpenGLES2WallpaperService.this);
setRenderer(renderer);
//set up preference listener
final SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(OpenGLES2WallpaperService.this);
prefListener = new SharedPreferences.OnSharedPreferenceChangeListener()
{
@Override
public void onSharedPreferenceChanged(SharedPreferences mprefs, String key) {
if(mPrefs.getBoolean("activate_sunset", true))
{
renderer.changeColor(1);
}
else
{
renderer.changeColor(0);
}
}
};
mPrefs.registerOnSharedPreferenceChangeListener(prefListener);
}
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
float yStep, int xPixels, int yPixels)
{
renderer.setEyeX(xOffset);
// Log.d("onOffsetsChanged", "was called");
}
//set up gesture detection
private android.view.GestureDetector.OnGestureListener gestureListener = new android.view.GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// if(preferences.getBoolean("pref_key_sim_scroll", true))
// renderer.setEyeX(e1.getX() - e2.getX());
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
};
GestureDetector mGestureDetector = new GestureDetector(OpenGLES2WallpaperService.this, gestureListener);
@Override
public void onTouchEvent(MotionEvent event)
{
mGestureDetector.onTouchEvent(event);
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
super.onSurfaceChanged(holder, format, width, height);
Log.d("GLES2 onSurfaceChanged", "the surface was changed");
}
@Override
public void onSurfaceRedrawNeeded(SurfaceHolder holder)
{
super.onSurfaceRedrawNeeded(holder);
Log.d("GLES2 RedrawNeeded", "the surface was redrawn");
}
}
GLSurfaceView.Renderer getNewRenderer()
{
return renderer = new GLRenderer(OpenGLES2WallpaperService.this);
}
}
classe Renderer (sorte de désordre en ce moment):
public class GLRenderer implements Renderer {
// Our matrices
private final float[] mtrxProjection = new float[16];
private final float[] mtrxView = new float[16];
private final float[] mMVPMatrix = new float[16];
private float[] mModelMatrix = new float[16];
private int mMVPMatrixHandle;
// Geometric variables
public static float vertices[];
public static short indices[];
public static float uvs[];
public FloatBuffer vertexBuffer;
public ShortBuffer drawListBuffer;
public FloatBuffer uvBuffer;
// Our screenresolution
float mScreenWidth = 1280;
float mScreenHeight = 768;
// Misc
Context mContext;
long mLastTime;
int mProgram;
//set up our main_preferences
SharedPreferences preferences;
//set up array database
ArrayHolder arrayHolder = new ArrayHolder();
// Square square, square1;
Sprite background, mountains, forest, person;
float offsetDifference = 1;
// Background background;
public void setEyeX(float offset)
{
eyeX = -offset * offsetDifference;
lookX = eyeX;
// Log.d("setEyeX", "eyeX: " + eyeX);
}
public GLRenderer(Context c)
{
mContext = c;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
//Load in Preferences
preferences = PreferenceManager.getDefaultSharedPreferences(mContext);
// Generate Textures, if more needed, alter these numbers.
int[] textureNames = new int[4];
GLES20.glGenTextures(4, textureNames, 0);
//set the scene color from preferences
float[] sceneColor;
if(preferences.getBoolean("activate_sunset", false))
{
sceneColor = arrayHolder.sunsetColor;
}
else
{
sceneColor = arrayHolder.normalColor;
}
//create the sprites
person = new Sprite(arrayHolder.vertices1, sceneColor);
forest = new Sprite(arrayHolder.vertices2, sceneColor);
mountains = new Sprite(arrayHolder.vertices3, sceneColor);
background = new Sprite(arrayHolder.vertices4, sceneColor);
// Set the clear color to white
GLES20.glClearColor(0.9f, 0.9f, 0.9f, 0);
// Create the shaders, solid color
int vertexShader = riGraphicTools.loadShader(GLES20.GL_VERTEX_SHADER, riGraphicTools.vs_SolidColor);
int fragmentShader = riGraphicTools.loadShader(GLES20.GL_FRAGMENT_SHADER, riGraphicTools.fs_SolidColor);
riGraphicTools.sp_SolidColor = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(riGraphicTools.sp_SolidColor, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(riGraphicTools.sp_SolidColor, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(riGraphicTools.sp_SolidColor); // creates OpenGL ES program executables
// Create the shaders, images
vertexShader = riGraphicTools.loadShader(GLES20.GL_VERTEX_SHADER, riGraphicTools.vs_Image);
fragmentShader = riGraphicTools.loadShader(GLES20.GL_FRAGMENT_SHADER, riGraphicTools.fs_Image);
riGraphicTools.sp_Image = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(riGraphicTools.sp_Image, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(riGraphicTools.sp_Image, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(riGraphicTools.sp_Image); // creates OpenGL ES program executables
// Set our shader program
GLES20.glUseProgram(riGraphicTools.sp_Image);
setupImages();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// We need to know the current width and height.
mScreenWidth = width;
mScreenHeight = height;
GLES20.glViewport(0, 0, width, height);
float ratio;
if(height > width)
{
ratio = (float) width/height;
Matrix.frustumM(mtrxProjection,0, -ratio, ratio, -1, 1, 3, 7);
offsetDifference = 1;
}
else
{
ratio = (float) height/width;
Matrix.frustumM(mtrxProjection,0, -1, 1, -ratio, ratio, 3, 7);
offsetDifference = 0.5f;
}
}
// Position the eye in front of the origin.
float eyeX = 0.0f;
float eyeY = 0.0f;
float eyeZ = -4.0f;
// We are looking toward the distance
float lookX = 0.0f;
float lookY = 0.0f;
float lookZ = 0.0f;
// Set our up vector. This is where our head would be pointing were we holding the camera.
float upX = 0.0f;
float upY = 1.0f;
float upZ = 0.0f;
boolean colorIsRed;
@Override
public void onDrawFrame(GL10 unused) {
// Set the camera position (View matrix)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVPMatrix");
// Log.d("onDrawFrame", "eyeX: " + eyeX);
Matrix.setLookAtM(mtrxView, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
// Calculate the projection and view transformation
// Matrix.multiplyMM(mMVPMatrix, 0, mtrxProjection, 0, mtrxView, 0);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, eyeX, 0.0f, 1.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mtrxView, 0, mModelMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mtrxProjection, 0, mMVPMatrix, 0);
background.draw(mMVPMatrix, uvBuffer, 0);
float[] scratch2 = new float[16];
//// Matrix.multiplyMM(scratch, 0, mtrxProjection, 0, mtrxView, 0);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, eyeX * 0.9f, 0.0f, 1.0f);
Matrix.multiplyMM(scratch2, 0, mtrxView, 0, mModelMatrix, 0);
Matrix.multiplyMM(scratch2, 0, mtrxProjection, 0, scratch2, 0);
mountains.draw(scratch2, uvBuffer, 3);
float[] scratch1 = new float[16];
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, eyeX * 0.5f, 0.0f, 1.0f);
Matrix.multiplyMM(scratch1, 0, mtrxView, 0, mModelMatrix, 0);
Matrix.multiplyMM(scratch1, 0, mtrxProjection, 0, scratch1, 0);
forest.draw(scratch1, uvBuffer, 1);
if(!preferences.getBoolean("pref_key_remove_layer", true))
{
float[] scratch = new float[16];
//// Matrix.multiplyMM(scratch, 0, mtrxProjection, 0, mtrxView, 0);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, -0.5f, 0.3f, 1.0f);
Matrix.multiplyMM(scratch, 0, mtrxView, 0, mModelMatrix, 0);
Matrix.multiplyMM(scratch, 0, mtrxProjection, 0, scratch, 0);
person.draw(scratch, uvBuffer, 2);
}
}
public void changeColor(int colorCode)
{
float[] newColor = arrayHolder.normalColor;
switch(colorCode){
case 0: newColor = arrayHolder.normalColor;
break;
case 1: newColor = arrayHolder.sunsetColor;
break;
}
person.changeColor(newColor);
forest.changeColor(newColor);
mountains.changeColor(newColor);
background.changeColor(newColor);
}
private void setupImages()
{
// Create our UV coordinates.
uvs = new float[] {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
// The texture buffer
ByteBuffer bb = ByteBuffer.allocateDirect(uvs.length * 4);
bb.order(ByteOrder.nativeOrder());
uvBuffer = bb.asFloatBuffer();
uvBuffer.put(uvs);
uvBuffer.position(0);
// Generate Textures, if more needed, alter these numbers.
int[] texturenames = new int[4];
GLES20.glGenTextures(4, texturenames, 0);
// Temporary create a bitmap
Bitmap bmp = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.squaresky);
// Bind texture to texturename
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
bmp = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.squareground);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[1]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
bmp = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.squareperson);
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[2]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
bmp = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.squaremountains);
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[3]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
bmp.recycle();
}
}
pouvez-vous publier la classe GLrenderer? –
C'est publié. Dites-moi si vous avez besoin de regarder quelque chose d'autre. –
onVisibilityChanged, essayez de supprimer l'appel requestRender, Il n'est pas nécessaire d'appeler cela si votre rendu rend toujours –