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 
FlockingScene(int width,int height)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 
setUpPrograms()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 
setUpModelMatrix()71 Matrix* FlockingScene::setUpModelMatrix() {
72     return new Matrix();
73 }
74 
setUpViewMatrix()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 
setUpProjectionMatrix(float width,float height)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 
setUpTextures()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 
setUpMeshes()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 
tearDown()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 
updateSceneGraphs(int frame)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 
draw()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