/* * Copyright (C) 2013 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. */ #include "FlockingScene.h" #include "WaterMeshNode.h" #include #include #include #include #include #include #include #include #include #include FlockingScene::FlockingScene(int width, int height) : Scene(width, height), mMainProgram(NULL), mWaterProgram(NULL) { for (int i = 0; i < NUM_BOIDS; i++) { // Generate a boid with a random position. (-50, 50) float x = (rand() % 101) - 50.0f; float y = (rand() % 101) - 50.0f; mBoids[i] = new Boid(x, y); } } bool FlockingScene::setUpPrograms() { // Main Program const char* vertex = GLUtils::openTextFile("vertex/perspective"); const char* fragment = GLUtils::openTextFile("fragment/perspective"); if (vertex == NULL || fragment == NULL) { return false; } GLuint programId = GLUtils::createProgram(&vertex, &fragment); delete[] vertex; delete[] fragment; if (programId == 0) { return false; } mMainProgram = new PerspectiveProgram(programId); // Water Program vertex = GLUtils::openTextFile("vertex/water"); fragment = GLUtils::openTextFile("fragment/water"); if (vertex == NULL || fragment == NULL) { return false; } programId = GLUtils::createProgram(&vertex, &fragment); delete[] vertex; delete[] fragment; if (programId == 0) { return false; } mWaterProgram = new PerspectiveProgram(programId); return true; } Matrix* FlockingScene::setUpModelMatrix() { return new Matrix(); } Matrix* FlockingScene::setUpViewMatrix() { // Position the eye in front of the origin. float eyeX = 0.0f; float eyeY = 0.0f; float eyeZ = 10.0f; // We are looking at the origin float centerX = 0.0f; float centerY = 0.0f; float centerZ = 0.0f; // Set our up vector. float upX = 0.0f; float upY = 1.0f; float upZ = 0.0f; // Set the view matrix. return Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); } Matrix* FlockingScene::setUpProjectionMatrix(float width, float height) { // Create a new perspective projection matrix. The height will stay the same // while the width will vary as per aspect ratio. mDisplayRatio = width / height; // Set board dimensions mBoardHeight = 1000.0f; mBoardWidth = mDisplayRatio * mBoardHeight; float left = -mDisplayRatio; float right = mDisplayRatio; float bottom = -1.0f; float top = 1.0f; float near = 8.0f; float far = 12.0f; return Matrix::newFrustum(left, right, bottom, top, near, far); } bool FlockingScene::setUpTextures() { SCOPED_TRACE(); mTextureIds.push_back(GLUtils::loadTexture("texture/fish_dark.png")); mTextureIds.push_back(GLUtils::loadTexture("texture/background.png")); mTextureIds.push_back(GLUtils::loadTexture("texture/water1.png")); mTextureIds.push_back(GLUtils::loadTexture("texture/water2.png")); return true; } bool FlockingScene::setUpMeshes() { SCOPED_TRACE(); mMeshes.push_back(GLUtils::loadMesh("mesh/fish.cob")); mMeshes.push_back(GLUtils::loadMesh("mesh/plane.cob")); return true; } bool FlockingScene::tearDown() { SCOPED_TRACE(); for (int i = 0; i < NUM_BOIDS; i++) { delete mBoids[i]; } delete mMainProgram; delete mWaterProgram; return Scene::tearDown(); } bool FlockingScene::updateSceneGraphs(int frame) { const float MAIN_SCALE = 1.25f; // Scale up as the camera is far away. const float LIMIT_X = mBoardWidth / 2.0f; const float LIMIT_Y = mBoardHeight / 2.0f; ProgramNode* mainSceneGraph = new ProgramNode(*mMainProgram); mSceneGraphs.push_back(mainSceneGraph); // Bottom Matrix* transformMatrix = Matrix::newScale(MAIN_SCALE * mDisplayRatio, MAIN_SCALE, 0.0f); TransformationNode* transformNode = new TransformationNode(transformMatrix); mainSceneGraph->addChild(transformNode); MeshNode* meshNode = new PerspectiveMeshNode(mMeshes[1], mTextureIds[1]); transformNode->addChild(meshNode); // Boids const float MARGIN = 30.0f; // So the fish dont disappear and appear at the edges. for (int i = 0; i < NUM_BOIDS; i++) { Boid* b = mBoids[i]; b->flock((const Boid**) &mBoids, NUM_BOIDS, i, LIMIT_X + MARGIN, LIMIT_Y + MARGIN); Vector2D* pos = &(b->mPosition); Vector2D* vel = &(b->mVelocity); // Normalize to (-1,1) float x = pos->mX / (LIMIT_X * BOID_SCALE) * mDisplayRatio; float y = pos->mY / (LIMIT_Y * BOID_SCALE); const float SCALE = BOID_SCALE * MAIN_SCALE; transformMatrix = Matrix::newScale(SCALE, SCALE, SCALE); transformMatrix->translate(x, y, 1.0f); transformMatrix->rotate(atan2(vel->mY, vel->mX) + M_PI, 0, 0, 1); transformNode = new TransformationNode(transformMatrix); mainSceneGraph->addChild(transformNode); meshNode = new PerspectiveMeshNode(mMeshes[0], mTextureIds[0]); transformNode->addChild(meshNode); } ProgramNode* waterSceneGraph = new ProgramNode(*mWaterProgram); mSceneGraphs.push_back(waterSceneGraph); // Top transformMatrix = Matrix::newScale(MAIN_SCALE * mDisplayRatio, MAIN_SCALE, 1.0f); transformMatrix->translate(0, 0, 0.1f); transformNode = new TransformationNode(transformMatrix); waterSceneGraph->addChild(transformNode); meshNode = new WaterMeshNode(mMeshes[1], frame, mTextureIds[2], mTextureIds[3]); transformNode->addChild(meshNode); return true; } bool FlockingScene::draw() { SCOPED_TRACE(); drawSceneGraph(0); // Draw fish and pond bottom // Use blending. glEnable (GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); drawSceneGraph(1); // Draw water glDisable(GL_BLEND); return true; }