1/*
2 * Copyright (C) 2011-2012 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.testapp;
18
19import java.util.ArrayList;
20import java.util.HashMap;
21import java.util.Map;
22import java.util.Vector;
23
24import com.android.scenegraph.*;
25import com.android.scenegraph.SceneManager.SceneLoadedCallback;
26
27import android.content.res.Resources;
28import android.graphics.Bitmap;
29import android.graphics.BitmapFactory;
30import android.os.AsyncTask;
31import android.renderscript.*;
32import android.renderscript.Program.TextureType;
33import android.util.Log;
34
35// This is where the scenegraph and the rendered objects are initialized and used
36public class TestAppRS {
37
38    private static String modelName = "orientation_test.dae";
39    private static String TAG = "TestAppRS";
40    private static String mFilePath = "";
41
42    int mWidth;
43    int mHeight;
44
45    boolean mUseBlur;
46
47    TestAppLoadingScreen mLoadingScreen;
48
49    // Used to asynchronously load scene elements like meshes and transform hierarchies
50    SceneLoadedCallback mLoadedCallback = new SceneLoadedCallback() {
51        public void run() {
52            prepareToRender(mLoadedScene);
53        }
54    };
55
56    // Top level class that initializes all the elements needed to use the scene graph
57    SceneManager mSceneManager;
58
59    // Used to move the camera around in the 3D world
60    TouchHandler mTouchHandler;
61
62    private Resources mRes;
63    private RenderScriptGL mRS;
64
65    // Shaders
66    private FragmentShader mPaintF;
67    private FragmentShader mLightsF;
68    private FragmentShader mLightsDiffF;
69    private FragmentShader mAluminumF;
70    private FragmentShader mPlasticF;
71    private FragmentShader mDiffuseF;
72    private FragmentShader mTextureF;
73    private VertexShader mGenericV;
74
75    Scene mActiveScene;
76
77    // This is a part of the test app, it's used to tests multiple render passes and is toggled
78    // on and off in the menu, off by default
79    void toggleBlur() {
80        mUseBlur = !mUseBlur;
81
82        mActiveScene.clearRenderPasses();
83        initRenderPasses();
84        mActiveScene.initRenderPassRS(mRS, mSceneManager);
85
86        // This is just a hardcoded object in the scene that gets turned on and off for the demo
87        // to make things look a bit better. This could be deleted in the cleanup
88        Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
89        if (plane != null) {
90            plane.setVisible(!mUseBlur);
91        }
92    }
93
94    public void init(RenderScriptGL rs, Resources res, int width, int height) {
95        mUseBlur = false;
96        mRS = rs;
97        mRes = res;
98        mWidth = width;
99        mHeight = height;
100
101        mTouchHandler = new TouchHandler();
102
103        mSceneManager = SceneManager.getInstance();
104        // Initializes all the RS specific scenegraph elements
105        mSceneManager.initRS(mRS, mRes, mWidth, mHeight);
106
107        mLoadingScreen = new TestAppLoadingScreen(mRS, mRes);
108
109        // Initi renderscript stuff specific to the app. This will need to be abstracted out later.
110        FullscreenBlur.createRenderTargets(mRS, mWidth, mHeight);
111        initPaintShaders();
112
113        // Load a scene to render
114        mSceneManager.loadModel(mFilePath + modelName, mLoadedCallback);
115    }
116
117    // When a new model file is selected from the UI, this function gets called to init everything
118    void loadModel(String path) {
119        mLoadingScreen.showLoadingScreen(true);
120        mActiveScene.destroyRS();
121        mSceneManager.loadModel(path, mLoadedCallback);
122    }
123
124    public void onActionDown(float x, float y) {
125        mTouchHandler.onActionDown(x, y);
126    }
127
128    public void onActionScale(float scale) {
129        mTouchHandler.onActionScale(scale);
130    }
131
132    public void onActionMove(float x, float y) {
133        mTouchHandler.onActionMove(x, y);
134    }
135
136    FragmentShader createFromResource(int id, boolean addCubemap, Type constType) {
137        FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
138        fb.setShaderConst(constType);
139        fb.setShader(mRes, id);
140        fb.addTexture(TextureType.TEXTURE_2D, "diffuse");
141        if (addCubemap) {
142            fb.addShaderTexture(TextureType.TEXTURE_CUBE, "reflection");
143        }
144        FragmentShader pf = fb.create();
145        pf.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0);
146        if (addCubemap) {
147            pf.getProgram().bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(mRS), 1);
148        }
149        return pf;
150    }
151
152    private void initPaintShaders() {
153        mGenericV = SceneManager.getDefaultVS();
154
155        ScriptField_CameraParams camParams = new ScriptField_CameraParams(mRS, 1);
156        Type camParamType = camParams.getAllocation().getType();
157        ScriptField_LightParams lightParams = new ScriptField_LightParams(mRS, 1);
158
159        mPaintF = createFromResource(R.raw.paintf, true, camParamType);
160        // Assign a reflection map
161        TextureCube envCube = new TextureCube("sdcard/scenegraph/", "cube_env.png");
162        mPaintF.appendSourceParams(new TextureParam("reflection", envCube));
163
164        mAluminumF = createFromResource(R.raw.metal, true, camParamType);
165        TextureCube diffCube = new TextureCube("sdcard/scenegraph/", "cube_spec.png");
166        mAluminumF.appendSourceParams(new TextureParam("reflection", diffCube));
167
168        mPlasticF = createFromResource(R.raw.plastic, false, camParamType);
169        mDiffuseF = createFromResource(R.raw.diffuse, false, camParamType);
170        mTextureF = SceneManager.getTextureFS();
171
172        FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
173        fb.setObjectConst(lightParams.getAllocation().getType());
174        fb.setShader(mRes, R.raw.plastic_lights);
175        mLightsF = fb.create();
176
177        fb = new FragmentShader.Builder(mRS);
178        fb.setObjectConst(lightParams.getAllocation().getType());
179        fb.setShader(mRes, R.raw.diffuse_lights);
180        mLightsDiffF = fb.create();
181
182        FullscreenBlur.initShaders(mRes, mRS);
183    }
184
185    void initRenderPasses() {
186        ArrayList<RenderableBase> allDraw = mActiveScene.getRenderables();
187        int numDraw = allDraw.size();
188
189        if (mUseBlur) {
190            FullscreenBlur.addBlurPasses(mActiveScene, mRS, mTouchHandler.getCamera());
191        }
192
193        RenderPass mainPass = new RenderPass();
194        mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
195        mainPass.setShouldClearColor(true);
196        mainPass.setClearDepth(1.0f);
197        mainPass.setShouldClearDepth(true);
198        mainPass.setCamera(mTouchHandler.getCamera());
199        for (int i = 0; i < numDraw; i ++) {
200            mainPass.appendRenderable((Renderable)allDraw.get(i));
201        }
202        mActiveScene.appendRenderPass(mainPass);
203
204        if (mUseBlur) {
205            FullscreenBlur.addCompositePass(mActiveScene, mRS, mTouchHandler.getCamera());
206        }
207    }
208
209    private void addShadersToScene() {
210        mActiveScene.appendShader(mPaintF);
211        mActiveScene.appendShader(mLightsF);
212        mActiveScene.appendShader(mLightsDiffF);
213        mActiveScene.appendShader(mAluminumF);
214        mActiveScene.appendShader(mPlasticF);
215        mActiveScene.appendShader(mDiffuseF);
216        mActiveScene.appendShader(mTextureF);
217    }
218
219    public void prepareToRender(Scene s) {
220        mSceneManager.setActiveScene(s);
221        mActiveScene = s;
222        mTouchHandler.init(mActiveScene);
223        addShadersToScene();
224        RenderState plastic = new RenderState(mGenericV, mPlasticF, null, null);
225        RenderState diffuse = new RenderState(mGenericV, mDiffuseF, null, null);
226        RenderState paint = new RenderState(mGenericV, mPaintF, null, null);
227        RenderState aluminum = new RenderState(mGenericV, mAluminumF, null, null);
228        RenderState lights = new RenderState(mGenericV, mLightsF, null, null);
229        RenderState diff_lights = new RenderState(mGenericV, mLightsDiffF, null, null);
230        RenderState diff_lights_no_cull = new RenderState(mGenericV, mLightsDiffF, null,
231                                                          ProgramRaster.CULL_NONE(mRS));
232        RenderState glassTransp = new RenderState(mGenericV, mPaintF,
233                                                  ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS), null);
234        RenderState texState = new RenderState(mGenericV, mTextureF, null, null);
235
236        initRenderPasses();
237
238        mActiveScene.assignRenderState(plastic);
239
240        mActiveScene.assignRenderStateToMaterial(diffuse, "lambert2$");
241
242        mActiveScene.assignRenderStateToMaterial(paint, "^Paint");
243        mActiveScene.assignRenderStateToMaterial(paint, "^Carbon");
244        mActiveScene.assignRenderStateToMaterial(paint, "^Glass");
245        mActiveScene.assignRenderStateToMaterial(paint, "^MainGlass");
246
247        mActiveScene.assignRenderStateToMaterial(aluminum, "^Metal");
248        mActiveScene.assignRenderStateToMaterial(aluminum, "^Brake");
249
250        mActiveScene.assignRenderStateToMaterial(glassTransp, "^GlassLight");
251
252        mActiveScene.assignRenderStateToMaterial(lights, "^LightBlinn");
253        mActiveScene.assignRenderStateToMaterial(diff_lights, "^LightLambert");
254        mActiveScene.assignRenderStateToMaterial(diff_lights_no_cull, "^LightLambertNoCull");
255        mActiveScene.assignRenderStateToMaterial(texState, "^TextureOnly");
256
257        Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
258        if (plane != null) {
259            plane.setRenderState(texState);
260            plane.setVisible(!mUseBlur);
261        }
262
263        long start = System.currentTimeMillis();
264        mActiveScene.initRS();
265        long end = System.currentTimeMillis();
266        Log.v("TIMER", "Scene init time: " + (end - start));
267
268        mLoadingScreen.showLoadingScreen(false);
269    }
270}
271