Home | History | Annotate | Download | only in scenegraph
      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 
     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 
    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 
    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 
    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 
    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 
    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 
    177     public static Allocation loadCubemap(String name, RenderScriptGL rs, Resources res) {
    178         return createFromBitmap(loadBitmap(name, res), rs, true);
    179     }
    180 
    181     public static Allocation loadCubemap(int id, RenderScriptGL rs, Resources res) {
    182         return createFromBitmap(BitmapFactory.decodeResource(res, id), rs, true);
    183     }
    184 
    185     public static Allocation loadTexture2D(String name, RenderScriptGL rs, Resources res) {
    186         return createFromBitmap(loadBitmap(name, res), rs, false);
    187     }
    188 
    189     public static Allocation loadTexture2D(int id, RenderScriptGL rs, Resources res) {
    190         return createFromBitmap(BitmapFactory.decodeResource(res, id), rs, false);
    191     }
    192 
    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 
    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 
    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 
    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;
    243         public void run() {
    244         }
    245     }
    246 
    247     public Scene getActiveScene() {
    248         return mActiveScene;
    249     }
    250 
    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 
    276     static RenderScriptGL getRS() {
    277         if (sSceneManager == null) {
    278             return null;
    279         }
    280         return sSceneManager.mRS;
    281     }
    282 
    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;
    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 
    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 
    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 
    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 
    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 
    413     public static SceneManager getInstance() {
    414         if (sSceneManager == null) {
    415             sSceneManager = new SceneManager();
    416         }
    417         return sSceneManager;
    418     }
    419 
    420     protected SceneManager() {
    421     }
    422 
    423     public void loadModel(String name, SceneLoadedCallback cb) {
    424         ColladaScene scene = new ColladaScene(name, cb);
    425         scene.init(mRS, mRes);
    426     }
    427 
    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 
    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 
    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 
    496     public ScriptC getRenderLoop() {
    497         return mRenderLoop;
    498     }
    499 }
    500 
    501 
    502 
    503 
    504