123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684 |
- package min3d.core;
- import java.nio.FloatBuffer;
- import java.nio.IntBuffer;
- import javax.microedition.khronos.egl.EGLConfig;
- import javax.microedition.khronos.opengles.GL10;
- import javax.microedition.khronos.opengles.GL11;
- import min3d.Min3d;
- import min3d.Shared;
- import min3d.animation.AnimationObject3d;
- import min3d.vos.FrustumManaged;
- import min3d.vos.Light;
- import min3d.vos.RenderType;
- import min3d.vos.TextureVo;
- import android.app.ActivityManager;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.opengl.GLSurfaceView;
- import android.opengl.GLU;
- import android.opengl.GLUtils;
- import android.util.Log;
- public class Renderer implements GLSurfaceView.Renderer
- {
- public static final int NUM_GLLIGHTS = 8;
- private GL10 _gl;
- private Scene _scene;
- private TextureManager _textureManager;
- private float _surfaceAspectRatio;
-
- private IntBuffer _scratchIntBuffer;
- private FloatBuffer _scratchFloatBuffer;
- private boolean _scratchB;
-
- // stats-related
- public static final int FRAMERATE_SAMPLEINTERVAL_MS = 1000;
- private boolean _logFps = false;
- private long _frameCount = 0;
- private float _fps = 0;
- private long _timeLastSample;
- private ActivityManager _activityManager;
- private ActivityManager.MemoryInfo _memoryInfo;
- public Renderer(Scene $scene)
- {
- _scene = $scene;
- _scratchIntBuffer = IntBuffer.allocate(4);
- _scratchFloatBuffer = FloatBuffer.allocate(4);
-
- _textureManager = new TextureManager();
- Shared.textureManager(_textureManager);
-
- _activityManager = (ActivityManager) Shared.context().getSystemService( Context.ACTIVITY_SERVICE );
- _memoryInfo = new ActivityManager.MemoryInfo();
- }
- public void onSurfaceCreated(GL10 $gl, EGLConfig eglConfig)
- {
- Log.i(Min3d.TAG, "Renderer.onSurfaceCreated()");
- RenderCaps.setRenderCaps($gl);
- setGl($gl);
- reset();
-
- _scene.init();
- }
- public void clearScene()
- {
- _scene.clear();
- }
- public void onSurfaceChanged(GL10 gl, int w, int h)
- {
- Log.i(Min3d.TAG, "Renderer.onSurfaceChanged()");
- Log.i("-----", "Renderer.onSurfaceChanged()");
- setGl(_gl);
- _surfaceAspectRatio = (float)w / (float)h;
-
- _gl.glViewport(0, 0, w, h);
- _gl.glMatrixMode(GL10.GL_PROJECTION);
- _gl.glLoadIdentity();
- updateViewFrustrum();
- }
-
- public void onDrawFrame(GL10 gl)
- {
- // Update 'model'
- _scene.update();
-
- // Update 'view'
- drawSetup();
- drawScene();
- if (_logFps) doFps();
- }
-
- //
-
- /**
- * Accessor to the GL object, in case anything outside this class wants to do
- * bad things with it :)
- */
- public GL10 gl()
- {
- return _gl;
- }
- /**
- * Returns last sampled framerate (logFps must be set to true)
- */
- public float fps()
- {
- return _fps;
- }
- /**
- * Return available system memory in bytes
- */
- public long availMem()
- {
- _activityManager.getMemoryInfo(_memoryInfo);
- return _memoryInfo.availMem;
- }
-
- protected void drawSetup()
- {
- // View frustrum
-
- if (_scene.camera().frustum.isDirty()) {
- updateViewFrustrum();
- }
-
- // Camera
-
- _gl.glMatrixMode(GL10.GL_MODELVIEW);
- _gl.glLoadIdentity();
- GLU.gluLookAt(_gl,
- _scene.camera().position.x,_scene.camera().position.y,_scene.camera().position.z,
- _scene.camera().target.x,_scene.camera().target.y,_scene.camera().target.z,
- _scene.camera().upAxis.x,_scene.camera().upAxis.y,_scene.camera().upAxis.z);
-
- // Background color
-
- if (_scene.backgroundColor().isDirty())
- {
- _gl.glClearColor(
- (float)_scene.backgroundColor().r() / 255f,
- (float)_scene.backgroundColor().g() / 255f,
- (float)_scene.backgroundColor().b() / 255f,
- (float)_scene.backgroundColor().a() / 255f);
- _scene.backgroundColor().clearDirtyFlag();
- }
-
- _gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
-
- drawSetupLights();
-
- // Always on:
- _gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
- }
-
- protected void drawSetupLights()
- {
- // GL_LIGHTS enabled/disabled based on enabledDirty list
- for (int glIndex = 0; glIndex < NUM_GLLIGHTS; glIndex++)
- {
- if (_scene.lights().glIndexEnabledDirty()[glIndex] == true)
- {
- if (_scene.lights().glIndexEnabled()[glIndex] == true)
- {
- _gl.glEnable(GL10.GL_LIGHT0 + glIndex);
-
- // make light's properties dirty to force update
- _scene.lights().getLightByGlIndex(glIndex).setAllDirty();
- }
- else
- {
- _gl.glDisable(GL10.GL_LIGHT0 + glIndex);
- }
-
- _scene.lights().glIndexEnabledDirty()[glIndex] = false; // clear dirtyflag
- }
- }
-
- // Lights' properties
- Light[] lights = _scene.lights().toArray();
- for (int i = 0; i < lights.length; i++)
- {
- Light light = lights[i];
-
- if (light.isDirty()) // .. something has changed
- {
- // Check all of Light's properties for dirty
-
- int glLightId = GL10.GL_LIGHT0 + _scene.lights().getGlIndexByLight(light);
-
- if (light.position.isDirty())
- {
- light.commitPositionAndTypeBuffer();
- _gl.glLightfv(glLightId, GL10.GL_POSITION, light._positionAndTypeBuffer);
- light.position.clearDirtyFlag();
- }
- if (light.ambient.isDirty())
- {
- light.ambient.commitToFloatBuffer();
- _gl.glLightfv(glLightId, GL10.GL_AMBIENT, light.ambient.floatBuffer());
- light.ambient.clearDirtyFlag();
- }
- if (light.diffuse.isDirty())
- {
- light.diffuse.commitToFloatBuffer();
- _gl.glLightfv(glLightId, GL10.GL_DIFFUSE, light.diffuse.floatBuffer());
- light.diffuse.clearDirtyFlag();
- }
- if (light.specular.isDirty())
- {
- light.specular.commitToFloatBuffer();
- _gl.glLightfv(glLightId, GL10.GL_SPECULAR, light.specular.floatBuffer());
- light.specular.clearDirtyFlag();
- }
- if (light.emissive.isDirty())
- {
- light.emissive.commitToFloatBuffer();
- _gl.glLightfv(glLightId, GL10.GL_EMISSION, light.emissive.floatBuffer());
- light.emissive.clearDirtyFlag();
- }
- if (light.direction.isDirty())
- {
- light.direction.commitToFloatBuffer();
- _gl.glLightfv(glLightId, GL10.GL_SPOT_DIRECTION, light.direction.floatBuffer());
- light.direction.clearDirtyFlag();
- }
- if (light._spotCutoffAngle.isDirty())
- {
- _gl.glLightf(glLightId, GL10.GL_SPOT_CUTOFF, light._spotCutoffAngle.get());
- }
- if (light._spotExponent.isDirty())
- {
- _gl.glLightf(glLightId, GL10.GL_SPOT_EXPONENT, light._spotExponent.get());
- }
- if (light._isVisible.isDirty())
- {
- if (light.isVisible()) {
- _gl.glEnable(glLightId);
- } else {
- _gl.glDisable(glLightId);
- }
- light._isVisible.clearDirtyFlag();
- }
- if (light._attenuation.isDirty())
- {
- _gl.glLightf(glLightId, GL10.GL_CONSTANT_ATTENUATION, light._attenuation.getX());
- _gl.glLightf(glLightId, GL10.GL_LINEAR_ATTENUATION, light._attenuation.getY());
- _gl.glLightf(glLightId, GL10.GL_QUADRATIC_ATTENUATION, light._attenuation.getZ());
- }
-
- light.clearDirtyFlag();
- }
- }
- }
- protected void drawScene()
- {
- if(_scene.fogEnabled() == true) {
- _gl.glFogf(GL10.GL_FOG_MODE, _scene.fogType().glValue());
- _gl.glFogf(GL10.GL_FOG_START, _scene.fogNear());
- _gl.glFogf(GL10.GL_FOG_END, _scene.fogFar());
- _gl.glFogfv(GL10.GL_FOG_COLOR, _scene.fogColor().toFloatBuffer() );
- _gl.glEnable(GL10.GL_FOG);
- } else {
- _gl.glDisable(GL10.GL_FOG);
- }
- for (int i = 0; i < _scene.children().size(); i++)
- {
- Object3d o = _scene.children().get(i);
- if(o.animationEnabled())
- {
- ((AnimationObject3d)o).update();
- }
- drawObject(o);
- }
- }
-
- //boolean customResult = o.customRenderer(_gl);
- //if (customResult) return;
- protected void drawObject(Object3d $o)
- {
- if ($o.isVisible() == false) return;
- // Various per-object settings:
-
- // Normals
- if ($o.hasNormals() && $o.normalsEnabled()) {
- $o.vertices().normals().buffer().position(0);
- _gl.glNormalPointer(GL10.GL_FLOAT, 0, $o.vertices().normals().buffer());
- _gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
- }
- else {
- _gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
- }
-
- // Is lighting enabled for object...
-
- /*
- // *** this version not working properly on emulator - why not? ***
- _scratchIntBuffer.position(0);
- _gl.glGetIntegerv(GL10.GL_LIGHTING, _scratchIntBuffer);
- if (useLighting != _scratchIntBuffer.get(0))
- {
- if (useLighting == 1) {
- _gl.glEnable(GL10.GL_LIGHTING);
- } else {
- _gl.glDisable(GL10.GL_LIGHTING);
- }
- }
- */
-
- boolean useLighting = (_scene.lightingEnabled() && $o.hasNormals() && $o.normalsEnabled() && $o.lightingEnabled());
- if (useLighting) {
- _gl.glEnable(GL10.GL_LIGHTING);
- } else {
- _gl.glDisable(GL10.GL_LIGHTING);
- }
-
- // Shademodel
-
- _gl.glGetIntegerv(GL11.GL_SHADE_MODEL, _scratchIntBuffer);
- if ($o.shadeModel().glConstant() != _scratchIntBuffer.get(0)) {
- _gl.glShadeModel($o.shadeModel().glConstant());
- }
-
- // Colors: either per-vertex, or per-object
- if ($o.hasVertexColors() && $o.vertexColorsEnabled()) {
- $o.vertices().colors().buffer().position(0);
- _gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, $o.vertices().colors().buffer());
- _gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
- }
- else {
- _gl.glColor4f(
- (float)$o.defaultColor().r / 255f,
- (float)$o.defaultColor().g / 255f,
- (float)$o.defaultColor().b / 255f,
- (float)$o.defaultColor().a / 255f
- );
- _gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
- }
-
- // Colormaterial
-
- _gl.glGetIntegerv(GL10.GL_COLOR_MATERIAL, _scratchIntBuffer);
- _scratchB = (_scratchIntBuffer.get(0) != 0);
- if ($o.colorMaterialEnabled() != _scratchB) {
- if ($o.colorMaterialEnabled())
- _gl.glEnable(GL10.GL_COLOR_MATERIAL);
- else
- _gl.glDisable(GL10.GL_COLOR_MATERIAL);
- }
-
- // Point size
-
- if ($o.renderType() == RenderType.POINTS)
- {
- if ($o.pointSmoothing())
- _gl.glEnable(GL10.GL_POINT_SMOOTH);
- else
- _gl.glDisable(GL10.GL_POINT_SMOOTH);
-
- _gl.glPointSize($o.pointSize());
- }
- // Line properties
-
- if ($o.renderType() == RenderType.LINES || $o.renderType() == RenderType.LINE_STRIP || $o.renderType() == RenderType.LINE_LOOP)
- {
- if ( $o.lineSmoothing() == true) {
- _gl.glEnable(GL10.GL_LINE_SMOOTH);
- }
- else {
- _gl.glDisable(GL10.GL_LINE_SMOOTH);
- }
- _gl.glLineWidth($o.lineWidth());
- }
- // Backface culling
-
- if ($o.doubleSidedEnabled()) {
- _gl.glDisable(GL10.GL_CULL_FACE);
- }
- else {
- _gl.glEnable(GL10.GL_CULL_FACE);
- }
-
- drawObject_textures($o);
-
- // Matrix operations in modelview
- _gl.glPushMatrix();
-
- _gl.glTranslatef($o.position().x, $o.position().y, $o.position().z);
-
- _gl.glRotatef($o.rotation().x, 1,0,0);
- _gl.glRotatef($o.rotation().y, 0,1,0);
- _gl.glRotatef($o.rotation().z, 0,0,1);
-
- _gl.glScalef($o.scale().x, $o.scale().y, $o.scale().z);
-
- // Draw
- $o.vertices().points().buffer().position(0);
- _gl.glVertexPointer(3, GL10.GL_FLOAT, 0, $o.vertices().points().buffer());
- if (! $o.ignoreFaces())
- {
- int pos, len;
-
- if (! $o.faces().renderSubsetEnabled()) {
- pos = 0;
- len = $o.faces().size();
- }
- else {
- pos = $o.faces().renderSubsetStartIndex() * FacesBufferedList.PROPERTIES_PER_ELEMENT;
- len = $o.faces().renderSubsetLength();
- }
- $o.faces().buffer().position(pos);
- _gl.glDrawElements(
- $o.renderType().glValue(),
- len * FacesBufferedList.PROPERTIES_PER_ELEMENT,
- GL10.GL_UNSIGNED_SHORT,
- $o.faces().buffer());
- }
- else
- {
- _gl.glDrawArrays($o.renderType().glValue(), 0, $o.vertices().size());
- }
-
- //
- // Recurse on children
- //
-
- if ($o instanceof Object3dContainer)
- {
- Object3dContainer container = (Object3dContainer)$o;
-
- for (int i = 0; i < container.children().size(); i++)
- {
- Object3d o = container.children().get(i);
- drawObject(o);
- }
- }
-
- // Restore matrix
-
- _gl.glPopMatrix();
- }
-
- private void drawObject_textures(Object3d $o)
- {
- // iterate thru object's textures
-
- for (int i = 0; i < RenderCaps.maxTextureUnits(); i++)
- {
- _gl.glActiveTexture(GL10.GL_TEXTURE0 + i);
- _gl.glClientActiveTexture(GL10.GL_TEXTURE0 + i);
- if ($o.hasUvs() && $o.texturesEnabled())
- {
- $o.vertices().uvs().buffer().position(0);
- _gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, $o.vertices().uvs().buffer());
- TextureVo textureVo = ((i < $o.textures().size())) ? textureVo = $o.textures().get(i) : null;
- if (textureVo != null)
- {
- // activate texture
- int glId = _textureManager.getGlTextureId(textureVo.textureId);
- _gl.glBindTexture(GL10.GL_TEXTURE_2D, glId);
- _gl.glEnable(GL10.GL_TEXTURE_2D);
- _gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
- int minFilterType = _textureManager.hasMipMap(textureVo.textureId) ? GL10.GL_LINEAR_MIPMAP_NEAREST : GL10.GL_NEAREST;
- _gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, minFilterType);
- _gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); // (OpenGL default)
-
- // do texture environment settings
- for (int j = 0; j < textureVo.textureEnvs.size(); j++)
- {
- _gl.glTexEnvx(GL10.GL_TEXTURE_ENV, textureVo.textureEnvs.get(j).pname, textureVo.textureEnvs.get(j).param);
- }
-
- // texture wrapping settings
- _gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, (textureVo.repeatU ? GL10.GL_REPEAT : GL10.GL_CLAMP_TO_EDGE));
- _gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, (textureVo.repeatV ? GL10.GL_REPEAT : GL10.GL_CLAMP_TO_EDGE));
- // texture offset, if any
- if (textureVo.offsetU != 0 || textureVo.offsetV != 0)
- {
- _gl.glMatrixMode(GL10.GL_TEXTURE);
- _gl.glLoadIdentity();
- _gl.glTranslatef(textureVo.offsetU, textureVo.offsetV, 0);
- _gl.glMatrixMode(GL10.GL_MODELVIEW); // .. restore matrixmode
- }
- }
- else
- {
- _gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
- _gl.glDisable(GL10.GL_TEXTURE_2D);
- _gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
- }
- }
- else
- {
- _gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
- _gl.glDisable(GL10.GL_TEXTURE_2D);
- _gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
- }
- }
- }
-
- /**
- * Used by TextureManager
- */
- int uploadTextureAndReturnId(Bitmap $bitmap, boolean $generateMipMap) /*package-private*/
- {
- int glTextureId;
-
- int[] a = new int[1];
- _gl.glGenTextures(1, a, 0); // create a 'texture name' and put it in array element 0
- glTextureId = a[0];
- _gl.glBindTexture(GL10.GL_TEXTURE_2D, glTextureId);
-
- if($generateMipMap && _gl instanceof GL11) {
- _gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
- } else {
- _gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_FALSE);
- }
- // 'upload' to gpu
- GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, $bitmap, 0);
-
- return glTextureId;
- }
-
- /**
- * Used by TextureManager
- */
- void deleteTexture(int $glTextureId) /*package-private*/
- {
- int[] a = new int[1];
- a[0] = $glTextureId;
- _gl.glDeleteTextures(1, a, 0);
- }
-
- protected void updateViewFrustrum()
- {
- FrustumManaged vf = _scene.camera().frustum;
- float n = vf.shortSideLength() / 2f;
- float lt, rt, btm, top;
-
- lt = vf.horizontalCenter() - n*_surfaceAspectRatio;
- rt = vf.horizontalCenter() + n*_surfaceAspectRatio;
- btm = vf.verticalCenter() - n*1;
- top = vf.verticalCenter() + n*1;
- if (_surfaceAspectRatio > 1) {
- lt *= 1f/_surfaceAspectRatio;
- rt *= 1f/_surfaceAspectRatio;
- btm *= 1f/_surfaceAspectRatio;
- top *= 1f/_surfaceAspectRatio;
- }
-
- _gl.glMatrixMode(GL10.GL_PROJECTION);
- _gl.glLoadIdentity();
- _gl.glFrustumf(lt,rt, btm,top, vf.zNear(), vf.zFar());
-
- vf.clearDirtyFlag();
- }
- /**
- * If true, framerate and memory is periodically calculated and Log'ed,
- * and gettable thru fps()
- */
- public void logFps(boolean $b)
- {
- _logFps = $b;
-
- if (_logFps) { // init
- _timeLastSample = System.currentTimeMillis();
- _frameCount = 0;
- }
- }
-
- private void setGl(GL10 $gl)
- {
- _gl = $gl;
- }
-
- private void doFps()
- {
- _frameCount++;
- long now = System.currentTimeMillis();
- long delta = now - _timeLastSample;
- if (delta >= FRAMERATE_SAMPLEINTERVAL_MS)
- {
- _fps = _frameCount / (delta/1000f);
- _activityManager.getMemoryInfo(_memoryInfo);
- Log.v(Min3d.TAG, "FPS: " + Math.round(_fps) + ", availMem: " + Math.round(_memoryInfo.availMem/1048576) + "MB");
- _timeLastSample = now;
- _frameCount = 0;
- }
- }
-
- private void reset()
- {
- // Reset TextureManager
- Shared.textureManager().reset();
- // Do OpenGL settings which we are using as defaults, or which we will not be changing on-draw
-
- // Explicit depth settings
- _gl.glEnable(GL10.GL_DEPTH_TEST);
- _gl.glClearDepthf(1.0f);
- _gl.glDepthFunc(GL10.GL_LESS);
- _gl.glDepthRangef(0,1f);
- _gl.glDepthMask(true);
- // Alpha enabled
- _gl.glEnable(GL10.GL_BLEND);
- _gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
-
- // "Transparency is best implemented using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
- // with primitives sorted from farthest to nearest."
- // Texture
- _gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); // (OpenGL default is GL_NEAREST_MIPMAP)
- _gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); // (is OpenGL default)
-
- // CCW frontfaces only, by default
- _gl.glFrontFace(GL10.GL_CCW);
- _gl.glCullFace(GL10.GL_BACK);
- _gl.glEnable(GL10.GL_CULL_FACE);
-
- // Disable lights by default
- for (int i = GL10.GL_LIGHT0; i < GL10.GL_LIGHT0 + NUM_GLLIGHTS; i++) {
- _gl.glDisable(i);
- }
- //
- // Scene object init only happens here, when we get GL for the first time
- //
- }
- }
|