|
Android example source code file (SimpleGLRenderer.java)
The SimpleGLRenderer.java Android example source code
/*
* Copyright (C) 2010 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 com.android.heightmapprofiler;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.GLUtils;
import android.util.Log;
/**
* An OpenGL ES renderer based on the GLSurfaceView rendering framework. This
* class is responsible for drawing a list of renderables to the screen every
* frame. It also manages loading of textures and (when VBOs are used) the
* allocation of vertex buffer objects.
*/
public class SimpleGLRenderer implements GLSurfaceView.Renderer {
// Texture filtering modes.
public final static int FILTER_NEAREST_NEIGHBOR = 0;
public final static int FILTER_BILINEAR = 1;
public final static int FILTER_TRILINEAR = 2;
// Specifies the format our textures should be converted to upon load.
private static BitmapFactory.Options sBitmapOptions
= new BitmapFactory.Options();
// Pre-allocated arrays to use at runtime so that allocation during the
// test can be avoided.
private int[] mTextureNameWorkspace;
// A reference to the application context.
private Context mContext;
private LandTileMap mTiles;
private int mTextureResource;
private int mTextureResource2;
private int mTextureId2;
private Vector3 mCameraPosition = new Vector3();
private Vector3 mLookAtPosition = new Vector3();
private Object mCameraLock = new Object();
private boolean mCameraDirty;
private NativeRenderer mNativeRenderer;
// Determines the use of vertex buffer objects.
private boolean mUseHardwareBuffers;
private boolean mUseTextureLods = false;
private boolean mUseHardwareMips = false;
boolean mColorTextureLods = false;
private int mTextureFilter = FILTER_BILINEAR;
private int mMaxTextureSize = 0;
public SimpleGLRenderer(Context context) {
// Pre-allocate and store these objects so we can use them at runtime
// without allocating memory mid-frame.
mTextureNameWorkspace = new int[1];
// Set our bitmaps to 16-bit, 565 format.
sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
mContext = context;
mUseHardwareBuffers = true;
}
public void setTiles(LandTileMap tiles, int textureResource, int textureResource2) {
mTextureResource = textureResource;
mTextureResource2 = textureResource2;
mTiles = tiles;
}
/** Draws the landscape. */
public void onDrawFrame(GL10 gl) {
ProfileRecorder.sSingleton.stop(ProfileRecorder.PROFILE_FRAME);
ProfileRecorder.sSingleton.start(ProfileRecorder.PROFILE_FRAME);
if (mTiles != null) {
// Clear the screen. Note that a real application probably would only clear the depth buffer
// (or maybe not even that).
if (mNativeRenderer == null) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
}
// If the camera has moved since the last frame, rebuild our projection matrix.
if (mCameraDirty){
synchronized (mCameraLock) {
if (mNativeRenderer != null) {
mNativeRenderer.setCamera(mCameraPosition, mLookAtPosition);
} else {
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, mCameraPosition.x, mCameraPosition.y, mCameraPosition.z,
mLookAtPosition.x, mLookAtPosition.y, mLookAtPosition.z,
0.0f, 1.0f, 0.0f);
}
mCameraDirty = false;
}
}
ProfileRecorder.sSingleton.start(ProfileRecorder.PROFILE_DRAW);
// Draw the landscape.
mTiles.draw(gl, mCameraPosition);
ProfileRecorder.sSingleton.stop(ProfileRecorder.PROFILE_DRAW);
}
ProfileRecorder.sSingleton.endFrame();
}
/* Called when the size of the window changes. */
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
/*
* Set our projection matrix. This doesn't have to be done each time we
* draw, but usually a new projection needs to be set when the viewport
* is resized.
*/
float ratio = (float)width / height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 60.0f, ratio, 2.0f, 3000.0f);
mCameraDirty = true;
}
public void setCameraPosition(float x, float y, float z) {
synchronized (mCameraLock) {
mCameraPosition.set(x, y, z);
mCameraDirty = true;
}
}
public void setCameraLookAtPosition(float x, float y, float z) {
synchronized (mCameraLock) {
mLookAtPosition.set(x, y, z);
mCameraDirty = true;
}
}
public void setUseHardwareBuffers(boolean vbos) {
mUseHardwareBuffers = vbos;
}
/**
* Called to turn on Levels of Detail option for rendering textures
*
* @param mUseTextureLods
*/
public void setUseTextureLods(boolean useTextureLods, boolean useHardwareMips) {
mUseTextureLods = useTextureLods;
mUseHardwareMips = useHardwareMips;
}
/**
* Turns on/off color the LOD bitmap textures based on their distance from view.
* This feature is useful since it helps visualize the LOD being used while viewing the scene.
*
* @param colorTextureLods
*/
public void setColorTextureLods(boolean colorTextureLods) {
this.mColorTextureLods = colorTextureLods;
}
public void setNativeRenderer(NativeRenderer render) {
mNativeRenderer = render;
}
public void setMaxTextureSize(int maxTextureSize) {
mMaxTextureSize = maxTextureSize;
}
public void setTextureFilter(int filter) {
mTextureFilter = filter;
}
/**
* Called whenever the surface is created. This happens at startup, and
* may be called again at runtime if the device context is lost (the screen
* goes to sleep, etc). This function must fill the contents of vram with
* texture data and (when using VBOs) hardware vertex arrays.
*/
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
int[] textureNames = null;
/*
* Some one-time OpenGL initialization can be made here probably based
* on features of this particular context
*/
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
gl.glDisable(GL10.GL_DITHER);
gl.glDisable(GL10.GL_CULL_FACE);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_TEXTURE_2D);
// set up some fog.
gl.glEnable(GL10.GL_FOG);
gl.glFogf(GL10.GL_FOG_MODE, GL10.GL_LINEAR);
float fogColor[] = { 0.5f, 0.5f, 0.5f, 1.0f };
gl.glFogfv(GL10.GL_FOG_COLOR, fogColor, 0);
gl.glFogf(GL10.GL_FOG_DENSITY, 0.15f);
gl.glFogf(GL10.GL_FOG_START, 800.0f);
gl.glFogf(GL10.GL_FOG_END, 2048.0f);
gl.glHint(GL10.GL_FOG_HINT, GL10.GL_FASTEST);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// load textures and buffers here
if (mUseHardwareBuffers && mTiles != null) {
mTiles.generateHardwareBuffers(gl);
}
if (mTextureResource != 0) {
textureNames = loadBitmap( mContext, gl, mTextureResource, mUseTextureLods, mUseHardwareMips );
}
if (mTextureResource2 != 0) {
mTextureId2 = loadBitmap(mContext, gl, mTextureResource2);
}
mTiles.setTextures(textureNames, mTextureId2);
}
/**
* Loads a bitmap into OpenGL and sets up the common parameters for
* 2D texture maps.
*/
protected int loadBitmap(Context context, GL10 gl, int resourceId) {
int textureName = -1;
InputStream is = context.getResources().openRawResource(resourceId);
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(is, null, sBitmapOptions);
} finally {
try {
is.close();
} catch (IOException e) {
// Ignore.
}
}
if (mMaxTextureSize > 0 && Math.max(bitmap.getWidth(), bitmap.getHeight()) != mMaxTextureSize) {
// we're assuming all our textures are square. sue me.
Bitmap tempBitmap = Bitmap.createScaledBitmap( bitmap, mMaxTextureSize, mMaxTextureSize, false );
bitmap.recycle();
bitmap = tempBitmap;
}
textureName = loadBitmapIntoOpenGL(context, gl, bitmap, false);
bitmap.recycle();
return textureName;
}
/**
* Loads a bitmap into OpenGL and sets up the common parameters for
* 2D texture maps.
*
* @param context
* @param resourceId
* @param numLevelsOfDetail number of detail textures to generate
*
* @return a array of OpenGL texture names corresponding to the different levels of detail textures
*/
protected int[] loadBitmap(Context context, GL10 gl, int resourceId, boolean generateMips, boolean useHardwareMips ) {
InputStream is = context.getResources().openRawResource(resourceId);
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(is, null, sBitmapOptions);
} finally {
try {
is.close();
} catch (IOException e) {
// Ignore.
}
}
if (mMaxTextureSize > 0 && Math.max(bitmap.getWidth(), bitmap.getHeight()) != mMaxTextureSize) {
// we're assuming all our textures are square. sue me.
Bitmap tempBitmap = Bitmap.createScaledBitmap( bitmap, mMaxTextureSize, mMaxTextureSize, false );
bitmap.recycle();
bitmap = tempBitmap;
}
final int minSide = Math.min(bitmap.getWidth(), bitmap.getHeight());
int numLevelsOfDetail = 1;
if (generateMips) {
for (int side = minSide / 2; side > 0; side /= 2) {
numLevelsOfDetail++;
}
}
int textureNames[];
if (generateMips && !useHardwareMips) {
textureNames = new int[numLevelsOfDetail];
} else {
textureNames = new int[1];
}
textureNames[0] = loadBitmapIntoOpenGL(context, gl, bitmap, useHardwareMips);
// Scale down base bitmap by powers of two to create lower resolution textures
for( int i = 1; i < numLevelsOfDetail; ++i ) {
int scale = (int)Math.pow(2, i);
int dstWidth = bitmap.getWidth() / scale;
int dstHeight = bitmap.getHeight() / scale;
Bitmap tempBitmap = Bitmap.createScaledBitmap( bitmap, dstWidth, dstHeight, false );
// Set each LOD level to a different color to help visualization
if( mColorTextureLods ) {
int color = 0;
switch( (int)(i % 4) ) {
case 1:
color = Color.RED;
break;
case 2:
color = Color.YELLOW;
break;
case 3:
color = Color.BLUE;
break;
}
tempBitmap.eraseColor( color );
}
if (!useHardwareMips) {
textureNames[i] = loadBitmapIntoOpenGL( context, gl, tempBitmap, false);
} else {
addHardwareMipmap(gl, textureNames[0], tempBitmap, i );
}
tempBitmap.recycle();
}
bitmap.recycle();
return textureNames;
}
protected void addHardwareMipmap(GL10 gl, int textureName, Bitmap bitmap, int level) {
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0);
}
/**
* Loads a bitmap into OpenGL and sets up the common parameters for
* 2D texture maps.
*
* @return OpenGL texture entry id
*/
protected int loadBitmapIntoOpenGL(Context context, GL10 gl, Bitmap bitmap, boolean useMipmaps) {
int textureName = -1;
if (context != null && gl != null) {
gl.glGenTextures(1, mTextureNameWorkspace, 0);
textureName = mTextureNameWorkspace[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
if (useMipmaps) {
if (mTextureFilter == FILTER_TRILINEAR) {
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_LINEAR);
} else {
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
}
} else {
if (mTextureFilter == FILTER_NEAREST_NEIGHBOR) {
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
} else {
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
}
}
if (mTextureFilter == FILTER_NEAREST_NEIGHBOR) {
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
} else {
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
}
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
int error = gl.glGetError();
if (error != GL10.GL_NO_ERROR) {
Log.e("SimpleGLRenderer", "Texture Load GLError: " + error);
}
}
return textureName;
}
}
Other Android examples (source code examples)Here is a short list of links related to this Android SimpleGLRenderer.java source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.