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