/* * Copyright (C) 2011 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.scenegraph; import java.lang.Math; import java.util.ArrayList; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.android.scenegraph.Camera; import com.android.scenegraph.CompoundTransform; import com.android.scenegraph.RenderPass; import com.android.scenegraph.Renderable; import com.android.scenegraph.SceneManager; import com.android.scenegraph.TextureBase; import android.content.res.Resources; import android.os.AsyncTask; import android.renderscript.*; import android.renderscript.Mesh; import android.renderscript.RenderScriptGL; import android.util.Log; /** * @hide */ public class Scene extends SceneGraphBase { private static String TIMER_TAG = "TIMER"; CompoundTransform mRootTransforms; HashMap mTransformMap; ArrayList mRenderPasses; ArrayList mLights; ArrayList mCameras; ArrayList mFragmentShaders; ArrayList mVertexShaders; ArrayList mRenderables; HashMap mRenderableMap; ArrayList mTextures; HashMap > mRenderableMeshMap; // RS Specific stuff ScriptField_SgTransform mTransformRSData; RenderScriptGL mRS; Resources mRes; ScriptField_RenderPass_s mRenderPassAlloc; public Scene() { mRenderPasses = new ArrayList(); mLights = new ArrayList(); mCameras = new ArrayList(); mFragmentShaders = new ArrayList(); mVertexShaders = new ArrayList(); mRenderables = new ArrayList(); mRenderableMap = new HashMap(); mRenderableMeshMap = new HashMap >(); mTextures = new ArrayList(); mRootTransforms = new CompoundTransform(); mRootTransforms.setName("_scene_root_"); mTransformMap = new HashMap(); } public void appendTransform(Transform t) { if (t == null) { throw new RuntimeException("Adding null object"); } mRootTransforms.appendChild(t); } public CompoundTransform appendNewCompoundTransform() { CompoundTransform t = new CompoundTransform(); appendTransform(t); return t; } public MatrixTransform appendNewMatrixTransform() { MatrixTransform t = new MatrixTransform(); appendTransform(t); return t; } // temporary public void addToTransformMap(Transform t) { mTransformMap.put(t.getName(), t); } public Transform getTransformByName(String name) { return mTransformMap.get(name); } public void appendRenderPass(RenderPass p) { if (p == null) { throw new RuntimeException("Adding null object"); } mRenderPasses.add(p); } public RenderPass appendNewRenderPass() { RenderPass p = new RenderPass(); appendRenderPass(p); return p; } public void clearRenderPasses() { mRenderPasses.clear(); } public void appendLight(LightBase l) { if (l == null) { throw new RuntimeException("Adding null object"); } mLights.add(l); } public void appendCamera(Camera c) { if (c == null) { throw new RuntimeException("Adding null object"); } mCameras.add(c); } public Camera appendNewCamera() { Camera c = new Camera(); appendCamera(c); return c; } public void appendShader(FragmentShader f) { if (f == null) { throw new RuntimeException("Adding null object"); } mFragmentShaders.add(f); } public void appendShader(VertexShader v) { if (v == null) { throw new RuntimeException("Adding null object"); } mVertexShaders.add(v); } public ArrayList getCameras() { return mCameras; } public ArrayList getLights() { return mLights; } public void appendRenderable(RenderableBase d) { if (d == null) { throw new RuntimeException("Adding null object"); } mRenderables.add(d); if (d.getName() != null) { mRenderableMap.put(d.getName(), d); } } public Renderable appendNewRenderable() { Renderable r = new Renderable(); appendRenderable(r); return r; } public ArrayList getRenderables() { return mRenderables; } public RenderableBase getRenderableByName(String name) { return mRenderableMap.get(name); } public void appendTextures(Texture2D tex) { if (tex == null) { throw new RuntimeException("Adding null object"); } mTextures.add(tex); } public void assignRenderStateToMaterial(RenderState renderState, String regex) { Pattern pattern = Pattern.compile(regex); int numRenderables = mRenderables.size(); for (int i = 0; i < numRenderables; i ++) { Renderable shape = (Renderable)mRenderables.get(i); Matcher m = pattern.matcher(shape.mMaterialName); if (m.find()) { shape.setRenderState(renderState); } } } public void assignRenderState(RenderState renderState) { int numRenderables = mRenderables.size(); for (int i = 0; i < numRenderables; i ++) { Renderable shape = (Renderable)mRenderables.get(i); shape.setRenderState(renderState); } } public void meshLoaded(Mesh m) { ArrayList entries = mRenderableMeshMap.get(m.getName()); int numEntries = entries.size(); for (int i = 0; i < numEntries; i++) { Renderable d = entries.get(i); d.resolveMeshData(m); } } void addToMeshMap(Renderable d) { ArrayList entries = mRenderableMeshMap.get(d.mMeshName); if (entries == null) { entries = new ArrayList(); mRenderableMeshMap.put(d.mMeshName, entries); } entries.add(d); } public void destroyRS() { SceneManager sceneManager = SceneManager.getInstance(); mTransformRSData = null; sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData); sceneManager.mRenderLoop.set_gRenderableObjects(null); mRenderPassAlloc = null; sceneManager.mRenderLoop.set_gRenderPasses(null); sceneManager.mRenderLoop.bind_gFrontToBack(null); sceneManager.mRenderLoop.bind_gBackToFront(null); sceneManager.mRenderLoop.set_gCameras(null); mTransformMap = null; mRenderPasses = null; mLights = null; mCameras = null; mRenderables = null; mRenderableMap = null; mTextures = null; mRenderableMeshMap = null; mRootTransforms = null; } public void initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager) { if (mRenderPasses.size() != 0) { mRenderPassAlloc = new ScriptField_RenderPass_s(mRS, mRenderPasses.size()); for (int i = 0; i < mRenderPasses.size(); i ++) { mRenderPassAlloc.set(mRenderPasses.get(i).getRsField(mRS, mRes), i, false); } mRenderPassAlloc.copyAll(); sceneManager.mRenderLoop.set_gRenderPasses(mRenderPassAlloc.getAllocation()); } } private void addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager) { Allocation drawableData = Allocation.createSized(rs, Element.ALLOCATION(rs), mRenderables.size()); Allocation[] drawableAllocs = new Allocation[mRenderables.size()]; for (int i = 0; i < mRenderables.size(); i ++) { Renderable dI = (Renderable)mRenderables.get(i); addToMeshMap(dI); drawableAllocs[i] = dI.getRsField(rs, res).getAllocation(); } drawableData.copyFrom(drawableAllocs); sceneManager.mRenderLoop.set_gRenderableObjects(drawableData); initRenderPassRS(rs, sceneManager); } private void addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager) { if (mVertexShaders.size() > 0) { Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), mVertexShaders.size()); Allocation[] shaderAllocs = new Allocation[mVertexShaders.size()]; for (int i = 0; i < mVertexShaders.size(); i ++) { VertexShader sI = mVertexShaders.get(i); shaderAllocs[i] = sI.getRSData().getAllocation(); } shaderData.copyFrom(shaderAllocs); sceneManager.mRenderLoop.set_gVertexShaders(shaderData); } if (mFragmentShaders.size() > 0) { Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), mFragmentShaders.size()); Allocation[] shaderAllocs = new Allocation[mFragmentShaders.size()]; for (int i = 0; i < mFragmentShaders.size(); i ++) { FragmentShader sI = mFragmentShaders.get(i); shaderAllocs[i] = sI.getRSData().getAllocation(); } shaderData.copyFrom(shaderAllocs); sceneManager.mRenderLoop.set_gFragmentShaders(shaderData); } } public void initRS() { SceneManager sceneManager = SceneManager.getInstance(); mRS = SceneManager.getRS(); mRes = SceneManager.getRes(); long start = System.currentTimeMillis(); mTransformRSData = mRootTransforms.getRSData(); long end = System.currentTimeMillis(); Log.v(TIMER_TAG, "Transform init time: " + (end - start)); start = System.currentTimeMillis(); sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData); end = System.currentTimeMillis(); Log.v(TIMER_TAG, "Script init time: " + (end - start)); start = System.currentTimeMillis(); addDrawables(mRS, mRes, sceneManager); end = System.currentTimeMillis(); Log.v(TIMER_TAG, "Renderable init time: " + (end - start)); addShaders(mRS, mRes, sceneManager); Allocation opaqueBuffer = null; if (mRenderables.size() > 0) { opaqueBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size()); } Allocation transparentBuffer = null; if (mRenderables.size() > 0) { transparentBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size()); } sceneManager.mRenderLoop.bind_gFrontToBack(opaqueBuffer); sceneManager.mRenderLoop.bind_gBackToFront(transparentBuffer); if (mCameras.size() > 0) { Allocation cameraData; cameraData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mCameras.size()); Allocation[] cameraAllocs = new Allocation[mCameras.size()]; for (int i = 0; i < mCameras.size(); i ++) { cameraAllocs[i] = mCameras.get(i).getRSData().getAllocation(); } cameraData.copyFrom(cameraAllocs); sceneManager.mRenderLoop.set_gCameras(cameraData); } if (mLights.size() > 0) { Allocation lightData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mLights.size()); Allocation[] lightAllocs = new Allocation[mLights.size()]; for (int i = 0; i < mLights.size(); i ++) { lightAllocs[i] = mLights.get(i).getRSData().getAllocation(); } lightData.copyFrom(lightAllocs); sceneManager.mRenderLoop.set_gLights(lightData); } } }