diff --git a/include/c-ray/c-ray.h b/include/c-ray/c-ray.h index ac790281..c1705d22 100644 --- a/include/c-ray/c-ray.h +++ b/include/c-ray/c-ray.h @@ -46,7 +46,6 @@ enum cr_renderer_param { cr_renderer_should_save, //FIXME: Remove cr_renderer_override_cam, cr_renderer_node_list, - cr_renderer_scene_cache, // FIXME: Remove cr_renderer_is_iterative, }; @@ -136,7 +135,7 @@ typedef cr_object cr_sphere; cr_sphere cr_scene_add_sphere(struct cr_scene *s_ext, float radius); typedef cr_object cr_mesh; -struct cr_vertex_buf { +struct cr_vertex_buf_param { struct cr_vector *vertices; size_t vertex_count; struct cr_vector *normals; @@ -145,9 +144,9 @@ struct cr_vertex_buf { size_t tex_coord_count; }; -struct cr_vertex_buf *cr_vertex_buf_new(struct cr_vertex_buf in); -void cr_vertex_buf_del(struct cr_vertex_buf *buf); -void cr_mesh_bind_vertex_buf(struct cr_scene *s_ext, cr_mesh mesh, struct cr_vertex_buf *buf); +typedef cr_object cr_vertex_buf; +cr_vertex_buf cr_scene_vertex_buf_new(struct cr_scene *s_ext, struct cr_vertex_buf_param in); +void cr_mesh_bind_vertex_buf(struct cr_scene *s_ext, cr_mesh mesh, cr_vertex_buf buf); struct cr_face { int vertex_idx[MAX_CRAY_VERTEX_COUNT]; @@ -189,10 +188,9 @@ bool cr_camera_update(struct cr_scene *ext, cr_camera c); // -- Materials -- #include "node.h" -typedef struct cr_material_set cr_material_set; -cr_material_set *cr_material_set_new(void); -void cr_material_set_add(struct cr_renderer *r_ext, cr_material_set *set, struct cr_shader_node *desc); -void cr_material_set_del(cr_material_set *set); +typedef cr_object cr_material_set; +cr_material_set cr_scene_new_material_set(struct cr_scene *s_ext); +void cr_material_set_add(struct cr_renderer *r_ext, struct cr_scene *s_ext, cr_material_set set, struct cr_shader_node *desc); // -- Instancing -- @@ -204,7 +202,7 @@ enum cr_object_type { cr_instance cr_instance_new(struct cr_scene *s_ext, cr_object object, enum cr_object_type type); void cr_instance_set_transform(struct cr_scene *s_ext, cr_instance instance, float row_major[4][4]); -bool cr_instance_bind_material_set(struct cr_renderer *r_ext, cr_instance instance, cr_material_set *set); +bool cr_instance_bind_material_set(struct cr_renderer *r_ext, cr_instance instance, cr_material_set set); // -- Misc. -- bool cr_scene_set_background(struct cr_renderer *r_ext, struct cr_scene *s_ext, struct cr_shader_node *desc); diff --git a/include/c-ray/node.h b/include/c-ray/node.h index ff8b6321..71d23510 100644 --- a/include/c-ray/node.h +++ b/include/c-ray/node.h @@ -236,6 +236,7 @@ struct cr_vector_node { }; struct cr_shader_node { + // TODO: s/bsdf/shader enum cr_bsdf_node_type { cr_bsdf_unknown = 0, cr_bsdf_diffuse, diff --git a/src/api/c-ray.c b/src/api/c-ray.c index 5253ce14..b1769cac 100644 --- a/src/api/c-ray.c +++ b/src/api/c-ray.c @@ -24,10 +24,11 @@ #include "../utils/string.h" #include "../utils/protocol/server.h" #include "../utils/protocol/worker.h" -#include "../utils/filecache.h" #include "../utils/hashtable.h" #include "../datatypes/camera.h" #include "../utils/loaders/textureloader.h" +#include "../driver/node_parse.h" +#include "../utils/protocol/protocol.h" #ifdef CRAY_DEBUG_ENABLED #define DEBUG "D" @@ -132,8 +133,9 @@ bool cr_renderer_set_str_pref(struct cr_renderer *ext, enum cr_renderer_param p, return true; } case cr_renderer_asset_path: { - if (r->prefs.assetPath) free(r->prefs.assetPath); - r->prefs.assetPath = stringCopy(str); + // TODO: we shouldn't really be touching anything but prefs in here. + if (r->scene->asset_path) free(r->scene->asset_path); + r->scene->asset_path = stringCopy(str); return true; } case cr_renderer_output_name: { @@ -156,12 +158,6 @@ bool cr_renderer_set_str_pref(struct cr_renderer *ext, enum cr_renderer_param p, case cr_renderer_node_list: { if (r->prefs.node_list) free(r->prefs.node_list); r->prefs.node_list = stringCopy(str); - if (!r->state.file_cache) r->state.file_cache = cache_create(); - return true; - } - case cr_renderer_scene_cache: { - if (r->sceneCache) free(r->sceneCache); - r->sceneCache = stringCopy(str); return true; } default: { @@ -201,7 +197,7 @@ const char *cr_renderer_get_str_pref(struct cr_renderer *ext, enum cr_renderer_p switch (p) { case cr_renderer_output_path: return r->prefs.imgFilePath; case cr_renderer_output_name: return r->prefs.imgFileName; - case cr_renderer_asset_path: return r->prefs.assetPath; + case cr_renderer_asset_path: return r->scene->asset_path; default: return NULL; } return NULL; @@ -226,10 +222,12 @@ uint64_t cr_renderer_get_num_pref(struct cr_renderer *ext, enum cr_renderer_para return 0; } +// TODO: Remove r_ext bool cr_scene_set_background(struct cr_renderer *r_ext, struct cr_scene *s_ext, struct cr_shader_node *desc) { if (!r_ext || !s_ext) return false; struct world *s = (struct world *)s_ext; - s->background = desc ? build_bsdf_node(r_ext, desc) : newBackground(&s->storage, NULL, NULL, NULL); + s->background = desc ? build_bsdf_node(s_ext, desc) : newBackground(&s->storage, NULL, NULL, NULL); + s->bg_desc = desc ? desc : NULL; return true; } @@ -259,37 +257,37 @@ cr_sphere cr_scene_add_sphere(struct cr_scene *s_ext, float radius) { return sphere_arr_add(&scene->spheres, (struct sphere){ .radius = radius }); } -struct cr_vertex_buf *cr_vertex_buf_new(struct cr_vertex_buf in) { - struct vertex_buffer *buf = vertex_buf_ref(NULL); +cr_vertex_buf cr_scene_vertex_buf_new(struct cr_scene *s_ext, struct cr_vertex_buf_param in) { + if (!s_ext) return -1; + struct world *scene = (struct world *)s_ext; + struct vertex_buffer new = { 0 }; // TODO: T_arr_add_n() if (in.vertices && in.vertex_count) { for (size_t i = 0; i < in.vertex_count; ++i) { - vector_arr_add(&buf->vertices, *(struct vector *)&in.vertices[i]); + vector_arr_add(&new.vertices, *(struct vector *)&in.vertices[i]); } } if (in.normals && in.normal_count) { for (size_t i = 0; i < in.normal_count; ++i) { - vector_arr_add(&buf->normals, *(struct vector *)&in.normals[i]); + vector_arr_add(&new.normals, *(struct vector *)&in.normals[i]); } } if (in.tex_coords && in.tex_coord_count) { for (size_t i = 0; i < in.tex_coord_count; ++i) { - coord_arr_add(&buf->texture_coords, *(struct coord *)&in.tex_coords[i]); + coord_arr_add(&new.texture_coords, *(struct coord *)&in.tex_coords[i]); } } - return (struct cr_vertex_buf *)buf; + return vertex_buffer_arr_add(&scene->v_buffers, new); } -void cr_vertex_buf_del(struct cr_vertex_buf *buf) { - vertex_buf_unref((struct vertex_buffer *)buf); -} - -void cr_mesh_bind_vertex_buf(struct cr_scene *s_ext, cr_mesh mesh, struct cr_vertex_buf *buf) { - if (!s_ext || !buf) return; +void cr_mesh_bind_vertex_buf(struct cr_scene *s_ext, cr_mesh mesh, cr_vertex_buf buf) { + if (!s_ext) return; struct world *scene = (struct world *)s_ext; if ((size_t)mesh > scene->meshes.count - 1) return; struct mesh *m = &scene->meshes.items[mesh]; - m->vbuf = vertex_buf_ref((struct vertex_buffer *)buf); + if ((size_t)buf > scene->v_buffers.count - 1) return; + m->vbuf = &scene->v_buffers.items[buf]; + m->vbuf_idx = buf; } void cr_mesh_bind_faces(struct cr_scene *s_ext, cr_mesh mesh, struct cr_face *faces, size_t face_count) { @@ -348,13 +346,15 @@ void cr_instance_set_transform(struct cr_scene *s_ext, cr_instance instance, flo }; } -bool cr_instance_bind_material_set(struct cr_renderer *r_ext, cr_instance instance, cr_material_set *set) { - if (!r_ext || !set) return false; +bool cr_instance_bind_material_set(struct cr_renderer *r_ext, cr_instance instance, cr_material_set set) { + if (!r_ext) return false; struct renderer *r = (struct renderer *)r_ext; struct world *scene = r->scene; if ((size_t)instance > scene->instances.count - 1) return false; + if ((size_t)set > scene->shader_buffers.count - 1) return false; struct instance *i = &scene->instances.items[instance]; - i->bbuf = bsdf_buf_ref((struct bsdf_buffer *)set); + i->bbuf = &scene->shader_buffers.items[set]; + i->bbuf_idx = set; return true; } @@ -459,29 +459,29 @@ bool cr_camera_remove(struct cr_scene *s, cr_camera c) { // -- -cr_material_set *cr_material_set_new(void) { - return (cr_material_set *)bsdf_buf_ref(NULL); +cr_material_set cr_scene_new_material_set(struct cr_scene *s_ext) { + if (!s_ext) return -1; + struct world *scene = (struct world *)s_ext; + return bsdf_buffer_arr_add(&scene->shader_buffers, (struct bsdf_buffer){ 0 }); } -void cr_material_set_add(struct cr_renderer *r_ext, cr_material_set *set, struct cr_shader_node *desc) { - if (!set || !desc) return; - struct bsdf_buffer *buf = (struct bsdf_buffer *)set; - const struct bsdfNode *node = build_bsdf_node(r_ext, desc); +// TODO: Remove r_ext +void cr_material_set_add(struct cr_renderer *r_ext, struct cr_scene *s_ext, cr_material_set set, struct cr_shader_node *desc) { + if (!r_ext || !s_ext) return; + struct renderer *r = (struct renderer *)r_ext; + struct world *s = (struct world *)s_ext; + if (s != r->scene) return; + if ((size_t)set > s->shader_buffers.count - 1) return; + struct bsdf_buffer *buf = &s->shader_buffers.items[set]; + const struct bsdfNode *node = build_bsdf_node(s_ext, desc); + cr_shader_node_ptr_arr_add(&buf->descriptions, desc); bsdf_node_ptr_arr_add(&buf->bsdfs, node); } -void cr_material_set_del(cr_material_set *set) { - if (!set) return; - bsdf_buf_unref((struct bsdf_buffer *)set); -} - struct texture *cr_renderer_render(struct cr_renderer *ext) { struct renderer *r = (struct renderer *)ext; if (r->prefs.node_list) { r->state.clients = clients_sync(r); - free(r->sceneCache); - r->sceneCache = NULL; - cache_destroy(r->state.file_cache); } if (!r->state.clients.count && !r->prefs.threads) { logr(warning, "You specified 0 local threads, and no network clients were found. Nothing to do.\n"); diff --git a/src/datatypes/image/texture.h b/src/datatypes/image/texture.h index 02ea0c57..9f0a3bb7 100644 --- a/src/datatypes/image/texture.h +++ b/src/datatypes/image/texture.h @@ -11,6 +11,7 @@ #include #include #include "../color.h" +#include "../../utils/dyn_array.h" enum colorspace { linear, @@ -35,6 +36,14 @@ struct texture { size_t height; }; +struct texture_asset { + char *path; + struct texture *t; +}; + +typedef struct texture_asset texture_asset; +dyn_array_def(texture_asset); + struct texture *newTexture(enum precision p, size_t width, size_t height, size_t channels); void setPixel(struct texture *t, struct color c, size_t x, size_t y); diff --git a/src/datatypes/mesh.c b/src/datatypes/mesh.c index 3904ed71..274a4f9b 100644 --- a/src/datatypes/mesh.c +++ b/src/datatypes/mesh.c @@ -17,27 +17,13 @@ void destroyMesh(struct mesh *mesh) { if (mesh) { free(mesh->name); - vertex_buf_unref(mesh->vbuf); poly_arr_free(&mesh->polygons); destroy_bvh(mesh->bvh); } } -struct vertex_buffer *vertex_buf_ref(struct vertex_buffer *buf) { - if (buf) { - buf->refs++; - return buf; - } - struct vertex_buffer *new = calloc(1, sizeof(*new)); - new->refs = 1; - return new; -} - -void vertex_buf_unref(struct vertex_buffer *buf) { - if (!buf) return; - if (--buf->refs) return; - vector_arr_free(&buf->vertices); - vector_arr_free(&buf->normals); - coord_arr_free(&buf->texture_coords); - free(buf); +void vertex_buf_free(struct vertex_buffer buf) { + vector_arr_free(&buf.vertices); + vector_arr_free(&buf.normals); + coord_arr_free(&buf.texture_coords); } diff --git a/src/datatypes/mesh.h b/src/datatypes/mesh.h index a085ebd0..a0832d11 100644 --- a/src/datatypes/mesh.h +++ b/src/datatypes/mesh.h @@ -13,22 +13,20 @@ #include "poly.h" #include "material.h" -/* - Several meshes may point to the same vertex buffer, shared among meshes in - a wavefront file, for instance. A simple refcount is kept to make it easier - to automatically free it when adding and removing meshes. -*/ struct vertex_buffer { struct vector_arr vertices; struct vector_arr normals; struct coord_arr texture_coords; - size_t refs; }; +typedef struct vertex_buffer vertex_buffer; +dyn_array_def(vertex_buffer); + struct mesh { struct vertex_buffer *vbuf; struct poly_arr polygons; struct bvh *bvh; + size_t vbuf_idx; float surface_area; char *name; float rayOffset; @@ -39,5 +37,4 @@ dyn_array_def(mesh); void destroyMesh(struct mesh *mesh); -struct vertex_buffer *vertex_buf_ref(struct vertex_buffer *buf); -void vertex_buf_unref(struct vertex_buffer *buf); +void vertex_buf_free(struct vertex_buffer buf); diff --git a/src/datatypes/scene.c b/src/datatypes/scene.c index d70bb4d6..4dfedc7b 100644 --- a/src/datatypes/scene.c +++ b/src/datatypes/scene.c @@ -13,14 +13,22 @@ #include "../utils/hashtable.h" #include "../utils/textbuffer.h" #include "../utils/dyn_array.h" +#include "../driver/node_parse.h" +#include "image/texture.h" #include "camera.h" #include "tile.h" #include "mesh.h" #include "poly.h" -//Free scene data +void tex_asset_free(struct texture_asset *a) { + if (a->path) free(a->path); + if (a->t) destroyTexture(a->t); +} + void scene_destroy(struct world *scene) { if (scene) { + scene->textures.elem_free = tex_asset_free; + texture_asset_arr_free(&scene->textures); camera_arr_free(&scene->cameras); for (size_t i = 0; i < scene->meshes.count; ++i) { destroyMesh(&scene->meshes.items[i]); @@ -29,11 +37,23 @@ void scene_destroy(struct world *scene) { destroy_bvh(scene->topLevel); destroyHashtable(scene->storage.node_table); destroyBlocks(scene->storage.node_pool); - for (size_t i = 0; i < scene->instances.count; ++i) { - bsdf_buf_unref(scene->instances.items[i].bbuf); + for (size_t i = 0; i < scene->shader_buffers.count; ++i) { + for (size_t j = 0; j < scene->shader_buffers.items[i].descriptions.count; ++j) { + cr_shader_node_free(scene->shader_buffers.items[i].descriptions.items[j]); + } + cr_shader_node_ptr_arr_free(&scene->shader_buffers.items[i].descriptions); + bsdf_node_ptr_arr_free(&scene->shader_buffers.items[i].bsdfs); + } + bsdf_buffer_arr_free(&scene->shader_buffers); + cr_shader_node_free(scene->bg_desc); + // TODO: set as dyn_array elem_free somewhere + for (size_t i = 0; i < scene->v_buffers.count; ++i) { + vertex_buf_free(scene->v_buffers.items[i]); } + vertex_buffer_arr_free(&scene->v_buffers); instance_arr_free(&scene->instances); sphere_arr_free(&scene->spheres); + if (scene->asset_path) free(scene->asset_path); free(scene); } } diff --git a/src/datatypes/scene.h b/src/datatypes/scene.h index 0d2f9eca..714f8a6b 100644 --- a/src/datatypes/scene.h +++ b/src/datatypes/scene.h @@ -12,6 +12,8 @@ #include "mesh.h" #include "../renderer/instance.h" #include "../datatypes/camera.h" +#include "../datatypes/image/texture.h" +#include "../nodes/bsdfnode.h" struct renderer; struct hashtable; @@ -27,14 +29,20 @@ struct node_storage { struct world { //Optional environment map / ambient color const struct bsdfNode *background; + struct cr_shader_node *bg_desc; + struct texture_asset_arr textures; + struct vertex_buffer_arr v_buffers; + struct bsdf_buffer_arr shader_buffers; struct mesh_arr meshes; struct instance_arr instances; // Top-level bounding volume hierarchy, // contains all 3D assets in the scene. - struct bvh *topLevel; + struct bvh *topLevel; // FIXME: Move to state? struct sphere_arr spheres; struct camera_arr cameras; - struct node_storage storage; + struct node_storage storage; // FIXME: Move to state? + + char *asset_path; }; void scene_destroy(struct world *scene); diff --git a/src/datatypes/tile.c b/src/datatypes/tile.c index 9d1a437c..f27e8cf6 100644 --- a/src/datatypes/tile.c +++ b/src/datatypes/tile.c @@ -116,6 +116,7 @@ void tile_set_free(struct tile_set *set) { if (set->tile_mutex) free(set->tile_mutex); set->tile_mutex = NULL; } + static void reorder_top_to_bottom(struct render_tile_arr *tiles) { struct render_tile_arr temp = { 0 }; diff --git a/src/driver/args.c b/src/driver/args.c index 0a6d9011..c4c3263b 100644 --- a/src/driver/args.c +++ b/src/driver/args.c @@ -92,10 +92,10 @@ struct driver_args *args_parse(int argc, char **argv) { } alternatePath = stringConcat(argv[i], ".json"); - if (is_valid_file(argv[i], NULL) && !inputFileSet) { + if (is_valid_file(argv[i]) && !inputFileSet) { setDatabaseString(args, "inputFile", argv[i]); inputFileSet = true; - } else if (is_valid_file(alternatePath, NULL) && !inputFileSet) { + } else if (is_valid_file(alternatePath) && !inputFileSet) { setDatabaseString(args, "inputFile", alternatePath); inputFileSet = true; } diff --git a/src/driver/json_loader.c b/src/driver/json_loader.c index 7a1f3f88..2ab13da1 100644 --- a/src/driver/json_loader.c +++ b/src/driver/json_loader.c @@ -14,8 +14,6 @@ #include "loaders/meshloader.h" #include "../utils/loaders/textureloader.h" -// FIXME: We should only need to include c-ray.h here! -#include "../renderer/renderer.h" // REMOVE #include #include "../datatypes/transforms.h" @@ -26,6 +24,7 @@ #include "../utils/platform/capabilities.h" #include "../utils/logging.h" #include "../utils/fileio.h" +#include "../utils/timer.h" static struct transform parse_tform(const cJSON *data) { const cJSON *type = cJSON_GetObjectItem(data, "type"); @@ -300,7 +299,6 @@ static void parse_mesh(struct cr_renderer *r, const cJSON *data, int idx, int me const cJSON *file_name = cJSON_GetObjectItem(data, "fileName"); if (!cJSON_IsString(file_name)) return; - struct renderer *todo_remove_r = (struct renderer *)r; struct cr_scene *scene = cr_renderer_scene_get(r); //FIXME: This concat + path fixing should be an utility function @@ -312,7 +310,7 @@ static void parse_mesh(struct cr_renderer *r, const cJSON *data, int idx, int me logr(info, "Loading mesh file %i/%i%s", idx + 1, mesh_file_count, (idx + 1) == mesh_file_count ? "\n" : "\r"); struct timeval timer; timer_start(&timer); - struct mesh_parse_result result = load_meshes_from_file(full_path, todo_remove_r->state.file_cache); + struct mesh_parse_result result = load_meshes_from_file(full_path); long us = timer_get_us(timer); free(full_path); long ms = us / 1000; @@ -320,7 +318,7 @@ static void parse_mesh(struct cr_renderer *r, const cJSON *data, int idx, int me if (!result.meshes.count) return; - struct cr_vertex_buf *vbuf = cr_vertex_buf_new((struct cr_vertex_buf){ + cr_vertex_buf vbuf = cr_scene_vertex_buf_new(scene, (struct cr_vertex_buf_param){ .vertices = (struct cr_vector *)result.geometry.vertices.items, .vertex_count = result.geometry.vertices.count, .normals = (struct cr_vector *)result.geometry.normals.items, @@ -334,12 +332,11 @@ static void parse_mesh(struct cr_renderer *r, const cJSON *data, int idx, int me // FIXME: Textures get loaded multiple times, put them in a hash table // Precompute guessed bsdfs for these instances - cr_material_set *file_set = cr_material_set_new(); + cr_material_set file_set = cr_scene_new_material_set(scene); logr(debug, "Figuring out bsdfs for mtllib materials\n"); for (size_t i = 0; i < result.materials.count; ++i) { struct cr_shader_node *desc = global_desc(result.materials, global_overrides, i); - cr_material_set_add(r, file_set, desc); - cr_shader_node_free(desc); + cr_material_set_add(r, scene, file_set, desc); } // Now apply some slightly overcomplicated logic to choose instances to add to the scene. @@ -382,7 +379,7 @@ static void parse_mesh(struct cr_renderer *r, const cJSON *data, int idx, int me } if (mesh < 0) continue; cr_instance new = cr_instance_new(scene, mesh, cr_object_mesh); - cr_material_set *instance_set = cr_material_set_new(); + cr_material_set instance_set = cr_scene_new_material_set(scene); const cJSON *instance_overrides = cJSON_GetObjectItem(instance, "materials"); for (size_t i = 0; i < result.materials.count; ++i) { struct cr_shader_node *override_match = NULL; @@ -395,23 +392,19 @@ static void parse_mesh(struct cr_renderer *r, const cJSON *data, int idx, int me } } if (override_match) { - cr_material_set_add(r, instance_set, override_match); - cr_shader_node_free(override_match); + cr_material_set_add(r, scene, instance_set, override_match); } else { struct cr_shader_node *global = global_desc(result.materials, global_overrides, i); - cr_material_set_add(r, instance_set, global); - cr_shader_node_free(global); + cr_material_set_add(r, scene, instance_set, global); } } cr_instance_set_transform(scene, new, parse_composite_transform(cJSON_GetObjectItem(instance, "transforms")).A.mtx); cr_instance_bind_material_set(r, new, instance_set); - cr_material_set_del(instance_set); } } done: - cr_material_set_del(file_set); for (size_t i = 0; i < result.meshes.count; ++i) { poly_arr_free(&result.meshes.items[i].polygons); destroyMesh(&result.meshes.items[i]); @@ -424,7 +417,6 @@ static void parse_mesh(struct cr_renderer *r, const cJSON *data, int idx, int me vector_arr_free(&result.geometry.vertices); vector_arr_free(&result.geometry.normals); coord_arr_free(&result.geometry.texture_coords); - cr_vertex_buf_del(vbuf); } static void parse_meshes(struct cr_renderer *r, const cJSON *data) { @@ -462,7 +454,7 @@ static void parse_sphere(struct cr_renderer *r, const cJSON *data) { cr_instance new_instance = cr_instance_new(scene, new_sphere, cr_object_sphere); - cr_material_set *instance_set = cr_material_set_new(); + cr_material_set instance_set = cr_scene_new_material_set(scene); const cJSON *instance_materials = cJSON_GetObjectItem(instance, "materials"); const cJSON *materials = instance_materials ? instance_materials : sphere_global_materials; @@ -475,8 +467,7 @@ static void parse_sphere(struct cr_renderer *r, const cJSON *data) { material = materials; } struct cr_shader_node *desc = cr_shader_node_build(material); - cr_material_set_add(r, instance_set, desc); - cr_shader_node_free(desc); + cr_material_set_add(r, scene, instance_set, desc); // FIXME // const cJSON *type_string = cJSON_GetObjectItem(material, "type"); @@ -488,7 +479,6 @@ static void parse_sphere(struct cr_renderer *r, const cJSON *data) { cr_instance_set_transform(scene, new_instance, parse_composite_transform(cJSON_GetObjectItem(instance, "transforms")).A.mtx); cr_instance_bind_material_set(r, new_instance, instance_set); - cr_material_set_del(instance_set); } } } @@ -519,7 +509,6 @@ static void parseScene(struct cr_renderer *r, const cJSON *data) { struct cr_shader_node *background = cr_shader_node_build(cJSON_GetObjectItem(data, "ambientColor")); cr_scene_set_background(r, scene, background); - cr_shader_node_free(background); parse_primitives(r, cJSON_GetObjectItem(data, "primitives")); parse_meshes(r, cJSON_GetObjectItem(data, "meshes")); @@ -534,11 +523,12 @@ int parse_json(struct cr_renderer *r, struct cJSON *json) { return -1; } - const cJSON *selected_camera = cJSON_GetObjectItem(json, "selected_camera"); + const cJSON *renderer = cJSON_GetObjectItem(json, "renderer"); + const cJSON *selected_camera = cJSON_GetObjectItem(renderer, "selected_camera"); if (cJSON_IsNumber(selected_camera)) { cr_renderer_set_num_pref(r, cr_renderer_override_cam, selected_camera->valueint); } parseScene(r, cJSON_GetObjectItem(json, "scene")); - + return 0; } diff --git a/src/driver/loaders/formats/gltf/gltf.c b/src/driver/loaders/formats/gltf/gltf.c index ae9c8e2b..fe53fa2e 100644 --- a/src/driver/loaders/formats/gltf/gltf.c +++ b/src/driver/loaders/formats/gltf/gltf.c @@ -70,11 +70,11 @@ unsigned char *parse_buffer(const cJSON *data) { return buffer; } else { // Otherwise just try to load the specified file - if (!is_valid_file(uri_string, NULL)) { //FIXME cache + if (!is_valid_file(uri_string)) { logr(warning, "Invalid buffer while parsing glTF. File %s not found.\n", uri_string); return NULL; } - file_data data = file_load(uri_string, NULL); //FIXME cache + file_data data = file_load(uri_string); if (data.count != expected_bytes) { logr(warning, "Invalid buffer while parsing glTF. Loaded file %s length %lu, expected %lu", uri_string, data.count, expected_bytes); } @@ -168,7 +168,7 @@ struct texture *parse_textures(const cJSON *data, size_t *amount, const struct b if (!cJSON_IsString(uri)) break; char *uri_string = uri->valuestring; //TODO: Add name to texture - images[i] = *load_texture(uri_string, (file_data){ 0 }, NULL); //FIXME + images[i] = *load_texture(uri_string, (file_data){ 0 }); //FIXME } else { const cJSON *buffer_view = cJSON_GetObjectItem(element, "bufferView"); const cJSON *mime_type = cJSON_GetObjectItem(element, "mimeType"); @@ -191,7 +191,7 @@ struct mesh *parse_glb_meshes(const char *data, size_t *meshCount) { } struct mesh *parse_glTF_meshes(const char *filePath, size_t *meshCount) { - file_data contents = file_load(filePath, NULL); //FIXME cache + file_data contents = file_load(filePath); if (stringStartsWith("glTF", (char *)contents.items)) return parse_glb_meshes((char *)contents.items, meshCount); const cJSON *data = cJSON_Parse((char *)contents.items); diff --git a/src/driver/loaders/formats/wavefront/mtlloader.c b/src/driver/loaders/formats/wavefront/mtlloader.c index 61f8a91a..a64c4277 100644 --- a/src/driver/loaders/formats/wavefront/mtlloader.c +++ b/src/driver/loaders/formats/wavefront/mtlloader.c @@ -23,12 +23,14 @@ static struct color parse_color(lineBuffer *line) { return (struct color){ atof(nextToken(line)), atof(nextToken(line)), atof(nextToken(line)), 1.0f }; } -struct material_arr parse_mtllib(const char *filePath, struct file_cache *cache) { - file_data mtllib_text = file_load(filePath, cache); +struct material_arr parse_mtllib(const char *filePath) { + file_data mtllib_text = file_load(filePath); if (!mtllib_text.count) return (struct material_arr){ 0 }; logr(debug, "Loading MTL at %s\n", filePath); textBuffer *file = newTextBuffer((char *)mtllib_text.items); file_free(&mtllib_text); + + char *asset_path = get_file_path(filePath); struct material_arr materials = { 0 }; struct material *current = NULL; @@ -75,11 +77,17 @@ struct material_arr parse_mtllib(const char *filePath, struct file_cache *cache) } else if (stringEquals(first, "Ni")) { current->IOR = atof(nextToken(&line)); } else if (stringEquals(first, "map_Kd") || stringEquals(first, "map_Ka")) { - current->texture_path = stringCopy(nextToken(&line)); + char *path = stringConcat(asset_path, peekNextToken(&line)); + windowsFixPath(path); + current->texture_path = path; } else if (stringEquals(first, "norm") || stringEquals(first, "bump") || stringEquals(first, "map_bump")) { - current->normal_path = stringCopy(nextToken(&line)); + char *path = stringConcat(asset_path, peekNextToken(&line)); + windowsFixPath(path); + current->normal_path = path; } else if (stringEquals(first, "map_Ns")) { - current->specular_path = stringCopy(nextToken(&line)); + char *path = stringConcat(asset_path, peekNextToken(&line)); + windowsFixPath(path); + current->specular_path = path; } else { char *fileName = get_file_name(filePath); logr(debug, "Unknown statement \"%s\" in MTL \"%s\" on line %zu\n", @@ -88,6 +96,8 @@ struct material_arr parse_mtllib(const char *filePath, struct file_cache *cache) } head = nextLine(file); } + + if (asset_path) free(asset_path); destroyTextBuffer(file); logr(debug, "Found %zu materials\n", materials.count); diff --git a/src/driver/loaders/formats/wavefront/mtlloader.h b/src/driver/loaders/formats/wavefront/mtlloader.h index e1338309..cd4b1858 100644 --- a/src/driver/loaders/formats/wavefront/mtlloader.h +++ b/src/driver/loaders/formats/wavefront/mtlloader.h @@ -8,7 +8,6 @@ #pragma once -struct file_cache; struct material_arr; -struct material_arr parse_mtllib(const char *filePath, struct file_cache *cache); +struct material_arr parse_mtllib(const char *filePath); diff --git a/src/driver/loaders/formats/wavefront/wavefront.c b/src/driver/loaders/formats/wavefront/wavefront.c index e8969007..bdab8173 100644 --- a/src/driver/loaders/formats/wavefront/wavefront.c +++ b/src/driver/loaders/formats/wavefront/wavefront.c @@ -100,8 +100,8 @@ float get_poly_area(struct poly *p, struct vector *vertices) { return vec_length(cross) / 2.0f; } -struct mesh_parse_result parse_wavefront(const char *file_path, struct file_cache *cache) { - file_data input = file_load(file_path, cache); +struct mesh_parse_result parse_wavefront(const char *file_path) { + file_data input = file_load(file_path); if (!input.items) return (struct mesh_parse_result){ 0 }; logr(debug, "Loading OBJ %s\n", file_path); textBuffer *file = newTextBuffer((char *)input.items); @@ -165,7 +165,7 @@ struct mesh_parse_result parse_wavefront(const char *file_path, struct file_cach windowsFixPath(mtlFilePath); //FIXME: Handle multiple mtllibs ASSERT(!result.materials.count); - result.materials = parse_mtllib(mtlFilePath, cache); + result.materials = parse_mtllib(mtlFilePath); free(mtlFilePath); } else { char *fileName = get_file_name(file_path); diff --git a/src/driver/loaders/formats/wavefront/wavefront.h b/src/driver/loaders/formats/wavefront/wavefront.h index 28385567..1e0fa963 100644 --- a/src/driver/loaders/formats/wavefront/wavefront.h +++ b/src/driver/loaders/formats/wavefront/wavefront.h @@ -10,4 +10,4 @@ struct file_cache; -struct mesh_parse_result parse_wavefront(const char *file_path, struct file_cache *cache); +struct mesh_parse_result parse_wavefront(const char *file_path); diff --git a/src/driver/loaders/meshloader.c b/src/driver/loaders/meshloader.c index 32ad17b5..36e30f81 100644 --- a/src/driver/loaders/meshloader.c +++ b/src/driver/loaders/meshloader.c @@ -13,10 +13,10 @@ #include "../../utils/fileio.h" #include "../../utils/logging.h" -struct mesh_parse_result load_meshes_from_file(const char *file_path, struct file_cache *cache) { +struct mesh_parse_result load_meshes_from_file(const char *file_path) { switch (guess_file_type(file_path)) { case obj: - return parse_wavefront(file_path, cache); + return parse_wavefront(file_path); default: logr(warning, "%s: Unknown file type, skipping.\n", file_path); return (struct mesh_parse_result){ 0 }; diff --git a/src/driver/loaders/meshloader.h b/src/driver/loaders/meshloader.h index 2c608d8d..f13d1a53 100644 --- a/src/driver/loaders/meshloader.h +++ b/src/driver/loaders/meshloader.h @@ -10,12 +10,10 @@ #include "../../datatypes/mesh.h" -struct file_cache; - struct mesh_parse_result { struct mesh_arr meshes; struct material_arr materials; struct vertex_buffer geometry; }; -struct mesh_parse_result load_meshes_from_file(const char *file_path, struct file_cache *cache); +struct mesh_parse_result load_meshes_from_file(const char *file_path); diff --git a/src/driver/main.c b/src/driver/main.c index c0d670bc..a2e4bb7f 100644 --- a/src/driver/main.c +++ b/src/driver/main.c @@ -88,19 +88,19 @@ int main(int argc, char *argv[]) { } int ret = 0; - file_data input = args_is_set(opts, "inputFile") ? file_load(args_path(opts), NULL) : read_stdin(); - if (!input.count) { + file_data input_bytes = args_is_set(opts, "inputFile") ? file_load(args_path(opts)) : read_stdin(); + if (!input_bytes.count) { logr(info, "No input provided, exiting.\n"); ret = -1; goto done; } char size_buf[64]; - logr(info, "%s of input JSON loaded from %s, parsing.\n", human_file_size(input.count, size_buf), args_is_set(opts, "inputFile") ? "file" : "stdin"); + logr(info, "%s of input JSON loaded from %s, parsing.\n", human_file_size(input_bytes.count, size_buf), args_is_set(opts, "inputFile") ? "file" : "stdin"); struct timeval json_timer; timer_start(&json_timer); - cJSON *scene = cJSON_ParseWithLength((const char *)input.items, input.count); + cJSON *input_json = cJSON_ParseWithLength((const char *)input_bytes.items, input_bytes.count); size_t json_ms = timer_get_ms(json_timer); - if (!scene) { + if (!input_json) { const char *errptr = cJSON_GetErrorPtr(); if (errptr) { logr(warning, "Failed to parse JSON\n"); @@ -110,13 +110,13 @@ int main(int argc, char *argv[]) { } logr(info, "JSON parse took %lums\n", json_ms); - file_free(&input); + file_free(&input_bytes); if (args_is_set(opts, "nodes_list")) { cr_renderer_set_str_pref(renderer, cr_renderer_node_list, args_string(opts, "nodes_list")); } - if (parse_json(renderer, scene) < 0) { + if (parse_json(renderer, input_json) < 0) { logr(warning, "Scene parse failed, exiting.\n"); ret = -1; goto done; @@ -179,80 +179,18 @@ int main(int argc, char *argv[]) { } } - // 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(opts, "nodes_list")) { - // Stash a cache of scene data here - // Apply overrides to the cache here - if (args_is_set(opts, "samples_override")) { - cJSON *renderer = cJSON_GetObjectItem(scene, "renderer"); - if (cJSON_IsObject(renderer)) { - int samples = args_int(opts, "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(opts, "dims_override")) { - cJSON *renderer = cJSON_GetObjectItem(scene, "renderer"); - if (cJSON_IsObject(renderer)) { - int width = args_int(opts, "dims_width"); - int height = args_int(opts, "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(opts, "tiledims_override")) { - cJSON *renderer = cJSON_GetObjectItem(scene, "renderer"); - if (cJSON_IsObject(renderer)) { - int width = args_int(opts, "tile_width"); - int height = args_int(opts, "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 (args_is_set(opts, "cam_index")) { - cJSON_AddItemToObject(scene, "selected_camera", cJSON_CreateNumber(args_int(opts, "cam_index"))); - } - - // Store cache. This is what gets sent to worker nodes. - // FIXME: This doesn't need to be stored in renderer - char *cache = cJSON_PrintUnformatted(scene); - cr_renderer_set_str_pref(renderer, cr_renderer_scene_cache, cache); - free(cache); - } - cr_renderer_set_callbacks(renderer, (struct cr_renderer_callbacks){ .cr_renderer_on_start = on_start, .cr_renderer_on_stop = on_stop, .cr_renderer_status = status, .user_data = &(struct usr_data){ - .p = sdl_parse(cJSON_GetObjectItem(scene, "display")), + .p = sdl_parse(cJSON_GetObjectItem(input_json, "display")), .r = renderer } }); logr(debug, "Deleting JSON...\n"); - cJSON_Delete(scene); + cJSON_Delete(input_json); logr(debug, "Deleting done\n"); struct timeval timer; diff --git a/src/driver/node_parse.c b/src/driver/node_parse.c index 9ba2d277..d03ba08d 100644 --- a/src/driver/node_parse.c +++ b/src/driver/node_parse.c @@ -91,6 +91,14 @@ struct cr_value_node *cr_value_node_build(const struct cJSON *node) { }); } + // Note: Fallback for serializer + if (stringEquals(type->valuestring, "constant")) { + return vn_alloc((struct cr_value_node){ + .type = cr_vn_constant, + .arg.constant = cJSON_GetNumberValue(cJSON_GetObjectItem(node, "value")) + }); + } + if (stringEquals(type->valuestring, "fresnel")) { return vn_alloc((struct cr_value_node){ .type = cr_vn_fresnel, @@ -124,21 +132,23 @@ struct cr_value_node *cr_value_node_build(const struct cJSON *node) { }); } if (stringEquals(type->valuestring, "vec_to_value")) { + const cJSON *comp = cJSON_GetObjectItem(node, "component"); return vn_alloc((struct cr_value_node){ .type = cr_vn_vec_to_value, .arg.vec_to_value = { .vec = cr_vector_node_build(cJSON_GetObjectItem(node, "vector")), - .comp = value_node_component(cJSON_GetObjectItem(node, "component")) + .comp = cJSON_IsNumber(comp) ? comp->valueint : value_node_component(comp) // For serializer } }); } if (stringEquals(type->valuestring, "math")) { + const cJSON *op = cJSON_GetObjectItem(node, "op"); return vn_alloc((struct cr_value_node){ .type = cr_vn_math, .arg.math = { .A = cr_value_node_build(cJSON_GetObjectItem(node, "a")), .B = cr_value_node_build(cJSON_GetObjectItem(node, "b")), - .op = value_node_op(cJSON_GetObjectItem(node, "op")) + .op = cJSON_IsNumber(op) ? op->valueint : value_node_op(op) // For serializer } }); } @@ -234,6 +244,12 @@ struct cr_color_node *cr_color_node_build(const struct cJSON *desc) { options |= NO_BILINEAR; } + // Fallback for serializer, specify options explicitly + const cJSON *opt = cJSON_GetObjectItem(desc, "options"); + if (cJSON_IsNumber(opt)) { + options = opt->valueint; + } + const cJSON *path = cJSON_GetObjectItem(desc, "path"); if (cJSON_IsString(path)) { return cn_alloc((struct cr_color_node){ @@ -254,7 +270,22 @@ struct cr_color_node *cr_color_node_build(const struct cJSON *desc) { } const cJSON *type = cJSON_GetObjectItem(desc, "type"); if (cJSON_IsString(type)) { - // Oo, what's this? + if (stringEquals(type->valuestring, "constant")) { + struct color c = color_parse(cJSON_GetObjectItem(desc, "color")); + return cn_alloc((struct cr_color_node){ + .type = cr_cn_constant, + .arg.constant = { c.red, c.green, c.blue, c.alpha } + }); + } + if (!stringEquals(type->valuestring, "image")) { + if (cJSON_IsString(path)) { + return cn_alloc((struct cr_color_node){ + .type = cr_cn_image, + .arg.image.full_path = stringCopy(path->valuestring), + .arg.image.options = options + }); + } + } if (stringEquals(type->valuestring, "checkerboard")) { return cn_alloc((struct cr_color_node){ .type = cr_cn_checkerboard, @@ -304,6 +335,15 @@ struct cr_color_node *cr_color_node_build(const struct cJSON *desc) { .arg.vec_to_color.vec = cr_vector_node_build(cJSON_GetObjectItem(desc, "vector")) }); } + if (stringEquals(type->valuestring, "gradient")) { + return cn_alloc((struct cr_color_node){ + .type = cr_cn_gradient, + .arg.gradient = { + .a = cr_color_node_build(cJSON_GetObjectItem(desc, "down")), + .b = cr_color_node_build(cJSON_GetObjectItem(desc, "up")), + } + }); + } } logr(warning, "Failed to parse textureNode. Here's a dump:\n"); @@ -422,6 +462,15 @@ struct cr_vector_node *cr_vector_node_build(const struct cJSON *node) { return NULL; } + // Note: Fallback for serializer + if (stringEquals(type->valuestring, "constant")) { + struct vector v = parseVector(cJSON_GetObjectItem(node, "vec")); + return vecn_alloc((struct cr_vector_node){ + .type = cr_vec_constant, + .arg.constant = { v.x, v.y, v.z } + }); + } + if (stringEquals(type->valuestring, "normal")) { return vecn_alloc((struct cr_vector_node){ .type = cr_vec_normal @@ -434,6 +483,7 @@ struct cr_vector_node *cr_vector_node_build(const struct cJSON *node) { } if (stringEquals(type->valuestring, "vecmath")) { + const cJSON *op = cJSON_GetObjectItem(node, "op"); return vecn_alloc((struct cr_vector_node){ .type = cr_vec_vecmath, .arg.vecmath = { @@ -441,7 +491,7 @@ struct cr_vector_node *cr_vector_node_build(const struct cJSON *node) { .B = cr_vector_node_build(cJSON_GetObjectItem(node, "b")), .C = cr_vector_node_build(cJSON_GetObjectItem(node, "c")), .f = cr_value_node_build(cJSON_GetObjectItem(node, "f")), - .op = parseVectorOp(cJSON_GetObjectItem(node, "op")) + .op = cJSON_IsNumber(op) ? op->valueint : parseVectorOp(op) // Note: Fallback for serializer } }); } @@ -486,6 +536,7 @@ static struct cr_shader_node *bn_alloc(struct cr_shader_node d) { memcpy(desc, &d, sizeof(*desc)); return desc; } + struct cr_shader_node *cr_shader_node_build(const struct cJSON *node) { if (!node) return NULL; const cJSON *type = cJSON_GetObjectItem(node, "type"); @@ -561,27 +612,37 @@ struct cr_shader_node *cr_shader_node_build(const struct cJSON *node) { .arg.translucent.color = cr_color_node_build(cJSON_GetObjectItem(node, "color")) }); } else if (stringEquals(type->valuestring, "background")) { - struct cr_color_node *hdr = NULL; - struct cr_color_node *gradient = NULL; - // Special cases for scene.ambientColor - const cJSON *hdr_in = cJSON_GetObjectItem(node, "hdr"); - if (cJSON_IsString(hdr_in)) { - hdr = cn_alloc((struct cr_color_node){ - .type = cr_cn_image, - .arg.image.full_path = stringCopy(hdr_in->valuestring), - .arg.image.options = 0 // TODO: Options? - }); - } - const cJSON *down = cJSON_GetObjectItem(node, "down"); - const cJSON *up = cJSON_GetObjectItem(node, "up"); - if (!hdr && cJSON_IsObject(down) && cJSON_IsObject(up)) { - gradient = cn_alloc((struct cr_color_node){ - .type = cr_cn_gradient, - .arg.gradient = { - .a = cr_color_node_build(down), - .b = cr_color_node_build(up), - } - }); + // Note: Fallback for serializer + struct cr_color_node *color = NULL; + const cJSON *color_in = cJSON_GetObjectItem(node, "color"); + if (cJSON_IsObject(color_in)) { + // This was generated by the internal serializer. + color = cr_color_node_build(color_in); + } else { + // Normal (ugly) encoding from json + struct cr_color_node *hdr = NULL; + struct cr_color_node *gradient = NULL; + // Special cases for scene.ambientColor + const cJSON *hdr_in = cJSON_GetObjectItem(node, "hdr"); + if (cJSON_IsString(hdr_in)) { + hdr = cn_alloc((struct cr_color_node){ + .type = cr_cn_image, + .arg.image.full_path = stringCopy(hdr_in->valuestring), + .arg.image.options = 0 // TODO: Options? + }); + } + const cJSON *down = cJSON_GetObjectItem(node, "down"); + const cJSON *up = cJSON_GetObjectItem(node, "up"); + if (!hdr && cJSON_IsObject(down) && cJSON_IsObject(up)) { + gradient = cn_alloc((struct cr_color_node){ + .type = cr_cn_gradient, + .arg.gradient = { + .a = cr_color_node_build(down), + .b = cr_color_node_build(up), + } + }); + } + color = hdr ? hdr : gradient; } const cJSON *strength = cJSON_GetObjectItem(node, "strength"); @@ -589,7 +650,7 @@ struct cr_shader_node *cr_shader_node_build(const struct cJSON *node) { return bn_alloc((struct cr_shader_node){ .type = cr_bsdf_background, .arg.background = { - .color = hdr ? hdr : gradient, + .color = color, .pose = cr_vector_node_build(offset), .strength = cr_value_node_build(strength), } diff --git a/src/driver/sdl.c b/src/driver/sdl.c index 5d8e7b75..faeb27f5 100644 --- a/src/driver/sdl.c +++ b/src/driver/sdl.c @@ -128,7 +128,7 @@ struct sdl_window { static void setWindowIcon(struct sdl_window *w) { #ifndef NO_LOGO - struct texture *icon = load_texture("logo.h", (file_data){ .items = logo_png_data, .count = logo_png_data_len }, NULL); + struct texture *icon = load_texture("logo.h", (file_data){ .items = logo_png_data, .count = logo_png_data_len }); uint32_t rmask; uint32_t gmask; uint32_t bmask; diff --git a/src/nodes/bsdfnode.c b/src/nodes/bsdfnode.c index 6d89d411..d2420930 100644 --- a/src/nodes/bsdfnode.c +++ b/src/nodes/bsdfnode.c @@ -15,61 +15,44 @@ #include "bsdfnode.h" #include -struct bsdf_buffer *bsdf_buf_ref(struct bsdf_buffer *buf) { - if (buf) { - buf->refs++; - return buf; - } - struct bsdf_buffer *new = calloc(1, sizeof(*new)); - new->refs = 1; - return new; -} - -void bsdf_buf_unref(struct bsdf_buffer *buf) { - if (!buf) return; - if (--buf->refs) return; - bsdf_node_ptr_arr_free(&buf->bsdfs); - free(buf); -} - -const struct bsdfNode *build_bsdf_node(struct cr_renderer *r_ext, const struct cr_shader_node *desc) { - if (!r_ext) return NULL; - struct renderer *r = (struct renderer *)r_ext; - struct node_storage s = r->scene->storage; +const struct bsdfNode *build_bsdf_node(struct cr_scene *s_ext, const struct cr_shader_node *desc) { + if (!s_ext) return NULL; + struct world *scene = (struct world *)s_ext; + struct node_storage s = scene->storage; if (!desc) return warningBsdf(&s); switch (desc->type) { case cr_bsdf_diffuse: - return newDiffuse(&s, build_color_node(r_ext, desc->arg.diffuse.color)); + return newDiffuse(&s, build_color_node(s_ext, desc->arg.diffuse.color)); case cr_bsdf_metal: - return newMetal(&s, build_color_node(r_ext, desc->arg.metal.color), build_value_node(r_ext, desc->arg.metal.roughness)); + return newMetal(&s, build_color_node(s_ext, desc->arg.metal.color), build_value_node(s_ext, desc->arg.metal.roughness)); case cr_bsdf_glass: return newGlass(&s, - build_color_node(r_ext, desc->arg.glass.color), - build_value_node(r_ext, desc->arg.glass.roughness), - build_value_node(r_ext, desc->arg.glass.IOR)); + build_color_node(s_ext, desc->arg.glass.color), + build_value_node(s_ext, desc->arg.glass.roughness), + build_value_node(s_ext, desc->arg.glass.IOR)); case cr_bsdf_plastic: return newPlastic(&s, - build_color_node(r_ext, desc->arg.plastic.color), - build_value_node(r_ext, desc->arg.plastic.roughness), - build_value_node(r_ext, desc->arg.plastic.IOR)); + build_color_node(s_ext, desc->arg.plastic.color), + build_value_node(s_ext, desc->arg.plastic.roughness), + build_value_node(s_ext, desc->arg.plastic.IOR)); case cr_bsdf_mix: return newMix(&s, - build_bsdf_node(r_ext, desc->arg.mix.A), - build_bsdf_node(r_ext, desc->arg.mix.B), - build_value_node(r_ext, desc->arg.mix.factor)); + build_bsdf_node(s_ext, desc->arg.mix.A), + build_bsdf_node(s_ext, desc->arg.mix.B), + build_value_node(s_ext, desc->arg.mix.factor)); case cr_bsdf_add: - return newAdd(&s, build_bsdf_node(r_ext, desc->arg.add.A), build_bsdf_node(r_ext, desc->arg.add.B)); + return newAdd(&s, build_bsdf_node(s_ext, desc->arg.add.A), build_bsdf_node(s_ext, desc->arg.add.B)); case cr_bsdf_transparent: - return newTransparent(&s, build_color_node(r_ext, desc->arg.transparent.color)); + return newTransparent(&s, build_color_node(s_ext, desc->arg.transparent.color)); case cr_bsdf_emissive: - return newEmission(&s, build_color_node(r_ext, desc->arg.emissive.color), build_value_node(r_ext, desc->arg.emissive.strength)); + return newEmission(&s, build_color_node(s_ext, desc->arg.emissive.color), build_value_node(s_ext, desc->arg.emissive.strength)); case cr_bsdf_translucent: - return newTranslucent(&s, build_color_node(r_ext, desc->arg.translucent.color)); + return newTranslucent(&s, build_color_node(s_ext, desc->arg.translucent.color)); case cr_bsdf_background: { return newBackground(&s, - build_color_node(r_ext, desc->arg.background.color), - build_value_node(r_ext, desc->arg.background.strength), - build_vector_node(r_ext, desc->arg.background.pose)); + build_color_node(s_ext, desc->arg.background.color), + build_value_node(s_ext, desc->arg.background.strength), + build_vector_node(s_ext, desc->arg.background.pose)); } default: return warningBsdf(&s); diff --git a/src/nodes/bsdfnode.h b/src/nodes/bsdfnode.h index cc7b6926..88a87778 100644 --- a/src/nodes/bsdfnode.h +++ b/src/nodes/bsdfnode.h @@ -33,13 +33,16 @@ struct bsdfNode { typedef const struct bsdfNode * bsdf_node_ptr; dyn_array_def(bsdf_node_ptr); +typedef struct cr_shader_node * cr_shader_node_ptr; +dyn_array_def(cr_shader_node_ptr); + struct bsdf_buffer { struct bsdf_node_ptr_arr bsdfs; - size_t refs; + struct cr_shader_node_ptr_arr descriptions; }; -struct bsdf_buffer *bsdf_buf_ref(struct bsdf_buffer *buf); -void bsdf_buf_unref(struct bsdf_buffer *buf); +typedef struct bsdf_buffer bsdf_buffer; +dyn_array_def(bsdf_buffer); #include "shaders/diffuse.h" #include "shaders/glass.h" @@ -54,4 +57,4 @@ void bsdf_buf_unref(struct bsdf_buffer *buf); #include "shaders/translucent.h" const struct bsdfNode *warningBsdf(const struct node_storage *s); -const struct bsdfNode *build_bsdf_node(struct cr_renderer *r_ext, const struct cr_shader_node *desc); +const struct bsdfNode *build_bsdf_node(struct cr_scene *s_ext, const struct cr_shader_node *desc); diff --git a/src/nodes/colornode.c b/src/nodes/colornode.c index 0c52fcb3..6519b4b1 100644 --- a/src/nodes/colornode.c +++ b/src/nodes/colornode.c @@ -23,10 +23,10 @@ // return newConstantTexture(s, g_black_color); // } -const struct colorNode *build_color_node(struct cr_renderer *r_ext, const struct cr_color_node *desc) { - if (!r_ext || !desc) return NULL; - struct renderer *r = (struct renderer *)r_ext; - struct node_storage s = r->scene->storage; +const struct colorNode *build_color_node(struct cr_scene *s_ext, const struct cr_color_node *desc) { + if (!s_ext || !desc) return NULL; + struct world *scene = (struct world *)s_ext; + struct node_storage s = scene->storage; switch (desc->type) { case cr_cn_constant: @@ -38,41 +38,53 @@ const struct colorNode *build_color_node(struct cr_renderer *r_ext, const struct desc->arg.constant.a }); case cr_cn_image: { - char *full = stringConcat(r->prefs.assetPath, desc->arg.image.full_path); - windowsFixPath(full); - file_data tex; - if (cache_contains(r->state.file_cache, full)) { - tex = cache_load(r->state.file_cache, full); - } else { - tex = file_load(full, NULL); - cache_store(r->state.file_cache, full, tex.items, tex.count); + // FIXME: Hack, figure out a consistent way to deal with relative paths everywhere + char *full = NULL; + if (!stringStartsWith(scene->asset_path, desc->arg.image.full_path)) { + full = stringConcat(scene->asset_path, desc->arg.image.full_path); + windowsFixPath(full); } - const struct colorNode *new = newImageTexture(&s, load_texture(full, tex, &r->scene->storage.node_pool), desc->arg.image.options); - free(full); - file_free(&tex); + const char *path = full ? full : desc->arg.image.full_path; + file_data data = file_load(path); + struct texture *tex = NULL; + for (size_t i = 0; i < scene->textures.count; ++i) { + if (stringEquals(scene->textures.items[i].path, path)) { + tex = scene->textures.items[i].t; + } + } + if (!tex) { + tex = load_texture(path, data); + texture_asset_arr_add(&scene->textures, (struct texture_asset){ + .path = stringCopy(path), + .t = tex + }); + } + file_free(&data); + const struct colorNode *new = newImageTexture(&s, tex, desc->arg.image.options); + if (full) free(full); return new; } case cr_cn_checkerboard: return newCheckerBoardTexture(&s, - build_color_node(r_ext, desc->arg.checkerboard.a), - build_color_node(r_ext, desc->arg.checkerboard.b), - build_value_node(r_ext, desc->arg.checkerboard.scale)); + build_color_node(s_ext, desc->arg.checkerboard.a), + build_color_node(s_ext, desc->arg.checkerboard.b), + build_value_node(s_ext, desc->arg.checkerboard.scale)); case cr_cn_blackbody: - return newBlackbody(&s, build_value_node(r_ext, desc->arg.blackbody.degrees)); + return newBlackbody(&s, build_value_node(s_ext, desc->arg.blackbody.degrees)); case cr_cn_split: - return newSplitValue(&s, build_value_node(r_ext, desc->arg.split.node)); + return newSplitValue(&s, build_value_node(s_ext, desc->arg.split.node)); case cr_cn_rgb: return newCombineRGB(&s, - build_value_node(r_ext, desc->arg.rgb.red), - build_value_node(r_ext, desc->arg.rgb.green), - build_value_node(r_ext, desc->arg.rgb.blue)); + build_value_node(s_ext, desc->arg.rgb.red), + build_value_node(s_ext, desc->arg.rgb.green), + build_value_node(s_ext, desc->arg.rgb.blue)); case cr_cn_hsl: return newCombineHSL(&s, - build_value_node(r_ext, desc->arg.hsl.H), - build_value_node(r_ext, desc->arg.hsl.S), - build_value_node(r_ext, desc->arg.hsl.L)); + build_value_node(s_ext, desc->arg.hsl.H), + build_value_node(s_ext, desc->arg.hsl.S), + build_value_node(s_ext, desc->arg.hsl.L)); case cr_cn_vec_to_color: - return newVecToColor(&s, build_vector_node(r_ext, desc->arg.vec_to_color.vec)); + return newVecToColor(&s, build_vector_node(s_ext, desc->arg.vec_to_color.vec)); default: return NULL; }; diff --git a/src/nodes/colornode.h b/src/nodes/colornode.h index 3d4e2949..1a0f3620 100644 --- a/src/nodes/colornode.h +++ b/src/nodes/colornode.h @@ -34,4 +34,4 @@ struct colorNode { // const struct colorNode *unknownTextureNode(const struct node_storage *s); -const struct colorNode *build_color_node(struct cr_renderer *r_ext, const struct cr_color_node *desc); +const struct colorNode *build_color_node(struct cr_scene *s_ext, const struct cr_color_node *desc); diff --git a/src/nodes/valuenode.c b/src/nodes/valuenode.c index 9931eb45..781bec8a 100644 --- a/src/nodes/valuenode.c +++ b/src/nodes/valuenode.c @@ -59,36 +59,36 @@ const struct valueNode *newConstantValue(const struct node_storage *s, float val }); } -const struct valueNode *build_value_node(struct cr_renderer *r_ext, const struct cr_value_node *desc) { - if (!r_ext || !desc) return NULL; - struct renderer *r = (struct renderer *)r_ext; - struct node_storage s = r->scene->storage; +const struct valueNode *build_value_node(struct cr_scene *s_ext, const struct cr_value_node *desc) { + if (!s_ext || !desc) return NULL; + struct world *scene = (struct world *)s_ext; + struct node_storage s = scene->storage; switch (desc->type) { case cr_vn_constant: return newConstantValue(&s, desc->arg.constant); case cr_vn_fresnel: - return newFresnel(&s, build_value_node(r_ext, desc->arg.fresnel.IOR), build_vector_node(r_ext, desc->arg.fresnel.normal)); + return newFresnel(&s, build_value_node(s_ext, desc->arg.fresnel.IOR), build_vector_node(s_ext, desc->arg.fresnel.normal)); case cr_vn_map_range: return newMapRange(&s, - build_value_node(r_ext, desc->arg.map_range.input_value), - build_value_node(r_ext, desc->arg.map_range.from_min), - build_value_node(r_ext, desc->arg.map_range.from_max), - build_value_node(r_ext, desc->arg.map_range.to_min), - build_value_node(r_ext, desc->arg.map_range.to_max)); + build_value_node(s_ext, desc->arg.map_range.input_value), + build_value_node(s_ext, desc->arg.map_range.from_min), + build_value_node(s_ext, desc->arg.map_range.from_max), + build_value_node(s_ext, desc->arg.map_range.to_min), + build_value_node(s_ext, desc->arg.map_range.to_max)); case cr_vn_raylength: return newRayLength(&s); case cr_vn_alpha: - return newAlpha(&s, build_color_node(r_ext, desc->arg.alpha.color)); + return newAlpha(&s, build_color_node(s_ext, desc->arg.alpha.color)); case cr_vn_vec_to_value: - return newVecToValue(&s, build_vector_node(r_ext, desc->arg.vec_to_value.vec), desc->arg.vec_to_value.comp); + return newVecToValue(&s, build_vector_node(s_ext, desc->arg.vec_to_value.vec), desc->arg.vec_to_value.comp); case cr_vn_math: return newMath(&s, - build_value_node(r_ext, desc->arg.math.A), - build_value_node(r_ext, desc->arg.math.B), + build_value_node(s_ext, desc->arg.math.A), + build_value_node(s_ext, desc->arg.math.B), desc->arg.math.op); case cr_vn_grayscale: - return newGrayscaleConverter(&s, build_color_node(r_ext, desc->arg.grayscale.color)); + return newGrayscaleConverter(&s, build_color_node(s_ext, desc->arg.grayscale.color)); default: return NULL; } diff --git a/src/nodes/valuenode.h b/src/nodes/valuenode.h index fd19f6eb..0c126522 100644 --- a/src/nodes/valuenode.h +++ b/src/nodes/valuenode.h @@ -28,4 +28,4 @@ struct valueNode { const struct valueNode *newConstantValue(const struct node_storage *s, float value); -const struct valueNode *build_value_node(struct cr_renderer *r_ext, const struct cr_value_node *desc); +const struct valueNode *build_value_node(struct cr_scene *s_ext, const struct cr_value_node *desc); diff --git a/src/nodes/vectornode.c b/src/nodes/vectornode.c index 6ca6568b..6425370e 100644 --- a/src/nodes/vectornode.c +++ b/src/nodes/vectornode.c @@ -99,10 +99,10 @@ const struct vectorNode *newConstantUV(const struct node_storage *s, const struc }); } -const struct vectorNode *build_vector_node(struct cr_renderer *r_ext, const struct cr_vector_node *desc) { - if (!r_ext || !desc) return NULL; - struct renderer *r = (struct renderer *)r_ext; - struct node_storage s = r->scene->storage; +const struct vectorNode *build_vector_node(struct cr_scene *s_ext, const struct cr_vector_node *desc) { + if (!s_ext || !desc) return NULL; + struct world *scene = (struct world *)s_ext; + struct node_storage s = scene->storage; switch (desc->type) { case cr_vec_constant: @@ -113,16 +113,16 @@ const struct vectorNode *build_vector_node(struct cr_renderer *r_ext, const stru return newUV(&s); case cr_vec_vecmath: return newVecMath(&s, - build_vector_node(r_ext, desc->arg.vecmath.A), - build_vector_node(r_ext, desc->arg.vecmath.B), - build_vector_node(r_ext, desc->arg.vecmath.C), - build_value_node(r_ext, desc->arg.vecmath.f), + build_vector_node(s_ext, desc->arg.vecmath.A), + build_vector_node(s_ext, desc->arg.vecmath.B), + build_vector_node(s_ext, desc->arg.vecmath.C), + build_value_node(s_ext, desc->arg.vecmath.f), desc->arg.vecmath.op); case cr_vec_mix: return new_vec_mix(&s, - build_vector_node(r_ext, desc->arg.vec_mix.A), - build_vector_node(r_ext, desc->arg.vec_mix.B), - build_value_node(r_ext, desc->arg.vec_mix.factor)); + build_vector_node(s_ext, desc->arg.vec_mix.A), + build_vector_node(s_ext, desc->arg.vec_mix.B), + build_value_node(s_ext, desc->arg.vec_mix.factor)); default: return NULL; }; diff --git a/src/nodes/vectornode.h b/src/nodes/vectornode.h index 2d9b5d40..ef0d4719 100644 --- a/src/nodes/vectornode.h +++ b/src/nodes/vectornode.h @@ -34,4 +34,4 @@ struct vectorNode { const struct vectorNode *newConstantVector(const struct node_storage *storage, struct vector vector); const struct vectorNode *newConstantUV(const struct node_storage *s, const struct coord c); -const struct vectorNode *build_vector_node(struct cr_renderer *r_ext, const struct cr_vector_node *desc); +const struct vectorNode *build_vector_node(struct cr_scene *s_ext, const struct cr_vector_node *desc); diff --git a/src/renderer/instance.h b/src/renderer/instance.h index 6f0601df..e18eb021 100644 --- a/src/renderer/instance.h +++ b/src/renderer/instance.h @@ -24,6 +24,7 @@ struct hitRecord; struct instance { struct transform composite; struct bsdf_buffer *bbuf; + size_t bbuf_idx; bool emits_light; bool (*intersectFn)(const struct instance *, const struct lightRay *, struct hitRecord *, sampler *); void (*getBBoxAndCenterFn)(const struct instance *, struct boundingBox *, struct vector *); diff --git a/src/renderer/renderer.c b/src/renderer/renderer.c index 44120814..f7718151 100644 --- a/src/renderer/renderer.c +++ b/src/renderer/renderer.c @@ -431,7 +431,7 @@ void *renderThread(void *arg) { return 0; } -static struct prefs defaults() { +struct prefs default_prefs() { return (struct prefs){ .tileOrder = ro_from_middle, .threads = getSysCores() + 2, @@ -441,7 +441,6 @@ static struct prefs defaults() { .tileWidth = 32, .tileHeight = 32, .imgFilePath = stringCopy("./"), - .assetPath = stringCopy("./"), .imgFileName = stringCopy("rendered"), .imgCount = 0, .imgType = png, @@ -450,10 +449,12 @@ static struct prefs defaults() { struct renderer *renderer_new() { struct renderer *r = calloc(1, sizeof(*r)); - r->prefs = defaults(); + r->prefs = default_prefs(); r->state.finishedPasses = 1; + // Move these elsewhere r->scene = calloc(1, sizeof(*r->scene)); + r->scene->asset_path = stringCopy("./"); r->scene->storage.node_pool = newBlock(NULL, 1024); r->scene->storage.node_table = newHashtable(compareNodes, &r->scene->storage.node_pool); return r; @@ -464,13 +465,8 @@ void renderer_destroy(struct renderer *r) { scene_destroy(r->scene); worker_arr_free(&r->state.workers); render_client_arr_free(&r->state.clients); - if (r->state.file_cache) { - cache_destroy(r->state.file_cache); - free(r->state.file_cache); - } free(r->prefs.imgFileName); free(r->prefs.imgFilePath); - free(r->prefs.assetPath); if (r->prefs.node_list) free(r->prefs.node_list); free(r); } diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h index bd0b06ce..a76c33a1 100644 --- a/src/renderer/renderer.h +++ b/src/renderer/renderer.h @@ -12,7 +12,6 @@ #include "../datatypes/tile.h" #include "../datatypes/image/imagefile.h" #include "../utils/timer.h" -#include "../utils/filecache.h" #include "../utils/platform/thread.h" #include "../utils/protocol/server.h" @@ -49,7 +48,6 @@ struct state { bool saveImage; struct worker_arr workers; struct render_client_arr clients; - struct file_cache *file_cache; // A file cache for network render nodes. NULL if only local render. struct cr_renderer_callbacks cb; }; @@ -71,7 +69,6 @@ struct prefs { size_t selected_camera; char *imgFilePath; char *imgFileName; - char *assetPath; size_t imgCount; enum fileType imgType; char *node_list; @@ -82,11 +79,11 @@ struct renderer { struct world *scene; //Scene to render struct state state; //Internal state struct prefs prefs; //User prefs - char *sceneCache; //Packed scene data that can be passed to workers }; //Initialize a new renderer struct renderer *renderer_new(void); +struct prefs default_prefs(); //Start main render loop struct texture *renderFrame(struct renderer *r); diff --git a/src/utils/filecache.c b/src/utils/filecache.c deleted file mode 100644 index ca5d04f4..00000000 --- a/src/utils/filecache.c +++ /dev/null @@ -1,109 +0,0 @@ -// -// filecache.c -// c-ray -// -// Created by Valtteri Koskivuori on 29/03/2021. -// Copyright © 2021-2023 Valtteri Koskivuori. All rights reserved. -// - -#include "filecache.h" -#include -#include "../vendored/cJSON.h" -#include "base64.h" -#include "string.h" -#include -#include "logging.h" - -bool cache_contains(const struct file_cache *cache, const char *path) { - if (!cache || !path) return false; - for (size_t i = 0; i < cache->files.count; ++i) { - if (stringEquals(path, cache->files.items[i].path)) { - return true; - } - } - return false; -} - -static void file_elem_free(struct file *f) { - if (f->path) free(f->path); - if (f->data.items) { - // File cache data is received over the wire, so it's always malloc'd - // normally, files would use file_free(), which munmap()s, if appropriate. - free(f->data.items); - f->data.items = NULL; - f->data.count = 0; - f->data.capacity = 0; - } -} - -struct file_cache *cache_create(void) { - struct file_cache *cache = calloc(1, sizeof(*cache)); - cache->files.elem_free = file_elem_free; - return cache; -} - -void cache_store(struct file_cache *cache, const char *path, const void *data, size_t length) { - if (!cache || !path || !data) return; - if (cache_contains(cache, path)) { - logr(debug, "File %s already cached, skipping.\n", path); - return; - } - struct file file; - file.path = stringCopy(path); - file.data = (file_data){ - .items = malloc(length + 1), - .count = length, - .capacity = length, - }; - memcpy(file.data.items, data, length + 1); - file_arr_add(&cache->files, file); - logr(debug, "Cached file %s\n", path); -} - -file_data cache_load(const struct file_cache *cache, const char *path) { - for (size_t i = 0; i < cache->files.count; ++i) { - if (stringEquals(path, cache->files.items[i].path)) { - logr(debug, "Retrieving file %s\n", path); - return cache->files.items[i].data; - } - } - logr(debug, "File %s not found in cache\n", path); - return (file_data){ 0 }; -} - -char *cache_encode(const struct file_cache *cache) { - cJSON *fileCache = cJSON_CreateArray(); - for (size_t i = 0; i < cache->files.count; ++i) { - cJSON *record = cJSON_CreateObject(); - char *encoded = b64encode(cache->files.items[i].data.items, cache->files.items[i].data.count); - cJSON_AddStringToObject(record, "path", cache->files.items[i].path); - cJSON_AddStringToObject(record, "data", encoded); - free(encoded); - cJSON_AddItemToArray(fileCache, record); - } - char *final = cJSON_PrintUnformatted(fileCache); - cJSON_Delete(fileCache); - return final; -} - -//FIXME: Are we sure this can't have an error to be returned? -struct file_cache *cache_decode(const char *data) { - cJSON *receivedCache = cJSON_Parse(data); - const cJSON *record = NULL; - struct file_cache *cache = cache_create(); - cJSON_ArrayForEach(record, receivedCache) { - cJSON *path = cJSON_GetObjectItem(record, "path"); - cJSON *data = cJSON_GetObjectItem(record, "data"); - size_t datalen = 0; - void *decoded = b64decode(data->valuestring, strlen(data->valuestring), &datalen); - cache_store(cache, path->valuestring, decoded, datalen); - free(decoded); - } - cJSON_Delete(receivedCache); - return cache; -} - -void cache_destroy(struct file_cache *cache) { - file_arr_free(&cache->files); - logr(debug, "Destroyed cache\n"); -} diff --git a/src/utils/filecache.h b/src/utils/filecache.h deleted file mode 100644 index a1321baf..00000000 --- a/src/utils/filecache.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// filecache.h -// c-ray -// -// Created by Valtteri Koskivuori on 29/03/2021. -// Copyright © 2021-2023 Valtteri Koskivuori. All rights reserved. -// - -#pragma once - -#include -#include -#include "dyn_array.h" -#include "fileio.h" - -struct file { - char *path; - file_data data; -}; - -typedef struct file file; -dyn_array_def(file); - -struct file_cache { - struct file_arr files; -}; - -struct file_cache *cache_create(void); -bool cache_contains(const struct file_cache *cache, const char *path); -void cache_store(struct file_cache *cache, const char *path, const void *data, size_t length); -file_data cache_load(const struct file_cache *cache, const char *path); -char *cache_encode(const struct file_cache *cache); -struct file_cache *cache_decode(const char *data); -void cache_destroy(struct file_cache *cache); diff --git a/src/utils/fileio.c b/src/utils/fileio.c index 52d6921b..3d861bf8 100644 --- a/src/utils/fileio.c +++ b/src/utils/fileio.c @@ -23,10 +23,10 @@ #include #include #include -#include "filecache.h" #include "textbuffer.h" static char *getFileExtension(const char *fileName) { + if (!fileName) return NULL; char buf[LINEBUFFER_MAXSIZE]; lineBuffer line = { .buf = buf }; fillLineBuffer(&line, fileName, '.'); @@ -63,6 +63,7 @@ enum fileType match_file_type(const char *ext) { } enum fileType guess_file_type(const char *filePath) { + if (!filePath) return unknown; char *fileName = get_file_name(filePath); char *extension = getFileExtension(fileName); char *lower = stringToLower(extension); @@ -95,8 +96,7 @@ size_t get_file_size(const char *path) { #endif } -file_data file_load(const char *file_path, struct file_cache *cache) { - if (cache && cache_contains(cache, file_path)) return cache_load(cache, file_path); +file_data file_load(const char *file_path) { off_t size = get_file_size(file_path); if (size == 0) { return (file_data){ 0 }; @@ -110,7 +110,6 @@ file_data file_load(const char *file_path, struct file_cache *cache) { } madvise(data, size, MADV_SEQUENTIAL); file_data file = (file_data){ .items = data, .count = size, .capacity = size }; - if (cache) cache_store(cache, file_path, file.items, file.count); return file; #else FILE *file = fopen(file_path, "rb"); @@ -124,7 +123,6 @@ file_data file_load(const char *file_path, struct file_cache *cache) { } fclose(file); file_data filedata = (file_data){ .items = buf, .count = readBytes, .capacity = readBytes }; - if (cache) cache_store(cache, file_path, filedata.items, filedata.count); return filedata; #endif } @@ -170,11 +168,11 @@ void write_file(file_data data, const char *filePath) { } -bool is_valid_file(char *path, struct file_cache *cache) { +bool is_valid_file(char *path) { #ifndef WINDOWS struct stat path_stat = { 0 }; stat(path, &path_stat); - return (S_ISREG(path_stat.st_mode) || (cache && cache_contains(cache, path))); + return S_ISREG(path_stat.st_mode); #else FILE *f = fopen(path, "r"); if (f) { @@ -213,6 +211,7 @@ void wait_for_stdin(int seconds) { */ //FIXME: Just return a pointer to the first byte of the filename? Why do we do all this char *get_file_name(const char *input) { + if (!input) return NULL; //FIXME: We're doing two copies here, maybe just rework the algorithm instead. char *copy = stringCopy(input); char *fn; diff --git a/src/utils/fileio.h b/src/utils/fileio.h index 8134be49..ca8a6628 100644 --- a/src/utils/fileio.h +++ b/src/utils/fileio.h @@ -35,12 +35,12 @@ typedef struct file_bytes_arr file_data; enum fileType guess_file_type(const char *path); char *human_file_size(unsigned long bytes, char *stat_buf); -file_data file_load(const char *filePath, struct file_cache *cache); +file_data file_load(const char *filePath); void file_free(file_data *file); // This is a more robust file writing function, that will seek alternate directories // if the specified one wasn't writeable. void write_file(file_data file, const char *path); -bool is_valid_file(char *path, struct file_cache *cache); +bool is_valid_file(char *path); char *get_file_name(const char *input); char *get_file_path(const char *input); // Await for input on stdin for up to 2 seconds. If nothing shows up, return empty file_data diff --git a/src/utils/loaders/textureloader.c b/src/utils/loaders/textureloader.c index 174f76ac..82a714c2 100644 --- a/src/utils/loaders/textureloader.c +++ b/src/utils/loaders/textureloader.c @@ -29,9 +29,9 @@ void copy_to_pool(struct block **pool, struct texture *tex) { tex->data.byte_p = newBuf; } -static struct texture *load_env_map(const file_data data, struct block **pool) { +static struct texture *load_env_map(const file_data data) { logr(info, "Loading HDR..."); - struct texture *tex = allocBlock(pool, sizeof(*tex)); + struct texture *tex = newTexture(none, 0, 0, 0); tex->data.float_p = stbi_loadf_from_memory(data.items, (int)data.count, (int *)&tex->width, (int *)&tex->height, (int *)&tex->channels, 0); tex->precision = float_p; if (!tex->data.float_p) { @@ -44,12 +44,11 @@ static struct texture *load_env_map(const file_data data, struct block **pool) { return tex; } -// We use copyToPool() in loadTexture to copy the actual image data into the memory pool. This code is a bit confusing. -struct texture *load_qoi_from_buffer(const file_data data, struct block **pool) { +struct texture *load_qoi_from_buffer(const file_data data) { qoi_desc desc; void *decoded_data = qoi_decode(data.items, data.count, &desc, 3); if (!decoded_data) return NULL; - struct texture *new = pool ? allocBlock(pool, sizeof(*new)) : newTexture(none, 0, 0, 0); + struct texture *new = newTexture(none, 0, 0, 0); new->data.byte_p = decoded_data; new->width = desc.width; new->height = desc.height; @@ -58,8 +57,8 @@ struct texture *load_qoi_from_buffer(const file_data data, struct block **pool) return new; } -static struct texture *load_texture_from_buffer(const file_data data, struct block **pool) { - struct texture *new = pool ? allocBlock(pool, sizeof(*new)) : newTexture(none, 0, 0, 0); +static struct texture *load_texture_from_buffer(const file_data data) { + struct texture *new = newTexture(none, 0, 0, 0); new->data.byte_p = stbi_load_from_memory(data.items, data.count, (int *)&new->width, (int *)&new->height, (int *)&new->channels, 0); if (!new->data.byte_p) { logr(warning, "Failed to decode texture from memory buffer of size %zu. Reason: \"%s\"\n", data.count, stbi_failure_reason()); @@ -70,25 +69,24 @@ static struct texture *load_texture_from_buffer(const file_data data, struct blo return new; } -struct texture *load_texture(const char *path, const file_data data, struct block **pool) { +struct texture *load_texture(const char *path, const file_data data) { if (!data.items) return NULL; enum fileType type = guess_file_type(path); struct texture *new = NULL; if (stbi_is_hdr_from_memory(data.items, data.count)) { - new = load_env_map(data, pool); + new = load_env_map(data); } else if (type == qoi) { - new = load_qoi_from_buffer(data, pool); + new = load_qoi_from_buffer(data); } else { - new = load_texture_from_buffer(data, pool); + new = load_texture_from_buffer(data); } if (!new) { logr(warning, "^That happened while decoding texture \"%s\"\n", path); return NULL; } - if (pool) copy_to_pool(pool, new); size_t raw_bytes = (new->channels * (new->precision == float_p ? 4 : 1)) * new->width * new->height; char b0[64]; diff --git a/src/utils/loaders/textureloader.h b/src/utils/loaders/textureloader.h index 05f4817d..cdd1e6c6 100644 --- a/src/utils/loaders/textureloader.h +++ b/src/utils/loaders/textureloader.h @@ -10,7 +10,5 @@ #include "../fileio.h" -struct block; - // Currently supports: JPEG, PNG, BMP, TGA, PIC, PNM, QOI, HDRI -struct texture *load_texture(const char *path, const file_data data, struct block **pool); +struct texture *load_texture(const char *path, const file_data data); diff --git a/src/utils/protocol/protocol.c b/src/utils/protocol/protocol.c index ac388f01..1536fb38 100644 --- a/src/utils/protocol/protocol.c +++ b/src/utils/protocol/protocol.c @@ -17,6 +17,10 @@ #include "../../datatypes/vector.h" #include "../../datatypes/tile.h" #include "../../datatypes/image/texture.h" +#include "../../renderer/renderer.h" +#include "../../datatypes/scene.h" +#include "../../driver/node_parse.h" +#include "../hashtable.h" #include "assert.h" #include "../string.h" #include "../gitsha1.h" @@ -97,7 +101,8 @@ struct render_tile decodeTile(const cJSON *json) { return tile; } -cJSON *encodeTexture(const struct texture *t) { +cJSON *serialize_texture(const struct texture *t) { + if (!t) return NULL; cJSON *json = cJSON_CreateObject(); cJSON_AddNumberToObject(json, "width", t->width); cJSON_AddNumberToObject(json, "height", t->height); @@ -111,7 +116,8 @@ cJSON *encodeTexture(const struct texture *t) { return json; } -struct texture *decodeTexture(const cJSON *json) { +struct texture *deserialize_texture(const cJSON *json) { + if (!json) return NULL; struct texture *tex = calloc(1, sizeof(*tex)); tex->colorspace = linear; char *data = cJSON_GetStringValue(cJSON_GetObjectItem(json, "data")); @@ -158,4 +164,729 @@ bool containsStats(const cJSON *json) { return false; } +static cJSON *serialize_coord(const struct coord in) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddNumberToObject(out, "x", in.x); + cJSON_AddNumberToObject(out, "y", in.y); + return out; +} + +static struct coord deserialize_coord(const cJSON *in) { + struct coord out = { 0 }; + if (!in) return out; + out.x = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "x")); + out.y = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "y")); + return out; +} + +static cJSON *serialize_vector(const struct vector in) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddNumberToObject(out, "x", in.x); + cJSON_AddNumberToObject(out, "y", in.y); + cJSON_AddNumberToObject(out, "z", in.z); + return out; +} + +static struct vector deserialize_vector(const cJSON *in) { + struct vector out = { 0 }; + if (!in) return out; + out.x = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "x")); + out.y = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "y")); + out.z = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "z")); + return out; +} + +static cJSON *serialize_transform(const struct transform in) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "A", cJSON_CreateFloatArray((float *)&in.A, (sizeof(in.A) / sizeof(float)))); // sus + cJSON_AddItemToObject(out, "Ainv", cJSON_CreateFloatArray((float *)&in.Ainv, (sizeof(in.Ainv) / sizeof(float)))); // sus + return out; +} + +struct transform deserialize_transform(const cJSON *in) { + struct transform out = { 0 }; + if (!in) return out; + cJSON *A = cJSON_GetObjectItem(in, "A"); + if (cJSON_IsArray(A)) { + for (size_t i = 0; i < (sizeof(out.A) / sizeof(float)); ++i) { + ((float *)out.A.mtx)[i] = cJSON_GetNumberValue(cJSON_GetArrayItem(A, i)); + } + } + cJSON *Ainv = cJSON_GetObjectItem(in, "Ainv"); + if (cJSON_IsArray(A)) { + for (size_t i = 0; i < (sizeof(out.Ainv) / sizeof(float)); ++i) { + ((float *)out.Ainv.mtx)[i] = cJSON_GetNumberValue(cJSON_GetArrayItem(Ainv, i)); + } + } + return out; +} + +static cJSON *serialize_euler_angles(const struct euler_angles in) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddNumberToObject(out, "roll", in.roll); + cJSON_AddNumberToObject(out, "pitch", in.pitch); + cJSON_AddNumberToObject(out, "yaw", in.yaw); + return out; +} + +static struct euler_angles deserialize_euler_angles(const cJSON *in) { + struct euler_angles out = { 0 }; + if (!in) return out; + out.roll = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "roll")); + out.pitch = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "pitch")); + out.yaw = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "yaw")); + return out; +} + +// We likely need to convert to network byte order before packing +// TODO: These would benefit much from zlib and not having to b64 +static cJSON *serialize_vertex_buffer(const struct vertex_buffer in) { + cJSON *out = cJSON_CreateObject(); + + cJSON_AddNumberToObject(out, "vertex_count", in.vertices.count); + if (in.vertices.count) { + char *data = b64encode(in.vertices.items, in.vertices.count * sizeof(*in.vertices.items)); + cJSON_AddStringToObject(out, "vertices", data); + free(data); + } + + cJSON_AddNumberToObject(out, "normal_count", in.normals.count); + if (in.normals.count) { + char *data = b64encode(in.normals.items, in.normals.count * sizeof(*in.normals.items)); + cJSON_AddStringToObject(out, "normals", data); + free(data); + } + + cJSON_AddNumberToObject(out, "texture_coord_count", in.texture_coords.count); + if (in.texture_coords.count) { + char *data = b64encode(in.texture_coords.items, in.texture_coords.count * sizeof(*in.texture_coords.items)); + cJSON_AddStringToObject(out, "texture_coords", data); + free(data); + } + return out; +} + +static struct vertex_buffer deserialize_vertex_buffer(const cJSON *in) { + struct vertex_buffer out = { 0 }; + if (!in) return out; + + size_t vertex_count = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "vertex_count")); + char *v_b64 = cJSON_GetStringValue(cJSON_GetObjectItem(in, "vertices")); + size_t out_bytes = 0; + if (v_b64 && vertex_count) { + struct vector *vertices = b64decode(v_b64, strlen(v_b64), &out_bytes); + ASSERT(out_bytes == vertex_count * sizeof(struct vector)); + for (size_t i = 0; i < vertex_count; ++i) { + vector_arr_add(&out.vertices, vertices[i]); + } + free(vertices); + } + + size_t normal_count = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "normal_count")); + char *n_b64 = cJSON_GetStringValue(cJSON_GetObjectItem(in, "normals")); + if (n_b64 && normal_count) { + struct vector *normals = b64decode(n_b64, strlen(n_b64), &out_bytes); + ASSERT(out_bytes == normal_count * sizeof(struct vector)); + for (size_t i = 0; i < normal_count; ++i) { + vector_arr_add(&out.normals, normals[i]); + } + free(normals); + } + + size_t texture_coord_count = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "texture_coord_count")); + char *t_b64 = cJSON_GetStringValue(cJSON_GetObjectItem(in, "texture_coords")); + if (t_b64 && texture_coord_count) { + struct coord *texture_coords = b64decode(t_b64, strlen(t_b64), &out_bytes); + ASSERT(out_bytes == texture_coord_count * sizeof(struct coord)); + for (size_t i = 0; i < texture_coord_count; ++i) { + coord_arr_add(&out.texture_coords, texture_coords[i]); + } + free(texture_coords); + } + + return out; +} + +static cJSON *serialize_faces(const struct poly_arr in) { + if (!in.count) return NULL; + cJSON *out = cJSON_CreateObject(); + size_t bytes = in.count * sizeof(*in.items); + char *encoded = b64encode(in.items, bytes); + cJSON_AddStringToObject(out, "data", encoded); + free(encoded); + cJSON_AddNumberToObject(out, "poly_count", in.count); + return out; +} + +struct poly_arr deserialize_faces(const cJSON *in) { + struct poly_arr out = { 0 }; + if (!in) return out; + size_t poly_count = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "poly_count")); + char *p_b64 = cJSON_GetStringValue(cJSON_GetObjectItem(in, "data")); + if (p_b64 && poly_count) { + size_t out_len = 0; + struct poly *polys = b64decode(p_b64, strlen(p_b64), &out_len); + ASSERT(out_len == poly_count * sizeof(struct poly)); + for (size_t i = 0; i < poly_count; ++i) { + poly_arr_add(&out, polys[i]); + } + free(polys); + } + return out; +} + +static cJSON *serialize_mesh(const struct mesh in) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "polygons", serialize_faces(in.polygons)); + cJSON_AddNumberToObject(out, "vbuf_idx", in.vbuf_idx); + // TODO: name + return out; +} + +static struct mesh deserialize_mesh(const cJSON *in) { + struct mesh out = { 0 }; + if (!in) return out; + + out.polygons = deserialize_faces(cJSON_GetObjectItem(in, "polygons")); + out.vbuf_idx = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "vbuf_idx")); + + return out; +} + +static cJSON *serialize_sphere(const struct sphere in) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddNumberToObject(out, "radius", in.radius); + cJSON_AddNumberToObject(out, "rayOffset", in.rayOffset); + return out; +} + +static sphere deserialize_sphere(const cJSON *in) { + struct sphere out = { 0 }; + if (!in) return out; + out.radius = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "radius")); + out.rayOffset = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "rayOffset")); + return out; +} + +static cJSON *serialize_instance(const struct instance in) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "composite", serialize_transform(in.composite)); + cJSON_AddNumberToObject(out, "object_idx", in.object_idx); + cJSON_AddNumberToObject(out, "bbuf_idx", in.bbuf_idx); + cJSON_AddBoolToObject(out, "is_mesh", isMesh(&in)); + return out; +} + +static struct instance deserialize_instance(const cJSON *in) { + // TODO: Remember to hook up bbuf and object_arr + if (!in) return (struct instance){ 0 }; + size_t object_idx = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "object_idx")); + bool is_mesh = cJSON_IsTrue(cJSON_GetObjectItem(in, "is_mesh")); + + struct instance out = { 0 }; + if (is_mesh) { + out = new_mesh_instance(NULL, object_idx, NULL, NULL); + } else { + out = new_sphere_instance(NULL, object_idx, NULL, NULL); + } + + out.composite = deserialize_transform(cJSON_GetObjectItem(in, "composite")); + out.bbuf_idx = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "bbuf_idx")); + + return out; +} + +static cJSON *serialize_camera(const struct camera in) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddNumberToObject(out, "FOV", in.FOV); + cJSON_AddNumberToObject(out, "focal_length", in.focal_length); + cJSON_AddNumberToObject(out, "focus_distance", in.focus_distance); + cJSON_AddNumberToObject(out, "fstops", in.fstops); + cJSON_AddNumberToObject(out, "aperture", in.aperture); + cJSON_AddNumberToObject(out, "aspect_ratio", in.aspect_ratio); + cJSON_AddItemToObject(out, "sensor_size", serialize_coord(in.sensor_size)); + cJSON_AddItemToObject(out, "up", serialize_vector(in.up)); + cJSON_AddItemToObject(out, "right", serialize_vector(in.right)); + cJSON_AddItemToObject(out, "look_at", serialize_vector(in.look_at)); + cJSON_AddItemToObject(out, "forward", serialize_vector(in.forward)); + cJSON_AddItemToObject(out, "composite", serialize_transform(in.composite)); + cJSON_AddItemToObject(out, "orientation", serialize_euler_angles(in.orientation)); + cJSON_AddItemToObject(out, "position", serialize_vector(in.position)); + // TODO: bezier path + cJSON_AddNumberToObject(out, "time", in.time); + cJSON_AddNumberToObject(out, "width", in.width); + cJSON_AddNumberToObject(out, "height", in.height); + return out; +} + +// FIXME: We probably don't need the ones we compute anyway when updating camera +static struct camera deserialize_camera(const cJSON *in) { + struct camera out = { 0 }; + if (!in) return out; + out.FOV = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "FOV")); + out.focal_length = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "focal_length")); + out.focus_distance = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "focus_distance")); + out.fstops = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "fstops")); + out.aperture = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "aperture")); + out.aspect_ratio = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "aspect_ratio")); + out.sensor_size = deserialize_coord(cJSON_GetObjectItem(in, "sensor_size")); + out.up = deserialize_vector(cJSON_GetObjectItem(in, "up")); + out.right = deserialize_vector(cJSON_GetObjectItem(in, "right")); + out.look_at = deserialize_vector(cJSON_GetObjectItem(in, "look_at")); + out.forward = deserialize_vector(cJSON_GetObjectItem(in, "forward")); + out.composite = deserialize_transform(cJSON_GetObjectItem(in, "composite")); + out.orientation = deserialize_euler_angles(cJSON_GetObjectItem(in, "orientation")); + out.position = deserialize_vector(cJSON_GetObjectItem(in, "position")); + out.time = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "time")); + out.width = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "width")); + out.height = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "height")); + + return out; +} + +static cJSON *serialize_color(const struct cr_color in) { + cJSON *out = cJSON_CreateArray(); + cJSON_AddItemToArray(out, cJSON_CreateNumber(in.r)); + cJSON_AddItemToArray(out, cJSON_CreateNumber(in.g)); + cJSON_AddItemToArray(out, cJSON_CreateNumber(in.b)); + cJSON_AddItemToArray(out, cJSON_CreateNumber(in.a)); + return out; +} + +static cJSON *serialize_color_node(const struct cr_color_node *in); +static cJSON *serialize_vector_node(const struct cr_vector_node *in); + +static cJSON *serialize_value_node(const struct cr_value_node *in) { + if (!in) return NULL; + cJSON *out = cJSON_CreateObject(); + switch (in->type) { + case cr_vn_unknown: + cJSON_AddStringToObject(out, "type", "unknown"); + break; + case cr_vn_constant: + cJSON_AddStringToObject(out, "type", "constant"); + cJSON_AddItemToObject(out, "value", cJSON_CreateNumber(in->arg.constant)); + break; + case cr_vn_fresnel: + cJSON_AddStringToObject(out, "type", "fresnel"); + cJSON_AddItemToObject(out, "IOR", serialize_value_node(in->arg.fresnel.IOR)); + cJSON_AddItemToObject(out, "normal", serialize_vector_node(in->arg.fresnel.normal)); + break; + case cr_vn_map_range: + cJSON_AddStringToObject(out, "type", "map_range"); + cJSON_AddItemToObject(out, "input", serialize_value_node(in->arg.map_range.input_value)); + cJSON_AddItemToObject(out, "from_min", serialize_value_node(in->arg.map_range.from_min)); + cJSON_AddItemToObject(out, "from_max", serialize_value_node(in->arg.map_range.from_max)); + cJSON_AddItemToObject(out, "to_min", serialize_value_node(in->arg.map_range.to_min)); + cJSON_AddItemToObject(out, "to_max", serialize_value_node(in->arg.map_range.to_max)); + break; + case cr_vn_raylength: + cJSON_AddStringToObject(out, "type", "raylength"); + break; + case cr_vn_alpha: + cJSON_AddStringToObject(out, "type", "alpha"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.alpha.color)); + break; + case cr_vn_vec_to_value: + cJSON_AddStringToObject(out, "type", "vec_to_value"); + cJSON_AddItemToObject(out, "vector", serialize_vector_node(in->arg.vec_to_value.vec)); + cJSON_AddNumberToObject(out, "component", in->arg.vec_to_value.comp); + break; + case cr_vn_math: + cJSON_AddStringToObject(out, "type", "math"); + cJSON_AddItemToObject(out, "a", serialize_value_node(in->arg.math.A)); + cJSON_AddItemToObject(out, "b", serialize_value_node(in->arg.math.B)); + cJSON_AddNumberToObject(out, "op", in->arg.math.op); + break; + case cr_vn_grayscale: + default: + cJSON_AddStringToObject(out, "type", "grayscale"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.grayscale.color)); + break; + } + return out; +} + +static cJSON *serialize_vector_node(const struct cr_vector_node *in) { + if (!in) return NULL; + cJSON *out = cJSON_CreateObject(); + switch (in->type) { + case cr_vec_unknown: + cJSON_AddStringToObject(out, "type", "unknown"); + break; + case cr_vec_constant: + cJSON_AddStringToObject(out, "type", "constant"); + struct cr_vector c = in->arg.constant; + cJSON_AddItemToObject(out, "vec", serialize_vector((struct vector){ c.x, c.y, c.z })); + break; + case cr_vec_normal: + cJSON_AddStringToObject(out, "type", "normal"); + break; + case cr_vec_uv: + cJSON_AddStringToObject(out, "type", "uv"); + break; + case cr_vec_vecmath: + cJSON_AddStringToObject(out, "type", "vecmath"); + cJSON_AddItemToObject(out, "a", serialize_vector_node(in->arg.vecmath.A)); + cJSON_AddItemToObject(out, "b", serialize_vector_node(in->arg.vecmath.B)); + cJSON_AddItemToObject(out, "c", serialize_vector_node(in->arg.vecmath.C)); + cJSON_AddItemToObject(out, "f", serialize_value_node(in->arg.vecmath.f)); + cJSON_AddNumberToObject(out, "op", in->arg.vecmath.op); + break; + case cr_vec_mix: + cJSON_AddStringToObject(out, "type", "mix"); + cJSON_AddItemToObject(out, "a", serialize_vector_node(in->arg.vec_mix.A)); + cJSON_AddItemToObject(out, "b", serialize_vector_node(in->arg.vec_mix.B)); + cJSON_AddItemToObject(out, "f", serialize_value_node(in->arg.vec_mix.factor)); + break; + } + return out; +} + +static cJSON *serialize_color_node(const struct cr_color_node *in) { + if (!in) return NULL; + cJSON *out = cJSON_CreateObject(); + switch (in->type) { + case cr_cn_unknown: + cJSON_AddStringToObject(out, "type", "unknown"); + break; + case cr_cn_constant: + cJSON_AddStringToObject(out, "type", "constant"); + cJSON_AddItemToObject(out, "color", serialize_color(in->arg.constant)); + break; + case cr_cn_image: + cJSON_AddStringToObject(out, "type", "image"); + cJSON_AddStringToObject(out, "path", in->arg.image.full_path); + cJSON_AddNumberToObject(out, "options", in->arg.image.options); + break; + case cr_cn_checkerboard: + cJSON_AddStringToObject(out, "type", "checkerboard"); + cJSON_AddItemToObject(out, "color1", serialize_color_node(in->arg.checkerboard.a)); + cJSON_AddItemToObject(out, "color2", serialize_color_node(in->arg.checkerboard.b)); + cJSON_AddItemToObject(out, "scale", serialize_value_node(in->arg.checkerboard.scale)); + break; + case cr_cn_blackbody: + cJSON_AddStringToObject(out, "type", "blackbody"); + cJSON_AddItemToObject(out, "degrees", serialize_value_node(in->arg.blackbody.degrees)); + break; + case cr_cn_split: + cJSON_AddStringToObject(out, "type", "split"); + cJSON_AddItemToObject(out, "constant", serialize_value_node(in->arg.split.node)); + break; + case cr_cn_rgb: + cJSON_AddStringToObject(out, "type", "rgb"); + cJSON_AddItemToObject(out, "r", serialize_value_node(in->arg.rgb.red)); + cJSON_AddItemToObject(out, "g", serialize_value_node(in->arg.rgb.green)); + cJSON_AddItemToObject(out, "b", serialize_value_node(in->arg.rgb.blue)); + break; + case cr_cn_hsl: + cJSON_AddStringToObject(out, "type", "hsl"); + cJSON_AddItemToObject(out, "h", serialize_value_node(in->arg.hsl.H)); + cJSON_AddItemToObject(out, "s", serialize_value_node(in->arg.hsl.S)); + cJSON_AddItemToObject(out, "l", serialize_value_node(in->arg.hsl.L)); + break; + case cr_cn_vec_to_color: + cJSON_AddStringToObject(out, "type", "to_color"); + cJSON_AddItemToObject(out, "vector", serialize_vector_node(in->arg.vec_to_color.vec)); + break; + case cr_cn_gradient: + cJSON_AddStringToObject(out, "type", "gradient"); + cJSON_AddItemToObject(out, "down", serialize_color_node(in->arg.gradient.a)); + cJSON_AddItemToObject(out, "up", serialize_color_node(in->arg.gradient.b)); + break; + } + return out; +} + +static cJSON *serialize_shader_node(const struct cr_shader_node *in) { + if (!in) return NULL; + cJSON *out = cJSON_CreateObject(); + switch (in->type) { + case cr_bsdf_unknown: + cJSON_AddStringToObject(out, "type", "unknown"); + break; + case cr_bsdf_diffuse: + cJSON_AddStringToObject(out, "type", "diffuse"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.diffuse.color)); + break; + case cr_bsdf_metal: + cJSON_AddStringToObject(out, "type", "metal"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.metal.color)); + cJSON_AddItemToObject(out, "roughness", serialize_value_node(in->arg.metal.roughness)); + break; + case cr_bsdf_glass: + cJSON_AddStringToObject(out, "type", "glass"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.glass.color)); + cJSON_AddItemToObject(out, "roughness", serialize_value_node(in->arg.glass.roughness)); + cJSON_AddItemToObject(out, "IOR", serialize_value_node(in->arg.glass.IOR)); + break; + case cr_bsdf_plastic: + cJSON_AddStringToObject(out, "type", "plastic"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.plastic.color)); + cJSON_AddItemToObject(out, "roughness", serialize_value_node(in->arg.plastic.roughness)); + cJSON_AddItemToObject(out, "IOR", serialize_value_node(in->arg.plastic.IOR)); + break; + case cr_bsdf_mix: + cJSON_AddStringToObject(out, "type", "mix"); + cJSON_AddItemToObject(out, "A", serialize_shader_node(in->arg.mix.A)); + cJSON_AddItemToObject(out, "B", serialize_shader_node(in->arg.mix.B)); + cJSON_AddItemToObject(out, "factor", serialize_value_node(in->arg.mix.factor)); + break; + case cr_bsdf_add: + cJSON_AddStringToObject(out, "type", "add"); + cJSON_AddItemToObject(out, "A", serialize_shader_node(in->arg.add.A)); + cJSON_AddItemToObject(out, "B", serialize_shader_node(in->arg.add.B)); + break; + case cr_bsdf_transparent: + cJSON_AddStringToObject(out, "type", "transparent"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.transparent.color)); + break; + case cr_bsdf_emissive: + cJSON_AddStringToObject(out, "type", "emissive"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.emissive.color)); + cJSON_AddItemToObject(out, "strength", serialize_value_node(in->arg.emissive.strength)); + break; + case cr_bsdf_translucent: + cJSON_AddStringToObject(out, "type", "translucent"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.translucent.color)); + break; + case cr_bsdf_background: + cJSON_AddStringToObject(out, "type", "background"); + cJSON_AddItemToObject(out, "color", serialize_color_node(in->arg.background.color)); + cJSON_AddItemToObject(out, "offset", serialize_vector_node(in->arg.background.pose)); + cJSON_AddItemToObject(out, "strength", serialize_value_node(in->arg.background.strength)); + break; + } + return out; +} + +struct cr_shader_node *deserialize_shader_node(const cJSON *in) { + return cr_shader_node_build(in); +} + +static cJSON *serialize_scene(const struct world *in) { + cJSON *out = cJSON_CreateObject(); + + cJSON_AddStringToObject(out, "asset_path", in->asset_path); + + cJSON_AddItemToObject(out, "background", serialize_shader_node(in->bg_desc)); + + cJSON *textures = cJSON_CreateArray(); + for (size_t i = 0; i < in->textures.count; ++i) { + cJSON *asset = cJSON_CreateObject(); + cJSON_AddItemToObject(asset, "p", cJSON_CreateString(in->textures.items[i].path)); + cJSON_AddItemToObject(asset, "t", serialize_texture(in->textures.items[i].t)); + cJSON_AddItemToArray(textures, asset); + } + cJSON_AddItemToObject(out, "textures", textures); + + cJSON *v_buffers = cJSON_CreateArray(); + for (size_t i = 0; i < in->v_buffers.count; ++i) { + cJSON_AddItemToArray(v_buffers, serialize_vertex_buffer(in->v_buffers.items[i])); + } + cJSON_AddItemToObject(out, "v_buffers", v_buffers); + + // Note: We only really need the descriptions, since we can't serialize the actual shaders anyway + cJSON *shader_buffers = cJSON_CreateArray(); + for (size_t i = 0; i < in->shader_buffers.count; ++i) { + cJSON *descriptions = cJSON_CreateArray(); + for (size_t j = 0; j < in->shader_buffers.items[i].descriptions.count; ++j) { + cJSON_AddItemToArray(descriptions, serialize_shader_node(in->shader_buffers.items[i].descriptions.items[j])); + } + cJSON_AddItemToArray(shader_buffers, descriptions); + } + cJSON_AddItemToObject(out, "shader_buffers", shader_buffers); + + cJSON *meshes = cJSON_CreateArray(); + for (size_t i = 0; i < in->meshes.count; ++i) { + cJSON_AddItemToArray(meshes, serialize_mesh(in->meshes.items[i])); + } + cJSON_AddItemToObject(out, "meshes", meshes); + + cJSON *spheres = cJSON_CreateArray(); + for (size_t i = 0; i < in->spheres.count; ++i) { + cJSON_AddItemToArray(spheres, serialize_sphere(in->spheres.items[i])); + } + cJSON_AddItemToObject(out, "spheres", spheres); + + cJSON *instances = cJSON_CreateArray(); + for (size_t i = 0; i < in->instances.count; ++i) { + cJSON_AddItemToArray(instances, serialize_instance(in->instances.items[i])); + } + cJSON_AddItemToObject(out, "instances", instances); + + cJSON *cameras = cJSON_CreateArray(); + for (size_t i = 0; i < in->cameras.count; ++i) { + cJSON_AddItemToArray(cameras, serialize_camera(in->cameras.items[i])); + } + cJSON_AddItemToObject(out, "cameras", cameras); + + return out; +} + +struct world *deserialize_scene(const cJSON *in) { + if (!in) return NULL; + struct world *out = calloc(1, sizeof(*out)); + + out->asset_path = stringCopy("./"); + out->storage.node_pool = newBlock(NULL, 1024); + out->storage.node_table = newHashtable(compareNodes, &out->storage.node_pool); + + cJSON *asset_path = cJSON_GetObjectItem(in, "asset_path"); + if (cJSON_IsString(asset_path)) { + if (out->asset_path) free(out->asset_path); + out->asset_path = stringCopy(asset_path->valuestring); + } + + const cJSON *background = cJSON_GetObjectItem(in, "background"); + if (cJSON_IsObject(background)) { + out->bg_desc = deserialize_shader_node(background); + out->background = build_bsdf_node((struct cr_scene *)out, out->bg_desc); + } + const cJSON *textures = cJSON_GetObjectItem(in, "textures"); + if (cJSON_IsArray(textures)) { + cJSON *texture = NULL; + cJSON_ArrayForEach(texture, textures) { + texture_asset_arr_add(&out->textures, (struct texture_asset){ + .path = stringCopy(cJSON_GetStringValue(cJSON_GetObjectItem(texture, "p"))), + .t = deserialize_texture(cJSON_GetObjectItem(texture, "t")) + }); + } + } + const cJSON *v_buffers = cJSON_GetObjectItem(in, "v_buffers"); + if (cJSON_IsArray(v_buffers)) { + cJSON *v_buffer = NULL; + cJSON_ArrayForEach(v_buffer, v_buffers) { + vertex_buffer_arr_add(&out->v_buffers, deserialize_vertex_buffer(v_buffer)); + } + } + const cJSON *shader_buffers = cJSON_GetObjectItem(in, "shader_buffers"); + if (cJSON_IsArray(shader_buffers)) { + cJSON *s_buffer = NULL; + cJSON_ArrayForEach(s_buffer, shader_buffers) { + size_t idx = bsdf_buffer_arr_add(&out->shader_buffers, (struct bsdf_buffer){ 0 }); + struct bsdf_buffer *buf = &out->shader_buffers.items[idx]; + if (cJSON_IsArray(s_buffer)) { + cJSON *description = NULL; + cJSON_ArrayForEach(description, s_buffer) { + struct cr_shader_node *desc = deserialize_shader_node(description); + cr_shader_node_ptr_arr_add(&buf->descriptions, desc); + bsdf_node_ptr_arr_add(&buf->bsdfs, build_bsdf_node((struct cr_scene *)out, desc)); + } + } + } + } + + cJSON *meshes = cJSON_GetObjectItem(in, "meshes"); + if (cJSON_IsArray(meshes)) { + cJSON *mesh = NULL; + cJSON_ArrayForEach(mesh, meshes) { + // TODO: Remember to hook up vbufs + mesh_arr_add(&out->meshes, deserialize_mesh(mesh)); + } + } + + // Hook up vertex buffers to meshes + for (size_t i = 0; i < out->meshes.count; ++i) { + struct mesh *m = &out->meshes.items[i]; + m->vbuf = &out->v_buffers.items[m->vbuf_idx]; + } + + cJSON *spheres = cJSON_GetObjectItem(in, "spheres"); + if (cJSON_IsArray(spheres)) { + cJSON *sphere = NULL; + cJSON_ArrayForEach(sphere, spheres) { + sphere_arr_add(&out->spheres, deserialize_sphere(sphere)); + } + } + cJSON *instances = cJSON_GetObjectItem(in, "instances"); + if (cJSON_IsArray(instances)) { + cJSON *instance = NULL; + cJSON_ArrayForEach(instance, instances) { + instance_arr_add(&out->instances, deserialize_instance(instance)); + } + } + + // Hook up shader buffers and object arrays to instances + for (size_t i = 0; i < out->instances.count; ++i) { + struct instance *inst = &out->instances.items[i]; + inst->bbuf = &out->shader_buffers.items[inst->bbuf_idx]; + if (isMesh(inst)) { + inst->object_arr = &out->meshes; + } else { + inst->object_arr = &out->spheres; + } + } + + cJSON *cameras = cJSON_GetObjectItem(in, "cameras"); + if (cJSON_IsArray(cameras)) { + cJSON *camera = NULL; + cJSON_ArrayForEach(camera, cameras) { + camera_arr_add(&out->cameras, deserialize_camera(camera)); + } + } + + return out; +} + +static cJSON *serialize_prefs(const struct prefs in) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "threads", cJSON_CreateNumber(in.threads)); + cJSON_AddItemToObject(out, "samples", cJSON_CreateNumber(in.sampleCount)); + cJSON_AddItemToObject(out, "bounces", cJSON_CreateNumber(in.bounces)); + cJSON_AddItemToObject(out, "tileWidth", cJSON_CreateNumber(in.tileWidth)); + cJSON_AddItemToObject(out, "tileHeight", cJSON_CreateNumber(in.tileHeight)); + cJSON_AddItemToObject(out, "tileOrder", cJSON_CreateNumber(in.tileOrder)); + cJSON_AddItemToObject(out, "outputFilePath", cJSON_CreateString(in.imgFilePath)); + cJSON_AddItemToObject(out, "outputFileName", cJSON_CreateString(in.imgFileName)); + cJSON_AddItemToObject(out, "count", cJSON_CreateNumber(in.imgCount)); + cJSON_AddItemToObject(out, "width", cJSON_CreateNumber(in.override_width)); + cJSON_AddItemToObject(out, "height", cJSON_CreateNumber(in.override_height)); + cJSON_AddItemToObject(out, "fileType", cJSON_CreateNumber(in.imgType)); + cJSON_AddItemToObject(out, "selected_camera", cJSON_CreateNumber(in.selected_camera)); + return out; +} + +struct prefs deserialize_prefs(const cJSON *in) { + struct prefs p = default_prefs(); + if (!in) return p; + p.threads = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "threads")); + p.sampleCount = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "samples")); + p.bounces = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "bounces")); + p.tileWidth = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "tileWidth")); + p.tileHeight = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "tileHeight")); + p.tileOrder = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "tileOrder")); + free(p.imgFilePath); + free(p.imgFileName); + p.imgFilePath = stringCopy(cJSON_GetStringValue(cJSON_GetObjectItem(in, "outputFilePath"))); + p.imgFileName = stringCopy(cJSON_GetStringValue(cJSON_GetObjectItem(in, "outputFileName"))); + p.imgCount = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "count")); + p.override_width = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "width")); + p.override_height = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "height")); + p.imgType = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "fileType")); + p.selected_camera = cJSON_GetNumberValue(cJSON_GetObjectItem(in, "selected_camera")); + return p; +} + +char *serialize_renderer(const struct renderer *r) { + if (!r) return NULL; + cJSON *out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "scene", serialize_scene(r->scene)); + cJSON_AddItemToObject(out, "prefs", serialize_prefs(r->prefs)); + char *data = cJSON_PrintUnformatted(out); + cJSON_Delete(out); + return data; +} + +struct renderer *deserialize_renderer(const char *data) { + cJSON *renderer = cJSON_Parse(data); + if (!renderer) return NULL; + struct renderer *r = calloc(1, sizeof(*r)); + r->state.finishedPasses = 1; + r->scene = deserialize_scene(cJSON_GetObjectItem(renderer, "scene")); + r->prefs = deserialize_prefs(cJSON_GetObjectItem(renderer, "prefs")); + cJSON_Delete(renderer); + return r; +} + #endif diff --git a/src/utils/protocol/protocol.h b/src/utils/protocol/protocol.h index f0abe0b8..a093b885 100644 --- a/src/utils/protocol/protocol.h +++ b/src/utils/protocol/protocol.h @@ -40,12 +40,15 @@ cJSON *encodeTile(const struct render_tile *tile); struct render_tile decodeTile(const cJSON *json); -cJSON *encodeTexture(const struct texture *t); +cJSON *serialize_texture(const struct texture *t); -struct texture *decodeTexture(const cJSON *json); +struct texture *deserialize_texture(const cJSON *json); bool containsError(const cJSON *json); bool containsGoodbye(const cJSON *json); bool containsStats(const cJSON *json); + +char *serialize_renderer(const struct renderer *r); +struct renderer *deserialize_renderer(const char *data); diff --git a/src/utils/protocol/server.c b/src/utils/protocol/server.c index d5aa08ce..0707f20d 100644 --- a/src/utils/protocol/server.c +++ b/src/utils/protocol/server.c @@ -33,7 +33,6 @@ #include "../textbuffer.h" #include "../gitsha1.h" #include "../assert.h" -#include "../filecache.h" #include "../platform/terminal.h" #include "../platform/signal.h" @@ -145,7 +144,7 @@ static cJSON *handle_get_work(struct worker *state, const cJSON *json) { static cJSON *handle_submit_work(struct worker *state, const cJSON *json) { cJSON *result = cJSON_GetObjectItem(json, "result"); - struct texture *texture = decodeTexture(result); + struct texture *texture = deserialize_texture(result); cJSON *tile_json = cJSON_GetObjectItem(json, "tile"); struct render_tile tile = decodeTile(tile_json); state->tiles->tiles.items[tile.index] = tile; @@ -257,8 +256,7 @@ void *client_connection_thread(void *arg) { struct sync_thread { struct render_client *client; - const struct renderer *renderer; - const char *asset_cache; + char *serialized_renderer; size_t progress; bool done; }; @@ -295,11 +293,9 @@ static void *client_sync_thread(void *arg) { // Send the scene & assets cJSON *scene = cJSON_CreateObject(); cJSON_AddStringToObject(scene, "action", "loadScene"); - logr(debug, "Syncing state: %s\n", params->renderer->sceneCache); - cJSON *data = cJSON_Parse(params->renderer->sceneCache); - cJSON_AddItemToObject(scene, "data", data); - cJSON_AddItemToObject(scene, "files", cJSON_Parse(params->asset_cache)); - cJSON_AddStringToObject(scene, "assetPath", params->renderer->prefs.assetPath); + logr(debug, "Syncing state to client %d\n", client->id); + // FIXME: Would be better to just send the string directly instead of wrapping it in json + cJSON_AddStringToObject(scene, "data", params->serialized_renderer); sendJSON(client->socket, scene, ¶ms->progress); response = readJSON(client->socket); if (!response) { @@ -382,20 +378,17 @@ struct render_client_arr clients_sync(const struct renderer *r) { return (struct render_client_arr){ 0 }; } - char *asset_cache = cache_encode(r->state.file_cache); - - size_t transfer_bytes = strlen(asset_cache) + strlen(r->sceneCache); - char *transfer_size = human_file_size(transfer_bytes, NULL); - logr(info, "Sending %s to %lu client%s...\n", transfer_size, clients.count, PLURAL(clients.count)); - free(transfer_size); + char *serialized = serialize_renderer(r); + size_t transfer_bytes = strlen(serialized); + char buf[64]; + logr(info, "Sending %s to %lu client%s...\n", human_file_size(transfer_bytes, buf), clients.count, PLURAL(clients.count)); struct sync_thread *params = calloc(clients.count, sizeof(*params)); logr(debug, "Client list:\n"); for (size_t i = 0; i < clients.count; ++i) { logr(debug, "\tclient %zu: %s:%i\n", i, inet_ntoa(clients.items[i].address.sin_addr), htons(clients.items[i].address.sin_port)); params[i].client = &clients.items[i]; - params[i].renderer = r; - params[i].asset_cache = asset_cache; + params[i].serialized_renderer = serialized; } struct cr_thread *sync_threads = calloc(clients.count, sizeof(*sync_threads)); @@ -432,10 +425,10 @@ struct render_client_arr clients_sync(const struct renderer *r) { thread_wait(&sync_threads[i]); } - free(asset_cache); for (size_t i = 0; i < clients.count; ++i) printf("\n"); logr(info, "Client sync finished.\n"); + free(serialized); free(sync_threads); free(params); return clients; diff --git a/src/utils/protocol/worker.c b/src/utils/protocol/worker.c index 12291329..d049136a 100644 --- a/src/utils/protocol/worker.c +++ b/src/utils/protocol/worker.c @@ -29,7 +29,6 @@ #include "../platform/thread.h" #include "../networking.h" #include "../string.h" -#include "../filecache.h" #include "../gitsha1.h" #include "../timer.h" #include "../../utils/platform/signal.h" @@ -69,28 +68,11 @@ static cJSON *validateHandshake(cJSON *in) { } static cJSON *receiveScene(const cJSON *json) { - // Load assets - cJSON *fileCache = cJSON_GetObjectItem(json, "files"); - if (!fileCache) return errorResponse("No file cache found"); - char *data = cJSON_PrintUnformatted(fileCache); - //FIXME: This is an awkward API, why not pass cJSON directly? - struct file_cache *cache = cache_decode(data); - free(data); // And then the scene - cJSON *scene = cJSON_GetObjectItem(json, "data"); logr(info, "Received scene description\n"); - g_worker_renderer = renderer_new(); - g_worker_renderer->state.file_cache = cache; + g_worker_renderer = deserialize_renderer(cJSON_GetStringValue(cJSON_GetObjectItem(json, "data"))); g_worker_socket_mutex = mutex_create(); - cJSON *assetPathJson = cJSON_GetObjectItem(json, "assetPath"); - if (g_worker_renderer->prefs.assetPath) free(g_worker_renderer->prefs.assetPath); - g_worker_renderer->prefs.assetPath = stringCopy(assetPathJson->valuestring); - // FIXME - if (parse_json((struct cr_renderer *)g_worker_renderer, scene)) { - return errorResponse("Scene parsing error"); - } - cache_destroy(cache); cJSON *resp = newAction("ready"); // Stash in our capabilities here @@ -126,7 +108,7 @@ static struct render_tile *getWork(int connectionSocket, struct tile_set *tiles) } static bool submitWork(int sock, struct texture *work, struct render_tile *forTile) { - cJSON *result = encodeTexture(work); + cJSON *result = serialize_texture(work); cJSON *tile = encodeTile(forTile); cJSON *package = newAction("submitWork"); cJSON_AddItemToObject(package, "result", result); diff --git a/src/utils/string.c b/src/utils/string.c index 64482e12..698fe47e 100644 --- a/src/utils/string.c +++ b/src/utils/string.c @@ -82,6 +82,7 @@ void windowsFixPath(char *path) { } char *stringToLower(const char *orig) { + if (!orig) return NULL; char *str = stringCopy(orig); size_t len = strlen(str); for (size_t i = 0; i < len; ++i) { diff --git a/tests/perf/perf_base64.h b/tests/perf/perf_base64.h index 8930d615..9d7b768b 100644 --- a/tests/perf/perf_base64.h +++ b/tests/perf/perf_base64.h @@ -12,7 +12,7 @@ #include "../../src/utils/timer.h" time_t base64_bigfile_encode(void) { - file_data bigfile = file_load("input/venusscaled.obj", NULL); + file_data bigfile = file_load("input/venusscaled.obj"); ASSERT(bigfile.items); struct timeval test; @@ -28,7 +28,7 @@ time_t base64_bigfile_encode(void) { } time_t base64_bigfile_decode(void) { - file_data bigfile = file_load("input/venusscaled.obj", NULL); + file_data bigfile = file_load("input/venusscaled.obj"); ASSERT(bigfile.items); char *encoded = b64encode(bigfile.items, bigfile.count); diff --git a/tests/perf/perf_fileio.h b/tests/perf/perf_fileio.h index 720a53e0..c0eabf53 100644 --- a/tests/perf/perf_fileio.h +++ b/tests/perf/perf_fileio.h @@ -12,7 +12,7 @@ time_t fileio_load(void) { struct timeval test; timer_start(&test); - file_data bigfile = file_load("input/venusscaled.obj", NULL); + file_data bigfile = file_load("input/venusscaled.obj"); ASSERT(bigfile.items); time_t us = timer_get_us(test);