OpenGL ES SDK for Android ARM Developer Center
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
app.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2014-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "app.h"
22 #include "timer.h"
23 #include "shader.h"
24 #include "primitives.h"
25 #include "noise.h"
26 #include "sort.h"
27 #include <math.h>
28 const float TIMESTEP = 0.005f;
30 
31 Shader
38 
39 Mesh
41  plane,
42  sphere;
43 
44 mat4
47  mat_view,
49 
50 vec2
53  last_tap;
54 
55 vec3
62  sphere_pos,
64  sort_axis;
65 
66 float
68 
69 bool
71  dragging;
72 
73 GLuint
78 
79 int
84 
85 Shader
87 
88 bool load_app()
89 {
90  string res = "/data/data/com.arm.malideveloper.openglessdk.computeparticles/files/";
91  if (!shader_update.load_compute_from_file(res + "update.cs") ||
92  !shader_spawn.load_compute_from_file(res + "spawn.cs") ||
93  !shader_plane.load_from_file(res + "plane.vs", res + "plane.fs") ||
94  !shader_sphere.load_from_file(res + "sphere.vs", res + "sphere.fs") ||
95  !shader_shadow_map.load_from_file(res + "shadowmap.vs", res + "shadowmap.fs") ||
96  !shader_draw_particle.load_from_file(res + "particle.vs", res + "particle.fs"))
97  return false;
98 
99  if (!shader_update.link() ||
100  !shader_spawn.link() ||
101  !shader_plane.link() ||
102  !shader_sphere.link() ||
103  !shader_shadow_map.link() ||
105  return false;
106 
107  if (!sort_init())
108  return false;
109 
110  return true;
111 }
112 
113 void free_app()
114 {
121 
124 
125  quad.dispose();
126  plane.dispose();
127  sphere.dispose();
128 
129  glDeleteTextures(1, &shadow_map_tex);
130  glDeleteFramebuffers(1, &shadow_map_fbo);
131 
132  sort_free();
133 }
134 
136 {
137  glGenTextures(1, &shadow_map_tex);
138  glBindTexture(GL_TEXTURE_2D, shadow_map_tex);
139  glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
140  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
141  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
142  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
143  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
144  glBindTexture(GL_TEXTURE_2D, 0);
145 
146  glGenFramebuffers(1, &shadow_map_fbo);
147  glBindFramebuffer(GL_FRAMEBUFFER, shadow_map_fbo);
148  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shadow_map_tex, 0);
149 
150  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
151  ASSERT(status == GL_FRAMEBUFFER_COMPLETE, "Framebuffer not complete\n");
152  glBindFramebuffer(GL_FRAMEBUFFER, 0);
153 }
154 
156 {
157  // Store particle position (x, y, z) and lifetime (w)
158  vec4 *data = new vec4[NUM_PARTICLES];
159  for (int i = 0; i < NUM_PARTICLES; ++i)
160  {
161  // Distribute initial position inside a sphere of radius 0.3
162  vec3 p = vec3(0.0f, 0.0f, 0.0f);
163  p.x = 0.3f * (-1.0f + 2.0f * frand());
164  p.y = 0.3f * (-1.0f + 2.0f * frand());
165  p.z = 0.3f * (-1.0f + 2.0f * frand());
166 
167  // Each particle has a slightly randomized lifetime, around a constant value
168  float lifetime = (1.0 + 0.25 * frand()) * particle_lifetime;
169  data[i] = vec4(p, lifetime);
170  }
171  buffer_position = gen_buffer(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_DRAW, NUM_PARTICLES * sizeof(vec4), data);
172  buffer_spawn = gen_buffer(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_DRAW, NUM_PARTICLES * sizeof(vec4), NULL);
173  delete[] data;
174 }
175 
176 void init_app(int width, int height)
177 {
180 
181  camera_angle = vec2(-0.7f, 0.0f);
182  camera_angle_vel = vec2(0.0f, 0.0f);
184  mat_view_light = translate(0.0f, 0.0f, -2.0f) * rotateX(-PI / 2.0f) * rotateY(PI / 2.0f);
185  mat_projection = perspective(PI / 4.0f, float(width) / height, 0.1f, 10.0f);
186  mat_projection_light = orthographic(-2.0f, 2.0f, -2.0f, 2.0f, 1.5f, 2.5f);
187 
188  sphere = gen_unit_sphere(24, 24);
190  quad = gen_tex_quad();
191 
192  emitter_pos = vec3(0.0, 0.0, 0.0);
193  sphere_pos = vec3(0.0, -0.5, 0.0);
194  last_tap = vec2(0.0f, 0.0f);
195  particle_lifetime = 0.7f;
196  dragging = false;
197 
198  light_ambient = vec3(0.00137f, 0.0029f, 0.0063f);
199  light_color = vec3(1.0f, 1.0f, 1.0f);
200  smoke_color = vec3(0.93f, 0.79f, 0.72f);
201  smoke_shadow = vec3(0.1f, 0.12f, 0.18f);
202 
203  shadow_map_width = 512;
204  shadow_map_height = 512;
205 
206  init_particles();
208 }
209 
210 /*
211  * Sort the particles back-to-front relative to the point of view.
212  * The sorting key is the distance along the sort axis, converted to
213  * a 16-bit integer. To convert to an integer we need to map the distance
214  * from a valid range (here -2 to 2) to [0, 65535].
215 */
216 int pass = 0;
218 {
219  // Calculate vector towards eye (in world space)
220  vec4 v = vec4(0.0, 0.0, 0.0, 1.0);
221  v = inverse(mat_view) * v;
222  vec3 view_axis = normalize(v.xyz());
223  radix_sort(buffer_position, view_axis, -2.0f, 2.0f);
224 }
225 
226 /*
227  * Simulates the particles according to a turbulent curl-noise fluid field,
228  * superposed with a repulsion field around the sphere.
229  * Particles run out of life after a while and respawn, using the information
230  * stored in the spawn buffer.
231 */
233 {
234  const uint32 WORK_GROUP_SIZE = 64;
235 
236  // Generate respawn info
238  uniform("time", get_elapsed_time());
239  uniform("emitterPos", emitter_pos);
240  uniform("particleLifetime", particle_lifetime);
241  glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer_spawn);
242  glDispatchCompute(NUM_PARTICLES / WORK_GROUP_SIZE, 1, 1);
243  glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
244 
245  // Advect through velocity field
247  uniform("dt", TIMESTEP);
248  uniform("time", get_elapsed_time());
249  uniform("seed", vec3(13.0f, 127.0f, 449.0f));
250  uniform("spherePos", sphere_pos);
251  uniform("particleLifetime", particle_lifetime);
252  glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffer_position);
253  glDispatchCompute(NUM_PARTICLES / WORK_GROUP_SIZE, 1, 1);
254  glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
255  glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
256  glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, 0);
257 }
258 
260 {
261  // Additive blending
262  blend_mode(true, GL_ONE, GL_ONE);
263 
264  // Clear shadowmap (all components 0!)
265  glBindFramebuffer(GL_FRAMEBUFFER, shadow_map_fbo);
266  glViewport(0, 0, shadow_map_width, shadow_map_height);
267  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
268  glClear(GL_COLOR_BUFFER_BIT);
269 
270  // Render shadow info
272  uniform("projection", mat_projection_light);
273  uniform("view", mat_view_light);
274  glBindBuffer(GL_ARRAY_BUFFER, buffer_position);
275  attribfv("position", 4, 0, 0);
276  glDrawArrays(GL_POINTS, 0, NUM_PARTICLES);
277 
278  blend_mode(false);
279  glBindFramebuffer(GL_FRAMEBUFFER, 0);
280  glViewport(0, 0, window_width, window_height);
281 }
282 
283 void update_app(float dt)
284 {
285  float t = get_elapsed_time() * 0.7f;
287  camera_angle.x = clamp(camera_angle.x, -PI - 0.3f, 0.3f);
288  camera_angle_vel *= 0.95f;
289 
291  mat_view_light = translate(0.0f, 0.0f, -2.0f) * rotateX(-PI / 2.0f);
292 
293  light_pos = (inverse(mat_view_light) * vec4(0.0, 0.0, 0.0, 1.0)).xyz();
294 
295  emitter_pos.x = 0.8f * sin(t * 1.2f);
296  emitter_pos.z = 0.8f * cos(t * 0.7f);
297  emitter_pos.y = 0.8f * sin(t * 2.0f) * 0.2f;
298 
299  sphere_pos += (sphere_pos_target - sphere_pos) * 3.5f * dt;
300 
302  sort_particles();
303 
305 }
306 
308 {
309  // Sphere
310  glBindTexture(GL_TEXTURE_2D, shadow_map_tex);
311  cull(true, GL_CW, GL_BACK);
313  uniform("projection", mat_projection);
314  uniform("projectionViewLight", mat_projection_light * mat_view_light);
315  uniform("view", mat_view);
316  uniform("lightDir", normalize(light_pos));
317  uniform("shadowMap0", 0);
318  uniform("model", translate(sphere_pos) * scale(0.1f));
319  uniform("color", vec3(0.20f, 0.34f, 0.09f));
320  sphere.bind();
321  attribfv("position", 3, 0, 0);
322  glDrawElements(GL_TRIANGLES, sphere.num_indices, GL_UNSIGNED_INT, 0);
323 
324  // Floor
326  uniform("projection", mat_projection);
327  uniform("projectionViewLight", mat_projection_light * mat_view_light);
328  uniform("view", mat_view);
329  uniform("shadowMap0", 0);
330  uniform("model", translate(0.0f, -1.0f, 0.0f) * scale(8.0f));
331  uniform("color", vec3(0.20f, 0.05f, 0.022f));
332  plane.bind();
333  attribfv("position", 3, 6, 0);
334  glDrawElements(GL_TRIANGLES, plane.num_indices, GL_UNSIGNED_INT, 0);
335 }
336 
338 {
339  // Alphablending with premultiplied alpha
340  blend_mode(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_FUNC_ADD);
341 
343  uniform("projection", mat_projection);
344  uniform("view", mat_view);
345  uniform("particleLifetime", particle_lifetime);
346  uniform("projectionViewLight", mat_projection_light * mat_view_light);
347  uniform("smokeColor", smoke_color);
348  uniform("smokeShadow", smoke_shadow);
349  uniform("shadowMap0", 0);
350  glBindTexture(GL_TEXTURE_2D, shadow_map_tex);
351  glBindBuffer(GL_ARRAY_BUFFER, buffer_position);
352  attribfv("position", 4, 0, 0);
353  glDrawArrays(GL_POINTS, 0, NUM_PARTICLES);
354  glBindBuffer(GL_ARRAY_BUFFER, 0);
355  glBindTexture(GL_TEXTURE_2D, 0);
356 }
357 
358 void render_app(float dt)
359 {
360  glEnable(GL_DEPTH_TEST);
361  glDepthMask(GL_TRUE);
362  glDepthRangef(0.0f, 1.0f);
363  glDepthFunc(GL_LEQUAL);
364  glClearDepthf(1.0f);
365  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
366  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
367 
368  render_geometry();
369 
370  // The particles are rendered without depth writes, but with depth testing
371  // If they write to the depth buffer you'll likely get some artifacts here and there.
372  glDepthMask(GL_FALSE);
374 }
375 
376 void on_pointer_down(float x, float y)
377 {
378  // Raycast mouse point onto the floor
379  float xndc = -1.0f + 2.0f * x / window_width;
380  float yndc = 1.0f - 2.0f * y / window_height;
381 
382  // Project onto near clipping plane
383  vec4 view = inverse(mat_projection) * vec4(xndc, yndc, 1.0f, 1.0f);
384 
385  // Solve ray intersection equation
386  vec3 origin = (inverse(mat_view) * vec4(0.0f, 0.0f, 0.0f, 1.0f)).xyz();
387  vec3 dir = normalize((inverse(mat_view) * view).xyz());
388  float t = -origin.y / dir.y;
389  vec3 p = origin + dir * t;
390 
391  if (p.x < -2.0f || p.x > 2.0f || p.z < -2.0f || p.z > 2.0f || dragging)
392  {
393  if (!dragging)
394  {
395  dragging = true;
396  last_tap = vec2(x, y);
397  }
398 
399  float dx = x - last_tap.x;
400  float dy = y - last_tap.y;
401  camera_angle_vel -= vec2(dy, dx) * 0.0025f;
402  last_tap = vec2(x, y);
403  }
404  else if (!dragging)
405  {
406  p.x = clamp(p.x, -2.0f, 2.0f);
407  p.z = clamp(p.z, -2.0f, 2.0f);
408  sphere_pos_target = p;
409  }
410 }
411 
412 void on_pointer_up(float x, float y)
413 {
414  dragging = false;
415 }
void init_particles()
Definition: app.cpp:155
vec3 smoke_shadow
Definition: app.cpp:56
const GLfloat * v
Definition: gl2ext.h:2231
Mesh plane
Definition: app.cpp:40
int pass
Definition: app.cpp:216
void on_pointer_down(float x, float y)
Definition: app.cpp:376
#define attribfv(prog, name, n, offset)
Definition: geometry.h:118
mat4 mat_projection_light
Definition: app.cpp:45
const uint32 NUM_PARTICLES
Definition: app.cpp:29
vec3 xyz() const
Definition: matrix.h:101
bool dragging
Definition: app.cpp:70
bool load_compute_from_file(string cs_path)
Definition: shader.cpp:117
vec3 sphere_pos
Definition: app.cpp:56
Shader shader_draw_particle
Definition: app.cpp:32
Definition: matrix.h:51
Mesh gen_unit_sphere(int t_samples, int s_samples)
Definition: primitives.cpp:67
float particle_lifetime
Definition: app.cpp:67
GLint GLsizei GLsizei height
Definition: gl2ext.h:179
void radix_sort(GLuint buf_input, vec3 axis, float z_min, float z_max)
Definition: sort.cpp:181
GLuint buffer_position
Definition: app.cpp:74
GLuint shadow_map_tex
Definition: app.cpp:74
Definition: matrix.h:28
bool load_from_file(const string *paths, GLenum *types, int count)
Definition: shader.cpp:93
Shader shader_count
Definition: app.cpp:86
bool load_app()
Definition: app.cpp:88
GLuint shadow_map_fbo
Definition: app.cpp:74
mat4 mat_view_light
Definition: app.cpp:45
float clamp(float x, float min, float max)
Definition: noise.cpp:24
Shader shader_spawn
Definition: app.cpp:32
void del_buffer(GLuint buffer)
Definition: glutil.cpp:137
mat4 mat_view
Definition: app.cpp:45
vec3 sort_axis
Definition: app.cpp:56
const vec3 dx
Definition: update.cs:38
float z
Definition: matrix.h:55
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
Definition: gl2ext.h:179
static mat4 rotateY(float rad)
Definition: matrix.h:320
Mesh gen_normal_plane()
Definition: primitives.cpp:23
Definition: matrix.h:75
#define PI
Definition: matrix.h:24
void bind()
Definition: primitives.cpp:122
mat4 mat_projection
Definition: app.cpp:45
void render_particles()
Definition: app.cpp:337
unsigned int uint32
Definition: common.h:32
vec2 last_tap
Definition: app.cpp:51
static mat4 orthographic(float left, float right, float bottom, float top, float near, float far)
Definition: matrix.h:172
static mat4 inverse(const mat4 &op)
Definition: matrix.h:185
int num_indices
Definition: primitives.h:30
vec3 light_color
Definition: app.cpp:56
Shader shader_update
Definition: app.cpp:32
float frand()
Definition: noise.cpp:53
void on_pointer_up(float x, float y)
Definition: app.cpp:412
static vec3 normalize(const vec3 &v)
Definition: matrix.h:154
void dispose()
Definition: shader.cpp:129
Mesh gen_tex_quad()
Definition: primitives.cpp:45
GLuint buffer_spawn
Definition: app.cpp:74
bool link()
Definition: shader.cpp:124
Mesh quad
Definition: app.cpp:40
vec2 camera_angle_vel
Definition: app.cpp:51
Matrix perspective
Definition: EGLPreserve.cpp:81
GLfloat GLfloat f
Definition: gl2ext.h:2707
const uint32_t NUM_KEYS
Definition: sort.h:26
void dispose()
Definition: primitives.cpp:116
float y
Definition: matrix.h:31
const vec3 dy
Definition: update.cs:39
static mat4 rotateX(float rad)
Definition: matrix.h:312
vec3 light_ambient
Definition: app.cpp:56
Matrix scale
Definition: RotoZoom.cpp:64
float x
Definition: matrix.h:53
void init_app(int width, int height)
Definition: app.cpp:176
void cull(bool enabled, GLenum front, GLenum mode)
Definition: glutil.cpp:27
float y
Definition: matrix.h:54
Mesh sphere
Definition: app.cpp:40
const float TIMESTEP
Definition: app.cpp:28
bool front_to_back
Definition: app.cpp:70
GLuint gen_buffer(GLenum target, GLenum usage, GLsizei size, const void *data)
Definition: glutil.cpp:122
Definition: shader.h:27
int window_height
Definition: app.cpp:80
void uniform(string name, const mat4 &v)
Definition: glutil.cpp:97
int window_width
Definition: app.cpp:80
void sort_free()
Definition: sort.cpp:87
bool sort_init()
Definition: sort.cpp:44
Shader shader_plane
Definition: app.cpp:32
int shadow_map_height
Definition: app.cpp:80
void sort_particles()
Definition: app.cpp:217
GLint GLint GLint GLint GLint x
Definition: gl2ext.h:574
Definition: matrix.h:104
vec2 camera_angle
Definition: app.cpp:51
vec3 sphere_pos_target
Definition: app.cpp:56
vec3 light_pos
Definition: app.cpp:56
void use_shader(Shader shader)
Definition: glutil.cpp:81
#define ASSERT(x, s)
Definition: common.h:45
int shadow_map_width
Definition: app.cpp:80
GLint GLsizei width
Definition: gl2ext.h:179
float x
Definition: matrix.h:30
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
void free_app()
Definition: app.cpp:113
uniform float dt
Definition: update.cs:29
double get_elapsed_time()
Definition: timer.cpp:33
vec3 emitter_pos
Definition: app.cpp:56
typedef GLuint(GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count
void update_shadow_map()
Definition: app.cpp:259
GLint y
Definition: gl2ext.h:179
static mat4 translate(float x, float y, float z)
Definition: matrix.h:336
vec3 smoke_color
Definition: app.cpp:56
void render_app(float dt)
Definition: app.cpp:358
void init_shadowmap(int width, int height)
Definition: app.cpp:135
void render_geometry()
Definition: app.cpp:307
void update_app(float dt)
Definition: app.cpp:283
Shader shader_shadow_map
Definition: app.cpp:32
void blend_mode(bool enabled, GLenum src, GLenum dest, GLenum func)
Definition: glutil.cpp:67
void update_particles()
Definition: app.cpp:232
Shader shader_sphere
Definition: app.cpp:32