Skip to content

Commit

Permalink
Merge loadScene() and parseJSON() into parse_json()
Browse files Browse the repository at this point in the history
Moved all that into sceneloader.c. Moved parseColor() into color.c, and
renamed it to color_parse().
  • Loading branch information
vkoskiv committed Nov 12, 2023
1 parent 16eb2d4 commit 8ad129a
Show file tree
Hide file tree
Showing 13 changed files with 273 additions and 327 deletions.
3 changes: 0 additions & 3 deletions include/c-ray/c-ray.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,6 @@ cr_camera cr_camera_new(struct cr_scene *ext);
bool cr_camera_set_num_pref(struct cr_scene *ext, cr_camera c, enum cr_camera_param p, double num);
bool cr_camera_update(struct cr_scene *ext, cr_camera c);

int cr_load_scene_from_file(struct cr_renderer *r, char *file_path);
int cr_load_scene_from_buf(struct cr_renderer *r, char *buf);

void cr_load_mesh_from_file(char *filePath);
void cr_load_mesh_from_buf(char *buf);

Expand Down
23 changes: 2 additions & 21 deletions src/api/c-ray.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//
// c-ray.c
// C-ray
// c-ray
//
// Created by Valtteri on 5.1.2020.
// Copyright © 2020-2022 Valtteri Koskivuori. All rights reserved.
// Copyright © 2020-2023 Valtteri Koskivuori. All rights reserved.
//

#include "../includes.h"
Expand Down Expand Up @@ -331,20 +331,6 @@ void cr_write_image(struct cr_renderer *ext) {
}
}

int cr_load_scene_from_file(struct cr_renderer *ext, char *file_path) {
struct renderer *r = (struct renderer *)ext;
size_t bytes = 0;
char *input = load_file(file_path, &bytes, NULL);
if (input) {
if (loadScene(r, file_path) != 0) {
return -1;
}
} else {
return -1;
}
return 0;
}

void cr_load_mesh_from_file(char *file_path) {
(void)file_path;
ASSERT_NOT_REACHED();
Expand All @@ -355,11 +341,6 @@ void cr_load_mesh_from_buf(char *buf) {
ASSERT_NOT_REACHED();
}

int cr_load_scene_from_buf(struct cr_renderer *ext, char *buf) {
struct renderer *r = (struct renderer *)ext;
return loadScene(r, buf);
}

int cr_get_thread_count(struct cr_renderer *ext) {
struct renderer *r = (struct renderer *)ext;
return r->prefs.threads;
Expand Down
37 changes: 37 additions & 0 deletions src/datatypes/color.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "../includes.h"
#include <stdio.h>
#include "color.h"
#include "../vendored/cJSON.h"
#include "../utils/assert.h"

//Some standard colours
const struct color g_red_color = { 1.0f, 0.0f, 0.0f, 1.0f };
Expand Down Expand Up @@ -99,3 +101,38 @@ struct color color_from_hsl(float hue, float saturation, float lightness) {
void color_dump(struct color c, char *buf, size_t bufsize) {
snprintf(buf, bufsize, "{ %.2f, %.2f, %.2f, %.2f }", (double)c.red, (double)c.green, (double)c.blue, (double)c.alpha);
}

struct color color_parse(const cJSON *data) {
if (cJSON_IsArray(data)) {
const float r = cJSON_IsNumber(cJSON_GetArrayItem(data, 0)) ? (float)cJSON_GetArrayItem(data, 0)->valuedouble : 0.0f;
const float g = cJSON_IsNumber(cJSON_GetArrayItem(data, 1)) ? (float)cJSON_GetArrayItem(data, 1)->valuedouble : 0.0f;
const float b = cJSON_IsNumber(cJSON_GetArrayItem(data, 2)) ? (float)cJSON_GetArrayItem(data, 2)->valuedouble : 0.0f;
const float a = cJSON_IsNumber(cJSON_GetArrayItem(data, 3)) ? (float)cJSON_GetArrayItem(data, 3)->valuedouble : 1.0f;
return (struct color){ r, g, b, a };
}

ASSERT(cJSON_IsObject(data));

const cJSON *kelvin = cJSON_GetObjectItem(data, "blackbody");
if (cJSON_IsNumber(kelvin)) return colorForKelvin(kelvin->valuedouble);

const cJSON *H = cJSON_GetObjectItem(data, "h");
const cJSON *S = cJSON_GetObjectItem(data, "s");
const cJSON *L = cJSON_GetObjectItem(data, "l");

if (cJSON_IsNumber(H) && cJSON_IsNumber(S) && cJSON_IsNumber(L)) {
return color_from_hsl(H->valuedouble, S->valuedouble, L->valuedouble);
}

const cJSON *R = cJSON_GetObjectItem(data, "r");
const cJSON *G = cJSON_GetObjectItem(data, "g");
const cJSON *B = cJSON_GetObjectItem(data, "b");
const cJSON *A = cJSON_GetObjectItem(data, "a");

return (struct color){
cJSON_IsNumber(R) ? (float)R->valuedouble : 0.0f,
cJSON_IsNumber(G) ? (float)G->valuedouble : 0.0f,
cJSON_IsNumber(B) ? (float)B->valuedouble : 0.0f,
cJSON_IsNumber(A) ? (float)A->valuedouble : 1.0f,
};
}
4 changes: 4 additions & 0 deletions src/datatypes/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,7 @@ struct color colorForKelvin(float kelvin);
struct color color_from_hsl(float hue, float saturation, float lightness);

void color_dump(struct color c, char *buf, size_t bufsize);

struct cJSON;

struct color color_parse(const struct cJSON *data);
234 changes: 6 additions & 228 deletions src/datatypes/scene.c
Original file line number Diff line number Diff line change
@@ -1,245 +1,23 @@
//
// scene.c
// C-ray
// c-ray
//
// Created by Valtteri Koskivuori on 28/02/2015.
// Copyright © 2015-2022 Valtteri Koskivuori. All rights reserved.
// Copyright © 2015-2023 Valtteri Koskivuori. All rights reserved.
//

#include "../includes.h"
#include "scene.h"

#include "../utils/timer.h"
#include "../utils/loaders/sceneloader.h"
#include "../utils/logging.h"
#include "image/imagefile.h"
#include "../renderer/renderer.h"
#include "image/texture.h"
#include "camera.h"
#include "../accelerators/bvh.h"
#include "tile.h"
#include "mesh.h"
#include "poly.h"
#include "../utils/platform/thread.h"
#include "../utils/platform/signal.h"
#include "../renderer/instance.h"
#include "../datatypes/bbox.h"
#include "../utils/mempool.h"
#include "../utils/hashtable.h"
#include "../nodes/bsdfnode.h"
#include "../utils/args.h"
#include "../utils/textbuffer.h"
#include "../utils/dyn_array.h"

struct bvh_build_task {
struct bvh *bvh;
const struct mesh *mesh;
};

void *bvh_build_thread(void *arg) {
block_signals();
struct bvh_build_task *task = (struct bvh_build_task *)thread_user_data(arg);
task->bvh = build_mesh_bvh(task->mesh);
return NULL;
}

static void compute_accels(struct mesh_arr meshes) {
logr(info, "Computing BVHs: ");
struct timeval timer = { 0 };
timer_start(&timer);
struct bvh_build_task *tasks = calloc(meshes.count, sizeof(*tasks));
struct cr_thread *build_threads = calloc(meshes.count, sizeof(*build_threads));
for (size_t t = 0; t < meshes.count; ++t) {
tasks[t] = (struct bvh_build_task){
.mesh = &meshes.items[t],
};
build_threads[t] = (struct cr_thread){
.thread_fn = bvh_build_thread,
.user_data = &tasks[t]
};
if (thread_start(&build_threads[t])) {
logr(error, "Failed to create a bvhBuildTask\n");
}
}

for (size_t t = 0; t < meshes.count; ++t) {
thread_wait(&build_threads[t]);
meshes.items[t].bvh = tasks[t].bvh;
}
printSmartTime(timer_get_ms(timer));
free(tasks);
free(build_threads);
logr(plain, "\n");
}

struct bvh *computeTopLevelBvh(struct instance_arr instances) {
logr(info, "Computing top-level BVH: ");
struct timeval timer = {0};
timer_start(&timer);
struct bvh *new = build_top_level_bvh(instances);
printSmartTime(timer_get_ms(timer));
logr(plain, "\n");
return new;
}

static void printSceneStats(struct world *scene, unsigned long long ms) {
logr(info, "Scene construction completed in ");
printSmartTime(ms);
uint64_t polys = 0;
uint64_t vertices = 0;
uint64_t normals = 0;
for (size_t i = 0; i < scene->instances.count; ++i) {
if (isMesh(&scene->instances.items[i])) {
const struct mesh *mesh = &scene->meshes.items[scene->instances.items[i].object_idx];
polys += mesh->polygons.count;
vertices += mesh->vbuf->vertices.count;
normals += mesh->vbuf->normals.count;
}
}
logr(plain, "\n");
logr(info, "Totals: %liV, %liN, %zuI, %liP, %zuS, %zuM\n",
vertices,
normals,
scene->instances.count,
polys,
scene->spheres.count,
scene->meshes.count);
}

//Split scene loading and prefs?
//Load the scene, allocate buffers, etc
//FIXME: Rename this func and take parseJSON out to a separate call.
int loadScene(struct renderer *r, char *input) {

struct timeval timer = {0};
timer_start(&timer);

cJSON *json = cJSON_Parse(input);
if (!json) {
const char *errptr = cJSON_GetErrorPtr();
if (errptr) {
logr(warning, "Failed to parse JSON\n");
logr(warning, "Error before: %s\n", errptr);
return -2;
}
}
// Input is potentially very large, so we free it as soon as possible
// FIXME: mmap() input
free(input);

//Load configuration and assets
//FIXME: Rename parseJSON
//FIXME: Actually throw out all of this code in this function and rewrite
switch (parseJSON(r, json)) {
case -1:
cJSON_Delete(json);
logr(warning, "Scene builder failed due to previous error.\n");
return -1;
case 4:
cJSON_Delete(json);
logr(warning, "Scene debug mode enabled, won't render image.\n");
return -1;
case -2:
cJSON_Delete(json);
//JSON parser failed
return -1;
default:
break;
}

// This is where we prepare a cache of scene data to be sent to worker nodes
// We also apply any potential command-line overrides to that cache here as well.
// FIXME: This overrides setting should be integrated with scene loading, probably.
if (args_is_set("use_clustering")) {
// Stash a cache of scene data here
// Apply overrides to the cache here
if (args_is_set("samples_override")) {
cJSON *renderer = cJSON_GetObjectItem(json, "renderer");
if (cJSON_IsObject(renderer)) {
int samples = args_int("samples_override");
logr(debug, "Overriding cache sample count to %i\n", samples);
if (cJSON_IsNumber(cJSON_GetObjectItem(renderer, "samples"))) {
cJSON_ReplaceItemInObject(renderer, "samples", cJSON_CreateNumber(samples));
} else {
cJSON_AddItemToObject(renderer, "samples", cJSON_CreateNumber(samples));
}
}
}

if (args_is_set("dims_override")) {
cJSON *renderer = cJSON_GetObjectItem(json, "renderer");
if (cJSON_IsObject(renderer)) {
int width = args_int("dims_width");
int height = args_int("dims_height");
logr(info, "Overriding cache image dimensions to %ix%i\n", width, height);
if (cJSON_IsNumber(cJSON_GetObjectItem(renderer, "width")) && cJSON_IsNumber(cJSON_GetObjectItem(renderer, "height"))) {
cJSON_ReplaceItemInObject(renderer, "width", cJSON_CreateNumber(width));
cJSON_ReplaceItemInObject(renderer, "height", cJSON_CreateNumber(height));
} else {
cJSON_AddItemToObject(renderer, "width", cJSON_CreateNumber(width));
cJSON_AddItemToObject(renderer, "height", cJSON_CreateNumber(height));
}
}
}

if (args_is_set("tiledims_override")) {
cJSON *renderer = cJSON_GetObjectItem(json, "renderer");
if (cJSON_IsObject(renderer)) {
int width = args_int("tile_width");
int height = args_int("tile_height");
logr(info, "Overriding cache tile dimensions to %ix%i\n", width, height);
if (cJSON_IsNumber(cJSON_GetObjectItem(renderer, "tileWidth")) && cJSON_IsNumber(cJSON_GetObjectItem(renderer, "tileHeight"))) {
cJSON_ReplaceItemInObject(renderer, "tileWidth", cJSON_CreateNumber(width));
cJSON_ReplaceItemInObject(renderer, "tileHeight", cJSON_CreateNumber(height));
} else {
cJSON_AddItemToObject(renderer, "tileWidth", cJSON_CreateNumber(width));
cJSON_AddItemToObject(renderer, "tileHeight", cJSON_CreateNumber(height));
}
}
}

if (r->prefs.selected_camera != 0) {
cJSON_AddItemToObject(json, "selected_camera", cJSON_CreateNumber(r->prefs.selected_camera));
}

// Store cache. This is what gets sent to worker nodes.
r->sceneCache = cJSON_PrintUnformatted(json);
}

logr(debug, "Deleting JSON...\n");
cJSON_Delete(json);
logr(debug, "Deleting done\n");

if (r->prefs.threads > 0) {
// Do some pre-render preparations
// Compute BVH acceleration structures for all objects in the scene
compute_accels(r->scene->meshes);
// And then compute a single top-level BVH that contains all the objects
r->scene->topLevel = computeTopLevelBvh(r->scene->instances);
printSceneStats(r->scene, timer_get_ms(timer));
} else {
logr(debug, "No local render threads, skipping local BVH construction.\n");
}

//Quantize image into renderTiles
tile_quantize(&r->state.tiles,
r->scene->cameras.items[r->prefs.selected_camera].width,
r->scene->cameras.items[r->prefs.selected_camera].height,
r->prefs.tileWidth,
r->prefs.tileHeight,
r->prefs.tileOrder);

for (size_t i = 0; i < r->state.tiles.count; ++i)
r->state.tiles.items[i].total_samples = r->prefs.sampleCount;

//Print a useful warning to user if the defined tile size results in less renderThreads
if (r->state.tiles.count < r->prefs.threads) {
logr(warning, "WARNING: Rendering with a less than optimal thread count due to large tile size!\n");
logr(warning, "Reducing thread count from %zu to %zu\n", r->prefs.threads, r->state.tiles.count);
r->prefs.threads = r->state.tiles.count;
}
return 0;
}
#include "camera.h"
#include "tile.h"
#include "mesh.h"
#include "poly.h"

//Free scene data
void destroyScene(struct world *scene) {
Expand Down
6 changes: 2 additions & 4 deletions src/datatypes/scene.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//
// scene.h
// C-ray
// c-ray
//
// Created by Valtteri Koskivuori on 28/02/2015.
// Copyright © 2015-2022 Valtteri Koskivuori. All rights reserved.
// Copyright © 2015-2023 Valtteri Koskivuori. All rights reserved.
//

#pragma once
Expand Down Expand Up @@ -38,6 +38,4 @@ struct world {
float backgroundOffset;
};

int loadScene(struct renderer *r, char *input);

void destroyScene(struct world *scene);
Loading

0 comments on commit 8ad129a

Please sign in to comment.