1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 #include "FlockingScene.h" 15 16 #include "WaterMeshNode.h" 17 18 #include <cstdlib> 19 #include <cmath> 20 21 #include <Trace.h> 22 23 #include <graphics/PerspectiveMeshNode.h> 24 #include <graphics/PerspectiveProgram.h> 25 #include <graphics/GLUtils.h> 26 #include <graphics/Matrix.h> 27 #include <graphics/Mesh.h> 28 #include <graphics/ProgramNode.h> 29 #include <graphics/TransformationNode.h> 30 31 FlockingScene::FlockingScene(int width, int height) : 32 Scene(width, height), mMainProgram(NULL), mWaterProgram(NULL) { 33 for (int i = 0; i < NUM_BOIDS; i++) { 34 // Generate a boid with a random position. (-50, 50) 35 float x = (rand() % 101) - 50.0f; 36 float y = (rand() % 101) - 50.0f; 37 mBoids[i] = new Boid(x, y); 38 } 39 } 40 41 bool FlockingScene::setUpPrograms() { 42 // Main Program 43 const char* vertex = GLUtils::openTextFile("vertex/perspective"); 44 const char* fragment = GLUtils::openTextFile("fragment/perspective"); 45 if (vertex == NULL || fragment == NULL) { 46 return false; 47 } 48 GLuint programId = GLUtils::createProgram(&vertex, &fragment); 49 delete[] vertex; 50 delete[] fragment; 51 if (programId == 0) { 52 return false; 53 } 54 mMainProgram = new PerspectiveProgram(programId); 55 // Water Program 56 vertex = GLUtils::openTextFile("vertex/water"); 57 fragment = GLUtils::openTextFile("fragment/water"); 58 if (vertex == NULL || fragment == NULL) { 59 return false; 60 } 61 programId = GLUtils::createProgram(&vertex, &fragment); 62 delete[] vertex; 63 delete[] fragment; 64 if (programId == 0) { 65 return false; 66 } 67 mWaterProgram = new PerspectiveProgram(programId); 68 return true; 69 } 70 71 Matrix* FlockingScene::setUpModelMatrix() { 72 return new Matrix(); 73 } 74 75 Matrix* FlockingScene::setUpViewMatrix() { 76 // Position the eye in front of the origin. 77 float eyeX = 0.0f; 78 float eyeY = 0.0f; 79 float eyeZ = 10.0f; 80 81 // We are looking at the origin 82 float centerX = 0.0f; 83 float centerY = 0.0f; 84 float centerZ = 0.0f; 85 86 // Set our up vector. 87 float upX = 0.0f; 88 float upY = 1.0f; 89 float upZ = 0.0f; 90 91 // Set the view matrix. 92 return Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); 93 } 94 95 Matrix* FlockingScene::setUpProjectionMatrix(float width, float height) { 96 // Create a new perspective projection matrix. The height will stay the same 97 // while the width will vary as per aspect ratio. 98 mDisplayRatio = width / height; 99 // Set board dimensions 100 mBoardHeight = 1000.0f; 101 mBoardWidth = mDisplayRatio * mBoardHeight; 102 float left = -mDisplayRatio; 103 float right = mDisplayRatio; 104 float bottom = -1.0f; 105 float top = 1.0f; 106 float near = 8.0f; 107 float far = 12.0f; 108 109 return Matrix::newFrustum(left, right, bottom, top, near, far); 110 } 111 112 bool FlockingScene::setUpTextures() { 113 SCOPED_TRACE(); 114 mTextureIds.push_back(GLUtils::loadTexture("texture/fish_dark.png")); 115 mTextureIds.push_back(GLUtils::loadTexture("texture/background.png")); 116 mTextureIds.push_back(GLUtils::loadTexture("texture/water1.png")); 117 mTextureIds.push_back(GLUtils::loadTexture("texture/water2.png")); 118 return true; 119 } 120 121 bool FlockingScene::setUpMeshes() { 122 SCOPED_TRACE(); 123 mMeshes.push_back(GLUtils::loadMesh("mesh/fish.cob")); 124 mMeshes.push_back(GLUtils::loadMesh("mesh/plane.cob")); 125 return true; 126 } 127 128 bool FlockingScene::tearDown() { 129 SCOPED_TRACE(); 130 for (int i = 0; i < NUM_BOIDS; i++) { 131 delete mBoids[i]; 132 } 133 delete mMainProgram; 134 delete mWaterProgram; 135 return Scene::tearDown(); 136 } 137 138 bool FlockingScene::updateSceneGraphs(int frame) { 139 const float MAIN_SCALE = 1.25f; // Scale up as the camera is far away. 140 const float LIMIT_X = mBoardWidth / 2.0f; 141 const float LIMIT_Y = mBoardHeight / 2.0f; 142 143 ProgramNode* mainSceneGraph = new ProgramNode(*mMainProgram); 144 mSceneGraphs.push_back(mainSceneGraph); 145 // Bottom 146 Matrix* transformMatrix = Matrix::newScale(MAIN_SCALE * mDisplayRatio, MAIN_SCALE, 0.0f); 147 TransformationNode* transformNode = new TransformationNode(transformMatrix); 148 mainSceneGraph->addChild(transformNode); 149 MeshNode* meshNode = new PerspectiveMeshNode(mMeshes[1], mTextureIds[1]); 150 transformNode->addChild(meshNode); 151 // Boids 152 const float MARGIN = 30.0f; // So the fish dont disappear and appear at the edges. 153 for (int i = 0; i < NUM_BOIDS; i++) { 154 Boid* b = mBoids[i]; 155 b->flock((const Boid**) &mBoids, NUM_BOIDS, i, LIMIT_X + MARGIN, LIMIT_Y + MARGIN); 156 Vector2D* pos = &(b->mPosition); 157 Vector2D* vel = &(b->mVelocity); 158 159 // Normalize to (-1,1) 160 float x = pos->mX / (LIMIT_X * BOID_SCALE) * mDisplayRatio; 161 float y = pos->mY / (LIMIT_Y * BOID_SCALE); 162 163 const float SCALE = BOID_SCALE * MAIN_SCALE; 164 transformMatrix = Matrix::newScale(SCALE, SCALE, SCALE); 165 transformMatrix->translate(x, y, 1.0f); 166 transformMatrix->rotate(atan2(vel->mY, vel->mX) + M_PI, 0, 0, 1); 167 transformNode = new TransformationNode(transformMatrix); 168 mainSceneGraph->addChild(transformNode); 169 meshNode = new PerspectiveMeshNode(mMeshes[0], mTextureIds[0]); 170 transformNode->addChild(meshNode); 171 } 172 ProgramNode* waterSceneGraph = new ProgramNode(*mWaterProgram); 173 mSceneGraphs.push_back(waterSceneGraph); 174 // Top 175 transformMatrix = Matrix::newScale(MAIN_SCALE * mDisplayRatio, MAIN_SCALE, 1.0f); 176 transformMatrix->translate(0, 0, 0.1f); 177 transformNode = new TransformationNode(transformMatrix); 178 waterSceneGraph->addChild(transformNode); 179 meshNode = new WaterMeshNode(mMeshes[1], frame, mTextureIds[2], mTextureIds[3]); 180 transformNode->addChild(meshNode); 181 return true; 182 } 183 184 bool FlockingScene::draw() { 185 SCOPED_TRACE(); 186 drawSceneGraph(0); // Draw fish and pond bottom 187 // Use blending. 188 glEnable (GL_BLEND); 189 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 190 drawSceneGraph(1); // Draw water 191 glDisable(GL_BLEND); 192 return true; 193 } 194