Android OpenGL Live Wallpaper 创建两个渲染器
Android OpenGL Live Wallpaper creating two renderers
我有一个具有视差效果的动态壁纸。我的代码基于 the openGL Tutorials.
它大部分时间都在工作,除了在壁纸已设置为壁纸的情况下进行预览。在我这样做之后,我的 onOffsetsChanged() 方法不断被调用,但我的渲染器 class 中的相机偏移值没有改变。这意味着我的视差墙纸变成静态的。一旦我设置不同的墙纸然后切换回此墙纸,视差效果就会再次起作用。
更新:因此,看起来正在绘制的渲染器和接收 onOffsetsChanged 调用的渲染器是两个独立的渲染器。有谁知道为什么在绘制旧的时新的由 WallpaperService 控制,或者如何解决这个问题?
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);
}
}
渲染器class(现在有点乱):
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();
}
}
看来我需要为新的 Surface 视图设置正确的渲染器。我通过将 GLRenderer 渲染器移动到 GLWallpaperService 并将 setRenderer() 更改为此:
protected void setRenderer(GLSurfaceView.Renderer renderer)
{
this.renderer = (GLRenderer)renderer; //this line was missing
glSurfaceView.setRenderer(renderer);
rendererHasBeenSet = true;
}
我有一个具有视差效果的动态壁纸。我的代码基于 the openGL Tutorials.
它大部分时间都在工作,除了在壁纸已设置为壁纸的情况下进行预览。在我这样做之后,我的 onOffsetsChanged() 方法不断被调用,但我的渲染器 class 中的相机偏移值没有改变。这意味着我的视差墙纸变成静态的。一旦我设置不同的墙纸然后切换回此墙纸,视差效果就会再次起作用。
更新:因此,看起来正在绘制的渲染器和接收 onOffsetsChanged 调用的渲染器是两个独立的渲染器。有谁知道为什么在绘制旧的时新的由 WallpaperService 控制,或者如何解决这个问题?
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);
}
}
渲染器class(现在有点乱):
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();
}
}
看来我需要为新的 Surface 视图设置正确的渲染器。我通过将 GLRenderer 渲染器移动到 GLWallpaperService 并将 setRenderer() 更改为此:
protected void setRenderer(GLSurfaceView.Renderer renderer)
{
this.renderer = (GLRenderer)renderer; //this line was missing
glSurfaceView.setRenderer(renderer);
rendererHasBeenSet = true;
}