// Copyright (C) 2011-2012 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) #include "rs_graphics.rsh" #include "scenegraph_objects.rsh" rs_script gTransformScript; rs_script gCameraScript; rs_script gLightScript; rs_script gObjectParamsScript; rs_script gFragmentParamsScript; rs_script gVertexParamsScript; rs_script gCullScript; SgTransform *gRootNode; rs_allocation gCameras; rs_allocation gLights; rs_allocation gFragmentShaders; rs_allocation gVertexShaders; rs_allocation gRenderableObjects; rs_allocation gRenderPasses; // Temporary shaders rs_program_store gPFSBackground; uint32_t *gFrontToBack; static uint32_t gFrontToBackCount = 0; uint32_t *gBackToFront; static uint32_t gBackToFrontCount = 0; static SgCamera *gActiveCamera = NULL; static rs_allocation nullAlloc; // #define DEBUG_RENDERABLES static void draw(SgRenderable *obj) { #ifdef DEBUG_RENDERABLES const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0); rsDebug("**** Drawing object with transform", obj); printName(objTransform->name); rsDebug("Model matrix: ", &objTransform->globalMat); printName(obj->name); #endif //DEBUG_RENDERABLES const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0); const SgVertexShader *pv = (const SgVertexShader *)rsGetElementAt(renderState->pv, 0); const SgFragmentShader *pf = (const SgFragmentShader *)rsGetElementAt(renderState->pf, 0); if (pv->objectConstIndex != -1) { rsgBindConstant(pv->program, pv->objectConstIndex, obj->pv_const); } if (pf->objectConstIndex != -1) { rsgBindConstant(pf->program, pf->objectConstIndex, obj->pf_const); } if (rsIsObject(renderState->ps)) { rsgBindProgramStore(renderState->ps); } else { rsgBindProgramStore(gPFSBackground); } if (rsIsObject(renderState->pr)) { rsgBindProgramRaster(renderState->pr); } else { rs_program_raster pr = {0}; rsgBindProgramRaster(pr); } rsgBindProgramVertex(pv->program); rsgBindProgramFragment(pf->program); for (uint32_t i = 0; i < obj->pf_num_textures; i ++) { const SgTexture *tex = rsGetElementAt(obj->pf_textures[i], 0); rsgBindTexture(pf->program, i, tex->texture); } rsgDrawMesh(obj->mesh, obj->meshIndex); } static void sortToBucket(SgRenderable *obj) { const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0); if (rsIsObject(renderState->ps)) { bool isOpaque = false; if (isOpaque) { gFrontToBack[gFrontToBackCount++] = (uint32_t)obj; } else { gBackToFront[gBackToFrontCount++] = (uint32_t)obj; } } else { gFrontToBack[gFrontToBackCount++] = (uint32_t)obj; } } static void updateActiveCamera(rs_allocation cam) { gActiveCamera = (SgCamera *)rsGetElementAt(cam, 0); } static void prepareCameras() { // now compute all the camera matrices if (rsIsObject(gCameras)) { float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); rsForEach(gCameraScript, gCameras, nullAlloc, &aspect, sizeof(aspect)); } } static void prepareLights() { if (rsIsObject(gLights)) { rsForEach(gLightScript, gLights, nullAlloc); } } static void drawSorted() { for (int i = 0; i < gFrontToBackCount; i ++) { SgRenderable *current = (SgRenderable*)gFrontToBack[i]; draw(current); } for (int i = 0; i < gBackToFrontCount; i ++) { SgRenderable *current = (SgRenderable*)gBackToFront[i]; draw(current); } } static void drawAllObjects(rs_allocation allObj) { if (!rsIsObject(allObj)) { return; } if (rsIsObject(gVertexShaders)) { rsForEach(gVertexParamsScript, nullAlloc, gVertexShaders, gActiveCamera, sizeof(gActiveCamera)); } if (rsIsObject(gFragmentShaders)) { rsForEach(gFragmentParamsScript, nullAlloc, gFragmentShaders, gActiveCamera, sizeof(gActiveCamera)); } // Run the params and cull script rsForEach(gCullScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera)); rsForEach(gObjectParamsScript, 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); if (current->isVisible) { sortToBucket(current); } } drawSorted(); } int root(void) { #ifdef DEBUG_RENDERABLES rsDebug("=============================================================================", 0); #endif // DEBUG_RENDERABLES // first step is to update the transform hierachy if (gRootNode && rsIsObject(gRootNode->children)) { rsForEach(gTransformScript, gRootNode->children, nullAlloc, 0, 0); } prepareCameras(); prepareLights(); if (rsIsObject(gRenderPasses)) { rsgClearDepth(1.0f); int numPasses = rsAllocationGetDimX(gRenderPasses); for (uint i = 0; i < numPasses; i ++) { gFrontToBackCount = 0; gBackToFrontCount = 0; SgRenderPass *pass = (SgRenderPass*)rsGetElementAt(gRenderPasses, i); if (rsIsObject(pass->color_target)) { rsgBindColorTarget(pass->color_target, 0); } if (rsIsObject(pass->depth_target)) { rsgBindDepthTarget(pass->depth_target); } if (!rsIsObject(pass->color_target) && !rsIsObject(pass->depth_target)) { rsgClearAllRenderTargets(); } updateActiveCamera(pass->camera); if (pass->should_clear_color) { rsgClearColor(pass->clear_color.x, pass->clear_color.y, pass->clear_color.z, pass->clear_color.w); } if (pass->should_clear_depth) { rsgClearDepth(pass->clear_depth); } drawAllObjects(pass->objects); } } else { gFrontToBackCount = 0; gBackToFrontCount = 0; rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); rsgClearDepth(1.0f); if (rsIsObject(gCameras)) { rs_allocation *camAlloc = (rs_allocation*)rsGetElementAt(gCameras, 0); updateActiveCamera(*camAlloc); } drawAllObjects(gRenderableObjects); } return 10; } // Search through sorted and culled objects void pick(int screenX, int screenY) { float3 pnt, vec; getCameraRay(gActiveCamera, screenX, screenY, &pnt, &vec); for (int i = 0; i < gFrontToBackCount; i ++) { SgRenderable *current = (SgRenderable*)gFrontToBack[i]; bool isPicked = intersect(current, pnt, vec); if (isPicked) { current->cullType = CULL_ALWAYS; } } for (int i = 0; i < gBackToFrontCount; i ++) { SgRenderable *current = (SgRenderable*)gBackToFront[i]; bool isPicked = intersect(current, pnt, vec); if (isPicked) { current->cullType = CULL_ALWAYS; } } }