test_ssol_draw.c (13694B)
1 /* Copyright (C) 2018-2026 |Meso|Star> (contact@meso-star.com) 2 * Copyright (C) 2016, 2018 CNRS 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #include "ssol.h" 18 #include "test_ssol_utils.h" 19 #include "test_ssol_geometries.h" 20 #include "test_ssol_materials.h" 21 22 #include <rsys/double3.h> 23 #include <rsys/float3.h> 24 #include <rsys/image.h> 25 #include <rsys/math.h> 26 27 #include <string.h> 28 29 #define WIDTH 256 30 #define HEIGHT 256 31 #define PITCH (WIDTH*sizeof(unsigned char[3])) 32 #define PROJ_RATIO ((double)WIDTH/(double)HEIGHT) 33 34 static void 35 get_wlen(const size_t i, double* wlen, double* data, void* ctx) 36 { 37 double wavelengths[3] = { 1, 2, 3 }; 38 double intensities[3] = { 1, 0.8, 1 }; 39 CHK(i < 3); 40 (void)ctx; 41 *wlen = wavelengths[i]; 42 *data = intensities[i]; 43 } 44 45 static res_T 46 write_RGB8 47 (void* data, 48 const size_t org[2], 49 const size_t sz[2], 50 const enum ssol_pixel_format fmt, 51 const void* pixels) 52 { 53 unsigned char* img = data; 54 const char* src_pixels = pixels; 55 size_t src_pitch = ssol_sizeof_pixel_format(fmt) * sz[0]; 56 size_t x, y; 57 58 CHK(org[0] + sz[0] <= WIDTH); 59 CHK(org[1] + sz[1] <= HEIGHT); 60 61 FOR_EACH(y, 0, sz[1]) { 62 unsigned char* row_dst = img + (y + org[1]) * PITCH; 63 const char* row_src = src_pixels + y * src_pitch; 64 FOR_EACH(x, 0, sz[0]) { 65 unsigned char* dst = row_dst + (x + org[0])*3/*#channels*/; 66 const char* src = row_src + x*ssol_sizeof_pixel_format(fmt); 67 68 switch(fmt) { 69 case SSOL_PIXEL_DOUBLE3: 70 dst[0] = (unsigned char)(255.0 * ((const double*)src)[0]); 71 dst[1] = (unsigned char)(255.0 * ((const double*)src)[1]); 72 dst[2] = (unsigned char)(255.0 * ((const double*)src)[2]); 73 break; 74 default: FATAL("Unreachable code.\n"); break; 75 } 76 } 77 } 78 return RES_OK; 79 } 80 81 static void 82 setup_cornell_box(struct ssol_device* dev, struct ssol_scene* scn) 83 { 84 const float walls[] = { 85 552.f, 0.f, 0.f, 86 0.f, 0.f, 0.f, 87 0.f, 559.f, 0.f, 88 552.f, 559.f, 0.f, 89 552.f, 0.f, 548.f, 90 0.f, 0.f, 548.f, 91 0.f, 559.f, 548.f, 92 552.f, 559.f, 548.f 93 }; 94 const float tall_block[] = { 95 423.f, 247.f, 0.f, 96 265.f, 296.f, 0.f, 97 314.f, 456.f, 0.f, 98 472.f, 406.f, 0.f, 99 423.f, 247.f, 330.f, 100 265.f, 296.f, 330.f, 101 314.f, 456.f, 330.f, 102 472.f, 406.f, 330.f 103 }; 104 const float short_block[] = { 105 130.f, 65.f, 0.f, 106 82.f, 225.f, 0.f, 107 240.f, 272.f, 0.f, 108 290.f, 114.f, 0.f, 109 130.f, 65.f, 165.f, 110 82.f, 225.f, 165.f, 111 240.f, 272.f, 165.f, 112 290.f, 114.f, 165.f 113 }; 114 const unsigned block_ids[] = { 115 4, 5, 6, 6, 7, 4, 116 1, 2, 6, 6, 5, 1, 117 0, 3, 7, 7, 4, 0, 118 2, 3, 7, 7, 6, 2, 119 0, 1, 5, 5, 4, 0 120 }; 121 const unsigned walls_ids[] = { 122 0, 1, 2, 2, 3, 0, 123 4, 5, 6, 6, 7, 4, 124 1, 2, 6, 6, 5, 1, 125 0, 3, 7, 7, 4, 0, 126 2, 3, 7, 7, 6, 2 127 }; 128 struct ssol_shape* shape; 129 struct ssol_object* obj; 130 struct ssol_instance* inst; 131 struct ssol_material* mtl; 132 struct ssol_matte_shader shader = SSOL_MATTE_SHADER_NULL; 133 struct ssol_vertex_data vdata; 134 struct desc desc; 135 float lower[3], upper[3]; 136 float tmp[3]; 137 138 shader.normal = get_shader_normal; 139 shader.reflectivity = get_shader_reflectivity; 140 CHK(ssol_material_create_matte(dev, &mtl) == RES_OK); 141 CHK(ssol_matte_setup(mtl, &shader) == RES_OK); 142 143 vdata.usage = SSOL_POSITION; 144 vdata.get = get_position; 145 146 desc.vertices = walls; 147 desc.indices = walls_ids; 148 149 CHK(ssol_shape_create_mesh(dev, &shape) == RES_OK); 150 CHK(ssol_mesh_setup(shape, 10, get_ids, 8, &vdata, 1, &desc) == RES_OK); 151 CHK(ssol_object_create(dev, &obj) == RES_OK); 152 CHK(ssol_object_add_shaded_shape(obj, shape, mtl, mtl) == RES_OK); 153 CHK(ssol_object_instantiate(obj, &inst) == RES_OK); 154 CHK(ssol_scene_attach_instance(scn, inst) == RES_OK); 155 CHK(ssol_instance_ref_put(inst) == RES_OK); 156 CHK(ssol_shape_ref_put(shape) == RES_OK); 157 CHK(ssol_object_ref_put(obj) == RES_OK); 158 159 desc.vertices = short_block; 160 desc.indices = block_ids; 161 CHK(ssol_shape_create_mesh(dev, &shape) == RES_OK); 162 CHK(ssol_mesh_setup(shape, 10, get_ids, 8, &vdata, 1, &desc) == RES_OK); 163 CHK(ssol_object_create(dev, &obj) == RES_OK); 164 CHK(ssol_object_add_shaded_shape(obj, shape, mtl, mtl) == RES_OK); 165 CHK(ssol_object_instantiate(obj, &inst) == RES_OK); 166 CHK(ssol_scene_attach_instance(scn, inst) == RES_OK); 167 CHK(ssol_instance_ref_put(inst) == RES_OK); 168 CHK(ssol_shape_ref_put(shape) == RES_OK); 169 CHK(ssol_object_ref_put(obj) == RES_OK); 170 171 desc.vertices = tall_block; 172 desc.indices = block_ids; 173 CHK(ssol_shape_create_mesh(dev, &shape) == RES_OK); 174 CHK(ssol_mesh_setup(shape, 10, get_ids, 8, &vdata, 1, &desc) == RES_OK); 175 CHK(ssol_object_create(dev, &obj) == RES_OK); 176 CHK(ssol_object_add_shaded_shape(obj, shape, mtl, mtl) == RES_OK); 177 CHK(ssol_object_instantiate(obj, &inst) == RES_OK); 178 CHK(ssol_scene_attach_instance(scn, inst) == RES_OK); 179 CHK(ssol_instance_ref_put(inst) == RES_OK); 180 CHK(ssol_shape_ref_put(shape) == RES_OK); 181 CHK(ssol_object_ref_put(obj) == RES_OK); 182 183 CHK(ssol_material_ref_put(mtl) == RES_OK); 184 185 CHK(ssol_scene_compute_aabb(scn, lower, upper) == RES_OK); 186 CHK(f3_eq_eps(lower, f3(tmp, 0, 0, 0), 1.e-6f) == 1); 187 CHK(f3_eq_eps(upper, f3(tmp, 552.f, 559.f, 548.f), 1.e-6f) == 1); 188 } 189 190 191 /* Wrap the ssol_draw_pt function to match the ssol_draw_draft profile */ 192 static INLINE res_T 193 draw_pt 194 (struct ssol_scene* scn, 195 struct ssol_camera* cam, 196 const size_t width, 197 const size_t height, 198 const size_t spp, 199 ssol_write_pixels_T writer, 200 void* data) 201 { 202 const double up[3] = {0, 0, 1}; 203 return ssol_draw_pt(scn, cam, width, height, spp, up, writer, data); 204 } 205 206 int 207 main(int argc, char** argv) 208 { 209 struct mem_allocator allocator; 210 struct ssol_device* dev; 211 struct ssol_camera* cam; 212 struct ssol_scene* scn; 213 struct ssol_spectrum* spectrum; 214 struct ssol_sun* sun; 215 struct image img; 216 uint8_t* pixels; 217 const double pos[3] = {278.0, -1000.0, 273.0}; 218 const double tgt[3] = {278.0, 0.0, 273.0}; 219 const double up[3] = {0.0, 0.0, 1.0}; 220 double dir[3]; 221 size_t pitch; 222 res_T (*draw_func) 223 (struct ssol_scene* scn, 224 struct ssol_camera* cam, 225 const size_t width, 226 const size_t height, 227 const size_t spp, 228 ssol_write_pixels_T writer, 229 void* data); 230 (void)argc, (void)argv; 231 232 if(argc <= 1) { 233 fprintf(stderr, "Usage: %s <draft|pt>\n", argv[0]); 234 return -1; 235 } 236 237 if(!strcmp(argv[1], "draft")) { 238 draw_func = ssol_draw_draft; 239 } else if(!strcmp(argv[1], "pt")) { 240 draw_func = draw_pt; 241 } else { 242 fprintf(stderr, "Usage: %s <draft|pt>\n", argv[0]); 243 return -1; 244 } 245 246 CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); 247 248 CHK(ssol_device_create 249 (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev) == RES_OK); 250 251 CHK(ssol_scene_create(dev, &scn) == RES_OK); 252 253 setup_cornell_box(dev, scn); 254 255 CHK(ssol_camera_create(dev, &cam) == RES_OK); 256 CHK(ssol_camera_set_proj_ratio(cam, PROJ_RATIO) == RES_OK); 257 CHK(ssol_camera_set_fov(cam, PI/4.0) == RES_OK); 258 CHK(ssol_camera_look_at(cam, pos, tgt, up) == RES_OK); 259 260 d3(dir, 1, 1, -1); 261 d3_normalize(dir, dir); 262 CHK(ssol_sun_create_directional(dev, &sun) == RES_OK); 263 CHK(ssol_sun_set_direction(sun, dir) == RES_OK); 264 CHK(ssol_sun_set_dni(sun, 1000) == RES_OK); 265 CHK(ssol_scene_attach_sun(scn, sun) == RES_OK); 266 267 pitch = WIDTH * sizeof_image_format(IMAGE_RGB8); 268 image_init(&allocator, &img); 269 image_setup(&img, WIDTH, HEIGHT, pitch, IMAGE_RGB8, NULL); 270 pixels = (uint8_t*)img.pixels; 271 272 CHK(draw_func(NULL, NULL, 0, 0, 0, NULL, pixels) == RES_BAD_ARG); 273 CHK(draw_func(scn, NULL, 0, 0, 0, NULL, pixels) == RES_BAD_ARG); 274 CHK(draw_func(NULL, cam, 0, 0, 0, NULL, pixels) == RES_BAD_ARG); 275 CHK(draw_func(scn, cam, 0, 0, 0, NULL, pixels) == RES_BAD_ARG); 276 CHK(draw_func(NULL, NULL, WIDTH, 0, 0, NULL, pixels) == RES_BAD_ARG); 277 CHK(draw_func(scn, NULL, WIDTH, 0, 0, NULL, pixels) == RES_BAD_ARG); 278 CHK(draw_func(NULL, cam, WIDTH, 0, 0, NULL, pixels) == RES_BAD_ARG); 279 CHK(draw_func(scn, cam, WIDTH, 0, 0, NULL, pixels) == RES_BAD_ARG); 280 CHK(draw_func(NULL, NULL, 0, HEIGHT, 0, NULL, pixels) == RES_BAD_ARG); 281 CHK(draw_func(scn, NULL, 0, HEIGHT, 0, NULL, pixels) == RES_BAD_ARG); 282 CHK(draw_func(NULL, cam, 0, HEIGHT, 0, NULL, pixels) == RES_BAD_ARG); 283 CHK(draw_func(scn, cam, 0, HEIGHT, 0, NULL, pixels) == RES_BAD_ARG); 284 CHK(draw_func(NULL, NULL, WIDTH, HEIGHT, 0, NULL, pixels) == RES_BAD_ARG); 285 CHK(draw_func(scn, NULL, WIDTH, HEIGHT, 0, NULL, pixels) == RES_BAD_ARG); 286 CHK(draw_func(NULL, cam, WIDTH, WIDTH, 0, NULL, pixels) == RES_BAD_ARG); 287 CHK(draw_func(scn, cam, WIDTH, HEIGHT, 0, NULL, pixels) == RES_BAD_ARG); 288 CHK(draw_func(NULL, NULL, 0, 0, 0, write_RGB8, pixels) == RES_BAD_ARG); 289 CHK(draw_func(scn, NULL, 0, 0, 0, write_RGB8, pixels) == RES_BAD_ARG); 290 CHK(draw_func(NULL, cam, 0, 0, 0, write_RGB8, pixels) == RES_BAD_ARG); 291 CHK(draw_func(scn, cam, 0, 0, 0, write_RGB8, pixels) == RES_BAD_ARG); 292 CHK(draw_func(NULL, NULL, WIDTH, 0, 0, write_RGB8, pixels) == RES_BAD_ARG); 293 CHK(draw_func(scn, NULL, WIDTH, 0, 0, write_RGB8, pixels) == RES_BAD_ARG); 294 CHK(draw_func(NULL, cam, WIDTH, 0, 0, write_RGB8, pixels) == RES_BAD_ARG); 295 CHK(draw_func(scn, cam, WIDTH, 0, 0, write_RGB8, pixels) == RES_BAD_ARG); 296 CHK(draw_func(NULL, NULL, 0, HEIGHT, 0, write_RGB8, pixels) == RES_BAD_ARG); 297 CHK(draw_func(scn, NULL, 0, HEIGHT, 0, write_RGB8, pixels) == RES_BAD_ARG); 298 CHK(draw_func(NULL, cam, 0, HEIGHT, 0, write_RGB8, pixels) == RES_BAD_ARG); 299 CHK(draw_func(scn, cam, 0, HEIGHT, 0, write_RGB8, pixels) == RES_BAD_ARG); 300 CHK(draw_func(NULL, NULL, WIDTH, HEIGHT, 0, write_RGB8, pixels) == RES_BAD_ARG); 301 CHK(draw_func(scn, NULL, WIDTH, HEIGHT, 0, write_RGB8, pixels) == RES_BAD_ARG); 302 CHK(draw_func(NULL, cam, WIDTH, WIDTH, 0, write_RGB8, pixels) == RES_BAD_ARG); 303 CHK(draw_func(scn, cam, WIDTH, HEIGHT, 0, write_RGB8, pixels) == RES_BAD_ARG); 304 CHK(draw_func(NULL, NULL, 0, 0, 4, NULL, pixels) == RES_BAD_ARG); 305 CHK(draw_func(scn, NULL, 0, 0, 4, NULL, pixels) == RES_BAD_ARG); 306 CHK(draw_func(NULL, cam, 0, 0, 4, NULL, pixels) == RES_BAD_ARG); 307 CHK(draw_func(scn, cam, 0, 0, 4, NULL, pixels) == RES_BAD_ARG); 308 CHK(draw_func(NULL, NULL, WIDTH, 0, 4, NULL, pixels) == RES_BAD_ARG); 309 CHK(draw_func(scn, NULL, WIDTH, 0, 4, NULL, pixels) == RES_BAD_ARG); 310 CHK(draw_func(NULL, cam, WIDTH, 0, 4, NULL, pixels) == RES_BAD_ARG); 311 CHK(draw_func(scn, cam, WIDTH, 0, 4, NULL, pixels) == RES_BAD_ARG); 312 CHK(draw_func(NULL, NULL, 0, HEIGHT, 4, NULL, pixels) == RES_BAD_ARG); 313 CHK(draw_func(scn, NULL, 0, HEIGHT, 4, NULL, pixels) == RES_BAD_ARG); 314 CHK(draw_func(NULL, cam, 0, HEIGHT, 4, NULL, pixels) == RES_BAD_ARG); 315 CHK(draw_func(scn, cam, 0, HEIGHT, 4, NULL, pixels) == RES_BAD_ARG); 316 CHK(draw_func(NULL, NULL, WIDTH, HEIGHT, 4, NULL, pixels) == RES_BAD_ARG); 317 CHK(draw_func(scn, NULL, WIDTH, HEIGHT, 4, NULL, pixels) == RES_BAD_ARG); 318 CHK(draw_func(NULL, cam, WIDTH, WIDTH, 4, NULL, pixels) == RES_BAD_ARG); 319 CHK(draw_func(scn, cam, WIDTH, HEIGHT, 4, NULL, pixels) == RES_BAD_ARG); 320 CHK(draw_func(NULL, NULL, 0, 0, 4, write_RGB8, pixels) == RES_BAD_ARG); 321 CHK(draw_func(scn, NULL, 0, 0, 4, write_RGB8, pixels) == RES_BAD_ARG); 322 CHK(draw_func(NULL, cam, 0, 0, 4, write_RGB8, pixels) == RES_BAD_ARG); 323 CHK(draw_func(scn, cam, 0, 0, 4, write_RGB8, pixels) == RES_BAD_ARG); 324 CHK(draw_func(NULL, NULL, WIDTH, 0, 4, write_RGB8, pixels) == RES_BAD_ARG); 325 CHK(draw_func(scn, NULL, WIDTH, 0, 4, write_RGB8, pixels) == RES_BAD_ARG); 326 CHK(draw_func(NULL, cam, WIDTH, 0, 4, write_RGB8, pixels) == RES_BAD_ARG); 327 CHK(draw_func(scn, cam, WIDTH, 0, 4, write_RGB8, pixels) == RES_BAD_ARG); 328 CHK(draw_func(NULL, NULL, 0, HEIGHT, 4, write_RGB8, pixels) == RES_BAD_ARG); 329 CHK(draw_func(scn, NULL, 0, HEIGHT, 4, write_RGB8, pixels) == RES_BAD_ARG); 330 CHK(draw_func(NULL, cam, 0, HEIGHT, 4, write_RGB8, pixels) == RES_BAD_ARG); 331 CHK(draw_func(scn, cam, 0, HEIGHT, 4, write_RGB8, pixels) == RES_BAD_ARG); 332 CHK(draw_func(NULL, NULL, WIDTH, HEIGHT, 4, write_RGB8, pixels) == RES_BAD_ARG); 333 CHK(draw_func(scn, NULL, WIDTH, HEIGHT, 4, write_RGB8, pixels) == RES_BAD_ARG); 334 CHK(draw_func(NULL, cam, WIDTH, WIDTH, 4, write_RGB8, pixels) == RES_BAD_ARG); 335 336 /* No sun spectrum */ 337 CHK(draw_func(scn, cam, WIDTH, HEIGHT, 4, write_RGB8, pixels) == RES_BAD_ARG); 338 339 CHK(ssol_spectrum_create(dev, &spectrum) == RES_OK); 340 CHK(ssol_spectrum_setup(spectrum, get_wlen, 3, NULL) == RES_OK); 341 CHK(ssol_sun_set_spectrum(sun, spectrum) == RES_OK); 342 CHK(draw_func(scn, cam, WIDTH, HEIGHT, 4, write_RGB8, pixels) == RES_OK); 343 344 CHK(image_write_ppm_stream(&img, 0, stdout) == RES_OK); 345 346 if(draw_func == draw_pt) { 347 CHK(ssol_draw_pt 348 (scn, cam, WIDTH, HEIGHT, 4, NULL, write_RGB8, pixels) == RES_BAD_ARG); 349 } 350 351 CHK(image_release(&img) == RES_OK); 352 CHK(ssol_device_ref_put(dev) == RES_OK); 353 CHK(ssol_camera_ref_put(cam) == RES_OK); 354 CHK(ssol_scene_ref_put(scn) == RES_OK); 355 CHK(ssol_spectrum_ref_put(spectrum) == RES_OK); 356 CHK(ssol_sun_ref_put(sun) == RES_OK); 357 358 check_memory_allocator(&allocator); 359 mem_shutdown_proxy_allocator(&allocator); 360 CHK(mem_allocated_size() == 0); 361 return 0; 362 } 363