1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.scenegraph;
18 
19 import java.lang.Math;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24 
25 import com.android.scenegraph.Camera;
26 import com.android.scenegraph.CompoundTransform;
27 import com.android.scenegraph.RenderPass;
28 import com.android.scenegraph.Renderable;
29 import com.android.scenegraph.SceneManager;
30 import com.android.scenegraph.TextureBase;
31 
32 import android.content.res.Resources;
33 import android.os.AsyncTask;
34 import android.renderscript.*;
35 import android.renderscript.Mesh;
36 import android.renderscript.RenderScriptGL;
37 import android.util.Log;
38 
39 /**
40  * @hide
41  */
42 public class Scene extends SceneGraphBase {
43     private static String TIMER_TAG = "TIMER";
44 
45     CompoundTransform mRootTransforms;
46     HashMap<String, Transform> mTransformMap;
47     ArrayList<RenderPass> mRenderPasses;
48     ArrayList<LightBase> mLights;
49     ArrayList<Camera> mCameras;
50     ArrayList<FragmentShader> mFragmentShaders;
51     ArrayList<VertexShader> mVertexShaders;
52     ArrayList<RenderableBase> mRenderables;
53     HashMap<String, RenderableBase> mRenderableMap;
54     ArrayList<Texture2D> mTextures;
55 
56     HashMap<String, ArrayList<Renderable> > mRenderableMeshMap;
57 
58     // RS Specific stuff
59     ScriptField_SgTransform mTransformRSData;
60 
61     RenderScriptGL mRS;
62     Resources mRes;
63 
64     ScriptField_RenderPass_s mRenderPassAlloc;
65 
Scene()66     public Scene() {
67         mRenderPasses = new ArrayList<RenderPass>();
68         mLights = new ArrayList<LightBase>();
69         mCameras = new ArrayList<Camera>();
70         mFragmentShaders = new ArrayList<FragmentShader>();
71         mVertexShaders = new ArrayList<VertexShader>();
72         mRenderables = new ArrayList<RenderableBase>();
73         mRenderableMap = new HashMap<String, RenderableBase>();
74         mRenderableMeshMap = new HashMap<String, ArrayList<Renderable> >();
75         mTextures = new ArrayList<Texture2D>();
76         mRootTransforms = new CompoundTransform();
77         mRootTransforms.setName("_scene_root_");
78         mTransformMap = new HashMap<String, Transform>();
79     }
80 
appendTransform(Transform t)81     public void appendTransform(Transform t) {
82         if (t == null) {
83             throw new RuntimeException("Adding null object");
84         }
85         mRootTransforms.appendChild(t);
86     }
87 
appendNewCompoundTransform()88     public CompoundTransform appendNewCompoundTransform() {
89         CompoundTransform t = new CompoundTransform();
90         appendTransform(t);
91         return t;
92     }
93 
appendNewMatrixTransform()94     public MatrixTransform appendNewMatrixTransform() {
95         MatrixTransform t = new MatrixTransform();
96         appendTransform(t);
97         return t;
98     }
99 
100     // temporary
addToTransformMap(Transform t)101     public void addToTransformMap(Transform t) {
102         mTransformMap.put(t.getName(), t);
103     }
104 
getTransformByName(String name)105     public Transform getTransformByName(String name) {
106         return mTransformMap.get(name);
107     }
108 
appendRenderPass(RenderPass p)109     public void appendRenderPass(RenderPass p) {
110         if (p == null) {
111             throw new RuntimeException("Adding null object");
112         }
113         mRenderPasses.add(p);
114     }
115 
appendNewRenderPass()116     public RenderPass appendNewRenderPass() {
117         RenderPass p = new RenderPass();
118         appendRenderPass(p);
119         return p;
120     }
121 
clearRenderPasses()122     public void clearRenderPasses() {
123         mRenderPasses.clear();
124     }
125 
appendLight(LightBase l)126     public void appendLight(LightBase l) {
127         if (l == null) {
128             throw new RuntimeException("Adding null object");
129         }
130         mLights.add(l);
131     }
132 
appendCamera(Camera c)133     public void appendCamera(Camera c) {
134         if (c == null) {
135             throw new RuntimeException("Adding null object");
136         }
137         mCameras.add(c);
138     }
139 
appendNewCamera()140     public Camera appendNewCamera() {
141         Camera c = new Camera();
142         appendCamera(c);
143         return c;
144     }
145 
appendShader(FragmentShader f)146     public void appendShader(FragmentShader f) {
147         if (f == null) {
148             throw new RuntimeException("Adding null object");
149         }
150         mFragmentShaders.add(f);
151     }
152 
appendShader(VertexShader v)153     public void appendShader(VertexShader v) {
154         if (v == null) {
155             throw new RuntimeException("Adding null object");
156         }
157         mVertexShaders.add(v);
158     }
159 
getCameras()160     public ArrayList<Camera> getCameras() {
161         return mCameras;
162     }
163 
getLights()164     public ArrayList<LightBase> getLights() {
165         return mLights;
166     }
167 
appendRenderable(RenderableBase d)168     public void appendRenderable(RenderableBase d) {
169         if (d == null) {
170             throw new RuntimeException("Adding null object");
171         }
172         mRenderables.add(d);
173         if (d.getName() != null) {
174             mRenderableMap.put(d.getName(), d);
175         }
176     }
177 
appendNewRenderable()178     public Renderable appendNewRenderable() {
179         Renderable r = new Renderable();
180         appendRenderable(r);
181         return r;
182     }
183 
getRenderables()184     public ArrayList<RenderableBase> getRenderables() {
185         return mRenderables;
186     }
187 
getRenderableByName(String name)188     public RenderableBase getRenderableByName(String name) {
189         return mRenderableMap.get(name);
190     }
191 
appendTextures(Texture2D tex)192     public void appendTextures(Texture2D tex) {
193         if (tex == null) {
194             throw new RuntimeException("Adding null object");
195         }
196         mTextures.add(tex);
197     }
198 
assignRenderStateToMaterial(RenderState renderState, String regex)199     public void assignRenderStateToMaterial(RenderState renderState, String regex) {
200         Pattern pattern = Pattern.compile(regex);
201         int numRenderables = mRenderables.size();
202         for (int i = 0; i < numRenderables; i ++) {
203             Renderable shape = (Renderable)mRenderables.get(i);
204             Matcher m = pattern.matcher(shape.mMaterialName);
205             if (m.find()) {
206                 shape.setRenderState(renderState);
207             }
208         }
209     }
210 
assignRenderState(RenderState renderState)211     public void assignRenderState(RenderState renderState) {
212         int numRenderables = mRenderables.size();
213         for (int i = 0; i < numRenderables; i ++) {
214             Renderable shape = (Renderable)mRenderables.get(i);
215             shape.setRenderState(renderState);
216         }
217     }
218 
meshLoaded(Mesh m)219     public void meshLoaded(Mesh m) {
220         ArrayList<Renderable> entries = mRenderableMeshMap.get(m.getName());
221         int numEntries = entries.size();
222         for (int i = 0; i < numEntries; i++) {
223             Renderable d = entries.get(i);
224             d.resolveMeshData(m);
225         }
226     }
227 
addToMeshMap(Renderable d)228     void addToMeshMap(Renderable d) {
229         ArrayList<Renderable> entries = mRenderableMeshMap.get(d.mMeshName);
230         if (entries == null) {
231             entries = new ArrayList<Renderable>();
232             mRenderableMeshMap.put(d.mMeshName, entries);
233         }
234         entries.add(d);
235     }
236 
destroyRS()237     public void destroyRS() {
238         SceneManager sceneManager = SceneManager.getInstance();
239         mTransformRSData = null;
240         sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
241         sceneManager.mRenderLoop.set_gRenderableObjects(null);
242         mRenderPassAlloc = null;
243         sceneManager.mRenderLoop.set_gRenderPasses(null);
244         sceneManager.mRenderLoop.bind_gFrontToBack(null);
245         sceneManager.mRenderLoop.bind_gBackToFront(null);
246         sceneManager.mRenderLoop.set_gCameras(null);
247 
248         mTransformMap = null;
249         mRenderPasses = null;
250         mLights = null;
251         mCameras = null;
252         mRenderables = null;
253         mRenderableMap = null;
254         mTextures = null;
255         mRenderableMeshMap = null;
256         mRootTransforms = null;
257     }
258 
initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager)259     public void initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager) {
260         if (mRenderPasses.size() != 0) {
261             mRenderPassAlloc = new ScriptField_RenderPass_s(mRS, mRenderPasses.size());
262             for (int i = 0; i < mRenderPasses.size(); i ++) {
263                 mRenderPassAlloc.set(mRenderPasses.get(i).getRsField(mRS, mRes), i, false);
264             }
265             mRenderPassAlloc.copyAll();
266             sceneManager.mRenderLoop.set_gRenderPasses(mRenderPassAlloc.getAllocation());
267         }
268     }
269 
addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager)270     private void addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
271         Allocation drawableData = Allocation.createSized(rs,
272                                                          Element.ALLOCATION(rs),
273                                                          mRenderables.size());
274         Allocation[] drawableAllocs = new Allocation[mRenderables.size()];
275         for (int i = 0; i < mRenderables.size(); i ++) {
276             Renderable dI = (Renderable)mRenderables.get(i);
277             addToMeshMap(dI);
278             drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
279         }
280         drawableData.copyFrom(drawableAllocs);
281         sceneManager.mRenderLoop.set_gRenderableObjects(drawableData);
282 
283         initRenderPassRS(rs, sceneManager);
284     }
285 
addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager)286     private void addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
287         if (mVertexShaders.size() > 0) {
288             Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs),
289                                                            mVertexShaders.size());
290             Allocation[] shaderAllocs = new Allocation[mVertexShaders.size()];
291             for (int i = 0; i < mVertexShaders.size(); i ++) {
292                 VertexShader sI = mVertexShaders.get(i);
293                 shaderAllocs[i] = sI.getRSData().getAllocation();
294             }
295             shaderData.copyFrom(shaderAllocs);
296             sceneManager.mRenderLoop.set_gVertexShaders(shaderData);
297         }
298 
299         if (mFragmentShaders.size() > 0) {
300             Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs),
301                                                            mFragmentShaders.size());
302             Allocation[] shaderAllocs = new Allocation[mFragmentShaders.size()];
303             for (int i = 0; i < mFragmentShaders.size(); i ++) {
304                 FragmentShader sI = mFragmentShaders.get(i);
305                 shaderAllocs[i] = sI.getRSData().getAllocation();
306             }
307             shaderData.copyFrom(shaderAllocs);
308             sceneManager.mRenderLoop.set_gFragmentShaders(shaderData);
309         }
310     }
311 
initRS()312     public void initRS() {
313         SceneManager sceneManager = SceneManager.getInstance();
314         mRS = SceneManager.getRS();
315         mRes = SceneManager.getRes();
316         long start = System.currentTimeMillis();
317         mTransformRSData = mRootTransforms.getRSData();
318         long end = System.currentTimeMillis();
319         Log.v(TIMER_TAG, "Transform init time: " + (end - start));
320 
321         start = System.currentTimeMillis();
322 
323         sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
324         end = System.currentTimeMillis();
325         Log.v(TIMER_TAG, "Script init time: " + (end - start));
326 
327         start = System.currentTimeMillis();
328         addDrawables(mRS, mRes, sceneManager);
329         end = System.currentTimeMillis();
330         Log.v(TIMER_TAG, "Renderable init time: " + (end - start));
331 
332         addShaders(mRS, mRes, sceneManager);
333 
334         Allocation opaqueBuffer = null;
335         if (mRenderables.size() > 0) {
336             opaqueBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
337         }
338         Allocation transparentBuffer = null;
339         if (mRenderables.size() > 0) {
340             transparentBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
341         }
342 
343         sceneManager.mRenderLoop.bind_gFrontToBack(opaqueBuffer);
344         sceneManager.mRenderLoop.bind_gBackToFront(transparentBuffer);
345 
346         if (mCameras.size() > 0) {
347             Allocation cameraData;
348             cameraData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mCameras.size());
349             Allocation[] cameraAllocs = new Allocation[mCameras.size()];
350             for (int i = 0; i < mCameras.size(); i ++) {
351                 cameraAllocs[i] = mCameras.get(i).getRSData().getAllocation();
352             }
353             cameraData.copyFrom(cameraAllocs);
354             sceneManager.mRenderLoop.set_gCameras(cameraData);
355         }
356 
357         if (mLights.size() > 0) {
358             Allocation lightData = Allocation.createSized(mRS,
359                                                           Element.ALLOCATION(mRS),
360                                                           mLights.size());
361             Allocation[] lightAllocs = new Allocation[mLights.size()];
362             for (int i = 0; i < mLights.size(); i ++) {
363                 lightAllocs[i] = mLights.get(i).getRSData().getAllocation();
364             }
365             lightData.copyFrom(lightAllocs);
366             sceneManager.mRenderLoop.set_gLights(lightData);
367         }
368     }
369 }
370 
371 
372 
373 
374