test_scam_cbox.c (6875B)
1 /* Copyright (C) 2021-2023 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "scam.h" 17 #include "test_scam_cbox.h" 18 #include "test_scam_utils.h" 19 20 #include <star/s3d.h> 21 22 #include <rsys/double3.h> 23 #include <rsys/float2.h> 24 #include <rsys/float3.h> 25 #include <rsys/image.h> 26 #include <rsys/mem_allocator.h> 27 28 #include <string.h> 29 30 #define IMG_WIDTH 640 31 #define IMG_HEIGHT 480 32 #define IMG_SPP 16 33 34 enum lens_model { 35 PINHOLE, 36 THIN_LENS 37 }; 38 39 enum camera_model { 40 ORTHOGRAPHIC, 41 PERSPECTIVE 42 }; 43 44 static struct s3d_scene_view* 45 create_s3d_scene_view(void) 46 { 47 struct s3d_vertex_data vdata; 48 struct s3d_device* s3d = NULL; 49 struct s3d_scene* scn = NULL; 50 struct s3d_shape* shape = NULL; 51 struct s3d_scene_view* view = NULL; 52 53 CHK(s3d_device_create(NULL, NULL, 0, &s3d) == RES_OK); 54 55 vdata.usage = S3D_POSITION; 56 vdata.type = S3D_FLOAT3; 57 vdata.get = cbox_get_vtx; 58 CHK(s3d_shape_create_mesh(s3d, &shape) == RES_OK); 59 CHK(s3d_mesh_setup_indexed_vertices(shape, cbox_ntris, cbox_get_tri, 60 cbox_nvtxs, &vdata, 1, NULL) == RES_OK); 61 62 CHK(s3d_scene_create(s3d, &scn) == RES_OK); 63 CHK(s3d_scene_attach_shape(scn, shape) == RES_OK); 64 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); 65 66 CHK(s3d_device_ref_put(s3d) == RES_OK); 67 CHK(s3d_shape_ref_put(shape) == RES_OK); 68 CHK(s3d_scene_ref_put(scn) == RES_OK); 69 70 return view; 71 } 72 73 static void 74 create_perspective(const enum lens_model lens_model, struct scam** cam) 75 { 76 struct scam_perspective_args args = SCAM_PERSPECTIVE_ARGS_DEFAULT; 77 CHK(cam); 78 79 args.position[0] = 89.66; 80 args.position[1] = 21.89; 81 args.position[2] = 202.22; 82 args.target[0] = 150.03; 83 args.target[1] = 135; 84 args.target[2] = 196.87; 85 args.up[0] = 0; 86 args.up[1] = 0; 87 args.up[2] = 1; 88 args.field_of_view = 1.22173047639603070383; /* ~70 degrees */ 89 args.aspect_ratio = (double)IMG_WIDTH/(double)IMG_HEIGHT; 90 91 switch(lens_model) { 92 case PINHOLE: 93 args.lens_radius = 0; 94 break; 95 case THIN_LENS: 96 args.lens_radius = 5; 97 args.focal_distance = 300; 98 break; 99 default: FATAL("Unreachable code.\n"); break; 100 } 101 102 CHK(scam_create_perspective(NULL, NULL, 1, &args, cam) == RES_OK); 103 } 104 105 static void 106 create_orthographic(const enum lens_model lens_model, struct scam** cam) 107 { 108 struct scam_orthographic_args args = SCAM_ORTHOGRAPHIC_ARGS_DEFAULT; 109 CHK(cam); 110 111 args.position[0] = 89.66; 112 args.position[1] = 21.89; 113 args.position[2] = 202.22; 114 args.target[0] = 150.03; 115 args.target[1] = 135; 116 args.target[2] = 196.87; 117 args.up[0] = 0; 118 args.up[1] = 0; 119 args.up[2] = 1; 120 args.height = 500; 121 args.aspect_ratio = (double)IMG_WIDTH/(double)IMG_HEIGHT; 122 123 /* No thin-lens model for orthographic projection */ 124 CHK(lens_model == PINHOLE); 125 126 CHK(scam_create_orthographic(NULL, NULL, 1, &args, cam) == RES_OK); 127 } 128 129 130 static void 131 draw 132 (const struct scam* cam, 133 struct s3d_scene_view* view, 134 struct image* img) 135 { 136 int x, y, s; 137 double pixsz[2]; 138 CHK(img); 139 140 pixsz[0] = 1.0 / (double)IMG_WIDTH; 141 pixsz[1] = 1.0 / (double)IMG_HEIGHT; 142 143 FOR_EACH(y, 0, IMG_HEIGHT) { 144 FOR_EACH(x, 0, IMG_WIDTH) { 145 double sum[3] = {0,0,0}; 146 double E[3] = {0,0,0}; 147 int ipix; 148 149 FOR_EACH(s, 0, IMG_SPP) { 150 struct s3d_hit hit = S3D_HIT_NULL; 151 struct scam_sample sample = SCAM_SAMPLE_NULL; 152 struct scam_ray ray = SCAM_RAY_NULL; 153 double col[3]; 154 float org[3]; 155 float dir[3]; 156 float range[2]; 157 float N[3]; 158 float cos_N_dir; 159 160 /* Generate the camera ray */ 161 sample.film[0] = ((double)x + rand_canonical()) * pixsz[0]; 162 sample.film[1] = ((double)y + rand_canonical()) * pixsz[1]; 163 sample.lens[0] = rand_canonical(); 164 sample.lens[1] = rand_canonical(); 165 CHK(scam_generate_ray(cam, &sample, &ray) == RES_OK); 166 167 /* Trace the ray */ 168 f3_set_d3(org, ray.org); 169 f3_normalize(dir, f3_set_d3(dir, ray.dir)); 170 f2(range, 0, (float)INF); 171 CHK(s3d_scene_view_trace_ray(view, org, dir, range, NULL, &hit) == RES_OK); 172 173 if(S3D_HIT_NONE(&hit)) continue; 174 175 /* Shade */ 176 cbox_get_col(hit.prim.prim_id, col); 177 f3_normalize(N, hit.normal); 178 cos_N_dir = absf(f3_dot(N, dir)); 179 180 sum[0] += (float)(cos_N_dir * col[0]); 181 sum[1] += (float)(cos_N_dir * col[1]); 182 sum[2] += (float)(cos_N_dir * col[2]); 183 } 184 /* Compute pixel color */ 185 E[0] = sum[0] / (double)IMG_SPP; 186 E[1] = sum[1] / (double)IMG_SPP; 187 E[2] = sum[2] / (double)IMG_SPP; 188 189 /* Write pixel color */ 190 ipix = (y*IMG_WIDTH + x) * 3/*RGB*/; 191 ((uint8_t*)img->pixels)[ipix+0] = (uint8_t)(E[0] * 255); 192 ((uint8_t*)img->pixels)[ipix+1] = (uint8_t)(E[1] * 255); 193 ((uint8_t*)img->pixels)[ipix+2] = (uint8_t)(E[2] * 255); 194 } 195 } 196 } 197 198 int 199 main(int argc, char** argv) 200 { 201 struct s3d_scene_view* view = NULL; 202 struct scam* cam = NULL; 203 struct image img; 204 enum camera_model cam_model; 205 enum lens_model lens_model; 206 int err = 0; 207 208 if(argc <= 2) { 209 fprintf(stderr, 210 "Usage: %s <orthographic|perspective> <pinhole|thin-lens>\n", 211 argv[0]); 212 goto error; 213 } 214 215 if(!strcmp(argv[1], "orthographic")) { 216 cam_model = ORTHOGRAPHIC; 217 } else if(!strcmp(argv[1], "perspective")) { 218 cam_model = PERSPECTIVE; 219 } else { 220 fprintf(stderr, "Invalid camera model `%s'.\n", argv[1]); 221 goto error; 222 } 223 224 if(!strcmp(argv[2], "pinhole")){ 225 lens_model = PINHOLE; 226 } else if(!strcmp(argv[2], "thin-lens")) { 227 lens_model = THIN_LENS; 228 } else { 229 fprintf(stderr, "Invalid lens model `%s'.\n", argv[2]); 230 goto error; 231 } 232 233 view = create_s3d_scene_view(); 234 235 switch(cam_model) { 236 case ORTHOGRAPHIC: create_orthographic(lens_model, &cam); break; 237 case PERSPECTIVE: create_perspective(lens_model, &cam); break; 238 default: FATAL("Unreachable code.\n"); break; 239 } 240 241 image_init(NULL, &img); 242 CHK(image_setup 243 (&img, IMG_WIDTH, IMG_HEIGHT, IMG_WIDTH*3, IMAGE_RGB8, NULL) == RES_OK); 244 245 draw(cam, view, &img); 246 247 CHK(image_write_ppm_stream(&img, 0, stdout) == RES_OK); 248 249 CHK(s3d_scene_view_ref_put(view) == RES_OK); 250 CHK(scam_ref_put(cam) == RES_OK); 251 image_release(&img); 252 253 exit: 254 CHK(mem_allocated_size() == 0); 255 return err; 256 error: 257 err = 1; 258 goto exit; 259 }