Home | History | Annotate | Download | only in flocking
      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