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.io.BufferedInputStream;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.Writer;
25 import java.lang.Math;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 
31 import com.android.scenegraph.Camera;
32 import com.android.scenegraph.FragmentShader;
33 import com.android.scenegraph.MatrixTransform;
34 import com.android.scenegraph.Scene;
35 import com.android.scenegraph.VertexShader;
36 import com.android.testapp.R;
37 
38 import android.content.res.Resources;
39 import android.graphics.Bitmap;
40 import android.graphics.BitmapFactory;
41 import android.os.AsyncTask;
42 import android.renderscript.*;
43 import android.renderscript.Allocation.MipmapControl;
44 import android.renderscript.Mesh;
45 import android.renderscript.RenderScriptGL;
46 import android.util.Log;
47 import android.view.SurfaceHolder;
48 
49 /**
50  * @hide
51  */
52 public class SceneManager extends SceneGraphBase {
53 
54     HashMap<String, Allocation> mAllocationMap;
55 
56     ScriptC_render mRenderLoop;
57     ScriptC mCameraScript;
58     ScriptC mLightScript;
59     ScriptC mObjectParamsScript;
60     ScriptC mFragmentParamsScript;
61     ScriptC mVertexParamsScript;
62     ScriptC mCullScript;
63     ScriptC_transform mTransformScript;
64     ScriptC_export mExportScript;
65 
66     RenderScriptGL mRS;
67     Resources mRes;
68     Mesh mQuad;
69     int mWidth;
70     int mHeight;
71 
72     Scene mActiveScene;
73     private static SceneManager sSceneManager;
74 
75     private Allocation mDefault2D;
76     private Allocation mDefaultCube;
77 
78     private FragmentShader mColor;
79     private FragmentShader mTexture;
80     private VertexShader mDefaultVertex;
81 
82     private RenderState mDefaultState;
83     private Transform mDefaultTransform;
84 
getDefault(boolean isCube)85     private static Allocation getDefault(boolean isCube) {
86         final int dimension = 4;
87         final int bytesPerPixel = 4;
88         int arraySize = dimension * dimension * bytesPerPixel;
89 
90         RenderScriptGL rs = sSceneManager.mRS;
91         Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
92         b.setX(dimension).setY(dimension);
93         if (isCube) {
94             b.setFaces(true);
95             arraySize *= 6;
96         }
97         Type bitmapType = b.create();
98 
99         Allocation.MipmapControl mip = Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE;
100         int usage =  Allocation.USAGE_GRAPHICS_TEXTURE;
101         Allocation defaultImage = Allocation.createTyped(rs, bitmapType, mip, usage);
102 
103         byte imageData[] = new byte[arraySize];
104         defaultImage.copyFrom(imageData);
105         return defaultImage;
106     }
107 
getDefaultTex2D()108     static Allocation getDefaultTex2D() {
109         if (sSceneManager == null) {
110             return null;
111         }
112         if (sSceneManager.mDefault2D == null) {
113             sSceneManager.mDefault2D = getDefault(false);
114         }
115         return sSceneManager.mDefault2D;
116     }
117 
getDefaultTexCube()118     static Allocation getDefaultTexCube() {
119         if (sSceneManager == null) {
120             return null;
121         }
122         if (sSceneManager.mDefaultCube == null) {
123             sSceneManager.mDefaultCube = getDefault(true);
124         }
125         return sSceneManager.mDefaultCube;
126     }
127 
isSDCardPath(String path)128     public static boolean isSDCardPath(String path) {
129         int sdCardIndex = path.indexOf("sdcard/");
130         // We are looking for /sdcard/ or sdcard/
131         if (sdCardIndex == 0 || sdCardIndex == 1) {
132             return true;
133         }
134         sdCardIndex = path.indexOf("mnt/sdcard/");
135         if (sdCardIndex == 0 || sdCardIndex == 1) {
136             return true;
137         }
138         return false;
139     }
140 
loadBitmap(String name, Resources res)141     static Bitmap loadBitmap(String name, Resources res) {
142         InputStream is = null;
143         boolean loadFromSD = isSDCardPath(name);
144         try {
145             if (!loadFromSD) {
146                 is = res.getAssets().open(name);
147             } else {
148                 File f = new File(name);
149                 is = new BufferedInputStream(new FileInputStream(f));
150             }
151         } catch (IOException e) {
152             Log.e("ImageLoaderTask", " Message: " + e.getMessage());
153             return null;
154         }
155 
156         Bitmap b = BitmapFactory.decodeStream(is);
157         try {
158             is.close();
159         } catch (IOException e) {
160             Log.e("ImageLoaderTask", " Message: " + e.getMessage());
161         }
162         return b;
163     }
164 
createFromBitmap(Bitmap b, RenderScriptGL rs, boolean isCube)165     static Allocation createFromBitmap(Bitmap b, RenderScriptGL rs, boolean isCube) {
166         if (b == null) {
167             return null;
168         }
169         MipmapControl mip = MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE;
170         int usage = Allocation.USAGE_GRAPHICS_TEXTURE;
171         if (isCube) {
172             return Allocation.createCubemapFromBitmap(rs, b, mip, usage);
173         }
174         return Allocation.createFromBitmap(rs, b, mip, usage);
175     }
176 
loadCubemap(String name, RenderScriptGL rs, Resources res)177     public static Allocation loadCubemap(String name, RenderScriptGL rs, Resources res) {
178         return createFromBitmap(loadBitmap(name, res), rs, true);
179     }
180 
loadCubemap(int id, RenderScriptGL rs, Resources res)181     public static Allocation loadCubemap(int id, RenderScriptGL rs, Resources res) {
182         return createFromBitmap(BitmapFactory.decodeResource(res, id), rs, true);
183     }
184 
loadTexture2D(String name, RenderScriptGL rs, Resources res)185     public static Allocation loadTexture2D(String name, RenderScriptGL rs, Resources res) {
186         return createFromBitmap(loadBitmap(name, res), rs, false);
187     }
188 
loadTexture2D(int id, RenderScriptGL rs, Resources res)189     public static Allocation loadTexture2D(int id, RenderScriptGL rs, Resources res) {
190         return createFromBitmap(BitmapFactory.decodeResource(res, id), rs, false);
191     }
192 
BLEND_ADD_DEPTH_NONE(RenderScript rs)193     public static ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
194         ProgramStore.Builder builder = new ProgramStore.Builder(rs);
195         builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
196         builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
197         builder.setDitherEnabled(false);
198         builder.setDepthMaskEnabled(false);
199         return builder.create();
200     }
201 
getStringAsAllocation(RenderScript rs, String str)202     static Allocation getStringAsAllocation(RenderScript rs, String str) {
203         if (str == null) {
204             return null;
205         }
206         if (str.length() == 0) {
207             return null;
208         }
209         byte[] allocArray = null;
210         byte[] nullChar = new byte[1];
211         nullChar[0] = 0;
212         try {
213             allocArray = str.getBytes("UTF-8");
214             Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
215                                                       allocArray.length + 1,
216                                                       Allocation.USAGE_SCRIPT);
217             alloc.copy1DRangeFrom(0, allocArray.length, allocArray);
218             alloc.copy1DRangeFrom(allocArray.length, 1, nullChar);
219             return alloc;
220         }
221         catch (Exception e) {
222             throw new RSRuntimeException("Could not convert string to utf-8.");
223         }
224     }
225 
getCachedAlloc(String str)226     static Allocation getCachedAlloc(String str) {
227         if (sSceneManager == null) {
228             throw new RuntimeException("Scene manager not initialized");
229         }
230         return sSceneManager.mAllocationMap.get(str);
231     }
232 
cacheAlloc(String str, Allocation alloc)233     static void cacheAlloc(String str, Allocation alloc) {
234         if (sSceneManager == null) {
235             throw new RuntimeException("Scene manager not initialized");
236         }
237         sSceneManager.mAllocationMap.put(str, alloc);
238     }
239 
240     public static class SceneLoadedCallback implements Runnable {
241         public Scene mLoadedScene;
242         public String mName;
run()243         public void run() {
244         }
245     }
246 
getActiveScene()247     public Scene getActiveScene() {
248         return mActiveScene;
249     }
250 
setActiveScene(Scene s)251     public void setActiveScene(Scene s) {
252         mActiveScene = s;
253 
254         if (mActiveScene == null) {
255             return;
256         }
257 
258         // Do some sanity checking
259         if (mActiveScene.getCameras().size() == 0) {
260             Matrix4f camPos = new Matrix4f();
261             camPos.translate(0, 0, 10);
262             MatrixTransform cameraTransform = new MatrixTransform();
263             cameraTransform.setName("_DefaultCameraTransform");
264             cameraTransform.setMatrix(camPos);
265             mActiveScene.appendTransform(cameraTransform);
266             Camera cam = new Camera();
267             cam.setName("_DefaultCamera");
268             cam.setTransform(cameraTransform);
269             mActiveScene.appendCamera(cam);
270         }
271 
272         mActiveScene.appendShader(getDefaultVS());
273         mActiveScene.appendTransform(getDefaultTransform());
274     }
275 
getRS()276     static RenderScriptGL getRS() {
277         if (sSceneManager == null) {
278             return null;
279         }
280         return sSceneManager.mRS;
281     }
282 
getRes()283     static Resources getRes() {
284         if (sSceneManager == null) {
285             return null;
286         }
287         return sSceneManager.mRes;
288     }
289 
290     // Provides the folowing inputs to fragment shader
291     // Assigned by default if nothing is present
292     // vec3 varWorldPos;
293     // vec3 varWorldNormal;
294     // vec2 varTex0;
getDefaultVS()295     public static VertexShader getDefaultVS() {
296         if (sSceneManager == null) {
297             return null;
298         }
299 
300         if (sSceneManager.mDefaultVertex == null) {
301             RenderScriptGL rs = getRS();
302             Element.Builder b = new Element.Builder(rs);
303             b.add(Element.MATRIX_4X4(rs), "model");
304             Type.Builder objConstBuilder = new Type.Builder(rs, b.create());
305 
306             b = new Element.Builder(rs);
307             b.add(Element.MATRIX_4X4(rs), "viewProj");
308             Type.Builder shaderConstBuilder = new Type.Builder(rs, b.create());
309 
310             b = new Element.Builder(rs);
311             b.add(Element.F32_4(rs), "position");
312             b.add(Element.F32_2(rs), "texture0");
313             b.add(Element.F32_3(rs), "normal");
314             Element defaultIn = b.create();
315 
316             final String code = "\n" +
317                 "varying vec3 varWorldPos;\n" +
318                 "varying vec3 varWorldNormal;\n" +
319                 "varying vec2 varTex0;\n" +
320                 "void main() {" +
321                 "   vec4 objPos = ATTRIB_position;\n" +
322                 "   vec4 worldPos = UNI_model * objPos;\n" +
323                 "   gl_Position = UNI_viewProj * worldPos;\n" +
324                 "   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);\n" +
325                 "   vec3 worldNorm = model3 * ATTRIB_normal;\n" +
326                 "   varWorldPos = worldPos.xyz;\n" +
327                 "   varWorldNormal = worldNorm;\n" +
328                 "   varTex0 = ATTRIB_texture0;\n" +
329                 "}\n";
330 
331             VertexShader.Builder sb = new VertexShader.Builder(rs);
332             sb.addInput(defaultIn);
333             sb.setObjectConst(objConstBuilder.setX(1).create());
334             sb.setShaderConst(shaderConstBuilder.setX(1).create());
335             sb.setShader(code);
336             sSceneManager.mDefaultVertex = sb.create();
337         }
338 
339         return sSceneManager.mDefaultVertex;
340     }
341 
getColorFS()342     public static FragmentShader getColorFS() {
343         if (sSceneManager == null) {
344             return null;
345         }
346         if (sSceneManager.mColor == null) {
347             RenderScriptGL rs = getRS();
348             Element.Builder b = new Element.Builder(rs);
349             b.add(Element.F32_4(rs), "color");
350             Type.Builder objConstBuilder = new Type.Builder(rs, b.create());
351 
352             final String code = "\n" +
353                 "varying vec2 varTex0;\n" +
354                 "void main() {\n" +
355                 "   lowp vec4 col = UNI_color;\n" +
356                 "   gl_FragColor = col;\n" +
357                 "}\n";
358             FragmentShader.Builder fb = new FragmentShader.Builder(rs);
359             fb.setShader(code);
360             fb.setObjectConst(objConstBuilder.create());
361             sSceneManager.mColor = fb.create();
362         }
363 
364         return sSceneManager.mColor;
365     }
366 
getTextureFS()367     public static FragmentShader getTextureFS() {
368         if (sSceneManager == null) {
369             return null;
370         }
371         if (sSceneManager.mTexture == null) {
372             RenderScriptGL rs = getRS();
373 
374             final String code = "\n" +
375                 "varying vec2 varTex0;\n" +
376                 "void main() {\n" +
377                 "   lowp vec4 col = texture2D(UNI_color, varTex0).rgba;\n" +
378                 "   gl_FragColor = col;\n" +
379                 "}\n";
380 
381             FragmentShader.Builder fb = new FragmentShader.Builder(rs);
382             fb.setShader(code);
383             fb.addTexture(Program.TextureType.TEXTURE_2D, "color");
384             sSceneManager.mTexture = fb.create();
385             sSceneManager.mTexture.mProgram.bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(rs), 0);
386         }
387 
388         return sSceneManager.mTexture;
389     }
390 
getDefaultState()391     static RenderState getDefaultState() {
392         if (sSceneManager == null) {
393             return null;
394         }
395         if (sSceneManager.mDefaultState == null) {
396             sSceneManager.mDefaultState = new RenderState(getDefaultVS(), getColorFS(), null, null);
397             sSceneManager.mDefaultState.setName("__DefaultState");
398         }
399         return sSceneManager.mDefaultState;
400     }
401 
getDefaultTransform()402     static Transform getDefaultTransform() {
403         if (sSceneManager == null) {
404             return null;
405         }
406         if (sSceneManager.mDefaultTransform == null) {
407             sSceneManager.mDefaultTransform = new MatrixTransform();
408             sSceneManager.mDefaultTransform.setName("__DefaultTransform");
409         }
410         return sSceneManager.mDefaultTransform;
411     }
412 
getInstance()413     public static SceneManager getInstance() {
414         if (sSceneManager == null) {
415             sSceneManager = new SceneManager();
416         }
417         return sSceneManager;
418     }
419 
SceneManager()420     protected SceneManager() {
421     }
422 
loadModel(String name, SceneLoadedCallback cb)423     public void loadModel(String name, SceneLoadedCallback cb) {
424         ColladaScene scene = new ColladaScene(name, cb);
425         scene.init(mRS, mRes);
426     }
427 
getScreenAlignedQuad()428     public Mesh getScreenAlignedQuad() {
429         if (mQuad != null) {
430             return mQuad;
431         }
432 
433         Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
434                                            3, Mesh.TriangleMeshBuilder.TEXTURE_0);
435 
436         tmb.setTexture(0.0f, 1.0f).addVertex(-1.0f, 1.0f, 1.0f);
437         tmb.setTexture(0.0f, 0.0f).addVertex(-1.0f, -1.0f, 1.0f);
438         tmb.setTexture(1.0f, 0.0f).addVertex(1.0f, -1.0f, 1.0f);
439         tmb.setTexture(1.0f, 1.0f).addVertex(1.0f, 1.0f, 1.0f);
440 
441         tmb.addTriangle(0, 1, 2);
442         tmb.addTriangle(2, 3, 0);
443 
444         mQuad = tmb.create(true);
445         return mQuad;
446     }
447 
getRenderableQuad(String name, RenderState state)448     public Renderable getRenderableQuad(String name, RenderState state) {
449         Renderable quad = new Renderable();
450         quad.setTransform(new MatrixTransform());
451         quad.setMesh(getScreenAlignedQuad());
452         quad.setName(name);
453         quad.setRenderState(state);
454         quad.setCullType(1);
455         return quad;
456     }
457 
initRS(RenderScriptGL rs, Resources res, int w, int h)458     public void initRS(RenderScriptGL rs, Resources res, int w, int h) {
459         mRS = rs;
460         mRes = res;
461         mAllocationMap = new HashMap<String, Allocation>();
462 
463         mQuad = null;
464         mDefault2D = null;
465         mDefaultCube = null;
466         mDefaultVertex = null;
467         mColor = null;
468         mTexture = null;
469         mDefaultState = null;
470         mDefaultTransform = null;
471 
472         mExportScript = new ScriptC_export(rs, res, R.raw.export);
473 
474         mTransformScript = new ScriptC_transform(rs, res, R.raw.transform);
475         mTransformScript.set_gTransformScript(mTransformScript);
476 
477         mCameraScript = new ScriptC_camera(rs, res, R.raw.camera);
478         mLightScript = new ScriptC_light(rs, res, R.raw.light);
479         mObjectParamsScript = new ScriptC_object_params(rs, res, R.raw.object_params);
480         mFragmentParamsScript = new ScriptC_object_params(rs, res, R.raw.fragment_params);
481         mVertexParamsScript = new ScriptC_object_params(rs, res, R.raw.vertex_params);
482         mCullScript = new ScriptC_cull(rs, res, R.raw.cull);
483 
484         mRenderLoop = new ScriptC_render(rs, res, R.raw.render);
485         mRenderLoop.set_gTransformScript(mTransformScript);
486         mRenderLoop.set_gCameraScript(mCameraScript);
487         mRenderLoop.set_gLightScript(mLightScript);
488         mRenderLoop.set_gObjectParamsScript(mObjectParamsScript);
489         mRenderLoop.set_gFragmentParamsScript(mFragmentParamsScript);
490         mRenderLoop.set_gVertexParamsScript(mVertexParamsScript);
491         mRenderLoop.set_gCullScript(mCullScript);
492 
493         mRenderLoop.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
494     }
495 
getRenderLoop()496     public ScriptC getRenderLoop() {
497         return mRenderLoop;
498     }
499 }
500 
501 
502 
503 
504