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