Skip to content

Commit dd55476

Browse files
committed
Add reaction diffusion example.
1 parent 915ab0b commit dd55476

File tree

1 file changed

+255
-0
lines changed

1 file changed

+255
-0
lines changed

example/reaction_diffusion.cpp

+255
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
//---------------------------------------------------------------------------//
2+
// Copyright (c) 2020 Adam Wulkiewicz
3+
//
4+
// Distributed under the Boost Software License, Version 1.0
5+
// See accompanying file LICENSE_1_0.txt or copy at
6+
// http://www.boost.org/LICENSE_1_0.txt
7+
//
8+
// See http://boostorg.github.com/compute for more information.
9+
//---------------------------------------------------------------------------//
10+
11+
#include <boost/compute.hpp>
12+
13+
#ifdef __APPLE__
14+
#include <GLUT/glut.h>
15+
#else
16+
#include <GL/glut.h>
17+
#endif
18+
19+
namespace bc = boost::compute;
20+
21+
// Inspired by Reaction-Diffusion Tutorial by Karl Sims
22+
// see: http://www.karlsims.com/rd.html
23+
class reaction
24+
{
25+
public:
26+
reaction(size_t w, size_t h)
27+
: m_device(bc::system::default_device())
28+
, m_context(m_device)
29+
, m_queue(m_context, m_device)
30+
, m_program(m_context)
31+
, m_kernel(m_program.program, "my_program")
32+
, m_current(0)
33+
, m_w(w)
34+
, m_h(h)
35+
{
36+
std::vector<bc::float2_> vec(w * h);
37+
for (size_t j = 0; j < h; j++)
38+
{
39+
for (size_t i = 0; i < w; i++)
40+
{
41+
size_t id = j * w + i;
42+
vec[id].x = 1;
43+
vec[id].y = 0;
44+
}
45+
}
46+
47+
for (size_t j = h / 2 - 5; j < h / 2 + 5; j++)
48+
{
49+
for (size_t i = w / 2 - 5; i < w / 2 + 5; i++)
50+
{
51+
size_t id = j * w + i;
52+
vec[id].y = 1;
53+
}
54+
}
55+
56+
m_device_vectors[0] = bc::vector<bc::float2_>(w * h, m_context);
57+
m_device_vectors[1] = bc::vector<bc::float2_>(w * h, m_context);
58+
m_current = 0;
59+
60+
bc::copy(vec.begin(), vec.end(), m_device_vectors[0].begin(), m_queue);
61+
bc::copy(m_device_vectors[0].begin(), m_device_vectors[0].end(), m_device_vectors[1].begin(), m_queue);
62+
}
63+
64+
template <typename Vector>
65+
void next(unsigned n, Vector & texture)
66+
{
67+
BOOST_ASSERT(texture.size() == m_w * m_h);
68+
69+
for (unsigned i = 0 ; i < n ; i++)
70+
calculate_next();
71+
72+
bc::vector<bc::float2_> const& current_vector = m_device_vectors[m_current];
73+
std::vector<bc::float2_> vec(m_w * m_h);
74+
bc::copy(current_vector.begin(), current_vector.end(), vec.begin(), m_queue);
75+
for (size_t k = 0; k < vec.size(); k++)
76+
texture[k] = luminosity(vec[k]);
77+
}
78+
79+
private:
80+
void calculate_next()
81+
{
82+
size_t next = (m_current + 1) % 2;
83+
bc::vector<bc::float2_> const& current_vector = m_device_vectors[m_current];
84+
bc::vector<bc::float2_> const& next_vector = m_device_vectors[next];
85+
m_current = next;
86+
87+
m_kernel.set_arg(0, current_vector.get_buffer());
88+
m_kernel.set_arg(1, next_vector.get_buffer());
89+
m_kernel.set_arg(2, (bc::uint_)m_w);
90+
m_kernel.set_arg(3, (bc::uint_)m_h);
91+
92+
size_t origin[2] = { 1, 1 };
93+
size_t region[2] = { m_w - 2, m_h - 2 };
94+
95+
m_queue.enqueue_nd_range_kernel(m_kernel, 2, origin, region, 0);
96+
m_queue.finish();
97+
}
98+
99+
static unsigned char luminosity(bc::float2_ const& f2)
100+
{
101+
//float val = bounded((f2.x - f2.y - 0.5f) * 2.0f, -0.5f, 0.5f) + 0.5;
102+
float val = bounded((f2.x - f2.y) * 2.0f, 0.0f, 1.0f);
103+
return (unsigned char)(255 * val);
104+
}
105+
106+
template <typename T>
107+
static T bounded(T val, T mi, T ma)
108+
{
109+
return (std::min)((std::max)(val, mi), ma);
110+
}
111+
112+
struct program_holder
113+
{
114+
program_holder(bc::context const& context)
115+
: program(bc::program::create_with_source(source(), context))
116+
{
117+
program.build();
118+
}
119+
120+
static const char * source()
121+
{
122+
return BOOST_COMPUTE_STRINGIZE_SOURCE(
123+
__kernel void my_program(__global __read_only float2* curr,
124+
__global __write_only float2* next,
125+
uint w,
126+
uint h)
127+
{
128+
uint i = get_global_id(0);
129+
uint j = get_global_id(1);
130+
131+
// Parameters
132+
float da = 1.0f;
133+
float db = 0.5f;
134+
//float f = 0.04f;
135+
//float k = 0.0649f;
136+
//float f = 0.0545f;
137+
//float k = 0.062f;
138+
//float f = 0.055f;
139+
//float k = 0.062f;
140+
float f = (float)j / h * (0.07f - 0.03f) + 0.01f;
141+
float k = (float)i / w * (0.07f - 0.045f) + 0.045f;
142+
143+
// 2D Laplacian
144+
// id_0 - 1 | id_0 | id_0 + 1
145+
// --------------------------
146+
// id_1 - 1 | id_1 | id_1 + 1
147+
// --------------------------
148+
// id_2 - 1 | id_2 | id_2 + 1
149+
int id_0 = (j - 1) * w + i;
150+
int id_1 = j * w + i;
151+
int id_2 = (j + 1) * w + i;
152+
float2 l = 0.05f * curr[id_0 - 1]
153+
+ 0.2f * curr[id_0]
154+
+ 0.05f * curr[id_0 + 1]
155+
+ 0.2f * curr[id_1 - 1]
156+
- 1 * curr[id_1]
157+
+ 0.2f * curr[id_1 + 1]
158+
+ 0.05f * curr[id_2 - 1]
159+
+ 0.2f * curr[id_2]
160+
+ 0.05f * curr[id_2 + 1];
161+
162+
// New values
163+
float a = curr[id_1].x;
164+
float b = curr[id_1].y;
165+
float la = l.x;
166+
float lb = l.y;
167+
float abb = a * b * b;
168+
float na = a + (da * la - abb + f * (1 - a));
169+
float nb = b + (db * lb + abb - (k + f) * b);
170+
171+
// Normaliziation
172+
if (na < 0.0f) na = 0.0f;
173+
else if (na > 1.0f) na = 1.0f;
174+
if (nb < 0.0f) nb = 0.0f;
175+
else if (nb > 1.0f) nb = 1.0f;
176+
177+
next[id_1].x = na;
178+
next[id_1].y = nb;
179+
}
180+
);
181+
}
182+
183+
bc::program program;
184+
};
185+
186+
bc::device m_device;
187+
bc::context m_context;
188+
bc::command_queue m_queue;
189+
program_holder m_program;
190+
bc::kernel m_kernel;
191+
192+
bc::vector<bc::float2_> m_device_vectors[2];
193+
size_t m_current;
194+
195+
size_t m_w;
196+
size_t m_h;
197+
};
198+
199+
int width = 800;
200+
int height = 800;
201+
202+
reaction react(width, height);
203+
204+
void init()
205+
{
206+
GLuint texture_id;
207+
glEnable(GL_TEXTURE_2D);
208+
glGenTextures(1, &texture_id);
209+
glBindTexture(GL_TEXTURE_2D, texture_id);
210+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
211+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
212+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
213+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
214+
}
215+
216+
void render_scene()
217+
{
218+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
219+
220+
glBegin(GL_QUADS);
221+
glTexCoord2f(0, 0);
222+
glVertex3f(-1, -1, 0);
223+
glTexCoord2f(1, 0);
224+
glVertex3f(1, -1, 0);
225+
glTexCoord2f(1, 1);
226+
glVertex3f(1, 1, 0);
227+
glTexCoord2f(0, 1);
228+
glVertex3f(-1, 1, 0);
229+
glEnd();
230+
231+
glutSwapBuffers();
232+
}
233+
234+
void idle()
235+
{
236+
std::vector<unsigned char> texture(width * height);
237+
react.next(64, texture);
238+
239+
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &texture[0]);
240+
241+
glutPostRedisplay();
242+
}
243+
244+
int main(int argc, char **argv)
245+
{
246+
glutInit(&argc, argv);
247+
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
248+
glutInitWindowPosition(100, 100);
249+
glutInitWindowSize(width, height);
250+
glutCreateWindow("Boost.Compute - Reaction Diffusion");
251+
init();
252+
glutDisplayFunc(render_scene);
253+
glutIdleFunc(idle);
254+
glutMainLoop();
255+
}

0 commit comments

Comments
 (0)