1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#include "../common/tutorial/tutorial_device.isph"
5#include "../common/math/random_sampler.isph"
6
7struct Point
8{
9  ALIGNED_STRUCT_(16)
10  Vec3f p;                      //!< position
11};
12
13struct PointQueryResult
14{
15  ALIGNED_STRUCT_(16)
16  unsigned int primID;
17};
18
19struct PointQuery
20{
21  Vec3f p;
22  float time;
23  float radius;
24};
25
26/* scene data */
27RTCScene g_scene  = NULL;
28uniform Point* uniform g_points = NULL;
29const uniform int g_num_colors = 27;
30uniform Vec3fa g_colors[g_num_colors];
31
32extern uniform int g_num_points;
33uniform int g_num_points_current;
34
35void renderTileStandardStream(uniform int taskIndex,
36                              uniform int threadIndex,
37                              uniform int* uniform pixels,
38                              const uniform unsigned int width,
39                              const uniform unsigned int height,
40                              const uniform float time,
41                              const uniform ISPCCamera& camera,
42                              const uniform int numTilesX,
43                              const uniform int numTilesY);
44
45// ======================================================================== //
46//                     User defined point geometry                         //
47// ======================================================================== //
48
49unmasked void pointBoundsFunc(const struct RTCBoundsFunctionArguments* uniform args)
50{
51  const uniform Point* uniform points = (const uniform Point* uniform) args->geometryUserPtr;
52  uniform RTCBounds* uniform bounds_o = args->bounds_o;
53  const uniform Point& point = points[args->primID];
54  bounds_o->lower_x = point.p.x;
55  bounds_o->lower_y = point.p.y;
56  bounds_o->lower_z = point.p.z;
57  bounds_o->upper_x = point.p.x;
58  bounds_o->upper_y = point.p.y;
59  bounds_o->upper_z = point.p.z;
60}
61
62unmasked bool pointQueryFunc(RTCPointQueryFunctionArguments* uniform args)
63{
64  assert(args->userPtr);
65
66  RTCPointQuery* query = (RTCPointQuery*)args->query;
67  unsigned int primID = args->primID;
68  Vec3f q = make_Vec3f(query->x, query->y, query->z);
69  const Point point = g_points[primID];
70  const float d = distance(point.p, q);
71
72  if(d < query->radius)
73  {
74    PointQueryResult* result = (PointQueryResult*)args->userPtr;
75    result->primID = primID;
76    query->radius = d;
77    return true;
78  }
79  return false;
80}
81
82uniform Point* uniform createPoints (RTCScene scene, uniform unsigned int N)
83{
84  RTCGeometry geom = rtcNewGeometry(g_device, RTC_GEOMETRY_TYPE_USER);
85  g_points = uniform new uniform Point[N];
86  uniform unsigned int geomID = rtcAttachGeometry(scene, geom);
87  rtcSetGeometryUserPrimitiveCount(geom, N);
88  rtcSetGeometryUserData(geom, g_points);
89  rtcSetGeometryBoundsFunction(geom, pointBoundsFunc, NULL);
90  rtcCommitGeometry(geom);
91  rtcReleaseGeometry(geom);
92
93  RandomSampler rs;
94  RandomSampler_init(rs, 42);
95  for (unsigned int i = 0; i < N; ++i)
96  {
97    float xi1 = RandomSampler_getFloat(rs);
98    float xi2 = RandomSampler_getFloat(rs);
99    g_points[i].p = make_Vec3f(xi1, 0.f, xi2);
100  }
101
102  g_num_points_current = N;
103  return g_points;
104}
105
106/* called by the C++ code for initialization */
107export void device_init (uniform int8* uniform cfg)
108{
109  /* create scene */
110  g_scene = rtcNewScene(g_device);
111  g_points = createPoints(g_scene, g_num_points);
112  rtcCommitScene(g_scene);
113
114  /* set all colors */
115  for (uniform int r = 0; r < 3; ++r)
116    for (uniform int g = 0; g < 3; ++g)
117      for (uniform int b = 0; b < 3; ++b)
118        g_colors[r * 9 + g * 3 + b] = make_Vec3fa(0.2f + 0.3f * r, 0.2f + 0.3f * g, 0.2f + 0.3f * b);
119
120}
121
122/* renders a single screen tile */
123void renderTileStandard(uniform int taskIndex,
124                        uniform int threadIndex,
125                        uniform int* uniform pixels,
126                        const uniform unsigned int width,
127                        const uniform unsigned int height,
128                        const uniform float time,
129                        const uniform ISPCCamera& camera,
130                        const uniform int numTilesX,
131                        const uniform int numTilesY)
132{
133  const uniform unsigned int tileY = taskIndex / numTilesX;
134  const uniform unsigned int tileX = taskIndex - tileY * numTilesX;
135  const uniform unsigned int x0 = tileX * TILE_SIZE_X;
136  const uniform unsigned int x1 = min(x0+TILE_SIZE_X,width);
137  const uniform unsigned int y0 = tileY * TILE_SIZE_Y;
138  const uniform unsigned int y1 = min(y0+TILE_SIZE_Y,height);
139
140  foreach_tiled (y = y0 ... y1, x = x0 ... x1)
141  {
142    if (all(__mask == 0)) continue;
143
144    /* calculate pixel color */
145    Vec3fa color = make_Vec3fa(0.f);
146    Vec3f q = make_Vec3f(((float)x + 0.5f) / width, 0.f, ((float)y + 0.5f) / height);
147
148    PointQuery query;
149    query.p = q;
150    query.time = 0.f;
151    query.radius = inf;
152
153    uniform PointQueryResult result[programCount];
154    result[programIndex].primID = RTC_INVALID_GEOMETRY_ID;
155    void* userPtr = (void*)&result[programIndex];
156
157    uniform RTCPointQueryContext context;
158    rtcInitPointQueryContext(&context);
159    rtcPointQueryV(g_scene,
160                  (varying RTCPointQuery* uniform)&query,
161                  &context,
162                  pointQueryFunc,
163                  &userPtr);
164
165    unsigned int primID = result[programIndex].primID;
166
167    if (primID != RTC_INVALID_GEOMETRY_ID)
168      color = g_colors[primID % 27];
169
170    /* write color to framebuffer */
171    unsigned int r = (unsigned int) (255.0f * clamp(color.x,0.0f,1.0f));
172    unsigned int g = (unsigned int) (255.0f * clamp(color.y,0.0f,1.0f));
173    unsigned int b = (unsigned int) (255.0f * clamp(color.z,0.0f,1.0f));
174    pixels[y*width+x] = (b << 16) + (g << 8) + r;
175  }
176}
177
178/* task that renders a single screen tile */
179task void renderTileTask(uniform int* uniform pixels,
180                         const uniform unsigned int width,
181                         const uniform unsigned int height,
182                         const uniform float time,
183                         const uniform ISPCCamera& camera,
184                         const uniform int numTilesX,
185                         const uniform int numTilesY)
186{
187  renderTileStandard(taskIndex,threadIndex,pixels,width,height,time,camera,numTilesX,numTilesY);
188}
189
190void splat_color(uniform int* pixels,
191                 const uniform unsigned int width,
192                 const uniform unsigned int height,
193                 const uniform int kernel_size,
194                 float x, float y, Vec3fa const& color)
195{
196  for (int dy = -kernel_size; dy <= kernel_size; ++dy)
197  for (int dx = -kernel_size; dx <= kernel_size; ++dx)
198  {
199    unsigned int r = (unsigned int)(255.0f * clamp(color.x, 0.0f, 1.0f));
200    unsigned int g = (unsigned int)(255.0f * clamp(color.y, 0.0f, 1.0f));
201    unsigned int b = (unsigned int)(255.0f * clamp(color.z, 0.0f, 1.0f));
202    const unsigned int px = (unsigned int)min(width  - 1.f, max(0.f, x * width  + dx));
203    const unsigned int py = (unsigned int)min(height - 1.f, max(0.f, y * height + dy));
204    pixels[py*width + px] = (b << 16) + (g << 8) + r;
205  }
206}
207
208
209task void drawPoints(uniform int* uniform pixels,
210                const uniform unsigned int width,
211                const uniform unsigned int height)
212{
213  Point p = g_points[taskIndex];
214  Vec3fa color = g_colors[taskIndex % g_num_colors] / 0.8f;
215  splat_color(pixels, width, height, 2, p.p.x, p.p.z, color);
216}
217
218export void renderFrameStandard (uniform int* uniform pixels,
219                          const uniform unsigned int width,
220                          const uniform unsigned int height,
221                          const uniform float time,
222                          const uniform ISPCCamera& camera)
223{
224  /* render all pixels */
225  const uniform int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X;
226  const uniform int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y;
227  launch[numTilesX*numTilesY] renderTileTask(pixels,width,height,time,camera,numTilesX,numTilesY); sync;
228
229  launch[g_num_points] drawPoints(pixels, width, height); sync;
230}
231
232/* called by the C++ code to render */
233export void device_render (uniform int* uniform pixels,
234                           const uniform unsigned int width,
235                           const uniform unsigned int height,
236                           const uniform float time,
237                           const uniform ISPCCamera& camera)
238{
239  if (g_num_points != g_num_points_current)
240  {
241    rtcReleaseScene (g_scene);
242    g_scene = rtcNewScene(g_device);
243    delete[] g_points; g_points = NULL;
244    g_points = createPoints(g_scene, g_num_points);
245    rtcCommitScene(g_scene);
246  }
247}
248
249/* called by the C++ code for cleanup */
250export void device_cleanup ()
251{
252  rtcReleaseScene (g_scene); g_scene = NULL;
253  rtcReleaseDevice(g_device); g_device = NULL;
254  delete[] g_points; g_points = NULL;
255}
256