Add scene file parsing

This commit is contained in:
2024-10-09 14:56:07 +02:00
parent 2f62b9f345
commit 6cee9c77a7
5 changed files with 581 additions and 298 deletions
+89
View File
@@ -0,0 +1,89 @@
cube
emission_color {0 0 0}
emission_power 0
metallic 1
reflectance 0
roughness 1
albedo {1 0.3 0.3}
origin {0 0 0}
size {3 5 0.1}
cube
emission_color {0 0 0}
emission_power 0
metallic 1
reflectance 0
roughness 0.5
albedo {1 0.3 0.3}
origin {3 0 0}
size {3 5 0.1}
cube
emission_color {0 0 0}
emission_power 0
metallic 1
reflectance 0
roughness 0
albedo {1 0.3 0.3}
origin {6 0 0}
size {3 5 0.1}
cube
emission_color {0 0 0}
emission_power 0
metallic 0
reflectance 0
roughness 1
albedo {0.4 0.3 0.9}
origin {0 -0.1 0}
size {9 0.1 9}
cube
emission_color {0 0 0}
emission_power 0
metallic 0
reflectance 0
roughness 1
albedo {1 0 0}
origin {5 0 6}
size {1 1 1}
cube
emission_color {0 0 0}
emission_power 0
metallic 0
reflectance 1
roughness 0
albedo {1 0 1}
origin {4 0 5}
size {1 1 1}
sphere
emission_color {0 0 0}
emission_power 0
metallic 0
reflectance 0
roughness 1
albedo {1 0.4 0}
center {3 1 3}
radius 1
sphere
emission_color {0 0 0}
emission_power 0
metallic 0
reflectance 1
roughness 0
albedo {0 1 0}
center {5 1 3}
radius 1
sphere
emission_color {1 1 1}
emission_power 5
metallic 0
reflectance 0
roughness 1
albedo {1 0.4 0}
center {3 5 3}
radius 1
+69
View File
@@ -0,0 +1,69 @@
cube
emission_color {0 0 0}
emission_power 0
roughness 1
metallic 0
reflectance 0
albedo {1 0.3 0.3}
origin {0 0 0}
size {3 0.1 3}
cube
emission_color {0 0 0}
emission_power 0
roughness 1
metallic 0
reflectance 0
albedo {0.3 1 0.3}
origin {0 5 0}
size {3 0.1 3}
cube
emission_color {0 0 0}
emission_power 0
metallic 1
reflectance 1
roughness 0
albedo {0.3 0.3 1}
origin {0 0 0}
size {0.1 5 3}
cube
emission_color {0 0 0}
emission_power 0
metallic 1
reflectance 1
roughness 0
albedo {0.3 1 1}
origin {3 0 0}
size {0.1 5 3}
cube
emission_color {0 0 0}
emission_power 0
metallic 0
reflectance 1
roughness 1
albedo {1 0.3 1}
origin {0 0 0}
size {3 5 0.1}
cube
emission_color {1 1 1}
emission_power 1
metallic 0
reflectance 1
roughness 0
albedo {1 1 0.3}
origin {1 4.9 1}
size {1 0.1 1}
sphere
emission_color {0 0 0}
emission_power 0
metallic 1
reflectance 1
roughness 0
albedo {0 1 0}
center {1.5 1 1.5}
radius 1
+29
View File
@@ -0,0 +1,29 @@
sphere
emission_color {0 0 0}
emission_power 0
metallic 0
reflectance 1
roughness 0
albedo {0.2 0.5 1}
center {-3 0 0}
radius 1
sphere
emission_color {0 0 0}
emission_power 0
metallic 0
reflectance 0
roughness 0
albedo {0.2 0.5 1}
center {0 0 0}
radius 1
sphere
emission_color {0 0 0}
emission_power 0
metallic 1
reflectance 0
roughness 0
albedo {0.5 0.2 1}
center {3 0 0}
radius 1
+358 -266
View File
@@ -520,14 +520,12 @@ Vector3 reflect(Vector3 dir, Vector3 normal)
}
#define MAX_OBJECTS 1024
Object objects[MAX_OBJECTS];
int num_objects = 0;
typedef struct {
Object objects[MAX_OBJECTS];
int num_objects;
} Scene;
void add_object(Object o)
{
if (num_objects < MAX_OBJECTS)
objects[num_objects++] = o;
}
Scene scene;
typedef struct {
float distance;
@@ -543,10 +541,10 @@ HitInfo trace_ray(Ray ray)
float nearest_t = FLT_MAX;
int nearest_object = -1;
Vector3 nearest_normal;
for (int i = 0; i < num_objects; i++) {
for (int i = 0; i < scene.num_objects; i++) {
float t;
Vector3 n;
if (!intersect_object(ray, objects[i], &t, &n))
if (!intersect_object(ray, scene.objects[i], &t, &n))
continue;
if (t >= 0 && t < nearest_t) {
nearest_t = t;
@@ -611,8 +609,8 @@ Vector3 pixel(float x, float y, float aspect_ratio)
// Choose a light source
int light_index = -1;
for (int i = 0; i < num_objects; i++) {
if (objects[i].material.emission_power > 0) {
for (int i = 0; i < scene.num_objects; i++) {
if (scene.objects[i].material.emission_power > 0) {
light_index = i;
break;
}
@@ -621,7 +619,7 @@ Vector3 pixel(float x, float y, float aspect_ratio)
Vector3 contrib = {1, 1, 1};
Vector3 result = {0, 0, 0};
int bounces = 2;
int bounces = 10;
for (int i = 0; i < bounces; i++) {
HitInfo hit = trace_ray(in_ray);
@@ -636,7 +634,7 @@ Vector3 pixel(float x, float y, float aspect_ratio)
Vector3 sampled_light_color = {0, 0, 0};
if (light_index != -1) {
Vector3 dir_to_light_source = combine(origin_of(objects[light_index]), hit.point, 1, -1);
Vector3 dir_to_light_source = combine(origin_of(scene.objects[light_index]), hit.point, 1, -1);
int max_samples = 3;
int num_samples = 0;
float spread = 0.5;
@@ -648,7 +646,7 @@ Vector3 pixel(float x, float y, float aspect_ratio)
Ray sample_ray = { combine(hit.point, sample_dir, 1, 0.001), sample_dir };
HitInfo hit2 = trace_ray(sample_ray);
if (hit2.object != -1)
sampled_light_color = combine(sampled_light_color, objects[hit2.object].material.emission_color, 1, objects[hit2.object].material.emission_power);
sampled_light_color = combine(sampled_light_color, scene.objects[hit2.object].material.emission_color, 1, scene.objects[hit2.object].material.emission_power);
num_samples++;
}
}
@@ -656,7 +654,7 @@ Vector3 pixel(float x, float y, float aspect_ratio)
sampled_light_color = scale(sampled_light_color, 1.0f / num_samples);
}
Material material = objects[hit.object].material;
Material material = scene.objects[hit.object].material;
Vector3 v = scale(in_ray.direction, -1);
Vector3 n = hit.normal;
@@ -878,8 +876,11 @@ void update_frame_texture(void)
os_mutex_unlock(&frame_mutex);
}
bool parse_scene_file(char *file, Scene *scene);
int main(int argc, char **argv)
{
char *scene_file = NULL;
num_columns = -1;
init_scale = 8;
for (int i = 1; i < argc; i++) {
@@ -905,10 +906,21 @@ int main(int argc, char **argv)
fprintf(stderr, "Error: Invalid count for --threads\n");
return -1;
}
} else if (!strcmp(argv[i], "--scene")) {
i++;
if (i == argc) {
fprintf(stderr, "Error: --scene option is missing the file path\n");
return -1;
}
scene_file = argv[i];
} else {
fprintf(stderr, "Warning: Ignoring option %s\n", argv[i]);
}
}
if (scene_file == NULL) {
fprintf(stderr, "Error: No scene specified (you should use --scene <filename>)\n");
return -1;
}
if (num_columns < 0) {
fprintf(stderr, "Error: Missing --threads <N> option\n");
return -1;
@@ -916,243 +928,9 @@ int main(int argc, char **argv)
if (num_columns > MAX_COLUMNS)
num_columns = MAX_COLUMNS;
#if 0
if (!parse_scene_file(scene_file, &scene))
return -1;
add_object(sphere(
(Material) {
.emission_color={1, 1, 1},
.emission_power=1,
.metallic=0,
.reflectance=0,
.roughness=0,
.albedo=(Vector3) {0.2, 0.5, 1},
},
(Vector3) {0, 2, 0},
1)
);
add_object(sphere(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=0,
.reflectance=0,
.roughness=0,
.albedo=(Vector3) {0.2, 0.5, 1},
},
(Vector3) {0, 0, 3},
1)
);
add_object(sphere(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=1,
.reflectance=0,
.roughness=0,
.albedo=(Vector3) {0.5, 0.2, 1},
},
(Vector3) {3, 0, 0},
1)
);
#elif 0
add_object(sphere(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=0,
.reflectance=1,
.roughness=0,
.albedo=(Vector3) {0.2, 0.5, 1},
},
(Vector3) {-3, 0, 0},
1)
);
add_object(sphere(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=0,
.reflectance=0,
.roughness=0,
.albedo=(Vector3) {0.2, 0.5, 1},
},
(Vector3) {0, 0, 0},
1)
);
add_object(sphere(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=1,
.reflectance=0,
.roughness=0,
.albedo=(Vector3) {0.5, 0.2, 1},
},
(Vector3) {3, 0, 0},
1)
);
#elif 0
int num_spheres = 5;
for (int i = 0; i < num_spheres; i++) {
add_object(sphere(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=0,
.reflectance=0,
.roughness= (float) i / (num_spheres-1),
.albedo=(Vector3) {0.2, 0.5, 1},
},
(Vector3) {3 * i, 0, 0},
1)
);
add_object(sphere(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=1,
.reflectance=0,
.roughness= (float) i / (num_spheres-1),
.albedo=(Vector3) {0.2, 0.5, 1},
},
(Vector3) {3 * i, 3, 0},
1)
);
}
#elif 0
float box_d = 3;
float box_w = 3;
float box_h = 5;
float box_border = 0.1;
add_object(cube(
(Material) {
.emission_color={0},
.emission_power=0,
.roughness=1,
.metallic=0,
.reflectance=0,
.albedo=(Vector3) {1, 0.3, 0.3}
},
(Vector3) {0, 0, 0},
(Vector3) {box_w, box_border, box_d}
));
add_object(cube(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=0,
.reflectance=0,
.roughness=1,
.albedo=(Vector3) {0.3, 1, 0.3}
},
(Vector3) {0, box_h, 0},
(Vector3) {box_w, box_border, box_d}
));
add_object(cube(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=0,
.reflectance=0,
.roughness=1,
.albedo=(Vector3) {0.3, 0.3, 1}
},
(Vector3) {0, 0, 0},
(Vector3) {box_border, box_h, box_d}
));
add_object(cube(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=0,
.reflectance=0,
.roughness=1,
.albedo=(Vector3) {0.3, 1, 1}
},
(Vector3) {box_w, 0, 0},
(Vector3) {box_border, box_h, box_d}
));
add_object(cube(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=0,
.reflectance=0,
.roughness=0,
.albedo=(Vector3) {1, 0.3, 1}
},
(Vector3) {0, 0, 0},
(Vector3) {box_w, box_h, box_border}
));
add_object(cube(
(Material) {
.emission_color={1, 1, 1},
.emission_power=1,
.metallic=0,
.reflectance=0,
.roughness=0,
.albedo=(Vector3) {1, 1, 0.3}
},
(Vector3) {box_w/3, box_h-box_border, box_d/3},
(Vector3) {box_w/3, box_border, box_d/3}
));
add_object(sphere(
(Material) {
.emission_color={0},
.emission_power=0,
.metallic=1,
.reflectance=0,
.roughness=0.5,
.albedo=(Vector3) {0, 1, 0}
},
(Vector3) {box_w/2, box_w/3, box_d/2},
box_w/3
));
#elif 1
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=1, .reflectance=0, .roughness=1, .albedo=(Vector3) {1, 0.3, 0.3}}, (Vector3) {0, 0, 0}, (Vector3) {3, 5, 0.1}));
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=1, .reflectance=0, .roughness=0.5, .albedo=(Vector3) {1, 0.3, 0.3}}, (Vector3) {3, 0, 0}, (Vector3) {3, 5, 0.1}));
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=1, .reflectance=0, .roughness=0, .albedo=(Vector3) {1, 0.3, 0.3}}, (Vector3) {6, 0, 0}, (Vector3) {3, 5, 0.1}));
/*
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=1, .albedo=(Vector3) {0.3, 1, 0.3}}, (Vector3) {0, 0, 0}, (Vector3) {0.1, 5, 3}));
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=0.5, .albedo=(Vector3) {0.3, 1, 0.3}}, (Vector3) {0, 0, 3}, (Vector3) {0.1, 5, 3}));
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=0, .albedo=(Vector3) {0.3, 1, 0.3}}, (Vector3) {0, 0, 6}, (Vector3) {0.1, 5, 3}));
*/
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=1, .albedo=(Vector3) {0.4, 0.3, 0.9}}, (Vector3) {0, -0.1, 0}, (Vector3) {9, 0.1, 9}));
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=1, .albedo=(Vector3) {1, 0, 0}}, (Vector3) {5, 0, 6}, (Vector3) {1, 1, 1}));
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=1, .roughness=0, .albedo=(Vector3) {1, 0, 1}}, (Vector3) {4, 0, 5}, (Vector3) {1, 1, 1}));
add_object(sphere((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=1, .albedo=(Vector3) {1, 0.4, 0}}, (Vector3) {3, 1, 3}, 1));
add_object(sphere((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=1, .roughness=0, .albedo=(Vector3) {0, 1, 0}}, (Vector3) {5, 1, 3}, 1));
add_object(sphere((Material) {.emission_color={1, 0.5, 0.5}, .emission_power=5, .metallic=0, .reflectance=0, .roughness=1, .albedo=(Vector3) {1, 0.4, 0}}, (Vector3) {3, 5, 3}, 1));
#elif 0
// add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=0, .albedo=(Vector3) {1, 0.3, 0.3}}, (Vector3) {0, 0, 0}, (Vector3) {10, 5, 0.1}));
// add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=0.6, .albedo=(Vector3) {0.3, 1, 0.3}}, (Vector3) {0, 0, 0}, (Vector3) {0.1, 5, 10}));
add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=1, .albedo=(Vector3) {0.4, 0.3, 0.9}}, (Vector3) {0, -0.1, 0}, (Vector3) {10, 0.1, 10}));
// add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=1, .albedo=(Vector3) {1, 0, 0}}, (Vector3) {7, 0, 8}, (Vector3) {1, 1, 1}));
// add_object(cube ((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=0, .albedo=(Vector3) {1, 0, 1}}, (Vector3) {6, 0, 7}, (Vector3) {1, 1, 1}));
// add_object(sphere((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=0.5, .albedo=(Vector3) {1, 0.4, 0}}, (Vector3) {3, 1, 3}, 1));
// add_object(sphere((Material) {.emission_color={0}, .emission_power=0, .metallic=0, .reflectance=0, .roughness=0, .albedo=(Vector3) {0, 1, 0}}, (Vector3) {5, 1, 3}, 1));
add_object(sphere((Material) {.emission_color={1, 1, 1}, .emission_power=1, .metallic=0, .reflectance=0, .roughness=1, .albedo=(Vector3) {1, 0.4, 0}}, (Vector3) {3, 5, 3}, 1));
#endif
{
const char *faces[] = {
[CF_RIGHT] = "assets/skybox/right.jpg",
[CF_LEFT] = "assets/skybox/left.jpg",
@@ -1162,7 +940,6 @@ int main(int argc, char **argv)
[CF_BACK] = "assets/skybox/back.jpg",
};
load_cubemap(&skybox, faces);
}
glfwSetErrorCallback(error_callback);
@@ -1293,22 +1070,31 @@ int main(int argc, char **argv)
return 0;
}
#if 0
typedef struct {
Object objects[MAX_OBJECTS];
int num_objects;
} Scene;
typedef enum {
PROP_ALBEDO,
PROP_ROUGHNESS,
PROP_REFLECTANCE,
PROP_METALLIC,
PROP_EMISSION_POWER,
PROP_EMISSION_COLOR,
PROP_RADIUS,
PROP_CENTER,
PROP_ORIGIN,
PROP_SIZE,
} Property;
bool parse_scene_string(char *src, size_t len)
bool parse_scene_string(char *src, size_t len, Scene *scene)
{
scene->num_objects = 0;
int line = 1;
size_t i = 0;
for (;;) {
while (i < len && is_space(src[i]))
while (i < len && is_space(src[i])) {
if (src[i] == '\n') line++;
i++;
}
if (i == len)
break;
@@ -1348,17 +1134,31 @@ bool parse_scene_string(char *src, size_t len)
object.material.emission_color = (Vector3) {1, 1, 1};
i += 4;
} else {
fprintf(stderr, "Error: Invalid character\n");
fprintf(stderr, "Error: Invalid character (line %d)\n", line);
return false;
}
for (;;) {
// Skip spaces before property
while (i < len && is_space(src[i]))
while (i < len && is_space(src[i])) {
if (src[i] == '\n') line++;
i++;
}
int valuetype; // 0 for float, 1 for color (3 floats)
Property prop;
if (8 < len - i
if (6 < len - i
&& src[i+0] == 'a'
&& src[i+1] == 'l'
&& src[i+2] == 'b'
&& src[i+3] == 'e'
&& src[i+4] == 'd'
&& src[i+5] == 'o') {
valuetype = 1;
prop = PROP_ALBEDO;
i += 9;
} else if (8 < len - i
&& src[i+0] == 'r'
&& src[i+1] == 'o'
&& src[i+2] == 'u'
@@ -1368,6 +1168,7 @@ bool parse_scene_string(char *src, size_t len)
&& src[i+6] == 'e'
&& src[i+7] == 's'
&& src[i+8] == 's') {
valuetype = 0;
prop = PROP_ROUGHNESS;
i += 9;
} else if (10 < len - i
@@ -1382,8 +1183,21 @@ bool parse_scene_string(char *src, size_t len)
&& src[i+8] == 'n'
&& src[i+9] == 'c'
&& src[i+10] == 'e') {
valuetype = 0;
prop = PROP_REFLECTANCE;
i += 11;
} else if (7 < len - i
&& src[i+0] == 'm'
&& src[i+1] == 'e'
&& src[i+2] == 't'
&& src[i+3] == 'a'
&& src[i+4] == 'l'
&& src[i+5] == 'l'
&& src[i+6] == 'i'
&& src[i+7] == 'c') {
valuetype = 0;
prop = PROP_METALLIC;
i += 11;
} else if (13 < len - i
&& src[i+0] == 'e'
&& src[i+1] == 'm'
@@ -1399,14 +1213,292 @@ bool parse_scene_string(char *src, size_t len)
&& src[i+11] == 'w'
&& src[i+12] == 'e'
&& src[i+13] == 'r') {
valuetype = 0;
prop = PROP_EMISSION_POWER;
i += 14;
} else if (13 < len - i
&& src[i+0] == 'e'
&& src[i+1] == 'm'
&& src[i+2] == 'i'
&& src[i+3] == 's'
&& src[i+4] == 's'
&& src[i+5] == 'i'
&& src[i+6] == 'o'
&& src[i+7] == 'n'
&& src[i+8] == '_'
&& src[i+9] == 'c'
&& src[i+10] == 'o'
&& src[i+11] == 'l'
&& src[i+12] == 'o'
&& src[i+13] == 'r') {
valuetype = 1;
prop = PROP_EMISSION_COLOR;
i += 14;
} else if (5 < len - i
&& src[i+0] == 'r'
&& src[i+1] == 'a'
&& src[i+2] == 'd'
&& src[i+3] == 'i'
&& src[i+4] == 'u'
&& src[i+5] == 's') {
if (object.type != OBJECT_SPHERE) {
fprintf(stderr, "Poperty 'radius' only allowed on spheres (line %d)\n", line);
return false;
}
valuetype = 0;
prop = PROP_RADIUS;
i += 6;
} else if (5 < len - i
&& src[i+0] == 'c'
&& src[i+1] == 'e'
&& src[i+2] == 'n'
&& src[i+3] == 't'
&& src[i+4] == 'e'
&& src[i+5] == 'r') {
if (object.type != OBJECT_SPHERE) {
fprintf(stderr, "Poperty 'center' only allowed on spheres (line %d)\n", line);
return false;
}
valuetype = 1;
prop = PROP_CENTER;
i += 6;
} else if (5 < len - i
&& src[i+0] == 'o'
&& src[i+1] == 'r'
&& src[i+2] == 'i'
&& src[i+3] == 'g'
&& src[i+4] == 'i'
&& src[i+5] == 'n') {
if (object.type != OBJECT_CUBE) {
fprintf(stderr, "Poperty 'origin' only allowed on cubes (line %d)\n", line);
return false;
}
valuetype = 1;
prop = PROP_ORIGIN;
i += 6;
} else if (3 < len - i
&& src[i+0] == 's'
&& src[i+1] == 'i'
&& src[i+2] == 'z'
&& src[i+3] == 'e') {
if (object.type != OBJECT_CUBE) {
fprintf(stderr, "Poperty 'size' only allowed on cubes (line %d)\n", line);
return false;
}
valuetype = 1;
prop = PROP_SIZE;
i += 4;
} else
// Not a valid property name
break;
// Consume spaces before the value
while (i < len && is_space(src[i])) {
if (src[i] == '\n') line++;
i++;
}
if (i == len) {
fprintf(stderr, "Error: Property value is missing (line %d)\n", line);
return false;
}
float value0;
Vector3 value1;
if (valuetype == 0) {
// Parse a single float
int sign = 1;
if (src[i] == '-') {
sign = -1;
i++;
if (i == len || !is_digit(src[i])) {
fprintf(stderr, "Error: Missing number after minus sign (line %d)\n", line);
return false;
}
} else if (!is_digit(src[i])) {
fprintf(stderr, "Error: Missing number after property name (line %d)\n", line);
return false;
}
value0 = 0;
do {
int d = src[i] - '0';
value0 = value0 * 10 + d;
i++;
} while (i < len && is_digit(src[i]));
if (i < len && src[i] == '.') {
i++; // Skip the dot
if (i == len || !is_digit(src[i])) {
fprintf(stderr, "Error: Missing decimal part after dot (line %d)\n", line);
return false;
}
float q = 1.0f / 10;
do {
int d = src[i] - '0';
value0 += q * d;
q /= 10;
i++;
} while (i < len && is_digit(src[i]));
}
value0 *= sign;
} else {
assert(valuetype == 1);
size_t start = i;
while ()
if (src[i] != '{') {
fprintf(stderr, "Error: Missing '{' after property name (line %d)\n", line);
return false;
}
i++;
float temp[3];
for (int j = 0; j < 3; j++) {
while (i < len && is_space(src[i])) {
if (src[i] == '\n') line++;
i++;
}
int sign = 1;
if (src[i] == '-') {
sign = -1;
i++;
if (i == len || !is_digit(src[i])) {
fprintf(stderr, "Error: Missing number after minus sign (line %d)\n", line);
return false;
}
} else if (!is_digit(src[i])) {
fprintf(stderr, "Error: Missing number %d in vector value (line %d)\n", j, line);
return false;
}
temp[j] = 0;
do {
int d = src[i] - '0';
temp[j] = temp[j] * 10 + d;
i++;
} while (i < len && is_digit(src[i]));
if (i < len && src[i] == '.') {
i++; // Skip the dot
if (i == len || !is_digit(src[i])) {
fprintf(stderr, "Error: Missing decimal part after dot (line %d)\n", line);
return false;
}
float q = 1.0f / 10;
do {
int d = src[i] - '0';
temp[j] += q * d;
q /= 10;
i++;
} while (i < len && is_digit(src[i]));
}
temp[j] *= sign;
}
while (i < len && is_space(src[i])) {
if (src[i] == '\n') line++;
i++;
}
if (i == len || src[i] != '}') {
fprintf(stderr, "Error: Missing '}' after property value (line %d)\n", line);
return false;
}
i++;
value1.x = temp[0];
value1.y = temp[1];
value1.z = temp[2];
}
switch (prop) {
case PROP_ALBEDO:
if (value1.x < 0 || value1.x > 1 ||
value1.y < 0 || value1.y > 1 ||
value1.z < 0 || value1.z > 1) {
fprintf(stderr, "Error: albedo values must be between 0 and 1 (line %d)\n", line);
return false;
}
object.material.albedo = value1;
break;
case PROP_ROUGHNESS:
if (value0 < 0 || value0 > 1) {
fprintf(stderr, "Error: Roughness must be between 0 and 1 (line %d)\n", line);
return false;
}
object.material.roughness = value0;
break;
case PROP_REFLECTANCE:
if (value0 < 0 || value0 > 1) {
fprintf(stderr, "Error: Reflectance must be between 0 and 1 (line %d)\n", line);
return false;
}
object.material.reflectance = value0;
break;
case PROP_METALLIC:
if (value0 < 0 || value0 > 1) {
fprintf(stderr, "Error: Metallic must be between 0 and 1 (line %d)\n", line);
return false;
}
object.material.metallic = value0;
break;
case PROP_EMISSION_POWER:
object.material.emission_power = value0;
break;
case PROP_EMISSION_COLOR:
if (value1.x < 0 || value1.x > 1 ||
value1.y < 0 || value1.y > 1 ||
value1.z < 0 || value1.z > 1) {
fprintf(stderr, "Error: Emission color values must be between 0 and 1 (line %d)\n", line);
return false;
}
object.material.emission_color = value1;
break;
case PROP_RADIUS:
object.sphere.radius = value0;
break;
case PROP_CENTER:
object.sphere.center = value1;
break;
case PROP_ORIGIN:
object.cube.origin = value1;
break;
case PROP_SIZE:
if (value1.x < 0 || value1.y < 0 || value1.z < 0) {
fprintf(stderr, "Error: Size values must be positive (line %d)\n", line);
return false;
}
object.cube.size = value1;
break;
}
}
if (scene->num_objects == MAX_OBJECTS)
fprintf(stderr, "Warning: Ignoring object because the scene is too big (line %d)\n", line);
else
scene->objects[scene->num_objects++] = object;
}
return true;
}
bool parse_scene_file(char *file, Scene *scene)
{
size_t len;
char *src = load_file(file, &len);
if (src == NULL) {
fprintf(stderr, "Error: Couldn't open scene file\n");
return false;
}
bool ok = parse_scene_string(src, len, scene);
free(src);
return ok;
}
#endif
+4
View File
@@ -1,5 +1,9 @@
#include <stddef.h>
#include <stdbool.h>
#define COUNTOF(X) (int) (sizeof(X) / sizeof((X)[0]))
char *load_file(const char *file, size_t *size);
inline bool is_space(char c) { return c == ' ' || c == '\r' || c == '\t' || c == '\n'; }
inline bool is_digit(char c) { return c >= '0' && c <= '9'; }