Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/app/cycles_json.cpp
- This file was added.
| /* | |||||
| * Copyright 2011-2013 Blender Foundation | |||||
| * | |||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| * you may not use this file except in compliance with the License. | |||||
| * You may obtain a copy of the License at | |||||
| * | |||||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||||
| * | |||||
| * Unless required by applicable law or agreed to in writing, software | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| * See the License for the specific language governing permissions and | |||||
| * limitations under the License | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <sstream> | |||||
| #include <algorithm> | |||||
| #include <iterator> | |||||
| #include <fstream> | |||||
| #include "camera.h" | |||||
| #include "film.h" | |||||
| #include "graph.h" | |||||
| #include "integrator.h" | |||||
| #include "light.h" | |||||
| #include "mesh.h" | |||||
| #include "nodes.h" | |||||
| #include "object.h" | |||||
| #include "shader.h" | |||||
| #include "scene.h" | |||||
| #include "subd_mesh.h" | |||||
| #include "subd_patch.h" | |||||
| #include "subd_split.h" | |||||
| #include "util_debug.h" | |||||
| #include "util_foreach.h" | |||||
| #include "util_path.h" | |||||
| #include "util_transform.h" | |||||
| #include "cycles_json.h" | |||||
| #include "rapidjson/document.h" | |||||
| #include "rapidjson/filestream.h" | |||||
| CCL_NAMESPACE_BEGIN | |||||
| /* XML reading state */ | |||||
| struct JSONReadState { | |||||
| Scene *scene; /* scene pointer */ | |||||
| Transform tfm; /* current transform state */ | |||||
| bool smooth; /* smooth normal state */ | |||||
| int shader; /* current shader */ | |||||
| string base; /* base path to current file*/ | |||||
| float dicing_rate; /* current dicing rate */ | |||||
| Mesh::DisplacementMethod displacement_method; | |||||
| }; | |||||
| /* Attribute Reading */ | |||||
| static bool json_read_bool(bool *value,const rapidjson::Value& node) | |||||
| { | |||||
| if(node.IsBool()) { | |||||
| *value = node.GetBool(); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_read_int(int *value,const rapidjson::Value& node) | |||||
| { | |||||
| if(node.IsInt()) { | |||||
| *value = node.GetInt(); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_read_int_array(vector<int>& value,const rapidjson::Value& node) | |||||
| { | |||||
| if(node.IsArray()) { | |||||
| vector<string> tokens; | |||||
| //TODO FIXME | |||||
| //string_split(tokens, attr.value()); | |||||
| //foreach(const string& token, tokens) | |||||
| // value.push_back(atoi(token.c_str())); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_read_float(float *value,const rapidjson::Value& node) | |||||
| { | |||||
| if(node.IsDouble()) { | |||||
| *value = (float)node.GetDouble(); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_read_float_array(vector<float>& value,const rapidjson::Value& node) | |||||
| { | |||||
| if(node.IsArray()) { | |||||
| vector<string> tokens; | |||||
| /*/TODO FIXME | |||||
| string_split(tokens, attr.value()); | |||||
| foreach(const string& token, tokens) | |||||
| value.push_back((float)atof(token.c_str())); | |||||
| */ | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_read_float3(float3 *value,const rapidjson::Value& node) | |||||
| { | |||||
| vector<float> array; | |||||
| if(json_read_float_array(array, node) && array.size() == 3) { | |||||
| *value = make_float3(array[0], array[1], array[2]); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_read_float3_array(vector<float3>& value,const rapidjson::Value& node) | |||||
| { | |||||
| vector<float> array; | |||||
| if(json_read_float_array(array, node)) { | |||||
| for(size_t i = 0; i < array.size(); i += 3) | |||||
| value.push_back(make_float3(array[i+0], array[i+1], array[i+2])); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_read_float4(float4 *value,const rapidjson::Value& node) | |||||
| { | |||||
| vector<float> array; | |||||
| if(json_read_float_array(array, node) && array.size() == 4) { | |||||
| *value = make_float4(array[0], array[1], array[2], array[3]); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_read_string(string *str,const rapidjson::Value& node) | |||||
| { | |||||
| if(node.IsString()) { | |||||
| *str = node.GetString(); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_read_ustring(ustring *str,const rapidjson::Value& node) | |||||
| { | |||||
| if(node.IsString()) { | |||||
| *str = ustring(node.GetString()); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool json_equal_string(const rapidjson::Value& node, const char *value) | |||||
| { | |||||
| if(node.IsString()) | |||||
| return string_iequals(node.GetString(), value); | |||||
| return false; | |||||
| } | |||||
| static bool json_read_enum(ustring *str, ShaderEnum& enm, const rapidjson::Value& node) | |||||
| { | |||||
| if(node.IsString()) { | |||||
| ustring ustr(node.GetString()); | |||||
| if(enm.exists(ustr)) { | |||||
| *str = ustr; | |||||
| return true; | |||||
| } | |||||
| else | |||||
| fprintf(stderr, "Unknown value \"%s\" for attribute.\n", ustr.c_str()); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static ShaderSocketType json_read_socket_type(const rapidjson::Value& node) | |||||
| { | |||||
| if(node.IsString()) { | |||||
| string value = node.GetString(); | |||||
| if (string_iequals(value, "float")) | |||||
| return SHADER_SOCKET_FLOAT; | |||||
| else if (string_iequals(value, "int")) | |||||
| return SHADER_SOCKET_INT; | |||||
| else if (string_iequals(value, "color")) | |||||
| return SHADER_SOCKET_COLOR; | |||||
| else if (string_iequals(value, "vector")) | |||||
| return SHADER_SOCKET_VECTOR; | |||||
| else if (string_iequals(value, "point")) | |||||
| return SHADER_SOCKET_POINT; | |||||
| else if (string_iequals(value, "normal")) | |||||
| return SHADER_SOCKET_NORMAL; | |||||
| else if (string_iequals(value, "closure color")) | |||||
| return SHADER_SOCKET_CLOSURE; | |||||
| else if (string_iequals(value, "string")) | |||||
| return SHADER_SOCKET_STRING; | |||||
| else | |||||
| fprintf(stderr, "Unknown shader socket type \"%s\" for attribute.\n", value.c_str()); | |||||
| } | |||||
| return SHADER_SOCKET_UNDEFINED; | |||||
| } | |||||
| /* Film */ | |||||
| static void json_read_film(const JSONReadState& state,const rapidjson::Value& node) | |||||
| { | |||||
| Film *film = state.scene->film; | |||||
| json_read_float(&film->exposure, node["exposure"]); | |||||
| /* ToDo: Filter Type */ | |||||
| json_read_float(&film->filter_width, node["filter_width"]); | |||||
| } | |||||
| /* Integrator */ | |||||
| static void json_read_integrator(const JSONReadState& state,const rapidjson::Value& node) | |||||
| { | |||||
| Integrator *integrator = state.scene->integrator; | |||||
| /* Branched Path */ | |||||
| bool branched = false; | |||||
| json_read_bool(&branched, node["branched"]); | |||||
| if(branched) { | |||||
| integrator->method = Integrator::BRANCHED_PATH; | |||||
| json_read_int(&integrator->diffuse_samples, node["diffuse_samples"]); | |||||
| json_read_int(&integrator->glossy_samples, node["glossy_samples"]); | |||||
| json_read_int(&integrator->transmission_samples, node["transmission_samples"]); | |||||
| json_read_int(&integrator->ao_samples, node["ao_samples"]); | |||||
| json_read_int(&integrator->mesh_light_samples, node["mesh_light_samples"]); | |||||
| json_read_int(&integrator->subsurface_samples, node["subsurface_samples"]); | |||||
| json_read_int(&integrator->volume_samples, node["volume_samples"]); | |||||
| json_read_bool(&integrator->sample_all_lights_direct, node["sample_all_lights_direct"]); | |||||
| json_read_bool(&integrator->sample_all_lights_indirect, node["sample_all_lights_indirect"]); | |||||
| } | |||||
| /* Bounces */ | |||||
| json_read_int(&integrator->min_bounce, node["min_bounce"]); | |||||
| json_read_int(&integrator->max_bounce, node["max_bounce"]); | |||||
| json_read_int(&integrator->max_diffuse_bounce, node["max_diffuse_bounce"]); | |||||
| json_read_int(&integrator->max_glossy_bounce, node["max_glossy_bounce"]); | |||||
| json_read_int(&integrator->max_transmission_bounce, node["max_transmission_bounce"]); | |||||
| json_read_int(&integrator->max_volume_bounce, node["max_volume_bounce"]); | |||||
| /* Transparency */ | |||||
| json_read_int(&integrator->transparent_min_bounce, node["transparent_min_bounce"]); | |||||
| json_read_int(&integrator->transparent_max_bounce, node["transparent_max_bounce"]); | |||||
| json_read_bool(&integrator->transparent_shadows, node["transparent_shadows"]); | |||||
| /* Volume */ | |||||
| json_read_int(&integrator->volume_homogeneous_sampling, node["volume_homogeneous_sampling"]); | |||||
| json_read_float(&integrator->volume_step_size, node["volume_step_size"]); | |||||
| json_read_int(&integrator->volume_max_steps, node["volume_max_steps"]); | |||||
| /* Various Settings */ | |||||
| json_read_bool(&integrator->caustics_reflective, node["caustics_reflective"]); | |||||
| json_read_bool(&integrator->caustics_refractive, node["caustics_refractive"]); | |||||
| json_read_float(&integrator->filter_glossy, node["filter_glossy"]); | |||||
| json_read_int(&integrator->seed, node["seed"]); | |||||
| json_read_float(&integrator->sample_clamp_direct, node["sample_clamp_direct"]); | |||||
| json_read_float(&integrator->sample_clamp_indirect, node["sample_clamp_indirect"]); | |||||
| } | |||||
| /* Camera */ | |||||
| static void json_read_camera(const JSONReadState& state,const rapidjson::Value& node) | |||||
| { | |||||
| Camera *cam = state.scene->camera; | |||||
| json_read_int(&cam->width, node["width"]); | |||||
| json_read_int(&cam->height, node["height"]); | |||||
| if(json_read_float(&cam->fov, node["fov"])) | |||||
| cam->fov = DEG2RADF(cam->fov); | |||||
| json_read_float(&cam->nearclip, node["nearclip"]); | |||||
| json_read_float(&cam->farclip, node["farclip"]); | |||||
| json_read_float(&cam->aperturesize, node["aperturesize"]); // 0.5*focallength/fstop | |||||
| json_read_float(&cam->focaldistance, node["focaldistance"]); | |||||
| json_read_float(&cam->shuttertime, node["shuttertime"]); | |||||
| json_read_float(&cam->aperture_ratio, node["aperture_ratio"]); | |||||
| if(json_equal_string(node["type"], "orthographic")) | |||||
| cam->type = CAMERA_ORTHOGRAPHIC; | |||||
| else if(json_equal_string(node["type"], "perspective")) | |||||
| cam->type = CAMERA_PERSPECTIVE; | |||||
| else if(json_equal_string(node["type"], "panorama")) | |||||
| cam->type = CAMERA_PANORAMA; | |||||
| if(json_equal_string(node["panorama_type"], "equirectangular")) | |||||
| cam->panorama_type = PANORAMA_EQUIRECTANGULAR; | |||||
| else if(json_equal_string(node["panorama_type"], "fisheye_equidistant")) | |||||
| cam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT; | |||||
| else if(json_equal_string(node["panorama_type"], "fisheye_equisolid")) | |||||
| cam->panorama_type = PANORAMA_FISHEYE_EQUISOLID; | |||||
| json_read_float(&cam->fisheye_fov, node["fisheye_fov"]); | |||||
| json_read_float(&cam->fisheye_lens, node["fisheye_lens"]); | |||||
| json_read_float(&cam->sensorwidth, node["sensorwidth"]); | |||||
| json_read_float(&cam->sensorheight, node["sensorheight"]); | |||||
| cam->matrix = state.tfm; | |||||
| cam->need_update = true; | |||||
| cam->update(); | |||||
| } | |||||
| /* Shader */ | |||||
| static string json_socket_name(const char *name) | |||||
| { | |||||
| string sname = name; | |||||
| size_t i; | |||||
| while((i = sname.find(" ")) != string::npos) | |||||
| sname.replace(i, 1, ""); | |||||
| return sname; | |||||
| } | |||||
| static void json_read_shader_graph(const JSONReadState& state, Shader *shader,const rapidjson::Value& graph_node) | |||||
| { | |||||
| ShaderGraph *graph = new ShaderGraph(); | |||||
| map<string, ShaderNode*> nodemap; | |||||
| nodemap["output"] = graph->output(); | |||||
| for(rapidjson::Value::ConstMemberIterator itr = graph_node.MemberBegin(); itr != graph_node.MemberEnd(); ++itr) { | |||||
| ShaderNode *snode = NULL; | |||||
| if(string_iequals(itr->name.GetString(), "image_texture")) { | |||||
| ImageTextureNode *img = new ImageTextureNode(); | |||||
| json_read_string(&img->filename, itr->value["src"]); | |||||
| img->filename = path_join(state.base, img->filename); | |||||
| json_read_enum(&img->color_space, ImageTextureNode::color_space_enum, itr->value["color_space"]); | |||||
| json_read_enum(&img->projection, ImageTextureNode::projection_enum, itr->value["projection"]); | |||||
| json_read_float(&img->projection_blend, itr->value["projection_blend"]); | |||||
| snode = img; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "environment_texture")) { | |||||
| EnvironmentTextureNode *env = new EnvironmentTextureNode(); | |||||
| json_read_string(&env->filename, itr->value["src"]); | |||||
| env->filename = path_join(state.base, env->filename); | |||||
| json_read_enum(&env->color_space, EnvironmentTextureNode::color_space_enum, itr->value["color_space"]); | |||||
| json_read_enum(&env->projection, EnvironmentTextureNode::projection_enum, itr->value["projection"]); | |||||
| snode = env; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "osl_shader")) { | |||||
| OSLScriptNode *osl = new OSLScriptNode(); | |||||
| /* Source */ | |||||
| json_read_string(&osl->filepath, itr->value["src"]); | |||||
| if(path_is_relative(osl->filepath)) { | |||||
| osl->filepath = path_join(state.base, osl->filepath); | |||||
| } | |||||
| /* Generate inputs/outputs from node sockets | |||||
| * | |||||
| * Note: ShaderInput/ShaderOutput store shallow string copies only! | |||||
| * Socket names must be stored in the extra lists instead. */ | |||||
| /* read input values */ | |||||
| for(rapidjson::Value::ConstMemberIterator citr = itr->value.MemberBegin(); itr != itr->value.MemberEnd(); ++itr) { | |||||
| if (string_iequals(citr->name.GetString(), "input")) { | |||||
| string name; | |||||
| if (!json_read_string(&name, citr->value["name"])) | |||||
| continue; | |||||
| ShaderSocketType type = json_read_socket_type(citr->value["type"]); | |||||
| if (type == SHADER_SOCKET_UNDEFINED) | |||||
| continue; | |||||
| osl->input_names.push_back(ustring(name)); | |||||
| osl->add_input(osl->input_names.back().c_str(), type); | |||||
| } | |||||
| else if (string_iequals(citr->name.GetString(), "output")) { | |||||
| string name; | |||||
| if (!json_read_string(&name, citr->value["name"])) | |||||
| continue; | |||||
| ShaderSocketType type = json_read_socket_type(citr->value["type"]); | |||||
| if (type == SHADER_SOCKET_UNDEFINED) | |||||
| continue; | |||||
| osl->output_names.push_back(ustring(name)); | |||||
| osl->add_output(osl->output_names.back().c_str(), type); | |||||
| } | |||||
| } | |||||
| snode = osl; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "sky_texture")) { | |||||
| SkyTextureNode *sky = new SkyTextureNode(); | |||||
| json_read_enum(&sky->type, SkyTextureNode::type_enum, itr->value["type"]); | |||||
| json_read_float3(&sky->sun_direction, itr->value["sun_direction"]); | |||||
| json_read_float(&sky->turbidity, itr->value["turbidity"]); | |||||
| json_read_float(&sky->ground_albedo, itr->value["ground_albedo"]); | |||||
| snode = sky; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "noise_texture")) { | |||||
| snode = new NoiseTextureNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "checker_texture")) { | |||||
| snode = new CheckerTextureNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "brick_texture")) { | |||||
| BrickTextureNode *brick = new BrickTextureNode(); | |||||
| json_read_float(&brick->offset, itr->value["offset"]); | |||||
| json_read_int(&brick->offset_frequency, itr->value["offset_frequency"]); | |||||
| json_read_float(&brick->squash, itr->value["squash"]); | |||||
| json_read_int(&brick->squash_frequency, itr->value["squash_frequency"]); | |||||
| snode = brick; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "gradient_texture")) { | |||||
| GradientTextureNode *blend = new GradientTextureNode(); | |||||
| json_read_enum(&blend->type, GradientTextureNode::type_enum, itr->value["type"]); | |||||
| snode = blend; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "voronoi_texture")) { | |||||
| VoronoiTextureNode *voronoi = new VoronoiTextureNode(); | |||||
| json_read_enum(&voronoi->coloring, VoronoiTextureNode::coloring_enum, itr->value["coloring"]); | |||||
| snode = voronoi; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "musgrave_texture")) { | |||||
| MusgraveTextureNode *musgrave = new MusgraveTextureNode(); | |||||
| json_read_enum(&musgrave->type, MusgraveTextureNode::type_enum, itr->value["type"]); | |||||
| snode = musgrave; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "magic_texture")) { | |||||
| MagicTextureNode *magic = new MagicTextureNode(); | |||||
| json_read_int(&magic->depth, itr->value["depth"]); | |||||
| snode = magic; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "noise_texture")) { | |||||
| NoiseTextureNode *dist = new NoiseTextureNode(); | |||||
| snode = dist; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "wave_texture")) { | |||||
| WaveTextureNode *wave = new WaveTextureNode(); | |||||
| json_read_enum(&wave->type, WaveTextureNode::type_enum, itr->value["type"]); | |||||
| snode = wave; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "normal")) { | |||||
| NormalNode *normal = new NormalNode(); | |||||
| json_read_float3(&normal->direction, itr->value["direction"]); | |||||
| snode = normal; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "mapping")) { | |||||
| snode = new MappingNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "anisotropic_bsdf")) { | |||||
| AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode(); | |||||
| json_read_enum(&aniso->distribution, AnisotropicBsdfNode::distribution_enum, itr->value["distribution"]); | |||||
| snode = aniso; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "diffuse_bsdf")) { | |||||
| snode = new DiffuseBsdfNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "translucent_bsdf")) { | |||||
| snode = new TranslucentBsdfNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "transparent_bsdf")) { | |||||
| snode = new TransparentBsdfNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "velvet_bsdf")) { | |||||
| snode = new VelvetBsdfNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "toon_bsdf")) { | |||||
| ToonBsdfNode *toon = new ToonBsdfNode(); | |||||
| json_read_enum(&toon->component, ToonBsdfNode::component_enum, itr->value["component"]); | |||||
| snode = toon; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "glossy_bsdf")) { | |||||
| GlossyBsdfNode *glossy = new GlossyBsdfNode(); | |||||
| json_read_enum(&glossy->distribution, GlossyBsdfNode::distribution_enum, itr->value["distribution"]); | |||||
| snode = glossy; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "glass_bsdf")) { | |||||
| GlassBsdfNode *diel = new GlassBsdfNode(); | |||||
| json_read_enum(&diel->distribution, GlassBsdfNode::distribution_enum, itr->value["distribution"]); | |||||
| snode = diel; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "refraction_bsdf")) { | |||||
| RefractionBsdfNode *diel = new RefractionBsdfNode(); | |||||
| json_read_enum(&diel->distribution, RefractionBsdfNode::distribution_enum, itr->value["distribution"]); | |||||
| snode = diel; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "hair_bsdf")) { | |||||
| HairBsdfNode *hair = new HairBsdfNode(); | |||||
| json_read_enum(&hair->component, HairBsdfNode::component_enum, itr->value["component"]); | |||||
| snode = hair; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "emission")) { | |||||
| snode = new EmissionNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "ambient_occlusion")) { | |||||
| snode = new AmbientOcclusionNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "background")) { | |||||
| snode = new BackgroundNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "absorption_volume")) { | |||||
| snode = new AbsorptionVolumeNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "scatter_volume")) { | |||||
| snode = new ScatterVolumeNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "subsurface_scattering")) { | |||||
| SubsurfaceScatteringNode *sss = new SubsurfaceScatteringNode(); | |||||
| //json_read_enum(&sss->falloff, SubsurfaceScatteringNode::falloff_enum, itr->value["falloff"]); | |||||
| snode = sss; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "geometry")) { | |||||
| snode = new GeometryNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "texture_coordinate")) { | |||||
| snode = new TextureCoordinateNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "light_path")) { | |||||
| snode = new LightPathNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "light_falloff")) { | |||||
| snode = new LightFalloffNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "object_info")) { | |||||
| snode = new ObjectInfoNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "particle_info")) { | |||||
| snode = new ParticleInfoNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "hair_info")) { | |||||
| snode = new HairInfoNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "value")) { | |||||
| ValueNode *value = new ValueNode(); | |||||
| json_read_float(&value->value, itr->value["value"]); | |||||
| snode = value; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "color")) { | |||||
| ColorNode *color = new ColorNode(); | |||||
| json_read_float3(&color->value, itr->value["value"]); | |||||
| snode = color; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "mix_closure")) { | |||||
| snode = new MixClosureNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "add_closure")) { | |||||
| snode = new AddClosureNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "invert")) { | |||||
| snode = new InvertNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "mix")) { | |||||
| MixNode *mix = new MixNode(); | |||||
| json_read_enum(&mix->type, MixNode::type_enum, itr->value["type"]); | |||||
| json_read_bool(&mix->use_clamp, itr->value["use_clamp"]); | |||||
| snode = mix; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "gamma")) { | |||||
| snode = new GammaNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "brightness")) { | |||||
| snode = new BrightContrastNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "combine_rgb")) { | |||||
| snode = new CombineRGBNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "separate_rgb")) { | |||||
| snode = new SeparateRGBNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "combine_hsv")) { | |||||
| snode = new CombineHSVNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "separate_hsv")) { | |||||
| snode = new SeparateHSVNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "combine_xyz")) { | |||||
| snode = new CombineHSVNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "separate_xyz")) { | |||||
| snode = new SeparateHSVNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "hsv")) { | |||||
| snode = new HSVNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "wavelength")) { | |||||
| snode = new WavelengthNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "blackbody")) { | |||||
| snode = new BlackbodyNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "attribute")) { | |||||
| AttributeNode *attr = new AttributeNode(); | |||||
| json_read_ustring(&attr->attribute, itr->value["attribute"]); | |||||
| snode = attr; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "uv_map")) { | |||||
| UVMapNode *uvm = new UVMapNode(); | |||||
| json_read_ustring(&uvm->attribute, itr->value["uv_map"]); | |||||
| snode = uvm; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "camera")) { | |||||
| snode = new CameraNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "fresnel")) { | |||||
| snode = new FresnelNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "layer_weight")) { | |||||
| snode = new LayerWeightNode(); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "wireframe")) { | |||||
| WireframeNode *wire = new WireframeNode; | |||||
| json_read_bool(&wire->use_pixel_size, itr->value["use_pixel_size"]); | |||||
| snode = wire; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "normal_map")) { | |||||
| NormalMapNode *nmap = new NormalMapNode; | |||||
| json_read_ustring(&nmap->attribute, itr->value["attribute"]); | |||||
| json_read_enum(&nmap->space, NormalMapNode::space_enum, itr->value["space"]); | |||||
| snode = nmap; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "tangent")) { | |||||
| TangentNode *tangent = new TangentNode; | |||||
| json_read_ustring(&tangent->attribute, itr->value["attribute"]); | |||||
| json_read_enum(&tangent->direction_type, TangentNode::direction_type_enum, itr->value["direction_type"]); | |||||
| json_read_enum(&tangent->axis, TangentNode::axis_enum, itr->value["axis"]); | |||||
| snode = tangent; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "math")) { | |||||
| MathNode *math = new MathNode(); | |||||
| json_read_enum(&math->type, MathNode::type_enum, itr->value["type"]); | |||||
| json_read_bool(&math->use_clamp, itr->value["use_clamp"]); | |||||
| snode = math; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "vector_math")) { | |||||
| VectorMathNode *vmath = new VectorMathNode(); | |||||
| json_read_enum(&vmath->type, VectorMathNode::type_enum, itr->value["type"]); | |||||
| snode = vmath; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "vector_transform")) { | |||||
| VectorTransformNode *vtransform = new VectorTransformNode(); | |||||
| json_read_enum(&vtransform->type, VectorTransformNode::type_enum, itr->value["type"]); | |||||
| json_read_enum(&vtransform->convert_from, VectorTransformNode::convert_space_enum, itr->value["convert_from"]); | |||||
| json_read_enum(&vtransform->convert_to, VectorTransformNode::convert_space_enum, itr->value["convert_to"]); | |||||
| snode = vtransform; | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "connect")) { | |||||
| /* connect nodes */ | |||||
| vector<string> from_tokens, to_tokens; | |||||
| string_split(from_tokens, itr->value["from"].GetString()); | |||||
| string_split(to_tokens, itr->value["to"].GetString()); | |||||
| if(from_tokens.size() == 2 && to_tokens.size() == 2) { | |||||
| /* find nodes and sockets */ | |||||
| ShaderOutput *output = NULL; | |||||
| ShaderInput *input = NULL; | |||||
| if(nodemap.find(from_tokens[0]) != nodemap.end()) { | |||||
| ShaderNode *fromnode = nodemap[from_tokens[0]]; | |||||
| foreach(ShaderOutput *out, fromnode->outputs) | |||||
| if(string_iequals(json_socket_name(out->name), from_tokens[1])) | |||||
| output = out; | |||||
| if(!output) | |||||
| fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_tokens[1].c_str(), from_tokens[0].c_str()); | |||||
| } | |||||
| else | |||||
| fprintf(stderr, "Unknown shader node name \"%s\".\n", from_tokens[0].c_str()); | |||||
| if(nodemap.find(to_tokens[0]) != nodemap.end()) { | |||||
| ShaderNode *tonode = nodemap[to_tokens[0]]; | |||||
| foreach(ShaderInput *in, tonode->inputs) | |||||
| if(string_iequals(json_socket_name(in->name), to_tokens[1])) | |||||
| input = in; | |||||
| if(!input) | |||||
| fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_tokens[1].c_str(), to_tokens[0].c_str()); | |||||
| } | |||||
| else | |||||
| fprintf(stderr, "Unknown shader node name \"%s\".\n", to_tokens[0].c_str()); | |||||
| /* connect */ | |||||
| if(output && input) | |||||
| graph->connect(output, input); | |||||
| } | |||||
| else | |||||
| fprintf(stderr, "Invalid from or to value for connect node.\n"); | |||||
| } | |||||
| else | |||||
| fprintf(stderr, "Unknown shader node \"%s\".\n", itr->name.GetString()); | |||||
| if(snode) { | |||||
| /* add to graph */ | |||||
| graph->add(snode); | |||||
| /* add to map for name lookups */ | |||||
| string name = ""; | |||||
| json_read_string(&name, itr->value["name"]); | |||||
| nodemap[name] = snode; | |||||
| /* read input values */ | |||||
| for(rapidjson::Value::ConstMemberIterator citr = itr->value.MemberBegin(); itr != itr->value.MemberEnd(); ++itr) { | |||||
| foreach(ShaderInput *in, snode->inputs) { | |||||
| if(string_iequals(in->name, citr->name.GetString())) { | |||||
| switch(in->type) { | |||||
| case SHADER_SOCKET_FLOAT: | |||||
| case SHADER_SOCKET_INT: | |||||
| json_read_float(&in->value.x, itr->value[citr->name.GetString()]); | |||||
| break; | |||||
| case SHADER_SOCKET_COLOR: | |||||
| case SHADER_SOCKET_VECTOR: | |||||
| case SHADER_SOCKET_POINT: | |||||
| case SHADER_SOCKET_NORMAL: | |||||
| json_read_float3(&in->value, itr->value[citr->name.GetString()]); | |||||
| break; | |||||
| case SHADER_SOCKET_STRING: | |||||
| json_read_ustring( &in->value_string, itr->value[citr->name.GetString()] ); | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| shader->set_graph(graph); | |||||
| shader->tag_update(state.scene); | |||||
| } | |||||
| static void json_read_shader(const JSONReadState& state,const rapidjson::Value& node) | |||||
| { | |||||
| Shader *shader = new Shader(); | |||||
| json_read_string(&shader->name, node["name"]); | |||||
| json_read_bool(&shader->use_mis, node["use_mis"]); | |||||
| json_read_bool(&shader->use_transparent_shadow, node["use_transparent_shadow"]); | |||||
| json_read_bool(&shader->heterogeneous_volume, node["heterogeneous_volume"]); | |||||
| json_read_shader_graph(state, shader, node); | |||||
| state.scene->shaders.push_back(shader); | |||||
| } | |||||
| /* Background */ | |||||
| static void json_read_background(const JSONReadState& state,const rapidjson::Value& node) | |||||
| { | |||||
| Shader *shader = state.scene->shaders[state.scene->default_background]; | |||||
| json_read_bool(&shader->heterogeneous_volume, node["heterogeneous_volume"]); | |||||
| json_read_shader_graph(state, shader, node); | |||||
| } | |||||
| /* Mesh */ | |||||
| static Mesh *json_add_mesh(Scene *scene, const Transform& tfm) | |||||
| { | |||||
| /* create mesh */ | |||||
| Mesh *mesh = new Mesh(); | |||||
| scene->meshes.push_back(mesh); | |||||
| /* create object*/ | |||||
| Object *object = new Object(); | |||||
| object->mesh = mesh; | |||||
| object->tfm = tfm; | |||||
| scene->objects.push_back(object); | |||||
| return mesh; | |||||
| } | |||||
| static void json_read_mesh(const JSONReadState& state,const rapidjson::Value& node) | |||||
| { | |||||
| /* add mesh */ | |||||
| Mesh *mesh = json_add_mesh(state.scene, state.tfm); | |||||
| mesh->used_shaders.push_back(state.shader); | |||||
| /* read state */ | |||||
| int shader = state.shader; | |||||
| bool smooth = state.smooth; | |||||
| mesh->displacement_method = state.displacement_method; | |||||
| /* read vertices and polygons, RIB style */ | |||||
| vector<float3> P; | |||||
| vector<int> verts, nverts; | |||||
| json_read_float3_array(P, node["P"]); | |||||
| json_read_int_array(verts, node["verts"]); | |||||
| json_read_int_array(nverts, node["nverts"]); | |||||
| if(json_equal_string(node["subdivision"], "catmull-clark")) { | |||||
| /* create subd mesh */ | |||||
| SubdMesh sdmesh; | |||||
| /* create subd vertices */ | |||||
| for(size_t i = 0; i < P.size(); i++) | |||||
| sdmesh.add_vert(P[i]); | |||||
| /* create subd faces */ | |||||
| int index_offset = 0; | |||||
| for(size_t i = 0; i < nverts.size(); i++) { | |||||
| if(nverts[i] == 4) { | |||||
| int v0 = verts[index_offset + 0]; | |||||
| int v1 = verts[index_offset + 1]; | |||||
| int v2 = verts[index_offset + 2]; | |||||
| int v3 = verts[index_offset + 3]; | |||||
| sdmesh.add_face(v0, v1, v2, v3); | |||||
| } | |||||
| else { | |||||
| for(int j = 0; j < nverts[i]-2; j++) { | |||||
| int v0 = verts[index_offset]; | |||||
| int v1 = verts[index_offset + j + 1]; | |||||
| int v2 = verts[index_offset + j + 2]; | |||||
| sdmesh.add_face(v0, v1, v2); | |||||
| } | |||||
| } | |||||
| index_offset += nverts[i]; | |||||
| } | |||||
| /* finalize subd mesh */ | |||||
| sdmesh.finish(); | |||||
| /* parameters */ | |||||
| SubdParams sdparams(mesh, shader, smooth); | |||||
| json_read_float(&sdparams.dicing_rate, node["dicing_rate"]); | |||||
| DiagSplit dsplit(sdparams); | |||||
| sdmesh.tessellate(&dsplit); | |||||
| } | |||||
| else { | |||||
| /* create vertices */ | |||||
| mesh->verts = P; | |||||
| /* create triangles */ | |||||
| int index_offset = 0; | |||||
| for(size_t i = 0; i < nverts.size(); i++) { | |||||
| for(int j = 0; j < nverts[i]-2; j++) { | |||||
| int v0 = verts[index_offset]; | |||||
| int v1 = verts[index_offset + j + 1]; | |||||
| int v2 = verts[index_offset + j + 2]; | |||||
| assert(v0 < (int)P.size()); | |||||
| assert(v1 < (int)P.size()); | |||||
| assert(v2 < (int)P.size()); | |||||
| mesh->add_triangle(v0, v1, v2, shader, smooth); | |||||
| } | |||||
| index_offset += nverts[i]; | |||||
| } | |||||
| } | |||||
| /* temporary for test compatibility */ | |||||
| mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); | |||||
| } | |||||
| /* Patch */ | |||||
| static void json_read_patch(const JSONReadState& state,const rapidjson::Value& node) | |||||
| { | |||||
| /* read patch */ | |||||
| Patch *patch = NULL; | |||||
| vector<float3> P; | |||||
| json_read_float3_array(P, node["P"]); | |||||
| if(json_equal_string(node["type"], "bilinear")) { | |||||
| /* bilinear patch */ | |||||
| if(P.size() == 4) { | |||||
| LinearQuadPatch *bpatch = new LinearQuadPatch(); | |||||
| for(int i = 0; i < 4; i++) | |||||
| P[i] = transform_point(&state.tfm, P[i]); | |||||
| memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull)); | |||||
| patch = bpatch; | |||||
| } | |||||
| else | |||||
| fprintf(stderr, "Invalid number of control points for bilinear patch.\n"); | |||||
| } | |||||
| else if(json_equal_string(node["type"], "bicubic")) { | |||||
| /* bicubic patch */ | |||||
| if(P.size() == 16) { | |||||
| BicubicPatch *bpatch = new BicubicPatch(); | |||||
| for(int i = 0; i < 16; i++) | |||||
| P[i] = transform_point(&state.tfm, P[i]); | |||||
| memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull)); | |||||
| patch = bpatch; | |||||
| } | |||||
| else | |||||
| fprintf(stderr, "Invalid number of control points for bicubic patch.\n"); | |||||
| } | |||||
| else | |||||
| fprintf(stderr, "Unknown patch type.\n"); | |||||
| if(patch) { | |||||
| /* add mesh */ | |||||
| Mesh *mesh = json_add_mesh(state.scene, transform_identity()); | |||||
| mesh->used_shaders.push_back(state.shader); | |||||
| /* split */ | |||||
| SubdParams sdparams(mesh, state.shader, state.smooth); | |||||
| json_read_float(&sdparams.dicing_rate, node["dicing_rate"]); | |||||
| DiagSplit dsplit(sdparams); | |||||
| dsplit.split_quad(patch); | |||||
| delete patch; | |||||
| /* temporary for test compatibility */ | |||||
| mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); | |||||
| } | |||||
| } | |||||
| /* Light */ | |||||
| static void json_read_light(const JSONReadState& state,const rapidjson::Value& node) | |||||
| { | |||||
| Light *light = new Light(); | |||||
| light->shader = state.shader; | |||||
| /* Light Type | |||||
| * 0: Point, 1: Sun, 3: Area, 5: Spot */ | |||||
| int type = 0; | |||||
| json_read_int(&type, node["type"]); | |||||
| light->type = (LightType)type; | |||||
| /* Spot Light */ | |||||
| json_read_float(&light->spot_angle, node["spot_angle"]); | |||||
| json_read_float(&light->spot_smooth, node["spot_smooth"]); | |||||
| /* Area Light */ | |||||
| json_read_float(&light->sizeu, node["sizeu"]); | |||||
| json_read_float(&light->sizev, node["sizev"]); | |||||
| json_read_float3(&light->axisu, node["axisu"]); | |||||
| json_read_float3(&light->axisv, node["axisv"]); | |||||
| /* Generic */ | |||||
| json_read_float(&light->size, node["size"]); | |||||
| json_read_float3(&light->dir, node["dir"]); | |||||
| json_read_float3(&light->co, node["P"]); | |||||
| light->co = transform_point(&state.tfm, light->co); | |||||
| state.scene->lights.push_back(light); | |||||
| } | |||||
| /* Transform */ | |||||
| static void json_read_transform(const rapidjson::Value& node, Transform& tfm) | |||||
| { | |||||
| if(node["matrix"].IsObject()) { | |||||
| vector<float> matrix; | |||||
| if(json_read_float_array(matrix, node["matrix"]) && matrix.size() == 16) | |||||
| tfm = tfm * transform_transpose((*(Transform*)&matrix[0])); | |||||
| } | |||||
| if(node["translate"].IsObject()) { | |||||
| float3 translate = make_float3(0.0f, 0.0f, 0.0f); | |||||
| json_read_float3(&translate, node["translate"]); | |||||
| tfm = tfm * transform_translate(translate); | |||||
| } | |||||
| if(node["rotate"].IsObject()) { | |||||
| float4 rotate = make_float4(0.0f, 0.0f, 0.0f, 0.0f); | |||||
| json_read_float4(&rotate, node["rotate"]); | |||||
| tfm = tfm * transform_rotate(DEG2RADF(rotate.x), make_float3(rotate.y, rotate.z, rotate.w)); | |||||
| } | |||||
| if(node["scale"].IsObject()) { | |||||
| float3 scale = make_float3(0.0f, 0.0f, 0.0f); | |||||
| json_read_float3(&scale, node["scale"]); | |||||
| tfm = tfm * transform_scale(scale); | |||||
| } | |||||
| } | |||||
| /* State */ | |||||
| static void json_read_state(JSONReadState& state, const rapidjson::Value& node) | |||||
| { | |||||
| /* read shader */ | |||||
| string shadername; | |||||
| if(json_read_string(&shadername, node["shader"])) { | |||||
| int i = 0; | |||||
| bool found = false; | |||||
| foreach(Shader *shader, state.scene->shaders) { | |||||
| if(shader->name == shadername) { | |||||
| state.shader = i; | |||||
| found = true; | |||||
| break; | |||||
| } | |||||
| i++; | |||||
| } | |||||
| if(!found) | |||||
| fprintf(stderr, "Unknown shader \"%s\".\n", shadername.c_str()); | |||||
| } | |||||
| json_read_float(&state.dicing_rate, node["dicing_rate"]); | |||||
| /* read smooth/flat */ | |||||
| if(json_equal_string(node["interpolation"], "smooth")) | |||||
| state.smooth = true; | |||||
| else if(json_equal_string(node["interpolation"], "flat")) | |||||
| state.smooth = false; | |||||
| /* read displacement method */ | |||||
| if(json_equal_string(node["displacement_method"], "true")) | |||||
| state.displacement_method = Mesh::DISPLACE_TRUE; | |||||
| else if(json_equal_string(node["displacement_method"], "bump")) | |||||
| state.displacement_method = Mesh::DISPLACE_BUMP; | |||||
| else if(json_equal_string(node["displacement_method"], "both")) | |||||
| state.displacement_method = Mesh::DISPLACE_BOTH; | |||||
| } | |||||
| /* Scene */ | |||||
| static void json_read_include(const JSONReadState& state, const string& src); | |||||
| static void json_read_scene(const JSONReadState& state,const rapidjson::Value& scene_node) | |||||
| { | |||||
| for(rapidjson::Value::ConstMemberIterator itr = scene_node.MemberBegin(); itr != scene_node.MemberEnd(); ++itr) { | |||||
| if(string_iequals(itr->name.GetString(), "film")) { | |||||
| json_read_film(state, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "integrator")) { | |||||
| json_read_integrator(state, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "camera")) { | |||||
| json_read_camera(state, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "shader")) { | |||||
| json_read_shader(state, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "background")) { | |||||
| json_read_background(state, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "mesh")) { | |||||
| json_read_mesh(state, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "patch")) { | |||||
| json_read_patch(state, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "light")) { | |||||
| json_read_light(state, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "transform")) { | |||||
| JSONReadState substate = state; | |||||
| json_read_transform(itr->value, substate.tfm); | |||||
| json_read_scene(substate, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "state")) { | |||||
| JSONReadState substate = state; | |||||
| json_read_state(substate, itr->value); | |||||
| json_read_scene(substate, itr->value); | |||||
| } | |||||
| else if(string_iequals(itr->name.GetString(), "include")) { | |||||
| string src; | |||||
| if(json_read_string(&src, itr->value["src"])) | |||||
| json_read_include(state, src); | |||||
| } | |||||
| else | |||||
| fprintf(stderr, "Unknown node \"%s\".\n", itr->name.GetString()); | |||||
| } | |||||
| } | |||||
| /* Include */ | |||||
| static void json_read_include(const JSONReadState& state, const string& src) | |||||
| { | |||||
| string path = path_join(state.base, src); | |||||
| FILE * pFile = fopen (path.c_str(), "r"); | |||||
| rapidjson::FileStream jsonFile(pFile); | |||||
| /* open XML document */ | |||||
| rapidjson::Document doc; | |||||
| doc.ParseStream<0>(jsonFile); | |||||
| if(!doc.HasParseError()) { | |||||
| JSONReadState substate = state; | |||||
| substate.base = path_dirname(path); | |||||
| json_read_scene(substate, doc); | |||||
| } | |||||
| else { | |||||
| fprintf(stderr, "%s read error\n", src.c_str()); | |||||
| exit(EXIT_FAILURE); | |||||
| } | |||||
| } | |||||
| /* File */ | |||||
| void json_read_file(Scene *scene, const char *filepath) | |||||
| { | |||||
| JSONReadState state; | |||||
| state.scene = scene; | |||||
| state.tfm = transform_identity(); | |||||
| state.shader = scene->default_surface; | |||||
| state.smooth = false; | |||||
| state.dicing_rate = 0.1f; | |||||
| state.base = path_dirname(filepath); | |||||
| json_read_include(state, path_filename(filepath)); | |||||
| scene->params.bvh_type = SceneParams::BVH_STATIC; | |||||
| } | |||||
| CCL_NAMESPACE_END | |||||