Adding shader parameter linking.

Change-Id: Ia5f0b6b7e935102bc2d5055875faeec209ae2b41
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
index b7f05ab..a0cb56d 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
@@ -186,10 +186,6 @@
 

                 //Log.v(TAG, "Created drawable geo " + geoURL + " index " + meshIndexName + " material " + materialName);

 

-                // Append transform and material data here

-                TransformParam modelP = new TransformParam("model");

-                modelP.setTransform(t);

-                d.appendSourceParams(modelP);

                 d.setTransform(t);

                 //Log.v(TAG, "Set source param " + t.getName());

 

diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
index b40db64..aaa4951 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
@@ -19,7 +19,7 @@
 import java.lang.Math;
 import java.util.ArrayList;
 
-import android.graphics.Camera;
+import android.renderscript.RenderScriptGL;
 import android.renderscript.Float4;
 import android.renderscript.Matrix4f;
 import android.renderscript.ProgramFragment;
@@ -33,18 +33,14 @@
  */
 public class Float4Param extends ShaderParam {
 
-    public static final int VALUE = 0;
-    public static final int CAMERA_POSITION = 1;
-    public static final int CAMERA_DIRECTION = 2;
-    public static final int LIGHT_POSITION = 3;
-    public static final int LIGHT_COLOR = 4;
-    public static final int LIGHT_DIRECTION = 5;
     Float4 mValue;
     Camera mCamera;
     LightBase mLight;
+    int mVecSize;
 
     public Float4Param(String name) {
         super(name);
+        mValue = new Float4();
     }
 
     public void setValue(Float4 v) {
@@ -55,6 +51,10 @@
         return mValue;
     }
 
+    public void setVecSize(int vecSize) {
+        mVecSize = vecSize;
+    }
+
     public void setCamera(Camera c) {
         mCamera = c;
     }
@@ -62,6 +62,35 @@
     public void setLight(LightBase l) {
         mLight = l;
     }
+
+    int getTypeFromName() {
+        int paramType = FLOAT4_DATA;
+        if (mParamName.equalsIgnoreCase(cameraPos)) {
+            paramType = FLOAT4_CAMERA_POS;
+        } else if(mParamName.equalsIgnoreCase(cameraDir)) {
+            paramType = FLOAT4_CAMERA_DIR;
+        } else if(mParamName.equalsIgnoreCase(lightColor)) {
+            paramType = FLOAT4_LIGHT_COLOR;
+        } else if(mParamName.equalsIgnoreCase(lightPos)) {
+            paramType = FLOAT4_LIGHT_POS;
+        } else if(mParamName.equalsIgnoreCase(lightDir)) {
+            paramType = FLOAT4_LIGHT_DIR;
+        }
+        return paramType;
+    }
+
+    void initLocalData(RenderScriptGL rs) {
+        mRsFieldItem.type = getTypeFromName();
+        mRsFieldItem.bufferOffset = mOffset;
+        mRsFieldItem.float_value = mValue;
+        mRsFieldItem.float_vecSize = mVecSize;
+        if (mCamera != null) {
+            mRsFieldItem.camera = mCamera.getRSData(rs).getAllocation();
+        }
+        if (mLight != null) {
+            mRsFieldItem.light = mLight.getRSData(rs).getAllocation();
+        }
+    }
 }
 
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
index dbbb1ba..e42a8ef 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
@@ -19,8 +19,16 @@
 import java.lang.Math;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 
+import com.android.scenegraph.Float4Param;
+import com.android.scenegraph.ShaderParam;
+import com.android.scenegraph.TransformParam;
+
+import android.content.res.Resources;
 import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Element.DataType;
 import android.renderscript.Matrix4f;
 import android.renderscript.Mesh;
 import android.renderscript.ProgramFragment;
@@ -28,18 +36,22 @@
 import android.renderscript.ProgramVertex;
 import android.renderscript.RenderScriptGL;
 import android.util.Log;
-import android.content.res.Resources;
 
 /**
  * @hide
  */
 public class Renderable extends RenderableBase {
+    Allocation mVertexConstants;
     Allocation mVertexParams;
+    Allocation mFragmentConstants;
     Allocation mFragmentParams;
     ArrayList<Allocation> mFragmentTextures;
-    ArrayList<ShaderParam> mVertexParam;
-    ArrayList<ShaderParam> mFragmentParam;
-    ArrayList<ShaderParam> mSourceParams;
+
+    HashMap<String, ShaderParam> mSourceParams;
+
+    ArrayList<ShaderParam> mVertexParamList;
+    ArrayList<ShaderParam> mFragmentParamList;
+
     Mesh mMesh;
     int mMeshIndex;
 
@@ -61,7 +73,9 @@
     ScriptField_Renderable_s.Item mRsFieldItem;
 
     public Renderable() {
-        mSourceParams = new ArrayList<ShaderParam>();
+        mSourceParams = new HashMap<String, ShaderParam>();
+        mVertexParamList = new ArrayList<ShaderParam>();
+        mFragmentParamList = new ArrayList<ShaderParam>();
     }
 
     public void setCullType(int cull) {
@@ -90,7 +104,7 @@
     }
 
     public void appendSourceParams(ShaderParam p) {
-        mSourceParams.add(p);
+        mSourceParams.put(p.getParamName(), p);
     }
 
     public void resolveMeshData(Mesh mMesh) {
@@ -118,8 +132,9 @@
     }
 
     void updateTextures(RenderScriptGL rs, Resources res) {
-        for (int i = 0; i < mSourceParams.size(); i ++) {
-            ShaderParam sp = mSourceParams.get(i);
+        Iterator<ShaderParam> allParamsIter = mSourceParams.values().iterator();
+        while (allParamsIter.hasNext()) {
+            ShaderParam sp = allParamsIter.next();
             if (sp instanceof TextureParam) {
                 TextureParam p = (TextureParam)sp;
                 mRsFieldItem.pf_textures[0] = p.getTexture().getRsData(rs, res);
@@ -140,6 +155,48 @@
         mRsField.set(mRsFieldItem, 0, true);
     }
 
+    ShaderParam findParamByName(String name) {
+        return mSourceParams.get(name);
+    }
+
+    void fillInParams(Element constantElem, ArrayList<ShaderParam> paramList) {
+        int subElemCount = constantElem.getSubElementCount();
+        for (int i = 0; i < subElemCount; i ++) {
+            String inputName = constantElem.getSubElementName(i);
+            int offset = constantElem.getSubElementOffsetBytes(i);
+            ShaderParam matchingParam = findParamByName(inputName);
+            // Make one if it's not there
+            if (matchingParam == null) {
+                Element subElem = constantElem.getSubElement(i);
+                if (subElem.getDataType() == Element.DataType.FLOAT_32) {
+                    Float4Param fParam = new Float4Param(inputName);
+                    fParam.setVecSize(subElem.getVectorSize());
+                    matchingParam = fParam;
+                } else if (subElem.getDataType() == Element.DataType.MATRIX_4X4) {
+                    TransformParam trParam = new TransformParam(inputName);
+                    trParam.setTransform(mTransform);
+                    matchingParam = trParam;
+                }
+            }
+            matchingParam.setOffset(offset);
+            paramList.add(matchingParam);
+        }
+    }
+
+    void linkConstants() {
+        // Assign all the fragment params
+        if (mFragmentConstants != null) {
+            Element fragmentConst = mFragmentConstants.getType().getElement();
+            fillInParams(fragmentConst, mFragmentParamList);
+        }
+
+        // Assign all the vertex params
+        if (mVertexConstants != null) {
+            Element vertexConst = mVertexConstants.getType().getElement();
+            fillInParams(vertexConst, mVertexParamList);
+        }
+    }
+
     ScriptField_Renderable_s getRsField(RenderScriptGL rs, Resources res) {
         if (mRsField != null) {
             return mRsField;
@@ -157,11 +214,45 @@
             return;
         }
 
+        ProgramVertex pv = mRenderState.mVertex;
+        if (pv != null && pv.getConstantCount() > 0) {
+            mVertexConstants = Allocation.createTyped(rs, pv.getConstant(0));
+        }
+        ProgramFragment pf = mRenderState.mFragment;
+        if (pf != null && pf.getConstantCount() > 0) {
+            mFragmentConstants = Allocation.createTyped(rs, pf.getConstant(0));
+        }
+
+        // Very important step that links available inputs and the constants vertex and
+        // fragment shader request
+        linkConstants();
+
+        ScriptField_ShaderParam_s pvParams = null, pfParams = null;
+        int paramCount = mVertexParamList.size();
+        if (paramCount != 0) {
+            pvParams = new ScriptField_ShaderParam_s(rs, paramCount);
+            for (int i = 0; i < paramCount; i++) {
+                pvParams.set(mVertexParamList.get(i).getRSData(rs), i, false);
+            }
+            pvParams.copyAll();
+        }
+
+        paramCount = mFragmentParamList.size();
+        if (paramCount != 0) {
+            pfParams = new ScriptField_ShaderParam_s(rs, paramCount);
+            for (int i = 0; i < paramCount; i++) {
+                pfParams.set(mFragmentParamList.get(i).getRSData(rs), i, false);
+            }
+            pfParams.copyAll();
+        }
+
         mRsFieldItem = new ScriptField_Renderable_s.Item();
         mRsFieldItem.mesh = mMesh;
         mRsFieldItem.meshIndex = mMeshIndex;
-        mRsFieldItem.pv_const = mVertexParams;
-        mRsFieldItem.pf_const = mFragmentParams;
+        mRsFieldItem.pv_const = mVertexConstants;
+        mRsFieldItem.pv_constParams = pvParams != null ? pvParams.getAllocation() : null;
+        mRsFieldItem.pf_const = mFragmentConstants;
+        mRsFieldItem.pf_constParams = pfParams != null ? pfParams.getAllocation() : null;
         if (mTransform != null) {
             mRsFieldItem.transformMatrix = mTransform.getRSData(rs).getAllocation();
         }
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
index 716c958..7e12bbd 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
@@ -39,6 +39,7 @@
     ScriptC_render mRenderLoop;
     ScriptC_camera mCameraScript;
     ScriptC_light mLightScript;
+    ScriptC_params mParamsScript;
     ScriptC_transform mTransformScript;
 
     RenderScriptGL mRS;
@@ -130,11 +131,13 @@
 
         mCameraScript = new ScriptC_camera(rs, res, R.raw.camera);
         mLightScript = new ScriptC_light(rs, res, R.raw.light);
+        mParamsScript = new ScriptC_params(rs, res, R.raw.params);
 
         mRenderLoop = new ScriptC_render(rs, res, R.raw.render);
         mRenderLoop.set_gTransformScript(mTransformScript);
         mRenderLoop.set_gCameraScript(mCameraScript);
         mRenderLoop.set_gLightScript(mLightScript);
+        mRenderLoop.set_gParamsScript(mParamsScript);
 
         Allocation checker = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.checker,
                                                          MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
index 22cd1ce..627d3b7 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
@@ -19,6 +19,7 @@
 import java.lang.Math;
 import java.util.ArrayList;
 
+import android.renderscript.RenderScriptGL;
 import android.renderscript.Matrix4f;
 import android.renderscript.ProgramFragment;
 import android.renderscript.ProgramStore;
@@ -29,8 +30,42 @@
 /**
  * @hide
  */
-public class ShaderParam extends SceneGraphBase {
+public abstract class ShaderParam extends SceneGraphBase {
+    static final int FLOAT4_DATA = 0;
+    static final int FLOAT4_CAMERA_POS = 1;
+    static final int FLOAT4_CAMERA_DIR = 2;
+    static final int FLOAT4_LIGHT_COLOR = 3;
+    static final int FLOAT4_LIGHT_POS = 4;
+    static final int FLOAT4_LIGHT_DIR = 5;
+
+    static final int TRANSFORM_DATA = 100;
+    static final int TRANSFORM_VIEW = 101;
+    static final int TRANSFORM_PROJ = 102;
+    static final int TRANSFORM_VIEW_PROJ = 103;
+    static final int TRANSFORM_MODEL = 104;
+    static final int TRANSFORM_MODEL_VIEW = 105;
+    static final int TRANSFORM_MODEL_VIEW_PROJ = 106;
+
+    static final int TEXTURE = 200;
+
+    static final String cameraPos        = "cameraPos";
+    static final String cameraDir        = "cameraDir";
+
+    static final String lightColor       = "lightColor";
+    static final String lightPos         = "lightPos";
+    static final String lightDir         = "lightDir";
+
+    static final String view             = "view";
+    static final String proj             = "proj";
+    static final String viewProj         = "viewProj";
+    static final String model            = "model";
+    static final String modelView        = "modelView";
+    static final String modelViewProj    = "modelViewProj";
+
+    ScriptField_ShaderParam_s.Item mRsFieldItem;
+
     String mParamName;
+    int mOffset;
 
     public ShaderParam(String name) {
         mParamName = name;
@@ -39,6 +74,22 @@
     public String getParamName() {
         return mParamName;
     }
+
+    void setOffset(int offset) {
+        mOffset = offset;
+    }
+
+    abstract void initLocalData(RenderScriptGL rs);
+
+    public ScriptField_ShaderParam_s.Item getRSData(RenderScriptGL rs) {
+        if (mRsFieldItem != null) {
+            return mRsFieldItem;
+        }
+
+        mRsFieldItem = new ScriptField_ShaderParam_s.Item();
+        initLocalData(rs);
+        return mRsFieldItem;
+    }
 }
 
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
index 0959d12..af22201 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
@@ -20,6 +20,7 @@
 import java.util.ArrayList;
 
 import android.graphics.Camera;
+import android.renderscript.RenderScriptGL;
 import android.renderscript.Float4;
 import android.renderscript.Matrix4f;
 import android.renderscript.ProgramFragment;
@@ -46,6 +47,9 @@
     public Texture2D getTexture() {
         return mTexture;
     }
+
+    void initLocalData(RenderScriptGL rs) {
+    }
 }
 
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
index 04793bc..cc70bed 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
@@ -28,15 +28,15 @@
  */
 public abstract class Transform extends SceneGraphBase {
 
-    RenderScriptGL mRS;
-    Transform mParent;
-    ArrayList<Transform> mChildren;
-
     static final int RS_ID_NONE = 0;
     static final int RS_ID_TRANSLATE = 1;
     static final int RS_ID_ROTATE = 2;
     static final int RS_ID_SCALE = 3;
 
+    RenderScriptGL mRS;
+    Transform mParent;
+    ArrayList<Transform> mChildren;
+
     ScriptField_SgTransform mField;
     ScriptField_SgTransform.Item mTransformData;
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
index fec7639..ff91b90 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
@@ -19,7 +19,7 @@
 import java.lang.Math;
 import java.util.ArrayList;
 
-import android.graphics.Camera;
+import android.renderscript.RenderScriptGL;
 import android.renderscript.Matrix4f;
 import android.renderscript.ProgramFragment;
 import android.renderscript.ProgramStore;
@@ -32,11 +32,9 @@
  */
 public class TransformParam extends ShaderParam {
 
-    public static final int TRANSFORM = 0;
-    public static final int TRANSFORM_VIEW = 1;
-    public static final int TRANSFORM_VIEW_PROJ = 2;
     Transform mTransform;
     Camera mCamera;
+    LightBase mLight;
 
     public TransformParam(String name) {
         super(name);
@@ -49,6 +47,36 @@
     public void setCamera(Camera c) {
         mCamera = c;
     }
+
+    int getTypeFromName() {
+        int paramType = TRANSFORM_DATA;
+        if (mParamName.equalsIgnoreCase(view)) {
+            paramType = TRANSFORM_VIEW;
+        } else if(mParamName.equalsIgnoreCase(proj)) {
+            paramType = TRANSFORM_PROJ;
+        } else if(mParamName.equalsIgnoreCase(viewProj)) {
+            paramType = TRANSFORM_VIEW_PROJ;
+        } else if(mParamName.equalsIgnoreCase(model)) {
+            paramType = TRANSFORM_MODEL;
+        } else if(mParamName.equalsIgnoreCase(modelView)) {
+            paramType = TRANSFORM_MODEL_VIEW;
+        } else if(mParamName.equalsIgnoreCase(modelViewProj)) {
+            paramType = TRANSFORM_MODEL_VIEW_PROJ;
+        }
+        return paramType;
+    }
+
+    void initLocalData(RenderScriptGL rs) {
+        mRsFieldItem.type = getTypeFromName();
+        mRsFieldItem.bufferOffset = mOffset;
+        mRsFieldItem.transform = mTransform.getRSData(rs).getAllocation();
+        if (mCamera != null) {
+            mRsFieldItem.camera = mCamera.getRSData(rs).getAllocation();
+        }
+        if (mLight != null) {
+            mRsFieldItem.light = mLight.getRSData(rs).getAllocation();
+        }
+    }
 }
 
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
index 0b7b00c..980eb9f 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
@@ -38,6 +38,11 @@
 
     rsMatrixLoad(&cam->viewProj, &cam->proj);
     rsMatrixMultiply(&cam->viewProj, &cam->view);
+
+    rsExtractFrustumPlanes(&cam->viewProj,
+                           &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+                           &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+                           &cam->frustumPlanes[3], &cam->frustumPlanes[4]);
 #ifdef DEBUG_CAMERA
     printCameraInfo(cam);
 #endif //DEBUG_CAMERA
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
index dbf1d48..b8edd2a 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
@@ -25,5 +25,6 @@
 SgRenderPass *pExport;
 SgCamera *exportPtrCam;
 SgLight *exportPtrLight;
+SgShaderParam *spExport;
 FBlurOffsets *blurExport;
 VertexShaderInputs *iExport;
\ No newline at end of file
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rs
new file mode 100644
index 0000000..270fa58
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rs
@@ -0,0 +1,188 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+//#define DEBUG_PARAMS
+#include "transform_def.rsh"
+
+static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
+    switch (vecSize) {
+    case 1:
+        *ptr = input->x;
+        break;
+    case 2:
+        *ptr++ = input->x;
+        *ptr = input->y;
+        break;
+    case 3:
+        *ptr++ = input->x;
+        *ptr++ = input->y;
+        *ptr = input->z;
+        break;
+    case 4:
+        *((float4*)ptr) = *input;
+        break;
+    }
+}
+
+static void processParam(SgShaderParam *p, uint8_t *constantBuffer, const SgCamera *currentCam) {
+    uint8_t *dataPtr = constantBuffer + p->bufferOffset;
+    const SgTransform *pTransform = NULL;
+    if (rsIsObject(p->transform)) {
+        pTransform = (const SgTransform *)rsGetElementAt(p->transform, 0);
+    }
+
+    switch(p->type) {
+    case SHADER_PARAM_FLOAT4_DATA:
+        writeFloatData((float*)dataPtr, &p->float_value, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_CAMERA_POS:
+        writeFloatData((float*)dataPtr, &currentCam->position, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_CAMERA_DIR: break;
+    case SHADER_PARAM_FLOAT4_LIGHT_COLOR: break;
+    case SHADER_PARAM_FLOAT4_LIGHT_POS: break;
+    case SHADER_PARAM_FLOAT4_LIGHT_DIR: break;
+
+    case SHADER_PARAM_TRANSFORM_DATA:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_VIEW:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+        break;
+    case SHADER_PARAM_TRANSFORM_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->proj);
+        break;
+    case SHADER_PARAM_TRANSFORM_VIEW_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL_VIEW:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+                             (rs_matrix4x4*)dataPtr,
+                             &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+                             (rs_matrix4x4*)dataPtr,
+                             &pTransform->globalMat);
+        break;
+    }
+}
+
+static void getTransformedSphere(SgRenderable *obj) {
+    obj->worldBoundingSphere = obj->boundingSphere;
+    obj->worldBoundingSphere.w = 1.0f;
+    const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
+    obj->worldBoundingSphere = rsMatrixMultiply(&objTransform->globalMat, obj->worldBoundingSphere);
+
+    const float4 unitVec = {0.57735f, 0.57735f, 0.57735f, 0.0f};
+    float4 scaledVec = rsMatrixMultiply(&objTransform->globalMat, unitVec);
+    scaledVec.w = 0.0f;
+    obj->worldBoundingSphere.w = obj->boundingSphere.w * length(scaledVec);
+}
+
+static bool frustumCulled(SgRenderable *obj, SgCamera *cam) {
+    if (!obj->bVolInitialized) {
+        float minX, minY, minZ, maxX, maxY, maxZ;
+        rsgMeshComputeBoundingBox(obj->mesh,
+                                  &minX, &minY, &minZ,
+                                  &maxX, &maxY, &maxZ);
+        //rsDebug("min", minX, minY, minZ);
+        //rsDebug("max", maxX, maxY, maxZ);
+        float4 sphere;
+        sphere.x = (maxX + minX) * 0.5f;
+        sphere.y = (maxY + minY) * 0.5f;
+        sphere.z = (maxZ + minZ) * 0.5f;
+        float3 radius;
+        radius.x = (maxX - sphere.x);
+        radius.y = (maxY - sphere.y);
+        radius.z = (maxZ - sphere.z);
+
+        sphere.w = length(radius);
+        obj->boundingSphere = sphere;
+        obj->bVolInitialized = 1;
+        //rsDebug("Sphere", sphere);
+    }
+
+    getTransformedSphere(obj);
+
+    return !rsIsSphereInFrustum(&obj->worldBoundingSphere,
+                                &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+                                &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+                                &cam->frustumPlanes[3], &cam->frustumPlanes[4]);
+}
+
+
+void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) {
+
+    SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
+    const SgCamera *camera = (const SgCamera*)usrData;
+
+    drawable->isVisible = 0;
+    // Not loaded yet
+    if (!rsIsObject(drawable->mesh) || drawable->cullType == CULL_ALWAYS) {
+        return;
+    }
+
+    // check to see if we are culling this object and if it's
+    // outside the frustum
+    if (drawable->cullType == CULL_FRUSTUM && frustumCulled(drawable, (SgCamera*)camera)) {
+#ifdef DEBUG_RENDERABLES
+        rsDebug("Culled", drawable);
+        printName(drawable->name);
+#endif //DEBUG_RENDERABLES
+        return;
+    }
+    drawable->isVisible = 1;
+
+    // Data we are updating
+    /*if (rsIsObject(drawable->pf_const)) {
+        uint8_t *constantBuffer = (uint8_t*)rsGetElementAt(drawable->pf_const, 0);
+
+        int numParams = 0;
+        if (rsIsObject(drawable->pf_constParams)) {
+            rsAllocationGetDimX(drawable->pf_constParams);
+        }
+        for (int i = 0; i < numParams; i ++) {
+            SgShaderParam *current = (SgShaderParam*)rsGetElementAt(drawable->pf_constParams, i);
+            processParam(current, constantBuffer, camera);
+        }
+        rsgAllocationSyncAll(drawable->pf_const);
+    }
+
+    if (rsIsObject(drawable->pv_const)) {
+        uint8_t *constantBuffer = (uint8_t*)rsGetElementAt(drawable->pv_const, 0);
+
+        int numParams = 0;
+        if (rsIsObject(drawable->pv_constParams)) {
+            numParams = rsAllocationGetDimX(drawable->pv_constParams);
+        }
+        for (int i = 0; i < numParams; i ++) {
+            SgShaderParam *current = (SgShaderParam*)rsGetElementAt(drawable->pv_constParams, i);
+            processParam(current, constantBuffer, camera);
+        }
+        rsgAllocationSyncAll(drawable->pv_const);
+    }*/
+
+#ifdef DEBUG_PARAMS
+#endif //DEBUG_PARAMS
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
index 9919295..ceaca40 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
@@ -22,6 +22,7 @@
 rs_script gTransformScript;
 rs_script gCameraScript;
 rs_script gLightScript;
+rs_script gParamsScript;
 
 SgTransform *gRootNode;
 rs_allocation gCameras;
@@ -43,10 +44,116 @@
 static uint32_t gBackToFrontCount = 0;
 
 static SgCamera *gActiveCamera = NULL;
-static float4 gFrustumPlanes[6];
 
 static rs_allocation nullAlloc;
 
+static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
+    switch (vecSize) {
+    case 1:
+        *ptr = input->x;
+        break;
+    case 2:
+        *ptr++ = input->x;
+        *ptr = input->y;
+        break;
+    case 3:
+        *ptr++ = input->x;
+        *ptr++ = input->y;
+        *ptr = input->z;
+        break;
+    case 4:
+        *((float4*)ptr) = *input;
+        break;
+    }
+}
+
+static void processParam(SgShaderParam *p, uint8_t *constantBuffer, const SgCamera *currentCam) {
+    uint8_t *dataPtr = constantBuffer + p->bufferOffset;
+    const SgTransform *pTransform = NULL;
+    if (rsIsObject(p->transform)) {
+        pTransform = (const SgTransform *)rsGetElementAt(p->transform, 0);
+    }
+
+    rsDebug("data ptr: ", (void*)dataPtr);
+    rsDebug("p type: ", p->type);
+
+    switch(p->type) {
+    case SHADER_PARAM_FLOAT4_DATA:
+        writeFloatData((float*)dataPtr, &p->float_value, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_CAMERA_POS:
+        writeFloatData((float*)dataPtr, &currentCam->position, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_CAMERA_DIR: break;
+    case SHADER_PARAM_FLOAT4_LIGHT_COLOR: break;
+    case SHADER_PARAM_FLOAT4_LIGHT_POS: break;
+    case SHADER_PARAM_FLOAT4_LIGHT_DIR: break;
+
+    case SHADER_PARAM_TRANSFORM_DATA:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_VIEW:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+        break;
+    case SHADER_PARAM_TRANSFORM_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->proj);
+        break;
+    case SHADER_PARAM_TRANSFORM_VIEW_PROJ:
+        rsDebug("View proj ptr: ", (void*)&vConst->viewProj);
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL:
+        rsDebug("Model ptr: ", (void*)&vConst->model);
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL_VIEW:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+                             (rs_matrix4x4*)dataPtr,
+                             &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+                             (rs_matrix4x4*)dataPtr,
+                             &pTransform->globalMat);
+        break;
+    }
+}
+
+static void updateParams(SgRenderable *drawable) {
+    if (rsIsObject(drawable->pf_const)) {
+        uint8_t *constantBuffer = (uint8_t*)fConst;
+
+        int numParams = 0;
+        if (rsIsObject(drawable->pf_constParams)) {
+            rsAllocationGetDimX(drawable->pf_constParams);
+        }
+        for (int i = 0; i < numParams; i ++) {
+            SgShaderParam *current = (SgShaderParam*)rsGetElementAt(drawable->pf_constParams, i);
+            processParam(current, constantBuffer, gActiveCamera);
+            rsDebug("Setting f param", i);
+        }
+        rsgAllocationSyncAll(rsGetAllocation(fConst));
+    }
+
+    if (rsIsObject(drawable->pv_const)) {
+        uint8_t *constantBuffer = (uint8_t*)vConst;
+
+        rsDebug("_______________________", 0);
+
+        int numParams = 0;
+        if (rsIsObject(drawable->pv_constParams)) {
+            numParams = rsAllocationGetDimX(drawable->pv_constParams);
+        }
+        for (int i = 0; i < numParams; i ++) {
+            SgShaderParam *current = (SgShaderParam*)rsGetElementAt(drawable->pv_constParams, i);
+            processParam(current, constantBuffer, gActiveCamera);
+        }
+        rsgAllocationSyncAll(rsGetAllocation(vConst));
+    }
+}
+
 //#define DEBUG_RENDERABLES
 static void draw(SgRenderable *obj) {
 
@@ -59,12 +166,13 @@
     printName(obj->name);
 #endif //DEBUG_RENDERABLES
 
-    SgCamera *cam = gActiveCamera;
+    updateParams(obj);
+    /*SgCamera *cam = gActiveCamera;
 
     rsMatrixLoad(&vConst->model, &objTransform->globalMat);
     rsMatrixLoad(&vConst->viewProj, &cam->viewProj);
-    rsgAllocationSyncAll(rsGetAllocation(vConst));
-    fConst->cameraPos = cam->position;
+    rsgAllocationSyncAll(rsGetAllocation(vConst));*/
+    fConst->cameraPos = gActiveCamera->position;
     rsgAllocationSyncAll(rsGetAllocation(fConst));
 
     if (rsIsObject(renderState->ps)) {
@@ -92,64 +200,7 @@
     rsgDrawMesh(obj->mesh, obj->meshIndex);
 }
 
-static void getTransformedSphere(SgRenderable *obj) {
-    obj->worldBoundingSphere = obj->boundingSphere;
-    obj->worldBoundingSphere.w = 1.0f;
-    const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
-    obj->worldBoundingSphere = rsMatrixMultiply(&objTransform->globalMat, obj->worldBoundingSphere);
-
-    const float4 unitVec = {0.57735f, 0.57735f, 0.57735f, 0.0f};
-    float4 scaledVec = rsMatrixMultiply(&objTransform->globalMat, unitVec);
-    scaledVec.w = 0.0f;
-    obj->worldBoundingSphere.w = obj->boundingSphere.w * length(scaledVec);
-}
-
-static bool frustumCulled(SgRenderable *obj) {
-    if (!obj->bVolInitialized) {
-        float minX, minY, minZ, maxX, maxY, maxZ;
-        rsgMeshComputeBoundingBox(obj->mesh,
-                                  &minX, &minY, &minZ,
-                                  &maxX, &maxY, &maxZ);
-        //rsDebug("min", minX, minY, minZ);
-        //rsDebug("max", maxX, maxY, maxZ);
-        float4 sphere;
-        sphere.x = (maxX + minX) * 0.5f;
-        sphere.y = (maxY + minY) * 0.5f;
-        sphere.z = (maxZ + minZ) * 0.5f;
-        float3 radius;
-        radius.x = (maxX - sphere.x);
-        radius.y = (maxY - sphere.y);
-        radius.z = (maxZ - sphere.z);
-
-        sphere.w = length(radius);
-        obj->boundingSphere = sphere;
-        obj->bVolInitialized = 1;
-        //rsDebug("Sphere", sphere);
-    }
-
-    getTransformedSphere(obj);
-
-    return !rsIsSphereInFrustum(&obj->worldBoundingSphere,
-                                &gFrustumPlanes[0], &gFrustumPlanes[1],
-                                &gFrustumPlanes[2], &gFrustumPlanes[3],
-                                &gFrustumPlanes[3], &gFrustumPlanes[4]);
-}
-
 static void sortToBucket(SgRenderable *obj) {
-    // Not loaded yet
-    if (!rsIsObject(obj->mesh) || obj->cullType == 2) {
-        return;
-    }
-
-    // check to see if we are culling this object and if it's
-    // outside the frustum
-    if (obj->cullType == 0 && frustumCulled(obj)) {
-#ifdef DEBUG_RENDERABLES
-        rsDebug("Culled", obj);
-        printName(obj->name);
-#endif //DEBUG_RENDERABLES
-        return;
-    }
     const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
     if (rsIsObject(renderState->ps)) {
 #define MR1_API
@@ -171,11 +222,6 @@
 
 static void updateActiveCamera(rs_allocation cam) {
     gActiveCamera = (SgCamera *)rsGetElementAt(cam, 0);
-
-    rsExtractFrustumPlanes(&gActiveCamera->viewProj,
-                           &gFrustumPlanes[0], &gFrustumPlanes[1],
-                           &gFrustumPlanes[2], &gFrustumPlanes[3],
-                           &gFrustumPlanes[3], &gFrustumPlanes[4]);
 }
 
 static void prepareCameras() {
@@ -206,11 +252,17 @@
     if (!rsIsObject(allObj)) {
         return;
     }
+
+    // Run the params and cull script
+    rsForEach(gParamsScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
+
     int numRenderables = rsAllocationGetDimX(allObj);
     for (int i = 0; i < numRenderables; i ++) {
         rs_allocation *drawAlloc = (rs_allocation*)rsGetElementAt(allObj, i);
         SgRenderable *current = (SgRenderable*)rsGetElementAt(*drawAlloc, 0);
-        sortToBucket(current);
+        if (current->isVisible) {
+            sortToBucket(current);
+        }
     }
     drawSorted();
 }
@@ -301,7 +353,7 @@
         SgRenderable *current = (SgRenderable*)gFrontToBack[i];
         bool isPicked = intersect(current, pnt, vec);
         if (isPicked) {
-            current->cullType = 2;
+            current->cullType = CULL_ALWAYS;
         }
     }
 
@@ -309,7 +361,7 @@
         SgRenderable *current = (SgRenderable*)gBackToFront[i];
         bool isPicked = intersect(current, pnt, vec);
         if (isPicked) {
-            current->cullType = 2;
+            current->cullType = CULL_ALWAYS;
         }
     }
 }
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform_def.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform_def.rsh
index ce4b78d..20d63bb 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform_def.rsh
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform_def.rsh
@@ -55,10 +55,19 @@
     rs_program_raster pr;
 } SgRenderState;
 
+#define CULL_FRUSTUM 0
+#define CULL_ALWAYS 2
+
 typedef struct Renderable_s {
     rs_allocation render_state;
+    // Buffer with vertex constant data
     rs_allocation pv_const;
+    // ShaderParam's that populate data
+    rs_allocation pv_constParams;
+    // Buffer with fragment constant data
     rs_allocation pf_const;
+    // ShaderParam's that populate data
+    rs_allocation pf_constParams;
     rs_allocation pf_textures[8];
     int pf_num_textures;
     rs_mesh mesh;
@@ -69,6 +78,7 @@
     float4 worldBoundingSphere;
     int bVolInitialized;
     int cullType; // specifies whether to frustum cull
+    int isVisible;
 } SgRenderable;
 
 typedef struct RenderPass_s {
@@ -94,6 +104,7 @@
     float aspect;
     rs_allocation name;
     rs_allocation transformMatrix;
+    float4 frustumPlanes[6];
 } SgCamera;
 
 #define LIGHT_POINT 0
@@ -108,6 +119,39 @@
     rs_allocation transformMatrix;
 } SgLight;
 
+#define SHADER_PARAM_FLOAT4_DATA 0
+#define SHADER_PARAM_FLOAT4_CAMERA_POS 1
+#define SHADER_PARAM_FLOAT4_CAMERA_DIR 2
+#define SHADER_PARAM_FLOAT4_LIGHT_COLOR 3
+#define SHADER_PARAM_FLOAT4_LIGHT_POS 4
+#define SHADER_PARAM_FLOAT4_LIGHT_DIR 5
+
+#define SHADER_PARAM_TRANSFORM_DATA 100
+#define SHADER_PARAM_TRANSFORM_VIEW 101
+#define SHADER_PARAM_TRANSFORM_PROJ 102
+#define SHADER_PARAM_TRANSFORM_VIEW_PROJ 103
+#define SHADER_PARAM_TRANSFORM_MODEL 104
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW 105
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ 106
+
+#define SHADER_PARAM_TEXTURE 200
+
+// This represents a shader parameter that knows for to update itself
+typedef struct ShaderParam_s {
+    uint32_t type;
+    uint32_t bufferOffset;
+
+    float4 float_value;
+    // Use one param type to handle all vector types for now
+    uint32_t float_vecSize;
+
+    rs_allocation camera;
+    rs_allocation light;
+    rs_allocation transform;
+    rs_allocation texture;
+} SgShaderParam;
+
+// Helpers
 typedef struct VShaderParams_s {
     rs_matrix4x4 model;
     rs_matrix4x4 viewProj;