1 /*
2 * Copyright © 2010-2011 Linaro Limited
3 *
4 * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
5 *
6 * glmark2 is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
9 * version.
10 *
11 * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * glmark2. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Authors:
20 * Alexandros Frantzis (glmark2)
21 * Jesse Barker (glmark2)
22 */
23 #include "scene.h"
24 #include "log.h"
25 #include "mat.h"
26 #include "options.h"
27 #include "stack.h"
28 #include "shader-source.h"
29 #include "model.h"
30 #include "texture.h"
31 #include "util.h"
32 #include <cmath>
33
SceneBump(Canvas & pCanvas)34 SceneBump::SceneBump(Canvas &pCanvas) :
35 Scene(pCanvas, "bump"),
36 texture_(0), rotation_(0.0f), rotationSpeed_(0.0f)
37 {
38 options_["bump-render"] = Scene::Option("bump-render", "off",
39 "How to render bumps",
40 "off,normals,normals-tangent,height,high-poly");
41 }
42
~SceneBump()43 SceneBump::~SceneBump()
44 {
45 }
46
47 bool
load()48 SceneBump::load()
49 {
50 rotationSpeed_ = 36.0f;
51
52 running_ = false;
53
54 return true;
55 }
56
57 void
unload()58 SceneBump::unload()
59 {
60 }
61
62 bool
setup_model_plain(const std::string & type)63 SceneBump::setup_model_plain(const std::string &type)
64 {
65 static const std::string vtx_shader_filename(Options::data_path + "/shaders/bump-poly.vert");
66 static const std::string frg_shader_filename(Options::data_path + "/shaders/bump-poly.frag");
67 static const std::string low_poly_filename("asteroid-low");
68 static const std::string high_poly_filename("asteroid-high");
69 static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
70 Model model;
71
72 /* Calculate the half vector */
73 LibMatrix::vec3 halfVector(lightPosition.x(), lightPosition.y(), lightPosition.z());
74 halfVector.normalize();
75 halfVector += LibMatrix::vec3(0.0, 0.0, 1.0);
76 halfVector.normalize();
77
78 std::string poly_filename = type == "high-poly" ?
79 high_poly_filename : low_poly_filename;
80
81 if(!model.load(poly_filename))
82 return false;
83
84 if (model.needNormals())
85 model.calculate_normals();
86
87 /* Tell the converter that we only care about position and normal attributes */
88 std::vector<std::pair<Model::AttribType, int> > attribs;
89 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypePosition, 3));
90 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeNormal, 3));
91
92 model.convert_to_mesh(mesh_, attribs);
93
94 /* Load shaders */
95 ShaderSource vtx_source(vtx_shader_filename);
96 ShaderSource frg_source(frg_shader_filename);
97
98 /* Add constants to shaders */
99 frg_source.add_const("LightSourcePosition", lightPosition);
100 frg_source.add_const("LightSourceHalfVector", halfVector);
101
102 if (!Scene::load_shaders_from_strings(program_, vtx_source.str(),
103 frg_source.str()))
104 {
105 return false;
106 }
107
108 std::vector<GLint> attrib_locations;
109 attrib_locations.push_back(program_["position"].location());
110 attrib_locations.push_back(program_["normal"].location());
111 mesh_.set_attrib_locations(attrib_locations);
112
113 return true;
114 }
115
116 bool
setup_model_normals()117 SceneBump::setup_model_normals()
118 {
119 static const std::string vtx_shader_filename(Options::data_path + "/shaders/bump-normals.vert");
120 static const std::string frg_shader_filename(Options::data_path + "/shaders/bump-normals.frag");
121 static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
122 Model model;
123
124 if(!model.load("asteroid-low"))
125 return false;
126
127 /* Calculate the half vector */
128 LibMatrix::vec3 halfVector(lightPosition.x(), lightPosition.y(), lightPosition.z());
129 halfVector.normalize();
130 halfVector += LibMatrix::vec3(0.0, 0.0, 1.0);
131 halfVector.normalize();
132
133 /*
134 * We don't care about the vertex normals. We are using a per-fragment
135 * normal map (in object space coordinates).
136 */
137 std::vector<std::pair<Model::AttribType, int> > attribs;
138 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypePosition, 3));
139 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeTexcoord, 2));
140
141 model.convert_to_mesh(mesh_, attribs);
142
143 /* Load shaders */
144 ShaderSource vtx_source(vtx_shader_filename);
145 ShaderSource frg_source(frg_shader_filename);
146
147 /* Add constants to shaders */
148 frg_source.add_const("LightSourcePosition", lightPosition);
149 frg_source.add_const("LightSourceHalfVector", halfVector);
150
151 if (!Scene::load_shaders_from_strings(program_, vtx_source.str(),
152 frg_source.str()))
153 {
154 return false;
155 }
156
157 std::vector<GLint> attrib_locations;
158 attrib_locations.push_back(program_["position"].location());
159 attrib_locations.push_back(program_["texcoord"].location());
160 mesh_.set_attrib_locations(attrib_locations);
161
162 if (!Texture::load("asteroid-normal-map", &texture_,
163 GL_NEAREST, GL_NEAREST, 0))
164 {
165 return false;
166 }
167
168 return true;
169 }
170
171 bool
setup_model_normals_tangent()172 SceneBump::setup_model_normals_tangent()
173 {
174 static const std::string vtx_shader_filename(Options::data_path + "/shaders/bump-normals-tangent.vert");
175 static const std::string frg_shader_filename(Options::data_path + "/shaders/bump-normals-tangent.frag");
176 static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
177 Model model;
178
179 if(!model.load("asteroid-low"))
180 return false;
181
182 if (model.needNormals())
183 model.calculate_normals();
184
185 /* Calculate the half vector */
186 LibMatrix::vec3 halfVector(lightPosition.x(), lightPosition.y(), lightPosition.z());
187 halfVector.normalize();
188 halfVector += LibMatrix::vec3(0.0, 0.0, 1.0);
189 halfVector.normalize();
190
191 std::vector<std::pair<Model::AttribType, int> > attribs;
192 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypePosition, 3));
193 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeNormal, 3));
194 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeTexcoord, 2));
195 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeTangent, 3));
196
197 model.convert_to_mesh(mesh_, attribs);
198
199 /* Load shaders */
200 ShaderSource vtx_source(vtx_shader_filename);
201 ShaderSource frg_source(frg_shader_filename);
202
203 /* Add constants to shaders */
204 frg_source.add_const("LightSourcePosition", lightPosition);
205 frg_source.add_const("LightSourceHalfVector", halfVector);
206
207 if (!Scene::load_shaders_from_strings(program_, vtx_source.str(),
208 frg_source.str()))
209 {
210 return false;
211 }
212
213 std::vector<GLint> attrib_locations;
214 attrib_locations.push_back(program_["position"].location());
215 attrib_locations.push_back(program_["normal"].location());
216 attrib_locations.push_back(program_["texcoord"].location());
217 attrib_locations.push_back(program_["tangent"].location());
218 mesh_.set_attrib_locations(attrib_locations);
219
220 if (!Texture::load("asteroid-normal-map-tangent", &texture_,
221 GL_NEAREST, GL_NEAREST, 0))
222 {
223 return false;
224 }
225
226 return true;
227 }
228
229 bool
setup_model_height()230 SceneBump::setup_model_height()
231 {
232 static const std::string vtx_shader_filename(Options::data_path + "/shaders/bump-height.vert");
233 static const std::string frg_shader_filename(Options::data_path + "/shaders/bump-height.frag");
234 static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
235 Model model;
236
237 if(!model.load("asteroid-low"))
238 return false;
239
240 if (model.needNormals())
241 model.calculate_normals();
242
243 /* Calculate the half vector */
244 LibMatrix::vec3 halfVector(lightPosition.x(), lightPosition.y(), lightPosition.z());
245 halfVector.normalize();
246 halfVector += LibMatrix::vec3(0.0, 0.0, 1.0);
247 halfVector.normalize();
248
249 std::vector<std::pair<Model::AttribType, int> > attribs;
250 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypePosition, 3));
251 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeNormal, 3));
252 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeTexcoord, 2));
253 attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeTangent, 3));
254
255 model.convert_to_mesh(mesh_, attribs);
256
257 /* Load shaders */
258 ShaderSource vtx_source(vtx_shader_filename);
259 ShaderSource frg_source(frg_shader_filename);
260
261 /* Add constants to shaders */
262 frg_source.add_const("LightSourcePosition", lightPosition);
263 frg_source.add_const("LightSourceHalfVector", halfVector);
264 frg_source.add_const("TextureStepX", 1.0 / 1024.0);
265 frg_source.add_const("TextureStepY", 1.0 / 1024.0);
266
267 if (!Scene::load_shaders_from_strings(program_, vtx_source.str(),
268 frg_source.str()))
269 {
270 return false;
271 }
272
273 std::vector<GLint> attrib_locations;
274 attrib_locations.push_back(program_["position"].location());
275 attrib_locations.push_back(program_["normal"].location());
276 attrib_locations.push_back(program_["texcoord"].location());
277 attrib_locations.push_back(program_["tangent"].location());
278 mesh_.set_attrib_locations(attrib_locations);
279
280 if (!Texture::load("asteroid-height-map", &texture_,
281 GL_NEAREST, GL_NEAREST, 0))
282 {
283 return false;
284 }
285
286 return true;
287 }
288
289 bool
setup()290 SceneBump::setup()
291 {
292 if (!Scene::setup())
293 return false;
294
295 const std::string &bump_render = options_["bump-render"].value;
296 Texture::find_textures();
297 Model::find_models();
298
299 bool setup_succeeded = false;
300
301 if (bump_render == "normals")
302 setup_succeeded = setup_model_normals();
303 else if (bump_render == "normals-tangent")
304 setup_succeeded = setup_model_normals_tangent();
305 else if (bump_render == "height")
306 setup_succeeded = setup_model_height();
307 else if (bump_render == "off" || bump_render == "high-poly")
308 setup_succeeded = setup_model_plain(bump_render);
309
310 if (!setup_succeeded)
311 return false;
312
313 mesh_.build_vbo();
314
315 program_.start();
316
317 // Load texture sampler value
318 program_["NormalMap"] = 0;
319 program_["HeightMap"] = 0;
320
321 currentFrame_ = 0;
322 rotation_ = 0.0;
323 running_ = true;
324 startTime_ = Util::get_timestamp_us() / 1000000.0;
325 lastUpdateTime_ = startTime_;
326
327 return true;
328 }
329
330 void
teardown()331 SceneBump::teardown()
332 {
333 mesh_.reset();
334
335 program_.stop();
336 program_.release();
337
338 glDeleteTextures(1, &texture_);
339 texture_ = 0;
340
341 Scene::teardown();
342 }
343
344 void
update()345 SceneBump::update()
346 {
347 Scene::update();
348
349 double elapsed_time = lastUpdateTime_ - startTime_;
350
351 rotation_ = rotationSpeed_ * elapsed_time;
352 }
353
354 void
draw()355 SceneBump::draw()
356 {
357 LibMatrix::Stack4 model_view;
358
359 // Load the ModelViewProjectionMatrix uniform in the shader
360 LibMatrix::mat4 model_view_proj(canvas_.projection());
361
362 model_view.translate(0.0f, 0.0f, -3.5f);
363 model_view.rotate(rotation_, 0.0f, 1.0f, 0.0f);
364 model_view_proj *= model_view.getCurrent();
365
366 program_["ModelViewProjectionMatrix"] = model_view_proj;
367
368 // Load the NormalMatrix uniform in the shader. The NormalMatrix is the
369 // inverse transpose of the model view matrix.
370 LibMatrix::mat4 normal_matrix(model_view.getCurrent());
371 normal_matrix.inverse().transpose();
372 program_["NormalMatrix"] = normal_matrix;
373
374 glActiveTexture(GL_TEXTURE0);
375 glBindTexture(GL_TEXTURE_2D, texture_);
376
377 mesh_.render_vbo();
378 }
379
380 Scene::ValidationResult
validate()381 SceneBump::validate()
382 {
383 static const double radius_3d(std::sqrt(3.0));
384
385 if (rotation_ != 0)
386 return Scene::ValidationUnknown;
387
388 Canvas::Pixel ref;
389
390 Canvas::Pixel pixel = canvas_.read_pixel(canvas_.width() / 2,
391 canvas_.height() / 2);
392
393 const std::string &bump_render = options_["bump-render"].value;
394
395 if (bump_render == "off")
396 ref = Canvas::Pixel(0x81, 0x81, 0x81, 0xff);
397 else if (bump_render == "high-poly")
398 ref = Canvas::Pixel(0x9c, 0x9c, 0x9c, 0xff);
399 else if (bump_render == "normals")
400 ref = Canvas::Pixel(0xa4, 0xa4, 0xa4, 0xff);
401 else if (bump_render == "normals-tangent")
402 ref = Canvas::Pixel(0x99, 0x99, 0x99, 0xff);
403 else if (bump_render == "height")
404 ref = Canvas::Pixel(0x9d, 0x9d, 0x9d, 0xff);
405 else
406 return Scene::ValidationUnknown;
407
408 double dist = pixel.distance_rgb(ref);
409
410 if (dist < radius_3d + 0.01) {
411 return Scene::ValidationSuccess;
412 }
413 else {
414 Log::debug("Validation failed! Expected: 0x%x Actual: 0x%x Distance: %f\n",
415 ref.to_le32(), pixel.to_le32(), dist);
416 return Scene::ValidationFailure;
417 }
418 }
419