This example describes the API of the code generated by the "GLSL" backend for compiled materials and shows how a renderer can call this generated code to evaluate sub-expressions of multiple materials using OpenGL.
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
#include "example_shared.h"
#include "example_glsl_shared.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#ifdef MI_PLATFORM_MACOSX
#define MAX_MATERIALS 16
#define MAX_TEXTURES 16
#else
#define USE_SSBO
#define MAX_MATERIALS 64
#define MAX_TEXTURES 64
#endif
#define REMAP_NOISE_FUNCTIONS
char const* vertex_shader_filename = "example_execution_glsl.vert";
char const* fragment_shader_filename = "example_execution_glsl.frag";
struct Options {
bool no_window;
unsigned material_pattern;
unsigned res_x, res_y;
Options()
: no_window(false)
, outputfile("output.png")
, material_pattern(7)
, res_x(1024)
, res_y(768)
{
}
};
struct Vertex {
};
static GLFWwindow *init_opengl(Options const &options)
{
check_success(glfwInit());
#ifdef USE_SSBO
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
#else
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
#endif
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
if (options.no_window)
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
GLFWwindow *window = glfwCreateWindow(
options.res_x, options.res_y,
"MDL SDK GLSL Execution Example - Switch pattern with keys 1 - 7", nullptr, nullptr);
if (!window) {
}
glfwMakeContextCurrent(window);
GLenum res = glewInit();
if (res != GLEW_OK) {
}
glfwSwapInterval(1);
check_gl_success();
return window;
}
{
"#version 330 core\n"
"struct State {\n"
" vec3 normal;\n"
" vec3 geometry_normal;\n"
" float animation_time;\n"
" vec3[1] texture_tangent_u;\n"
" vec3[1] texture_tangent_v;\n"
"};\n"
"\n"
"uint get_mdl_num_mat_subexprs() { return " +
"u; }\n"
"\n";
"vec3 mdl_mat_subexpr(uint id, State state) {\n"
" switch(id) {\n";
i < num_target_codes;
++i)
{
i, mi::neuraylib::ITarget_code::SL_GLSL);
src += '\n';
switch_func +=
" case " +
to_string(i) +
"u: return " + func_name +
"(state);\n";
}
switch_func +=
" default: return vec3(0);\n"
" }\n"
"}\n";
return src + "\n" + switch_func;
}
static GLuint create_shader_program(
{
GLint success;
GLuint program = glCreateProgram();
add_shader(GL_VERTEX_SHADER,
read_text_file(get_executable_folder() + "/" + vertex_shader_filename), program);
sstr << "#version 330 core\n";
sstr <<
"#define MAX_MATERIALS " <<
to_string(MAX_MATERIALS) <<
"\n";
sstr <<
"#define MAX_TEXTURES " <<
to_string(MAX_TEXTURES) <<
"\n";
sstr << read_text_file(get_executable_folder() + "/" + fragment_shader_filename);
add_shader(GL_FRAGMENT_SHADER, sstr.
str() , program);
#ifdef REMAP_NOISE_FUNCTIONS
code.
append(read_text_file(get_executable_folder() +
"/" +
"noise_no_lut.glsl"));
#endif
add_shader(GL_FRAGMENT_SHADER, code, program);
std::string glsl_switch_func = generate_glsl_switch_func(target_code);
#ifdef DUMP_GLSL
std::cout <<
"Dumping GLSL code for the \"mdl_mat_subexpr\" switch function:\n\n"
#endif
add_shader(GL_FRAGMENT_SHADER, glsl_switch_func.
c_str(), program);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
dump_program_info(program, "Error linking the shader program: ");
}
glUseProgram(program);
check_gl_success();
return program;
}
static GLuint create_quad(GLuint program, GLuint* vertex_buffer)
{
static Vertex const vertices[6] = {
{ { -1.f, -1.f, 0.0f }, { 0.f, 0.f } },
{ { 1.f, -1.f, 0.0f }, { 1.f, 0.f } },
{ { -1.f, 1.f, 0.0f }, { 0.f, 1.f } },
{ { 1.f, -1.f, 0.0f }, { 1.f, 0.f } },
{ { 1.f, 1.f, 0.0f }, { 1.f, 1.f } },
{ { -1.f, 1.f, 0.0f }, { 0.f, 1.f } }
};
glGenBuffers(1, vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, *vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint vertex_array;
glGenVertexArrays(1, &vertex_array);
glBindVertexArray(vertex_array);
GLint pos_index = glGetAttribLocation(program, "Position");
GLint tex_coord_index = glGetAttribLocation(program, "TexCoord");
check_success(pos_index >= 0 && tex_coord_index >= 0);
glEnableVertexAttribArray(pos_index);
glVertexAttribPointer(
pos_index, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glEnableVertexAttribArray(tex_coord_index);
glVertexAttribPointer(
tex_coord_index, 2, GL_FLOAT, GL_FALSE,
check_gl_success();
return vertex_array;
}
class Material_opengl_context
{
public:
Material_opengl_context(GLuint program)
: m_program(program)
, m_next_storage_block_binding(0)
{}
~Material_opengl_context();
bool prepare_material_data(
bool set_material_data();
private:
bool prepare_texture(
GLuint texture_array);
private:
GLuint m_program;
GLuint m_next_storage_block_binding;
};
Material_opengl_context::~Material_opengl_context()
{
if (m_buffer_objects.size() > 0)
glDeleteBuffers(GLsizei(m_buffer_objects.size()), &m_buffer_objects[0]);
if (m_texture_objects.size() > 0)
glDeleteTextures(GLsizei(m_texture_objects.size()), &m_texture_objects[0]);
check_gl_success();
}
void Material_opengl_context::set_mdl_readonly_data(
{
if (num_uniforms == 0) return;
#ifdef USE_SSBO
size_t cur_buffer_offs = m_buffer_objects.size();
m_buffer_objects.insert(m_buffer_objects.end(), num_uniforms, 0);
glGenBuffers(GLsizei(num_uniforms), &m_buffer_objects[cur_buffer_offs]);
for (
mi::Size i = 0; i < num_uniforms; ++i) {
#ifdef DUMP_GLSL
std::cout <<
"Dump ro segment data " << i <<
" \""
for (int j = 0; j < 16 && j < segment_size; ++j) {
std::cout <<
"0x" << (
unsigned int)(
unsigned char)segment_data[j] <<
", ";
}
#endif
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer_objects[cur_buffer_offs + i]);
glBufferData(
GL_SHADER_STORAGE_BUFFER, GLsizeiptr(segment_size), segment_data, GL_STATIC_DRAW);
GLuint block_index = glGetProgramResourceIndex(
glShaderStorageBlockBinding(m_program, block_index, m_next_storage_block_binding);
glBindBufferBase(
GL_SHADER_STORAGE_BUFFER,
m_next_storage_block_binding,
m_buffer_objects[cur_buffer_offs + i]);
++m_next_storage_block_binding;
check_gl_success();
}
#else
for (
mi::Size i = 0; i < num_uniforms; ++i) {
#ifdef DUMP_GLSL
std::cout <<
"Dump ro segment data " << i <<
" \""
for (int i = 0; i < 16 && i < segment_size; ++i) {
std::cout <<
"0x" << (
unsigned int)(
unsigned char)segment_data[i] <<
", ";
}
#endif
}
glGetUniformIndices(m_program, GLsizei(num_uniforms), &uniform_names[0], &uniform_indices[0]);
for (
mi::Size i = 0; i < num_uniforms; ++i) {
if (uniform_indices[i] == GL_INVALID_INDEX)
continue;
GLint uniform_type = 0;
GLuint index = GLuint(uniform_indices[i]);
glGetActiveUniformsiv(m_program, 1, &index, GL_UNIFORM_TYPE, &uniform_type);
#ifdef DUMP_GLSL
std::cout <<
"Uniform type of " << uniform_names[i]
#endif
GLint uniform_location = glGetUniformLocation(m_program, uniform_names[i]);
switch (uniform_type) {
#define CASE_TYPE_BOOL(type, func, num) \
case type: { \
GLint *buf = new GLint[segment_size]; \
for (mi::Size j = 0; j < segment_size; ++j) \
buf[j] = GLint(segment_data[j]); \
func(uniform_location, GLsizei(segment_size / num), buf); \
delete[] buf; \
break; \
}
CASE_TYPE_BOOL(GL_BOOL, glUniform1iv, 1)
CASE_TYPE_BOOL(GL_BOOL_VEC2, glUniform2iv, 2)
CASE_TYPE_BOOL(GL_BOOL_VEC3, glUniform3iv, 3)
CASE_TYPE_BOOL(GL_BOOL_VEC4, glUniform4iv, 4)
#define CASE_TYPE(type, func, num, elemtype) \
case type: \
func(uniform_location, GLsizei(segment_size/(num * sizeof(elemtype))), \
(const elemtype*)segment_data); \
break
CASE_TYPE(GL_INT, glUniform1iv, 1, GLint);
CASE_TYPE(GL_INT_VEC2, glUniform2iv, 2, GLint);
CASE_TYPE(GL_INT_VEC3, glUniform3iv, 3, GLint);
CASE_TYPE(GL_INT_VEC4, glUniform4iv, 4, GLint);
CASE_TYPE(GL_FLOAT, glUniform1fv, 1, GLfloat);
CASE_TYPE(GL_FLOAT_VEC2, glUniform2fv, 2, GLfloat);
CASE_TYPE(GL_FLOAT_VEC3, glUniform3fv, 3, GLfloat);
CASE_TYPE(GL_FLOAT_VEC4, glUniform4fv, 4, GLfloat);
CASE_TYPE(GL_DOUBLE, glUniform1dv, 1, GLdouble);
CASE_TYPE(GL_DOUBLE_VEC2, glUniform2dv, 2, GLdouble);
CASE_TYPE(GL_DOUBLE_VEC3, glUniform3dv, 3, GLdouble);
CASE_TYPE(GL_DOUBLE_VEC4, glUniform4dv, 4, GLdouble);
#define CASE_TYPE_MAT(type, func, num, elemtype) \
case type: \
func(uniform_location, GLsizei(segment_size/(num * sizeof(elemtype))), \
false, (const elemtype*)segment_data); \
break
CASE_TYPE_MAT(GL_FLOAT_MAT2_ARB, glUniformMatrix2fv, 4, GLfloat);
CASE_TYPE_MAT(GL_FLOAT_MAT2x3, glUniformMatrix2x3fv, 6, GLfloat);
CASE_TYPE_MAT(GL_FLOAT_MAT3x2, glUniformMatrix3x2fv, 6, GLfloat);
CASE_TYPE_MAT(GL_FLOAT_MAT2x4, glUniformMatrix2x4fv, 8, GLfloat);
CASE_TYPE_MAT(GL_FLOAT_MAT4x2, glUniformMatrix4x2fv, 8, GLfloat);
CASE_TYPE_MAT(GL_FLOAT_MAT3_ARB, glUniformMatrix3fv, 9, GLfloat);
CASE_TYPE_MAT(GL_FLOAT_MAT3x4, glUniformMatrix3x4fv, 12, GLfloat);
CASE_TYPE_MAT(GL_FLOAT_MAT4x3, glUniformMatrix4x3fv, 12, GLfloat);
CASE_TYPE_MAT(GL_FLOAT_MAT4_ARB, glUniformMatrix4fv, 16, GLfloat);
CASE_TYPE_MAT(GL_DOUBLE_MAT2, glUniformMatrix2dv, 4, GLdouble);
CASE_TYPE_MAT(GL_DOUBLE_MAT2x3, glUniformMatrix2x3dv, 6, GLdouble);
CASE_TYPE_MAT(GL_DOUBLE_MAT3x2, glUniformMatrix3x2dv, 6, GLdouble);
CASE_TYPE_MAT(GL_DOUBLE_MAT2x4, glUniformMatrix2x4dv, 8, GLdouble);
CASE_TYPE_MAT(GL_DOUBLE_MAT4x2, glUniformMatrix4x2dv, 8, GLdouble);
CASE_TYPE_MAT(GL_DOUBLE_MAT3, glUniformMatrix3dv, 9, GLdouble);
CASE_TYPE_MAT(GL_DOUBLE_MAT3x4, glUniformMatrix3x4dv, 12, GLdouble);
CASE_TYPE_MAT(GL_DOUBLE_MAT4x3, glUniformMatrix4x3dv, 12, GLdouble);
CASE_TYPE_MAT(GL_DOUBLE_MAT4, glUniformMatrix4dv, 16, GLdouble);
default:
break;
}
check_gl_success();
}
#endif
}
bool Material_opengl_context::prepare_texture(
GLuint texture_obj)
{
char const *image_type = image->get_type();
return false;
}
if (tex_layers != 1) {
std::cerr <<
"The example and the GLSL backend don't support layered images!" <<
std::endl;
return false;
}
if (texture->get_effective_gamma() != 1.0f) {
gamma_canvas->set_gamma(texture->get_effective_gamma());
canvas = gamma_canvas;
}
else if (
strcmp(image_type,
"Color") != 0 &&
strcmp(image_type,
"Float32<4>") != 0) {
canvas = image_api->
convert(canvas.
get(),
"Color");
}
if (texture_shape == mi::neuraylib::ITarget_code::Texture_shape_2d) {
glBindTexture(GL_TEXTURE_2D, texture_obj);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_FLOAT, data);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
check_gl_success();
return true;
}
bool Material_opengl_context::prepare_material_data(
{
set_mdl_readonly_data(target_code);
size_t cur_tex_offs = m_texture_objects.size();
m_material_texture_starts.push_back(GLuint(cur_tex_offs));
if (num_textures > 1) {
m_texture_objects.insert(m_texture_objects.end(), num_textures - 1, 0);
glGenTextures(GLsizei(num_textures - 1), &m_texture_objects[cur_tex_offs]);
for (
mi::Size i = 1; i < num_textures; ++i) {
if (!prepare_texture(
transaction, image_api, target_code,
i, m_texture_objects[cur_tex_offs + i - 1]))
return false;
}
}
return true;
}
bool Material_opengl_context::set_material_data()
{
GLsizei total_textures = GLsizei(m_texture_objects.size());
if(total_textures > MAX_TEXTURES)
{
fprintf( stderr,
"Number of required textures (%d) is not supported (max: %d)\n",
total_textures, MAX_TEXTURES);
return false;
}
#ifdef USE_SSBO
if (glfwExtensionSupported("GL_ARB_bindless_texture"))
{
if (total_textures > 0) {
texture_handles.
resize(total_textures);
for (GLsizei i = 0; i < total_textures; ++i) {
texture_handles[i] = glGetTextureHandleARB(m_texture_objects[i]);
glMakeTextureHandleResidentARB(texture_handles[i]);
}
glUniformHandleui64vARB(
glGetUniformLocation(m_program, "material_texture_samplers_2d"),
total_textures,
&texture_handles[0]);
glUniform1uiv(
glGetUniformLocation(m_program, "material_texture_starts"),
GLsizei(m_material_texture_starts.size()),
&m_material_texture_starts[0]);
}
}
else if (glfwExtensionSupported("GL_NV_bindless_texture"))
{
if (total_textures > 0) {
texture_handles.
resize(total_textures);
for (GLsizei i = 0; i < total_textures; ++i) {
texture_handles[i] = glGetTextureHandleNV(m_texture_objects[i]);
glMakeTextureHandleResidentNV(texture_handles[i]);
}
glUniformHandleui64vARB(
glGetUniformLocation(m_program, "material_texture_samplers_2d"),
total_textures,
&texture_handles[0]);
glUniform1uiv(
glGetUniformLocation(m_program, "material_texture_starts"),
GLsizei(m_material_texture_starts.size()),
&m_material_texture_starts[0]);
}
}
else
{
fprintf(stderr,
"Sample requires Bindless Textures, "
"that are not supported by the current system.\n");
return false;
}
#endif // USE_SSBO
return glGetError() == GL_NO_ERROR;
}
class Material_compiler {
public:
Material_compiler(
bool add_material_subexpr(
const char* path,
const char* fname);
private:
bool class_compilation);
private:
m_context;
};
{
return material_name.
substr(0, p);
}
{
if (p == std::string::npos)
return material_name;
return material_name.
substr(p + 2, material_name.
size() - p);
}
{
std::string module_name = get_module_name(material_name);
check_success(m_mdl_compiler->load_module(
m_transaction.get(), module_name.
c_str(), m_context.get()) >= 0);
print_messages(m_context.get());
material_db_name.c_str()));
check_success(material_definition);
material_definition->create_material_instance(0, &result));
check_success(result == 0);
return material_instance.get();
}
bool class_compilation)
{
check_success(print_messages(m_context.get()));
return compiled_material.get();
}
{
m_be_glsl->translate_link_unit(m_link_unit.get(), m_context.get()));
check_success(print_messages(m_context.get()));
check_success(code_glsl);
#ifdef DUMP_GLSL
#endif
return code_glsl;
}
bool Material_compiler::add_material_subexpr(
const char* path,
const char* fname)
{
create_material_instance(material_name.
c_str()));
compile_material_instance(material_instance.get(), false));
m_link_unit->add_material_expression(compiled_material.get(), path, fname,
m_context.get());
return print_messages(m_context.get());
}
Material_compiler::Material_compiler(
, m_be_glsl(mdl_compiler->get_backend(mi::neuraylib::IMdl_compiler::MB_GLSL))
, m_context(mdl_factory->create_execution_context())
, m_link_unit()
{
check_success(m_be_glsl->set_option("num_texture_spaces", "1") == 0);
#ifdef USE_SSBO
check_success(m_be_glsl->set_option("glsl_version", "430") == 0);
#else
check_success(m_be_glsl->set_option("glsl_version", "330") == 0);
#endif
check_success(m_be_glsl->set_option("glsl_state_animation_time_mode", "field") == 0);
check_success(m_be_glsl->set_option("glsl_state_position_mode", "func") == 0);
check_success(m_be_glsl->set_option("glsl_state_texture_coordinate_mode", "arg") == 0);
check_success(m_be_glsl->set_option("glsl_state_texture_tangent_u_mode", "field") == 0);
check_success(m_be_glsl->set_option("glsl_state_texture_tangent_v_mode", "field") == 0);
#ifdef USE_SSBO
check_success(m_be_glsl->set_option("glsl_max_const_data", "0") == 0);
check_success(m_be_glsl->set_option("glsl_place_uniforms_into_ssbo", "on") == 0);
#else
check_success(m_be_glsl->set_option("glsl_max_const_data", "1024") == 0);
check_success(m_be_glsl->set_option("glsl_place_uniforms_into_ssbo", "off") == 0);
#endif
#ifdef REMAP_NOISE_FUNCTIONS
check_success(m_be_glsl->set_option("glsl_remap_functions",
"_ZN4base12perlin_noiseEu6float4=noise_float4"
",_ZN4base12worley_noiseEu6float3fi=noise_worley"
",_ZN4base8mi_noiseEu6float3=noise_mi_float3"
",_ZN4base8mi_noiseEu4int3=noise_mi_int3") == 0);
#endif
}
struct Window_context
{
unsigned material_pattern;
};
void handle_key(GLFWwindow *window, int key, int , int action, int )
{
if (action == GLFW_PRESS) {
if (GLFW_KEY_KP_0 <= key && key <= GLFW_KEY_KP_9)
key += GLFW_KEY_0 - GLFW_KEY_KP_0;
switch (key) {
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, GLFW_TRUE);
break;
case GLFW_KEY_1:
case GLFW_KEY_2:
case GLFW_KEY_3:
case GLFW_KEY_4:
case GLFW_KEY_5:
case GLFW_KEY_6:
case GLFW_KEY_7:
{
Window_context *ctx = static_cast<Window_context*>(
glfwGetWindowUserPointer(window));
ctx->material_pattern = key - GLFW_KEY_0;
break;
}
default:
break;
}
}
}
void handle_framebuffer_size(GLFWwindow* , int width, int height)
{
glViewport(0, 0, width, height);
}
void show_and_animate_scene(
Options const &options)
{
Window_context window_context = { options.material_pattern };
GLFWwindow *window = init_opengl(options);
GLuint program = create_shader_program(target_code);
GLuint quad_vertex_buffer;
GLuint quad_vao = create_quad(program, &quad_vertex_buffer);
{
Material_opengl_context material_opengl_context(program);
check_success(material_opengl_context.prepare_material_data(
transaction, image_api, target_code));
check_success(material_opengl_context.set_material_data());
GLint material_pattern_index = glGetUniformLocation(program, "material_pattern");
GLint animation_time_index = glGetUniformLocation(program, "animation_time");
if (!options.no_window) {
GLfloat animation_time = 0;
double last_frame_time = glfwGetTime();
glfwSetWindowUserPointer(window, &window_context);
glfwSetKeyCallback(window, handle_key);
glfwSetFramebufferSizeCallback(window, handle_framebuffer_size);
while (!glfwWindowShouldClose(window))
{
double cur_frame_time = glfwGetTime();
animation_time += GLfloat(cur_frame_time - last_frame_time);
last_frame_time = cur_frame_time;
glUniform1ui(material_pattern_index, window_context.material_pattern);
glUniform1f(animation_time_index, animation_time);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(quad_vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwSwapBuffers(window);
glfwPollEvents();
}
} else {
GLuint frame_buffer = 0, color_buffer = 0;
glGenFramebuffers(1, &frame_buffer);
glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer);
glGenRenderbuffers(1, &color_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, color_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, options.res_x, options.res_y);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, color_buffer);
check_gl_success();
glUniform1ui(material_pattern_index, window_context.material_pattern);
glUniform1f(animation_time_index, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, options.res_x, options.res_y);
check_gl_success();
glBindVertexArray(quad_vao);
check_gl_success();
glDrawArrays(GL_TRIANGLES, 0, 6);
check_gl_success();
glReadPixels(0, 0, options.res_x, options.res_y,
GL_RGBA, GL_UNSIGNED_BYTE, tile->get_data());
glDeleteRenderbuffers(1, &color_buffer);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &frame_buffer);
}
}
glDeleteVertexArrays(1, &quad_vao);
glDeleteBuffers(1, &quad_vertex_buffer);
glDeleteProgram(program);
check_gl_success();
glfwDestroyWindow(window);
glfwTerminate();
}
void usage(char const *prog_name)
{
<< "Usage: " << prog_name << " [options] [<material_pattern>]\n"
<< "Options:\n"
<< " --nowin don't show interactive display\n"
<< " --res <x> <y> resolution (default: 1024x768)\n"
<< " -o <outputfile> image file to write result in nowin mode (default: output.png)\n"
<< " <material_pattern> a number from 1 to 7 choosing which material combination to use"
keep_console_open();
}
int main(int argc, char* argv[])
{
Options options;
for (int i = 1; i < argc; ++i) {
char const *opt = argv[i];
if (opt[0] == '-') {
if (
strcmp(opt,
"--nowin") == 0)
options.no_window = true;
else if (
strcmp(opt,
"-o") == 0) {
if (i < argc - 1)
options.outputfile = argv[++i];
else
usage(argv[0]);
}
else if (
strcmp(opt,
"--res") == 0) {
if (i < argc - 2) {
} else
usage(argv[0]);
}
else
usage(argv[0]);
} else {
options.material_pattern = unsigned(
atoi(opt));
if (options.material_pattern < 1 || options.material_pattern > 7) {
usage(argv[0]);
}
}
}
check_success(neuray.is_valid_interface());
configure(neuray.get());
check_start_success(result);
{
Material_compiler mc(mdl_compiler.
get(), mdl_factory.get(), transaction.
get());
{
#if defined(USE_SSBO) || defined(REMAP_NOISE_FUNCTIONS)
mc.add_material_subexpr(
"::nvidia::sdk_examples::tutorials::example_execution1",
"surface.scattering.tint", "tint");
#endif
mc.add_material_subexpr(
"::nvidia::sdk_examples::tutorials::example_execution2",
"surface.scattering.tint", "tint_2");
#if defined(USE_SSBO) || defined(REMAP_NOISE_FUNCTIONS)
mc.add_material_subexpr(
"::nvidia::sdk_examples::tutorials::example_execution3",
"surface.scattering.tint", "tint_3");
#endif
show_and_animate_scene(transaction, mdl_compiler, image_api, target_code, options);
}
}
check_success(neuray->shutdown() == 0);
neuray = 0;
check_success(unload());
keep_console_open();
return EXIT_SUCCESS;
}