import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix; import android.util.Log; import org.andresoviedo.android_3d_model_engine.animation.Animator; import org.andresoviedo.android_3d_model_engine.drawer.DrawerFactory; import org.andresoviedo.android_3d_model_engine.model.Camera; import org.andresoviedo.android_3d_model_engine.model.AnimatedModel; import org.andresoviedo.android_3d_model_engine.model.Object3D; import org.andresoviedo.android_3d_model_engine.services.Object3DBuilder; import org.andresoviedo.android_3d_model_engine.model.Object3DData; import org.andresoviedo.android_3d_model_engine.drawer.Object3DImpl; import org.andresoviedo.util.android.GLUtil; import java.io.ByteArrayInputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import cz.reinto.olmaar.modelviewer.SceneLoader; public class ModelRenderer implements GLSurfaceView.Renderer { private final static String TAG = ModelRenderer.class.getName(); private SceneLoader sceneLoader; public void setSceneLoader(SceneLoader sceneLoader) { this.sceneLoader = sceneLoader; } // 3D window (parent component) private ModelSurfaceView main; // width of the screen private int width; // height of the screen private int height; // frustrum - nearest pixel private static final float near = 1f; // frustrum - fartest pixel private static final float far = 100f; private DrawerFactory drawer; // The wireframe associated shape (it should be made of lines only) private Map wireframes = new HashMap(); // The loaded textures private Map textures = new HashMap(); // The corresponding opengl bounding boxes and drawer private Map boundingBoxes = new HashMap(); // The corresponding opengl bounding boxes private Map normals = new HashMap(); private Map skeleton = new HashMap<>(); // 3D matrices to project our 3D world private final float[] modelProjectionMatrix = new float[16]; private final float[] modelViewMatrix = new float[16]; // mvpMatrix is an abbreviation for "Model View Projection Matrix" private final float[] mvpMatrix = new float[16]; // light position required to render with lighting private final float[] lightPosInEyeSpace = new float[4]; /** * Whether the info of the model has been written to console log */ private boolean infoLogged = false; /** * Skeleton Animator */ private Animator animator = new Animator(); /** * Construct a new renderer for the specified surface view * * @param modelSurfaceView * the 3D window */ public ModelRenderer(ModelSurfaceView modelSurfaceView) { this.main = modelSurfaceView; } public float getNear() { return near; } public float getFar() { return far; } @Override public void onSurfaceCreated(GL10 unused, EGLConfig config) { // Set the background frame color float[] backgroundColor = new float[] {1.0f, 1.0f, 1.0f, 1.0f}; GLES20.glClearColor(backgroundColor[0], backgroundColor[1], backgroundColor[2], backgroundColor[3]); // Use culling to remove back faces. // Don't remove back faces so we can see them // GLES20.glEnable(GLES20.GL_CULL_FACE); // Enable depth testing for hidden-surface elimination. GLES20.glEnable(GLES20.GL_DEPTH_TEST); // Enable blending for combining colors when there is transparency GLES20.glEnable(GLES20.GL_BLEND); GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); // This component will draw the actual models using OpenGL drawer = new DrawerFactory(); } @Override public void onSurfaceChanged(GL10 unused, int width, int height) { this.width = width; this.height = height; // Adjust the viewport based on geometry changes, such as screen rotation GLES20.glViewport(0, 0, width, height); // INFO: Set the camera position (View matrix) // The camera has 3 vectors (the position, the vector where we are looking at, and the up position (sky) Camera camera = sceneLoader.getCamera(); Matrix.setLookAtM(modelViewMatrix, 0, camera.xPos, camera.yPos, camera.zPos, camera.xView, camera.yView, camera.zView, camera.xUp, camera.yUp, camera.zUp); // the projection matrix is the 3D virtual space (cube) that we want to project float ratio = (float) width / height; Log.d(TAG, "projection: [" + -ratio + "," + ratio + ",-1,1]-near/far[1,10]"); Matrix.frustumM(modelProjectionMatrix, 0, -ratio, ratio, -1, 1, getNear(), getFar()); // Calculate the projection and view transformation Matrix.multiplyMM(mvpMatrix, 0, modelProjectionMatrix, 0, modelViewMatrix, 0); } @Override public void onDrawFrame(GL10 unused) { // Draw background color GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); // animate scene sceneLoader.onDrawFrame(); // recalculate mvp matrix according to where we are looking at now Camera camera = sceneLoader.getCamera(); if (camera.hasChanged()) { Matrix.setLookAtM(modelViewMatrix, 0, camera.xPos, camera.yPos, camera.zPos, camera.xView, camera.yView, camera.zView, camera.xUp, camera.yUp, camera.zUp); // Log.d("Camera", "Changed! :"+camera.ToStringVector()); Matrix.multiplyMM(mvpMatrix, 0, modelProjectionMatrix, 0, modelViewMatrix, 0); camera.setChanged(false); } // draw light /*if (sceneLoader.isDrawLighting()) { Object3DImpl lightBulbDrawer = (Object3DImpl) drawer.getPointDrawer(); float[] lightModelViewMatrix = lightBulbDrawer.getMvMatrix(lightBulbDrawer.getMMatrix(sceneLoader.getLightBulb()),modelViewMatrix); // Calculate position of the light in eye space to support lighting Matrix.multiplyMV(lightPosInEyeSpace, 0, lightModelViewMatrix, 0, sceneLoader.getLightPosition(), 0); // Draw a point that represents the light bulb lightBulbDrawer.draw(sceneLoader.getLightBulb(), modelProjectionMatrix, modelViewMatrix, -1, lightPosInEyeSpace); }*/ List objects = sceneLoader.getObjects(); for (int i=0; i