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
17package com.android.scenegraph;
18
19import java.lang.Math;
20import java.util.ArrayList;
21import java.util.HashMap;
22import java.util.regex.Matcher;
23import java.util.regex.Pattern;
24
25import com.android.scenegraph.Camera;
26import com.android.scenegraph.CompoundTransform;
27import com.android.scenegraph.RenderPass;
28import com.android.scenegraph.Renderable;
29import com.android.scenegraph.SceneManager;
30import com.android.scenegraph.TextureBase;
31
32import android.content.res.Resources;
33import android.os.AsyncTask;
34import android.renderscript.*;
35import android.renderscript.Mesh;
36import android.renderscript.RenderScriptGL;
37import android.util.Log;
38
39/**
40 * @hide
41 */
42public 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
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
81    public void appendTransform(Transform t) {
82        if (t == null) {
83            throw new RuntimeException("Adding null object");
84        }
85        mRootTransforms.appendChild(t);
86    }
87
88    public CompoundTransform appendNewCompoundTransform() {
89        CompoundTransform t = new CompoundTransform();
90        appendTransform(t);
91        return t;
92    }
93
94    public MatrixTransform appendNewMatrixTransform() {
95        MatrixTransform t = new MatrixTransform();
96        appendTransform(t);
97        return t;
98    }
99
100    // temporary
101    public void addToTransformMap(Transform t) {
102        mTransformMap.put(t.getName(), t);
103    }
104
105    public Transform getTransformByName(String name) {
106        return mTransformMap.get(name);
107    }
108
109    public void appendRenderPass(RenderPass p) {
110        if (p == null) {
111            throw new RuntimeException("Adding null object");
112        }
113        mRenderPasses.add(p);
114    }
115
116    public RenderPass appendNewRenderPass() {
117        RenderPass p = new RenderPass();
118        appendRenderPass(p);
119        return p;
120    }
121
122    public void clearRenderPasses() {
123        mRenderPasses.clear();
124    }
125
126    public void appendLight(LightBase l) {
127        if (l == null) {
128            throw new RuntimeException("Adding null object");
129        }
130        mLights.add(l);
131    }
132
133    public void appendCamera(Camera c) {
134        if (c == null) {
135            throw new RuntimeException("Adding null object");
136        }
137        mCameras.add(c);
138    }
139
140    public Camera appendNewCamera() {
141        Camera c = new Camera();
142        appendCamera(c);
143        return c;
144    }
145
146    public void appendShader(FragmentShader f) {
147        if (f == null) {
148            throw new RuntimeException("Adding null object");
149        }
150        mFragmentShaders.add(f);
151    }
152
153    public void appendShader(VertexShader v) {
154        if (v == null) {
155            throw new RuntimeException("Adding null object");
156        }
157        mVertexShaders.add(v);
158    }
159
160    public ArrayList<Camera> getCameras() {
161        return mCameras;
162    }
163
164    public ArrayList<LightBase> getLights() {
165        return mLights;
166    }
167
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
178    public Renderable appendNewRenderable() {
179        Renderable r = new Renderable();
180        appendRenderable(r);
181        return r;
182    }
183
184    public ArrayList<RenderableBase> getRenderables() {
185        return mRenderables;
186    }
187
188    public RenderableBase getRenderableByName(String name) {
189        return mRenderableMap.get(name);
190    }
191
192    public void appendTextures(Texture2D tex) {
193        if (tex == null) {
194            throw new RuntimeException("Adding null object");
195        }
196        mTextures.add(tex);
197    }
198
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
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
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
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
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
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
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
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
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