2023-06-14 16:52:36 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
#include <cstdio>
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
2017-03-29 16:53:46 +02:00
|
|
|
#include "graph/node_xml.h"
|
|
|
|
|
|
2022-03-23 17:45:34 +01:00
|
|
|
#include "scene/alembic.h"
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "scene/background.h"
|
|
|
|
|
#include "scene/camera.h"
|
|
|
|
|
#include "scene/film.h"
|
|
|
|
|
#include "scene/integrator.h"
|
|
|
|
|
#include "scene/light.h"
|
|
|
|
|
#include "scene/mesh.h"
|
|
|
|
|
#include "scene/object.h"
|
|
|
|
|
#include "scene/osl.h"
|
|
|
|
|
#include "scene/scene.h"
|
|
|
|
|
#include "scene/shader.h"
|
|
|
|
|
#include "scene/shader_graph.h"
|
|
|
|
|
#include "scene/shader_nodes.h"
|
2017-03-29 16:53:46 +02:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "util/path.h"
|
|
|
|
|
#include "util/projection.h"
|
|
|
|
|
#include "util/transform.h"
|
|
|
|
|
#include "util/xml.h"
|
2017-03-29 16:53:46 +02:00
|
|
|
|
|
|
|
|
#include "app/cycles_xml.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
/* XML reading state */
|
|
|
|
|
|
2016-05-07 20:05:21 +02:00
|
|
|
struct XMLReadState : public XMLReader {
|
2024-12-26 17:53:59 +01:00
|
|
|
Scene *scene = nullptr; /* Scene pointer. */
|
|
|
|
|
Transform tfm; /* Current transform state. */
|
|
|
|
|
bool smooth = false; /* Smooth normal state. */
|
|
|
|
|
Shader *shader = nullptr; /* Current shader. */
|
|
|
|
|
string base; /* Base path to current file. */
|
|
|
|
|
float dicing_rate = 1.0f; /* Current dicing rate. */
|
|
|
|
|
Object *object = nullptr; /* Current object. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:55 +01:00
|
|
|
XMLReadState()
|
2015-04-30 15:46:09 +05:00
|
|
|
{
|
|
|
|
|
tfm = transform_identity();
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Attribute Reading */
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static bool xml_read_int(int *value, const xml_node node, const char *name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const xml_attribute attr = node.attribute(name);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
if (attr) {
|
|
|
|
|
*value = atoi(attr.value());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static bool xml_read_int_array(vector<int> &value, const xml_node node, const char *name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const xml_attribute attr = node.attribute(name);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
if (attr) {
|
|
|
|
|
vector<string> tokens;
|
|
|
|
|
string_split(tokens, attr.value());
|
|
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (const string &token : tokens) {
|
2011-04-27 11:58:34 +00:00
|
|
|
value.push_back(atoi(token.c_str()));
|
2024-12-26 19:41:25 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static bool xml_read_float(float *value, const xml_node node, const char *name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const xml_attribute attr = node.attribute(name);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
if (attr) {
|
2014-05-04 03:15:20 +10:00
|
|
|
*value = (float)atof(attr.value());
|
2011-04-27 11:58:34 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static bool xml_read_float_array(vector<float> &value, const xml_node node, const char *name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const xml_attribute attr = node.attribute(name);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
if (attr) {
|
|
|
|
|
vector<string> tokens;
|
|
|
|
|
string_split(tokens, attr.value());
|
|
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (const string &token : tokens) {
|
2014-05-04 03:15:20 +10:00
|
|
|
value.push_back((float)atof(token.c_str()));
|
2024-12-26 19:41:25 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static bool xml_read_float3(float3 *value, const xml_node node, const char *name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
vector<float> array;
|
|
|
|
|
|
|
|
|
|
if (xml_read_float_array(array, node, name) && array.size() == 3) {
|
|
|
|
|
*value = make_float3(array[0], array[1], array[2]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static bool xml_read_float3_array(vector<float3> &value, const xml_node node, const char *name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
vector<float> array;
|
|
|
|
|
|
|
|
|
|
if (xml_read_float_array(array, node, name)) {
|
2023-09-17 09:01:48 +10:00
|
|
|
for (size_t i = 0; i < array.size(); i += 3) {
|
2011-04-27 11:58:34 +00:00
|
|
|
value.push_back(make_float3(array[i + 0], array[i + 1], array[i + 2]));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static bool xml_read_float4(float4 *value, const xml_node node, const char *name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
vector<float> array;
|
|
|
|
|
|
|
|
|
|
if (xml_read_float_array(array, node, name) && array.size() == 4) {
|
|
|
|
|
*value = make_float4(array[0], array[1], array[2], array[3]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static bool xml_read_string(string *str, const xml_node node, const char *name)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const xml_attribute attr = node.attribute(name);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
if (attr) {
|
|
|
|
|
*str = attr.value();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static bool xml_equal_string(const xml_node node, const char *name, const char *value)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const xml_attribute attr = node.attribute(name);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (attr) {
|
2011-04-27 11:58:34 +00:00
|
|
|
return string_iequals(attr.value(), value);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Camera */
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_camera(XMLReadState &state, const xml_node node)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
Camera *cam = state.scene->camera;
|
|
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
int width = -1;
|
|
|
|
|
int height = -1;
|
2021-01-18 07:43:42 +01:00
|
|
|
xml_read_int(&width, node, "width");
|
|
|
|
|
xml_read_int(&height, node, "height");
|
2014-01-25 18:57:02 +01:00
|
|
|
|
2021-01-18 07:43:42 +01:00
|
|
|
cam->set_full_width(width);
|
|
|
|
|
cam->set_full_height(height);
|
2016-08-23 13:57:45 -04:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
xml_read_node(state, cam, node);
|
2012-05-04 16:20:51 +00:00
|
|
|
|
2021-01-18 07:43:42 +01:00
|
|
|
cam->set_matrix(state.tfm);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-01-18 07:43:42 +01:00
|
|
|
cam->need_flags_update = true;
|
2018-03-02 19:54:14 +01:00
|
|
|
cam->update(state.scene);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2022-03-23 17:45:34 +01:00
|
|
|
/* Alembic */
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_ALEMBIC
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_alembic(XMLReadState &state, const xml_node graph_node)
|
2022-03-23 17:45:34 +01:00
|
|
|
{
|
|
|
|
|
AlembicProcedural *proc = state.scene->create_node<AlembicProcedural>();
|
|
|
|
|
xml_read_node(state, proc, graph_node);
|
|
|
|
|
|
|
|
|
|
for (xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
|
|
|
|
|
if (string_iequals(node.name(), "object")) {
|
|
|
|
|
string path;
|
|
|
|
|
if (xml_read_string(&path, node, "path")) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const ustring object_path(path, 0);
|
2024-12-26 17:53:59 +01:00
|
|
|
AlembicObject *object = proc->get_or_create_object(object_path);
|
2022-03-23 17:45:34 +01:00
|
|
|
|
|
|
|
|
array<Node *> used_shaders = object->get_used_shaders();
|
|
|
|
|
used_shaders.push_back_slow(state.shader);
|
|
|
|
|
object->set_used_shaders(used_shaders);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Shader */
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_shader_graph(XMLReadState &state, Shader *shader, const xml_node graph_node)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-08 00:18:32 +02:00
|
|
|
xml_read_node(state, shader, graph_node);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 23:13:45 +01:00
|
|
|
unique_ptr<ShaderGraph> graph = make_unique<ShaderGraph>();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
/* local state, shader nodes can't link to nodes outside the shader graph */
|
|
|
|
|
XMLReader graph_reader;
|
|
|
|
|
graph_reader.node_map[ustring("output")] = graph->output();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-11-10 10:04:33 +01:00
|
|
|
for (xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
|
2016-05-07 19:48:28 +02:00
|
|
|
ustring node_name(node.name());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
if (node_name == "connect") {
|
|
|
|
|
/* connect nodes */
|
2024-12-29 17:32:00 +01:00
|
|
|
vector<string> from_tokens;
|
|
|
|
|
vector<string> to_tokens;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
string_split(from_tokens, node.attribute("from").value());
|
|
|
|
|
string_split(to_tokens, node.attribute("to").value());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
if (from_tokens.size() == 2 && to_tokens.size() == 2) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const ustring from_node_name(from_tokens[0]);
|
|
|
|
|
const ustring from_socket_name(from_tokens[1]);
|
|
|
|
|
const ustring to_node_name(to_tokens[0]);
|
|
|
|
|
const ustring to_socket_name(to_tokens[1]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
/* find nodes and sockets */
|
2024-12-26 17:53:55 +01:00
|
|
|
ShaderOutput *output = nullptr;
|
|
|
|
|
ShaderInput *input = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
if (graph_reader.node_map.find(from_node_name) != graph_reader.node_map.end()) {
|
|
|
|
|
ShaderNode *fromnode = (ShaderNode *)graph_reader.node_map[from_node_name];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderOutput *out : fromnode->outputs) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (string_iequals(out->socket_type.name.string(), from_socket_name.string())) {
|
2016-05-07 19:48:28 +02:00
|
|
|
output = out;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2024-12-26 19:41:25 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!output) {
|
2016-05-07 19:48:28 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
|
"Unknown output socket name \"%s\" on \"%s\".\n",
|
|
|
|
|
from_node_name.c_str(),
|
|
|
|
|
from_socket_name.c_str());
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2016-05-07 19:48:28 +02:00
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2016-05-07 19:48:28 +02:00
|
|
|
fprintf(stderr, "Unknown shader node name \"%s\".\n", from_node_name.c_str());
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
if (graph_reader.node_map.find(to_node_name) != graph_reader.node_map.end()) {
|
|
|
|
|
ShaderNode *tonode = (ShaderNode *)graph_reader.node_map[to_node_name];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderInput *in : tonode->inputs) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (string_iequals(in->socket_type.name.string(), to_socket_name.string())) {
|
2016-05-07 19:48:28 +02:00
|
|
|
input = in;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2024-12-26 19:41:25 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!input) {
|
2016-05-07 19:48:28 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
|
"Unknown input socket name \"%s\" on \"%s\".\n",
|
|
|
|
|
to_socket_name.c_str(),
|
|
|
|
|
to_node_name.c_str());
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2016-05-07 19:48:28 +02:00
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2016-05-07 19:48:28 +02:00
|
|
|
fprintf(stderr, "Unknown shader node name \"%s\".\n", to_node_name.c_str());
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
/* connect */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (output && input) {
|
2016-05-07 19:48:28 +02:00
|
|
|
graph->connect(output, input);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2016-05-07 19:48:28 +02:00
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2016-05-07 19:48:28 +02:00
|
|
|
fprintf(stderr, "Invalid from or to value for connect node.\n");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
continue;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:55 +01:00
|
|
|
ShaderNode *snode = nullptr;
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2016-05-31 15:32:31 +02:00
|
|
|
#ifdef WITH_OSL
|
2016-05-07 19:48:28 +02:00
|
|
|
if (node_name == "osl_shader") {
|
2024-12-29 23:13:45 +01:00
|
|
|
ShaderManager *manager = state.scene->shader_manager.get();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (manager->use_osl()) {
|
|
|
|
|
std::string filepath;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (xml_read_string(&filepath, node, "src")) {
|
|
|
|
|
if (path_is_relative(filepath)) {
|
|
|
|
|
filepath = path_join(state.base, filepath);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
snode = OSLShaderManager::osl_node(graph.get(), state.scene, filepath, "");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (!snode) {
|
|
|
|
|
fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str());
|
2016-05-07 19:48:28 +02:00
|
|
|
continue;
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
2014-02-24 11:24:43 +01:00
|
|
|
}
|
2016-05-29 15:10:34 +02:00
|
|
|
else {
|
|
|
|
|
fprintf(stderr, "OSL node missing \"src\" attribute.\n");
|
2016-05-07 19:48:28 +02:00
|
|
|
continue;
|
2014-02-24 11:24:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-29 15:10:34 +02:00
|
|
|
else {
|
|
|
|
|
fprintf(stderr, "OSL node without using --shadingsys osl.\n");
|
2016-05-07 19:48:28 +02:00
|
|
|
continue;
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
2014-01-26 16:22:19 +01:00
|
|
|
}
|
2016-05-07 19:48:28 +02:00
|
|
|
else
|
2016-05-31 15:32:31 +02:00
|
|
|
#endif
|
2016-05-07 19:48:28 +02:00
|
|
|
{
|
|
|
|
|
/* exception for name collision */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (node_name == "background") {
|
2016-05-07 19:48:28 +02:00
|
|
|
node_name = "background_shader";
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
const NodeType *node_type = NodeType::find(node_name);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
if (!node_type) {
|
|
|
|
|
fprintf(stderr, "Unknown shader node \"%s\".\n", node.name());
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node_type->type != NodeType::SHADER) {
|
2016-05-07 19:48:28 +02:00
|
|
|
fprintf(stderr, "Node type \"%s\" is not a shader node.\n", node_type->name.c_str());
|
|
|
|
|
continue;
|
2016-05-19 11:35:50 +02:00
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node_type->create == nullptr) {
|
2020-02-03 09:02:00 +01:00
|
|
|
fprintf(stderr, "Can't create abstract node type \"%s\".\n", node_type->name.c_str());
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-30 02:20:36 +01:00
|
|
|
snode = graph->create_node(node_type);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
xml_read_node(graph_reader, snode, node);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
if (node_name == "image_texture") {
|
|
|
|
|
ImageTextureNode *img = (ImageTextureNode *)snode;
|
2024-12-29 17:32:00 +01:00
|
|
|
const ustring filename(path_join(state.base, img->get_filename().string()));
|
2021-01-18 07:43:42 +01:00
|
|
|
img->set_filename(filename);
|
2016-05-07 19:48:28 +02:00
|
|
|
}
|
|
|
|
|
else if (node_name == "environment_texture") {
|
|
|
|
|
EnvironmentTextureNode *env = (EnvironmentTextureNode *)snode;
|
2024-12-29 17:32:00 +01:00
|
|
|
const ustring filename(path_join(state.base, env->get_filename().string()));
|
2021-01-18 07:43:42 +01:00
|
|
|
env->set_filename(filename);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->set_graph(std::move(graph));
|
2011-04-27 11:58:34 +00:00
|
|
|
shader->tag_update(state.scene);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_shader(XMLReadState &state, const xml_node node)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-30 02:20:36 +01:00
|
|
|
Shader *shader = state.scene->create_node<Shader>();
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_shader_graph(state, shader, node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Background */
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_background(XMLReadState &state, const xml_node node)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2015-06-10 21:27:20 +02:00
|
|
|
/* Background Settings */
|
2016-05-07 20:30:16 +02:00
|
|
|
xml_read_node(state, state.scene->background, node);
|
2015-06-10 21:27:20 +02:00
|
|
|
|
|
|
|
|
/* Background Shader */
|
2016-05-14 14:50:03 +02:00
|
|
|
Shader *shader = state.scene->default_background;
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_shader_graph(state, shader, node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mesh */
|
|
|
|
|
|
2024-01-15 20:04:22 +01:00
|
|
|
static Mesh *xml_add_mesh(Scene *scene, const Transform &tfm, Object *object)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-01-15 20:04:22 +01:00
|
|
|
if (object && object->get_geometry()->is_mesh()) {
|
|
|
|
|
/* Use existing object and mesh */
|
|
|
|
|
object->set_tfm(tfm);
|
|
|
|
|
Geometry *geometry = object->get_geometry();
|
|
|
|
|
return static_cast<Mesh *>(geometry);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
/* Create mesh */
|
2024-12-30 02:20:36 +01:00
|
|
|
Mesh *mesh = scene->create_node<Mesh>();
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
/* Create object. */
|
2024-12-30 02:20:36 +01:00
|
|
|
object = scene->create_node<Object>();
|
2024-12-26 17:53:59 +01:00
|
|
|
object->set_geometry(mesh);
|
|
|
|
|
object->set_tfm(tfm);
|
|
|
|
|
|
|
|
|
|
return mesh;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_mesh(const XMLReadState &state, const xml_node node)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* add mesh */
|
2024-01-15 20:04:22 +01:00
|
|
|
Mesh *mesh = xml_add_mesh(state.scene, state.tfm, state.object);
|
2021-01-18 07:43:42 +01:00
|
|
|
array<Node *> used_shaders = mesh->get_used_shaders();
|
|
|
|
|
used_shaders.push_back_slow(state.shader);
|
|
|
|
|
mesh->set_used_shaders(used_shaders);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* read state */
|
2024-12-29 17:32:00 +01:00
|
|
|
const int shader = 0;
|
|
|
|
|
const bool smooth = state.smooth;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-11-12 17:21:21 +01:00
|
|
|
/* read vertices and polygons */
|
2011-04-27 11:58:34 +00:00
|
|
|
vector<float3> P;
|
2024-02-09 12:12:02 +01:00
|
|
|
vector<float3> VN; /* Vertex normals */
|
2015-06-27 12:05:05 +02:00
|
|
|
vector<float> UV;
|
2024-02-09 12:12:02 +01:00
|
|
|
vector<float> T; /* UV tangents */
|
|
|
|
|
vector<float> TS; /* UV tangent signs */
|
2024-12-29 17:32:00 +01:00
|
|
|
vector<int> verts;
|
|
|
|
|
vector<int> nverts;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_float3_array(P, node, "P");
|
|
|
|
|
xml_read_int_array(verts, node, "verts");
|
|
|
|
|
xml_read_int_array(nverts, node, "nverts");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if (xml_equal_string(node, "subdivision", "catmull-clark")) {
|
2021-01-18 07:43:42 +01:00
|
|
|
mesh->set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2016-08-23 13:57:45 -04:00
|
|
|
else if (xml_equal_string(node, "subdivision", "linear")) {
|
2021-01-18 07:43:42 +01:00
|
|
|
mesh->set_subdivision_type(Mesh::SUBDIVISION_LINEAR);
|
2016-08-23 13:57:45 -04:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-01-18 07:43:42 +01:00
|
|
|
array<float3> P_array;
|
|
|
|
|
P_array = P;
|
|
|
|
|
|
|
|
|
|
if (mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE) {
|
2011-04-27 11:58:34 +00:00
|
|
|
/* create vertices */
|
2021-01-18 07:43:42 +01:00
|
|
|
|
|
|
|
|
mesh->set_verts(P_array);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 11:16:27 +02:00
|
|
|
size_t num_triangles = 0;
|
2023-09-17 09:01:48 +10:00
|
|
|
for (size_t i = 0; i < nverts.size(); i++) {
|
2016-05-29 11:16:27 +02:00
|
|
|
num_triangles += nverts[i] - 2;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2021-01-18 07:43:42 +01:00
|
|
|
mesh->reserve_mesh(mesh->get_verts().size(), num_triangles);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* create triangles */
|
|
|
|
|
int index_offset = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
for (size_t i = 0; i < nverts.size(); i++) {
|
|
|
|
|
for (int j = 0; j < nverts[i] - 2; j++) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const int v0 = verts[index_offset];
|
|
|
|
|
const int v1 = verts[index_offset + j + 1];
|
|
|
|
|
const int v2 = verts[index_offset + j + 2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
assert(v0 < (int)P.size());
|
|
|
|
|
assert(v1 < (int)P.size());
|
|
|
|
|
assert(v2 < (int)P.size());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
mesh->add_triangle(v0, v1, v2, shader, smooth);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
index_offset += nverts[i];
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-02-09 12:12:02 +01:00
|
|
|
/* Vertex normals */
|
|
|
|
|
if (xml_read_float3_array(VN, node, Attribute::standard_name(ATTR_STD_VERTEX_NORMAL))) {
|
|
|
|
|
Attribute *attr = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
|
|
|
|
|
float3 *fdata = attr->data_float3();
|
|
|
|
|
|
|
|
|
|
/* Loop over the normals */
|
|
|
|
|
for (auto n : VN) {
|
|
|
|
|
fdata[0] = n;
|
|
|
|
|
fdata++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* UV map */
|
|
|
|
|
if (xml_read_float_array(UV, node, "UV") ||
|
|
|
|
|
xml_read_float_array(UV, node, Attribute::standard_name(ATTR_STD_UV)))
|
|
|
|
|
{
|
|
|
|
|
Attribute *attr = mesh->attributes.add(ATTR_STD_UV);
|
2019-03-05 15:25:36 +01:00
|
|
|
float2 *fdata = attr->data_float2();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-02-09 12:12:02 +01:00
|
|
|
/* Loop over the triangles */
|
2015-06-27 12:05:05 +02:00
|
|
|
index_offset = 0;
|
|
|
|
|
for (size_t i = 0; i < nverts.size(); i++) {
|
|
|
|
|
for (int j = 0; j < nverts[i] - 2; j++) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const int v0 = index_offset;
|
|
|
|
|
const int v1 = index_offset + j + 1;
|
|
|
|
|
const int v2 = index_offset + j + 2;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-06-27 12:05:05 +02:00
|
|
|
assert(v0 * 2 + 1 < (int)UV.size());
|
|
|
|
|
assert(v1 * 2 + 1 < (int)UV.size());
|
|
|
|
|
assert(v2 * 2 + 1 < (int)UV.size());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-05 15:25:36 +01:00
|
|
|
fdata[0] = make_float2(UV[v0 * 2], UV[v0 * 2 + 1]);
|
|
|
|
|
fdata[1] = make_float2(UV[v1 * 2], UV[v1 * 2 + 1]);
|
|
|
|
|
fdata[2] = make_float2(UV[v2 * 2], UV[v2 * 2 + 1]);
|
2015-06-27 12:05:05 +02:00
|
|
|
fdata += 3;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-29 10:02:17 +02:00
|
|
|
index_offset += nverts[i];
|
2015-06-27 12:05:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-02-09 12:12:02 +01:00
|
|
|
|
|
|
|
|
/* Tangents */
|
|
|
|
|
if (xml_read_float_array(T, node, Attribute::standard_name(ATTR_STD_UV_TANGENT))) {
|
|
|
|
|
Attribute *attr = mesh->attributes.add(ATTR_STD_UV_TANGENT);
|
|
|
|
|
float3 *fdata = attr->data_float3();
|
|
|
|
|
|
|
|
|
|
/* Loop over the triangles */
|
|
|
|
|
index_offset = 0;
|
|
|
|
|
for (size_t i = 0; i < nverts.size(); i++) {
|
|
|
|
|
for (int j = 0; j < nverts[i] - 2; j++) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const int v0 = index_offset;
|
|
|
|
|
const int v1 = index_offset + j + 1;
|
|
|
|
|
const int v2 = index_offset + j + 2;
|
2024-02-09 12:12:02 +01:00
|
|
|
|
|
|
|
|
assert(v0 * 3 + 2 < (int)T.size());
|
|
|
|
|
assert(v1 * 3 + 2 < (int)T.size());
|
|
|
|
|
assert(v2 * 3 + 2 < (int)T.size());
|
|
|
|
|
|
|
|
|
|
fdata[0] = make_float3(T[v0 * 3], T[v0 * 3 + 1], T[v0 * 3 + 2]);
|
|
|
|
|
fdata[1] = make_float3(T[v1 * 3], T[v1 * 3 + 1], T[v1 * 3 + 2]);
|
|
|
|
|
fdata[2] = make_float3(T[v2 * 3], T[v2 * 3 + 1], T[v2 * 3 + 2]);
|
|
|
|
|
fdata += 3;
|
|
|
|
|
}
|
|
|
|
|
index_offset += nverts[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tangent signs */
|
|
|
|
|
if (xml_read_float_array(TS, node, Attribute::standard_name(ATTR_STD_UV_TANGENT_SIGN))) {
|
|
|
|
|
Attribute *attr = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN);
|
|
|
|
|
float *fdata = attr->data_float();
|
|
|
|
|
|
|
|
|
|
/* Loop over the triangles */
|
|
|
|
|
index_offset = 0;
|
|
|
|
|
for (size_t i = 0; i < nverts.size(); i++) {
|
|
|
|
|
for (int j = 0; j < nverts[i] - 2; j++) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const int v0 = index_offset;
|
|
|
|
|
const int v1 = index_offset + j + 1;
|
|
|
|
|
const int v2 = index_offset + j + 2;
|
2024-02-09 12:12:02 +01:00
|
|
|
|
|
|
|
|
assert(v0 < (int)TS.size());
|
|
|
|
|
assert(v1 < (int)TS.size());
|
|
|
|
|
assert(v2 < (int)TS.size());
|
|
|
|
|
|
|
|
|
|
fdata[0] = TS[v0];
|
|
|
|
|
fdata[1] = TS[v1];
|
|
|
|
|
fdata[2] = TS[v2];
|
|
|
|
|
fdata += 3;
|
|
|
|
|
}
|
|
|
|
|
index_offset += nverts[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2016-08-23 13:57:45 -04:00
|
|
|
else {
|
|
|
|
|
/* create vertices */
|
2021-01-18 07:43:42 +01:00
|
|
|
mesh->set_verts(P_array);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-08-23 13:57:45 -04:00
|
|
|
size_t num_corners = 0;
|
|
|
|
|
for (size_t i = 0; i < nverts.size(); i++) {
|
|
|
|
|
num_corners += nverts[i];
|
|
|
|
|
}
|
2025-03-09 03:07:29 +01:00
|
|
|
mesh->reserve_subd_faces(nverts.size(), num_corners);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-08-23 13:57:45 -04:00
|
|
|
/* create subd_faces */
|
|
|
|
|
int index_offset = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-08-23 13:57:45 -04:00
|
|
|
for (size_t i = 0; i < nverts.size(); i++) {
|
|
|
|
|
mesh->add_subd_face(&verts[index_offset], nverts[i], shader, smooth);
|
|
|
|
|
index_offset += nverts[i];
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-02-09 12:12:02 +01:00
|
|
|
/* UV map */
|
|
|
|
|
if (xml_read_float_array(UV, node, "UV") ||
|
|
|
|
|
xml_read_float_array(UV, node, Attribute::standard_name(ATTR_STD_UV)))
|
|
|
|
|
{
|
|
|
|
|
Attribute *attr = mesh->subd_attributes.add(ATTR_STD_UV);
|
2016-08-23 13:57:45 -04:00
|
|
|
float3 *fdata = attr->data_float3();
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-08-23 13:57:45 -04:00
|
|
|
index_offset = 0;
|
|
|
|
|
for (size_t i = 0; i < nverts.size(); i++) {
|
|
|
|
|
for (int j = 0; j < nverts[i]; j++) {
|
|
|
|
|
*(fdata++) = make_float3(UV[index_offset++]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-08-23 13:57:45 -04:00
|
|
|
/* setup subd params */
|
2021-01-18 07:43:42 +01:00
|
|
|
float dicing_rate = state.dicing_rate;
|
|
|
|
|
xml_read_float(&dicing_rate, node, "dicing_rate");
|
|
|
|
|
dicing_rate = std::max(0.1f, dicing_rate);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-01-18 07:43:42 +01:00
|
|
|
mesh->set_subd_dicing_rate(dicing_rate);
|
|
|
|
|
mesh->set_subd_objecttoworld(state.tfm);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-11-12 17:21:21 +01:00
|
|
|
/* we don't yet support arbitrary attributes, for now add vertex
|
|
|
|
|
* coordinates as generated coordinates if requested */
|
2017-01-13 15:24:56 +01:00
|
|
|
if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) {
|
2016-11-12 17:21:21 +01:00
|
|
|
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
|
2024-12-27 21:50:31 +01:00
|
|
|
std::copy_n(mesh->get_verts().data(), mesh->get_verts().size(), attr->data_float3());
|
2016-11-12 17:21:21 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Light */
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_light(XMLReadState &state, const xml_node node)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2025-03-26 15:40:56 +01:00
|
|
|
Scene *scene = state.scene;
|
|
|
|
|
|
|
|
|
|
/* Create light. */
|
|
|
|
|
Light *light = scene->create_node<Light>();
|
|
|
|
|
|
|
|
|
|
array<Node *> used_shaders;
|
|
|
|
|
used_shaders.push_back_slow(state.shader);
|
|
|
|
|
light->set_used_shaders(used_shaders);
|
|
|
|
|
|
|
|
|
|
/* Create object. */
|
|
|
|
|
Object *object = scene->create_node<Object>();
|
|
|
|
|
object->set_tfm(state.tfm);
|
|
|
|
|
object->set_visibility(PATH_RAY_ALL_VISIBILITY & ~PATH_RAY_CAMERA);
|
|
|
|
|
object->set_geometry(light);
|
2014-02-14 23:22:05 +01:00
|
|
|
|
2016-05-08 00:18:32 +02:00
|
|
|
xml_read_node(state, light, node);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Transform */
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_transform(const xml_node node, Transform &tfm)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
if (node.attribute("matrix")) {
|
|
|
|
|
vector<float> matrix;
|
2018-03-08 06:48:14 +01:00
|
|
|
if (xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const ProjectionTransform projection = *(ProjectionTransform *)matrix.data();
|
2018-03-08 06:48:14 +01:00
|
|
|
tfm = tfm * projection_to_transform(projection_transpose(projection));
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if (node.attribute("translate")) {
|
2021-02-17 01:47:18 +01:00
|
|
|
float3 translate = zero_float3();
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_float3(&translate, node, "translate");
|
|
|
|
|
tfm = tfm * transform_translate(translate);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if (node.attribute("rotate")) {
|
2021-02-17 01:47:18 +01:00
|
|
|
float4 rotate = zero_float4();
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_float4(&rotate, node, "rotate");
|
2014-05-04 03:15:20 +10:00
|
|
|
tfm = tfm * transform_rotate(DEG2RADF(rotate.x), make_float3(rotate.y, rotate.z, rotate.w));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if (node.attribute("scale")) {
|
2021-02-17 01:47:18 +01:00
|
|
|
float3 scale = zero_float3();
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_float3(&scale, node, "scale");
|
|
|
|
|
tfm = tfm * transform_scale(scale);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* State */
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_state(XMLReadState &state, const xml_node node)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-01-15 20:04:22 +01:00
|
|
|
/* Read shader */
|
2011-04-27 11:58:34 +00:00
|
|
|
string shadername;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if (xml_read_string(&shadername, node, "shader")) {
|
|
|
|
|
bool found = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (Shader *shader : state.scene->shaders) {
|
2011-04-27 11:58:34 +00:00
|
|
|
if (shader->name == shadername) {
|
2016-05-14 14:50:03 +02:00
|
|
|
state.shader = shader;
|
2011-04-27 11:58:34 +00:00
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!found) {
|
2011-04-27 11:58:34 +00:00
|
|
|
fprintf(stderr, "Unknown shader \"%s\".\n", shadername.c_str());
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-01-15 20:04:22 +01:00
|
|
|
/* Read object */
|
|
|
|
|
string objectname;
|
|
|
|
|
|
|
|
|
|
if (xml_read_string(&objectname, node, "object")) {
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (Object *object : state.scene->objects) {
|
2024-01-15 20:04:22 +01:00
|
|
|
if (object->name == objectname) {
|
|
|
|
|
state.object = object;
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
fprintf(stderr, "Unknown object \"%s\".\n", objectname.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_float(&state.dicing_rate, node, "dicing_rate");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* read smooth/flat */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (xml_equal_string(node, "interpolation", "smooth")) {
|
2011-04-27 11:58:34 +00:00
|
|
|
state.smooth = true;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (xml_equal_string(node, "interpolation", "flat")) {
|
2011-04-27 11:58:34 +00:00
|
|
|
state.smooth = false;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-15 20:04:22 +01:00
|
|
|
/* Object */
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_object(XMLReadState &state, const xml_node node)
|
2024-01-15 20:04:22 +01:00
|
|
|
{
|
|
|
|
|
Scene *scene = state.scene;
|
|
|
|
|
|
|
|
|
|
/* create mesh */
|
2024-12-30 02:20:36 +01:00
|
|
|
Mesh *mesh = scene->create_node<Mesh>();
|
2024-01-15 20:04:22 +01:00
|
|
|
|
|
|
|
|
/* create object */
|
2024-12-30 02:20:36 +01:00
|
|
|
Object *object = scene->create_node<Object>();
|
2024-01-15 20:04:22 +01:00
|
|
|
object->set_geometry(mesh);
|
|
|
|
|
object->set_tfm(state.tfm);
|
|
|
|
|
|
|
|
|
|
xml_read_node(state, object, node);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Scene */
|
|
|
|
|
|
2016-05-07 20:05:21 +02:00
|
|
|
static void xml_read_include(XMLReadState &state, const string &src);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static void xml_read_scene(XMLReadState &state, const xml_node scene_node)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2017-11-10 10:04:33 +01:00
|
|
|
for (xml_node node = scene_node.first_child(); node; node = node.next_sibling()) {
|
2011-04-27 11:58:34 +00:00
|
|
|
if (string_iequals(node.name(), "film")) {
|
2016-05-07 20:30:16 +02:00
|
|
|
xml_read_node(state, state.scene->film, node);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
else if (string_iequals(node.name(), "integrator")) {
|
2016-05-07 20:05:21 +02:00
|
|
|
xml_read_node(state, state.scene->integrator, node);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
else if (string_iequals(node.name(), "camera")) {
|
|
|
|
|
xml_read_camera(state, node);
|
|
|
|
|
}
|
|
|
|
|
else if (string_iequals(node.name(), "shader")) {
|
|
|
|
|
xml_read_shader(state, node);
|
|
|
|
|
}
|
|
|
|
|
else if (string_iequals(node.name(), "background")) {
|
|
|
|
|
xml_read_background(state, node);
|
|
|
|
|
}
|
|
|
|
|
else if (string_iequals(node.name(), "mesh")) {
|
|
|
|
|
xml_read_mesh(state, node);
|
|
|
|
|
}
|
|
|
|
|
else if (string_iequals(node.name(), "light")) {
|
|
|
|
|
xml_read_light(state, node);
|
|
|
|
|
}
|
|
|
|
|
else if (string_iequals(node.name(), "transform")) {
|
|
|
|
|
XMLReadState substate = state;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_transform(node, substate.tfm);
|
|
|
|
|
xml_read_scene(substate, node);
|
|
|
|
|
}
|
|
|
|
|
else if (string_iequals(node.name(), "state")) {
|
|
|
|
|
XMLReadState substate = state;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_state(substate, node);
|
|
|
|
|
xml_read_scene(substate, node);
|
|
|
|
|
}
|
|
|
|
|
else if (string_iequals(node.name(), "include")) {
|
|
|
|
|
string src;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (xml_read_string(&src, node, "src")) {
|
2011-04-27 11:58:34 +00:00
|
|
|
xml_read_include(state, src);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2024-01-15 20:04:22 +01:00
|
|
|
else if (string_iequals(node.name(), "object")) {
|
|
|
|
|
XMLReadState substate = state;
|
|
|
|
|
|
|
|
|
|
xml_read_object(substate, node);
|
|
|
|
|
xml_read_scene(substate, node);
|
|
|
|
|
}
|
2022-03-23 17:45:34 +01:00
|
|
|
#ifdef WITH_ALEMBIC
|
|
|
|
|
else if (string_iequals(node.name(), "alembic")) {
|
|
|
|
|
xml_read_alembic(state, node);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
fprintf(stderr, "Unknown node \"%s\".\n", node.name());
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Include */
|
|
|
|
|
|
2016-05-07 20:05:21 +02:00
|
|
|
static void xml_read_include(XMLReadState &state, const string &src)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* open XML document */
|
2017-11-10 10:04:33 +01:00
|
|
|
xml_document doc;
|
|
|
|
|
xml_parse_result parse_result;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const string path = path_join(state.base, src);
|
2011-04-27 11:58:34 +00:00
|
|
|
parse_result = doc.load_file(path.c_str());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if (parse_result) {
|
|
|
|
|
XMLReadState substate = state;
|
|
|
|
|
substate.base = path_dirname(path);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const xml_node cycles = doc.child("cycles");
|
2015-05-17 23:41:38 +02:00
|
|
|
xml_read_scene(substate, cycles);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2014-02-07 22:29:49 +01:00
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
fprintf(stderr, "%s read error: %s\n", src.c_str(), parse_result.description());
|
2014-02-07 22:29:49 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* File */
|
|
|
|
|
|
|
|
|
|
void xml_read_file(Scene *scene, const char *filepath)
|
|
|
|
|
{
|
|
|
|
|
XMLReadState state;
|
|
|
|
|
|
|
|
|
|
state.scene = scene;
|
|
|
|
|
state.tfm = transform_identity();
|
|
|
|
|
state.shader = scene->default_surface;
|
|
|
|
|
state.smooth = false;
|
2016-08-23 13:57:45 -04:00
|
|
|
state.dicing_rate = 1.0f;
|
2011-04-27 11:58:34 +00:00
|
|
|
state.base = path_dirname(filepath);
|
|
|
|
|
|
|
|
|
|
xml_read_include(state, path_filename(filepath));
|
|
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
scene->params.bvh_type = BVH_TYPE_STATIC;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CCL_NAMESPACE_END
|