diff --git a/.classpath b/.classpath deleted file mode 100644 index a3a7486..0000000 --- a/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/.externalToolBuilders/Ant Build.launch b/.externalToolBuilders/Ant Build.launch deleted file mode 100644 index 41ca506..0000000 --- a/.externalToolBuilders/Ant Build.launch +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a543a51 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.iml +.idea +target/ \ No newline at end of file diff --git a/.project b/.project deleted file mode 100644 index 2615127..0000000 --- a/.project +++ /dev/null @@ -1,27 +0,0 @@ - - - sunflow - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/Ant Build.launch - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 9cdf284..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,258 +0,0 @@ -#Sun Nov 19 15:00:49 CST 2006 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.5 -org.eclipse.jdt.core.formatter.align_type_members_on_columns=false -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 -org.eclipse.jdt.core.formatter.alignment_for_assignment=0 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 -org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 -org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 -org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 -org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0 -org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 -org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_after_package=1 -org.eclipse.jdt.core.formatter.blank_lines_before_field=0 -org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 -org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 -org.eclipse.jdt.core.formatter.blank_lines_before_method=1 -org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=0 -org.eclipse.jdt.core.formatter.blank_lines_before_package=0 -org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 -org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.comment.clear_blank_lines=true -org.eclipse.jdt.core.formatter.comment.format_comments=true -org.eclipse.jdt.core.formatter.comment.format_header=true -org.eclipse.jdt.core.formatter.comment.format_html=true -org.eclipse.jdt.core.formatter.comment.format_source_code=true -org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true -org.eclipse.jdt.core.formatter.comment.indent_root_tags=true -org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert -org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert -org.eclipse.jdt.core.formatter.comment.line_length=80 -org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=2 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 -org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true -org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_empty_lines=false -org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true -org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true -org.eclipse.jdt.core.formatter.indentation.size=4 -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert -org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false -org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false -org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false -org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false -org.eclipse.jdt.core.formatter.lineSplit=80 -org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 -org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 -org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true -org.eclipse.jdt.core.formatter.tabulation.char=space -org.eclipse.jdt.core.formatter.tabulation.size=4 -org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs deleted file mode 100644 index c4f6cf3..0000000 --- a/.settings/org.eclipse.jdt.ui.prefs +++ /dev/null @@ -1,6 +0,0 @@ -#Sat Sep 23 11:47:05 CDT 2006 -eclipse.preferences.version=1 -formatter_profile=_Sunflow Conventions -formatter_settings_version=10 -internal.default.compliance=default -org.eclipse.jdt.ui.text.custom_code_templates= diff --git a/.settings/org.eclipse.ltk.core.refactoring.prefs b/.settings/org.eclipse.ltk.core.refactoring.prefs deleted file mode 100644 index 436b429..0000000 --- a/.settings/org.eclipse.ltk.core.refactoring.prefs +++ /dev/null @@ -1,3 +0,0 @@ -#Sat Sep 23 11:47:05 CDT 2006 -eclipse.preferences.version=1 -org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..8ceacfa --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: java +install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -Dgpg.skip=true -B -V +script: mvn test -Dgpg.skip=true +jdk: + - oraclejdk8 diff --git a/CHANGELOG b/CHANGELOG index 05c6ef9..c2fc9e4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,12 @@ +v0.07.5 +* Added procedural scenes +* Added box type +v0.07.4 +* Updated janino version to 2.7.8 +* Allow changing shading cache parameters for a quality/speed trade-off +* Fixed missing TriangleMeshLight shader in PluginRegistry +* Fixed self-intersection bias +* Fixed infinite loop in bih caused by small triangle v0.07.3 * Fixed bump mapping to correctly treat black as the lowest point in the map * Added command line override for samples paramter (affect bucket and multipas samplers) diff --git a/README b/README.md similarity index 72% rename from README rename to README.md index e9b2002..7f4305a 100644 --- a/README +++ b/README.md @@ -1,5 +1,5 @@ -Sunflow Global Illumination Rendering System -v0.07.3 +# Sunflow Global Illumination Rendering System +v0.07.5 Contact: Christopher Kulla fpsunflower@users.sourceforge.net @@ -9,12 +9,10 @@ Contact: Christopher Kulla Sunflow is a rendering system for photo-realistic image synthesis. It is written in Java and built around a flexible ray tracing core and an extensible object-oriented design. -Please consult the LICENSE file for license information. - ----------------------------------------------------------------- - -Quickstart: +Please consult the [LICENSE file](https://github.com/Harium/sunflow/blob/master/LICENSE) for license information. +
+ Quickstart The fastest way to get started rendering images if you are not familiar with Java development is to get the binary release from the website. You will also need the latest Java SE JDK (to get the server VM) from http://java.sun.com/. Launch sunflow from the command prompt like this: @@ -31,12 +29,18 @@ You can find some simple demo scenes on the website's data distribution. A simpl DISCLAIMER: Keep in mind that this is still an early version. At the moment you will need to dig around the scene files in order to get the most out of the software. If you have any questions, feel free to e-mail me at the adress at the top. +
----------------------------------------------------------------- +
+ Build instructions +Download the latest JDK (6.0 at the time of this writing) if you don't have it already. Please note that the source code makes use of some new features like generics. Keep this in mind if you are trying to compile/run the code under a different JVM. -Build instructions: +Using mvn, type: +```bash +mvn clean package +``` -Download the latest JDK (6.0 at the time of this writing) if you don't have it already. Please note that the source code makes use of some new features like generics. Keep this in mind if you are trying to compile/run the code under a different JVM. +Or, using javac Create a main directory to hold the code (for example, "sunflow") and unzip the contents of the source package into it, preserving sub-directories. Create the "classes" subdirectory if your unzip program did not. You may now compile the software from the main directory by running: @@ -48,15 +52,18 @@ once the compiling is complete, run the code with: The tips above apply here as well (-Xmx and -server command line options). ----------------------------------------------------------------- +
-Scene file format: + +## Scene file format The SunflowGUI program accepts input in the .sc file format. As this is only a temporary file format, the best documentation for it is SCParser.java. You may also get a feel for what is supported by examining the example scene files provided in the data distribution. ----------------------------------------------------------------- +More information can be found at the [manual](https://github.com/Harium/sunflow/blob/master/Sunflow-Manual.pdf). -Rendering options: +---------------------------------------------------------------- +
+ Rendering options Here is a quick explanation of the basic rendering options. @@ -95,7 +102,7 @@ Box and triangle are best for previews as they are small and fast. The other fil Bucket rendering: -Sunflow proceses the image to be rendered in small squares called buckets. The size of these buckets can be controlled by a pixel width. Each rendering thread will be a assigned a single bucket. You may not get the bucket size you expect if you try to make them really small or really big, as there are some hard-coded limits to prevent excessive memory usage or excessive overhead. +Sunflow proceses the image to be rendered in small squares called buckets. The size of these buckets can be controlled by a pixel width. Each rendering thread will be assigned to a single bucket. You may not get the bucket size you expect if you try to make them really small or really big, as there are some hard-coded limits to prevent excessive memory usage or excessive overhead. The bucket ordering simply affects the order in which the buckets appear. They shouldn't have too much of an effect on overall rendering speed. @@ -117,21 +124,43 @@ Caustics are produced by light shining through refractive objects or being bounc Once you have a number of photons to emit, you must pick a way to store them. Only a kd engine is currently available for caustics. You can then set a value for the number of photons to gather at each shading point (start with ~50 to ~100) as well as a maximum search radius. These settings are highly scene dependent so experiment with them until you get satisfactory results. ----------------------------------------------------------------- +
-Third party libraries: +## Third party libraries Sunflow makes use of the following libraries, distributed according to the following terms: +
+ Janino License Janino - An embedded Java[TM] compiler -Copyright (c) 2006, Arno Unkrig +Copyright (c) 2001-2016, Arno Unkrig +Copyright (c) 2015-2016 TIBCO Software Inc. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + 3. Neither the name of JANINO nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +
diff --git a/Sunflow-Manual.pdf b/Sunflow-Manual.pdf new file mode 100644 index 0000000..26ae47c Binary files /dev/null and b/Sunflow-Manual.pdf differ diff --git a/build.xml b/build.xml index 147007a..8ae3bee 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - + diff --git a/janino.jar b/janino.jar deleted file mode 100644 index 50b34ea..0000000 Binary files a/janino.jar and /dev/null differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d5463e4 --- /dev/null +++ b/pom.xml @@ -0,0 +1,149 @@ + + 4.0.0 + com.harium.sunflow + core + 0.07.5 + Sunflow + Sunflow Global Illumination Rendering System + http://github.com/Harium/sunflow + + scm:git:git://github.com/harium/sunflow.git + scm:git:ssh://github.com:harium/sunflow.git + http://github.com/harium/sunflow/tree/master + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + -Xdoclint:none + UTF-8 + gpg2 + + + + MIT License + http://www.opensource.org/licenses/mit-license.php + + + + + Contributors + https://github.com/Harium/sunflow/graphs/contributors + + + + + org.codehaus.janino + janino + 2.7.8 + + + net.jafama + jafama + 2.1.0 + + + junit + junit + 4.12 + test + + + org.mockito + mockito-all + 1.10.19 + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.5.1 + + 1.8 + 1.8 + true + + **/examples/* + **/exporters/* + **/resources/* + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + ${javadoc.opts} + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + + default-deploy + deploy + + deploy + + + + + ossrh + https://oss.sonatype.org/ + true + + + + + \ No newline at end of file diff --git a/src/SunflowGUI.java b/src/main/java/SunflowGUI.java similarity index 97% rename from src/SunflowGUI.java rename to src/main/java/SunflowGUI.java index 831fd3f..b79e725 100644 --- a/src/SunflowGUI.java +++ b/src/main/java/SunflowGUI.java @@ -42,6 +42,9 @@ import org.sunflow.Benchmark; import org.sunflow.RealtimeBenchmark; import org.sunflow.SunflowAPI; +import org.sunflow.core.parameter.BucketParameter; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.OverrideParameter; import org.sunflow.core.Display; import org.sunflow.core.TextureCache; import org.sunflow.core.accel.KDTree; @@ -49,10 +52,7 @@ import org.sunflow.core.display.FrameDisplay; import org.sunflow.core.display.ImgPipeDisplay; import org.sunflow.core.primitive.TriangleMesh; -import org.sunflow.system.ImagePanel; -import org.sunflow.system.Timer; -import org.sunflow.system.UI; -import org.sunflow.system.UserInterface; +import org.sunflow.system.*; import org.sunflow.system.UI.Module; import org.sunflow.system.UI.PrintLevel; @@ -361,18 +361,18 @@ else if (baketype.equals("ortho")) } } if (runBenchmark) { - SunflowAPI.runSystemCheck(); + SystemUtil.runSystemCheck(); new Benchmark().execute(); return; } if (runRTBenchmark) { - SunflowAPI.runSystemCheck(); + SystemUtil.runSystemCheck(); new RealtimeBenchmark(showFrame, threads); return; } if (input == null) usage(false); - SunflowAPI.runSystemCheck(); + SystemUtil.runSystemCheck(); if (translateFilename != null) { SunflowAPI.translate(input, translateFilename); return; @@ -392,20 +392,20 @@ else if (baketype.equals("ortho")) if (noRender) continue; if (resolutionW > 0 && resolutionH > 0) { - api.parameter("resolutionX", resolutionW); - api.parameter("resolutionY", resolutionH); + api.parameter(ImageParameter.PARAM_RESOLUTION_X, resolutionW); + api.parameter(ImageParameter.PARAM_RESOLUTION_Y, resolutionH); } if (aaMin != -5 || aaMax != -5) { - api.parameter("aa.min", aaMin); - api.parameter("aa.max", aaMax); + api.parameter(ImageParameter.PARAM_AA_MIN, aaMin); + api.parameter(ImageParameter.PARAM_AA_MAX, aaMax); } if (samples >= 0) - api.parameter("aa.samples", samples); + api.parameter(ImageParameter.PARAM_AA_SAMPLES, samples); if (bucketSize > 0) - api.parameter("bucket.size", bucketSize); + api.parameter(BucketParameter.PARAM_BUCKET_SIZE, bucketSize); if (bucketOrder != null) - api.parameter("bucket.order", bucketOrder); - api.parameter("aa.display", showAA); + api.parameter(BucketParameter.PARAM_BUCKET_ORDER, bucketOrder); + api.parameter(ImageParameter.PARAM_AA_DISPLAY, showAA); api.parameter("threads", threads); api.parameter("threads.lowPriority", lowPriority); if (bakingName != null) { @@ -413,7 +413,7 @@ else if (baketype.equals("ortho")) api.parameter("baking.viewdep", bakeViewdep); } if (filterType != null) - api.parameter("filter", filterType); + api.parameter(ImageParameter.PARAM_FILTER, filterType); if (noGI) api.parameter("gi.engine", "none"); else if (pathGI > 0) { @@ -423,14 +423,14 @@ else if (pathGI > 0) { if (noCaustics) api.parameter("caustics", "none"); if (sampler != null) - api.parameter("sampler", sampler); + api.parameter(ImageParameter.PARAM_SAMPLER, sampler); api.options(SunflowAPI.DEFAULT_OPTIONS); if (shaderOverride != null) { if (shaderOverride.equals("ambient_occlusion")) api.parameter("maxdist", maxDist); api.shader("cmdline_override", shaderOverride); - api.parameter("override.shader", "cmdline_override"); - api.parameter("override.photons", true); + api.parameter(OverrideParameter.PARAM_OVERRIDE_SHADER, "cmdline_override"); + api.parameter(OverrideParameter.PARAM_OVERRIDE_PHOTONS, true); api.options(SunflowAPI.DEFAULT_OPTIONS); } // create display @@ -454,7 +454,7 @@ else if (pathGI > 0) { if (screenRes.getWidth() <= DEFAULT_WIDTH || screenRes.getHeight() <= DEFAULT_HEIGHT) gui.setExtendedState(MAXIMIZED_BOTH); gui.tileWindowMenuItem.doClick(); - SunflowAPI.runSystemCheck(); + SystemUtil.runSystemCheck(); } } diff --git a/src/main/java/examples/BumpScene.java b/src/main/java/examples/BumpScene.java new file mode 100644 index 0000000..3192f3b --- /dev/null +++ b/src/main/java/examples/BumpScene.java @@ -0,0 +1,182 @@ +package examples; + +import org.sunflow.SunflowAPI; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.camera.PinholeCameraParameter; +import org.sunflow.core.parameter.geometry.PlaneParameter; +import org.sunflow.core.parameter.geometry.SphereParameter; +import org.sunflow.core.parameter.geometry.TeapotParameter; +import org.sunflow.core.parameter.light.SunSkyLightParameter; +import org.sunflow.core.parameter.modifier.BumpMapModifierParameter; +import org.sunflow.core.parameter.modifier.NormalMapModifierParameter; +import org.sunflow.core.parameter.shader.DiffuseShaderParameter; +import org.sunflow.core.parameter.shader.GlassShaderParameter; +import org.sunflow.core.parameter.shader.ShinyShaderParameter; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class BumpScene { + + public static void main(String[] args) { + SunflowAPI api = new SunflowAPI(); + api.reset(); + api.searchpath("texture", System.getProperty("user.dir") + "/examples/"); + buildScene(api); + + finalRender(api); + } + + public static void buildScene(SunflowAPI api) { + ImageParameter image = new ImageParameter(); + image.setResolutionX(800); + image.setResolutionY(450); + image.setAAMin(0); + image.setAAMax(1); + image.setFilter(ImageParameter.FILTER_TRIANGLE); + image.setup(api); + + PinholeCameraParameter camera = new PinholeCameraParameter(); + + camera.setName("camera"); + Point3 eye = new Point3(-18.19f, 8.97f, -0.93f); + Point3 target = new Point3(-0.690f, 0.97f, -0.93f); + Vector3 up = new Vector3(0, 1, 0); + + camera.setupTransform(api, eye, target, up); + + camera.setFov(30f); + camera.setAspect(1.777777777777f); + camera.setup(api); + + SunSkyLightParameter lightParameter = new SunSkyLightParameter(); + lightParameter.setName("sunsky"); + lightParameter.setUp(new Vector3(0, 1, 0)); + lightParameter.setEast(new Vector3(0, 0, 1)); + lightParameter.setSunDirection(new Vector3(-1, 1, -1)); + lightParameter.setTurbidity(2); + lightParameter.setSamples(32); + lightParameter.setup(api); + + NormalMapModifierParameter bumpy01 = new NormalMapModifierParameter("bumpy_01"); + bumpy01.setTexture("textures/brick_normal.jpg"); + bumpy01.setup(api); + + BumpMapModifierParameter bumpy02 = new BumpMapModifierParameter("bumpy_02"); + bumpy02.setTexture("textures/dirty_bump.jpg"); + bumpy02.setScale(0.02f); + bumpy02.setup(api); + + BumpMapModifierParameter bumpy03 = new BumpMapModifierParameter("bumpy_03"); + bumpy03.setTexture("textures/reptileskin_bump.png"); + bumpy03.setScale(0.02f); + bumpy03.setup(api); + + BumpMapModifierParameter bumpy04 = new BumpMapModifierParameter("bumpy_04"); + bumpy04.setTexture("textures/shiphull_bump.png"); + bumpy04.setScale(0.15f); + bumpy04.setup(api); + + BumpMapModifierParameter bumpy05 = new BumpMapModifierParameter("bumpy_05"); + bumpy05.setTexture("textures/slime_bump.jpg"); + bumpy05.setScale(0.15f); + bumpy05.setup(api); + + ShinyShaderParameter shiny = new ShinyShaderParameter("default"); + shiny.setDiffuse(new Color(0.2f, 0.2f, 0.2f)); + shiny.setShininess(0.3f); + shiny.setup(api); + + GlassShaderParameter glassy = new GlassShaderParameter("glassy"); + glassy.setEta(1.2f); + glassy.setColor(new Color(0.8f, 0.8f, 0.8f)); + glassy.setAbsorptionDistance(7); + glassy.setAbsorptionColor(new Color(0.2f, 0.7f, 0.2f).toLinear()); + glassy.setup(api); + + DiffuseShaderParameter simpleRed = new DiffuseShaderParameter("simple_red"); + simpleRed.setDiffuse(new Color(0.7f, 0.15f, 0.15f).toLinear()); + simpleRed.setup(api); + + DiffuseShaderParameter simpleGreen = new DiffuseShaderParameter("simple_green"); + simpleGreen.setDiffuse(new Color(0.15f, 0.7f, 0.15f).toLinear()); + simpleGreen.setup(api); + + DiffuseShaderParameter simpleYellow = new DiffuseShaderParameter("simple_yellow"); + simpleYellow.setDiffuse(new Color(0.8f, 0.8f, 0.2f).toLinear()); + simpleYellow.setup(api); + + DiffuseShaderParameter floorShader = new DiffuseShaderParameter("floor"); + //floorShader.setDiffuse(new Color(0.3f, 0.3f, 0.3f)); + floorShader.setTexture("textures/brick_color.jpg"); + floorShader.setup(api); + + PlaneParameter floor = new PlaneParameter(); + floor.shaders(floorShader); + floor.modifiers(bumpy01); + floor.setCenter(new Point3(0, 0, 0)); + floor.setPoint1(new Point3(4, 0, 3)); + floor.setPoint2(new Point3(-3, 0, 4)); + floor.setup(api); + + TeapotParameter teapot0 = new TeapotParameter("teapot_0"); + teapot0.shaders(simpleGreen); + teapot0.modifiers(bumpy03); + teapot0.rotateX(-90); + teapot0.scale(0.018f); + teapot0.rotateY(245f); + teapot0.translate(1.5f, 0, -1); + teapot0.setSubdivs(20); + teapot0.setup(api); + + SphereParameter sphere0 = new SphereParameter("sphere_0"); + sphere0.shaders(glassy); + sphere0.rotateX(35); + sphere0.scale(1.5f); + sphere0.rotateY(245); + sphere0.translate(1.5f, 1.5f, 3); + sphere0.setup(api); + + SphereParameter sphere1 = new SphereParameter("sphere_1"); + sphere1.shaders(shiny); + sphere1.modifiers(bumpy05); + sphere1.rotateX(35); + sphere1.scale(1.5f); + sphere1.rotateY(245); + sphere1.translate(1.5f, 1.5f, -5); + sphere1.setup(api); + + TeapotParameter teapot1 = new TeapotParameter("teapot_1"); + teapot1.geometry(teapot0); + teapot1.rotateX(-90); + teapot1.scale(0.018f); + teapot1.rotateY(245f); + teapot1.translate(-1.5f, 0, -3); + teapot1.shaders(simpleYellow); + teapot1.modifiers(bumpy04); + teapot1.setup(api); + + TeapotParameter teapot3 = new TeapotParameter("teapot_3"); + teapot3.geometry(teapot0); + teapot3.shaders(simpleRed); + teapot3.modifiers(bumpy02); + teapot3.rotateX(-90); + teapot3.scale(0.018f); + teapot3.rotateY(245f); + teapot3.translate(-1.5f, 0, 1); + teapot3.setup(api); + } + + private static void previewRender(SunflowAPI api) { + api.parameter("sampler", "ipr"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + + private static void finalRender(SunflowAPI api) { + api.parameter("sampler", "bucket"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + +} diff --git a/src/main/java/examples/CornellBoxJensenScene.java b/src/main/java/examples/CornellBoxJensenScene.java new file mode 100644 index 0000000..6d6efa2 --- /dev/null +++ b/src/main/java/examples/CornellBoxJensenScene.java @@ -0,0 +1,119 @@ +package examples; + +import org.sunflow.SunflowAPI; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.InstanceParameter; +import org.sunflow.core.parameter.PhotonParameter; +import org.sunflow.core.parameter.TraceDepthsParameter; +import org.sunflow.core.parameter.camera.PinholeCameraParameter; +import org.sunflow.core.parameter.geometry.SphereParameter; +import org.sunflow.core.parameter.gi.InstantGIParameter; +import org.sunflow.core.parameter.light.CornellBoxLightParameter; +import org.sunflow.core.parameter.shader.GlassShaderParameter; +import org.sunflow.core.parameter.shader.MirrorShaderParameter; +import org.sunflow.image.Color; +import org.sunflow.math.Matrix4; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class CornellBoxJensenScene { + + public static void main(String[] args) { + SunflowAPI api = new SunflowAPI(); + api.reset(); + + ImageParameter image = new ImageParameter(); + image.setResolutionX(800); + image.setResolutionY(600); + image.setAAMin(0); + image.setAAMax(2); + image.setFilter(ImageParameter.FILTER_GAUSSIAN); + image.setup(api); + + TraceDepthsParameter traceDepths = new TraceDepthsParameter(); + traceDepths.setDiffuse(4); + traceDepths.setReflection(3); + traceDepths.setRefraction(2); + traceDepths.setup(api); + + PhotonParameter photons = new PhotonParameter(); + photons.setNumEmit(1000000); + photons.setCaustics("kd"); + photons.setCausticsGather(100); + photons.setCausticsRadius(0.5f); + photons.setup(api); + + InstantGIParameter gi = new InstantGIParameter(); + gi.setSamples(64); + gi.setSets(1); + gi.setBias(0.00003f); + gi.setBiasSamples(0); + gi.setup(api); + + PinholeCameraParameter camera = new PinholeCameraParameter(); + + camera.setName("camera"); + Point3 eye = new Point3(0, -205, 50); + Point3 target = new Point3(0, 0, 50); + Vector3 up = new Vector3(0, 0, 1); + + camera.setupTransform(api, eye,target,up); + + camera.setFov(45f); + camera.setAspect(1.333333f); + camera.setup(api); + + // Materials + MirrorShaderParameter mirror = new MirrorShaderParameter("Mirror"); + mirror.setReflection(new Color(0.7f, 0.7f, 0.7f)); + mirror.setup(api); + + GlassShaderParameter glass = new GlassShaderParameter("Glass"); + glass.setEta(1.6f); + glass.setAbsorptionColor(new Color(1, 1, 1)); + glass.setup(api); + + // Lights + CornellBoxLightParameter lightParameter = new CornellBoxLightParameter(); + lightParameter.setName("cornell-box-light"); + lightParameter.setMin(new Point3(-60, -60, 0)); + lightParameter.setMax(new Point3(60, 60, 100)); + lightParameter.setLeft(new Color(0.8f, 0.25f, 0.25f)); + lightParameter.setRight(new Color(0.25f, 0.25f, 0.8f)); + lightParameter.setTop(new Color(0.7f, 0.7f, 0.7f)); + lightParameter.setBottom(new Color(0.7f, 0.7f, 0.7f)); + lightParameter.setBack(new Color(0.7f, 0.7f, 0.7f)); + lightParameter.setRadiance(new Color(15, 15, 15)); + lightParameter.setSamples(32); + lightParameter.setup(api); + + SphereParameter mirrorSphere = new SphereParameter(); + mirrorSphere.setName("mirror-sphere"); + mirrorSphere.setCenter(new Point3(-30, 30, 20)); + mirrorSphere.setInstanceParameter(new InstanceParameter().shaders("Mirror")); + mirrorSphere.setRadius(20); + mirrorSphere.setup(api); + + SphereParameter glassSphere = new SphereParameter(); + glassSphere.setName("glass-sphere"); + glassSphere.setCenter(new Point3(28, 2, 20)); + glassSphere.setInstanceParameter(new InstanceParameter().shaders("Glass")); + glassSphere.setRadius(20); + glassSphere.setup(api); + + finalRender(api); + } + + private static void previewRender(SunflowAPI api) { + api.parameter("sampler", "ipr"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + + private static void finalRender(SunflowAPI api) { + api.parameter("sampler", "bucket"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + +} diff --git a/src/main/java/examples/CornellBoxJensenWithBoxesScene.java b/src/main/java/examples/CornellBoxJensenWithBoxesScene.java new file mode 100644 index 0000000..99f26ba --- /dev/null +++ b/src/main/java/examples/CornellBoxJensenWithBoxesScene.java @@ -0,0 +1,119 @@ +package examples; + +import org.sunflow.SunflowAPI; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.InstanceParameter; +import org.sunflow.core.parameter.PhotonParameter; +import org.sunflow.core.parameter.TraceDepthsParameter; +import org.sunflow.core.parameter.camera.PinholeCameraParameter; +import org.sunflow.core.parameter.geometry.BoxParameter; +import org.sunflow.core.parameter.geometry.SphereParameter; +import org.sunflow.core.parameter.gi.InstantGIParameter; +import org.sunflow.core.parameter.light.CornellBoxLightParameter; +import org.sunflow.core.parameter.shader.GlassShaderParameter; +import org.sunflow.core.parameter.shader.MirrorShaderParameter; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class CornellBoxJensenWithBoxesScene { + + public static void main(String[] args) { + SunflowAPI api = new SunflowAPI(); + api.reset(); + + ImageParameter image = new ImageParameter(); + image.setResolutionX(800); + image.setResolutionY(600); + image.setAAMin(0); + image.setAAMax(2); + image.setFilter(ImageParameter.FILTER_GAUSSIAN); + image.setup(api); + + TraceDepthsParameter traceDepths = new TraceDepthsParameter(); + traceDepths.setDiffuse(4); + traceDepths.setReflection(3); + traceDepths.setRefraction(2); + traceDepths.setup(api); + + PhotonParameter photons = new PhotonParameter(); + photons.setNumEmit(1000000); + photons.setCaustics("kd"); + photons.setCausticsGather(100); + photons.setCausticsRadius(0.5f); + photons.setup(api); + + InstantGIParameter gi = new InstantGIParameter(); + gi.setSamples(64); + gi.setSets(1); + gi.setBias(0.00003f); + gi.setBiasSamples(0); + gi.setup(api); + + PinholeCameraParameter camera = new PinholeCameraParameter(); + + camera.setName("camera"); + Point3 eye = new Point3(0, -205, 50); + Point3 target = new Point3(0, 0, 50); + Vector3 up = new Vector3(0, 0, 1); + + camera.setupTransform(api, eye,target,up); + + camera.setFov(45f); + camera.setAspect(1.333333f); + camera.setup(api); + + // Materials + MirrorShaderParameter mirror = new MirrorShaderParameter("Mirror"); + mirror.setReflection(new Color(0.7f, 0.7f, 0.7f)); + mirror.setup(api); + + GlassShaderParameter glass = new GlassShaderParameter("Glass"); + glass.setEta(1.6f); + glass.setAbsorptionColor(new Color(1, 1, 1)); + glass.setup(api); + + // Lights + CornellBoxLightParameter lightParameter = new CornellBoxLightParameter(); + lightParameter.setName("cornell-box-light"); + lightParameter.setMin(new Point3(-60, -60, 0)); + lightParameter.setMax(new Point3(60, 60, 100)); + lightParameter.setLeft(new Color(0.8f, 0.25f, 0.25f)); + lightParameter.setRight(new Color(0.25f, 0.25f, 0.8f)); + lightParameter.setTop(new Color(0.7f, 0.7f, 0.7f)); + lightParameter.setBottom(new Color(0.7f, 0.7f, 0.7f)); + lightParameter.setBack(new Color(0.7f, 0.7f, 0.7f)); + lightParameter.setRadiance(new Color(15, 15, 15)); + lightParameter.setSamples(32); + lightParameter.setup(api); + + BoxParameter mirrorBox = new BoxParameter(); + mirrorBox.setName("mirror-box"); + mirrorBox.setMin(new Point3(-50, 10, 0)); + mirrorBox.setMax(new Point3(-10, 50, 40)); + mirrorBox.shaders(mirror); + mirrorBox.setup(api); + + BoxParameter glassBox = new BoxParameter(); + glassBox.setName("glass-box"); + glassBox.setMin(new Point3(8, -22, 0)); + glassBox.setMax(new Point3(48, 22, 40)); + glassBox.shaders(glass); + glassBox.setup(api); + + finalRender(api); + } + + private static void previewRender(SunflowAPI api) { + api.parameter("sampler", "ipr"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + + private static void finalRender(SunflowAPI api) { + api.parameter("sampler", "bucket"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + +} diff --git a/src/main/java/examples/GlassScene.java b/src/main/java/examples/GlassScene.java new file mode 100644 index 0000000..5db1528 --- /dev/null +++ b/src/main/java/examples/GlassScene.java @@ -0,0 +1,118 @@ +package examples; + +import org.sunflow.SunflowAPI; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.InstanceParameter; +import org.sunflow.core.parameter.PhotonParameter; +import org.sunflow.core.parameter.TraceDepthsParameter; +import org.sunflow.core.parameter.camera.PinholeCameraParameter; +import org.sunflow.core.parameter.geometry.SphereParameter; +import org.sunflow.core.parameter.gi.InstantGIParameter; +import org.sunflow.core.parameter.light.CornellBoxLightParameter; +import org.sunflow.core.parameter.shader.GlassShaderParameter; +import org.sunflow.core.parameter.shader.MirrorShaderParameter; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class GlassScene { + + public static void main(String[] args) { + SunflowAPI api = new SunflowAPI(); + api.reset(); + + ImageParameter image = new ImageParameter(); + image.setResolutionX(800); + image.setResolutionY(600); + image.setAAMin(0); + image.setAAMax(2); + image.setFilter(ImageParameter.FILTER_GAUSSIAN); + image.setup(api); + + TraceDepthsParameter traceDepths = new TraceDepthsParameter(); + traceDepths.setDiffuse(4); + traceDepths.setReflection(3); + traceDepths.setRefraction(2); + traceDepths.setup(api); + + PhotonParameter photons = new PhotonParameter(); + photons.setNumEmit(1000000); + photons.setCaustics("kd"); + photons.setCausticsGather(100); + photons.setCausticsRadius(0.5f); + photons.setup(api); + + InstantGIParameter gi = new InstantGIParameter(); + gi.setSamples(64); + gi.setSets(1); + gi.setBias(0.00003f); + gi.setBiasSamples(0); + gi.setup(api); + + PinholeCameraParameter camera = new PinholeCameraParameter(); + + camera.setName("camera"); + Point3 eye = new Point3(0, -205, 50); + Point3 target = new Point3(0, 0, 50); + Vector3 up = new Vector3(0, 0, 1); + + camera.setupTransform(api, eye,target,up); + + camera.setFov(45f); + camera.setAspect(1.333333f); + camera.setup(api); + + // Materials + MirrorShaderParameter mirror = new MirrorShaderParameter("Mirror"); + mirror.setReflection(new Color(0.7f, 0.7f, 0.7f)); + mirror.setup(api); + + GlassShaderParameter glass = new GlassShaderParameter("Glass"); + glass.setEta(1.6f); + glass.setAbsorptionColor(new Color(1, 1, 1)); + glass.setup(api); + + // Lights + CornellBoxLightParameter lightParameter = new CornellBoxLightParameter(); + lightParameter.setName("cornell-box-light"); + lightParameter.setMin(new Point3(-60, -60, 0)); + lightParameter.setMax(new Point3(60, 60, 100)); + lightParameter.setLeft(new Color(0.8f, 0.25f, 0.25f)); + lightParameter.setRight(new Color(0.25f, 0.25f, 0.8f)); + lightParameter.setTop(new Color(0.7f, 0.7f, 0.7f)); + lightParameter.setBottom(new Color(0.7f, 0.7f, 0.7f)); + lightParameter.setBack(new Color(0.7f, 0.7f, 0.7f)); + lightParameter.setRadiance(new Color(15, 15, 15)); + lightParameter.setSamples(32); + lightParameter.setup(api); + + SphereParameter mirrorSphere = new SphereParameter(); + mirrorSphere.setName("mirror-sphere"); + mirrorSphere.setCenter(new Point3(-30, 30, 20)); + mirrorSphere.setInstanceParameter(new InstanceParameter().shaders("Mirror")); + mirrorSphere.setRadius(20); + mirrorSphere.setup(api); + + SphereParameter glassSphere = new SphereParameter(); + glassSphere.setName("glass-sphere"); + glassSphere.setCenter(new Point3(28, 2, 20)); + glassSphere.setInstanceParameter(new InstanceParameter().shaders("Glass")); + glassSphere.setRadius(20); + glassSphere.setup(api); + + finalRender(api); + } + + private static void previewRender(SunflowAPI api) { + api.parameter("sampler", "ipr"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + + private static void finalRender(SunflowAPI api) { + api.parameter("sampler", "bucket"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + +} diff --git a/src/main/java/examples/GumboAndTeapotScene.java b/src/main/java/examples/GumboAndTeapotScene.java new file mode 100644 index 0000000..3ed9f4f --- /dev/null +++ b/src/main/java/examples/GumboAndTeapotScene.java @@ -0,0 +1,209 @@ +package examples; + +import org.sunflow.SunflowAPI; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.camera.PinholeCameraParameter; +import org.sunflow.core.parameter.geometry.GumboParameter; +import org.sunflow.core.parameter.geometry.PlaneParameter; +import org.sunflow.core.parameter.geometry.TeapotParameter; +import org.sunflow.core.parameter.light.SunSkyLightParameter; +import org.sunflow.core.parameter.shader.DiffuseShaderParameter; +import org.sunflow.core.parameter.shader.ShinyShaderParameter; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class GumboAndTeapotScene { + + public static void main(String[] args) { + SunflowAPI api = new SunflowAPI(); + api.reset(); + buildScene(api); + + finalRender(api); + } + + public static void buildScene(SunflowAPI api){ + ImageParameter image = new ImageParameter(); + image.setResolutionX(800); + image.setResolutionY(450); + image.setAAMin(0); + image.setAAMax(1); + image.setFilter(ImageParameter.FILTER_TRIANGLE); + image.setup(api); + + PinholeCameraParameter camera = new PinholeCameraParameter(); + + camera.setName("camera"); + Point3 eye = new Point3(-18.19f, 8.97f, -0.93f); + Point3 target = new Point3(-0.690f, 0.97f, -0.93f); + Vector3 up = new Vector3(0, 1, 0); + + camera.setupTransform(api, eye, target, up); + + camera.setFov(30f); + camera.setAspect(1.777777777777f); + camera.setup(api); + + SunSkyLightParameter lightParameter = new SunSkyLightParameter(); + lightParameter.setName("sunsky"); + lightParameter.setUp(new Vector3(0, 1, 0)); + lightParameter.setEast(new Vector3(0, 0, 1)); + lightParameter.setSunDirection(new Vector3(1, 1, 1)); + lightParameter.setTurbidity(4); + lightParameter.setSamples(64); + lightParameter.setup(api); + + // Materials + ShinyShaderParameter shiny = new ShinyShaderParameter("default"); + shiny.setDiffuse(new Color(0.2f, 0.2f, 0.2f)); + shiny.setShininess(0.1f); + shiny.setup(api); + + DiffuseShaderParameter simple = new DiffuseShaderParameter("simple"); + simple.setDiffuse(new Color(0.2f, 0.2f, 0.2f)); + simple.setup(api); + + DiffuseShaderParameter simpleRed = new DiffuseShaderParameter("simple_red"); + simpleRed.setDiffuse(new Color(0.8f, 0.2f, 0.2f).toLinear()); + simpleRed.setup(api); + + DiffuseShaderParameter simpleGreen = new DiffuseShaderParameter("simple_green"); + simpleGreen.setDiffuse(new Color(0.2f, 0.8f, 0.2f).toLinear()); + simpleGreen.setup(api); + + DiffuseShaderParameter simpleBlue = new DiffuseShaderParameter("simple_blue"); + simpleBlue.setDiffuse(new Color(0.2f, 0.2f, 0.8f).toLinear()); + simpleBlue.setup(api); + + DiffuseShaderParameter simpleYellow = new DiffuseShaderParameter("simple_yellow"); + simpleYellow.setDiffuse(new Color(0.8f, 0.8f, 0.2f).toLinear()); + simpleYellow.setup(api); + + DiffuseShaderParameter floorShader = new DiffuseShaderParameter("floor"); + floorShader.setDiffuse(new Color(0.1f, 0.1f, 0.1f)); + floorShader.setup(api); + + GumboParameter gumbo0 = new GumboParameter(); + gumbo0.setName("gumbo_0"); + gumbo0.setSubdivs(7); + gumbo0.shaders(shiny); + gumbo0.rotateX(-90); + gumbo0.scale(0.1f); + gumbo0.rotateY(75); + gumbo0.translate(-0.25f, 0, 0.63f); + gumbo0.setup(api); + + GumboParameter gumbo1 = new GumboParameter(); + gumbo1.setName("gumbo_1"); + gumbo1.setSubdivs(4); + gumbo1.shaders(simpleRed); + gumbo1.rotateX(-90); + gumbo1.scale(0.1f); + gumbo1.rotateY(25); + gumbo1.translate(1.5f, 0, -1.5f); + gumbo1.setSmooth(false); + gumbo1.setup(api); + + GumboParameter gumbo2 = new GumboParameter(); + gumbo2.setName("gumbo_2"); + gumbo2.setSubdivs(3); + gumbo2.shaders(simpleBlue); + gumbo2.rotateX(-90); + gumbo2.scale(0.1f); + gumbo2.rotateY(25); + gumbo2.translate(0, 0, -3f); + gumbo2.setSmooth(false); + gumbo2.setup(api); + + GumboParameter gumbo3 = new GumboParameter(); + gumbo3.setName("gumbo_3"); + gumbo3.setSubdivs(6); + gumbo3.shaders(simpleGreen); + gumbo3.rotateX(-90); + gumbo3.scale(0.1f); + gumbo3.rotateY(-25); + gumbo3.translate(1.5f, 0, 1.5f); + gumbo3.setSmooth(false); + gumbo3.setup(api); + + GumboParameter gumbo4 = new GumboParameter(); + gumbo4.setName("gumbo_4"); + gumbo4.setSubdivs(8); + gumbo4.shaders(simpleYellow); + gumbo4.rotateX(-90); + gumbo4.scale(0.1f); + gumbo4.rotateY(-25); + gumbo4.translate(0f, 0, 3f); + gumbo4.setSmooth(false); + gumbo4.setup(api); + + PlaneParameter floor = new PlaneParameter(); + floor.shaders(floorShader); + floor.setCenter(new Point3(0, 0, 0)); + floor.setNormal(new Vector3(0, 1, 0)); + floor.setup(api); + + TeapotParameter teapot0 = new TeapotParameter("teapot_0"); + teapot0.shaders(shiny); + teapot0.rotateX(-90); + teapot0.scale(0.008f); + teapot0.rotateY(245f); + teapot0.translate(-3, 0, -1); + teapot0.setSubdivs(7); + teapot0.setup(api); + + TeapotParameter teapot1 = new TeapotParameter("teapot_1"); + teapot1.shaders(simpleYellow); + teapot1.rotateX(-90); + teapot1.scale(0.008f); + teapot1.rotateY(245f); + teapot1.translate(-1.5f, 0, -3); + teapot1.setSubdivs(4); + teapot1.setSmooth(false); + teapot1.setup(api); + + TeapotParameter teapot2 = new TeapotParameter("teapot_2"); + teapot2.shaders(simpleGreen); + teapot2.rotateX(-90); + teapot2.scale(0.008f); + teapot2.rotateY(245f); + teapot2.translate(0, 0, -5); + teapot2.setSubdivs(3); + teapot2.setSmooth(false); + teapot2.setup(api); + + TeapotParameter teapot3 = new TeapotParameter("teapot_3"); + teapot3.shaders(simpleRed); + teapot3.rotateX(-90); + teapot3.scale(0.008f); + teapot3.rotateY(245f); + teapot3.translate(-1.5f, 0, 1); + teapot3.setSubdivs(5); + teapot3.setSmooth(false); + teapot3.setup(api); + + TeapotParameter teapot4 = new TeapotParameter("teapot_4"); + teapot4.shaders(simpleBlue); + teapot4.rotateX(-90); + teapot4.scale(0.008f); + teapot4.rotateY(245f); + teapot4.translate(0, 0, 3); + teapot4.setSubdivs(7); + teapot4.setSmooth(false); + teapot4.setup(api); + } + + private static void previewRender(SunflowAPI api) { + api.parameter("sampler", "ipr"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + + private static void finalRender(SunflowAPI api) { + api.parameter("sampler", "bucket"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + +} diff --git a/src/main/java/examples/JuliaScene.java b/src/main/java/examples/JuliaScene.java new file mode 100644 index 0000000..3ed2ca6 --- /dev/null +++ b/src/main/java/examples/JuliaScene.java @@ -0,0 +1,95 @@ +package examples; + +import org.sunflow.SunflowAPI; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.TraceDepthsParameter; +import org.sunflow.core.parameter.camera.PinholeCameraParameter; +import org.sunflow.core.parameter.geometry.JuliaParameter; +import org.sunflow.core.parameter.gi.PathTracingGIParameter; +import org.sunflow.core.parameter.light.SphereLightParameter; +import org.sunflow.core.parameter.shader.DiffuseShaderParameter; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class JuliaScene { + + public static void main(String[] args) { + SunflowAPI api = new SunflowAPI(); + api.reset(); + + ImageParameter image = new ImageParameter(); + image.setResolutionX(512); + image.setResolutionY(512); + image.setAAMin(0); + image.setAAMax(2); + image.setFilter(ImageParameter.FILTER_GAUSSIAN); + image.setup(api); + + TraceDepthsParameter traceDepths = new TraceDepthsParameter(); + traceDepths.setDiffuse(1); + traceDepths.setReflection(0); + traceDepths.setRefraction(0); + traceDepths.setup(api); + + PinholeCameraParameter camera = new PinholeCameraParameter(); + + camera.setName("camera"); + Point3 eye = new Point3(-5, 0, 0); + Point3 target = new Point3(0, 0, 0); + Vector3 up = new Vector3(0, 1, 0); + + camera.setupTransform(api, eye, target, up); + + camera.setFov(58f); + camera.setAspect(1); + camera.setup(api); + + PathTracingGIParameter gi = new PathTracingGIParameter(); + gi.setSamples(16); + gi.setup(api); + + DiffuseShaderParameter simple1 = new DiffuseShaderParameter("simple1"); + simple1.setDiffuse(new Color(0.5f, 0.5f, 0.5f).toLinear()); + simple1.setup(api); + + SphereLightParameter light0 = new SphereLightParameter(); + light0.setRadiance(new Color(1, 1, 0.6f).toLinear().mul(60)); + light0.setCenter(new Point3(-5, 7, 5)); + light0.setRadius(2); + light0.setSamples(8); + light0.setup(api); + + SphereLightParameter light1 = new SphereLightParameter(); + light1.setRadiance(new Color(0.6f, 0.6f, 1f).toLinear().mul(20)); + light1.setCenter(new Point3(-15, -17, -15)); + light1.setRadius(5); + light1.setSamples(8); + light1.setup(api); + + JuliaParameter left = new JuliaParameter("left"); + left.shaders(simple1); + left.scale(2); + left.rotateY(45); + left.rotateX(-55); + left.setIterations(8); + left.setEpsilon(0.001f); + left.setQuaternion(-0.125f, -0.256f, 0.847f, 0.0895f); + left.setup(api); + + finalRender(api); + } + + private static void previewRender(SunflowAPI api) { + api.parameter("sampler", "ipr"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + + private static void finalRender(SunflowAPI api) { + api.parameter("sampler", "bucket"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + +} diff --git a/src/main/java/examples/SphereFlakeScene.java b/src/main/java/examples/SphereFlakeScene.java new file mode 100644 index 0000000..0c7b98d --- /dev/null +++ b/src/main/java/examples/SphereFlakeScene.java @@ -0,0 +1,119 @@ +package examples; + +import org.sunflow.SunflowAPI; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.InstanceParameter; +import org.sunflow.core.parameter.TraceDepthsParameter; +import org.sunflow.core.parameter.camera.PinholeCameraParameter; +import org.sunflow.core.parameter.camera.ThinLensCameraParameter; +import org.sunflow.core.parameter.geometry.PlaneParameter; +import org.sunflow.core.parameter.geometry.SphereFlakeParameter; +import org.sunflow.core.parameter.geometry.TeapotParameter; +import org.sunflow.core.parameter.gi.GlobalIlluminationParameter; +import org.sunflow.core.parameter.gi.PathTracingGIParameter; +import org.sunflow.core.parameter.light.SunSkyLightParameter; +import org.sunflow.core.parameter.modifier.BumpMapModifierParameter; +import org.sunflow.core.parameter.modifier.NormalMapModifierParameter; +import org.sunflow.core.parameter.shader.DiffuseShaderParameter; +import org.sunflow.core.parameter.shader.GlassShaderParameter; +import org.sunflow.core.parameter.shader.PhongShaderParameter; +import org.sunflow.core.parameter.shader.ShinyShaderParameter; +import org.sunflow.image.Color; +import org.sunflow.math.Matrix4; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class SphereFlakeScene { + + public static void main(String[] args) { + SunflowAPI api = new SunflowAPI(); + api.reset(); + + ImageParameter image = new ImageParameter(); + image.setResolutionX(1920); + image.setResolutionY(1080); + image.setAAMin(4); + image.setAAMax(4); + image.setAASamples(4); + image.setFilter(ImageParameter.FILTER_GAUSSIAN); + image.setup(api); + + TraceDepthsParameter traceDepths = new TraceDepthsParameter(); + traceDepths.setDiffuse(1); + traceDepths.setReflection(1); + traceDepths.setRefraction(0); + traceDepths.setup(api); + + ThinLensCameraParameter camera = new ThinLensCameraParameter(); + + camera.setName("camera"); + + Point3 eye = new Point3(-5, 0, -0.9f); + Point3 target = new Point3(0, 0, 0.2f); + Vector3 up = new Vector3(0, 0, 1); + + camera.setupTransform(api, eye, target, up); + + camera.setFov(60f); + camera.setAspect(1.777777777777f); + camera.setFocusDistance(5); + camera.setLensRadius(0.01f); + camera.setup(api); + + PathTracingGIParameter gi = new PathTracingGIParameter(); + gi.setSamples(16); + gi.setup(api); + + DiffuseShaderParameter simple1 = new DiffuseShaderParameter("simple1"); + simple1.setDiffuse(new Color(0.5f, 0.5f, 0.5f)); + simple1.setup(api); + + GlassShaderParameter glassy = new GlassShaderParameter("glassy"); + glassy.setEta(1.333f); + glassy.setColor(new Color(0.8f, 0.8f, 0.8f)); + glassy.setAbsorptionDistance(15); + glassy.setAbsorptionColor(new Color(0.2f, 0.7f, 0.2f).toNonLinear()); + glassy.setup(api); + + SunSkyLightParameter lightParameter = new SunSkyLightParameter(); + lightParameter.setName("sunsky"); + lightParameter.setUp(new Vector3(0, 0, 1)); + lightParameter.setEast(new Vector3(0, 1, 0)); + lightParameter.setSunDirection(new Vector3(-1, 1, 0.2f)); + lightParameter.setTurbidity(2); + lightParameter.setSamples(32); + lightParameter.setup(api); + + PhongShaderParameter metal = new PhongShaderParameter("metal"); + metal.setDiffuse(new Color(0.1f,0.1f,0.1f)); + metal.setSpecular(new Color(0.1f,0.1f,0.1f)); + metal.setSamples(4); + metal.setup(api); + + SphereFlakeParameter sphereFlakeParameter = new SphereFlakeParameter("flake"); + sphereFlakeParameter.setInstanceParameter(new InstanceParameter().shaders("metal")); + sphereFlakeParameter.setLevel(7); + sphereFlakeParameter.setup(api); + + PlaneParameter planeParameter = new PlaneParameter(); + planeParameter.shaders(simple1); + planeParameter.setCenter(new Point3(0,0,-1)); + planeParameter.setNormal(new Vector3(0,0,1)); + planeParameter.setup(api); + + finalRender(api); + } + + private static void previewRender(SunflowAPI api) { + api.parameter("sampler", "ipr"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + + private static void finalRender(SunflowAPI api) { + api.parameter("sampler", "bucket"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + +} diff --git a/src/main/java/examples/WireframeDemoScene.java b/src/main/java/examples/WireframeDemoScene.java new file mode 100644 index 0000000..a17d664 --- /dev/null +++ b/src/main/java/examples/WireframeDemoScene.java @@ -0,0 +1,60 @@ +package examples; + +import org.sunflow.PluginRegistry; +import org.sunflow.SunflowAPI; +import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.shader.WireframeShader; +import org.sunflow.image.Color; + +public class WireframeDemoScene { + + public static void main(String[] args) { + SunflowAPI api = new SunflowAPI(); + api.reset(); + + // Loading a custom procedural shader + PluginRegistry.shaderPlugins.registerPlugin("custom_wireframe", CustomWireShader.class); + api.parameter("width", (float) (Math.PI * 0.5 / 8192)); + api.shader("ao_wire", "custom_wireframe"); + + // Including a scene + GumboAndTeapotScene.buildScene(api); + + // Overriding existent shaders + api.parameter("override.shader", "ao_wire"); + api.parameter("override.photons", true); + + ImageParameter image = new ImageParameter(); + image.setResolutionX(320); + image.setResolutionY(240); + image.setAAMin(2); + image.setAAMax(2); + image.setFilter(ImageParameter.FILTER_BLACKMAN_HARRIS); + image.setup(api); + + finalRender(api); + } + + private static void previewRender(SunflowAPI api) { + api.parameter("sampler", "ipr"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + + private static void finalRender(SunflowAPI api) { + api.parameter("sampler", "bucket"); + api.options(SunflowAPI.DEFAULT_OPTIONS); + api.render(SunflowAPI.DEFAULT_OPTIONS, null); + } + + public static class CustomWireShader extends WireframeShader { + // set to false to overlay wires on regular shaders + private boolean ambocc = true; + + public Color getFillColor(ShadingState state) { + return ambocc ? state.occlusion(16, 6.0f) : state.getShader().getRadiance(state); + } + } + +} diff --git a/src/org/sunflow/AsciiFileSunflowAPI.java b/src/main/java/org/sunflow/AsciiFileSunflowAPI.java similarity index 100% rename from src/org/sunflow/AsciiFileSunflowAPI.java rename to src/main/java/org/sunflow/AsciiFileSunflowAPI.java diff --git a/src/org/sunflow/Benchmark.java b/src/main/java/org/sunflow/Benchmark.java similarity index 91% rename from src/org/sunflow/Benchmark.java rename to src/main/java/org/sunflow/Benchmark.java index 956c5b5..070e0d5 100644 --- a/src/org/sunflow/Benchmark.java +++ b/src/main/java/org/sunflow/Benchmark.java @@ -6,6 +6,9 @@ import javax.imageio.ImageIO; +import org.sunflow.core.parameter.BucketParameter; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.TraceDepthsParameter; import org.sunflow.core.Display; import org.sunflow.core.display.FileDisplay; import org.sunflow.core.display.FrameDisplay; @@ -116,16 +119,16 @@ public void build() { parameter("threads", threads); // spawn regular priority threads parameter("threads.lowPriority", false); - parameter("resolutionX", resolution); - parameter("resolutionY", resolution); - parameter("aa.min", -1); - parameter("aa.max", 1); - parameter("filter", "triangle"); - parameter("depths.diffuse", 2); - parameter("depths.reflection", 2); - parameter("depths.refraction", 2); - parameter("bucket.order", "hilbert"); - parameter("bucket.size", 32); + parameter(ImageParameter.PARAM_RESOLUTION_X, resolution); + parameter(ImageParameter.PARAM_RESOLUTION_Y, resolution); + parameter(ImageParameter.PARAM_AA_MIN, -1); + parameter(ImageParameter.PARAM_AA_MAX, 1); + parameter(ImageParameter.PARAM_FILTER, ImageParameter.FILTER_TRIANGLE); + parameter(TraceDepthsParameter.PARAM_DEPTHS_DIFFUSE, 2); + parameter(TraceDepthsParameter.PARAM_DEPTHS_REFLECTION, 2); + parameter(TraceDepthsParameter.PARAM_DEPTHS_REFRACTION, 2); + parameter(BucketParameter.PARAM_BUCKET_ORDER, BucketParameter.ORDER_HILBERT); + parameter(BucketParameter.PARAM_BUCKET_SIZE, 32); // gi options parameter("gi.engine", "igi"); parameter("gi.igi.samples", 90); diff --git a/src/org/sunflow/BinaryFileSunflowAPI.java b/src/main/java/org/sunflow/BinaryFileSunflowAPI.java similarity index 100% rename from src/org/sunflow/BinaryFileSunflowAPI.java rename to src/main/java/org/sunflow/BinaryFileSunflowAPI.java diff --git a/src/org/sunflow/FileSunflowAPI.java b/src/main/java/org/sunflow/FileSunflowAPI.java similarity index 100% rename from src/org/sunflow/FileSunflowAPI.java rename to src/main/java/org/sunflow/FileSunflowAPI.java diff --git a/src/org/sunflow/PluginRegistry.java b/src/main/java/org/sunflow/PluginRegistry.java similarity index 89% rename from src/org/sunflow/PluginRegistry.java rename to src/main/java/org/sunflow/PluginRegistry.java index def4853..88bad8b 100644 --- a/src/org/sunflow/PluginRegistry.java +++ b/src/main/java/org/sunflow/PluginRegistry.java @@ -51,6 +51,9 @@ import org.sunflow.core.modifiers.BumpMappingModifier; import org.sunflow.core.modifiers.NormalMapModifier; import org.sunflow.core.modifiers.PerlinModifier; +import org.sunflow.core.parameter.BucketParameter; +import org.sunflow.core.parameter.camera.CameraParameter; +import org.sunflow.core.parameter.modifier.ModifierParameter; import org.sunflow.core.parser.RA2Parser; import org.sunflow.core.parser.RA3Parser; import org.sunflow.core.parser.SCAsciiParser; @@ -204,13 +207,16 @@ public final class PluginRegistry { shaderPlugins.registerPlugin("view_caustics", ViewCausticsShader.class); shaderPlugins.registerPlugin("view_global", ViewGlobalPhotonsShader.class); shaderPlugins.registerPlugin("view_irradiance", ViewIrradianceShader.class); + + // light shaders + shaderPlugins.registerPlugin("triangle_mesh_light", TriangleMeshLight.class); } static { // modifiers - modifierPlugins.registerPlugin("bump_map", BumpMappingModifier.class); - modifierPlugins.registerPlugin("normal_map", NormalMapModifier.class); - modifierPlugins.registerPlugin("perlin", PerlinModifier.class); + modifierPlugins.registerPlugin(ModifierParameter.TYPE_BUMP_MAP, BumpMappingModifier.class); + modifierPlugins.registerPlugin(ModifierParameter.TYPE_NORMAL_MAP, NormalMapModifier.class); + modifierPlugins.registerPlugin(ModifierParameter.TYPE_PERLIN, PerlinModifier.class); } static { @@ -226,10 +232,10 @@ public final class PluginRegistry { static { // camera lenses - cameraLensPlugins.registerPlugin("pinhole", PinholeLens.class); - cameraLensPlugins.registerPlugin("thinlens", ThinLens.class); - cameraLensPlugins.registerPlugin("fisheye", FisheyeLens.class); - cameraLensPlugins.registerPlugin("spherical", SphericalLens.class); + cameraLensPlugins.registerPlugin(CameraParameter.TYPE_PINHOLE, PinholeLens.class); + cameraLensPlugins.registerPlugin(CameraParameter.TYPE_THINLENS, ThinLens.class); + cameraLensPlugins.registerPlugin(CameraParameter.TYPE_FISH_EYE, FisheyeLens.class); + cameraLensPlugins.registerPlugin(CameraParameter.TYPE_SPHERICAL, SphericalLens.class); } static { @@ -242,12 +248,12 @@ public final class PluginRegistry { static { // bucket orders - bucketOrderPlugins.registerPlugin("column", ColumnBucketOrder.class); - bucketOrderPlugins.registerPlugin("diagonal", DiagonalBucketOrder.class); - bucketOrderPlugins.registerPlugin("hilbert", HilbertBucketOrder.class); - bucketOrderPlugins.registerPlugin("random", RandomBucketOrder.class); - bucketOrderPlugins.registerPlugin("row", RowBucketOrder.class); - bucketOrderPlugins.registerPlugin("spiral", SpiralBucketOrder.class); + bucketOrderPlugins.registerPlugin(BucketParameter.ORDER_COLUMN, ColumnBucketOrder.class); + bucketOrderPlugins.registerPlugin(BucketParameter.ORDER_DIAGONAL, DiagonalBucketOrder.class); + bucketOrderPlugins.registerPlugin(BucketParameter.ORDER_HILBERT, HilbertBucketOrder.class); + bucketOrderPlugins.registerPlugin(BucketParameter.ORDER_RANDOM, RandomBucketOrder.class); + bucketOrderPlugins.registerPlugin(BucketParameter.ORDER_ROW, RowBucketOrder.class); + bucketOrderPlugins.registerPlugin(BucketParameter.ORDER_SPIRAL, SpiralBucketOrder.class); } static { diff --git a/src/org/sunflow/RealtimeBenchmark.java b/src/main/java/org/sunflow/RealtimeBenchmark.java similarity index 83% rename from src/org/sunflow/RealtimeBenchmark.java rename to src/main/java/org/sunflow/RealtimeBenchmark.java index af20648..966b118 100644 --- a/src/org/sunflow/RealtimeBenchmark.java +++ b/src/main/java/org/sunflow/RealtimeBenchmark.java @@ -1,5 +1,8 @@ package org.sunflow; +import org.sunflow.core.parameter.BucketParameter; +import org.sunflow.core.parameter.ImageParameter; +import org.sunflow.core.parameter.TraceDepthsParameter; import org.sunflow.core.Display; import org.sunflow.core.display.FastDisplay; import org.sunflow.core.display.FileDisplay; @@ -19,15 +22,15 @@ public RealtimeBenchmark(boolean showGUI, int threads) { parameter("threads", threads); // spawn regular priority threads parameter("threads.lowPriority", false); - parameter("resolutionX", 512); - parameter("resolutionY", 512); - parameter("aa.min", -3); - parameter("aa.max", 0); - parameter("depths.diffuse", 1); - parameter("depths.reflection", 1); - parameter("depths.refraction", 0); - parameter("bucket.order", "hilbert"); - parameter("bucket.size", 32); + parameter(ImageParameter.PARAM_RESOLUTION_X, 512); + parameter(ImageParameter.PARAM_RESOLUTION_Y, 512); + parameter(ImageParameter.PARAM_AA_MIN, -3); + parameter(ImageParameter.PARAM_AA_MAX, 0); + parameter(TraceDepthsParameter.PARAM_DEPTHS_DIFFUSE, 1); + parameter(TraceDepthsParameter.PARAM_DEPTHS_REFLECTION, 1); + parameter(TraceDepthsParameter.PARAM_DEPTHS_REFRACTION, 0); + parameter(BucketParameter.PARAM_BUCKET_ORDER, BucketParameter.ORDER_HILBERT); + parameter(BucketParameter.PARAM_BUCKET_SIZE, 32); options(SunflowAPI.DEFAULT_OPTIONS); // camera Point3 eye = new Point3(30, 0, 10.967f); diff --git a/src/org/sunflow/RenderObjectMap.java b/src/main/java/org/sunflow/RenderObjectMap.java similarity index 94% rename from src/org/sunflow/RenderObjectMap.java rename to src/main/java/org/sunflow/RenderObjectMap.java index fa49cd2..83acb36 100644 --- a/src/org/sunflow/RenderObjectMap.java +++ b/src/main/java/org/sunflow/RenderObjectMap.java @@ -19,7 +19,7 @@ import org.sunflow.system.UI.Module; import org.sunflow.util.FastHashMap; -final class RenderObjectMap { +public final class RenderObjectMap { private FastHashMap renderObjects; private boolean rebuildInstanceList; private boolean rebuildLightList; @@ -33,10 +33,14 @@ private enum RenderObjectType { rebuildInstanceList = rebuildLightList = false; } - final boolean has(String name) { + public final boolean has(String name) { return renderObjects.containsKey(name); } + public final RenderObjectHandle get(String name) { + return renderObjects.get(name); + } + final void remove(String name) { RenderObjectHandle obj = renderObjects.get(name); if (obj == null) { @@ -249,8 +253,8 @@ final LightSource lookupLight(String name) { return (handle == null) ? null : handle.getLight(); } - private static final class RenderObjectHandle { - private final RenderObject obj; + public static final class RenderObjectHandle { + public final RenderObject obj; private final RenderObjectType type; private RenderObjectHandle(Shader shader) { diff --git a/src/org/sunflow/SunflowAPI.java b/src/main/java/org/sunflow/SunflowAPI.java similarity index 88% rename from src/org/sunflow/SunflowAPI.java rename to src/main/java/org/sunflow/SunflowAPI.java index 49ea83a..65ebf34 100644 --- a/src/org/sunflow/SunflowAPI.java +++ b/src/main/java/org/sunflow/SunflowAPI.java @@ -6,11 +6,10 @@ import java.io.StringReader; import java.util.Locale; +import org.codehaus.commons.compiler.CompileException; import org.codehaus.janino.ClassBodyEvaluator; -import org.codehaus.janino.CompileException; import org.codehaus.janino.Scanner; -import org.codehaus.janino.Parser.ParseException; -import org.codehaus.janino.Scanner.ScanException; +import org.sunflow.core.parameter.shader.ShaderParameter; import org.sunflow.core.Camera; import org.sunflow.core.CameraLens; import org.sunflow.core.Display; @@ -47,34 +46,15 @@ * scene. */ public class SunflowAPI implements SunflowAPIInterface { - public static final String VERSION = "0.07.3"; + public static final String VERSION = "0.07.5"; public static final String DEFAULT_OPTIONS = "::options"; - private Scene scene; - private SearchPath includeSearchPath; - private SearchPath textureSearchPath; - private ParameterList parameterList; - private RenderObjectMap renderObjects; - private int currentFrame; - - /** - * This is a quick system test which verifies that the user has launched - * Java properly. - */ - public static void runSystemCheck() { - final long RECOMMENDED_MAX_SIZE = 800; - long maxMb = Runtime.getRuntime().maxMemory() / 1048576; - if (maxMb < RECOMMENDED_MAX_SIZE) - UI.printError(Module.API, "JVM available memory is below %d MB (found %d MB only).\nPlease make sure you launched the program with the -Xmx command line options.", RECOMMENDED_MAX_SIZE, maxMb); - String compiler = System.getProperty("java.vm.name"); - if (compiler == null || !(compiler.contains("HotSpot") && compiler.contains("Server"))) - UI.printError(Module.API, "You do not appear to be running Sun's server JVM\nPerformance may suffer"); - UI.printDetailed(Module.API, "Java environment settings:"); - UI.printDetailed(Module.API, " * Max memory available : %d MB", maxMb); - UI.printDetailed(Module.API, " * Virtual machine name : %s", compiler == null ? " 2000000) name = "bih"; - else if (n > 2) + else if (n > 1) name = "kdtree"; else name = "null"; } else { - if (n > 2) + if (n > 1) name = "bih"; else name = "null"; diff --git a/src/org/sunflow/core/BucketOrder.java b/src/main/java/org/sunflow/core/BucketOrder.java similarity index 100% rename from src/org/sunflow/core/BucketOrder.java rename to src/main/java/org/sunflow/core/BucketOrder.java diff --git a/src/org/sunflow/core/Camera.java b/src/main/java/org/sunflow/core/Camera.java similarity index 85% rename from src/org/sunflow/core/Camera.java rename to src/main/java/org/sunflow/core/Camera.java index 512ac74..2d22c59 100644 --- a/src/org/sunflow/core/Camera.java +++ b/src/main/java/org/sunflow/core/Camera.java @@ -1,6 +1,7 @@ package org.sunflow.core; import org.sunflow.SunflowAPI; +import org.sunflow.core.parameter.camera.CameraParameter; import org.sunflow.math.Matrix4; import org.sunflow.math.MovingMatrix4; import org.sunflow.math.Point3; @@ -27,8 +28,8 @@ public Camera(CameraLens lens) { } public boolean update(ParameterList pl, SunflowAPI api) { - shutterOpen = pl.getFloat("shutter.open", shutterOpen); - shutterClose = pl.getFloat("shutter.close", shutterClose); + shutterOpen = pl.getFloat(CameraParameter.PARAM_SHUTTER_OPEN, shutterOpen); + shutterClose = pl.getFloat(CameraParameter.PARAM_SHUTTER_CLOSE, shutterClose); c2w = pl.getMovingMatrix("transform", c2w); w2c = c2w.inverse(); if (w2c == null) { @@ -117,4 +118,20 @@ Matrix4 getCameraToWorld(float time) { Matrix4 getWorldToCamera(float time) { return w2c == null ? Matrix4.IDENTITY : w2c.sample(time); } + + public float getShutterOpen() { + return shutterOpen; + } + + public void setShutterOpen(float shutterOpen) { + this.shutterOpen = shutterOpen; + } + + public float getShutterClose() { + return shutterClose; + } + + public void setShutterClose(float shutterClose) { + this.shutterClose = shutterClose; + } } \ No newline at end of file diff --git a/src/org/sunflow/core/CameraLens.java b/src/main/java/org/sunflow/core/CameraLens.java similarity index 100% rename from src/org/sunflow/core/CameraLens.java rename to src/main/java/org/sunflow/core/CameraLens.java diff --git a/src/org/sunflow/core/CausticPhotonMapInterface.java b/src/main/java/org/sunflow/core/CausticPhotonMapInterface.java similarity index 100% rename from src/org/sunflow/core/CausticPhotonMapInterface.java rename to src/main/java/org/sunflow/core/CausticPhotonMapInterface.java diff --git a/src/org/sunflow/core/Display.java b/src/main/java/org/sunflow/core/Display.java similarity index 100% rename from src/org/sunflow/core/Display.java rename to src/main/java/org/sunflow/core/Display.java diff --git a/src/org/sunflow/core/Filter.java b/src/main/java/org/sunflow/core/Filter.java similarity index 100% rename from src/org/sunflow/core/Filter.java rename to src/main/java/org/sunflow/core/Filter.java diff --git a/src/org/sunflow/core/GIEngine.java b/src/main/java/org/sunflow/core/GIEngine.java similarity index 100% rename from src/org/sunflow/core/GIEngine.java rename to src/main/java/org/sunflow/core/GIEngine.java diff --git a/src/org/sunflow/core/Geometry.java b/src/main/java/org/sunflow/core/Geometry.java similarity index 100% rename from src/org/sunflow/core/Geometry.java rename to src/main/java/org/sunflow/core/Geometry.java diff --git a/src/org/sunflow/core/GlobalPhotonMapInterface.java b/src/main/java/org/sunflow/core/GlobalPhotonMapInterface.java similarity index 100% rename from src/org/sunflow/core/GlobalPhotonMapInterface.java rename to src/main/java/org/sunflow/core/GlobalPhotonMapInterface.java diff --git a/src/org/sunflow/core/ImageSampler.java b/src/main/java/org/sunflow/core/ImageSampler.java similarity index 100% rename from src/org/sunflow/core/ImageSampler.java rename to src/main/java/org/sunflow/core/ImageSampler.java diff --git a/src/org/sunflow/core/Instance.java b/src/main/java/org/sunflow/core/Instance.java similarity index 100% rename from src/org/sunflow/core/Instance.java rename to src/main/java/org/sunflow/core/Instance.java diff --git a/src/org/sunflow/core/InstanceList.java b/src/main/java/org/sunflow/core/InstanceList.java similarity index 100% rename from src/org/sunflow/core/InstanceList.java rename to src/main/java/org/sunflow/core/InstanceList.java diff --git a/src/org/sunflow/core/IntersectionState.java b/src/main/java/org/sunflow/core/IntersectionState.java similarity index 100% rename from src/org/sunflow/core/IntersectionState.java rename to src/main/java/org/sunflow/core/IntersectionState.java diff --git a/src/org/sunflow/core/LightSample.java b/src/main/java/org/sunflow/core/LightSample.java similarity index 100% rename from src/org/sunflow/core/LightSample.java rename to src/main/java/org/sunflow/core/LightSample.java diff --git a/src/org/sunflow/core/LightServer.java b/src/main/java/org/sunflow/core/LightServer.java similarity index 100% rename from src/org/sunflow/core/LightServer.java rename to src/main/java/org/sunflow/core/LightServer.java diff --git a/src/org/sunflow/core/LightSource.java b/src/main/java/org/sunflow/core/LightSource.java similarity index 100% rename from src/org/sunflow/core/LightSource.java rename to src/main/java/org/sunflow/core/LightSource.java diff --git a/src/org/sunflow/core/Modifier.java b/src/main/java/org/sunflow/core/Modifier.java similarity index 100% rename from src/org/sunflow/core/Modifier.java rename to src/main/java/org/sunflow/core/Modifier.java diff --git a/src/org/sunflow/core/Options.java b/src/main/java/org/sunflow/core/Options.java similarity index 100% rename from src/org/sunflow/core/Options.java rename to src/main/java/org/sunflow/core/Options.java diff --git a/src/org/sunflow/core/ParameterList.java b/src/main/java/org/sunflow/core/ParameterList.java similarity index 96% rename from src/org/sunflow/core/ParameterList.java rename to src/main/java/org/sunflow/core/ParameterList.java index e824f6f..5eded98 100644 --- a/src/org/sunflow/core/ParameterList.java +++ b/src/main/java/org/sunflow/core/ParameterList.java @@ -18,6 +18,10 @@ * named variables as a unified way of getting data into user objects. */ public class ParameterList { + + public static final String PARAM_COLOR = "color"; + public static final String PARAM_SHADERS = "shaders"; + protected final FastHashMap list; private int numVerts, numFaces, numFaceVerts; diff --git a/src/org/sunflow/core/PhotonStore.java b/src/main/java/org/sunflow/core/PhotonStore.java similarity index 100% rename from src/org/sunflow/core/PhotonStore.java rename to src/main/java/org/sunflow/core/PhotonStore.java diff --git a/src/org/sunflow/core/PrimitiveList.java b/src/main/java/org/sunflow/core/PrimitiveList.java similarity index 100% rename from src/org/sunflow/core/PrimitiveList.java rename to src/main/java/org/sunflow/core/PrimitiveList.java diff --git a/src/org/sunflow/core/Ray.java b/src/main/java/org/sunflow/core/Ray.java similarity index 100% rename from src/org/sunflow/core/Ray.java rename to src/main/java/org/sunflow/core/Ray.java diff --git a/src/org/sunflow/core/RenderObject.java b/src/main/java/org/sunflow/core/RenderObject.java similarity index 100% rename from src/org/sunflow/core/RenderObject.java rename to src/main/java/org/sunflow/core/RenderObject.java diff --git a/src/org/sunflow/core/Scene.java b/src/main/java/org/sunflow/core/Scene.java similarity index 96% rename from src/org/sunflow/core/Scene.java rename to src/main/java/org/sunflow/core/Scene.java index 97b2cae..a413f7c 100644 --- a/src/org/sunflow/core/Scene.java +++ b/src/main/java/org/sunflow/core/Scene.java @@ -313,6 +313,9 @@ public void render(Options options, ImageSampler sampler, Display display) { // prepare lights createAreaLightInstances(); + // prepare ShadingState + ShadingState.init(options); + // get acceleration structure info // count scene primitives long numPrimitives = 0; diff --git a/src/org/sunflow/core/SceneParser.java b/src/main/java/org/sunflow/core/SceneParser.java similarity index 100% rename from src/org/sunflow/core/SceneParser.java rename to src/main/java/org/sunflow/core/SceneParser.java diff --git a/src/org/sunflow/core/Shader.java b/src/main/java/org/sunflow/core/Shader.java similarity index 100% rename from src/org/sunflow/core/Shader.java rename to src/main/java/org/sunflow/core/Shader.java diff --git a/src/org/sunflow/core/ShadingCache.java b/src/main/java/org/sunflow/core/ShadingCache.java similarity index 66% rename from src/org/sunflow/core/ShadingCache.java rename to src/main/java/org/sunflow/core/ShadingCache.java index c7e9faa..d1dd148 100644 --- a/src/org/sunflow/core/ShadingCache.java +++ b/src/main/java/org/sunflow/core/ShadingCache.java @@ -2,8 +2,10 @@ import org.sunflow.image.Color; +import java.util.Arrays; + public class ShadingCache { - private Sample first; + private final Sample[] samples = new Sample[256]; private int depth; // stats long hits; @@ -11,26 +13,29 @@ public class ShadingCache { long sumDepth; long numCaches; + private final float dirTolerance, normalTolerance; + private static class Sample { Instance i; Shader s; float nx, ny, nz; float dx, dy, dz; Color c; - Sample next; // linked list } - public ShadingCache() { + public ShadingCache(float dirTolerance, float normalTolerance) { reset(); hits = 0; misses = 0; + this.dirTolerance = dirTolerance; + this.normalTolerance = normalTolerance; } public void reset() { sumDepth += depth; if (depth > 0) numCaches++; - first = null; + Arrays.fill(samples, null); depth = 0; } @@ -38,14 +43,15 @@ public Color lookup(ShadingState state, Shader shader) { if (state.getNormal() == null) return null; // search further - for (Sample s = first; s != null; s = s.next) { + for (int i = 0; i < depth; i++) { + Sample s = samples[i]; if (s.i != state.getInstance()) continue; if (s.s != shader) continue; - if (state.getRay().dot(s.dx, s.dy, s.dz) < 0.999f) + if (state.getRay().dot(s.dx, s.dy, s.dz) < 1 - dirTolerance) continue; - if (state.getNormal().dot(s.nx, s.ny, s.nz) < 0.99f) + if (state.getNormal().dot(s.nx, s.ny, s.nz) < 1 - normalTolerance) continue; // we have a match hits++; @@ -56,9 +62,8 @@ public Color lookup(ShadingState state, Shader shader) { } public void add(ShadingState state, Shader shader, Color c) { - if (state.getNormal() == null) + if (state.getNormal() == null || depth >= samples.length) return; - depth++; Sample s = new Sample(); s.i = state.getInstance(); s.s = shader; @@ -69,7 +74,7 @@ public void add(ShadingState state, Shader shader, Color c) { s.nx = state.getNormal().x; s.ny = state.getNormal().y; s.nz = state.getNormal().z; - s.next = first; - first = s; + samples[depth] = s; + depth++; } } \ No newline at end of file diff --git a/src/org/sunflow/core/ShadingState.java b/src/main/java/org/sunflow/core/ShadingState.java similarity index 96% rename from src/org/sunflow/core/ShadingState.java rename to src/main/java/org/sunflow/core/ShadingState.java index d4d3613..0a319ea 100644 --- a/src/org/sunflow/core/ShadingState.java +++ b/src/main/java/org/sunflow/core/ShadingState.java @@ -47,6 +47,12 @@ public final class ShadingState implements Iterable { private LightSample lightSample; private PhotonStore map; + private static float minBias = 0.001f; + + public static void init(Options options) { + minBias = options.getFloat("bias", 0.001f); + } + static ShadingState createPhotonState(Ray r, IntersectionState istate, int i, PhotonStore map, LightServer server) { ShadingState s = new ShadingState(null, istate, r, i, 4); s.server = server; @@ -134,7 +140,7 @@ private ShadingState(ShadingState previous, IntersectionState istate, Ray r, int qmcD0I = QMC.halton(this.d, this.i); qmcD1I = QMC.halton(this.d + 1, this.i); result = null; - bias = 0.001f; + bias = minBias; } final void setRay(Ray r) { diff --git a/src/org/sunflow/core/Statistics.java b/src/main/java/org/sunflow/core/Statistics.java similarity index 100% rename from src/org/sunflow/core/Statistics.java rename to src/main/java/org/sunflow/core/Statistics.java diff --git a/src/org/sunflow/core/Tesselatable.java b/src/main/java/org/sunflow/core/Tesselatable.java similarity index 100% rename from src/org/sunflow/core/Tesselatable.java rename to src/main/java/org/sunflow/core/Tesselatable.java diff --git a/src/org/sunflow/core/Texture.java b/src/main/java/org/sunflow/core/Texture.java similarity index 100% rename from src/org/sunflow/core/Texture.java rename to src/main/java/org/sunflow/core/Texture.java diff --git a/src/org/sunflow/core/TextureCache.java b/src/main/java/org/sunflow/core/TextureCache.java similarity index 100% rename from src/org/sunflow/core/TextureCache.java rename to src/main/java/org/sunflow/core/TextureCache.java diff --git a/src/org/sunflow/core/accel/BoundingIntervalHierarchy.java b/src/main/java/org/sunflow/core/accel/BoundingIntervalHierarchy.java similarity index 97% rename from src/org/sunflow/core/accel/BoundingIntervalHierarchy.java rename to src/main/java/org/sunflow/core/accel/BoundingIntervalHierarchy.java index 6335006..b05cd9e 100644 --- a/src/org/sunflow/core/accel/BoundingIntervalHierarchy.java +++ b/src/main/java/org/sunflow/core/accel/BoundingIntervalHierarchy.java @@ -256,7 +256,7 @@ else if (d[1] > d[2]) // ensure we are making progress in the subdivision if (right == rightOrig) { // all left - if (clipL <= split) { + if (clipL <= split && gridBox[2 * axis + 1] != split) { // keep looping on left half gridBox[2 * axis + 1] = split; prevClip = clipL; @@ -274,7 +274,7 @@ else if (d[1] > d[2]) } else if (left > right) { // all right right = rightOrig; - if (clipR >= split) { + if (clipR >= split && gridBox[2 * axis + 0] != split) { // keep looping on right half gridBox[2 * axis + 0] = split; prevClip = clipR; diff --git a/src/org/sunflow/core/accel/KDTree.java b/src/main/java/org/sunflow/core/accel/KDTree.java similarity index 100% rename from src/org/sunflow/core/accel/KDTree.java rename to src/main/java/org/sunflow/core/accel/KDTree.java diff --git a/src/org/sunflow/core/accel/NullAccelerator.java b/src/main/java/org/sunflow/core/accel/NullAccelerator.java similarity index 100% rename from src/org/sunflow/core/accel/NullAccelerator.java rename to src/main/java/org/sunflow/core/accel/NullAccelerator.java diff --git a/src/org/sunflow/core/accel/UniformGrid.java b/src/main/java/org/sunflow/core/accel/UniformGrid.java similarity index 100% rename from src/org/sunflow/core/accel/UniformGrid.java rename to src/main/java/org/sunflow/core/accel/UniformGrid.java diff --git a/src/org/sunflow/core/bucket/BucketOrderFactory.java b/src/main/java/org/sunflow/core/bucket/BucketOrderFactory.java similarity index 100% rename from src/org/sunflow/core/bucket/BucketOrderFactory.java rename to src/main/java/org/sunflow/core/bucket/BucketOrderFactory.java diff --git a/src/org/sunflow/core/bucket/ColumnBucketOrder.java b/src/main/java/org/sunflow/core/bucket/ColumnBucketOrder.java similarity index 100% rename from src/org/sunflow/core/bucket/ColumnBucketOrder.java rename to src/main/java/org/sunflow/core/bucket/ColumnBucketOrder.java diff --git a/src/org/sunflow/core/bucket/DiagonalBucketOrder.java b/src/main/java/org/sunflow/core/bucket/DiagonalBucketOrder.java similarity index 100% rename from src/org/sunflow/core/bucket/DiagonalBucketOrder.java rename to src/main/java/org/sunflow/core/bucket/DiagonalBucketOrder.java diff --git a/src/org/sunflow/core/bucket/HilbertBucketOrder.java b/src/main/java/org/sunflow/core/bucket/HilbertBucketOrder.java similarity index 100% rename from src/org/sunflow/core/bucket/HilbertBucketOrder.java rename to src/main/java/org/sunflow/core/bucket/HilbertBucketOrder.java diff --git a/src/org/sunflow/core/bucket/InvertedBucketOrder.java b/src/main/java/org/sunflow/core/bucket/InvertedBucketOrder.java similarity index 100% rename from src/org/sunflow/core/bucket/InvertedBucketOrder.java rename to src/main/java/org/sunflow/core/bucket/InvertedBucketOrder.java diff --git a/src/org/sunflow/core/bucket/RandomBucketOrder.java b/src/main/java/org/sunflow/core/bucket/RandomBucketOrder.java similarity index 100% rename from src/org/sunflow/core/bucket/RandomBucketOrder.java rename to src/main/java/org/sunflow/core/bucket/RandomBucketOrder.java diff --git a/src/org/sunflow/core/bucket/RowBucketOrder.java b/src/main/java/org/sunflow/core/bucket/RowBucketOrder.java similarity index 100% rename from src/org/sunflow/core/bucket/RowBucketOrder.java rename to src/main/java/org/sunflow/core/bucket/RowBucketOrder.java diff --git a/src/org/sunflow/core/bucket/SpiralBucketOrder.java b/src/main/java/org/sunflow/core/bucket/SpiralBucketOrder.java similarity index 100% rename from src/org/sunflow/core/bucket/SpiralBucketOrder.java rename to src/main/java/org/sunflow/core/bucket/SpiralBucketOrder.java diff --git a/src/org/sunflow/core/camera/FisheyeLens.java b/src/main/java/org/sunflow/core/camera/FisheyeLens.java similarity index 100% rename from src/org/sunflow/core/camera/FisheyeLens.java rename to src/main/java/org/sunflow/core/camera/FisheyeLens.java diff --git a/src/org/sunflow/core/camera/PinholeLens.java b/src/main/java/org/sunflow/core/camera/PinholeLens.java similarity index 65% rename from src/org/sunflow/core/camera/PinholeLens.java rename to src/main/java/org/sunflow/core/camera/PinholeLens.java index 0a9b86e..092c0dd 100644 --- a/src/org/sunflow/core/camera/PinholeLens.java +++ b/src/main/java/org/sunflow/core/camera/PinholeLens.java @@ -37,4 +37,36 @@ public Ray getRay(float x, float y, int imageWidth, int imageHeight, double lens float dv = shiftY - av + ((2.0f * av * y) / (imageHeight - 1.0f)); return new Ray(0, 0, 0, du, dv, -1); } + + public float getAspect() { + return aspect; + } + + public void setAspect(float aspect) { + this.aspect = aspect; + } + + public float getFov() { + return fov; + } + + public void setFov(float fov) { + this.fov = fov; + } + + public float getShiftX() { + return shiftX; + } + + public void setShiftX(float shiftX) { + this.shiftX = shiftX; + } + + public float getShiftY() { + return shiftY; + } + + public void setShiftY(float shiftY) { + this.shiftY = shiftY; + } } \ No newline at end of file diff --git a/src/org/sunflow/core/camera/SphericalLens.java b/src/main/java/org/sunflow/core/camera/SphericalLens.java similarity index 100% rename from src/org/sunflow/core/camera/SphericalLens.java rename to src/main/java/org/sunflow/core/camera/SphericalLens.java diff --git a/src/org/sunflow/core/camera/ThinLens.java b/src/main/java/org/sunflow/core/camera/ThinLens.java similarity index 70% rename from src/org/sunflow/core/camera/ThinLens.java rename to src/main/java/org/sunflow/core/camera/ThinLens.java index 092a6e4..6f63fac 100644 --- a/src/org/sunflow/core/camera/ThinLens.java +++ b/src/main/java/org/sunflow/core/camera/ThinLens.java @@ -100,4 +100,76 @@ public Ray getRay(float x, float y, int imageWidth, int imageHeight, double lens // ray return new Ray(eyeX, eyeY, eyeZ, dirX - eyeX, dirY - eyeY, dirZ - eyeZ); } + + public float getAspect() { + return aspect; + } + + public void setAspect(float aspect) { + this.aspect = aspect; + } + + public float getFov() { + return fov; + } + + public void setFov(float fov) { + this.fov = fov; + } + + public float getShiftX() { + return shiftX; + } + + public void setShiftX(float shiftX) { + this.shiftX = shiftX; + } + + public float getShiftY() { + return shiftY; + } + + public void setShiftY(float shiftY) { + this.shiftY = shiftY; + } + + public float getFocusDistance() { + return focusDistance; + } + + public void setFocusDistance(float focusDistance) { + this.focusDistance = focusDistance; + } + + public float getLensRadius() { + return lensRadius; + } + + public void setLensRadius(float lensRadius) { + this.lensRadius = lensRadius; + } + + public int getLensSides() { + return lensSides; + } + + public void setLensSides(int lensSides) { + this.lensSides = lensSides; + } + + public float getLensRotation() { + return lensRotation; + } + + public void setLensRotation(float lensRotation) { + this.lensRotation = lensRotation; + } + + public float getLensRotationRadians() { + return lensRotationRadians; + } + + public void setLensRotationRadians(float lensRotationRadians) { + this.lensRotationRadians = lensRotationRadians; + } } \ No newline at end of file diff --git a/src/org/sunflow/core/display/FastDisplay.java b/src/main/java/org/sunflow/core/display/FastDisplay.java similarity index 100% rename from src/org/sunflow/core/display/FastDisplay.java rename to src/main/java/org/sunflow/core/display/FastDisplay.java diff --git a/src/org/sunflow/core/display/FileDisplay.java b/src/main/java/org/sunflow/core/display/FileDisplay.java similarity index 100% rename from src/org/sunflow/core/display/FileDisplay.java rename to src/main/java/org/sunflow/core/display/FileDisplay.java diff --git a/src/org/sunflow/core/display/FrameDisplay.java b/src/main/java/org/sunflow/core/display/FrameDisplay.java similarity index 100% rename from src/org/sunflow/core/display/FrameDisplay.java rename to src/main/java/org/sunflow/core/display/FrameDisplay.java diff --git a/src/org/sunflow/core/display/ImgPipeDisplay.java b/src/main/java/org/sunflow/core/display/ImgPipeDisplay.java similarity index 100% rename from src/org/sunflow/core/display/ImgPipeDisplay.java rename to src/main/java/org/sunflow/core/display/ImgPipeDisplay.java diff --git a/src/org/sunflow/core/filter/BlackmanHarrisFilter.java b/src/main/java/org/sunflow/core/filter/BlackmanHarrisFilter.java similarity index 100% rename from src/org/sunflow/core/filter/BlackmanHarrisFilter.java rename to src/main/java/org/sunflow/core/filter/BlackmanHarrisFilter.java diff --git a/src/org/sunflow/core/filter/BoxFilter.java b/src/main/java/org/sunflow/core/filter/BoxFilter.java similarity index 100% rename from src/org/sunflow/core/filter/BoxFilter.java rename to src/main/java/org/sunflow/core/filter/BoxFilter.java diff --git a/src/org/sunflow/core/filter/CatmullRomFilter.java b/src/main/java/org/sunflow/core/filter/CatmullRomFilter.java similarity index 100% rename from src/org/sunflow/core/filter/CatmullRomFilter.java rename to src/main/java/org/sunflow/core/filter/CatmullRomFilter.java diff --git a/src/org/sunflow/core/filter/CubicBSpline.java b/src/main/java/org/sunflow/core/filter/CubicBSpline.java similarity index 100% rename from src/org/sunflow/core/filter/CubicBSpline.java rename to src/main/java/org/sunflow/core/filter/CubicBSpline.java diff --git a/src/org/sunflow/core/filter/GaussianFilter.java b/src/main/java/org/sunflow/core/filter/GaussianFilter.java similarity index 100% rename from src/org/sunflow/core/filter/GaussianFilter.java rename to src/main/java/org/sunflow/core/filter/GaussianFilter.java diff --git a/src/org/sunflow/core/filter/LanczosFilter.java b/src/main/java/org/sunflow/core/filter/LanczosFilter.java similarity index 100% rename from src/org/sunflow/core/filter/LanczosFilter.java rename to src/main/java/org/sunflow/core/filter/LanczosFilter.java diff --git a/src/org/sunflow/core/filter/MitchellFilter.java b/src/main/java/org/sunflow/core/filter/MitchellFilter.java similarity index 100% rename from src/org/sunflow/core/filter/MitchellFilter.java rename to src/main/java/org/sunflow/core/filter/MitchellFilter.java diff --git a/src/org/sunflow/core/filter/SincFilter.java b/src/main/java/org/sunflow/core/filter/SincFilter.java similarity index 100% rename from src/org/sunflow/core/filter/SincFilter.java rename to src/main/java/org/sunflow/core/filter/SincFilter.java diff --git a/src/org/sunflow/core/filter/TriangleFilter.java b/src/main/java/org/sunflow/core/filter/TriangleFilter.java similarity index 100% rename from src/org/sunflow/core/filter/TriangleFilter.java rename to src/main/java/org/sunflow/core/filter/TriangleFilter.java diff --git a/src/org/sunflow/core/gi/AmbientOcclusionGIEngine.java b/src/main/java/org/sunflow/core/gi/AmbientOcclusionGIEngine.java similarity index 78% rename from src/org/sunflow/core/gi/AmbientOcclusionGIEngine.java rename to src/main/java/org/sunflow/core/gi/AmbientOcclusionGIEngine.java index 80a9dea..9dde12a 100644 --- a/src/org/sunflow/core/gi/AmbientOcclusionGIEngine.java +++ b/src/main/java/org/sunflow/core/gi/AmbientOcclusionGIEngine.java @@ -5,6 +5,7 @@ import org.sunflow.core.Ray; import org.sunflow.core.Scene; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.gi.AmbientOcclusionGIParameter; import org.sunflow.image.Color; import org.sunflow.math.OrthoNormalBasis; import org.sunflow.math.Vector3; @@ -20,10 +21,10 @@ public Color getGlobalRadiance(ShadingState state) { } public boolean init(Options options, Scene scene) { - bright = options.getColor("gi.ambocc.bright", Color.WHITE); - dark = options.getColor("gi.ambocc.dark", Color.BLACK); - samples = options.getInt("gi.ambocc.samples", 32); - maxDist = options.getFloat("gi.ambocc.maxdist", 0); + bright = options.getColor(AmbientOcclusionGIParameter.PARAM_BRIGHT, Color.WHITE); + dark = options.getColor(AmbientOcclusionGIParameter.PARAM_DARK, Color.BLACK); + samples = options.getInt(AmbientOcclusionGIParameter.PARAM_SAMPLES, 32); + maxDist = options.getFloat(AmbientOcclusionGIParameter.PARAM_MAXDIST, 0); maxDist = (maxDist <= 0) ? Float.POSITIVE_INFINITY : maxDist; return true; } diff --git a/src/org/sunflow/core/gi/FakeGIEngine.java b/src/main/java/org/sunflow/core/gi/FakeGIEngine.java similarity index 77% rename from src/org/sunflow/core/gi/FakeGIEngine.java rename to src/main/java/org/sunflow/core/gi/FakeGIEngine.java index c1cc46c..61a5737 100644 --- a/src/org/sunflow/core/gi/FakeGIEngine.java +++ b/src/main/java/org/sunflow/core/gi/FakeGIEngine.java @@ -4,6 +4,7 @@ import org.sunflow.core.Options; import org.sunflow.core.Scene; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.gi.FakeGIParameter; import org.sunflow.image.Color; import org.sunflow.math.Vector3; @@ -33,9 +34,9 @@ public Color getGlobalRadiance(ShadingState state) { } public boolean init(Options options, Scene scene) { - up = options.getVector("gi.fake.up", new Vector3(0, 1, 0)).normalize(); - sky = options.getColor("gi.fake.sky", Color.WHITE).copy(); - ground = options.getColor("gi.fake.ground", Color.BLACK).copy(); + up = options.getVector(FakeGIParameter.PARAM_UP, new Vector3(0, 1, 0)).normalize(); + sky = options.getColor(FakeGIParameter.PARAM_SKY, Color.WHITE).copy(); + ground = options.getColor(FakeGIParameter.PARAM_GROUND, Color.BLACK).copy(); sky.mul((float) Math.PI); ground.mul((float) Math.PI); return true; diff --git a/src/org/sunflow/core/gi/InstantGI.java b/src/main/java/org/sunflow/core/gi/InstantGI.java similarity index 91% rename from src/org/sunflow/core/gi/InstantGI.java rename to src/main/java/org/sunflow/core/gi/InstantGI.java index 6f41a60..1e2d985 100644 --- a/src/org/sunflow/core/gi/InstantGI.java +++ b/src/main/java/org/sunflow/core/gi/InstantGI.java @@ -8,6 +8,7 @@ import org.sunflow.core.Ray; import org.sunflow.core.Scene; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.gi.InstantGIParameter; import org.sunflow.image.Color; import org.sunflow.math.BoundingBox; import org.sunflow.math.OrthoNormalBasis; @@ -44,10 +45,10 @@ public Color getGlobalRadiance(ShadingState state) { } public boolean init(Options options, Scene scene) { - numPhotons = options.getInt("gi.igi.samples", 64); - numSets = options.getInt("gi.igi.sets", 1); - c = options.getFloat("gi.igi.c", 0.00003f); - numBias = options.getInt("gi.igi.bias_samples", 0); + numPhotons = options.getInt(InstantGIParameter.PARAM_SAMPLES, 64); + numSets = options.getInt(InstantGIParameter.PARAM_SETS, 1); + c = options.getFloat(InstantGIParameter.PARAM_BIAS, 0.00003f); + numBias = options.getInt(InstantGIParameter.PARAM_BIAS_SAMPLES, 0); virtualLights = null; if (numSets < 1) numSets = 1; @@ -93,8 +94,9 @@ public Color getIrradiance(ShadingState state, Color diffuseReflectance) { } // bias compensation int nb = (state.getDiffuseDepth() == 0 || numBias <= 0) ? numBias : 1; - if (nb <= 0) + if (nb <= 0) { return irr; + } OrthoNormalBasis onb = state.getBasis(); Vector3 w = new Vector3(); float scale = (float) Math.PI / nb; diff --git a/src/org/sunflow/core/gi/IrradianceCacheGIEngine.java b/src/main/java/org/sunflow/core/gi/IrradianceCacheGIEngine.java similarity index 93% rename from src/org/sunflow/core/gi/IrradianceCacheGIEngine.java rename to src/main/java/org/sunflow/core/gi/IrradianceCacheGIEngine.java index 230198b..bd47359 100644 --- a/src/org/sunflow/core/gi/IrradianceCacheGIEngine.java +++ b/src/main/java/org/sunflow/core/gi/IrradianceCacheGIEngine.java @@ -9,6 +9,7 @@ import org.sunflow.core.Ray; import org.sunflow.core.Scene; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.gi.IrrCacheGIParameter; import org.sunflow.image.Color; import org.sunflow.math.MathUtils; import org.sunflow.math.OrthoNormalBasis; @@ -29,14 +30,14 @@ public class IrradianceCacheGIEngine implements GIEngine { public boolean init(Options options, Scene scene) { // get settings - samples = options.getInt("gi.irr-cache.samples", 256); - tolerance = options.getFloat("gi.irr-cache.tolerance", 0.05f); + samples = options.getInt(IrrCacheGIParameter.PARAM_SAMPLES, 256); + tolerance = options.getFloat(IrrCacheGIParameter.PARAM_TOLERANCE, 0.05f); invTolerance = 1.0f / tolerance; - minSpacing = options.getFloat("gi.irr-cache.min_spacing", 0.05f); - maxSpacing = options.getFloat("gi.irr-cache.max_spacing", 5.00f); + minSpacing = options.getFloat(IrrCacheGIParameter.PARAM_MIN_SPACING, 0.05f); + maxSpacing = options.getFloat(IrrCacheGIParameter.PARAM_MAX_SPACING, 5.00f); root = null; rwl = new ReentrantReadWriteLock(); - globalPhotonMap = PluginRegistry.globalPhotonMapPlugins.createObject(options.getString("gi.irr-cache.gmap", null)); + globalPhotonMap = PluginRegistry.globalPhotonMapPlugins.createObject(options.getString(IrrCacheGIParameter.PARAM_GLOBAL, null)); // check settings samples = Math.max(0, samples); minSpacing = Math.max(0.001f, minSpacing); diff --git a/src/org/sunflow/core/gi/PathTracingGIEngine.java b/src/main/java/org/sunflow/core/gi/PathTracingGIEngine.java similarity index 91% rename from src/org/sunflow/core/gi/PathTracingGIEngine.java rename to src/main/java/org/sunflow/core/gi/PathTracingGIEngine.java index 09b499f..2b66136 100644 --- a/src/org/sunflow/core/gi/PathTracingGIEngine.java +++ b/src/main/java/org/sunflow/core/gi/PathTracingGIEngine.java @@ -5,6 +5,7 @@ import org.sunflow.core.Ray; import org.sunflow.core.Scene; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.gi.PathTracingGIParameter; import org.sunflow.image.Color; import org.sunflow.math.OrthoNormalBasis; import org.sunflow.math.Vector3; @@ -15,7 +16,7 @@ public class PathTracingGIEngine implements GIEngine { private int samples; public boolean init(Options options, Scene scene) { - samples = options.getInt("gi.path.samples", 16); + samples = options.getInt(PathTracingGIParameter.PARAM_SAMPLES, 16); samples = Math.max(0, samples); UI.printInfo(Module.LIGHT, "Path tracer settings:"); UI.printInfo(Module.LIGHT, " * Samples: %d", samples); diff --git a/src/main/java/org/sunflow/core/light/DirectionalSpotlight.java b/src/main/java/org/sunflow/core/light/DirectionalSpotlight.java new file mode 100644 index 0000000..4991298 --- /dev/null +++ b/src/main/java/org/sunflow/core/light/DirectionalSpotlight.java @@ -0,0 +1,133 @@ +package org.sunflow.core.light; + +import org.sunflow.SunflowAPI; +import org.sunflow.core.Instance; +import org.sunflow.core.LightSample; +import org.sunflow.core.LightSource; +import org.sunflow.core.ParameterList; +import org.sunflow.core.Ray; +import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.light.DirectionalLightParameter; +import org.sunflow.core.parameter.light.LightParameter; +import org.sunflow.image.Color; +import org.sunflow.math.OrthoNormalBasis; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class DirectionalSpotlight implements LightSource { + private Point3 source; + private Vector3 direction; + private OrthoNormalBasis basis; + // Radius + private float r; + // Radius^2 + private float r2; + private Color radiance; + + public DirectionalSpotlight() { + source = new Point3(0, 0, 0); + direction = new Vector3(0, 0, -1); + direction.normalize(); + basis = OrthoNormalBasis.makeFromW(direction); + r = 1; + r2 = r * r; + radiance = Color.WHITE; + } + + public boolean update(ParameterList pl, SunflowAPI api) { + source = pl.getPoint(DirectionalLightParameter.PARAM_SOURCE, source); + direction = pl.getVector(DirectionalLightParameter.PARAM_DIRECTION, direction); + direction.normalize(); + r = pl.getFloat(DirectionalLightParameter.PARAM_RADIUS, r); + basis = OrthoNormalBasis.makeFromW(direction); + r2 = r * r; + radiance = pl.getColor(LightParameter.PARAM_RADIANCE, radiance); + return true; + } + + public int getNumSamples() { + return 1; + } + + public int getLowSamples() { + return 1; + } + + public void getSamples(ShadingState state) { + if (Vector3.dot(direction, state.getGeoNormal()) < 0 && Vector3.dot(direction, state.getNormal()) < 0) { + // project point onto source plane + float x = state.getPoint().x - source.x; + float y = state.getPoint().y - source.y; + float z = state.getPoint().z - source.z; + float t = ((x * direction.x) + (y * direction.y) + (z * direction.z)); + if (t >= 0.0) { + x -= (t * direction.x); + y -= (t * direction.y); + z -= (t * direction.z); + if (((x * x) + (y * y) + (z * z)) <= r2) { + Point3 p = new Point3(); + p.x = source.x + x; + p.y = source.y + y; + p.z = source.z + z; + LightSample dest = new LightSample(); + dest.setShadowRay(new Ray(state.getPoint(), p)); + dest.setRadiance(radiance, radiance); + dest.traceShadow(state); + state.addSample(dest); + } + } + } + } + + public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) { + float phi = (float) (2 * Math.PI * randX1); + float s = (float) Math.sqrt(1.0f - randY1); + dir.x = r * (float) Math.cos(phi) * s; + dir.y = r * (float) Math.sin(phi) * s; + dir.z = 0; + basis.transform(dir); + Point3.add(source, dir, p); + dir.set(this.direction); + power.set(radiance).mul((float) Math.PI * r2); + } + + public float getPower() { + return radiance.copy().mul((float) Math.PI * r2).getLuminance(); + } + + public Instance createInstance() { + return null; + } + + public Point3 getSource() { + return source; + } + + public void setSource(Point3 source) { + this.source = source; + } + + public Vector3 getDirection() { + return direction; + } + + public void setDirection(Vector3 direction) { + this.direction = direction; + } + + public float getR() { + return r; + } + + public void setR(float r) { + this.r = r; + } + + public Color getRadiance() { + return radiance; + } + + public void setRadiance(Color radiance) { + this.radiance = radiance; + } +} \ No newline at end of file diff --git a/src/org/sunflow/core/light/ImageBasedLight.java b/src/main/java/org/sunflow/core/light/ImageBasedLight.java similarity index 92% rename from src/org/sunflow/core/light/ImageBasedLight.java rename to src/main/java/org/sunflow/core/light/ImageBasedLight.java index 8d3b465..4b20577 100644 --- a/src/org/sunflow/core/light/ImageBasedLight.java +++ b/src/main/java/org/sunflow/core/light/ImageBasedLight.java @@ -12,6 +12,8 @@ import org.sunflow.core.ShadingState; import org.sunflow.core.Texture; import org.sunflow.core.TextureCache; +import org.sunflow.core.parameter.light.ImageBasedLightParameter; +import org.sunflow.core.parameter.light.LightParameter; import org.sunflow.image.Bitmap; import org.sunflow.image.Color; import org.sunflow.math.BoundingBox; @@ -50,10 +52,10 @@ private void updateBasis(Vector3 center, Vector3 up) { } public boolean update(ParameterList pl, SunflowAPI api) { - updateBasis(pl.getVector("center", null), pl.getVector("up", null)); - numSamples = pl.getInt("samples", numSamples); - numLowSamples = pl.getInt("lowsamples", numLowSamples); - String filename = pl.getString("texture", null); + updateBasis(pl.getVector(ImageBasedLightParameter.PARAM_CENTER, null), pl.getVector(ImageBasedLightParameter.PARAM_UP, null)); + numSamples = pl.getInt(LightParameter.PARAM_SAMPLES, numSamples); + numLowSamples = pl.getInt(ImageBasedLightParameter.PARAM_LOW_SAMPLES, numLowSamples); + String filename = pl.getString(ImageBasedLightParameter.PARAM_TEXTURE, null); if (filename != null) texture = TextureCache.getTexture(api.resolveTextureFilename(filename), false); @@ -90,7 +92,7 @@ public boolean update(ParameterList pl, SunflowAPI api) { jacobian = (float) (2 * Math.PI * Math.PI) / (b.getWidth() * b.getHeight()); } // take fixed samples - if (pl.getBoolean("fixed", samples != null)) { + if (pl.getBoolean(ImageBasedLightParameter.PARAM_FIXED, samples != null)) { // high density samples samples = new Vector3[numSamples]; colors = new Color[numSamples]; diff --git a/src/org/sunflow/core/light/PointLight.java b/src/main/java/org/sunflow/core/light/PointLight.java similarity index 70% rename from src/org/sunflow/core/light/PointLight.java rename to src/main/java/org/sunflow/core/light/PointLight.java index 86e5955..61cf2a8 100644 --- a/src/org/sunflow/core/light/PointLight.java +++ b/src/main/java/org/sunflow/core/light/PointLight.java @@ -7,22 +7,26 @@ import org.sunflow.core.ParameterList; import org.sunflow.core.Ray; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.light.PointLightParameter; import org.sunflow.image.Color; import org.sunflow.math.Point3; import org.sunflow.math.Vector3; public class PointLight implements LightSource { + // Center private Point3 lightPoint; - private Color power; + + // Radiance + private Color color; public PointLight() { lightPoint = new Point3(0, 0, 0); - power = Color.WHITE; + color = Color.WHITE; } public boolean update(ParameterList pl, SunflowAPI api) { - lightPoint = pl.getPoint("center", lightPoint); - power = pl.getColor("power", power); + lightPoint = pl.getPoint(PointLightParameter.PARAM_CENTER, lightPoint); + color = pl.getColor(PointLightParameter.PARAM_POWER, color); return true; } @@ -37,7 +41,7 @@ public void getSamples(ShadingState state) { // prepare shadow ray dest.setShadowRay(new Ray(state.getPoint(), lightPoint)); float scale = 1.0f / (float) (4 * Math.PI * lightPoint.distanceToSquared(state.getPoint())); - dest.setRadiance(power, power); + dest.setRadiance(color, color); dest.getDiffuseRadiance().mul(scale); dest.getSpecularRadiance().mul(scale); dest.traceShadow(state); @@ -52,11 +56,27 @@ public void getPhoton(double randX1, double randY1, double randX2, double randY2 dir.x = (float) Math.cos(phi) * s; dir.y = (float) Math.sin(phi) * s; dir.z = (float) (1 - 2 * randY1); - power.set(this.power); + power.set(this.color); + } + + public Point3 getLightPoint() { + return lightPoint; + } + + public void setLightPoint(Point3 lightPoint) { + this.lightPoint = lightPoint; } public float getPower() { - return power.getLuminance(); + return color.getLuminance(); + } + + public void setColor(Color color) { + this.color = color; + } + + public Color getColor() { + return color; } public Instance createInstance() { diff --git a/src/org/sunflow/core/light/SphereLight.java b/src/main/java/org/sunflow/core/light/SphereLight.java similarity index 82% rename from src/org/sunflow/core/light/SphereLight.java rename to src/main/java/org/sunflow/core/light/SphereLight.java index d589a02..b78eefe 100644 --- a/src/org/sunflow/core/light/SphereLight.java +++ b/src/main/java/org/sunflow/core/light/SphereLight.java @@ -8,6 +8,8 @@ import org.sunflow.core.Ray; import org.sunflow.core.Shader; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.light.LightParameter; +import org.sunflow.core.parameter.light.SphereLightParameter; import org.sunflow.core.primitive.Sphere; import org.sunflow.image.Color; import org.sunflow.math.Matrix4; @@ -31,18 +33,14 @@ public SphereLight() { } public boolean update(ParameterList pl, SunflowAPI api) { - radiance = pl.getColor("radiance", radiance); - numSamples = pl.getInt("samples", numSamples); - radius = pl.getFloat("radius", radius); + radiance = pl.getColor(LightParameter.PARAM_RADIANCE, radiance); + numSamples = pl.getInt(LightParameter.PARAM_SAMPLES, numSamples); + radius = pl.getFloat(SphereLightParameter.PARAM_RADIUS, radius); r2 = radius * radius; - center = pl.getPoint("center", center); + center = pl.getPoint(SphereLightParameter.PARAM_CENTER, center); return true; } - public int getNumSamples() { - return numSamples; - } - public int getLowSamples() { return 1; } @@ -150,4 +148,44 @@ public void scatterPhoton(ShadingState state, Color power) { public Instance createInstance() { return Instance.createTemporary(new Sphere(), Matrix4.translation(center.x, center.y, center.z).multiply(Matrix4.scale(radius)), this); } + + public Color getRadiance() { + return radiance; + } + + public void setRadiance(Color radiance) { + this.radiance = radiance; + } + + public int getNumSamples() { + return numSamples; + } + + public void setNumSamples(int numSamples) { + this.numSamples = numSamples; + } + + public Point3 getCenter() { + return center; + } + + public void setCenter(Point3 center) { + this.center = center; + } + + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public float getR2() { + return r2; + } + + public void setR2(float r2) { + this.r2 = r2; + } } \ No newline at end of file diff --git a/src/org/sunflow/core/light/SunSkyLight.java b/src/main/java/org/sunflow/core/light/SunSkyLight.java similarity index 93% rename from src/org/sunflow/core/light/SunSkyLight.java rename to src/main/java/org/sunflow/core/light/SunSkyLight.java index 8b9c794..af7db49 100644 --- a/src/org/sunflow/core/light/SunSkyLight.java +++ b/src/main/java/org/sunflow/core/light/SunSkyLight.java @@ -10,6 +10,8 @@ import org.sunflow.core.Ray; import org.sunflow.core.Shader; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.light.LightParameter; +import org.sunflow.core.parameter.light.SunSkyLightParameter; import org.sunflow.image.ChromaticitySpectrum; import org.sunflow.image.Color; import org.sunflow.image.ConstantSpectralCurve; @@ -190,17 +192,17 @@ private void initSunSky() { } public boolean update(ParameterList pl, SunflowAPI api) { - Vector3 up = pl.getVector("up", null); - Vector3 east = pl.getVector("east", null); + Vector3 up = pl.getVector(SunSkyLightParameter.PARAM_UP, null); + Vector3 east = pl.getVector(SunSkyLightParameter.PARAM_EAST, null); if (up != null && east != null) basis = OrthoNormalBasis.makeFromWV(up, east); else if (up != null) basis = OrthoNormalBasis.makeFromW(up); - numSkySamples = pl.getInt("samples", numSkySamples); - sunDirWorld = pl.getVector("sundir", sunDirWorld); - turbidity = pl.getFloat("turbidity", turbidity); - groundExtendSky = pl.getBoolean("ground.extendsky", groundExtendSky); - groundColor = pl.getColor("ground.color", groundColor); + numSkySamples = pl.getInt(LightParameter.PARAM_SAMPLES, numSkySamples); + sunDirWorld = pl.getVector(SunSkyLightParameter.PARAM_SUN_DIRECTION, sunDirWorld); + turbidity = pl.getFloat(SunSkyLightParameter.PARAM_TURBIDITY, turbidity); + groundExtendSky = pl.getBoolean(SunSkyLightParameter.PARAM_GROUND_EXTENDSKY, groundExtendSky); + groundColor = pl.getColor(SunSkyLightParameter.PARAM_GROUND_COLOR, groundColor); // recompute model initSunSky(); return true; diff --git a/src/org/sunflow/core/light/TriangleMeshLight.java b/src/main/java/org/sunflow/core/light/TriangleMeshLight.java similarity index 92% rename from src/org/sunflow/core/light/TriangleMeshLight.java rename to src/main/java/org/sunflow/core/light/TriangleMeshLight.java index 3af8071..5c174d6 100644 --- a/src/org/sunflow/core/light/TriangleMeshLight.java +++ b/src/main/java/org/sunflow/core/light/TriangleMeshLight.java @@ -1,5 +1,6 @@ package org.sunflow.core.light; +import net.jafama.FastMath; import org.sunflow.SunflowAPI; import org.sunflow.core.Instance; import org.sunflow.core.LightSample; @@ -8,6 +9,7 @@ import org.sunflow.core.Ray; import org.sunflow.core.Shader; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.light.LightParameter; import org.sunflow.core.primitive.TriangleMesh; import org.sunflow.image.Color; import org.sunflow.math.MathUtils; @@ -29,8 +31,8 @@ public TriangleMeshLight() { @Override public boolean update(ParameterList pl, SunflowAPI api) { - radiance = pl.getColor("radiance", radiance); - numSamples = pl.getInt("samples", numSamples); + radiance = pl.getColor(LightParameter.PARAM_RADIANCE, radiance); + numSamples = pl.getInt(LightParameter.PARAM_SAMPLES, numSamples); if (super.update(pl, api)) { // precompute triangle areas and normals areas = new float[getNumPrimitives()]; @@ -202,14 +204,14 @@ public void getSamples(ShadingState state) { float cosBeta = MathUtils.clamp(-Vector3.dot(n0, n1), -1.0f, 1.0f); float cosGamma = MathUtils.clamp(-Vector3.dot(n1, n2), -1.0f, 1.0f); - float alpha = (float) Math.acos(cosAlpha); - float beta = (float) Math.acos(cosBeta); - float gamma = (float) Math.acos(cosGamma); + float alpha = (float) FastMath.acos(cosAlpha); + float beta = (float) FastMath.acos(cosBeta); + float gamma = (float) FastMath.acos(cosGamma); float area = alpha + beta + gamma - (float) Math.PI; float cosC = MathUtils.clamp(Vector3.dot(p0, p1), -1.0f, 1.0f); - float salpha = (float) Math.sin(alpha); + float salpha = (float) FastMath.sinQuick(alpha); float product = salpha * cosC; // use lower sampling depth for diffuse bounces @@ -221,8 +223,8 @@ public void getSamples(ShadingState state) { double randY = state.getRandom(j, 1, samples); float phi = (float) randX * area - alpha + (float) Math.PI; - float sinPhi = (float) Math.sin(phi); - float cosPhi = (float) Math.cos(phi); + float sinPhi = (float) FastMath.sinQuick(phi); + float cosPhi = (float) FastMath.cosQuick(phi); float u = cosPhi + cosAlpha; float v = sinPhi - product; diff --git a/src/org/sunflow/core/modifiers/BumpMappingModifier.java b/src/main/java/org/sunflow/core/modifiers/BumpMappingModifier.java similarity index 82% rename from src/org/sunflow/core/modifiers/BumpMappingModifier.java rename to src/main/java/org/sunflow/core/modifiers/BumpMappingModifier.java index ef525db..5614775 100644 --- a/src/org/sunflow/core/modifiers/BumpMappingModifier.java +++ b/src/main/java/org/sunflow/core/modifiers/BumpMappingModifier.java @@ -19,8 +19,9 @@ public BumpMappingModifier() { public boolean update(ParameterList pl, SunflowAPI api) { String filename = pl.getString("texture", null); - if (filename != null) + if (filename != null) { bumpTexture = TextureCache.getTexture(api.resolveTextureFilename(filename), true); + } scale = pl.getFloat("scale", scale); return bumpTexture != null; } @@ -30,4 +31,12 @@ public void modify(ShadingState state) { state.getNormal().set(bumpTexture.getBump(state.getUV().x, state.getUV().y, state.getBasis(), scale)); state.setBasis(OrthoNormalBasis.makeFromW(state.getNormal())); } + + public float getScale() { + return scale; + } + + public void setScale(float scale) { + this.scale = scale; + } } \ No newline at end of file diff --git a/src/org/sunflow/core/modifiers/NormalMapModifier.java b/src/main/java/org/sunflow/core/modifiers/NormalMapModifier.java similarity index 92% rename from src/org/sunflow/core/modifiers/NormalMapModifier.java rename to src/main/java/org/sunflow/core/modifiers/NormalMapModifier.java index a297cc3..157060d 100644 --- a/src/org/sunflow/core/modifiers/NormalMapModifier.java +++ b/src/main/java/org/sunflow/core/modifiers/NormalMapModifier.java @@ -17,8 +17,9 @@ public NormalMapModifier() { public boolean update(ParameterList pl, SunflowAPI api) { String filename = pl.getString("texture", null); - if (filename != null) + if (filename != null) { normalMap = TextureCache.getTexture(api.resolveTextureFilename(filename), true); + } return normalMap != null; } diff --git a/src/org/sunflow/core/modifiers/PerlinModifier.java b/src/main/java/org/sunflow/core/modifiers/PerlinModifier.java similarity index 83% rename from src/org/sunflow/core/modifiers/PerlinModifier.java rename to src/main/java/org/sunflow/core/modifiers/PerlinModifier.java index 08bfc77..e1a3438 100644 --- a/src/org/sunflow/core/modifiers/PerlinModifier.java +++ b/src/main/java/org/sunflow/core/modifiers/PerlinModifier.java @@ -73,4 +73,28 @@ private static final double noise(double x, double y, double z, double freq) { x1 = .707 * x1 - .707 * y; return PerlinScalar.snoise((float) (freq * x1 + 100), (float) (freq * y1), (float) (freq * z1)); } + + public int getFunction() { + return function; + } + + public void setFunction(int function) { + this.function = function; + } + + public float getScale() { + return scale; + } + + public void setScale(float scale) { + this.scale = scale; + } + + public float getSize() { + return size; + } + + public void setSize(float size) { + this.size = size; + } } \ No newline at end of file diff --git a/src/main/java/org/sunflow/core/parameter/BackgroundParameter.java b/src/main/java/org/sunflow/core/parameter/BackgroundParameter.java new file mode 100644 index 0000000..6f7cd0b --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/BackgroundParameter.java @@ -0,0 +1,33 @@ +package org.sunflow.core.parameter; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.ParameterList; +import org.sunflow.core.parameter.shader.ShaderParameter; +import org.sunflow.image.Color; + +public class BackgroundParameter implements Parameter { + + public static final String PARAM_BACKGROUND = "background"; + public static final String PARAM_BACKGROUND_SHADER = "background.shader"; + public static final String PARAM_BACKGROUND_INSTANCE = "background.instance"; + public static final String PARAM_TYPE_BACKGROUND = "background"; + + Color color; + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(ParameterList.PARAM_COLOR, null, color.getRGB()); + api.shader(PARAM_BACKGROUND_SHADER, ShaderParameter.TYPE_CONSTANT); + api.geometry(PARAM_BACKGROUND, PARAM_TYPE_BACKGROUND); + api.parameter(ParameterList.PARAM_SHADERS, PARAM_BACKGROUND_SHADER); + api.instance(PARAM_BACKGROUND_INSTANCE, PARAM_TYPE_BACKGROUND); + } + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/BucketParameter.java b/src/main/java/org/sunflow/core/parameter/BucketParameter.java new file mode 100644 index 0000000..7b995e8 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/BucketParameter.java @@ -0,0 +1,47 @@ +package org.sunflow.core.parameter; + +import org.sunflow.SunflowAPI; +import org.sunflow.SunflowAPIInterface; + +public class BucketParameter implements Parameter { + + public static final String PARAM_BUCKET_SIZE = "bucket.size"; + public static final String PARAM_BUCKET_ORDER = "bucket.order"; + public static final String ORDER_COLUMN = "column"; + public static final String ORDER_DIAGONAL = "diagonal"; + public static final String ORDER_HILBERT = "hilbert"; + public static final String ORDER_SPIRAL = "spiral"; + public static final String ORDER_RANDOM = "random"; + public static final String ORDER_ROW = "row"; + + private int size = 0; + private String order = ""; + + @Override + public void setup(SunflowAPIInterface api) { + if (size > 0) { + api.parameter(PARAM_BUCKET_SIZE, size); + } + if (!order.isEmpty()) { + api.parameter(PARAM_BUCKET_ORDER, order); + } + + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } + + public String getOrder() { + return order; + } + + public void setOrder(String order) { + this.order = order; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/IlluminationParameter.java b/src/main/java/org/sunflow/core/parameter/IlluminationParameter.java new file mode 100644 index 0000000..38922c9 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/IlluminationParameter.java @@ -0,0 +1,41 @@ +package org.sunflow.core.parameter; + +public class IlluminationParameter { + + int emit = 0; + String map = ""; + int gather = 0; + float radius = 0; + + public int getEmit() { + return emit; + } + + public void setEmit(int emit) { + this.emit = emit; + } + + public String getMap() { + return map; + } + + public void setMap(String map) { + this.map = map; + } + + public int getGather() { + return gather; + } + + public void setGather(int gather) { + this.gather = gather; + } + + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + this.radius = radius; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/ImageParameter.java b/src/main/java/org/sunflow/core/parameter/ImageParameter.java new file mode 100644 index 0000000..04a60e6 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/ImageParameter.java @@ -0,0 +1,152 @@ +package org.sunflow.core.parameter; + +import org.sunflow.SunflowAPI; +import org.sunflow.SunflowAPIInterface; + +/** + * Image Block based on SCParser.parseImageBlock() + */ +public class ImageParameter implements Parameter { + + public static final String PARAM_AA_CACHE = "aa.cache"; + public static final String PARAM_AA_CONTRAST = "aa.contrast"; + public static final String PARAM_AA_DISPLAY = "aa.display"; + public static final String PARAM_AA_JITTER = "aa.jitter"; + public static final String PARAM_AA_MIN = "aa.min"; + public static final String PARAM_AA_MAX = "aa.max"; + public static final String PARAM_AA_SAMPLES = "aa.samples"; + public static final String PARAM_RESOLUTION_X = "resolutionX"; + public static final String PARAM_RESOLUTION_Y = "resolutionY"; + public static final String PARAM_SAMPLER = "sampler"; + public static final String PARAM_FILTER = "filter"; + + public static final String FILTER_TRIANGLE = "triangle"; + public static final String FILTER_GAUSSIAN = "gaussian"; + public static final String FILTER_MITCHELL = "mitchel"; + public static final String FILTER_BLACKMAN_HARRIS = "blackman-harris"; + + int resolutionX = 1920; + int resolutionY = 1080; + int aaMin = 0; + int aaMax = 2; + int aaSamples = 4; + float aaContrast = 0; + boolean aaJitter = false; + boolean aaCache = false; + + String sampler = ""; + String filter = ""; + + public void setup(SunflowAPIInterface api) { + if (resolutionX > 0) { + api.parameter(PARAM_RESOLUTION_X, resolutionX); + } + if (resolutionY > 0) { + api.parameter(PARAM_RESOLUTION_Y, resolutionY); + } + + // Always set AA params + api.parameter(PARAM_AA_MIN, aaMin); + api.parameter(PARAM_AA_MAX, aaMax); + + if (aaSamples > 0) { + api.parameter(PARAM_AA_SAMPLES, aaSamples); + } + if (aaContrast != 0) { + api.parameter(PARAM_AA_CONTRAST, aaContrast); + } + + api.parameter(PARAM_AA_JITTER, aaJitter); + + if (!sampler.isEmpty()) { + api.parameter(PARAM_SAMPLER, sampler); + } + if (!filter.isEmpty()) { + api.parameter(PARAM_FILTER, filter); + } + + api.parameter(PARAM_AA_CACHE, aaCache); + + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + + public int getResolutionX() { + return resolutionX; + } + + public void setResolutionX(int resolutionX) { + this.resolutionX = resolutionX; + } + + public int getResolutionY() { + return resolutionY; + } + + public void setResolutionY(int resolutionY) { + this.resolutionY = resolutionY; + } + + public int getAAMin() { + return aaMin; + } + + public void setAAMin(int aaMin) { + this.aaMin = aaMin; + } + + public int getAAMax() { + return aaMax; + } + + public void setAAMax(int aaMax) { + this.aaMax = aaMax; + } + + public int getAASamples() { + return aaSamples; + } + + public void setAASamples(int aaSamples) { + this.aaSamples = aaSamples; + } + + public float getAAContrast() { + return aaContrast; + } + + public void setAAContrast(float aaContrast) { + this.aaContrast = aaContrast; + } + + public boolean isAAJitter() { + return aaJitter; + } + + public void setAAJitter(boolean aaJitter) { + this.aaJitter = aaJitter; + } + + public boolean isAACache() { + return aaCache; + } + + public void setAACache(boolean aaCache) { + this.aaCache = aaCache; + } + + public String getSampler() { + return sampler; + } + + public void setSampler(String sampler) { + this.sampler = sampler; + } + + public String getFilter() { + return filter; + } + + public void setFilter(String filter) { + this.filter = filter; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/InstanceParameter.java b/src/main/java/org/sunflow/core/parameter/InstanceParameter.java new file mode 100644 index 0000000..73a8f59 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/InstanceParameter.java @@ -0,0 +1,75 @@ +package org.sunflow.core.parameter; + +import org.sunflow.SunflowAPIInterface; + +public class InstanceParameter implements Parameter { + + private String name; + private String geometry; + + private String[] shaders = null; + private String[] modifiers = null; + + private TransformParameter transform = null; + + @Override + public void setup(SunflowAPIInterface api) { + if (transform != null) { + transform.setup(api); + } + if (shaders != null) { + api.parameter("shaders", shaders); + } + if (modifiers != null) { + api.parameter("modifiers", modifiers); + } + if (geometry != null) { + api.instance(name, geometry); + } + } + + public String name() { + return name; + } + + public InstanceParameter name(String name) { + this.name = name; + return this; + } + + public String geometry() { + return geometry; + } + + public InstanceParameter geometry(String geometry) { + this.geometry = geometry; + return this; + } + + public String[] shaders() { + return shaders; + } + + public InstanceParameter shaders(String... shaders) { + this.shaders = shaders; + return this; + } + + public String[] modifiers() { + return modifiers; + } + + public InstanceParameter modifiers(String... modifiers) { + this.modifiers = modifiers; + return this; + } + + public TransformParameter transform() { + return transform; + } + + public InstanceParameter transform(TransformParameter transform) { + this.transform = transform; + return this; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/OverrideParameter.java b/src/main/java/org/sunflow/core/parameter/OverrideParameter.java new file mode 100644 index 0000000..3667184 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/OverrideParameter.java @@ -0,0 +1,40 @@ +package org.sunflow.core.parameter; + +import org.sunflow.SunflowAPI; +import org.sunflow.SunflowAPIInterface; + +public class OverrideParameter implements Parameter { + + public static final String PARAM_OVERRIDE_SHADER = "override.shader"; + public static final String PARAM_OVERRIDE_PHOTONS = "override.photons"; + + String shader = ""; + boolean photons = false; + + @Override + public void setup(SunflowAPIInterface api) { + + if (!shader.isEmpty()) { + api.parameter(PARAM_OVERRIDE_SHADER, shader); + } + api.parameter(PARAM_OVERRIDE_PHOTONS, photons); + + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + + public String getShader() { + return shader; + } + + public void setShader(String shader) { + this.shader = shader; + } + + public boolean isPhotons() { + return photons; + } + + public void setPhotons(boolean photons) { + this.photons = photons; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/Parameter.java b/src/main/java/org/sunflow/core/parameter/Parameter.java new file mode 100644 index 0000000..1d3e9ec --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/Parameter.java @@ -0,0 +1,7 @@ +package org.sunflow.core.parameter; + +import org.sunflow.SunflowAPIInterface; + +public interface Parameter { + void setup(SunflowAPIInterface api); +} diff --git a/src/main/java/org/sunflow/core/parameter/PhotonParameter.java b/src/main/java/org/sunflow/core/parameter/PhotonParameter.java new file mode 100644 index 0000000..5fba9e1 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/PhotonParameter.java @@ -0,0 +1,47 @@ +package org.sunflow.core.parameter; + +import org.sunflow.SunflowAPI; +import org.sunflow.SunflowAPIInterface; + +public class PhotonParameter implements Parameter { + + public static final String PARAM_CAUSTICS = "caustics"; + public static final String PARAM_CAUSTICS_EMIT = "caustics.emit"; + public static final String PARAM_CAUSTICS_GATHER = "caustics.gather"; + public static final String PARAM_CAUSTICS_RADIUS = "caustics.radius"; + + IlluminationParameter caustics; + + public PhotonParameter() { + caustics = new IlluminationParameter(); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_CAUSTICS, caustics.map); + api.parameter(PARAM_CAUSTICS_EMIT, caustics.emit); + api.parameter(PARAM_CAUSTICS_GATHER, caustics.gather); + api.parameter(PARAM_CAUSTICS_RADIUS, caustics.radius); + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + + public int getNumEmit() { + return caustics.emit; + } + + public void setNumEmit(int numEmit) { + caustics.emit = numEmit; + } + + public void setCaustics(String caustics) { + this.caustics.map = caustics; + } + + public void setCausticsGather(int causticsGather) { + caustics.gather = causticsGather; + } + + public void setCausticsRadius(float causticsRadius) { + caustics.radius = causticsRadius; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/TraceDepthsParameter.java b/src/main/java/org/sunflow/core/parameter/TraceDepthsParameter.java new file mode 100644 index 0000000..b78d0d9 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/TraceDepthsParameter.java @@ -0,0 +1,51 @@ +package org.sunflow.core.parameter; + +import org.sunflow.SunflowAPIInterface; + +public class TraceDepthsParameter implements Parameter { + + public static final String PARAM_DEPTHS_DIFFUSE = "depths.diffuse"; + public static final String PARAM_DEPTHS_REFLECTION = "depths.reflection"; + public static final String PARAM_DEPTHS_REFRACTION = "depths.refraction"; + + int diffuse = 0; + int reflection = 0; + int refraction = 0; + + @Override + public void setup(SunflowAPIInterface api) { + if (diffuse > 0) { + api.parameter(PARAM_DEPTHS_DIFFUSE, diffuse); + } + if (reflection > 0) { + api.parameter(PARAM_DEPTHS_REFLECTION, reflection); + } + if (refraction > 0) { + api.parameter(PARAM_DEPTHS_REFRACTION, refraction); + } + } + + public int getDiffuse() { + return diffuse; + } + + public void setDiffuse(int diffuse) { + this.diffuse = diffuse; + } + + public int getReflection() { + return reflection; + } + + public void setReflection(int reflection) { + this.reflection = reflection; + } + + public int getRefraction() { + return refraction; + } + + public void setRefraction(int refraction) { + this.refraction = refraction; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/TransformParameter.java b/src/main/java/org/sunflow/core/parameter/TransformParameter.java new file mode 100644 index 0000000..20e122a --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/TransformParameter.java @@ -0,0 +1,80 @@ +package org.sunflow.core.parameter; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.math.Matrix4; + +public class TransformParameter implements Parameter { + + public static final String INTERPOLATION_NONE = "none"; + + float[] times; + Matrix4[] transforms = new Matrix4[]{Matrix4.IDENTITY}; + + String interpolation = INTERPOLATION_NONE; + + @Override + public void setup(SunflowAPIInterface api) { + if (times == null) { + api.parameter("transform", transforms[0]); + } else { + int steps = times.length; + api.parameter("transform.steps", steps); + api.parameter("transform.times", "float", interpolation, times); + for (int i = 0; i < steps; i++) { + api.parameter(String.format("transform[%d]", i), transforms[i]); + } + } + } + + public float[] getTimes() { + return times; + } + + public void setTimes(float[] times) { + this.times = times; + } + + public Matrix4[] getTransforms() { + return transforms; + } + + public void setTransforms(Matrix4[] transforms) { + this.transforms = transforms; + } + + public TransformParameter rotateX(float angle) { + Matrix4 t = Matrix4.rotateX((float) Math.toRadians(angle)); + transforms[0] = t.multiply(transforms[0]); + return this; + } + + public TransformParameter rotateY(float angle) { + Matrix4 t = Matrix4.rotateY((float) Math.toRadians(angle)); + transforms[0] = t.multiply(transforms[0]); + return this; + } + + public TransformParameter rotateZ(float angle) { + Matrix4 t = Matrix4.rotateZ((float) Math.toRadians(angle)); + transforms[0] = t.multiply(transforms[0]); + return this; + } + + public TransformParameter scale(float scale) { + Matrix4 t = Matrix4.scale(scale); + transforms[0] = t.multiply(transforms[0]); + return this; + } + + public TransformParameter scale(float x, float y, float z) { + Matrix4 t = Matrix4.scale(x, y, z); + transforms[0] = t.multiply(transforms[0]); + return this; + } + + public TransformParameter translate(float x, float y, float z) { + Matrix4 t = Matrix4.translation(x, y, z); + transforms[0] = t.multiply(transforms[0]); + return this; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/camera/CameraParameter.java b/src/main/java/org/sunflow/core/parameter/camera/CameraParameter.java new file mode 100644 index 0000000..70d9675 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/camera/CameraParameter.java @@ -0,0 +1,64 @@ +package org.sunflow.core.parameter.camera; + +import org.sunflow.SunflowAPI; +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.parameter.Parameter; +import org.sunflow.math.Matrix4; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class CameraParameter implements Parameter { + + public static final String TYPE_FISH_EYE = "fisheye"; + public static final String TYPE_PINHOLE = "pinhole"; + public static final String TYPE_SPHERICAL = "spherical"; + public static final String TYPE_THINLENS = "thinlens"; + + public static final String PARAM_FOV = "fov"; + public static final String PARAM_ASPECT = "aspect"; + public static final String PARAM_SHIFT_X = "shift.x"; + public static final String PARAM_SHIFT_Y = "shift.y"; + public static final String PARAM_SHUTTER_OPEN = "shutter.open"; + public static final String PARAM_SHUTTER_CLOSE = "shutter.close"; + public static final String PARAM_CAMERA = "camera"; + + // Default values from Camera + protected float shutterOpen = 0; + protected float shutterClose = 0; + + protected String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public float getShutterOpen() { + return shutterOpen; + } + + public void setShutterOpen(float shutterOpen) { + this.shutterOpen = shutterOpen; + } + + public float getShutterClose() { + return shutterClose; + } + + public void setShutterClose(float shutterClose) { + this.shutterClose = shutterClose; + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_CAMERA, name); + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + + public void setupTransform(SunflowAPI api, Point3 eye, Point3 target, Vector3 up) { + api.parameter("transform", Matrix4.lookAt(eye, target, up)); + } +} diff --git a/src/main/java/org/sunflow/core/parameter/camera/FishEyeCameraParameter.java b/src/main/java/org/sunflow/core/parameter/camera/FishEyeCameraParameter.java new file mode 100644 index 0000000..605ab88 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/camera/FishEyeCameraParameter.java @@ -0,0 +1,17 @@ +package org.sunflow.core.parameter.camera; + +import org.sunflow.SunflowAPIInterface; + +public class FishEyeCameraParameter extends CameraParameter { + + // FisheyeLens lens; + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_SHUTTER_OPEN, shutterOpen); + api.parameter(PARAM_SHUTTER_CLOSE, shutterClose); + api.camera(name, TYPE_FISH_EYE); + super.setup(api); + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/camera/PinholeCameraParameter.java b/src/main/java/org/sunflow/core/parameter/camera/PinholeCameraParameter.java new file mode 100644 index 0000000..e942dd2 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/camera/PinholeCameraParameter.java @@ -0,0 +1,59 @@ +package org.sunflow.core.parameter.camera; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.camera.PinholeLens; + +public class PinholeCameraParameter extends CameraParameter { + + private PinholeLens lens; + + public PinholeCameraParameter() { + lens = new PinholeLens(); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_SHUTTER_OPEN, shutterOpen); + api.parameter(PARAM_SHUTTER_CLOSE, shutterClose); + api.parameter(PARAM_FOV, lens.getFov()); + api.parameter(PARAM_ASPECT, lens.getAspect()); + api.parameter(PARAM_SHIFT_X, lens.getShiftX()); + api.parameter(PARAM_SHIFT_Y, lens.getShiftY()); + + api.camera(name, TYPE_PINHOLE); + super.setup(api); + } + + public float getFov() { + return lens.getFov(); + } + + public void setFov(float fov) { + lens.setFov(fov); + } + + public float getAspect() { + return lens.getAspect(); + } + + public void setAspect(float aspect) { + lens.setAspect(aspect); + } + + public float getShiftX() { + return lens.getShiftX(); + } + + public void setShiftX(float shiftX) { + lens.setShiftX(shiftX); + } + + public float getShiftY() { + return lens.getShiftY(); + } + + public void setShiftY(float shiftY) { + lens.setShiftY(shiftY); + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/camera/SphericalCameraParameter.java b/src/main/java/org/sunflow/core/parameter/camera/SphericalCameraParameter.java new file mode 100644 index 0000000..8d72f07 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/camera/SphericalCameraParameter.java @@ -0,0 +1,17 @@ +package org.sunflow.core.parameter.camera; + +import org.sunflow.SunflowAPIInterface; + +public class SphericalCameraParameter extends CameraParameter { + + // SphericalLens lens; + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_SHUTTER_OPEN, shutterOpen); + api.parameter(PARAM_SHUTTER_CLOSE, shutterClose); + api.camera(name, TYPE_SPHERICAL); + super.setup(api); + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/camera/ThinLensCameraParameter.java b/src/main/java/org/sunflow/core/parameter/camera/ThinLensCameraParameter.java new file mode 100644 index 0000000..6acd2da --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/camera/ThinLensCameraParameter.java @@ -0,0 +1,107 @@ +package org.sunflow.core.parameter.camera; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.camera.ThinLens; + +public class ThinLensCameraParameter extends CameraParameter { + + public static final String PARAM_FOCUS_DISTANCE = "focus.distance"; + public static final String PARAM_LENS_RADIUS = "lens.radius"; + public static final String PARAM_LENS_SIDES = "lens.sides"; + public static final String PARAM_LENS_ROTATION = "lens.rotation"; + + private ThinLens lens; + + public ThinLensCameraParameter() { + lens = new ThinLens(); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_SHUTTER_OPEN, shutterOpen); + api.parameter(PARAM_SHUTTER_CLOSE, shutterClose); + api.parameter(PARAM_FOV, lens.getFov()); + api.parameter(PARAM_ASPECT, lens.getAspect()); + api.parameter(PARAM_SHIFT_X, lens.getShiftX()); + api.parameter(PARAM_SHIFT_Y, lens.getShiftY()); + api.parameter(PARAM_FOCUS_DISTANCE, lens.getFocusDistance()); + api.parameter(PARAM_LENS_RADIUS, lens.getLensRadius()); + api.parameter(PARAM_LENS_SIDES, lens.getLensSides()); + api.parameter(PARAM_LENS_ROTATION, lens.getLensRotation()); + api.camera(name, TYPE_THINLENS); + super.setup(api); + } + + public float getAspect() { + return lens.getAspect(); + } + + public void setAspect(float aspect) { + lens.setAspect(aspect); + } + + public float getFov() { + return lens.getFov(); + } + + public void setFov(float fov) { + lens.setFov(fov); + } + + public float getShiftX() { + return lens.getShiftX(); + } + + public void setShiftX(float shiftX) { + lens.setShiftX(shiftX); + } + + public float getShiftY() { + return lens.getShiftY(); + } + + public void setShiftY(float shiftY) { + lens.setShiftY(shiftY); + } + + public float getFocusDistance() { + return lens.getFocusDistance(); + } + + public void setFocusDistance(float focusDistance) { + lens.setFocusDistance(focusDistance); + } + + public float getLensRadius() { + return lens.getLensRadius(); + } + + public void setLensRadius(float lensRadius) { + lens.setLensRadius(lensRadius); + } + + public int getLensSides() { + return lens.getLensSides(); + } + + public void setLensSides(int lensSides) { + lens.setLensSides(lensSides); + } + + public float getLensRotation() { + return lens.getLensRotation(); + } + + public void setLensRotation(float lensRotation) { + lens.setLensRotation(lensRotation); + } + + public float getLensRotationRadians() { + return lens.getLensRotationRadians(); + } + + public void setLensRotationRadians(float lensRotationRadians) { + lens.setLensRotationRadians(lensRotationRadians); + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/BanchOffParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/BanchOffParameter.java new file mode 100644 index 0000000..c7495bf --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/BanchOffParameter.java @@ -0,0 +1,13 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class BanchOffParameter extends GeometryParameter { + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.geometry(name, TYPE_BANCHOFF); + setupInstance(api); + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/BezierMeshParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/BezierMeshParameter.java new file mode 100644 index 0000000..437b5eb --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/BezierMeshParameter.java @@ -0,0 +1,84 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class BezierMeshParameter extends GeometryParameter { + + int nu, nv; + boolean uwrap = false, vwrap = false; + float[] points; + + int subdivs = 1; + boolean smooth = false; + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("nu", nu); + api.parameter("nv", nv); + api.parameter("uwrap", uwrap); + api.parameter("vwrap", vwrap); + api.parameter("points", "point", "vertex", points); + api.parameter("subdivs", subdivs); + api.parameter("smooth", smooth); + api.geometry(name, TYPE_BEZIER_MESH); + + setupInstance(api); + } + + public int getNu() { + return nu; + } + + public void setNu(int nu) { + this.nu = nu; + } + + public int getNv() { + return nv; + } + + public void setNv(int nv) { + this.nv = nv; + } + + public boolean isUwrap() { + return uwrap; + } + + public void setUwrap(boolean uwrap) { + this.uwrap = uwrap; + } + + public boolean isVwrap() { + return vwrap; + } + + public void setVwrap(boolean vwrap) { + this.vwrap = vwrap; + } + + public float[] getPoints() { + return points; + } + + public void setPoints(float[] points) { + this.points = points; + } + + public int getSubdivs() { + return subdivs; + } + + public void setSubdivs(int subdivs) { + this.subdivs = subdivs; + } + + public boolean isSmooth() { + return smooth; + } + + public void setSmooth(boolean smooth) { + this.smooth = smooth; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/BoxParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/BoxParameter.java new file mode 100644 index 0000000..a83cceb --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/BoxParameter.java @@ -0,0 +1,46 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class BoxParameter extends GeometryParameter { + + Point3 min; + Point3 max; + + public BoxParameter() { + + } + + public BoxParameter(String name) { + super(name); + } + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("min", min); + api.parameter("max", max); + + api.geometry(name, TYPE_BOX); + + setupInstance(api); + } + + public Point3 getMin() { + return min; + } + + public void setMin(Point3 min) { + this.min = min; + } + + public Point3 getMax() { + return max; + } + + public void setMax(Point3 max) { + this.max = max; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/CylinderParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/CylinderParameter.java new file mode 100644 index 0000000..a1087e4 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/CylinderParameter.java @@ -0,0 +1,14 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class CylinderParameter extends GeometryParameter { + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.geometry(name, TYPE_CYLINDER); + + setupInstance(api); + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/FileMeshParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/FileMeshParameter.java new file mode 100644 index 0000000..edf1b58 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/FileMeshParameter.java @@ -0,0 +1,34 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class FileMeshParameter extends GeometryParameter { + + String filename; + boolean smoothNormals = false; + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("filename", filename); + api.parameter("smooth_normals", smoothNormals); + api.geometry(name, TYPE_FILE_MESH); + setupInstance(api); + } + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public boolean isSmoothNormals() { + return smoothNormals; + } + + public void setSmoothNormals(boolean smoothNormals) { + this.smoothNormals = smoothNormals; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/GenericMeshParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/GenericMeshParameter.java new file mode 100644 index 0000000..684efc5 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/GenericMeshParameter.java @@ -0,0 +1,103 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class GenericMeshParameter extends GeometryParameter { + + float[] points; + int[] triangles; + float[] normals; + float[] uvs; + + boolean faceVaryingNormals = false; + boolean faceVaryingTextures = false; + + int[] faceShaders = null; + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("points", "point", "vertex", points); + api.parameter("triangles", triangles); + + if (normals != null) { + if (!faceVaryingNormals) { + api.parameter("normals", "vector", "vertex", normals); + } else { + api.parameter("normals", "vector", "facevarying", normals); + } + } + + if (uvs != null) { + if (!faceVaryingTextures) { + api.parameter("uvs", "texcoord", "vertex", uvs); + } else { + api.parameter("uvs", "texcoord", "facevarying", uvs); + } + } + + if (faceShaders != null) { + api.parameter("faceshaders", faceShaders); + } + + api.geometry(name, TYPE_TRIANGLE_MESH); + + setupInstance(api); + } + + public float[] getPoints() { + return points; + } + + public void setPoints(float[] points) { + this.points = points; + } + + public int[] getTriangles() { + return triangles; + } + + public void setTriangles(int[] triangles) { + this.triangles = triangles; + } + + public float[] getNormals() { + return normals; + } + + public void setNormals(float[] normals) { + this.normals = normals; + } + + public boolean isFaceVaryingNormals() { + return faceVaryingNormals; + } + + public void setFaceVaryingNormals(boolean faceVaryingNormals) { + this.faceVaryingNormals = faceVaryingNormals; + } + + public boolean isFaceVaryingTextures() { + return faceVaryingTextures; + } + + public void setFaceVaryingTextures(boolean faceVaryingTextures) { + this.faceVaryingTextures = faceVaryingTextures; + } + + public float[] getUvs() { + return uvs; + } + + public void setUvs(float[] uvs) { + this.uvs = uvs; + } + + public int[] getFaceShaders() { + return faceShaders; + } + + public void setFaceShaders(int[] faceShaders) { + this.faceShaders = faceShaders; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/GeometryParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/GeometryParameter.java new file mode 100644 index 0000000..6832d67 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/GeometryParameter.java @@ -0,0 +1,27 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public abstract class GeometryParameter extends ObjectParameter { + + public GeometryParameter() { + + } + + public GeometryParameter(String name) { + this.name = name; + } + + public void setupInstance(SunflowAPIInterface api) { + if (instanceParameter != null) { + instanceParameter.name(name + ".instance"); + + if (instanceParameter.geometry() == null) { + instanceParameter.geometry(name); + } + + instanceParameter.setup(api); + } + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/GumboParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/GumboParameter.java new file mode 100644 index 0000000..1264fb9 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/GumboParameter.java @@ -0,0 +1,40 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class GumboParameter extends GeometryParameter { + + int subdivs; + boolean smooth; + + public GumboParameter() { + // Default values from BezierMesh + subdivs = 8; + smooth = true; + } + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("subdivs", subdivs); + api.parameter("smooth", smooth); + api.geometry(name, TYPE_GUMBO); + setupInstance(api); + } + + public int getSubdivs() { + return subdivs; + } + + public void setSubdivs(int subdivs) { + this.subdivs = subdivs; + } + + public boolean isSmooth() { + return smooth; + } + + public void setSmooth(boolean smooth) { + this.smooth = smooth; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/HairParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/HairParameter.java new file mode 100644 index 0000000..bd5a4d9 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/HairParameter.java @@ -0,0 +1,44 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class HairParameter extends GeometryParameter { + + int segments; + float width; + float[] points; + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("segments", segments); + api.parameter("widths", width); + api.parameter("points", "point", "vertex", points); + api.geometry(name, TYPE_HAIR); + setupInstance(api); + } + + public int getSegments() { + return segments; + } + + public void setSegments(int segments) { + this.segments = segments; + } + + public float getWidth() { + return width; + } + + public void setWidth(float width) { + this.width = width; + } + + public float[] getPoints() { + return points; + } + + public void setPoints(float[] points) { + this.points = points; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/JuliaParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/JuliaParameter.java new file mode 100644 index 0000000..c805433 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/JuliaParameter.java @@ -0,0 +1,90 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class JuliaParameter extends GeometryParameter { + + // Quaternion + float cx, cy, cz, cw; + + int iterations = 1; + float epsilon; + + public JuliaParameter() { + } + + public JuliaParameter(String name) { + this.name = name; + } + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + + api.parameter("cw", cw); + api.parameter("cx", cx); + api.parameter("cy", cy); + api.parameter("cz", cz); + api.parameter("iterations", iterations); + api.parameter("epsilon", epsilon); + + api.geometry(name, TYPE_JULIA); + + setupInstance(api); + } + + public float getCx() { + return cx; + } + + public void setCx(float cx) { + this.cx = cx; + } + + public float getCy() { + return cy; + } + + public void setCy(float cy) { + this.cy = cy; + } + + public float getCz() { + return cz; + } + + public void setCz(float cz) { + this.cz = cz; + } + + public float getCw() { + return cw; + } + + public void setCw(float cw) { + this.cw = cw; + } + + public int getIterations() { + return iterations; + } + + public void setIterations(int iterations) { + this.iterations = iterations; + } + + public float getEpsilon() { + return epsilon; + } + + public void setEpsilon(float epsilon) { + this.epsilon = epsilon; + } + + public void setQuaternion(float cx, float cy, float cz, float cw) { + this.cx = cx; + this.cy = cy; + this.cz = cz; + this.cw = cw; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/ObjectParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/ObjectParameter.java new file mode 100644 index 0000000..6fca44d --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/ObjectParameter.java @@ -0,0 +1,168 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.parameter.InstanceParameter; +import org.sunflow.core.parameter.Parameter; +import org.sunflow.core.parameter.TransformParameter; +import org.sunflow.core.parameter.modifier.ModifierParameter; +import org.sunflow.core.parameter.shader.ShaderParameter; + +public class ObjectParameter implements Parameter { + + public static final String TYPE_BANCHOFF = "banchoff"; + public static final String TYPE_BEZIER_MESH = "bezier_mesh"; + public static final String TYPE_BOX = "box"; + public static final String TYPE_CYLINDER = "cylinder"; + public static final String TYPE_GUMBO = "gumbo"; + public static final String TYPE_HAIR = "hair"; + public static final String TYPE_JULIA = "julia"; + public static final String TYPE_TORUS = "torus"; + public static final String TYPE_SPHERE = "sphere"; + public static final String TYPE_SPHEREFLAKE = "sphereflake"; + public static final String TYPE_PARTICLES = "particles"; + public static final String TYPE_PLANE = "plane"; + public static final String TYPE_TEAPOT = "teapot"; + public static final String TYPE_TRIANGLE_MESH = "triangle_mesh"; + public static final String TYPE_FILE_MESH = "file_mesh"; + + public static final String PARAM_ACCEL = "accel"; + + protected String name = "none"; + protected String accel = ""; + + protected InstanceParameter instanceParameter; + + public String getAccel() { + return accel; + } + + public void setAccel(String accel) { + this.accel = accel; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public InstanceParameter getInstanceParameter() { + return instanceParameter; + } + + public void setInstanceParameter(InstanceParameter instanceParameter) { + this.instanceParameter = instanceParameter; + } + + @Override + public void setup(SunflowAPIInterface api) { + if (!accel.isEmpty()) { + api.parameter(PARAM_ACCEL, accel); + } + } + + public void geometry(String geometry) { + if (instanceParameter == null) { + instanceParameter = new InstanceParameter(); + } + + instanceParameter.geometry(geometry); + } + + public void geometry(ObjectParameter objectParameter) { + if (instanceParameter == null) { + instanceParameter = new InstanceParameter(); + } + + instanceParameter.geometry(objectParameter.name); + } + + public void shaders(String... shaders) { + if (instanceParameter == null) { + instanceParameter = new InstanceParameter(); + } + + instanceParameter.shaders(shaders); + } + + public void shaders(ShaderParameter... shaders) { + if (instanceParameter == null) { + instanceParameter = new InstanceParameter(); + } + + String[] names = new String[shaders.length]; + for (int i = 0; i < shaders.length; i++) { + names[i] = shaders[i].getName(); + } + + instanceParameter.shaders(names); + } + + public void modifiers(String... modifiers) { + if (instanceParameter == null) { + instanceParameter = new InstanceParameter(); + } + + instanceParameter.shaders(modifiers); + } + + public void modifiers(ModifierParameter... modifiers) { + if (instanceParameter == null) { + instanceParameter = new InstanceParameter(); + } + + String[] names = new String[modifiers.length]; + for (int i = 0; i < modifiers.length; i++) { + names[i] = modifiers[i].getName(); + } + + instanceParameter.modifiers(names); + } + + public void rotateX(float angle) { + TransformParameter transformParameter = getInstanceTransform(); + transformParameter.rotateX(angle); + } + + public void rotateY(float angle) { + TransformParameter transformParameter = getInstanceTransform(); + transformParameter.rotateY(angle); + } + + public void rotateZ(float angle) { + TransformParameter transformParameter = getInstanceTransform(); + transformParameter.rotateZ(angle); + } + + public void scale(float scale) { + TransformParameter transformParameter = getInstanceTransform(); + transformParameter.scale(scale); + } + + public void scale(float x, float y, float z) { + TransformParameter transformParameter = getInstanceTransform(); + transformParameter.scale(x, y, z); + } + + public void translate(float x, float y, float z) { + TransformParameter transformParameter = getInstanceTransform(); + transformParameter.translate(x, y, z); + } + + private TransformParameter getInstanceTransform() { + if (instanceParameter == null) { + instanceParameter = new InstanceParameter(); + } + + TransformParameter transformParameter = instanceParameter.transform(); + + if (transformParameter == null) { + transformParameter = new TransformParameter(); + instanceParameter.transform(transformParameter); + } + return transformParameter; + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/ParticlesParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/ParticlesParameter.java new file mode 100644 index 0000000..7464405 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/ParticlesParameter.java @@ -0,0 +1,45 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class ParticlesParameter extends GeometryParameter { + + int num; + float radius; + float[] points; + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("particles", "point", "vertex", points); + api.parameter("num", num); + api.parameter("radius", radius); + api.geometry(name, TYPE_PARTICLES); + + setupInstance(api); + } + + public int getNum() { + return num; + } + + public void setNum(int num) { + this.num = num; + } + + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public float[] getPoints() { + return points; + } + + public void setPoints(float[] points) { + this.points = points; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/PlaneParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/PlaneParameter.java new file mode 100644 index 0000000..cc35602 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/PlaneParameter.java @@ -0,0 +1,68 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class PlaneParameter extends GeometryParameter { + + Point3 center; + Point3 point1; + Point3 point2; + Vector3 normal; + + public PlaneParameter() { + + } + + public PlaneParameter(String name) { + super(name); + } + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("center", center); + if (normal != null) { + api.parameter("normal", normal); + } else { + api.parameter("point1", point1); + api.parameter("point2", point2); + } + api.geometry(name, TYPE_PLANE); + + setupInstance(api); + } + + public Point3 getCenter() { + return center; + } + + public void setCenter(Point3 center) { + this.center = center; + } + + public Point3 getPoint1() { + return point1; + } + + public void setPoint1(Point3 point1) { + this.point1 = point1; + } + + public Point3 getPoint2() { + return point2; + } + + public void setPoint2(Point3 point2) { + this.point2 = point2; + } + + public Vector3 getNormal() { + return normal; + } + + public void setNormal(Vector3 normal) { + this.normal = normal; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/SphereFlakeParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/SphereFlakeParameter.java new file mode 100644 index 0000000..7074c1c --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/SphereFlakeParameter.java @@ -0,0 +1,66 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.math.Vector3; + +public class SphereFlakeParameter extends GeometryParameter { + + int level = 2; + float radius = 1; + Vector3 axis; + + public SphereFlakeParameter() { + // Default values from SphereFlake + level = 2; + radius = 1; + axis = new Vector3(0, 0, 1); + } + + public SphereFlakeParameter(String name) { + this(); + this.name = name; + } + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + + api.parameter("level", level); + + if (axis != null) { + api.parameter("axis", axis); + } + + if (radius > 0) { + api.parameter("radius", radius); + } + + api.geometry(name, TYPE_SPHEREFLAKE); + + setupInstance(api); + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public Vector3 getAxis() { + return axis; + } + + public void setAxis(Vector3 axis) { + this.axis = axis; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/SphereParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/SphereParameter.java new file mode 100644 index 0000000..65e9d3b --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/SphereParameter.java @@ -0,0 +1,58 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.math.Matrix4; +import org.sunflow.math.Point3; + +public class SphereParameter extends GeometryParameter { + + Point3 center; + float radius; + + public SphereParameter() { + + } + + public SphereParameter(String name) { + this.name = name; + } + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.geometry(name, TYPE_SPHERE); + + // Legacy instantiation + if (center != null) { + api.parameter("transform", Matrix4.translation(center.x, center.y, center.z).multiply(Matrix4.scale(radius))); + + if (instanceParameter != null) { + if (instanceParameter.shaders() != null) { + api.parameter("shaders", instanceParameter.shaders()); + } + if (instanceParameter.modifiers() != null) { + api.parameter("modifiers", instanceParameter.modifiers()); + } + } + api.instance(name + ".instance", name); + } else { + setupInstance(api); + } + } + + public Point3 getCenter() { + return center; + } + + public void setCenter(Point3 center) { + this.center = center; + } + + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + this.radius = radius; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/TeapotParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/TeapotParameter.java new file mode 100644 index 0000000..a22102d --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/TeapotParameter.java @@ -0,0 +1,46 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class TeapotParameter extends GeometryParameter { + + int subdivs = 1; + boolean smooth = false; + + public TeapotParameter() { + + } + + public TeapotParameter(String name) { + this.name = name; + } + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("subdivs", subdivs); + api.parameter("smooth", smooth); + + if (instanceParameter == null || instanceParameter.geometry() == null) { + api.geometry(name, TYPE_TEAPOT); + } + + setupInstance(api); + } + + public int getSubdivs() { + return subdivs; + } + + public void setSubdivs(int subdivs) { + this.subdivs = subdivs; + } + + public boolean isSmooth() { + return smooth; + } + + public void setSmooth(boolean smooth) { + this.smooth = smooth; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/TorusParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/TorusParameter.java new file mode 100644 index 0000000..a9069c8 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/TorusParameter.java @@ -0,0 +1,35 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class TorusParameter extends GeometryParameter { + + float radiusInner; + float radiusOuter; + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + api.parameter("radiusInner", radiusInner); + api.parameter("radiusOuter", radiusOuter); + api.geometry(name, TYPE_TORUS); + + setupInstance(api); + } + + public float getRadiusInner() { + return radiusInner; + } + + public void setRadiusInner(float radiusInner) { + this.radiusInner = radiusInner; + } + + public float getRadiusOuter() { + return radiusOuter; + } + + public void setRadiusOuter(float radiusOuter) { + this.radiusOuter = radiusOuter; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/geometry/TriangleMeshParameter.java b/src/main/java/org/sunflow/core/parameter/geometry/TriangleMeshParameter.java new file mode 100644 index 0000000..df040e2 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/geometry/TriangleMeshParameter.java @@ -0,0 +1,63 @@ +package org.sunflow.core.parameter.geometry; + +import org.sunflow.SunflowAPIInterface; + +public class TriangleMeshParameter extends GeometryParameter { + + float[] points; + float[] normals; + float[] uvs; + int[] triangles; + + @Override + public void setup(SunflowAPIInterface api) { + super.setup(api); + if (name == null || name.isEmpty()) { + throw new RuntimeException("Name cannot be null"); + } + // create geometry + api.parameter("triangles", triangles); + api.parameter("points", "point", "vertex", points); + if (normals != null) { + api.parameter("normals", "vector", "vertex", normals); + } + if (uvs != null) { + api.parameter("uvs", "texcoord", "vertex", uvs); + } + api.geometry(name, "triangle_mesh"); + + setupInstance(api); + } + + public float[] getPoints() { + return points; + } + + public void setPoints(float[] points) { + this.points = points; + } + + public float[] getNormals() { + return normals; + } + + public void setNormals(float[] normals) { + this.normals = normals; + } + + public float[] getUvs() { + return uvs; + } + + public void setUvs(float[] uvs) { + this.uvs = uvs; + } + + public int[] getTriangles() { + return triangles; + } + + public void setTriangles(int[] triangles) { + this.triangles = triangles; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/gi/AmbientOcclusionGIParameter.java b/src/main/java/org/sunflow/core/parameter/gi/AmbientOcclusionGIParameter.java new file mode 100644 index 0000000..c1c8d12 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/gi/AmbientOcclusionGIParameter.java @@ -0,0 +1,65 @@ +package org.sunflow.core.parameter.gi; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +/** + * Global Illumination with Ambient Occlusion + */ +public class AmbientOcclusionGIParameter extends GlobalIlluminationParameter { + + public static final String PARAM_BRIGHT = "gi.ambocc.bright"; + public static final String PARAM_DARK = "gi.ambocc.dark"; + public static final String PARAM_SAMPLES = "gi.ambocc.samples"; + public static final String PARAM_MAXDIST = "gi.ambocc.maxdist"; + + Color bright; + Color dark; + int samples; + float maxDist = 0; + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(GlobalIlluminationParameter.PARAM_ENGINE, GlobalIlluminationParameter.TYPE_AMBOCC); + api.parameter(PARAM_BRIGHT, null, bright.getRGB()); + api.parameter(PARAM_DARK, null, dark.getRGB()); + api.parameter(PARAM_SAMPLES, samples); + + if (maxDist > 0) { + api.parameter(PARAM_MAXDIST, maxDist); + } + super.setup(api); + } + + public Color getBright() { + return bright; + } + + public void setBright(Color bright) { + this.bright = bright; + } + + public Color getDark() { + return dark; + } + + public void setDark(Color dark) { + this.dark = dark; + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } + + public float getMaxDist() { + return maxDist; + } + + public void setMaxDist(float maxDist) { + this.maxDist = maxDist; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/gi/DisabledGIParameter.java b/src/main/java/org/sunflow/core/parameter/gi/DisabledGIParameter.java new file mode 100644 index 0000000..23dccb1 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/gi/DisabledGIParameter.java @@ -0,0 +1,16 @@ +package org.sunflow.core.parameter.gi; + +import org.sunflow.SunflowAPIInterface; + +/** + * Disabled Global Illumination + */ +public class DisabledGIParameter extends GlobalIlluminationParameter { + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(GlobalIlluminationParameter.PARAM_ENGINE, GlobalIlluminationParameter.TYPE_NONE); + super.setup(api); + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/gi/FakeGIParameter.java b/src/main/java/org/sunflow/core/parameter/gi/FakeGIParameter.java new file mode 100644 index 0000000..4d7378f --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/gi/FakeGIParameter.java @@ -0,0 +1,48 @@ +package org.sunflow.core.parameter.gi; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; +import org.sunflow.math.Vector3; + +public class FakeGIParameter extends GlobalIlluminationParameter { + + public static final String PARAM_SKY = "gi.fake.sky"; + public static final String PARAM_GROUND = "gi.fake.ground"; + public static final String PARAM_UP = "gi.fake.up"; + Color ground; + Color sky; + Vector3 up; + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(GlobalIlluminationParameter.PARAM_ENGINE, GlobalIlluminationParameter.TYPE_FAKE); + api.parameter(PARAM_SKY, null, sky.getRGB()); + api.parameter(PARAM_GROUND, null, ground.getRGB()); + api.parameter(PARAM_UP, up); + super.setup(api); + } + + public Color getGround() { + return ground; + } + + public void setGround(Color ground) { + this.ground = ground; + } + + public Color getSky() { + return sky; + } + + public void setSky(Color sky) { + this.sky = sky; + } + + public Vector3 getUp() { + return up; + } + + public void setUp(Vector3 up) { + this.up = up; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/gi/GlobalIlluminationParameter.java b/src/main/java/org/sunflow/core/parameter/gi/GlobalIlluminationParameter.java new file mode 100644 index 0000000..55c6d96 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/gi/GlobalIlluminationParameter.java @@ -0,0 +1,27 @@ +package org.sunflow.core.parameter.gi; + +import org.sunflow.SunflowAPI; +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.parameter.Parameter; + +/** + * Global Illumination (GI) + */ +public class GlobalIlluminationParameter implements Parameter { + + public static final String PARAM_ENGINE = "gi.engine"; + + public static final String TYPE_AMBOCC = "ambocc"; + public static final String TYPE_FAKE = "fake"; + public static final String TYPE_IGI = "igi"; + public static final String TYPE_IRR_CACHE = "irr-cache"; + public static final String TYPE_PATH = "path"; + + + public static final String TYPE_NONE = "none"; + + @Override + public void setup(SunflowAPIInterface api) { + api.options(SunflowAPI.DEFAULT_OPTIONS); + } +} diff --git a/src/main/java/org/sunflow/core/parameter/gi/InstantGIParameter.java b/src/main/java/org/sunflow/core/parameter/gi/InstantGIParameter.java new file mode 100644 index 0000000..21bb9be --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/gi/InstantGIParameter.java @@ -0,0 +1,61 @@ +package org.sunflow.core.parameter.gi; + +import org.sunflow.SunflowAPIInterface; + +/** + * Instant Global Illumination + */ +public class InstantGIParameter extends GlobalIlluminationParameter { + + public static final String PARAM_SAMPLES = "gi.igi.samples"; + public static final String PARAM_SETS = "gi.igi.sets"; + public static final String PARAM_BIAS = "gi.igi.bias"; + public static final String PARAM_BIAS_SAMPLES = "gi.igi.bias_samples"; + + int samples; + int sets; + float bias; + int biasSamples; + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(GlobalIlluminationParameter.PARAM_ENGINE, GlobalIlluminationParameter.TYPE_IGI); + api.parameter(PARAM_SAMPLES, samples); + api.parameter(PARAM_SETS, sets); + api.parameter(PARAM_BIAS, bias); + api.parameter(PARAM_BIAS_SAMPLES, biasSamples); + super.setup(api); + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } + + public int getSets() { + return sets; + } + + public void setSets(int sets) { + this.sets = sets; + } + + public float getBias() { + return bias; + } + + public void setBias(float bias) { + this.bias = bias; + } + + public int getBiasSamples() { + return biasSamples; + } + + public void setBiasSamples(int biasSamples) { + this.biasSamples = biasSamples; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/gi/IrrCacheGIParameter.java b/src/main/java/org/sunflow/core/parameter/gi/IrrCacheGIParameter.java new file mode 100644 index 0000000..235fb7e --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/gi/IrrCacheGIParameter.java @@ -0,0 +1,83 @@ +package org.sunflow.core.parameter.gi; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.parameter.IlluminationParameter; + +/** + * Global Illumination Irradiance Cache + */ +public class IrrCacheGIParameter extends GlobalIlluminationParameter { + + public static final String PARAM_TOLERANCE = "gi.irr-cache.tolerance"; + public static final String PARAM_SAMPLES = "gi.irr-cache.samples"; + public static final String PARAM_MIN_SPACING = "gi.irr-cache.min_spacing"; + public static final String PARAM_MAX_SPACING = "gi.irr-cache.max_spacing"; + public static final String PARAM_GLOBAL_EMIT = "gi.irr-cache.gmap.emit"; + public static final String PARAM_GLOBAL = "gi.irr-cache.gmap"; + public static final String PARAM_GLOBAL_GATHER = "gi.irr-cache.gmap.gather"; + public static final String PARAM_GLOBAL_RADIUS = "gi.irr-cache.gmap.radius"; + + int samples = 0; + float tolerance; + float minSpacing; + float maxSpacing; + + IlluminationParameter global = null; + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(GlobalIlluminationParameter.PARAM_ENGINE, GlobalIlluminationParameter.TYPE_IRR_CACHE); + api.parameter(PARAM_SAMPLES, samples); + api.parameter(PARAM_TOLERANCE, tolerance); + api.parameter(PARAM_MIN_SPACING, minSpacing); + api.parameter(PARAM_MAX_SPACING, maxSpacing); + + if (global != null) { + api.parameter(PARAM_GLOBAL_EMIT, global.getEmit()); + api.parameter(PARAM_GLOBAL, global.getMap()); + api.parameter(PARAM_GLOBAL_GATHER, global.getGather()); + api.parameter(PARAM_GLOBAL_RADIUS, global.getRadius()); + } + super.setup(api); + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } + + public float getTolerance() { + return tolerance; + } + + public void setTolerance(float tolerance) { + this.tolerance = tolerance; + } + + public float getMinSpacing() { + return minSpacing; + } + + public void setMinSpacing(float minSpacing) { + this.minSpacing = minSpacing; + } + + public float getMaxSpacing() { + return maxSpacing; + } + + public void setMaxSpacing(float maxSpacing) { + this.maxSpacing = maxSpacing; + } + + public IlluminationParameter getGlobal() { + return global; + } + + public void setGlobal(IlluminationParameter global) { + this.global = global; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/gi/PathTracingGIParameter.java b/src/main/java/org/sunflow/core/parameter/gi/PathTracingGIParameter.java new file mode 100644 index 0000000..0847acb --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/gi/PathTracingGIParameter.java @@ -0,0 +1,25 @@ +package org.sunflow.core.parameter.gi; + +import org.sunflow.SunflowAPIInterface; + +public class PathTracingGIParameter extends GlobalIlluminationParameter { + + public static final String PARAM_SAMPLES = "gi.path.samples"; + + int samples; + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(GlobalIlluminationParameter.PARAM_ENGINE, GlobalIlluminationParameter.TYPE_PATH); + api.parameter(PARAM_SAMPLES, samples); + super.setup(api); + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/light/CornellBoxLightParameter.java b/src/main/java/org/sunflow/core/parameter/light/CornellBoxLightParameter.java new file mode 100644 index 0000000..f02061c --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/light/CornellBoxLightParameter.java @@ -0,0 +1,113 @@ +package org.sunflow.core.parameter.light; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; + +public class CornellBoxLightParameter extends LightParameter { + + public static final String PARAM_MIN_CORNER = "corner0"; + public static final String PARAM_MAX_CORNER = "corner1"; + public static final String PARAM_LEFT_COLOR = "leftColor"; + public static final String PARAM_RIGHT_COLOR = "rightColor"; + public static final String PARAM_TOP_COLOR = "topColor"; + public static final String PARAM_BOTTOM_COLOR = "bottomColor"; + public static final String PARAM_BACK_COLOR = "backColor"; + + int samples; + Point3 min; + Point3 max; + Color left, right, top, bottom, back; + Color radiance; + + public CornellBoxLightParameter() { + generateUniqueName("cornellbox"); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_MIN_CORNER, min); + api.parameter(PARAM_MAX_CORNER, max); + api.parameter(PARAM_LEFT_COLOR, null, left.getRGB()); + api.parameter(PARAM_RIGHT_COLOR, null, right.getRGB()); + api.parameter(PARAM_TOP_COLOR, null, top.getRGB()); + api.parameter(PARAM_BOTTOM_COLOR, null, bottom.getRGB()); + api.parameter(PARAM_BACK_COLOR, null, back.getRGB()); + api.parameter(PARAM_RADIANCE, null, radiance.getRGB()); + api.parameter(PARAM_SAMPLES, samples); + + api.light(name, TYPE_CORNELL_BOX); + } + + public Point3 getMin() { + return min; + } + + public void setMin(Point3 min) { + this.min = min; + } + + public Point3 getMax() { + return max; + } + + public void setMax(Point3 max) { + this.max = max; + } + + public Color getLeft() { + return left; + } + + public void setLeft(Color left) { + this.left = left; + } + + public Color getRight() { + return right; + } + + public void setRight(Color right) { + this.right = right; + } + + public Color getTop() { + return top; + } + + public void setTop(Color top) { + this.top = top; + } + + public Color getBottom() { + return bottom; + } + + public void setBottom(Color bottom) { + this.bottom = bottom; + } + + public Color getBack() { + return back; + } + + public void setBack(Color back) { + this.back = back; + } + + public Color getRadiance() { + return radiance; + } + + public void setRadiance(Color radiance) { + this.radiance = radiance; + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/light/DirectionalLightParameter.java b/src/main/java/org/sunflow/core/parameter/light/DirectionalLightParameter.java new file mode 100644 index 0000000..707227c --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/light/DirectionalLightParameter.java @@ -0,0 +1,68 @@ +package org.sunflow.core.parameter.light; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.light.DirectionalSpotlight; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class DirectionalLightParameter extends LightParameter { + + public static final String PARAM_SOURCE = "source"; + public static final String PARAM_DIRECTION = "dir"; + public static final String PARAM_RADIUS = "radius"; + + DirectionalSpotlight light; + + public DirectionalLightParameter() { + light = new DirectionalSpotlight(); + generateUniqueName("directional"); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_SOURCE, light.getSource()); + api.parameter(PARAM_DIRECTION, light.getDirection()); + api.parameter(PARAM_RADIUS, light.getR()); + api.parameter(PARAM_RADIANCE, null, light.getRadiance().getRGB()); + api.light(name, LightParameter.TYPE_DIRECTIONAL); + } + + public Point3 getSource() { + return light.getSource(); + } + + public void setSource(Point3 source) { + light.setSource(source); + } + + public Vector3 getDirection() { + return light.getDirection(); + } + + public void setDirection(Point3 target) { + Vector3 direction = Point3.sub(target, light.getSource(), new Vector3()); + light.setDirection(direction); + } + + public void setDirection(Vector3 direction) { + light.setDirection(direction); + } + + public float getRadius() { + return light.getR(); + } + + public void setRadius(float r) { + light.setR(r); + } + + public Color getRadiance() { + return light.getRadiance(); + } + + public void setRadiance(Color radiance) { + light.setRadiance(radiance); + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/light/ImageBasedLightParameter.java b/src/main/java/org/sunflow/core/parameter/light/ImageBasedLightParameter.java new file mode 100644 index 0000000..93a9f88 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/light/ImageBasedLightParameter.java @@ -0,0 +1,86 @@ +package org.sunflow.core.parameter.light; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.math.Vector3; + +public class ImageBasedLightParameter extends LightParameter { + + public static final String PARAM_CENTER = "center"; + public static final String PARAM_UP = "up"; + public static final String PARAM_FIXED = "fixed"; + public static final String PARAM_TEXTURE = "texture"; + public static final String PARAM_LOW_SAMPLES = "lowsamples"; + int samples; + int lowSamples = 0; + + String texture = ""; + Vector3 center; + Vector3 up; + boolean fixed; + + public ImageBasedLightParameter() { + generateUniqueName("ibl"); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_TEXTURE, texture); + api.parameter(PARAM_CENTER, center); + api.parameter(PARAM_UP, up); + api.parameter(PARAM_FIXED, fixed); + api.parameter(PARAM_SAMPLES, samples); + + if (lowSamples == 0) { + api.parameter(PARAM_LOW_SAMPLES, samples); + } + api.light(name, TYPE_IMAGE_BASED); + } + + public String getTexture() { + return texture; + } + + public void setTexture(String texture) { + this.texture = texture; + } + + public Vector3 getCenter() { + return center; + } + + public void setCenter(Vector3 center) { + this.center = center; + } + + public Vector3 getUp() { + return up; + } + + public void setUp(Vector3 up) { + this.up = up; + } + + public boolean isFixed() { + return fixed; + } + + public void setFixed(boolean fixed) { + this.fixed = fixed; + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } + + public int getLowSamples() { + return lowSamples; + } + + public void setLowSamples(int lowSamples) { + this.lowSamples = lowSamples; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/light/LightParameter.java b/src/main/java/org/sunflow/core/parameter/light/LightParameter.java new file mode 100644 index 0000000..00a5767 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/light/LightParameter.java @@ -0,0 +1,34 @@ +package org.sunflow.core.parameter.light; + +import org.sunflow.core.parameter.Parameter; + +public abstract class LightParameter implements Parameter { + + public static final String PARAM_RADIANCE = "radiance"; + public static final String PARAM_SAMPLES = "samples"; + + public static final String TYPE_CORNELL_BOX = "cornell_box"; + public static final String TYPE_DIRECTIONAL = "directional"; + public static final String TYPE_IMAGE_BASED = "ibl"; + public static final String TYPE_POINTLIGHT = "point"; + public static final String TYPE_SPHERE = "sphere"; + public static final String TYPE_SUNSKY = "sunsky"; + public static final String TYPE_TRIANGLE_MESH = "triangle_mesh"; + + private static int count = 0; + protected String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + protected void generateUniqueName(String prefix) { + name = prefix + count; + count++; + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/light/PointLightParameter.java b/src/main/java/org/sunflow/core/parameter/light/PointLightParameter.java new file mode 100644 index 0000000..a18828a --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/light/PointLightParameter.java @@ -0,0 +1,42 @@ +package org.sunflow.core.parameter.light; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.light.PointLight; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; + +public class PointLightParameter extends LightParameter { + + public static final String PARAM_CENTER = "center"; + public static final String PARAM_POWER = "power"; + private PointLight light; + + public PointLightParameter() { + light = new PointLight(); + generateUniqueName("pointlight"); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_CENTER, getCenter()); + api.parameter(PARAM_POWER, null, getColor().getRGB()); + api.light(name, LightParameter.TYPE_POINTLIGHT); + } + + public Point3 getCenter() { + return light.getLightPoint(); + } + + public void setCenter(Point3 lightPoint) { + light.setLightPoint(lightPoint); + } + + public Color getColor() { + return light.getColor(); + } + + public void setColor(Color color) { + light.setColor(color); + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/light/SphereLightParameter.java b/src/main/java/org/sunflow/core/parameter/light/SphereLightParameter.java new file mode 100644 index 0000000..a295e2a --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/light/SphereLightParameter.java @@ -0,0 +1,68 @@ +package org.sunflow.core.parameter.light; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.light.SphereLight; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; + +public class SphereLightParameter extends LightParameter { + + public static final String PARAM_CENTER = "center"; + public static final String PARAM_RADIUS = "radius"; + private SphereLight light; + + public SphereLightParameter() { + light = new SphereLight(); + generateUniqueName("spherelight"); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(LightParameter.PARAM_RADIANCE, null, light.getRadiance().getRGB()); + api.parameter(PARAM_CENTER, light.getCenter()); + api.parameter(PARAM_RADIUS, light.getRadius()); + api.parameter(LightParameter.PARAM_SAMPLES, light.getNumSamples()); + api.light(name, LightParameter.TYPE_SPHERE); + } + + public Color getRadiance() { + return light.getRadiance(); + } + + public void setRadiance(Color radiance) { + light.setRadiance(radiance); + } + + public int getSamples() { + return light.getNumSamples(); + } + + public void setSamples(int numSamples) { + light.setNumSamples(numSamples); + } + + public Point3 getCenter() { + return light.getCenter(); + } + + public void setCenter(Point3 center) { + light.setCenter(center); + } + + public float getRadius() { + return light.getRadius(); + } + + public void setRadius(float radius) { + light.setRadius(radius); + } + + public float getR2() { + return light.getR2(); + } + + public void setR2(float r2) { + light.setR2(r2); + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/light/SunSkyLightParameter.java b/src/main/java/org/sunflow/core/parameter/light/SunSkyLightParameter.java new file mode 100644 index 0000000..0b7e092 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/light/SunSkyLightParameter.java @@ -0,0 +1,100 @@ +package org.sunflow.core.parameter.light; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; +import org.sunflow.math.Vector3; + +public class SunSkyLightParameter extends LightParameter { + + public static final String PARAM_TURBIDITY = "turbidity"; + public static final String PARAM_SUN_DIRECTION = "sundir"; + public static final String PARAM_EAST = "east"; + public static final String PARAM_UP = "up"; + public static final String PARAM_GROUND_EXTENDSKY = "ground.extendsky"; + public static final String PARAM_GROUND_COLOR = "ground.color"; + Vector3 up; + Vector3 east; + Vector3 sunDirection; + + float turbidity; + int samples; + boolean extendSky = false; + + Color groundColor = null; + + public SunSkyLightParameter() { + generateUniqueName("sunsky"); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_UP, up); + api.parameter(PARAM_EAST, east); + api.parameter(PARAM_SUN_DIRECTION, sunDirection); + api.parameter(PARAM_TURBIDITY, turbidity); + api.parameter(LightParameter.PARAM_SAMPLES, samples); + api.parameter(PARAM_GROUND_EXTENDSKY, extendSky); + + if (groundColor != null) { + api.parameter(PARAM_GROUND_COLOR, null, groundColor.getRGB()); + } + + api.light(name, TYPE_SUNSKY); + } + + public Vector3 getUp() { + return up; + } + + public void setUp(Vector3 up) { + this.up = up; + } + + public Vector3 getEast() { + return east; + } + + public void setEast(Vector3 east) { + this.east = east; + } + + public Vector3 getSunDirection() { + return sunDirection; + } + + public void setSunDirection(Vector3 sunDirection) { + this.sunDirection = sunDirection; + } + + public float getTurbidity() { + return turbidity; + } + + public void setTurbidity(float turbidity) { + this.turbidity = turbidity; + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } + + public boolean isExtendSky() { + return extendSky; + } + + public void setExtendSky(boolean extendSky) { + this.extendSky = extendSky; + } + + public Color getGroundColor() { + return groundColor; + } + + public void setGroundColor(Color groundColor) { + this.groundColor = groundColor; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/light/TriangleMeshLightParameter.java b/src/main/java/org/sunflow/core/parameter/light/TriangleMeshLightParameter.java new file mode 100644 index 0000000..0879c96 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/light/TriangleMeshLightParameter.java @@ -0,0 +1,60 @@ +package org.sunflow.core.parameter.light; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class TriangleMeshLightParameter extends LightParameter { + + public static final String PARAM_POINTS = "points"; + public static final String PARAM_TRIANGLES = "triangles"; + + int samples; + Color radiance; + float[] points; + int[] triangles; + + public TriangleMeshLightParameter() { + generateUniqueName("meshlight"); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter(PARAM_RADIANCE, null, radiance.getRGB()); + api.parameter(PARAM_SAMPLES, samples); + api.parameter(PARAM_POINTS, "point", "vertex", points); + api.parameter(PARAM_TRIANGLES, triangles); + api.light(name, TYPE_TRIANGLE_MESH); + } + + public Color getRadiance() { + return radiance; + } + + public void setRadiance(Color radiance) { + this.radiance = radiance; + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } + + public float[] getPoints() { + return points; + } + + public void setPoints(float[] points) { + this.points = points; + } + + public int[] getTriangles() { + return triangles; + } + + public void setTriangles(int[] triangles) { + this.triangles = triangles; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/modifier/BumpMapModifierParameter.java b/src/main/java/org/sunflow/core/parameter/modifier/BumpMapModifierParameter.java new file mode 100644 index 0000000..e21c98f --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/modifier/BumpMapModifierParameter.java @@ -0,0 +1,40 @@ +package org.sunflow.core.parameter.modifier; + +import org.sunflow.SunflowAPIInterface; + +public class BumpMapModifierParameter extends ModifierParameter { + + float scale; + String texture = ""; + + public BumpMapModifierParameter() { + + } + + public BumpMapModifierParameter(String name) { + this.name = name; + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter("texture", texture); + api.parameter("scale", scale); + api.modifier(name, TYPE_BUMP_MAP); + } + + public String getTexture() { + return texture; + } + + public void setTexture(String texture) { + this.texture = texture; + } + + public float getScale() { + return scale; + } + + public void setScale(float scale) { + this.scale = scale; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/modifier/ModifierParameter.java b/src/main/java/org/sunflow/core/parameter/modifier/ModifierParameter.java new file mode 100644 index 0000000..c55e4c6 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/modifier/ModifierParameter.java @@ -0,0 +1,20 @@ +package org.sunflow.core.parameter.modifier; + +import org.sunflow.core.parameter.Parameter; + +public abstract class ModifierParameter implements Parameter { + + public static final String TYPE_BUMP_MAP = "bump_map"; + public static final String TYPE_NORMAL_MAP = "normal_map"; + public static final String TYPE_PERLIN = "perlin"; + + protected String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/modifier/NormalMapModifierParameter.java b/src/main/java/org/sunflow/core/parameter/modifier/NormalMapModifierParameter.java new file mode 100644 index 0000000..913c088 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/modifier/NormalMapModifierParameter.java @@ -0,0 +1,30 @@ +package org.sunflow.core.parameter.modifier; + +import org.sunflow.SunflowAPIInterface; + +public class NormalMapModifierParameter extends ModifierParameter { + + String texture = ""; + + public NormalMapModifierParameter() { + + } + + public NormalMapModifierParameter(String name) { + this.name = name; + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter("texture", texture); + api.modifier(name, TYPE_NORMAL_MAP); + } + + public String getTexture() { + return texture; + } + + public void setTexture(String texture) { + this.texture = texture; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/modifier/PerlinModifierParameter.java b/src/main/java/org/sunflow/core/parameter/modifier/PerlinModifierParameter.java new file mode 100644 index 0000000..42f69e0 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/modifier/PerlinModifierParameter.java @@ -0,0 +1,42 @@ +package org.sunflow.core.parameter.modifier; + +import org.sunflow.SunflowAPIInterface; + +public class PerlinModifierParameter extends ModifierParameter { + + int function; + float size; + float scale; + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter("function", function); + api.parameter("size", size); + api.parameter("scale", scale); + api.modifier(name, TYPE_PERLIN); + } + + public int getFunction() { + return function; + } + + public void setFunction(int function) { + this.function = function; + } + + public float getSize() { + return size; + } + + public void setSize(float size) { + this.size = size; + } + + public float getScale() { + return scale; + } + + public void setScale(float scale) { + this.scale = scale; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/AmbientOcclusionShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/AmbientOcclusionShaderParameter.java new file mode 100644 index 0000000..f1c812b --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/AmbientOcclusionShaderParameter.java @@ -0,0 +1,80 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class AmbientOcclusionShaderParameter extends ShaderParameter { + + String texture = ""; + Color bright; + Color dark = null; + int samples = 1; + float maxDist = 1; + + public AmbientOcclusionShaderParameter(String name) { + super(name); + // Default values from AmbientOcclusionShader + bright = Color.WHITE; + dark = Color.BLACK; + samples = 32; + maxDist = Float.POSITIVE_INFINITY; + } + + @Override + public void setup(SunflowAPIInterface api) { + + if(dark!=null) { + api.parameter("dark", null, dark.getRGB()); + api.parameter("samples", samples); + api.parameter("maxdist", maxDist); + } + + if(texture.isEmpty()) { + api.parameter("bright", null, bright.getRGB()); + api.shader(name, TYPE_AMBIENT_OCCLUSION); + } else { + api.parameter("texture", texture); + api.shader(name, TYPE_TEXTURED_AMBIENT_OCCLUSION); + } + } + + public String getTexture() { + return texture; + } + + public void setTexture(String texture) { + this.texture = texture; + } + + public Color getBright() { + return bright; + } + + public void setBright(Color bright) { + this.bright = bright; + } + + public Color getDark() { + return dark; + } + + public void setDark(Color dark) { + this.dark = dark; + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } + + public float getMaxDist() { + return maxDist; + } + + public void setMaxDist(float maxDist) { + this.maxDist = maxDist; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/ConstantShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/ConstantShaderParameter.java new file mode 100644 index 0000000..bbae705 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/ConstantShaderParameter.java @@ -0,0 +1,28 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class ConstantShaderParameter extends ShaderParameter { + + private Color color; + + public ConstantShaderParameter(String name) { + super(name); + color = Color.WHITE; + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter("color", null, color.getRGB()); + api.shader(name, TYPE_CONSTANT); + } + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/DiffuseShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/DiffuseShaderParameter.java new file mode 100644 index 0000000..7eaaf0f --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/DiffuseShaderParameter.java @@ -0,0 +1,42 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class DiffuseShaderParameter extends ShaderParameter { + + String texture = ""; + Color diffuse; + + public DiffuseShaderParameter(String name) { + super(name); + diffuse = Color.WHITE; + } + + @Override + public void setup(SunflowAPIInterface api) { + if (texture.isEmpty()) { + api.parameter("diffuse", null, diffuse.getRGB()); + api.shader(name, TYPE_DIFFUSE); + } else { + api.parameter("texture", texture); + api.shader(name, TYPE_TEXTURED_DIFFUSE); + } + } + + public Color getDiffuse() { + return diffuse; + } + + public void setDiffuse(Color diffuse) { + this.diffuse = diffuse; + } + + public String getTexture() { + return texture; + } + + public void setTexture(String texture) { + this.texture = texture; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/GlassShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/GlassShaderParameter.java new file mode 100644 index 0000000..462a08c --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/GlassShaderParameter.java @@ -0,0 +1,62 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class GlassShaderParameter extends ShaderParameter { + + float eta; + Color color; + float absorptionDistance; + Color absorptionColor; + + public GlassShaderParameter(String name) { + super(name); + // Default values from GlassShader + eta = 1.3f; + color = Color.WHITE; + absorptionDistance = 0; // disabled by default + absorptionColor = Color.GRAY; // 50% absorbtion + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter("eta", eta); + api.parameter("color", null, color.getRGB()); + api.parameter("absorption.distance", absorptionDistance); + api.parameter("absorption.color", null, absorptionColor.getRGB()); + api.shader(name, TYPE_GLASS); + } + + public float getEta() { + return eta; + } + + public void setEta(float eta) { + this.eta = eta; + } + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + public float getAbsorptionDistance() { + return absorptionDistance; + } + + public void setAbsorptionDistance(float absorptionDistance) { + this.absorptionDistance = absorptionDistance; + } + + public Color getAbsorptionColor() { + return absorptionColor; + } + + public void setAbsorptionColor(Color absorptionColor) { + this.absorptionColor = absorptionColor; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/IDShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/IDShaderParameter.java new file mode 100644 index 0000000..1a357b6 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/IDShaderParameter.java @@ -0,0 +1,15 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; + +public class IDShaderParameter extends ShaderParameter { + + public IDShaderParameter(String name) { + super(name); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.shader(name, TYPE_SHOW_INSTANCE_ID); + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/MirrorShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/MirrorShaderParameter.java new file mode 100644 index 0000000..493cda0 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/MirrorShaderParameter.java @@ -0,0 +1,28 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class MirrorShaderParameter extends ShaderParameter { + + private Color color; + + public MirrorShaderParameter(String name) { + super(name); + color = Color.WHITE; + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter("color", null, color.getRGB()); + api.shader(name, TYPE_MIRROR); + } + + public Color getColor() { + return color; + } + + public void setReflection(Color color) { + this.color = color; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/PhongShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/PhongShaderParameter.java new file mode 100644 index 0000000..6e7efda --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/PhongShaderParameter.java @@ -0,0 +1,77 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class PhongShaderParameter extends ShaderParameter { + + String texture = ""; + Color diffuse; + Color specular; + float power; + int samples; + + public PhongShaderParameter(String name) { + super(name); + diffuse = Color.GRAY; + specular = Color.GRAY; + power = 20; + // Number of Rays + samples = 4; + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter("specular", null, specular.getRGB()); + api.parameter("power", power); + api.parameter("samples", samples); + + if (texture.isEmpty()) { + api.parameter("diffuse", null, diffuse.getRGB()); + api.shader(name, TYPE_PHONG); + } else { + api.parameter("texture", texture); + api.shader(name, TYPE_TEXTURED_PHONG); + } + } + + public Color getDiffuse() { + return diffuse; + } + + public void setDiffuse(Color diffuse) { + this.diffuse = diffuse; + } + + public String getTexture() { + return texture; + } + + public void setTexture(String texture) { + this.texture = texture; + } + + public Color getSpecular() { + return specular; + } + + public void setSpecular(Color specular) { + this.specular = specular; + } + + public float getPower() { + return power; + } + + public void setPower(float power) { + this.power = power; + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/ShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/ShaderParameter.java new file mode 100644 index 0000000..464e467 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/ShaderParameter.java @@ -0,0 +1,46 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.core.parameter.Parameter; + +public abstract class ShaderParameter implements Parameter { + + public static final String TYPE_AMBIENT_OCCLUSION = "ambient_occlusion"; + public static final String TYPE_TEXTURED_AMBIENT_OCCLUSION = "textured_ambient_occlusion"; + public static final String TYPE_CONSTANT = "constant"; + public static final String TYPE_DIFFUSE = "diffuse"; + public static final String TYPE_TEXTURED_DIFFUSE = "textured_diffuse"; + public static final String TYPE_GLASS = "glass"; + public static final String TYPE_MIRROR = "mirror"; + public static final String TYPE_PHONG = "phong"; + public static final String TYPE_TEXTURED_PHONG = "textured_phong"; + public static final String TYPE_SHINY_DIFFUSE = "shiny_diffuse"; + public static final String TYPE_TEXTURED_SHINY_DIFFUSE = "textured_shiny_diffuse"; + public static final String TYPE_UBER = "uber"; + public static final String TYPE_WARD = "ward"; + public static final String TYPE_SHOW_INSTANCE_ID = "show_instance_id"; + public static final String TYPE_TEXTURED_WARD = "textured_ward"; + public static final String TYPE_VIEW_CAUSTICS = "view_caustics"; + public static final String TYPE_VIEW_IRRADIANCE = "view_irradiance"; + public static final String TYPE_VIEW_GLOBAL = "view_global"; + public static final String TYPE_NONE = "none"; + + protected String name; + + public ShaderParameter() { + super(); + } + + public ShaderParameter(String name) { + super(); + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/ShinyShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/ShinyShaderParameter.java new file mode 100644 index 0000000..0da87b1 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/ShinyShaderParameter.java @@ -0,0 +1,58 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class ShinyShaderParameter extends ShaderParameter { + + String texture = ""; + Color diffuse; + float shininess; + + public ShinyShaderParameter(String name) { + super(name); + diffuse = Color.GRAY; + shininess = 0.5f; + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter("shiny", shininess); + + if (texture.isEmpty()) { + api.parameter("diffuse", null, diffuse.getRGB()); + api.shader(name, TYPE_SHINY_DIFFUSE); + } else { + api.parameter("texture", texture); + api.shader(name, TYPE_TEXTURED_SHINY_DIFFUSE); + } + } + + public String getTexture() { + return texture; + } + + public void setTexture(String texture) { + this.texture = texture; + } + + public Color getDiffuse() { + return diffuse; + } + + public void setDiffuse(Color diffuse) { + this.diffuse = diffuse; + } + + public float getShininess() { + return shininess; + } + + /** + * Refl parameter + * @param shininess + */ + public void setShininess(float shininess) { + this.shininess = shininess; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/UberShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/UberShaderParameter.java new file mode 100644 index 0000000..790948e --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/UberShaderParameter.java @@ -0,0 +1,111 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class UberShaderParameter extends ShaderParameter { + + Color diffuse; + float diffuseBlend; + String diffuseTexture; + + Color specular; + float specularBlend; + String specularTexture; + + int samples; + float glossyness; + + + public UberShaderParameter(String name) { + super(name); + // Default values from UberShader + diffuse = specular = Color.GRAY; + diffuseTexture = specularTexture = ""; + diffuseBlend = specularBlend = 1; + glossyness = 0; + samples = 4; + } + + @Override + public void setup(SunflowAPIInterface api) { + api.parameter("diffuse", null, diffuse.getRGB()); + if (!diffuseTexture.isEmpty()) { + api.parameter("diffuse.texture", diffuseTexture); + } + api.parameter("diffuse.blend", diffuseBlend); + api.parameter("specular", null, specular.getRGB()); + if (!specularTexture.isEmpty()) { + api.parameter("specular.texture", specularTexture); + } + api.parameter("specular.blend", specularBlend); + api.parameter("glossyness", glossyness); + api.parameter("samples", samples); + + api.shader(name, TYPE_UBER); + } + + public Color getDiffuse() { + return diffuse; + } + + public void setDiffuse(Color diffuse) { + this.diffuse = diffuse; + } + + public float getDiffuseBlend() { + return diffuseBlend; + } + + public void setDiffuseBlend(float diffuseBlend) { + this.diffuseBlend = diffuseBlend; + } + + public String getDiffuseTexture() { + return diffuseTexture; + } + + public void setDiffuseTexture(String diffuseTexture) { + this.diffuseTexture = diffuseTexture; + } + + public Color getSpecular() { + return specular; + } + + public void setSpecular(Color specular) { + this.specular = specular; + } + + public String getSpecularTexture() { + return specularTexture; + } + + public void setSpecularTexture(String specularTexture) { + this.specularTexture = specularTexture; + } + + public float getSpecularBlend() { + return specularBlend; + } + + public void setSpecularBlend(float specularBlend) { + this.specularBlend = specularBlend; + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } + + public float getGlossyness() { + return glossyness; + } + + public void setGlossyness(float glossyness) { + this.glossyness = glossyness; + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/ViewCausticsShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/ViewCausticsShaderParameter.java new file mode 100644 index 0000000..7a8b9a3 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/ViewCausticsShaderParameter.java @@ -0,0 +1,15 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; + +public class ViewCausticsShaderParameter extends ShaderParameter { + + public ViewCausticsShaderParameter(String name) { + super(name); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.shader(name, TYPE_VIEW_CAUSTICS); + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/ViewGlobalShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/ViewGlobalShaderParameter.java new file mode 100644 index 0000000..319cea9 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/ViewGlobalShaderParameter.java @@ -0,0 +1,15 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; + +public class ViewGlobalShaderParameter extends ShaderParameter { + + public ViewGlobalShaderParameter(String name) { + super(name); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.shader(name, TYPE_VIEW_GLOBAL); + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/ViewIrradianceShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/ViewIrradianceShaderParameter.java new file mode 100644 index 0000000..0cbf97f --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/ViewIrradianceShaderParameter.java @@ -0,0 +1,15 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; + +public class ViewIrradianceShaderParameter extends ShaderParameter { + + public ViewIrradianceShaderParameter(String name) { + super(name); + } + + @Override + public void setup(SunflowAPIInterface api) { + api.shader(name, TYPE_VIEW_IRRADIANCE); + } +} diff --git a/src/main/java/org/sunflow/core/parameter/shader/WardShaderParameter.java b/src/main/java/org/sunflow/core/parameter/shader/WardShaderParameter.java new file mode 100644 index 0000000..dd62b37 --- /dev/null +++ b/src/main/java/org/sunflow/core/parameter/shader/WardShaderParameter.java @@ -0,0 +1,84 @@ +package org.sunflow.core.parameter.shader; + +import org.sunflow.SunflowAPIInterface; +import org.sunflow.image.Color; + +public class WardShaderParameter extends ShaderParameter { + + + String texture = ""; + Color diffuse; + Color specular; + + int samples; + float roughnessX, roughnessY; + + public WardShaderParameter(String name) { + super(name); + } + + @Override + public void setup(SunflowAPIInterface api) { + + api.parameter("specular", null, specular.getRGB()); + api.parameter("roughnessX", roughnessX); + api.parameter("roughnessY", roughnessY); + api.parameter("samples", samples); + + if (texture.isEmpty()) { + api.parameter("diffuse", null, diffuse.getRGB()); + api.shader(name, TYPE_WARD); + } else { + api.parameter("texture", texture); + api.shader(name, TYPE_TEXTURED_WARD); + } + } + + public String getTexture() { + return texture; + } + + public void setTexture(String texture) { + this.texture = texture; + } + + public Color getDiffuse() { + return diffuse; + } + + public void setDiffuse(Color diffuse) { + this.diffuse = diffuse; + } + + public Color getSpecular() { + return specular; + } + + public void setSpecular(Color specular) { + this.specular = specular; + } + + public float getRoughnessX() { + return roughnessX; + } + + public void setRoughnessX(float roughnessX) { + this.roughnessX = roughnessX; + } + + public float getRoughnessY() { + return roughnessY; + } + + public void setRoughnessY(float roughnessY) { + this.roughnessY = roughnessY; + } + + public int getSamples() { + return samples; + } + + public void setSamples(int samples) { + this.samples = samples; + } +} diff --git a/src/org/sunflow/core/parser/RA2Parser.java b/src/main/java/org/sunflow/core/parser/RA2Parser.java similarity index 100% rename from src/org/sunflow/core/parser/RA2Parser.java rename to src/main/java/org/sunflow/core/parser/RA2Parser.java diff --git a/src/org/sunflow/core/parser/RA3Parser.java b/src/main/java/org/sunflow/core/parser/RA3Parser.java similarity index 100% rename from src/org/sunflow/core/parser/RA3Parser.java rename to src/main/java/org/sunflow/core/parser/RA3Parser.java diff --git a/src/org/sunflow/core/parser/SCAbstractParser.java b/src/main/java/org/sunflow/core/parser/SCAbstractParser.java similarity index 100% rename from src/org/sunflow/core/parser/SCAbstractParser.java rename to src/main/java/org/sunflow/core/parser/SCAbstractParser.java diff --git a/src/org/sunflow/core/parser/SCAsciiParser.java b/src/main/java/org/sunflow/core/parser/SCAsciiParser.java similarity index 100% rename from src/org/sunflow/core/parser/SCAsciiParser.java rename to src/main/java/org/sunflow/core/parser/SCAsciiParser.java diff --git a/src/org/sunflow/core/parser/SCBinaryParser.java b/src/main/java/org/sunflow/core/parser/SCBinaryParser.java similarity index 100% rename from src/org/sunflow/core/parser/SCBinaryParser.java rename to src/main/java/org/sunflow/core/parser/SCBinaryParser.java diff --git a/src/main/java/org/sunflow/core/parser/SCNewParser.java b/src/main/java/org/sunflow/core/parser/SCNewParser.java new file mode 100644 index 0000000..ad46f91 --- /dev/null +++ b/src/main/java/org/sunflow/core/parser/SCNewParser.java @@ -0,0 +1,1596 @@ +package org.sunflow.core.parser; + +import org.sunflow.PluginRegistry; +import org.sunflow.SunflowAPI; +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.SceneParser; +import org.sunflow.core.parameter.*; +import org.sunflow.core.parameter.camera.*; +import org.sunflow.core.parameter.geometry.*; +import org.sunflow.core.parameter.gi.*; +import org.sunflow.core.parameter.light.*; +import org.sunflow.core.parameter.modifier.BumpMapModifierParameter; +import org.sunflow.core.parameter.modifier.NormalMapModifierParameter; +import org.sunflow.core.parameter.modifier.PerlinModifierParameter; +import org.sunflow.core.parameter.shader.*; +import org.sunflow.image.Color; +import org.sunflow.image.ColorFactory; +import org.sunflow.image.ColorFactory.ColorSpecificationException; +import org.sunflow.math.Matrix4; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; +import org.sunflow.system.Parser; +import org.sunflow.system.Parser.ParserException; +import org.sunflow.system.Timer; +import org.sunflow.system.UI; +import org.sunflow.system.UI.Module; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.HashMap; + +/** + * This class provides a static method for loading files in the Sunflow scene + * file format. + */ +public class SCNewParser implements SceneParser { + private static int instanceCounter = 0; + private int instanceNumber; + private Parser p; + private int numLightSamples; + // used to generate unique names inside this parser + private HashMap objectNames; + + public SCNewParser() { + objectNames = new HashMap(); + instanceCounter++; + instanceNumber = instanceCounter; + } + + private String generateUniqueName(String prefix) { + // generate a unique name for this class: + int index = 1; + Integer value = objectNames.get(prefix); + if (value != null) { + index = value; + objectNames.put(prefix, index + 1); + } else { + objectNames.put(prefix, index + 1); + } + return String.format("@sc_%d::%s_%d", instanceNumber, prefix, index); + } + + public boolean parse(String filename, SunflowAPIInterface api) { + String localDir = new File(filename).getAbsoluteFile().getParentFile().getAbsolutePath(); + numLightSamples = 1; + Timer timer = new Timer(); + timer.start(); + UI.printInfo(Module.API, "Parsing \"%s\" ...", filename); + try { + p = new Parser(filename); + while (true) { + String token = p.getNextToken(); + if (token == null) + break; + if (token.equals("image")) { + UI.printInfo(Module.API, "Reading image settings ..."); + parseImageBlock(api); + } else if (token.equals("background")) { + UI.printInfo(Module.API, "Reading background ..."); + parseBackgroundBlock(api); + } else if (token.equals("accel")) { + UI.printInfo(Module.API, "Reading accelerator type ..."); + p.getNextToken(); + UI.printWarning(Module.API, "Setting accelerator type is not recommended - ignoring"); + } else if (token.equals("filter")) { + // Deprecated + UI.printInfo(Module.API, "Reading image filter type ..."); + parseFilter(api); + } else if (token.equals("bucket")) { + UI.printInfo(Module.API, "Reading bucket settings ..."); + parseBucketBlock(api); + } else if (token.equals("photons")) { + UI.printInfo(Module.API, "Reading photon settings ..."); + parsePhotonBlock(api); + } else if (token.equals("gi")) { + UI.printInfo(Module.API, "Reading global illumination settings ..."); + parseGIBlock(api); + } else if (token.equals("lightserver")) { + // Deprecated + UI.printInfo(Module.API, "Reading light server settings ..."); + parseLightserverBlock(api); + } else if (token.equals("trace-depths")) { + UI.printInfo(Module.API, "Reading trace depths ..."); + parseTraceBlock(api); + } else if (token.equals("camera")) { + parseCamera(api); + } else if (token.equals("shader")) { + if (!parseShader(api)) { + // Close before return + p.close(); + return false; + } + } else if (token.equals("modifier")) { + if (!parseModifier(api)) { + // Close before return + p.close(); + return false; + } + } else if (token.equals("override")) { + parseOverrideBlock(api); + } else if (token.equals("object")) { + parseObjectBlock(api); + } else if (token.equals("instance")) { + parseInstanceBlock(api); + } else if (token.equals("light")) { + parseLightBlock(api); + } else if (token.equals("texturepath")) { + String path = p.getNextToken(); + if (!new File(path).isAbsolute()) { + path = localDir + File.separator + path; + } + api.searchpath("texture", path); + } else if (token.equals("includepath")) { + String path = p.getNextToken(); + if (!new File(path).isAbsolute()) { + path = localDir + File.separator + path; + } + api.searchpath("include", path); + } else if (token.equals("include")) { + String file = p.getNextToken(); + UI.printInfo(Module.API, "Including: \"%s\" ...", file); + api.include(file); + } else + UI.printWarning(Module.API, "Unrecognized token %s", token); + } + p.close(); + } catch (ParserException e) { + UI.printError(Module.API, "%s", e.getMessage()); + e.printStackTrace(); + return false; + } catch (FileNotFoundException e) { + UI.printError(Module.API, "%s", e.getMessage()); + return false; + } catch (IOException e) { + UI.printError(Module.API, "%s", e.getMessage()); + return false; + } catch (ColorSpecificationException e) { + UI.printError(Module.API, "%s", e.getMessage()); + return false; + } + timer.end(); + UI.printInfo(Module.API, "Done parsing."); + UI.printInfo(Module.API, "Parsing time: %s", timer.toString()); + return true; + } + + private void parseBucketBlock(SunflowAPIInterface api) throws IOException { + BucketParameter bucket = new BucketParameter(); + bucket.setSize(p.getNextInt()); + bucket.setOrder(p.getNextToken()); + bucket.setup(api); + } + + private void parseImageBlock(SunflowAPIInterface api) throws IOException, ParserException { + ImageParameter image = new ImageParameter(); + + p.checkNextToken("{"); + if (p.peekNextToken("resolution")) { + image.setResolutionX(p.getNextInt()); + image.setResolutionY(p.getNextInt()); + } + if (p.peekNextToken("sampler")) + image.setSampler(p.getNextToken()); + if (p.peekNextToken("aa")) { + image.setAAMin(p.getNextInt()); + image.setAAMax(p.getNextInt()); + } + if (p.peekNextToken("samples")) { + image.setAASamples(p.getNextInt()); + } + if (p.peekNextToken("contrast")) { + image.setAAContrast(p.getNextFloat()); + } + if (p.peekNextToken("filter")) { + image.setFilter(p.getNextToken()); + } + if (p.peekNextToken("jitter")) { + image.setAAJitter(p.getNextBoolean()); + } + if (p.peekNextToken("show-aa")) { + UI.printWarning(Module.API, "Deprecated: show-aa ignored"); + p.getNextBoolean(); + } + if (p.peekNextToken("cache")) { + image.setAACache(p.getNextBoolean()); + } + if (p.peekNextToken("output")) { + UI.printWarning(Module.API, "Deprecated: output statement ignored"); + p.getNextToken(); + } + + image.setup(api); + p.checkNextToken("}"); + } + + private void parseBackgroundBlock(SunflowAPIInterface api) throws IOException, ParserException, ColorSpecificationException { + BackgroundParameter background = new BackgroundParameter(); + + p.checkNextToken("{"); + p.checkNextToken("color"); + + background.setColor(parseColor()); + background.setup(api); + + p.checkNextToken("}"); + } + + private void parseFilter(SunflowAPIInterface api) throws IOException, ParserException { + UI.printWarning(Module.API, "Deprecated keyword \"filter\" - set this option in the image block"); + String name = p.getNextToken(); + api.parameter("filter", name); + api.options(SunflowAPI.DEFAULT_OPTIONS); + boolean hasSizeParams = name.equals("box") || name.equals("gaussian") || name.equals("blackman-harris") || name.equals("sinc") || name.equals("triangle"); + if (hasSizeParams) { + p.getNextFloat(); + p.getNextFloat(); + } + } + + private void parsePhotonBlock(SunflowAPIInterface api) throws ParserException, IOException { + PhotonParameter photon = new PhotonParameter(); + + boolean globalEmit = false; + + p.checkNextToken("{"); + if (p.peekNextToken("emit")) { + UI.printWarning(Module.API, "Shared photon emit values are deprecated - specify number of photons to emit per map"); + photon.setNumEmit(p.getNextInt()); + globalEmit = true; + } + if (p.peekNextToken("global")) { + UI.printWarning(Module.API, "Global photon map setting belongs inside the gi block - ignoring"); + if (!globalEmit) { + p.getNextInt(); + } + p.getNextToken(); + p.getNextInt(); + p.getNextFloat(); + } + p.checkNextToken("caustics"); + if (!globalEmit) { + photon.setNumEmit(p.getNextInt()); + } + + photon.setCaustics(p.getNextToken()); + photon.setCausticsGather(p.getNextInt()); + photon.setCausticsRadius(p.getNextFloat()); + + photon.setup(api); + p.checkNextToken("}"); + } + + private void parseGIBlock(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException { + p.checkNextToken("{"); + p.checkNextToken("type"); + if (p.peekNextToken("irr-cache")) { + IrrCacheGIParameter gi = new IrrCacheGIParameter(); + + p.checkNextToken("samples"); + gi.setSamples(p.getNextInt()); + p.checkNextToken("tolerance"); + gi.setTolerance(p.getNextFloat()); + p.checkNextToken("spacing"); + gi.setMinSpacing(p.getNextFloat()); + gi.setMaxSpacing(p.getNextFloat()); + + // parse global photon map info + if (p.peekNextToken("global")) { + gi.setGlobal(new IlluminationParameter()); + gi.getGlobal().setEmit(p.getNextInt()); + gi.getGlobal().setMap(p.getNextToken()); + gi.getGlobal().setGather(p.getNextInt()); + gi.getGlobal().setRadius(p.getNextFloat()); + } + } else if (p.peekNextToken("path")) { + PathTracingGIParameter gi = new PathTracingGIParameter(); + + p.checkNextToken("samples"); + gi.setSamples(p.getNextInt()); + + if (p.peekNextToken("bounces")) { + UI.printWarning(Module.API, "Deprecated setting: bounces - use diffuse trace depth instead"); + p.getNextInt(); + } + + gi.setup(api); + } else if (p.peekNextToken("fake")) { + FakeGIParameter gi = new FakeGIParameter(); + + p.checkNextToken("up"); + gi.setUp(parseVector()); + p.checkNextToken("sky"); + gi.setSky(parseColor()); + p.checkNextToken("ground"); + gi.setGround(parseColor()); + + gi.setup(api); + } else if (p.peekNextToken("igi")) { + InstantGIParameter gi = new InstantGIParameter(); + + p.checkNextToken("samples"); + gi.setSamples(p.getNextInt()); + p.checkNextToken("sets"); + gi.setSets(p.getNextInt()); + + if (!p.peekNextToken("b")) { + p.checkNextToken("c"); + } + gi.setBias(p.getNextFloat()); + + p.checkNextToken("bias-samples"); + gi.setBiasSamples(p.getNextInt()); + + gi.setup(api); + } else if (p.peekNextToken("ambocc")) { + AmbientOcclusionGIParameter gi = new AmbientOcclusionGIParameter(); + + p.checkNextToken("bright"); + gi.setBright(parseColor()); + p.checkNextToken("dark"); + gi.setDark(parseColor()); + p.checkNextToken("samples"); + gi.setSamples(p.getNextInt()); + if (p.peekNextToken("maxdist")) { + gi.setMaxDist(p.getNextFloat()); + } + + gi.setup(api); + } else if (p.peekNextToken("none") || p.peekNextToken("null")) { + DisabledGIParameter gi = new DisabledGIParameter(); + // disable GI + gi.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized gi engine type \"%s\" - ignoring", p.getNextToken()); + } + api.options(SunflowAPI.DEFAULT_OPTIONS); + p.checkNextToken("}"); + } + + private void parseOverrideBlock(SunflowAPIInterface api) throws IOException { + OverrideParameter block = new OverrideParameter(); + + block.setShader(p.getNextToken()); + block.setPhotons(p.getNextBoolean()); + block.setup(api); + } + + private void parseLightserverBlock(SunflowAPIInterface api) throws ParserException, IOException { + p.checkNextToken("{"); + if (p.peekNextToken("shadows")) { + UI.printWarning(Module.API, "Deprecated: shadows setting ignored"); + p.getNextBoolean(); + } + if (p.peekNextToken("direct-samples")) { + UI.printWarning(Module.API, "Deprecated: use samples keyword in area light definitions"); + numLightSamples = p.getNextInt(); + } + if (p.peekNextToken("glossy-samples")) { + UI.printWarning(Module.API, "Deprecated: use samples keyword in glossy shader definitions"); + p.getNextInt(); + } + if (p.peekNextToken("max-depth")) { + UI.printWarning(Module.API, "Deprecated: max-depth setting - use trace-depths block instead"); + int d = p.getNextInt(); + api.parameter("depths.diffuse", 1); + api.parameter("depths.reflection", d - 1); + api.parameter("depths.refraction", 0); + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + if (p.peekNextToken("global")) { + UI.printWarning(Module.API, "Deprecated: global settings ignored - use photons block instead"); + p.getNextBoolean(); + p.getNextInt(); + p.getNextInt(); + p.getNextInt(); + p.getNextFloat(); + } + if (p.peekNextToken("caustics")) { + UI.printWarning(Module.API, "Deprecated: caustics settings ignored - use photons block instead"); + p.getNextBoolean(); + p.getNextInt(); + p.getNextFloat(); + p.getNextInt(); + p.getNextFloat(); + } + if (p.peekNextToken("irr-cache")) { + UI.printWarning(Module.API, "Deprecated: irradiance cache settings ignored - use gi block instead"); + p.getNextInt(); + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + } + p.checkNextToken("}"); + } + + private void parseTraceBlock(SunflowAPIInterface api) throws ParserException, IOException { + TraceDepthsParameter traceDepthsParameter = new TraceDepthsParameter(); + p.checkNextToken("{"); + if (p.peekNextToken("diff")) { + traceDepthsParameter.setDiffuse(p.getNextInt()); + } + if (p.peekNextToken("refl")) { + traceDepthsParameter.setReflection(p.getNextInt()); + } + if (p.peekNextToken("refr")) { + traceDepthsParameter.setRefraction(p.getNextInt()); + } + p.checkNextToken("}"); + + traceDepthsParameter.setup(api); + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + + private void parseCamera(SunflowAPIInterface api) throws ParserException, IOException { + p.checkNextToken("{"); + p.checkNextToken("type"); + String type = p.getNextToken(); + UI.printInfo(Module.API, "Reading %s camera ...", type); + + float shutterOpen = 0, shutterClose = 0; + + if (p.peekNextToken("shutter")) { + shutterOpen = p.getNextFloat(); + shutterClose = p.getNextFloat(); + } + parseCameraTransform(api); + String name = generateUniqueName("camera"); + if (type.equals(CameraParameter.TYPE_PINHOLE)) { + PinholeCameraParameter camera = new PinholeCameraParameter(); + camera.setName(name); + camera.setShutterOpen(shutterOpen); + camera.setShutterClose(shutterClose); + + p.checkNextToken("fov"); + camera.setFov(p.getNextFloat()); + p.checkNextToken("aspect"); + camera.setAspect(p.getNextFloat()); + + if (p.peekNextToken("shift")) { + camera.setShiftX(p.getNextFloat()); + camera.setShiftY(p.getNextFloat()); + } + camera.setup(api); + } else if (type.equals(CameraParameter.TYPE_THINLENS)) { + ThinLensCameraParameter camera = new ThinLensCameraParameter(); + camera.setName(name); + camera.setShutterOpen(shutterOpen); + camera.setShutterClose(shutterClose); + + p.checkNextToken("fov"); + camera.setFov(p.getNextFloat()); + p.checkNextToken("aspect"); + camera.setAspect(p.getNextFloat()); + if (p.peekNextToken("shift")) { + camera.setShiftX(p.getNextFloat()); + camera.setShiftY(p.getNextFloat()); + } + p.checkNextToken("fdist"); + camera.setFocusDistance(p.getNextFloat()); + p.checkNextToken("lensr"); + camera.setLensRadius(p.getNextFloat()); + if (p.peekNextToken("sides")) { + camera.setLensSides(p.getNextInt()); + } + if (p.peekNextToken("rotation")) { + camera.setLensRotation(p.getNextFloat()); + } + camera.setup(api); + } else if (type.equals(CameraParameter.TYPE_SPHERICAL)) { + SphericalCameraParameter camera = new SphericalCameraParameter(); + camera.setName(name); + camera.setShutterOpen(shutterOpen); + camera.setShutterClose(shutterClose); + // no extra arguments + camera.setup(api); + } else if (type.equals(CameraParameter.TYPE_FISH_EYE)) { + FishEyeCameraParameter camera = new FishEyeCameraParameter(); + camera.setName(name); + camera.setShutterOpen(shutterOpen); + camera.setShutterClose(shutterClose); + // no extra arguments + camera.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized camera type: %s", p.getNextToken()); + p.checkNextToken("}"); + return; + } + p.checkNextToken("}"); + /*if (name != null) { + api.parameter("camera", name); + api.options(SunflowAPI.DEFAULT_OPTIONS); + }*/ + } + + private void parseCameraTransform(SunflowAPIInterface api) throws ParserException, IOException { + if (p.peekNextToken("steps")) { + // motion blur camera + int n = p.getNextInt(); + api.parameter("transform.steps", n); + // parse time extents + p.checkNextToken("times"); + float t0 = p.getNextFloat(); + float t1 = p.getNextFloat(); + api.parameter("transform.times", "float", "none", new float[]{t0, t1}); + for (int i = 0; i < n; i++) { + parseCameraMatrix(i, api); + } + } else { + parseCameraMatrix(-1, api); + } + } + + private void parseCameraMatrix(int index, SunflowAPIInterface api) throws IOException, ParserException { + String offset = index < 0 ? "" : String.format("[%d]", index); + if (p.peekNextToken("transform")) { + // advanced camera + api.parameter(String.format("transform%s", offset), parseMatrix()); + } else { + if (index >= 0) { + p.checkNextToken("{"); + } + // regular camera specification + p.checkNextToken("eye"); + Point3 eye = parsePoint(); + p.checkNextToken("target"); + Point3 target = parsePoint(); + p.checkNextToken("up"); + Vector3 up = parseVector(); + + // TODO Move logic to camera + api.parameter(String.format("transform%s", offset), Matrix4.lookAt(eye, target, up)); + if (index >= 0) { + p.checkNextToken("}"); + } + } + } + + private boolean parseShader(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException { + p.checkNextToken("{"); + p.checkNextToken("name"); + String name = p.getNextToken(); + UI.printInfo(Module.API, "Reading shader: %s ...", name); + p.checkNextToken("type"); + if (p.peekNextToken("diffuse")) { + DiffuseShaderParameter shader = new DiffuseShaderParameter(name); + + if (p.peekNextToken("diff")) { + shader.setDiffuse(parseColor()); + } else if (p.peekNextToken("texture")) { + shader.setTexture(p.getNextToken()); + } else { + UI.printWarning(Module.API, "Unrecognized option in diffuse shader block: %s", p.getNextToken()); + } + shader.setup(api); + } else if (p.peekNextToken("phong")) { + PhongShaderParameter shaderParameter = new PhongShaderParameter(name); + if (p.peekNextToken("texture")) { + shaderParameter.setTexture(p.getNextToken()); + } else { + p.checkNextToken("diff"); + shaderParameter.setDiffuse(parseColor()); + } + p.checkNextToken("spec"); + shaderParameter.setSpecular(parseColor()); + shaderParameter.setPower(p.getNextFloat()); + + if (p.peekNextToken("samples")) { + shaderParameter.setSamples(p.getNextInt()); + } + shaderParameter.setup(api); + } else if (p.peekNextToken("amb-occ") || p.peekNextToken("amb-occ2")) { + AmbientOcclusionShaderParameter shaderParameter = new AmbientOcclusionShaderParameter(name); + + if (p.peekNextToken("diff") || p.peekNextToken("bright")) { + shaderParameter.setBright(parseColor()); + } else if (p.peekNextToken("texture")) { + shaderParameter.setTexture(p.getNextToken()); + } + + if (p.peekNextToken("dark")) { + shaderParameter.setDark(parseColor()); + p.checkNextToken("samples"); + shaderParameter.setSamples(p.getNextInt()); + p.checkNextToken("dist"); + shaderParameter.setMaxDist(p.getNextFloat()); + } + shaderParameter.setup(api); + } else if (p.peekNextToken("mirror")) { + MirrorShaderParameter shaderParameter = new MirrorShaderParameter(name); + p.checkNextToken("refl"); + shaderParameter.setReflection(parseColor()); + shaderParameter.setup(api); + } else if (p.peekNextToken("glass")) { + GlassShaderParameter shaderParameter = new GlassShaderParameter(name); + + p.checkNextToken("eta"); + shaderParameter.setEta(p.getNextFloat()); + p.checkNextToken("color"); + shaderParameter.setColor(parseColor()); + + if (p.peekNextToken("absorption.distance") || p.peekNextToken("absorbtion.distance")) { + shaderParameter.setAbsorptionDistance(p.getNextFloat()); + } + if (p.peekNextToken("absorption.color") || p.peekNextToken("absorbtion.color")) { + shaderParameter.setAbsorptionColor(parseColor()); + } + shaderParameter.setup(api); + } else if (p.peekNextToken("shiny")) { + ShinyShaderParameter shaderParameter = new ShinyShaderParameter(name); + + if (p.peekNextToken("texture")) { + shaderParameter.setTexture(p.getNextToken()); + } else { + p.checkNextToken("diff"); + shaderParameter.setDiffuse(parseColor()); + } + p.checkNextToken("refl"); + shaderParameter.setShininess(p.getNextFloat()); + shaderParameter.setup(api); + } else if (p.peekNextToken("ward")) { + WardShaderParameter shaderParameter = new WardShaderParameter(name); + + if (p.peekNextToken("texture")) { + shaderParameter.setTexture(p.getNextToken()); + } else { + p.checkNextToken("diff"); + shaderParameter.setDiffuse(parseColor()); + } + p.checkNextToken("spec"); + shaderParameter.setSpecular(parseColor()); + + p.checkNextToken("rough"); + shaderParameter.setRoughnessX(p.getNextFloat()); + shaderParameter.setRoughnessY(p.getNextFloat()); + + if (p.peekNextToken("samples")) { + shaderParameter.setSamples(p.getNextInt()); + } + shaderParameter.setup(api); + } else if (p.peekNextToken("view-caustics")) { + ViewCausticsShaderParameter shaderParameter = new ViewCausticsShaderParameter(name); + shaderParameter.setup(api); + } else if (p.peekNextToken("view-irradiance")) { + ViewIrradianceShaderParameter shaderParameter = new ViewIrradianceShaderParameter(name); + shaderParameter.setup(api); + } else if (p.peekNextToken("view-global")) { + ViewGlobalShaderParameter shaderParameter = new ViewGlobalShaderParameter(name); + shaderParameter.setup(api); + } else if (p.peekNextToken("constant")) { + ConstantShaderParameter shaderParameter = new ConstantShaderParameter(name); + // backwards compatibility -- peek only + p.peekNextToken("color"); + shaderParameter.setColor(parseColor()); + shaderParameter.setup(api); + } else if (p.peekNextToken("janino")) { + String typename = p.peekNextToken("typename") ? p.getNextToken() : PluginRegistry.shaderPlugins.generateUniqueName("janino_shader"); + if (!PluginRegistry.shaderPlugins.registerPlugin(typename, p.getNextCodeBlock())) + return false; + api.shader(name, typename); + } else if (p.peekNextToken("id")) { + IDShaderParameter shaderParameter = new IDShaderParameter(name); + shaderParameter.setup(api); + } else if (p.peekNextToken("uber")) { + UberShaderParameter shaderParameter = new UberShaderParameter(name); + + if (p.peekNextToken("diff")) { + shaderParameter.setDiffuse(parseColor()); + } + if (p.peekNextToken("diff.texture")) { + shaderParameter.setDiffuseTexture(p.getNextToken()); + } + if (p.peekNextToken("diff.blend")) { + shaderParameter.setDiffuseBlend(p.getNextFloat()); + } + if (p.peekNextToken("refl") || p.peekNextToken("spec")) { + shaderParameter.setSpecular(parseColor()); + } + if (p.peekNextToken("texture")) { + // deprecated + UI.printWarning(Module.API, "Deprecated uber shader parameter \"texture\" - please use \"diffuse.texture\" and \"diffuse.blend\" instead"); + shaderParameter.setDiffuseTexture(p.getNextToken()); + shaderParameter.setDiffuseBlend(p.getNextFloat()); + } + if (p.peekNextToken("spec.texture")) { + shaderParameter.setSpecularTexture(p.getNextToken()); + } + if (p.peekNextToken("spec.blend")) { + shaderParameter.setSpecularBlend(p.getNextFloat()); + } + if (p.peekNextToken("glossy")) { + shaderParameter.setGlossyness(p.getNextFloat()); + } + if (p.peekNextToken("samples")) { + shaderParameter.setSamples(p.getNextInt()); + } + shaderParameter.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized shader type: %s", p.getNextToken()); + } + p.checkNextToken("}"); + return true; + } + + private boolean parseModifier(SunflowAPIInterface api) throws ParserException, IOException { + p.checkNextToken("{"); + p.checkNextToken("name"); + String name = p.getNextToken(); + UI.printInfo(Module.API, "Reading modifier: %s ...", name); + p.checkNextToken("type"); + if (p.peekNextToken("bump")) { + BumpMapModifierParameter parameter = new BumpMapModifierParameter(); + parameter.setName(name); + p.checkNextToken("texture"); + parameter.setTexture(p.getNextToken()); + p.checkNextToken("scale"); + parameter.setScale(p.getNextFloat()); + parameter.setup(api); + } else if (p.peekNextToken("normalmap")) { + NormalMapModifierParameter parameter = new NormalMapModifierParameter(); + parameter.setName(name); + p.checkNextToken("texture"); + parameter.setTexture(p.getNextToken()); + parameter.setup(api); + } else if (p.peekNextToken("perlin")) { + PerlinModifierParameter parameter = new PerlinModifierParameter(); + p.checkNextToken("function"); + parameter.setFunction(p.getNextInt()); + p.checkNextToken("size"); + parameter.setSize(p.getNextFloat()); + p.checkNextToken("scale"); + parameter.setScale(p.getNextFloat()); + parameter.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized modifier type: %s", p.getNextToken()); + } + p.checkNextToken("}"); + return true; + } + + private void parseObjectBlock(SunflowAPIInterface api) throws ParserException, IOException { + p.checkNextToken("{"); + InstanceParameter instanceParameter = new InstanceParameter(); + + String name = ""; + String accel = ""; + + boolean noInstance = false; + //Matrix4[] transform = null; + //float transformTime0 = 0, transformTime1 = 0; + String[] shaders = null; + String[] modifiers = null; + if (p.peekNextToken("noinstance")) { + // this indicates that the geometry is to be created, but not + // instanced into the scene + noInstance = true; + } else { + // these are the parameters to be passed to the instance + if (p.peekNextToken("shaders")) { + int n = p.getNextInt(); + shaders = new String[n]; + for (int i = 0; i < n; i++) + shaders[i] = p.getNextToken(); + } else { + p.checkNextToken("shader"); + shaders = new String[]{p.getNextToken()}; + } + instanceParameter.shaders(shaders); + + if (p.peekNextToken("modifiers")) { + int n = p.getNextInt(); + modifiers = new String[n]; + for (int i = 0; i < n; i++) + modifiers[i] = p.getNextToken(); + } else if (p.peekNextToken("modifier")) { + modifiers = new String[]{p.getNextToken()}; + } + instanceParameter.modifiers(modifiers); + + // Can be null + TransformParameter transform = checkParseTransform(); + instanceParameter.transform(transform); + } + if (p.peekNextToken("accel")) { + accel = p.getNextToken(); + } + p.checkNextToken("type"); + String type = p.getNextToken(); + if (p.peekNextToken("name")) { + name = p.getNextToken(); + } else { + name = generateUniqueName(type); + } + + if (type.equals("mesh")) { + UI.printWarning(Module.API, "Deprecated object type: mesh"); + UI.printInfo(Module.API, "Reading mesh: %s ...", name); + + TriangleMeshParameter geometry = new TriangleMeshParameter(); + geometry.setName(name); + geometry.setAccel(accel); + geometry.setInstanceParameter(instanceParameter); + + int numVertices = p.getNextInt(); + int numTriangles = p.getNextInt(); + float[] points = new float[numVertices * 3]; + float[] normals = new float[numVertices * 3]; + float[] uvs = new float[numVertices * 2]; + for (int i = 0; i < numVertices; i++) { + p.checkNextToken("v"); + points[3 * i + 0] = p.getNextFloat(); + points[3 * i + 1] = p.getNextFloat(); + points[3 * i + 2] = p.getNextFloat(); + normals[3 * i + 0] = p.getNextFloat(); + normals[3 * i + 1] = p.getNextFloat(); + normals[3 * i + 2] = p.getNextFloat(); + uvs[2 * i + 0] = p.getNextFloat(); + uvs[2 * i + 1] = p.getNextFloat(); + } + int[] triangles = new int[numTriangles * 3]; + for (int i = 0; i < numTriangles; i++) { + p.checkNextToken("t"); + triangles[i * 3 + 0] = p.getNextInt(); + triangles[i * 3 + 1] = p.getNextInt(); + triangles[i * 3 + 2] = p.getNextInt(); + } + + geometry.setPoints(points); + geometry.setNormals(normals); + geometry.setUvs(uvs); + geometry.setTriangles(triangles); + geometry.setup(api); + } else if (type.equals("flat-mesh")) { + UI.printWarning(Module.API, "Deprecated object type: flat-mesh"); + UI.printInfo(Module.API, "Reading flat mesh: %s ...", name); + + TriangleMeshParameter geometry = new TriangleMeshParameter(); + geometry.setName(name); + geometry.setAccel(accel); + geometry.setInstanceParameter(instanceParameter); + + int numVertices = p.getNextInt(); + int numTriangles = p.getNextInt(); + float[] points = new float[numVertices * 3]; + float[] uvs = new float[numVertices * 2]; + for (int i = 0; i < numVertices; i++) { + p.checkNextToken("v"); + points[3 * i + 0] = p.getNextFloat(); + points[3 * i + 1] = p.getNextFloat(); + points[3 * i + 2] = p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + uvs[2 * i + 0] = p.getNextFloat(); + uvs[2 * i + 1] = p.getNextFloat(); + } + int[] triangles = new int[numTriangles * 3]; + for (int i = 0; i < numTriangles; i++) { + p.checkNextToken("t"); + triangles[i * 3 + 0] = p.getNextInt(); + triangles[i * 3 + 1] = p.getNextInt(); + triangles[i * 3 + 2] = p.getNextInt(); + } + + geometry.setPoints(points); + geometry.setUvs(uvs); + geometry.setTriangles(triangles); + geometry.setup(api); + } else if (type.equals("sphere")) { + UI.printInfo(Module.API, "Reading sphere ..."); + instanceParameter + .name(name + ".instance") + .geometry(name); + + SphereParameter geometry = new SphereParameter(); + geometry.setName(name); + geometry.setInstanceParameter(instanceParameter); + + if (instanceParameter.transform() == null && !noInstance) { + // legacy method of specifying transformation for spheres + p.checkNextToken("c"); + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + geometry.setCenter(new Point3(x, y, z)); + p.checkNextToken("r"); + float radius = p.getNextFloat(); + geometry.setRadius(radius); + + geometry.setup(api); + // disable future instancing - instance has already been created + noInstance = true; + } + } else if (type.equals("cylinder")) { + UI.printInfo(Module.API, "Reading cylinder ..."); + + CylinderParameter parameter = new CylinderParameter(); + parameter.setName(name); + parameter.setInstanceParameter(instanceParameter); + + parameter.setup(api); + } else if (type.equals("banchoff")) { + UI.printInfo(Module.API, "Reading banchoff ..."); + + BanchOffParameter parameter = new BanchOffParameter(); + parameter.setName(name); + parameter.setInstanceParameter(instanceParameter); + + parameter.setup(api); + } else if (type.equals("torus")) { + UI.printInfo(Module.API, "Reading torus ..."); + + TorusParameter geometry = new TorusParameter(); + geometry.setName(name); + geometry.setInstanceParameter(instanceParameter); + + p.checkNextToken("r"); + geometry.setRadiusInner(p.getNextFloat()); + geometry.setRadiusOuter(p.getNextFloat()); + geometry.setup(api); + } else if (type.equals("sphereflake")) { + UI.printInfo(Module.API, "Reading sphereflake ..."); + SphereFlakeParameter geometry = new SphereFlakeParameter(); + geometry.setName(name); + + if (p.peekNextToken("level")) { + geometry.setLevel(p.getNextInt()); + } + if (p.peekNextToken("axis")) { + geometry.setAxis(parseVector()); + } + if (p.peekNextToken("radius")) { + geometry.setRadius(p.getNextFloat()); + } + geometry.setup(api); + } else if (type.equals("plane")) { + UI.printInfo(Module.API, "Reading plane ..."); + PlaneParameter geometry = new PlaneParameter(); + geometry.setName(name); + p.checkNextToken("p"); + geometry.setCenter(parsePoint()); + if (p.peekNextToken("n")) { + geometry.setNormal(parseVector()); + } else { + p.checkNextToken("p"); + geometry.setPoint1(parsePoint()); + p.checkNextToken("p"); + geometry.setPoint2(parsePoint()); + } + geometry.setup(api); + } else if (type.equals("generic-mesh")) { + UI.printInfo(Module.API, "Reading generic mesh: %s ... ", name); + GenericMeshParameter geometry = new GenericMeshParameter(); + // parse vertices + p.checkNextToken("points"); + int np = p.getNextInt(); + float[] points = parseFloatArray(np * 3); + geometry.setPoints(points); + // parse triangle indices + p.checkNextToken("triangles"); + int nt = p.getNextInt(); + geometry.setTriangles(parseIntArray(nt * 3)); + // parse normals + p.checkNextToken("normals"); + if (p.peekNextToken("vertex")) { + geometry.setNormals(parseFloatArray(np * 3)); + } else if (p.peekNextToken("facevarying")) { + geometry.setFaceVaryingNormals(true); + geometry.setNormals(parseFloatArray(nt * 9)); + } else { + p.checkNextToken("none"); + } + + // parse texture coordinates + p.checkNextToken("uvs"); + if (p.peekNextToken("vertex")) { + geometry.setUvs(parseFloatArray(np * 2)); + } else if (p.peekNextToken("facevarying")) { + geometry.setFaceVaryingTextures(true); + geometry.setUvs(parseFloatArray(nt * 6)); + } else { + p.checkNextToken("none"); + } + if (p.peekNextToken("face_shaders")) { + geometry.setFaceShaders(parseIntArray(nt)); + } + geometry.setup(api); + } else if (type.equals("hair")) { + UI.printInfo(Module.API, "Reading hair curves: %s ... ", name); + HairParameter geometry = new HairParameter(); + p.checkNextToken("segments"); + geometry.setSegments(p.getNextInt()); + p.checkNextToken("width"); + geometry.setWidth(p.getNextFloat()); + p.checkNextToken("points"); + geometry.setPoints(parseFloatArray(p.getNextInt())); + geometry.setup(api); + } else if (type.equals("janino-tesselatable")) { + UI.printInfo(Module.API, "Reading procedural primitive: %s ... ", name); + String typename = p.peekNextToken("typename") ? p.getNextToken() : PluginRegistry.shaderPlugins.generateUniqueName("janino_shader"); + if (!PluginRegistry.tesselatablePlugins.registerPlugin(typename, p.getNextCodeBlock())) { + noInstance = true; + } else { + api.geometry(name, typename); + } + } else if (type.equals("teapot")) { + UI.printInfo(Module.API, "Reading teapot: %s ... ", name); + TeapotParameter geometry = new TeapotParameter(); + geometry.setName(name); + + if (p.peekNextToken("subdivs")) { + geometry.setSubdivs(p.getNextInt()); + } + if (p.peekNextToken("smooth")) { + geometry.setSmooth(p.getNextBoolean()); + } + geometry.setup(api); + } else if (type.equals("gumbo")) { + UI.printInfo(Module.API, "Reading gumbo: %s ... ", name); + GumboParameter geometry = new GumboParameter(); + geometry.setName(name); + + if (p.peekNextToken("subdivs")) { + geometry.setSubdivs(p.getNextInt()); + } + if (p.peekNextToken("smooth")) { + geometry.setSmooth(p.getNextBoolean()); + } + geometry.setup(api); + } else if (type.equals("julia")) { + UI.printInfo(Module.API, "Reading julia fractal: %s ... ", name); + JuliaParameter geometry = new JuliaParameter(); + geometry.setName(name); + if (p.peekNextToken("q")) { + geometry.setCw(p.getNextFloat()); + geometry.setCx(p.getNextFloat()); + geometry.setCy(p.getNextFloat()); + geometry.setCz(p.getNextFloat()); + } + if (p.peekNextToken("iterations")) { + geometry.setIterations(p.getNextInt()); + } + if (p.peekNextToken("epsilon")) { + geometry.setEpsilon(p.getNextFloat()); + } + geometry.setup(api); + } else if (type.equals("particles") || type.equals("dlasurface")) { + ParticlesParameter geometry = new ParticlesParameter(); + geometry.setName(name); + if (type.equals("dlasurface")) { + UI.printWarning(Module.API, "Deprecated object type: \"dlasurface\" - please use \"particles\" instead"); + } + float[] data; + if (p.peekNextToken("filename")) { + // FIXME: this code should be moved into an on demand loading + // primitive + String filename = p.getNextToken(); + boolean littleEndian = false; + if (p.peekNextToken("little_endian")) { + littleEndian = true; + } + UI.printInfo(Module.USER, "Loading particle file: %s", filename); + File file = new File(filename); + FileInputStream stream = new FileInputStream(filename); + MappedByteBuffer map = stream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()); + if (littleEndian) + map.order(ByteOrder.LITTLE_ENDIAN); + FloatBuffer buffer = map.asFloatBuffer(); + data = new float[buffer.capacity()]; + for (int i = 0; i < data.length; i++) { + data[i] = buffer.get(i); + } + stream.close(); + } else { + p.checkNextToken("points"); + int n = p.getNextInt(); + data = parseFloatArray(n * 3); // read 3n points + } + + geometry.setPoints(data); + + if (p.peekNextToken("num")) { + geometry.setNum(p.getNextInt()); + } else { + geometry.setNum(data.length / 3); + } + + p.checkNextToken("radius"); + geometry.setRadius(p.getNextFloat()); + geometry.setup(api); + } else if (type.equals("file-mesh")) { + UI.printInfo(Module.API, "Reading file mesh: %s ... ", name); + FileMeshParameter geometry = new FileMeshParameter(); + geometry.setName(name); + + p.checkNextToken("filename"); + geometry.setFilename(p.getNextToken()); + + if (p.peekNextToken("smooth_normals")) { + geometry.setSmoothNormals(p.getNextBoolean()); + } + geometry.setup(api); + } else if (type.equals("bezier-mesh")) { + UI.printInfo(Module.API, "Reading bezier mesh: %s ... ", name); + BezierMeshParameter geometry = new BezierMeshParameter(); + geometry.setName(name); + + p.checkNextToken("n"); + //int nu, nv; + + geometry.setNu(p.getNextInt()); + geometry.setNv(p.getNextInt()); + + if (p.peekNextToken("wrap")) { + geometry.setUwrap(p.getNextBoolean()); + geometry.setVwrap(p.getNextBoolean()); + } + p.checkNextToken("points"); + float[] points = new float[3 * geometry.getNu() * geometry.getNv()]; + for (int i = 0; i < points.length; i++) { + points[i] = p.getNextFloat(); + } + + geometry.setPoints(points); + + if (p.peekNextToken("subdivs")) { + geometry.setSubdivs(p.getNextInt()); + } + if (p.peekNextToken("smooth")) { + geometry.setSmooth(p.getNextBoolean()); + } + geometry.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized object type: %s", p.getNextToken()); + noInstance = true; + } + if (!noInstance) { + instanceParameter + .name(name + ".instance") + .geometry(name); + instanceParameter.setup(api); + + // create instance + /*api.parameter("shaders", shaders); + if (modifiers != null) + api.parameter("modifiers", modifiers); + if (transform != null && transform.length > 0) { + if (transform.length == 1) + api.parameter("transform", transform[0]); + else { + api.parameter("transform.steps", transform.length); + api.parameter("transform.times", "float", "none", new float[]{ + transformTime0, transformTime1}); + for (int i = 0; i < transform.length; i++) + api.parameter(String.format("transform[%d]", i), transform[i]); + } + } + api.instance(name + ".instance", name);*/ + } + p.checkNextToken("}"); + } + + private void parseInstanceBlock(SunflowAPIInterface api) throws ParserException, IOException { + InstanceParameter parameter = new InstanceParameter(); + p.checkNextToken("{"); + p.checkNextToken("name"); + parameter.name(p.getNextToken()); + UI.printInfo(Module.API, "Reading instance: %s ...", parameter.name()); + p.checkNextToken("geometry"); + parameter.geometry(p.getNextToken()); + + TransformParameter transformParameter = parseTransform(); + parameter.transform(transformParameter); + + String[] shaders; + if (p.peekNextToken("shaders")) { + int n = p.getNextInt(); + shaders = new String[n]; + for (int i = 0; i < n; i++) { + shaders[i] = p.getNextToken(); + } + } else { + p.checkNextToken("shader"); + shaders = new String[]{p.getNextToken()}; + } + parameter.shaders(shaders); + + String[] modifiers = null; + if (p.peekNextToken("modifiers")) { + int n = p.getNextInt(); + modifiers = new String[n]; + for (int i = 0; i < n; i++) { + modifiers[i] = p.getNextToken(); + } + } else if (p.peekNextToken("modifier")) { + modifiers = new String[]{p.getNextToken()}; + } + parameter.modifiers(modifiers); + parameter.setup(api); + + p.checkNextToken("}"); + } + + private TransformParameter parseTransform() throws ParserException, IOException { + TransformParameter transformParameter = new TransformParameter(); + p.checkNextToken("transform"); + if (p.peekNextToken("steps")) { + int n = p.getNextInt(); + + p.checkNextToken("times"); + float[] times = new float[n]; + for (int i = 0; i < n; i++) { + times[i] = p.getNextFloat(); + } + transformParameter.setTimes(times); + + Matrix4[] transforms = new Matrix4[n]; + for (int i = 0; i < n; i++) { + transforms[i] = parseMatrix(); + } + } else { + Matrix4[] transforms = new Matrix4[]{parseMatrix()}; + transformParameter.setTransforms(transforms); + } + return transformParameter; + } + + private TransformParameter checkParseTransform() throws ParserException, IOException { + TransformParameter transformParameter = new TransformParameter(); + if(p.peekNextToken("transform")) { + if (p.peekNextToken("steps")) { + int n = p.getNextInt(); + + p.checkNextToken("times"); + float[] times = new float[n]; + for (int i = 0; i < n; i++) { + times[i] = p.getNextFloat(); + } + transformParameter.setTimes(times); + + Matrix4[] transforms = new Matrix4[n]; + for (int i = 0; i < n; i++) { + transforms[i] = parseMatrix(); + } + } else { + Matrix4[] transforms = new Matrix4[]{parseMatrix()}; + transformParameter.setTransforms(transforms); + } + } else { + return null; + } + return transformParameter; + } + + private void parseLightBlock(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException { + p.checkNextToken("{"); + p.checkNextToken("type"); + if (p.peekNextToken("mesh")) { + UI.printWarning(Module.API, "Deprecated light type: mesh"); + p.checkNextToken("name"); + String name = p.getNextToken(); + UI.printInfo(Module.API, "Reading light mesh: %s ...", name); + p.checkNextToken("emit"); + api.parameter("radiance", null, parseColor().getRGB()); + int samples = numLightSamples; + if (p.peekNextToken("samples")) + samples = p.getNextInt(); + else + UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", samples); + api.parameter("samples", samples); + int numVertices = p.getNextInt(); + int numTriangles = p.getNextInt(); + float[] points = new float[3 * numVertices]; + int[] triangles = new int[3 * numTriangles]; + for (int i = 0; i < numVertices; i++) { + p.checkNextToken("v"); + points[3 * i + 0] = p.getNextFloat(); + points[3 * i + 1] = p.getNextFloat(); + points[3 * i + 2] = p.getNextFloat(); + // ignored + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + } + for (int i = 0; i < numTriangles; i++) { + p.checkNextToken("t"); + triangles[3 * i + 0] = p.getNextInt(); + triangles[3 * i + 1] = p.getNextInt(); + triangles[3 * i + 2] = p.getNextInt(); + } + api.parameter("points", "point", "vertex", points); + api.parameter("triangles", triangles); + api.light(name, "triangle_mesh"); + } else if (p.peekNextToken("point")) { + UI.printInfo(Module.API, "Reading point light ..."); + PointLightParameter light = new PointLightParameter(); + light.setName(generateUniqueName("pointlight")); + + Color color; + if (p.peekNextToken("color")) { + color = parseColor(); + p.checkNextToken("power"); + float power = p.getNextFloat(); + color.mul(power); + } else { + UI.printWarning(Module.API, "Deprecated color specification - please use color and power instead"); + p.checkNextToken("power"); + color = parseColor(); + } + light.setColor(color); + + p.checkNextToken("p"); + light.setCenter(parsePoint()); + light.setup(api); + } else if (p.peekNextToken("spherical")) { + UI.printInfo(Module.API, "Reading spherical light ..."); + SphereLightParameter light = new SphereLightParameter(); + light.setName(generateUniqueName("spherelight")); + p.checkNextToken("color"); + Color color = parseColor(); + p.checkNextToken("radiance"); + float power = p.getNextFloat(); + color.mul(power); + light.setRadiance(color); + p.checkNextToken("center"); + light.setCenter(parsePoint()); + p.checkNextToken("radius"); + light.setRadius(p.getNextFloat()); + p.checkNextToken("samples"); + light.setSamples(p.getNextInt()); + light.setup(api); + } else if (p.peekNextToken("directional")) { + UI.printInfo(Module.API, "Reading directional light ..."); + DirectionalLightParameter light = new DirectionalLightParameter(); + light.setName(generateUniqueName("dirlight")); + p.checkNextToken("source"); + light.setSource(parsePoint()); + p.checkNextToken("target"); + light.setDirection(parsePoint()); + p.checkNextToken("radius"); + light.setRadius(p.getNextFloat()); + p.checkNextToken("emit"); + Color color = parseColor(); + if (p.peekNextToken("intensity")) { + float power = p.getNextFloat(); + color.mul(power); + } else { + UI.printWarning(Module.API, "Deprecated color specification - please use emit and intensity instead"); + } + light.setRadiance(color); + light.setup(api); + } else if (p.peekNextToken("ibl")) { + UI.printInfo(Module.API, "Reading image based light ..."); + ImageBasedLightParameter light = new ImageBasedLightParameter(); + light.setName(generateUniqueName("ibl")); + p.checkNextToken("image"); + light.setTexture(p.getNextToken()); + p.checkNextToken("center"); + light.setCenter(parseVector()); + p.checkNextToken("up"); + light.setUp(parseVector()); + p.checkNextToken("lock"); + light.setFixed(p.getNextBoolean()); + + light.setSamples(numLightSamples); + + if (p.peekNextToken("samples")) { + light.setSamples(p.getNextInt()); + } else { + UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", numLightSamples); + } + + if (p.peekNextToken("lowsamples")) { + light.setLowSamples(p.getNextInt()); + } + + light.setup(api); + } else if (p.peekNextToken("meshlight")) { + p.checkNextToken("name"); + TriangleMeshLightParameter light = new TriangleMeshLightParameter(); + light.setName(p.getNextToken()); + + UI.printInfo(Module.API, "Reading meshlight: %s ...", light.getName()); + p.checkNextToken("emit"); + Color color = parseColor(); + if (p.peekNextToken("radiance")) { + float r = p.getNextFloat(); + color.mul(r); + } else { + UI.printWarning(Module.API, "Deprecated color specification - please use emit and radiance instead"); + } + light.setRadiance(color); + light.setSamples(numLightSamples); + + if (p.peekNextToken("samples")) { + light.setSamples(p.getNextInt()); + } else { + UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", light.getSamples()); + } + + // parse vertices + p.checkNextToken("points"); + int np = p.getNextInt(); + float[] points = parseFloatArray(np * 3); + light.setPoints(points); + + // parse triangle indices + p.checkNextToken("triangles"); + int nt = p.getNextInt(); + int[] triangles = parseIntArray(nt * 3); + light.setTriangles(triangles); + light.setup(api); + } else if (p.peekNextToken("sunsky")) { + SunSkyLightParameter light = new SunSkyLightParameter(); + light.setName(generateUniqueName("sunsky")); + p.checkNextToken("up"); + light.setUp(parseVector()); + p.checkNextToken("east"); + light.setEast(parseVector()); + p.checkNextToken("sundir"); + light.setSunDirection(parseVector()); + p.checkNextToken("turbidity"); + light.setTurbidity(p.getNextFloat()); + + // TODO Is possible not to have samples in sun sky? + // light.setSamples(numLightSamples); + if (p.peekNextToken("samples")) { + light.setSamples(p.getNextInt()); + } + + if (p.peekNextToken("ground.extendsky")) { + light.setExtendSky(p.getNextBoolean()); + } else if (p.peekNextToken("ground.color")) { + light.setGroundColor(parseColor()); + } + light.setup(api); + } else if (p.peekNextToken("cornellbox")) { + UI.printInfo(Module.API, "Reading cornell box ..."); + CornellBoxLightParameter light = new CornellBoxLightParameter(); + light.setName(generateUniqueName("cornellbox")); + + p.checkNextToken("corner0"); + light.setMin(parsePoint()); + p.checkNextToken("corner1"); + light.setMax(parsePoint()); + p.checkNextToken("left"); + light.setLeft(parseColor()); + p.checkNextToken("right"); + light.setRight(parseColor()); + p.checkNextToken("top"); + light.setTop(parseColor()); + p.checkNextToken("bottom"); + light.setBottom(parseColor()); + p.checkNextToken("back"); + light.setBack(parseColor()); + p.checkNextToken("emit"); + light.setRadiance(parseColor()); + + // TODO Is possible not to have samples in cornell box? + // light.setSamples(numLightSamples); + if (p.peekNextToken("samples")) { + light.setSamples(p.getNextInt()); + } + light.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized object type: %s", p.getNextToken()); + } + p.checkNextToken("}"); + } + + private Color parseColor() throws IOException, ParserException, ColorSpecificationException { + if (p.peekNextToken("{")) { + String space = p.getNextToken(); + int req = ColorFactory.getRequiredDataValues(space); + if (req == -2) { + UI.printWarning(Module.API, "Unrecognized color space: %s", space); + return null; + } else if (req == -1) { + // array required, parse how many values are required + req = p.getNextInt(); + } + Color c = ColorFactory.createColor(space, parseFloatArray(req)); + p.checkNextToken("}"); + return c; + } else { + float r = p.getNextFloat(); + float g = p.getNextFloat(); + float b = p.getNextFloat(); + return ColorFactory.createColor(null, r, g, b); + } + } + + private Point3 parsePoint() throws IOException { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + return new Point3(x, y, z); + } + + private Vector3 parseVector() throws IOException { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + return new Vector3(x, y, z); + } + + private int[] parseIntArray(int size) throws IOException { + int[] data = new int[size]; + for (int i = 0; i < size; i++) { + data[i] = p.getNextInt(); + } + return data; + } + + private float[] parseFloatArray(int size) throws IOException { + float[] data = new float[size]; + for (int i = 0; i < size; i++) { + data[i] = p.getNextFloat(); + } + return data; + } + + private Matrix4 parseMatrix() throws IOException, ParserException { + if (p.peekNextToken("row")) { + return new Matrix4(parseFloatArray(16), true); + } else if (p.peekNextToken("col")) { + return new Matrix4(parseFloatArray(16), false); + } else { + Matrix4 m = Matrix4.IDENTITY; + p.checkNextToken("{"); + while (!p.peekNextToken("}")) { + Matrix4 t = null; + if (p.peekNextToken("translate")) { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + t = Matrix4.translation(x, y, z); + } else if (p.peekNextToken("scaleu")) { + float s = p.getNextFloat(); + t = Matrix4.scale(s); + } else if (p.peekNextToken("scale")) { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + t = Matrix4.scale(x, y, z); + } else if (p.peekNextToken("rotatex")) { + float angle = p.getNextFloat(); + t = Matrix4.rotateX((float) Math.toRadians(angle)); + } else if (p.peekNextToken("rotatey")) { + float angle = p.getNextFloat(); + t = Matrix4.rotateY((float) Math.toRadians(angle)); + } else if (p.peekNextToken("rotatez")) { + float angle = p.getNextFloat(); + t = Matrix4.rotateZ((float) Math.toRadians(angle)); + } else if (p.peekNextToken("rotate")) { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + float angle = p.getNextFloat(); + t = Matrix4.rotate(x, y, z, (float) Math.toRadians(angle)); + } else + UI.printWarning(Module.API, "Unrecognized transformation type: %s", p.getNextToken()); + if (t != null) + m = t.multiply(m); + } + return m; + } + } +} \ No newline at end of file diff --git a/src/org/sunflow/core/parser/SCParser.java b/src/main/java/org/sunflow/core/parser/SCParser.java similarity index 55% rename from src/org/sunflow/core/parser/SCParser.java rename to src/main/java/org/sunflow/core/parser/SCParser.java index eee7286..7cdc01a 100644 --- a/src/org/sunflow/core/parser/SCParser.java +++ b/src/main/java/org/sunflow/core/parser/SCParser.java @@ -1,1284 +1,1587 @@ -package org.sunflow.core.parser; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; -import java.util.HashMap; - -import org.sunflow.PluginRegistry; -import org.sunflow.SunflowAPI; -import org.sunflow.SunflowAPIInterface; -import org.sunflow.core.SceneParser; -import org.sunflow.image.Color; -import org.sunflow.image.ColorFactory; -import org.sunflow.image.ColorFactory.ColorSpecificationException; -import org.sunflow.math.Matrix4; -import org.sunflow.math.Point3; -import org.sunflow.math.Vector3; -import org.sunflow.system.Parser; -import org.sunflow.system.Timer; -import org.sunflow.system.UI; -import org.sunflow.system.Parser.ParserException; -import org.sunflow.system.UI.Module; - -/** - * This class provides a static method for loading files in the Sunflow scene - * file format. - */ -public class SCParser implements SceneParser { - private static int instanceCounter = 0; - private int instanceNumber; - private Parser p; - private int numLightSamples; - // used to generate unique names inside this parser - private HashMap objectNames; - - public SCParser() { - objectNames = new HashMap(); - instanceCounter++; - instanceNumber = instanceCounter; - } - - private String generateUniqueName(String prefix) { - // generate a unique name for this class: - int index = 1; - Integer value = objectNames.get(prefix); - if (value != null) { - index = value; - objectNames.put(prefix, index + 1); - } else { - objectNames.put(prefix, index + 1); - } - return String.format("@sc_%d::%s_%d", instanceNumber, prefix, index); - } - - public boolean parse(String filename, SunflowAPIInterface api) { - String localDir = new File(filename).getAbsoluteFile().getParentFile().getAbsolutePath(); - numLightSamples = 1; - Timer timer = new Timer(); - timer.start(); - UI.printInfo(Module.API, "Parsing \"%s\" ...", filename); - try { - p = new Parser(filename); - while (true) { - String token = p.getNextToken(); - if (token == null) - break; - if (token.equals("image")) { - UI.printInfo(Module.API, "Reading image settings ..."); - parseImageBlock(api); - } else if (token.equals("background")) { - UI.printInfo(Module.API, "Reading background ..."); - parseBackgroundBlock(api); - } else if (token.equals("accel")) { - UI.printInfo(Module.API, "Reading accelerator type ..."); - p.getNextToken(); - UI.printWarning(Module.API, "Setting accelerator type is not recommended - ignoring"); - } else if (token.equals("filter")) { - UI.printInfo(Module.API, "Reading image filter type ..."); - parseFilter(api); - } else if (token.equals("bucket")) { - UI.printInfo(Module.API, "Reading bucket settings ..."); - api.parameter("bucket.size", p.getNextInt()); - api.parameter("bucket.order", p.getNextToken()); - api.options(SunflowAPI.DEFAULT_OPTIONS); - } else if (token.equals("photons")) { - UI.printInfo(Module.API, "Reading photon settings ..."); - parsePhotonBlock(api); - } else if (token.equals("gi")) { - UI.printInfo(Module.API, "Reading global illumination settings ..."); - parseGIBlock(api); - } else if (token.equals("lightserver")) { - UI.printInfo(Module.API, "Reading light server settings ..."); - parseLightserverBlock(api); - } else if (token.equals("trace-depths")) { - UI.printInfo(Module.API, "Reading trace depths ..."); - parseTraceBlock(api); - } else if (token.equals("camera")) { - parseCamera(api); - } else if (token.equals("shader")) { - if (!parseShader(api)) - return false; - } else if (token.equals("modifier")) { - if (!parseModifier(api)) - return false; - } else if (token.equals("override")) { - api.parameter("override.shader", p.getNextToken()); - api.parameter("override.photons", p.getNextBoolean()); - api.options(SunflowAPI.DEFAULT_OPTIONS); - } else if (token.equals("object")) { - parseObjectBlock(api); - } else if (token.equals("instance")) { - parseInstanceBlock(api); - } else if (token.equals("light")) { - parseLightBlock(api); - } else if (token.equals("texturepath")) { - String path = p.getNextToken(); - if (!new File(path).isAbsolute()) - path = localDir + File.separator + path; - api.searchpath("texture", path); - } else if (token.equals("includepath")) { - String path = p.getNextToken(); - if (!new File(path).isAbsolute()) - path = localDir + File.separator + path; - api.searchpath("include", path); - } else if (token.equals("include")) { - String file = p.getNextToken(); - UI.printInfo(Module.API, "Including: \"%s\" ...", file); - api.include(file); - } else - UI.printWarning(Module.API, "Unrecognized token %s", token); - } - p.close(); - } catch (ParserException e) { - UI.printError(Module.API, "%s", e.getMessage()); - e.printStackTrace(); - return false; - } catch (FileNotFoundException e) { - UI.printError(Module.API, "%s", e.getMessage()); - return false; - } catch (IOException e) { - UI.printError(Module.API, "%s", e.getMessage()); - return false; - } catch (ColorSpecificationException e) { - UI.printError(Module.API, "%s", e.getMessage()); - return false; - } - timer.end(); - UI.printInfo(Module.API, "Done parsing."); - UI.printInfo(Module.API, "Parsing time: %s", timer.toString()); - return true; - } - - private void parseImageBlock(SunflowAPIInterface api) throws IOException, ParserException { - p.checkNextToken("{"); - if (p.peekNextToken("resolution")) { - api.parameter("resolutionX", p.getNextInt()); - api.parameter("resolutionY", p.getNextInt()); - } - if (p.peekNextToken("sampler")) - api.parameter("sampler", p.getNextToken()); - if (p.peekNextToken("aa")) { - api.parameter("aa.min", p.getNextInt()); - api.parameter("aa.max", p.getNextInt()); - } - if (p.peekNextToken("samples")) - api.parameter("aa.samples", p.getNextInt()); - if (p.peekNextToken("contrast")) - api.parameter("aa.contrast", p.getNextFloat()); - if (p.peekNextToken("filter")) - api.parameter("filter", p.getNextToken()); - if (p.peekNextToken("jitter")) - api.parameter("aa.jitter", p.getNextBoolean()); - if (p.peekNextToken("show-aa")) { - UI.printWarning(Module.API, "Deprecated: show-aa ignored"); - p.getNextBoolean(); - } - if (p.peekNextToken("cache")) - api.parameter("aa.cache", p.getNextBoolean()); - if (p.peekNextToken("output")) { - UI.printWarning(Module.API, "Deprecated: output statement ignored"); - p.getNextToken(); - } - api.options(SunflowAPI.DEFAULT_OPTIONS); - p.checkNextToken("}"); - } - - private void parseBackgroundBlock(SunflowAPIInterface api) throws IOException, ParserException, ColorSpecificationException { - p.checkNextToken("{"); - p.checkNextToken("color"); - api.parameter("color", null, parseColor().getRGB()); - api.shader("background.shader", "constant"); - api.geometry("background", "background"); - api.parameter("shaders", "background.shader"); - api.instance("background.instance", "background"); - p.checkNextToken("}"); - } - - private void parseFilter(SunflowAPIInterface api) throws IOException, ParserException { - UI.printWarning(Module.API, "Deprecated keyword \"filter\" - set this option in the image block"); - String name = p.getNextToken(); - api.parameter("filter", name); - api.options(SunflowAPI.DEFAULT_OPTIONS); - boolean hasSizeParams = name.equals("box") || name.equals("gaussian") || name.equals("blackman-harris") || name.equals("sinc") || name.equals("triangle"); - if (hasSizeParams) { - p.getNextFloat(); - p.getNextFloat(); - } - } - - private void parsePhotonBlock(SunflowAPIInterface api) throws ParserException, IOException { - int numEmit = 0; - boolean globalEmit = false; - p.checkNextToken("{"); - if (p.peekNextToken("emit")) { - UI.printWarning(Module.API, "Shared photon emit values are deprectated - specify number of photons to emit per map"); - numEmit = p.getNextInt(); - globalEmit = true; - } - if (p.peekNextToken("global")) { - UI.printWarning(Module.API, "Global photon map setting belonds inside the gi block - ignoring"); - if (!globalEmit) - p.getNextInt(); - p.getNextToken(); - p.getNextInt(); - p.getNextFloat(); - } - p.checkNextToken("caustics"); - if (!globalEmit) - numEmit = p.getNextInt(); - api.parameter("caustics.emit", numEmit); - api.parameter("caustics", p.getNextToken()); - api.parameter("caustics.gather", p.getNextInt()); - api.parameter("caustics.radius", p.getNextFloat()); - api.options(SunflowAPI.DEFAULT_OPTIONS); - p.checkNextToken("}"); - } - - private void parseGIBlock(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException { - p.checkNextToken("{"); - p.checkNextToken("type"); - if (p.peekNextToken("irr-cache")) { - api.parameter("gi.engine", "irr-cache"); - p.checkNextToken("samples"); - api.parameter("gi.irr-cache.samples", p.getNextInt()); - p.checkNextToken("tolerance"); - api.parameter("gi.irr-cache.tolerance", p.getNextFloat()); - p.checkNextToken("spacing"); - api.parameter("gi.irr-cache.min_spacing", p.getNextFloat()); - api.parameter("gi.irr-cache.max_spacing", p.getNextFloat()); - // parse global photon map info - if (p.peekNextToken("global")) { - api.parameter("gi.irr-cache.gmap.emit", p.getNextInt()); - api.parameter("gi.irr-cache.gmap", p.getNextToken()); - api.parameter("gi.irr-cache.gmap.gather", p.getNextInt()); - api.parameter("gi.irr-cache.gmap.radius", p.getNextFloat()); - } - } else if (p.peekNextToken("path")) { - api.parameter("gi.engine", "path"); - p.checkNextToken("samples"); - api.parameter("gi.path.samples", p.getNextInt()); - if (p.peekNextToken("bounces")) { - UI.printWarning(Module.API, "Deprecated setting: bounces - use diffuse trace depth instead"); - p.getNextInt(); - } - } else if (p.peekNextToken("fake")) { - api.parameter("gi.engine", "fake"); - p.checkNextToken("up"); - api.parameter("gi.fake.up", parseVector()); - p.checkNextToken("sky"); - api.parameter("gi.fake.sky", null, parseColor().getRGB()); - p.checkNextToken("ground"); - api.parameter("gi.fake.ground", null, parseColor().getRGB()); - } else if (p.peekNextToken("igi")) { - api.parameter("gi.engine", "igi"); - p.checkNextToken("samples"); - api.parameter("gi.igi.samples", p.getNextInt()); - p.checkNextToken("sets"); - api.parameter("gi.igi.sets", p.getNextInt()); - if (!p.peekNextToken("b")) - p.checkNextToken("c"); - api.parameter("gi.igi.c", p.getNextFloat()); - p.checkNextToken("bias-samples"); - api.parameter("gi.igi.bias_samples", p.getNextInt()); - } else if (p.peekNextToken("ambocc")) { - api.parameter("gi.engine", "ambocc"); - p.checkNextToken("bright"); - api.parameter("gi.ambocc.bright", null, parseColor().getRGB()); - p.checkNextToken("dark"); - api.parameter("gi.ambocc.dark", null, parseColor().getRGB()); - p.checkNextToken("samples"); - api.parameter("gi.ambocc.samples", p.getNextInt()); - if (p.peekNextToken("maxdist")) - api.parameter("gi.ambocc.maxdist", p.getNextFloat()); - } else if (p.peekNextToken("none") || p.peekNextToken("null")) { - // disable GI - api.parameter("gi.engine", "none"); - } else - UI.printWarning(Module.API, "Unrecognized gi engine type \"%s\" - ignoring", p.getNextToken()); - api.options(SunflowAPI.DEFAULT_OPTIONS); - p.checkNextToken("}"); - } - - private void parseLightserverBlock(SunflowAPIInterface api) throws ParserException, IOException { - p.checkNextToken("{"); - if (p.peekNextToken("shadows")) { - UI.printWarning(Module.API, "Deprecated: shadows setting ignored"); - p.getNextBoolean(); - } - if (p.peekNextToken("direct-samples")) { - UI.printWarning(Module.API, "Deprecated: use samples keyword in area light definitions"); - numLightSamples = p.getNextInt(); - } - if (p.peekNextToken("glossy-samples")) { - UI.printWarning(Module.API, "Deprecated: use samples keyword in glossy shader definitions"); - p.getNextInt(); - } - if (p.peekNextToken("max-depth")) { - UI.printWarning(Module.API, "Deprecated: max-depth setting - use trace-depths block instead"); - int d = p.getNextInt(); - api.parameter("depths.diffuse", 1); - api.parameter("depths.reflection", d - 1); - api.parameter("depths.refraction", 0); - api.options(SunflowAPI.DEFAULT_OPTIONS); - } - if (p.peekNextToken("global")) { - UI.printWarning(Module.API, "Deprecated: global settings ignored - use photons block instead"); - p.getNextBoolean(); - p.getNextInt(); - p.getNextInt(); - p.getNextInt(); - p.getNextFloat(); - } - if (p.peekNextToken("caustics")) { - UI.printWarning(Module.API, "Deprecated: caustics settings ignored - use photons block instead"); - p.getNextBoolean(); - p.getNextInt(); - p.getNextFloat(); - p.getNextInt(); - p.getNextFloat(); - } - if (p.peekNextToken("irr-cache")) { - UI.printWarning(Module.API, "Deprecated: irradiance cache settings ignored - use gi block instead"); - p.getNextInt(); - p.getNextFloat(); - p.getNextFloat(); - p.getNextFloat(); - } - p.checkNextToken("}"); - } - - private void parseTraceBlock(SunflowAPIInterface api) throws ParserException, IOException { - p.checkNextToken("{"); - if (p.peekNextToken("diff")) - api.parameter("depths.diffuse", p.getNextInt()); - if (p.peekNextToken("refl")) - api.parameter("depths.reflection", p.getNextInt()); - if (p.peekNextToken("refr")) - api.parameter("depths.refraction", p.getNextInt()); - p.checkNextToken("}"); - api.options(SunflowAPI.DEFAULT_OPTIONS); - } - - private void parseCamera(SunflowAPIInterface api) throws ParserException, IOException { - p.checkNextToken("{"); - p.checkNextToken("type"); - String type = p.getNextToken(); - UI.printInfo(Module.API, "Reading %s camera ...", type); - if (p.peekNextToken("shutter")) { - api.parameter("shutter.open", p.getNextFloat()); - api.parameter("shutter.close", p.getNextFloat()); - } - parseCameraTransform(api); - String name = generateUniqueName("camera"); - if (type.equals("pinhole")) { - p.checkNextToken("fov"); - api.parameter("fov", p.getNextFloat()); - p.checkNextToken("aspect"); - api.parameter("aspect", p.getNextFloat()); - if (p.peekNextToken("shift")) { - api.parameter("shift.x", p.getNextFloat()); - api.parameter("shift.y", p.getNextFloat()); - } - api.camera(name, "pinhole"); - } else if (type.equals("thinlens")) { - p.checkNextToken("fov"); - api.parameter("fov", p.getNextFloat()); - p.checkNextToken("aspect"); - api.parameter("aspect", p.getNextFloat()); - if (p.peekNextToken("shift")) { - api.parameter("shift.x", p.getNextFloat()); - api.parameter("shift.y", p.getNextFloat()); - } - p.checkNextToken("fdist"); - api.parameter("focus.distance", p.getNextFloat()); - p.checkNextToken("lensr"); - api.parameter("lens.radius", p.getNextFloat()); - if (p.peekNextToken("sides")) - api.parameter("lens.sides", p.getNextInt()); - if (p.peekNextToken("rotation")) - api.parameter("lens.rotation", p.getNextFloat()); - api.camera(name, "thinlens"); - } else if (type.equals("spherical")) { - // no extra arguments - api.camera(name, "spherical"); - } else if (type.equals("fisheye")) { - // no extra arguments - api.camera(name, "fisheye"); - } else { - UI.printWarning(Module.API, "Unrecognized camera type: %s", p.getNextToken()); - p.checkNextToken("}"); - return; - } - p.checkNextToken("}"); - if (name != null) { - api.parameter("camera", name); - api.options(SunflowAPI.DEFAULT_OPTIONS); - } - } - - private void parseCameraTransform(SunflowAPIInterface api) throws ParserException, IOException { - if (p.peekNextToken("steps")) { - // motion blur camera - int n = p.getNextInt(); - api.parameter("transform.steps", n); - // parse time extents - p.checkNextToken("times"); - float t0 = p.getNextFloat(); - float t1 = p.getNextFloat(); - api.parameter("transform.times", "float", "none", new float[] { t0, - t1 }); - for (int i = 0; i < n; i++) - parseCameraMatrix(i, api); - } else - parseCameraMatrix(-1, api); - } - - private void parseCameraMatrix(int index, SunflowAPIInterface api) throws IOException, ParserException { - String offset = index < 0 ? "" : String.format("[%d]", index); - if (p.peekNextToken("transform")) { - // advanced camera - api.parameter(String.format("transform%s", offset), parseMatrix()); - } else { - if (index >= 0) - p.checkNextToken("{"); - // regular camera specification - p.checkNextToken("eye"); - Point3 eye = parsePoint(); - p.checkNextToken("target"); - Point3 target = parsePoint(); - p.checkNextToken("up"); - Vector3 up = parseVector(); - api.parameter(String.format("transform%s", offset), Matrix4.lookAt(eye, target, up)); - if (index >= 0) - p.checkNextToken("}"); - } - } - - private boolean parseShader(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException { - p.checkNextToken("{"); - p.checkNextToken("name"); - String name = p.getNextToken(); - UI.printInfo(Module.API, "Reading shader: %s ...", name); - p.checkNextToken("type"); - if (p.peekNextToken("diffuse")) { - if (p.peekNextToken("diff")) { - api.parameter("diffuse", null, parseColor().getRGB()); - api.shader(name, "diffuse"); - } else if (p.peekNextToken("texture")) { - api.parameter("texture", p.getNextToken()); - api.shader(name, "textured_diffuse"); - } else - UI.printWarning(Module.API, "Unrecognized option in diffuse shader block: %s", p.getNextToken()); - } else if (p.peekNextToken("phong")) { - String tex = null; - if (p.peekNextToken("texture")) - api.parameter("texture", tex = p.getNextToken()); - else { - p.checkNextToken("diff"); - api.parameter("diffuse", null, parseColor().getRGB()); - } - p.checkNextToken("spec"); - api.parameter("specular", null, parseColor().getRGB()); - api.parameter("power", p.getNextFloat()); - if (p.peekNextToken("samples")) - api.parameter("samples", p.getNextInt()); - if (tex != null) - api.shader(name, "textured_phong"); - else - api.shader(name, "phong"); - } else if (p.peekNextToken("amb-occ") || p.peekNextToken("amb-occ2")) { - String tex = null; - if (p.peekNextToken("diff") || p.peekNextToken("bright")) - api.parameter("bright", null, parseColor().getRGB()); - else if (p.peekNextToken("texture")) - api.parameter("texture", tex = p.getNextToken()); - if (p.peekNextToken("dark")) { - api.parameter("dark", null, parseColor().getRGB()); - p.checkNextToken("samples"); - api.parameter("samples", p.getNextInt()); - p.checkNextToken("dist"); - api.parameter("maxdist", p.getNextFloat()); - } - if (tex == null) - api.shader(name, "ambient_occlusion"); - else - api.shader(name, "textured_ambient_occlusion"); - } else if (p.peekNextToken("mirror")) { - p.checkNextToken("refl"); - api.parameter("color", null, parseColor().getRGB()); - api.shader(name, "mirror"); - } else if (p.peekNextToken("glass")) { - p.checkNextToken("eta"); - api.parameter("eta", p.getNextFloat()); - p.checkNextToken("color"); - api.parameter("color", null, parseColor().getRGB()); - if (p.peekNextToken("absorption.distance") || p.peekNextToken("absorbtion.distance")) - api.parameter("absorption.distance", p.getNextFloat()); - if (p.peekNextToken("absorption.color") || p.peekNextToken("absorbtion.color")) - api.parameter("absorption.color", null, parseColor().getRGB()); - api.shader(name, "glass"); - } else if (p.peekNextToken("shiny")) { - String tex = null; - if (p.peekNextToken("texture")) - api.parameter("texture", tex = p.getNextToken()); - else { - p.checkNextToken("diff"); - api.parameter("diffuse", null, parseColor().getRGB()); - } - p.checkNextToken("refl"); - api.parameter("shiny", p.getNextFloat()); - if (tex == null) - api.shader(name, "shiny_diffuse"); - else - api.shader(name, "textured_shiny_diffuse"); - } else if (p.peekNextToken("ward")) { - String tex = null; - if (p.peekNextToken("texture")) - api.parameter("texture", tex = p.getNextToken()); - else { - p.checkNextToken("diff"); - api.parameter("diffuse", null, parseColor().getRGB()); - } - p.checkNextToken("spec"); - api.parameter("specular", null, parseColor().getRGB()); - p.checkNextToken("rough"); - api.parameter("roughnessX", p.getNextFloat()); - api.parameter("roughnessY", p.getNextFloat()); - if (p.peekNextToken("samples")) - api.parameter("samples", p.getNextInt()); - if (tex != null) - api.shader(name, "textured_ward"); - else - api.shader(name, "ward"); - } else if (p.peekNextToken("view-caustics")) { - api.shader(name, "view_caustics"); - } else if (p.peekNextToken("view-irradiance")) { - api.shader(name, "view_irradiance"); - } else if (p.peekNextToken("view-global")) { - api.shader(name, "view_global"); - } else if (p.peekNextToken("constant")) { - // backwards compatibility -- peek only - p.peekNextToken("color"); - api.parameter("color", null, parseColor().getRGB()); - api.shader(name, "constant"); - } else if (p.peekNextToken("janino")) { - String typename = p.peekNextToken("typename") ? p.getNextToken() : PluginRegistry.shaderPlugins.generateUniqueName("janino_shader"); - if (!PluginRegistry.shaderPlugins.registerPlugin(typename, p.getNextCodeBlock())) - return false; - api.shader(name, typename); - } else if (p.peekNextToken("id")) { - api.shader(name, "show_instance_id"); - } else if (p.peekNextToken("uber")) { - if (p.peekNextToken("diff")) - api.parameter("diffuse", null, parseColor().getRGB()); - if (p.peekNextToken("diff.texture")) - api.parameter("diffuse.texture", p.getNextToken()); - if (p.peekNextToken("diff.blend")) - api.parameter("diffuse.blend", p.getNextFloat()); - if (p.peekNextToken("refl") || p.peekNextToken("spec")) - api.parameter("specular", null, parseColor().getRGB()); - if (p.peekNextToken("texture")) { - // deprecated - UI.printWarning(Module.API, "Deprecated uber shader parameter \"texture\" - please use \"diffuse.texture\" and \"diffuse.blend\" instead"); - api.parameter("diffuse.texture", p.getNextToken()); - api.parameter("diffuse.blend", p.getNextFloat()); - } - if (p.peekNextToken("spec.texture")) - api.parameter("specular.texture", p.getNextToken()); - if (p.peekNextToken("spec.blend")) - api.parameter("specular.blend", p.getNextFloat()); - if (p.peekNextToken("glossy")) - api.parameter("glossyness", p.getNextFloat()); - if (p.peekNextToken("samples")) - api.parameter("samples", p.getNextInt()); - api.shader(name, "uber"); - } else - UI.printWarning(Module.API, "Unrecognized shader type: %s", p.getNextToken()); - p.checkNextToken("}"); - return true; - } - - private boolean parseModifier(SunflowAPIInterface api) throws ParserException, IOException { - p.checkNextToken("{"); - p.checkNextToken("name"); - String name = p.getNextToken(); - UI.printInfo(Module.API, "Reading modifier: %s ...", name); - p.checkNextToken("type"); - if (p.peekNextToken("bump")) { - p.checkNextToken("texture"); - api.parameter("texture", p.getNextToken()); - p.checkNextToken("scale"); - api.parameter("scale", p.getNextFloat()); - api.modifier(name, "bump_map"); - } else if (p.peekNextToken("normalmap")) { - p.checkNextToken("texture"); - api.parameter("texture", p.getNextToken()); - api.modifier(name, "normal_map"); - } else if (p.peekNextToken("perlin")) { - p.checkNextToken("function"); - api.parameter("function", p.getNextInt()); - p.checkNextToken("size"); - api.parameter("size", p.getNextFloat()); - p.checkNextToken("scale"); - api.parameter("scale", p.getNextFloat()); - api.modifier(name, "perlin"); - } else { - UI.printWarning(Module.API, "Unrecognized modifier type: %s", p.getNextToken()); - } - p.checkNextToken("}"); - return true; - } - - private void parseObjectBlock(SunflowAPIInterface api) throws ParserException, IOException { - p.checkNextToken("{"); - boolean noInstance = false; - Matrix4[] transform = null; - float transformTime0 = 0, transformTime1 = 0; - String name = null; - String[] shaders = null; - String[] modifiers = null; - if (p.peekNextToken("noinstance")) { - // this indicates that the geometry is to be created, but not - // instanced into the scene - noInstance = true; - } else { - // these are the parameters to be passed to the instance - if (p.peekNextToken("shaders")) { - int n = p.getNextInt(); - shaders = new String[n]; - for (int i = 0; i < n; i++) - shaders[i] = p.getNextToken(); - } else { - p.checkNextToken("shader"); - shaders = new String[] { p.getNextToken() }; - } - if (p.peekNextToken("modifiers")) { - int n = p.getNextInt(); - modifiers = new String[n]; - for (int i = 0; i < n; i++) - modifiers[i] = p.getNextToken(); - } else if (p.peekNextToken("modifier")) - modifiers = new String[] { p.getNextToken() }; - if (p.peekNextToken("transform")) { - if (p.peekNextToken("steps")) { - transform = new Matrix4[p.getNextInt()]; - p.checkNextToken("times"); - transformTime0 = p.getNextFloat(); - transformTime1 = p.getNextFloat(); - for (int i = 0; i < transform.length; i++) - transform[i] = parseMatrix(); - } else - transform = new Matrix4[] { parseMatrix() }; - } - } - if (p.peekNextToken("accel")) - api.parameter("accel", p.getNextToken()); - p.checkNextToken("type"); - String type = p.getNextToken(); - if (p.peekNextToken("name")) - name = p.getNextToken(); - else - name = generateUniqueName(type); - if (type.equals("mesh")) { - UI.printWarning(Module.API, "Deprecated object type: mesh"); - UI.printInfo(Module.API, "Reading mesh: %s ...", name); - int numVertices = p.getNextInt(); - int numTriangles = p.getNextInt(); - float[] points = new float[numVertices * 3]; - float[] normals = new float[numVertices * 3]; - float[] uvs = new float[numVertices * 2]; - for (int i = 0; i < numVertices; i++) { - p.checkNextToken("v"); - points[3 * i + 0] = p.getNextFloat(); - points[3 * i + 1] = p.getNextFloat(); - points[3 * i + 2] = p.getNextFloat(); - normals[3 * i + 0] = p.getNextFloat(); - normals[3 * i + 1] = p.getNextFloat(); - normals[3 * i + 2] = p.getNextFloat(); - uvs[2 * i + 0] = p.getNextFloat(); - uvs[2 * i + 1] = p.getNextFloat(); - } - int[] triangles = new int[numTriangles * 3]; - for (int i = 0; i < numTriangles; i++) { - p.checkNextToken("t"); - triangles[i * 3 + 0] = p.getNextInt(); - triangles[i * 3 + 1] = p.getNextInt(); - triangles[i * 3 + 2] = p.getNextInt(); - } - // create geometry - api.parameter("triangles", triangles); - api.parameter("points", "point", "vertex", points); - api.parameter("normals", "vector", "vertex", normals); - api.parameter("uvs", "texcoord", "vertex", uvs); - api.geometry(name, "triangle_mesh"); - } else if (type.equals("flat-mesh")) { - UI.printWarning(Module.API, "Deprecated object type: flat-mesh"); - UI.printInfo(Module.API, "Reading flat mesh: %s ...", name); - int numVertices = p.getNextInt(); - int numTriangles = p.getNextInt(); - float[] points = new float[numVertices * 3]; - float[] uvs = new float[numVertices * 2]; - for (int i = 0; i < numVertices; i++) { - p.checkNextToken("v"); - points[3 * i + 0] = p.getNextFloat(); - points[3 * i + 1] = p.getNextFloat(); - points[3 * i + 2] = p.getNextFloat(); - p.getNextFloat(); - p.getNextFloat(); - p.getNextFloat(); - uvs[2 * i + 0] = p.getNextFloat(); - uvs[2 * i + 1] = p.getNextFloat(); - } - int[] triangles = new int[numTriangles * 3]; - for (int i = 0; i < numTriangles; i++) { - p.checkNextToken("t"); - triangles[i * 3 + 0] = p.getNextInt(); - triangles[i * 3 + 1] = p.getNextInt(); - triangles[i * 3 + 2] = p.getNextInt(); - } - // create geometry - api.parameter("triangles", triangles); - api.parameter("points", "point", "vertex", points); - api.parameter("uvs", "texcoord", "vertex", uvs); - api.geometry(name, "triangle_mesh"); - } else if (type.equals("sphere")) { - UI.printInfo(Module.API, "Reading sphere ..."); - api.geometry(name, "sphere"); - if (transform == null && !noInstance) { - // legacy method of specifying transformation for spheres - p.checkNextToken("c"); - float x = p.getNextFloat(); - float y = p.getNextFloat(); - float z = p.getNextFloat(); - p.checkNextToken("r"); - float radius = p.getNextFloat(); - api.parameter("transform", Matrix4.translation(x, y, z).multiply(Matrix4.scale(radius))); - api.parameter("shaders", shaders); - if (modifiers != null) - api.parameter("modifiers", modifiers); - api.instance(name + ".instance", name); - // disable future instancing - instance has already been created - noInstance = true; - } - } else if (type.equals("cylinder")) { - UI.printInfo(Module.API, "Reading cylinder ..."); - api.geometry(name, "cylinder"); - } else if (type.equals("banchoff")) { - UI.printInfo(Module.API, "Reading banchoff ..."); - api.geometry(name, "banchoff"); - } else if (type.equals("torus")) { - UI.printInfo(Module.API, "Reading torus ..."); - p.checkNextToken("r"); - api.parameter("radiusInner", p.getNextFloat()); - api.parameter("radiusOuter", p.getNextFloat()); - api.geometry(name, "torus"); - } else if (type.equals("sphereflake")) { - UI.printInfo(Module.API, "Reading sphereflake ..."); - if (p.peekNextToken("level")) - api.parameter("level", p.getNextInt()); - if (p.peekNextToken("axis")) - api.parameter("axis", parseVector()); - if (p.peekNextToken("radius")) - api.parameter("radius", p.getNextFloat()); - api.geometry(name, "sphereflake"); - } else if (type.equals("plane")) { - UI.printInfo(Module.API, "Reading plane ..."); - p.checkNextToken("p"); - api.parameter("center", parsePoint()); - if (p.peekNextToken("n")) { - api.parameter("normal", parseVector()); - } else { - p.checkNextToken("p"); - api.parameter("point1", parsePoint()); - p.checkNextToken("p"); - api.parameter("point2", parsePoint()); - } - api.geometry(name, "plane"); - } else if (type.equals("generic-mesh")) { - UI.printInfo(Module.API, "Reading generic mesh: %s ... ", name); - // parse vertices - p.checkNextToken("points"); - int np = p.getNextInt(); - api.parameter("points", "point", "vertex", parseFloatArray(np * 3)); - // parse triangle indices - p.checkNextToken("triangles"); - int nt = p.getNextInt(); - api.parameter("triangles", parseIntArray(nt * 3)); - // parse normals - p.checkNextToken("normals"); - if (p.peekNextToken("vertex")) - api.parameter("normals", "vector", "vertex", parseFloatArray(np * 3)); - else if (p.peekNextToken("facevarying")) - api.parameter("normals", "vector", "facevarying", parseFloatArray(nt * 9)); - else - p.checkNextToken("none"); - // parse texture coordinates - p.checkNextToken("uvs"); - if (p.peekNextToken("vertex")) - api.parameter("uvs", "texcoord", "vertex", parseFloatArray(np * 2)); - else if (p.peekNextToken("facevarying")) - api.parameter("uvs", "texcoord", "facevarying", parseFloatArray(nt * 6)); - else - p.checkNextToken("none"); - if (p.peekNextToken("face_shaders")) - api.parameter("faceshaders", parseIntArray(nt)); - api.geometry(name, "triangle_mesh"); - } else if (type.equals("hair")) { - UI.printInfo(Module.API, "Reading hair curves: %s ... ", name); - p.checkNextToken("segments"); - api.parameter("segments", p.getNextInt()); - p.checkNextToken("width"); - api.parameter("widths", p.getNextFloat()); - p.checkNextToken("points"); - api.parameter("points", "point", "vertex", parseFloatArray(p.getNextInt())); - api.geometry(name, "hair"); - } else if (type.equals("janino-tesselatable")) { - UI.printInfo(Module.API, "Reading procedural primitive: %s ... ", name); - String typename = p.peekNextToken("typename") ? p.getNextToken() : PluginRegistry.shaderPlugins.generateUniqueName("janino_shader"); - if (!PluginRegistry.tesselatablePlugins.registerPlugin(typename, p.getNextCodeBlock())) - noInstance = true; - else - api.geometry(name, typename); - } else if (type.equals("teapot")) { - UI.printInfo(Module.API, "Reading teapot: %s ... ", name); - if (p.peekNextToken("subdivs")) - api.parameter("subdivs", p.getNextInt()); - if (p.peekNextToken("smooth")) - api.parameter("smooth", p.getNextBoolean()); - api.geometry(name, "teapot"); - } else if (type.equals("gumbo")) { - UI.printInfo(Module.API, "Reading gumbo: %s ... ", name); - if (p.peekNextToken("subdivs")) - api.parameter("subdivs", p.getNextInt()); - if (p.peekNextToken("smooth")) - api.parameter("smooth", p.getNextBoolean()); - api.geometry(name, "gumbo"); - } else if (type.equals("julia")) { - UI.printInfo(Module.API, "Reading julia fractal: %s ... ", name); - if (p.peekNextToken("q")) { - api.parameter("cw", p.getNextFloat()); - api.parameter("cx", p.getNextFloat()); - api.parameter("cy", p.getNextFloat()); - api.parameter("cz", p.getNextFloat()); - } - if (p.peekNextToken("iterations")) - api.parameter("iterations", p.getNextInt()); - if (p.peekNextToken("epsilon")) - api.parameter("epsilon", p.getNextFloat()); - api.geometry(name, "julia"); - } else if (type.equals("particles") || type.equals("dlasurface")) { - if (type.equals("dlasurface")) - UI.printWarning(Module.API, "Deprecated object type: \"dlasurface\" - please use \"particles\" instead"); - float[] data; - if (p.peekNextToken("filename")) { - // FIXME: this code should be moved into an on demand loading - // primitive - String filename = p.getNextToken(); - boolean littleEndian = false; - if (p.peekNextToken("little_endian")) - littleEndian = true; - UI.printInfo(Module.USER, "Loading particle file: %s", filename); - File file = new File(filename); - FileInputStream stream = new FileInputStream(filename); - MappedByteBuffer map = stream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()); - if (littleEndian) - map.order(ByteOrder.LITTLE_ENDIAN); - FloatBuffer buffer = map.asFloatBuffer(); - data = new float[buffer.capacity()]; - for (int i = 0; i < data.length; i++) - data[i] = buffer.get(i); - stream.close(); - } else { - p.checkNextToken("points"); - int n = p.getNextInt(); - data = parseFloatArray(n * 3); // read 3n points - } - api.parameter("particles", "point", "vertex", data); - if (p.peekNextToken("num")) - api.parameter("num", p.getNextInt()); - else - api.parameter("num", data.length / 3); - p.checkNextToken("radius"); - api.parameter("radius", p.getNextFloat()); - api.geometry(name, "particles"); - } else if (type.equals("file-mesh")) { - UI.printInfo(Module.API, "Reading file mesh: %s ... ", name); - p.checkNextToken("filename"); - api.parameter("filename", p.getNextToken()); - if (p.peekNextToken("smooth_normals")) - api.parameter("smooth_normals", p.getNextBoolean()); - api.geometry(name, "file_mesh"); - } else if (type.equals("bezier-mesh")) { - UI.printInfo(Module.API, "Reading bezier mesh: %s ... ", name); - p.checkNextToken("n"); - int nu, nv; - api.parameter("nu", nu = p.getNextInt()); - api.parameter("nv", nv = p.getNextInt()); - if (p.peekNextToken("wrap")) { - api.parameter("uwrap", p.getNextBoolean()); - api.parameter("vwrap", p.getNextBoolean()); - } - p.checkNextToken("points"); - float[] points = new float[3 * nu * nv]; - for (int i = 0; i < points.length; i++) - points[i] = p.getNextFloat(); - api.parameter("points", "point", "vertex", points); - if (p.peekNextToken("subdivs")) - api.parameter("subdivs", p.getNextInt()); - if (p.peekNextToken("smooth")) - api.parameter("smooth", p.getNextBoolean()); - api.geometry(name, "bezier_mesh"); - } else { - UI.printWarning(Module.API, "Unrecognized object type: %s", p.getNextToken()); - noInstance = true; - } - if (!noInstance) { - // create instance - api.parameter("shaders", shaders); - if (modifiers != null) - api.parameter("modifiers", modifiers); - if (transform != null && transform.length > 0) { - if (transform.length == 1) - api.parameter("transform", transform[0]); - else { - api.parameter("transform.steps", transform.length); - api.parameter("transform.times", "float", "none", new float[] { - transformTime0, transformTime1 }); - for (int i = 0; i < transform.length; i++) - api.parameter(String.format("transform[%d]", i), transform[i]); - } - } - api.instance(name + ".instance", name); - } - p.checkNextToken("}"); - } - - private void parseInstanceBlock(SunflowAPIInterface api) throws ParserException, IOException { - p.checkNextToken("{"); - p.checkNextToken("name"); - String name = p.getNextToken(); - UI.printInfo(Module.API, "Reading instance: %s ...", name); - p.checkNextToken("geometry"); - String geoname = p.getNextToken(); - p.checkNextToken("transform"); - if (p.peekNextToken("steps")) { - int n = p.getNextInt(); - api.parameter("transform.steps", n); - p.checkNextToken("times"); - float[] times = new float[2]; - times[0] = p.getNextFloat(); - times[1] = p.getNextFloat(); - api.parameter("transform.times", "float", "none", times); - for (int i = 0; i < n; i++) - api.parameter(String.format("transform[%d]", i), parseMatrix()); - } else - api.parameter("transform", parseMatrix()); - String[] shaders; - if (p.peekNextToken("shaders")) { - int n = p.getNextInt(); - shaders = new String[n]; - for (int i = 0; i < n; i++) - shaders[i] = p.getNextToken(); - } else { - p.checkNextToken("shader"); - shaders = new String[] { p.getNextToken() }; - } - api.parameter("shaders", shaders); - String[] modifiers = null; - if (p.peekNextToken("modifiers")) { - int n = p.getNextInt(); - modifiers = new String[n]; - for (int i = 0; i < n; i++) - modifiers[i] = p.getNextToken(); - } else if (p.peekNextToken("modifier")) - modifiers = new String[] { p.getNextToken() }; - if (modifiers != null) - api.parameter("modifiers", modifiers); - api.instance(name, geoname); - p.checkNextToken("}"); - } - - private void parseLightBlock(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException { - p.checkNextToken("{"); - p.checkNextToken("type"); - if (p.peekNextToken("mesh")) { - UI.printWarning(Module.API, "Deprecated light type: mesh"); - p.checkNextToken("name"); - String name = p.getNextToken(); - UI.printInfo(Module.API, "Reading light mesh: %s ...", name); - p.checkNextToken("emit"); - api.parameter("radiance", null, parseColor().getRGB()); - int samples = numLightSamples; - if (p.peekNextToken("samples")) - samples = p.getNextInt(); - else - UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", samples); - api.parameter("samples", samples); - int numVertices = p.getNextInt(); - int numTriangles = p.getNextInt(); - float[] points = new float[3 * numVertices]; - int[] triangles = new int[3 * numTriangles]; - for (int i = 0; i < numVertices; i++) { - p.checkNextToken("v"); - points[3 * i + 0] = p.getNextFloat(); - points[3 * i + 1] = p.getNextFloat(); - points[3 * i + 2] = p.getNextFloat(); - // ignored - p.getNextFloat(); - p.getNextFloat(); - p.getNextFloat(); - p.getNextFloat(); - p.getNextFloat(); - } - for (int i = 0; i < numTriangles; i++) { - p.checkNextToken("t"); - triangles[3 * i + 0] = p.getNextInt(); - triangles[3 * i + 1] = p.getNextInt(); - triangles[3 * i + 2] = p.getNextInt(); - } - api.parameter("points", "point", "vertex", points); - api.parameter("triangles", triangles); - api.light(name, "triangle_mesh"); - } else if (p.peekNextToken("point")) { - UI.printInfo(Module.API, "Reading point light ..."); - Color pow; - if (p.peekNextToken("color")) { - pow = parseColor(); - p.checkNextToken("power"); - float po = p.getNextFloat(); - pow.mul(po); - } else { - UI.printWarning(Module.API, "Deprecated color specification - please use color and power instead"); - p.checkNextToken("power"); - pow = parseColor(); - } - p.checkNextToken("p"); - api.parameter("center", parsePoint()); - api.parameter("power", null, pow.getRGB()); - api.light(generateUniqueName("pointlight"), "point"); - } else if (p.peekNextToken("spherical")) { - UI.printInfo(Module.API, "Reading spherical light ..."); - p.checkNextToken("color"); - Color pow = parseColor(); - p.checkNextToken("radiance"); - pow.mul(p.getNextFloat()); - api.parameter("radiance", null, pow.getRGB()); - p.checkNextToken("center"); - api.parameter("center", parsePoint()); - p.checkNextToken("radius"); - api.parameter("radius", p.getNextFloat()); - p.checkNextToken("samples"); - api.parameter("samples", p.getNextInt()); - api.light(generateUniqueName("spherelight"), "sphere"); - } else if (p.peekNextToken("directional")) { - UI.printInfo(Module.API, "Reading directional light ..."); - p.checkNextToken("source"); - Point3 s = parsePoint(); - api.parameter("source", s); - p.checkNextToken("target"); - Point3 t = parsePoint(); - api.parameter("dir", Point3.sub(t, s, new Vector3())); - p.checkNextToken("radius"); - api.parameter("radius", p.getNextFloat()); - p.checkNextToken("emit"); - Color e = parseColor(); - if (p.peekNextToken("intensity")) { - float i = p.getNextFloat(); - e.mul(i); - } else - UI.printWarning(Module.API, "Deprecated color specification - please use emit and intensity instead"); - api.parameter("radiance", null, e.getRGB()); - api.light(generateUniqueName("dirlight"), "directional"); - } else if (p.peekNextToken("ibl")) { - UI.printInfo(Module.API, "Reading image based light ..."); - p.checkNextToken("image"); - api.parameter("texture", p.getNextToken()); - p.checkNextToken("center"); - api.parameter("center", parseVector()); - p.checkNextToken("up"); - api.parameter("up", parseVector()); - p.checkNextToken("lock"); - api.parameter("fixed", p.getNextBoolean()); - int samples = numLightSamples; - if (p.peekNextToken("samples")) - samples = p.getNextInt(); - else - UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", samples); - api.parameter("samples", samples); - if (p.peekNextToken("lowsamples")) - api.parameter("lowsamples", p.getNextInt()); - else - api.parameter("lowsamples", samples); - api.light(generateUniqueName("ibl"), "ibl"); - } else if (p.peekNextToken("meshlight")) { - p.checkNextToken("name"); - String name = p.getNextToken(); - UI.printInfo(Module.API, "Reading meshlight: %s ...", name); - p.checkNextToken("emit"); - Color e = parseColor(); - if (p.peekNextToken("radiance")) { - float r = p.getNextFloat(); - e.mul(r); - } else - UI.printWarning(Module.API, "Deprecated color specification - please use emit and radiance instead"); - api.parameter("radiance", null, e.getRGB()); - int samples = numLightSamples; - if (p.peekNextToken("samples")) - samples = p.getNextInt(); - else - UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", samples); - api.parameter("samples", samples); - // parse vertices - p.checkNextToken("points"); - int np = p.getNextInt(); - api.parameter("points", "point", "vertex", parseFloatArray(np * 3)); - // parse triangle indices - p.checkNextToken("triangles"); - int nt = p.getNextInt(); - api.parameter("triangles", parseIntArray(nt * 3)); - api.light(name, "triangle_mesh"); - } else if (p.peekNextToken("sunsky")) { - p.checkNextToken("up"); - api.parameter("up", parseVector()); - p.checkNextToken("east"); - api.parameter("east", parseVector()); - p.checkNextToken("sundir"); - api.parameter("sundir", parseVector()); - p.checkNextToken("turbidity"); - api.parameter("turbidity", p.getNextFloat()); - if (p.peekNextToken("samples")) - api.parameter("samples", p.getNextInt()); - if (p.peekNextToken("ground.extendsky")) - api.parameter("ground.extendsky", p.getNextBoolean()); - else if (p.peekNextToken("ground.color")) - api.parameter("ground.color", null, parseColor().getRGB()); - api.light(generateUniqueName("sunsky"), "sunsky"); - } else if (p.peekNextToken("cornellbox")) { - UI.printInfo(Module.API, "Reading cornell box ..."); - p.checkNextToken("corner0"); - api.parameter("corner0", parsePoint()); - p.checkNextToken("corner1"); - api.parameter("corner1", parsePoint()); - p.checkNextToken("left"); - api.parameter("leftColor", null, parseColor().getRGB()); - p.checkNextToken("right"); - api.parameter("rightColor", null, parseColor().getRGB()); - p.checkNextToken("top"); - api.parameter("topColor", null, parseColor().getRGB()); - p.checkNextToken("bottom"); - api.parameter("bottomColor", null, parseColor().getRGB()); - p.checkNextToken("back"); - api.parameter("backColor", null, parseColor().getRGB()); - p.checkNextToken("emit"); - api.parameter("radiance", null, parseColor().getRGB()); - if (p.peekNextToken("samples")) - api.parameter("samples", p.getNextInt()); - api.light(generateUniqueName("cornellbox"), "cornell_box"); - } else - UI.printWarning(Module.API, "Unrecognized object type: %s", p.getNextToken()); - p.checkNextToken("}"); - } - - private Color parseColor() throws IOException, ParserException, ColorSpecificationException { - if (p.peekNextToken("{")) { - String space = p.getNextToken(); - int req = ColorFactory.getRequiredDataValues(space); - if (req == -2) { - UI.printWarning(Module.API, "Unrecognized color space: %s", space); - return null; - } else if (req == -1) { - // array required, parse how many values are required - req = p.getNextInt(); - } - Color c = ColorFactory.createColor(space, parseFloatArray(req)); - p.checkNextToken("}"); - return c; - } else { - float r = p.getNextFloat(); - float g = p.getNextFloat(); - float b = p.getNextFloat(); - return ColorFactory.createColor(null, r, g, b); - } - } - - private Point3 parsePoint() throws IOException { - float x = p.getNextFloat(); - float y = p.getNextFloat(); - float z = p.getNextFloat(); - return new Point3(x, y, z); - } - - private Vector3 parseVector() throws IOException { - float x = p.getNextFloat(); - float y = p.getNextFloat(); - float z = p.getNextFloat(); - return new Vector3(x, y, z); - } - - private int[] parseIntArray(int size) throws IOException { - int[] data = new int[size]; - for (int i = 0; i < size; i++) - data[i] = p.getNextInt(); - return data; - } - - private float[] parseFloatArray(int size) throws IOException { - float[] data = new float[size]; - for (int i = 0; i < size; i++) - data[i] = p.getNextFloat(); - return data; - } - - private Matrix4 parseMatrix() throws IOException, ParserException { - if (p.peekNextToken("row")) { - return new Matrix4(parseFloatArray(16), true); - } else if (p.peekNextToken("col")) { - return new Matrix4(parseFloatArray(16), false); - } else { - Matrix4 m = Matrix4.IDENTITY; - p.checkNextToken("{"); - while (!p.peekNextToken("}")) { - Matrix4 t = null; - if (p.peekNextToken("translate")) { - float x = p.getNextFloat(); - float y = p.getNextFloat(); - float z = p.getNextFloat(); - t = Matrix4.translation(x, y, z); - } else if (p.peekNextToken("scaleu")) { - float s = p.getNextFloat(); - t = Matrix4.scale(s); - } else if (p.peekNextToken("scale")) { - float x = p.getNextFloat(); - float y = p.getNextFloat(); - float z = p.getNextFloat(); - t = Matrix4.scale(x, y, z); - } else if (p.peekNextToken("rotatex")) { - float angle = p.getNextFloat(); - t = Matrix4.rotateX((float) Math.toRadians(angle)); - } else if (p.peekNextToken("rotatey")) { - float angle = p.getNextFloat(); - t = Matrix4.rotateY((float) Math.toRadians(angle)); - } else if (p.peekNextToken("rotatez")) { - float angle = p.getNextFloat(); - t = Matrix4.rotateZ((float) Math.toRadians(angle)); - } else if (p.peekNextToken("rotate")) { - float x = p.getNextFloat(); - float y = p.getNextFloat(); - float z = p.getNextFloat(); - float angle = p.getNextFloat(); - t = Matrix4.rotate(x, y, z, (float) Math.toRadians(angle)); - } else - UI.printWarning(Module.API, "Unrecognized transformation type: %s", p.getNextToken()); - if (t != null) - m = t.multiply(m); - } - return m; - } - } +package org.sunflow.core.parser; + +import org.sunflow.PluginRegistry; +import org.sunflow.SunflowAPI; +import org.sunflow.SunflowAPIInterface; +import org.sunflow.core.SceneParser; +import org.sunflow.core.parameter.*; +import org.sunflow.core.parameter.camera.*; +import org.sunflow.core.parameter.geometry.*; +import org.sunflow.core.parameter.gi.*; +import org.sunflow.core.parameter.light.*; +import org.sunflow.core.parameter.modifier.BumpMapModifierParameter; +import org.sunflow.core.parameter.modifier.NormalMapModifierParameter; +import org.sunflow.core.parameter.modifier.PerlinModifierParameter; +import org.sunflow.core.parameter.shader.*; +import org.sunflow.image.Color; +import org.sunflow.image.ColorFactory; +import org.sunflow.image.ColorFactory.ColorSpecificationException; +import org.sunflow.math.Matrix4; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; +import org.sunflow.system.Parser; +import org.sunflow.system.Parser.ParserException; +import org.sunflow.system.Timer; +import org.sunflow.system.UI; +import org.sunflow.system.UI.Module; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.HashMap; + +/** + * This class provides a static method for loading files in the Sunflow scene + * file format. + */ +public class SCParser implements SceneParser { + private static int instanceCounter = 0; + private int instanceNumber; + private Parser p; + private int numLightSamples; + // used to generate unique names inside this parser + private HashMap objectNames; + + public SCParser() { + objectNames = new HashMap(); + instanceCounter++; + instanceNumber = instanceCounter; + } + + private String generateUniqueName(String prefix) { + // generate a unique name for this class: + int index = 1; + Integer value = objectNames.get(prefix); + if (value != null) { + index = value; + objectNames.put(prefix, index + 1); + } else { + objectNames.put(prefix, index + 1); + } + return String.format("@sc_%d::%s_%d", instanceNumber, prefix, index); + } + + public boolean parse(String filename, SunflowAPIInterface api) { + String localDir = new File(filename).getAbsoluteFile().getParentFile().getAbsolutePath(); + numLightSamples = 1; + Timer timer = new Timer(); + timer.start(); + UI.printInfo(Module.API, "Parsing \"%s\" ...", filename); + try { + p = new Parser(filename); + while (true) { + String token = p.getNextToken(); + if (token == null) + break; + if (token.equals("image")) { + UI.printInfo(Module.API, "Reading image settings ..."); + parseImageBlock(api); + } else if (token.equals("background")) { + UI.printInfo(Module.API, "Reading background ..."); + parseBackgroundBlock(api); + } else if (token.equals("accel")) { + UI.printInfo(Module.API, "Reading accelerator type ..."); + p.getNextToken(); + UI.printWarning(Module.API, "Setting accelerator type is not recommended - ignoring"); + } else if (token.equals("filter")) { + // Deprecated + UI.printInfo(Module.API, "Reading image filter type ..."); + parseFilter(api); + } else if (token.equals("bucket")) { + UI.printInfo(Module.API, "Reading bucket settings ..."); + parseBucketBlock(api); + } else if (token.equals("photons")) { + UI.printInfo(Module.API, "Reading photon settings ..."); + parsePhotonBlock(api); + } else if (token.equals("gi")) { + UI.printInfo(Module.API, "Reading global illumination settings ..."); + parseGIBlock(api); + } else if (token.equals("lightserver")) { + // Deprecated + UI.printInfo(Module.API, "Reading light server settings ..."); + parseLightserverBlock(api); + } else if (token.equals("trace-depths")) { + UI.printInfo(Module.API, "Reading trace depths ..."); + parseTraceBlock(api); + } else if (token.equals("camera")) { + parseCamera(api); + } else if (token.equals("shader")) { + if (!parseShader(api)) { + // Close before return + p.close(); + return false; + } + } else if (token.equals("modifier")) { + if (!parseModifier(api)) { + // Close before return + p.close(); + return false; + } + } else if (token.equals("override")) { + parseOverrideBlock(api); + } else if (token.equals("object")) { + parseObjectBlock(api); + } else if (token.equals("instance")) { + parseInstanceBlock(api); + } else if (token.equals("light")) { + parseLightBlock(api); + } else if (token.equals("texturepath")) { + String path = p.getNextToken(); + if (!new File(path).isAbsolute()) { + path = localDir + File.separator + path; + } + api.searchpath("texture", path); + } else if (token.equals("includepath")) { + String path = p.getNextToken(); + if (!new File(path).isAbsolute()) { + path = localDir + File.separator + path; + } + api.searchpath("include", path); + } else if (token.equals("include")) { + String file = p.getNextToken(); + UI.printInfo(Module.API, "Including: \"%s\" ...", file); + api.include(file); + } else + UI.printWarning(Module.API, "Unrecognized token %s", token); + } + p.close(); + } catch (ParserException e) { + UI.printError(Module.API, "%s", e.getMessage()); + e.printStackTrace(); + return false; + } catch (FileNotFoundException e) { + UI.printError(Module.API, "%s", e.getMessage()); + return false; + } catch (IOException e) { + UI.printError(Module.API, "%s", e.getMessage()); + return false; + } catch (ColorSpecificationException e) { + UI.printError(Module.API, "%s", e.getMessage()); + return false; + } + timer.end(); + UI.printInfo(Module.API, "Done parsing."); + UI.printInfo(Module.API, "Parsing time: %s", timer.toString()); + return true; + } + + private void parseBucketBlock(SunflowAPIInterface api) throws IOException { + BucketParameter bucket = new BucketParameter(); + bucket.setSize(p.getNextInt()); + bucket.setOrder(p.getNextToken()); + bucket.setup(api); + } + + private void parseImageBlock(SunflowAPIInterface api) throws IOException, ParserException { + ImageParameter image = new ImageParameter(); + + p.checkNextToken("{"); + if (p.peekNextToken("resolution")) { + image.setResolutionX(p.getNextInt()); + image.setResolutionY(p.getNextInt()); + } + if (p.peekNextToken("sampler")) + image.setSampler(p.getNextToken()); + if (p.peekNextToken("aa")) { + image.setAAMin(p.getNextInt()); + image.setAAMax(p.getNextInt()); + } + if (p.peekNextToken("samples")) { + image.setAASamples(p.getNextInt()); + } + if (p.peekNextToken("contrast")) { + image.setAAContrast(p.getNextFloat()); + } + if (p.peekNextToken("filter")) { + image.setFilter(p.getNextToken()); + } + if (p.peekNextToken("jitter")) { + image.setAAJitter(p.getNextBoolean()); + } + if (p.peekNextToken("show-aa")) { + UI.printWarning(Module.API, "Deprecated: show-aa ignored"); + p.getNextBoolean(); + } + if (p.peekNextToken("cache")) { + image.setAACache(p.getNextBoolean()); + } + if (p.peekNextToken("output")) { + UI.printWarning(Module.API, "Deprecated: output statement ignored"); + p.getNextToken(); + } + + image.setup(api); + p.checkNextToken("}"); + } + + private void parseBackgroundBlock(SunflowAPIInterface api) throws IOException, ParserException, ColorSpecificationException { + BackgroundParameter background = new BackgroundParameter(); + + p.checkNextToken("{"); + p.checkNextToken("color"); + + background.setColor(parseColor()); + background.setup(api); + + p.checkNextToken("}"); + } + + private void parseFilter(SunflowAPIInterface api) throws IOException, ParserException { + UI.printWarning(Module.API, "Deprecated keyword \"filter\" - set this option in the image block"); + String name = p.getNextToken(); + api.parameter("filter", name); + api.options(SunflowAPI.DEFAULT_OPTIONS); + boolean hasSizeParams = name.equals("box") || name.equals("gaussian") || name.equals("blackman-harris") || name.equals("sinc") || name.equals("triangle"); + if (hasSizeParams) { + p.getNextFloat(); + p.getNextFloat(); + } + } + + private void parsePhotonBlock(SunflowAPIInterface api) throws ParserException, IOException { + PhotonParameter photon = new PhotonParameter(); + + boolean globalEmit = false; + + p.checkNextToken("{"); + if (p.peekNextToken("emit")) { + UI.printWarning(Module.API, "Shared photon emit values are deprecated - specify number of photons to emit per map"); + photon.setNumEmit(p.getNextInt()); + globalEmit = true; + } + if (p.peekNextToken("global")) { + UI.printWarning(Module.API, "Global photon map setting belongs inside the gi block - ignoring"); + if (!globalEmit) { + p.getNextInt(); + } + p.getNextToken(); + p.getNextInt(); + p.getNextFloat(); + } + p.checkNextToken("caustics"); + if (!globalEmit) { + photon.setNumEmit(p.getNextInt()); + } + + photon.setCaustics(p.getNextToken()); + photon.setCausticsGather(p.getNextInt()); + photon.setCausticsRadius(p.getNextFloat()); + + photon.setup(api); + p.checkNextToken("}"); + } + + private void parseGIBlock(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException { + p.checkNextToken("{"); + p.checkNextToken("type"); + if (p.peekNextToken("irr-cache")) { + IrrCacheGIParameter gi = new IrrCacheGIParameter(); + + p.checkNextToken("samples"); + gi.setSamples(p.getNextInt()); + p.checkNextToken("tolerance"); + gi.setTolerance(p.getNextFloat()); + p.checkNextToken("spacing"); + gi.setMinSpacing(p.getNextFloat()); + gi.setMaxSpacing(p.getNextFloat()); + + // parse global photon map info + if (p.peekNextToken("global")) { + gi.setGlobal(new IlluminationParameter()); + gi.getGlobal().setEmit(p.getNextInt()); + gi.getGlobal().setMap(p.getNextToken()); + gi.getGlobal().setGather(p.getNextInt()); + gi.getGlobal().setRadius(p.getNextFloat()); + } + gi.setup(api); + } else if (p.peekNextToken("path")) { + PathTracingGIParameter gi = new PathTracingGIParameter(); + + p.checkNextToken("samples"); + gi.setSamples(p.getNextInt()); + + if (p.peekNextToken("bounces")) { + UI.printWarning(Module.API, "Deprecated setting: bounces - use diffuse trace depth instead"); + p.getNextInt(); + } + gi.setup(api); + } else if (p.peekNextToken("fake")) { + FakeGIParameter gi = new FakeGIParameter(); + + p.checkNextToken("up"); + gi.setUp(parseVector()); + p.checkNextToken("sky"); + gi.setSky(parseColor()); + p.checkNextToken("ground"); + gi.setGround(parseColor()); + + gi.setup(api); + } else if (p.peekNextToken("igi")) { + InstantGIParameter gi = new InstantGIParameter(); + + p.checkNextToken("samples"); + gi.setSamples(p.getNextInt()); + p.checkNextToken("sets"); + gi.setSets(p.getNextInt()); + + if (!p.peekNextToken("b")) { + p.checkNextToken("c"); + } + gi.setBias(p.getNextFloat()); + + p.checkNextToken("bias-samples"); + gi.setBiasSamples(p.getNextInt()); + + gi.setup(api); + } else if (p.peekNextToken("ambocc")) { + AmbientOcclusionGIParameter gi = new AmbientOcclusionGIParameter(); + + p.checkNextToken("bright"); + gi.setBright(parseColor()); + p.checkNextToken("dark"); + gi.setDark(parseColor()); + p.checkNextToken("samples"); + gi.setSamples(p.getNextInt()); + if (p.peekNextToken("maxdist")) { + gi.setMaxDist(p.getNextFloat()); + } + + gi.setup(api); + } else if (p.peekNextToken("none") || p.peekNextToken("null")) { + DisabledGIParameter gi = new DisabledGIParameter(); + // disable GI + gi.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized gi engine type \"%s\" - ignoring", p.getNextToken()); + } + + p.checkNextToken("}"); + } + + private void parseOverrideBlock(SunflowAPIInterface api) throws IOException { + OverrideParameter block = new OverrideParameter(); + + block.setShader(p.getNextToken()); + block.setPhotons(p.getNextBoolean()); + block.setup(api); + } + + private void parseLightserverBlock(SunflowAPIInterface api) throws ParserException, IOException { + p.checkNextToken("{"); + if (p.peekNextToken("shadows")) { + UI.printWarning(Module.API, "Deprecated: shadows setting ignored"); + p.getNextBoolean(); + } + if (p.peekNextToken("direct-samples")) { + UI.printWarning(Module.API, "Deprecated: use samples keyword in area light definitions"); + numLightSamples = p.getNextInt(); + } + if (p.peekNextToken("glossy-samples")) { + UI.printWarning(Module.API, "Deprecated: use samples keyword in glossy shader definitions"); + p.getNextInt(); + } + if (p.peekNextToken("max-depth")) { + UI.printWarning(Module.API, "Deprecated: max-depth setting - use trace-depths block instead"); + int d = p.getNextInt(); + api.parameter("depths.diffuse", 1); + api.parameter("depths.reflection", d - 1); + api.parameter("depths.refraction", 0); + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + if (p.peekNextToken("global")) { + UI.printWarning(Module.API, "Deprecated: global settings ignored - use photons block instead"); + p.getNextBoolean(); + p.getNextInt(); + p.getNextInt(); + p.getNextInt(); + p.getNextFloat(); + } + if (p.peekNextToken("caustics")) { + UI.printWarning(Module.API, "Deprecated: caustics settings ignored - use photons block instead"); + p.getNextBoolean(); + p.getNextInt(); + p.getNextFloat(); + p.getNextInt(); + p.getNextFloat(); + } + if (p.peekNextToken("irr-cache")) { + UI.printWarning(Module.API, "Deprecated: irradiance cache settings ignored - use gi block instead"); + p.getNextInt(); + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + } + p.checkNextToken("}"); + } + + private void parseTraceBlock(SunflowAPIInterface api) throws ParserException, IOException { + TraceDepthsParameter traceDepthsParameter = new TraceDepthsParameter(); + p.checkNextToken("{"); + if (p.peekNextToken("diff")) { + traceDepthsParameter.setDiffuse(p.getNextInt()); + } + if (p.peekNextToken("refl")) { + traceDepthsParameter.setReflection(p.getNextInt()); + } + if (p.peekNextToken("refr")) { + traceDepthsParameter.setRefraction(p.getNextInt()); + } + p.checkNextToken("}"); + + traceDepthsParameter.setup(api); + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + + private void parseCamera(SunflowAPIInterface api) throws ParserException, IOException { + p.checkNextToken("{"); + p.checkNextToken("type"); + String type = p.getNextToken(); + UI.printInfo(Module.API, "Reading %s camera ...", type); + + float shutterOpen = 0, shutterClose = 0; + + if (p.peekNextToken("shutter")) { + shutterOpen = p.getNextFloat(); + shutterClose = p.getNextFloat(); + } + parseCameraTransform(api); + String name = generateUniqueName("camera"); + if (type.equals(CameraParameter.TYPE_PINHOLE)) { + PinholeCameraParameter camera = new PinholeCameraParameter(); + camera.setName(name); + camera.setShutterOpen(shutterOpen); + camera.setShutterClose(shutterClose); + + p.checkNextToken("fov"); + camera.setFov(p.getNextFloat()); + p.checkNextToken("aspect"); + camera.setAspect(p.getNextFloat()); + + if (p.peekNextToken("shift")) { + camera.setShiftX(p.getNextFloat()); + camera.setShiftY(p.getNextFloat()); + } + camera.setup(api); + } else if (type.equals(CameraParameter.TYPE_THINLENS)) { + ThinLensCameraParameter camera = new ThinLensCameraParameter(); + camera.setName(name); + camera.setShutterOpen(shutterOpen); + camera.setShutterClose(shutterClose); + + p.checkNextToken("fov"); + camera.setFov(p.getNextFloat()); + p.checkNextToken("aspect"); + camera.setAspect(p.getNextFloat()); + if (p.peekNextToken("shift")) { + camera.setShiftX(p.getNextFloat()); + camera.setShiftY(p.getNextFloat()); + } + p.checkNextToken("fdist"); + camera.setFocusDistance(p.getNextFloat()); + p.checkNextToken("lensr"); + camera.setLensRadius(p.getNextFloat()); + if (p.peekNextToken("sides")) { + camera.setLensSides(p.getNextInt()); + } + if (p.peekNextToken("rotation")) { + camera.setLensRotation(p.getNextFloat()); + } + camera.setup(api); + } else if (type.equals(CameraParameter.TYPE_SPHERICAL)) { + SphericalCameraParameter camera = new SphericalCameraParameter(); + camera.setName(name); + camera.setShutterOpen(shutterOpen); + camera.setShutterClose(shutterClose); + // no extra arguments + camera.setup(api); + } else if (type.equals(CameraParameter.TYPE_FISH_EYE)) { + FishEyeCameraParameter camera = new FishEyeCameraParameter(); + camera.setName(name); + camera.setShutterOpen(shutterOpen); + camera.setShutterClose(shutterClose); + // no extra arguments + camera.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized camera type: %s", p.getNextToken()); + p.checkNextToken("}"); + return; + } + p.checkNextToken("}"); + if (name != null) { + api.parameter("camera", name); + api.options(SunflowAPI.DEFAULT_OPTIONS); + } + } + + private void parseCameraTransform(SunflowAPIInterface api) throws ParserException, IOException { + if (p.peekNextToken("steps")) { + // motion blur camera + int n = p.getNextInt(); + api.parameter("transform.steps", n); + // parse time extents + p.checkNextToken("times"); + float t0 = p.getNextFloat(); + float t1 = p.getNextFloat(); + api.parameter("transform.times", "float", "none", new float[]{t0, t1}); + for (int i = 0; i < n; i++) { + parseCameraMatrix(i, api); + } + } else { + parseCameraMatrix(-1, api); + } + } + + private void parseCameraMatrix(int index, SunflowAPIInterface api) throws IOException, ParserException { + String offset = index < 0 ? "" : String.format("[%d]", index); + if (p.peekNextToken("transform")) { + // advanced camera + api.parameter(String.format("transform%s", offset), parseMatrix()); + } else { + if (index >= 0) { + p.checkNextToken("{"); + } + // regular camera specification + p.checkNextToken("eye"); + Point3 eye = parsePoint(); + p.checkNextToken("target"); + Point3 target = parsePoint(); + p.checkNextToken("up"); + Vector3 up = parseVector(); + api.parameter(String.format("transform%s", offset), Matrix4.lookAt(eye, target, up)); + if (index >= 0) { + p.checkNextToken("}"); + } + } + } + + private boolean parseShader(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException { + p.checkNextToken("{"); + p.checkNextToken("name"); + String name = p.getNextToken(); + UI.printInfo(Module.API, "Reading shader: %s ...", name); + p.checkNextToken("type"); + if (p.peekNextToken("diffuse")) { + DiffuseShaderParameter shader = new DiffuseShaderParameter(name); + + if (p.peekNextToken("diff")) { + shader.setDiffuse(parseColor()); + } else if (p.peekNextToken("texture")) { + shader.setTexture(p.getNextToken()); + } else { + UI.printWarning(Module.API, "Unrecognized option in diffuse shader block: %s", p.getNextToken()); + } + shader.setup(api); + } else if (p.peekNextToken("phong")) { + PhongShaderParameter shaderParameter = new PhongShaderParameter(name); + if (p.peekNextToken("texture")) { + shaderParameter.setTexture(p.getNextToken()); + } else { + p.checkNextToken("diff"); + shaderParameter.setDiffuse(parseColor()); + } + p.checkNextToken("spec"); + shaderParameter.setSpecular(parseColor()); + shaderParameter.setPower(p.getNextFloat()); + + if (p.peekNextToken("samples")) { + shaderParameter.setSamples(p.getNextInt()); + } + shaderParameter.setup(api); + } else if (p.peekNextToken("amb-occ") || p.peekNextToken("amb-occ2")) { + AmbientOcclusionShaderParameter shaderParameter = new AmbientOcclusionShaderParameter(name); + + if (p.peekNextToken("diff") || p.peekNextToken("bright")) { + shaderParameter.setBright(parseColor()); + } else if (p.peekNextToken("texture")) { + shaderParameter.setTexture(p.getNextToken()); + } + + if (p.peekNextToken("dark")) { + shaderParameter.setDark(parseColor()); + p.checkNextToken("samples"); + shaderParameter.setSamples(p.getNextInt()); + p.checkNextToken("dist"); + shaderParameter.setMaxDist(p.getNextFloat()); + } + shaderParameter.setup(api); + } else if (p.peekNextToken("mirror")) { + MirrorShaderParameter shaderParameter = new MirrorShaderParameter(name); + p.checkNextToken("refl"); + shaderParameter.setReflection(parseColor()); + shaderParameter.setup(api); + } else if (p.peekNextToken("glass")) { + GlassShaderParameter shaderParameter = new GlassShaderParameter(name); + + p.checkNextToken("eta"); + shaderParameter.setEta(p.getNextFloat()); + p.checkNextToken("color"); + shaderParameter.setColor(parseColor()); + + if (p.peekNextToken("absorption.distance") || p.peekNextToken("absorbtion.distance")) { + shaderParameter.setAbsorptionDistance(p.getNextFloat()); + } + if (p.peekNextToken("absorption.color") || p.peekNextToken("absorbtion.color")) { + shaderParameter.setAbsorptionColor(parseColor()); + } + shaderParameter.setup(api); + } else if (p.peekNextToken("shiny")) { + ShinyShaderParameter shaderParameter = new ShinyShaderParameter(name); + + if (p.peekNextToken("texture")) { + shaderParameter.setTexture(p.getNextToken()); + } else { + p.checkNextToken("diff"); + shaderParameter.setDiffuse(parseColor()); + } + p.checkNextToken("refl"); + shaderParameter.setShininess(p.getNextFloat()); + shaderParameter.setup(api); + } else if (p.peekNextToken("ward")) { + WardShaderParameter shaderParameter = new WardShaderParameter(name); + + if (p.peekNextToken("texture")) { + shaderParameter.setTexture(p.getNextToken()); + } else { + p.checkNextToken("diff"); + shaderParameter.setDiffuse(parseColor()); + } + p.checkNextToken("spec"); + shaderParameter.setSpecular(parseColor()); + + p.checkNextToken("rough"); + shaderParameter.setRoughnessX(p.getNextFloat()); + shaderParameter.setRoughnessY(p.getNextFloat()); + + if (p.peekNextToken("samples")) { + shaderParameter.setSamples(p.getNextInt()); + } + shaderParameter.setup(api); + } else if (p.peekNextToken("view-caustics")) { + ViewCausticsShaderParameter shaderParameter = new ViewCausticsShaderParameter(name); + shaderParameter.setup(api); + } else if (p.peekNextToken("view-irradiance")) { + ViewIrradianceShaderParameter shaderParameter = new ViewIrradianceShaderParameter(name); + shaderParameter.setup(api); + } else if (p.peekNextToken("view-global")) { + ViewGlobalShaderParameter shaderParameter = new ViewGlobalShaderParameter(name); + shaderParameter.setup(api); + } else if (p.peekNextToken("constant")) { + ConstantShaderParameter shaderParameter = new ConstantShaderParameter(name); + // backwards compatibility -- peek only + p.peekNextToken("color"); + shaderParameter.setColor(parseColor()); + shaderParameter.setup(api); + } else if (p.peekNextToken("janino")) { + String typename = p.peekNextToken("typename") ? p.getNextToken() : PluginRegistry.shaderPlugins.generateUniqueName("janino_shader"); + if (!PluginRegistry.shaderPlugins.registerPlugin(typename, p.getNextCodeBlock())) + return false; + api.shader(name, typename); + } else if (p.peekNextToken("id")) { + IDShaderParameter shaderParameter = new IDShaderParameter(name); + shaderParameter.setup(api); + } else if (p.peekNextToken("uber")) { + UberShaderParameter shaderParameter = new UberShaderParameter(name); + + if (p.peekNextToken("diff")) { + shaderParameter.setDiffuse(parseColor()); + } + if (p.peekNextToken("diff.texture")) { + shaderParameter.setDiffuseTexture(p.getNextToken()); + } + if (p.peekNextToken("diff.blend")) { + shaderParameter.setDiffuseBlend(p.getNextFloat()); + } + if (p.peekNextToken("refl") || p.peekNextToken("spec")) { + shaderParameter.setSpecular(parseColor()); + } + if (p.peekNextToken("texture")) { + // deprecated + UI.printWarning(Module.API, "Deprecated uber shader parameter \"texture\" - please use \"diffuse.texture\" and \"diffuse.blend\" instead"); + shaderParameter.setDiffuseTexture(p.getNextToken()); + shaderParameter.setDiffuseBlend(p.getNextFloat()); + } + if (p.peekNextToken("spec.texture")) { + shaderParameter.setSpecularTexture(p.getNextToken()); + } + if (p.peekNextToken("spec.blend")) { + shaderParameter.setSpecularBlend(p.getNextFloat()); + } + if (p.peekNextToken("glossy")) { + shaderParameter.setGlossyness(p.getNextFloat()); + } + if (p.peekNextToken("samples")) { + shaderParameter.setSamples(p.getNextInt()); + } + shaderParameter.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized shader type: %s", p.getNextToken()); + } + p.checkNextToken("}"); + return true; + } + + private boolean parseModifier(SunflowAPIInterface api) throws ParserException, IOException { + p.checkNextToken("{"); + p.checkNextToken("name"); + String name = p.getNextToken(); + UI.printInfo(Module.API, "Reading modifier: %s ...", name); + p.checkNextToken("type"); + if (p.peekNextToken("bump")) { + BumpMapModifierParameter parameter = new BumpMapModifierParameter(); + parameter.setName(name); + p.checkNextToken("texture"); + parameter.setTexture(p.getNextToken()); + p.checkNextToken("scale"); + parameter.setScale(p.getNextFloat()); + parameter.setup(api); + } else if (p.peekNextToken("normalmap")) { + NormalMapModifierParameter parameter = new NormalMapModifierParameter(); + parameter.setName(name); + p.checkNextToken("texture"); + parameter.setTexture(p.getNextToken()); + parameter.setup(api); + } else if (p.peekNextToken("perlin")) { + PerlinModifierParameter parameter = new PerlinModifierParameter(); + p.checkNextToken("function"); + parameter.setFunction(p.getNextInt()); + p.checkNextToken("size"); + parameter.setSize(p.getNextFloat()); + p.checkNextToken("scale"); + parameter.setScale(p.getNextFloat()); + parameter.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized modifier type: %s", p.getNextToken()); + } + p.checkNextToken("}"); + return true; + } + + private void parseObjectBlock(SunflowAPIInterface api) throws ParserException, IOException { + p.checkNextToken("{"); + InstanceParameter instanceParameter = new InstanceParameter(); + + String name = ""; + String accel = ""; + + String[] shaders = null; + String[] modifiers = null; + if (p.peekNextToken("noinstance")) { + // this indicates that the geometry is to be created, but not + // instanced into the scene + instanceParameter = null; + } else { + // these are the parameters to be passed to the instance + if (p.peekNextToken("shaders")) { + int n = p.getNextInt(); + shaders = new String[n]; + for (int i = 0; i < n; i++) + shaders[i] = p.getNextToken(); + } else { + p.checkNextToken("shader"); + shaders = new String[]{p.getNextToken()}; + } + instanceParameter.shaders(shaders); + + if (p.peekNextToken("modifiers")) { + int n = p.getNextInt(); + modifiers = new String[n]; + for (int i = 0; i < n; i++) + modifiers[i] = p.getNextToken(); + } else if (p.peekNextToken("modifier")) { + modifiers = new String[]{p.getNextToken()}; + } + instanceParameter.modifiers(modifiers); + + // Can be null + TransformParameter transform = checkParseTransform(); + instanceParameter.transform(transform); + } + if (p.peekNextToken("accel")) { + accel = p.getNextToken(); + } + p.checkNextToken("type"); + String type = p.getNextToken(); + if (p.peekNextToken("name")) { + name = p.getNextToken(); + } else { + name = generateUniqueName(type); + } + + if (type.equals("mesh")) { + UI.printWarning(Module.API, "Deprecated object type: mesh"); + UI.printInfo(Module.API, "Reading mesh: %s ...", name); + + TriangleMeshParameter geometry = new TriangleMeshParameter(); + geometry.setName(name); + geometry.setAccel(accel); + geometry.setInstanceParameter(instanceParameter); + + int numVertices = p.getNextInt(); + int numTriangles = p.getNextInt(); + float[] points = new float[numVertices * 3]; + float[] normals = new float[numVertices * 3]; + float[] uvs = new float[numVertices * 2]; + for (int i = 0; i < numVertices; i++) { + p.checkNextToken("v"); + points[3 * i + 0] = p.getNextFloat(); + points[3 * i + 1] = p.getNextFloat(); + points[3 * i + 2] = p.getNextFloat(); + normals[3 * i + 0] = p.getNextFloat(); + normals[3 * i + 1] = p.getNextFloat(); + normals[3 * i + 2] = p.getNextFloat(); + uvs[2 * i + 0] = p.getNextFloat(); + uvs[2 * i + 1] = p.getNextFloat(); + } + int[] triangles = new int[numTriangles * 3]; + for (int i = 0; i < numTriangles; i++) { + p.checkNextToken("t"); + triangles[i * 3 + 0] = p.getNextInt(); + triangles[i * 3 + 1] = p.getNextInt(); + triangles[i * 3 + 2] = p.getNextInt(); + } + + geometry.setPoints(points); + geometry.setNormals(normals); + geometry.setUvs(uvs); + geometry.setTriangles(triangles); + geometry.setup(api); + } else if (type.equals("flat-mesh")) { + UI.printWarning(Module.API, "Deprecated object type: flat-mesh"); + UI.printInfo(Module.API, "Reading flat mesh: %s ...", name); + + TriangleMeshParameter geometry = new TriangleMeshParameter(); + geometry.setName(name); + geometry.setAccel(accel); + geometry.setInstanceParameter(instanceParameter); + + int numVertices = p.getNextInt(); + int numTriangles = p.getNextInt(); + float[] points = new float[numVertices * 3]; + float[] uvs = new float[numVertices * 2]; + for (int i = 0; i < numVertices; i++) { + p.checkNextToken("v"); + points[3 * i + 0] = p.getNextFloat(); + points[3 * i + 1] = p.getNextFloat(); + points[3 * i + 2] = p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + uvs[2 * i + 0] = p.getNextFloat(); + uvs[2 * i + 1] = p.getNextFloat(); + } + int[] triangles = new int[numTriangles * 3]; + for (int i = 0; i < numTriangles; i++) { + p.checkNextToken("t"); + triangles[i * 3 + 0] = p.getNextInt(); + triangles[i * 3 + 1] = p.getNextInt(); + triangles[i * 3 + 2] = p.getNextInt(); + } + + geometry.setPoints(points); + geometry.setUvs(uvs); + geometry.setTriangles(triangles); + geometry.setup(api); + } else if (type.equals("sphere")) { + UI.printInfo(Module.API, "Reading sphere ..."); + + SphereParameter geometry = new SphereParameter(); + geometry.setName(name); + geometry.setInstanceParameter(instanceParameter); + + if (instanceParameter == null || instanceParameter.transform() == null) { + // legacy method of specifying transformation for spheres + p.checkNextToken("c"); + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + geometry.setCenter(new Point3(x, y, z)); + p.checkNextToken("r"); + float radius = p.getNextFloat(); + geometry.setRadius(radius); + + geometry.setup(api); + } else { + geometry.setup(api); + } + } else if (type.equals("box")) { + UI.printInfo(Module.API, "Reading box ..."); + BoxParameter geometry = new BoxParameter(); + geometry.setInstanceParameter(instanceParameter); + geometry.setName(name); + + if (p.peekNextToken("min")) { + geometry.setMin(parsePoint()); + } + if (p.peekNextToken("max")) { + geometry.setMax(parsePoint()); + } + + geometry.setup(api); + } else if (type.equals("cylinder")) { + UI.printInfo(Module.API, "Reading cylinder ..."); + + CylinderParameter parameter = new CylinderParameter(); + parameter.setName(name); + parameter.setInstanceParameter(instanceParameter); + + parameter.setup(api); + } else if (type.equals("banchoff")) { + UI.printInfo(Module.API, "Reading banchoff ..."); + + BanchOffParameter parameter = new BanchOffParameter(); + parameter.setName(name); + parameter.setInstanceParameter(instanceParameter); + + parameter.setup(api); + } else if (type.equals("torus")) { + UI.printInfo(Module.API, "Reading torus ..."); + + TorusParameter geometry = new TorusParameter(); + geometry.setName(name); + geometry.setInstanceParameter(instanceParameter); + + p.checkNextToken("r"); + geometry.setRadiusInner(p.getNextFloat()); + geometry.setRadiusOuter(p.getNextFloat()); + geometry.setup(api); + } else if (type.equals("sphereflake")) { + UI.printInfo(Module.API, "Reading sphereflake ..."); + SphereFlakeParameter geometry = new SphereFlakeParameter(); + geometry.setInstanceParameter(instanceParameter); + geometry.setName(name); + + if (p.peekNextToken("level")) { + geometry.setLevel(p.getNextInt()); + } + if (p.peekNextToken("axis")) { + geometry.setAxis(parseVector()); + } + if (p.peekNextToken("radius")) { + geometry.setRadius(p.getNextFloat()); + } + geometry.setup(api); + } else if (type.equals("plane")) { + UI.printInfo(Module.API, "Reading plane ..."); + PlaneParameter geometry = new PlaneParameter(); + geometry.setInstanceParameter(instanceParameter); + geometry.setName(name); + p.checkNextToken("p"); + geometry.setCenter(parsePoint()); + if (p.peekNextToken("n")) { + geometry.setNormal(parseVector()); + } else { + p.checkNextToken("p"); + geometry.setPoint1(parsePoint()); + p.checkNextToken("p"); + geometry.setPoint2(parsePoint()); + } + geometry.setup(api); + } else if (type.equals("generic-mesh")) { + UI.printInfo(Module.API, "Reading generic mesh: %s ... ", name); + GenericMeshParameter geometry = new GenericMeshParameter(); + geometry.setInstanceParameter(instanceParameter); + // parse vertices + p.checkNextToken("points"); + int np = p.getNextInt(); + float[] points = parseFloatArray(np * 3); + geometry.setPoints(points); + // parse triangle indices + p.checkNextToken("triangles"); + int nt = p.getNextInt(); + geometry.setTriangles(parseIntArray(nt * 3)); + // parse normals + p.checkNextToken("normals"); + if (p.peekNextToken("vertex")) { + geometry.setNormals(parseFloatArray(np * 3)); + } else if (p.peekNextToken("facevarying")) { + geometry.setFaceVaryingNormals(true); + geometry.setNormals(parseFloatArray(nt * 9)); + } else { + p.checkNextToken("none"); + } + + // parse texture coordinates + p.checkNextToken("uvs"); + if (p.peekNextToken("vertex")) { + geometry.setUvs(parseFloatArray(np * 2)); + } else if (p.peekNextToken("facevarying")) { + geometry.setFaceVaryingTextures(true); + geometry.setUvs(parseFloatArray(nt * 6)); + } else { + p.checkNextToken("none"); + } + if (p.peekNextToken("face_shaders")) { + geometry.setFaceShaders(parseIntArray(nt)); + } + geometry.setup(api); + } else if (type.equals("hair")) { + UI.printInfo(Module.API, "Reading hair curves: %s ... ", name); + HairParameter geometry = new HairParameter(); + geometry.setInstanceParameter(instanceParameter); + p.checkNextToken("segments"); + geometry.setSegments(p.getNextInt()); + p.checkNextToken("width"); + geometry.setWidth(p.getNextFloat()); + p.checkNextToken("points"); + geometry.setPoints(parseFloatArray(p.getNextInt())); + geometry.setup(api); + } else if (type.equals("janino-tesselatable")) { + UI.printInfo(Module.API, "Reading procedural primitive: %s ... ", name); + String typename = p.peekNextToken("typename") ? p.getNextToken() : PluginRegistry.shaderPlugins.generateUniqueName("janino_shader"); + if (PluginRegistry.tesselatablePlugins.registerPlugin(typename, p.getNextCodeBlock())) { + api.geometry(name, typename); + } + } else if (type.equals("teapot")) { + UI.printInfo(Module.API, "Reading teapot: %s ... ", name); + TeapotParameter geometry = new TeapotParameter(); + geometry.setInstanceParameter(instanceParameter); + geometry.setName(name); + + if (p.peekNextToken("subdivs")) { + geometry.setSubdivs(p.getNextInt()); + } + if (p.peekNextToken("smooth")) { + geometry.setSmooth(p.getNextBoolean()); + } + geometry.setup(api); + } else if (type.equals("gumbo")) { + UI.printInfo(Module.API, "Reading gumbo: %s ... ", name); + GumboParameter geometry = new GumboParameter(); + geometry.setInstanceParameter(instanceParameter); + geometry.setName(name); + + if (p.peekNextToken("subdivs")) { + geometry.setSubdivs(p.getNextInt()); + } + if (p.peekNextToken("smooth")) { + geometry.setSmooth(p.getNextBoolean()); + } + geometry.setup(api); + } else if (type.equals("julia")) { + UI.printInfo(Module.API, "Reading julia fractal: %s ... ", name); + JuliaParameter geometry = new JuliaParameter(); + geometry.setInstanceParameter(instanceParameter); + geometry.setName(name); + if (p.peekNextToken("q")) { + geometry.setCw(p.getNextFloat()); + geometry.setCx(p.getNextFloat()); + geometry.setCy(p.getNextFloat()); + geometry.setCz(p.getNextFloat()); + } + if (p.peekNextToken("iterations")) { + geometry.setIterations(p.getNextInt()); + } + if (p.peekNextToken("epsilon")) { + geometry.setEpsilon(p.getNextFloat()); + } + geometry.setup(api); + } else if (type.equals("particles") || type.equals("dlasurface")) { + ParticlesParameter geometry = new ParticlesParameter(); + geometry.setInstanceParameter(instanceParameter); + geometry.setName(name); + if (type.equals("dlasurface")) { + UI.printWarning(Module.API, "Deprecated object type: \"dlasurface\" - please use \"particles\" instead"); + } + float[] data; + if (p.peekNextToken("filename")) { + // FIXME: this code should be moved into an on demand loading + // primitive + String filename = p.getNextToken(); + boolean littleEndian = false; + if (p.peekNextToken("little_endian")) { + littleEndian = true; + } + UI.printInfo(Module.USER, "Loading particle file: %s", filename); + File file = new File(filename); + FileInputStream stream = new FileInputStream(filename); + MappedByteBuffer map = stream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()); + if (littleEndian) + map.order(ByteOrder.LITTLE_ENDIAN); + FloatBuffer buffer = map.asFloatBuffer(); + data = new float[buffer.capacity()]; + for (int i = 0; i < data.length; i++) { + data[i] = buffer.get(i); + } + stream.close(); + } else { + p.checkNextToken("points"); + int n = p.getNextInt(); + data = parseFloatArray(n * 3); // read 3n points + } + + geometry.setPoints(data); + + if (p.peekNextToken("num")) { + geometry.setNum(p.getNextInt()); + } else { + geometry.setNum(data.length / 3); + } + + p.checkNextToken("radius"); + geometry.setRadius(p.getNextFloat()); + geometry.setup(api); + } else if (type.equals("file-mesh")) { + UI.printInfo(Module.API, "Reading file mesh: %s ... ", name); + FileMeshParameter geometry = new FileMeshParameter(); + geometry.setInstanceParameter(instanceParameter); + geometry.setName(name); + + p.checkNextToken("filename"); + geometry.setFilename(p.getNextToken()); + + if (p.peekNextToken("smooth_normals")) { + geometry.setSmoothNormals(p.getNextBoolean()); + } + geometry.setup(api); + } else if (type.equals("bezier-mesh")) { + UI.printInfo(Module.API, "Reading bezier mesh: %s ... ", name); + BezierMeshParameter geometry = new BezierMeshParameter(); + geometry.setInstanceParameter(instanceParameter); + geometry.setName(name); + + p.checkNextToken("n"); + //int nu, nv; + + geometry.setNu(p.getNextInt()); + geometry.setNv(p.getNextInt()); + + if (p.peekNextToken("wrap")) { + geometry.setUwrap(p.getNextBoolean()); + geometry.setVwrap(p.getNextBoolean()); + } + p.checkNextToken("points"); + float[] points = new float[3 * geometry.getNu() * geometry.getNv()]; + for (int i = 0; i < points.length; i++) { + points[i] = p.getNextFloat(); + } + + geometry.setPoints(points); + + if (p.peekNextToken("subdivs")) { + geometry.setSubdivs(p.getNextInt()); + } + if (p.peekNextToken("smooth")) { + geometry.setSmooth(p.getNextBoolean()); + } + geometry.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized object type: %s", p.getNextToken()); + } + + p.checkNextToken("}"); + } + + private void parseInstanceBlock(SunflowAPIInterface api) throws ParserException, IOException { + InstanceParameter parameter = new InstanceParameter(); + p.checkNextToken("{"); + p.checkNextToken("name"); + parameter.name(p.getNextToken()); + UI.printInfo(Module.API, "Reading instance: %s ...", parameter.name()); + p.checkNextToken("geometry"); + parameter.geometry(p.getNextToken()); + + TransformParameter transformParameter = parseTransform(); + parameter.transform(transformParameter); + + String[] shaders; + if (p.peekNextToken("shaders")) { + int n = p.getNextInt(); + shaders = new String[n]; + for (int i = 0; i < n; i++) { + shaders[i] = p.getNextToken(); + } + } else { + p.checkNextToken("shader"); + shaders = new String[]{p.getNextToken()}; + } + parameter.shaders(shaders); + + String[] modifiers = null; + if (p.peekNextToken("modifiers")) { + int n = p.getNextInt(); + modifiers = new String[n]; + for (int i = 0; i < n; i++) { + modifiers[i] = p.getNextToken(); + } + } else if (p.peekNextToken("modifier")) { + modifiers = new String[]{p.getNextToken()}; + } + parameter.modifiers(modifiers); + parameter.setup(api); + + p.checkNextToken("}"); + } + + private TransformParameter parseTransform() throws ParserException, IOException { + TransformParameter transformParameter = new TransformParameter(); + p.checkNextToken("transform"); + if (p.peekNextToken("steps")) { + int n = p.getNextInt(); + + p.checkNextToken("times"); + float[] times = new float[n]; + for (int i = 0; i < n; i++) { + times[i] = p.getNextFloat(); + } + transformParameter.setTimes(times); + + Matrix4[] transforms = new Matrix4[n]; + for (int i = 0; i < n; i++) { + transforms[i] = parseMatrix(); + } + } else { + Matrix4[] transforms = new Matrix4[]{parseMatrix()}; + transformParameter.setTransforms(transforms); + } + return transformParameter; + } + + private TransformParameter checkParseTransform() throws ParserException, IOException { + TransformParameter transformParameter = new TransformParameter(); + if(p.peekNextToken("transform")) { + if (p.peekNextToken("steps")) { + int n = p.getNextInt(); + + p.checkNextToken("times"); + float[] times = new float[n]; + for (int i = 0; i < n; i++) { + times[i] = p.getNextFloat(); + } + transformParameter.setTimes(times); + + Matrix4[] transforms = new Matrix4[n]; + for (int i = 0; i < n; i++) { + transforms[i] = parseMatrix(); + } + } else { + Matrix4[] transforms = new Matrix4[]{parseMatrix()}; + transformParameter.setTransforms(transforms); + } + } else { + return null; + } + return transformParameter; + } + + private void parseLightBlock(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException { + p.checkNextToken("{"); + p.checkNextToken("type"); + if (p.peekNextToken("mesh")) { + UI.printWarning(Module.API, "Deprecated light type: mesh"); + p.checkNextToken("name"); + String name = p.getNextToken(); + UI.printInfo(Module.API, "Reading light mesh: %s ...", name); + p.checkNextToken("emit"); + api.parameter("radiance", null, parseColor().getRGB()); + int samples = numLightSamples; + if (p.peekNextToken("samples")) + samples = p.getNextInt(); + else + UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", samples); + api.parameter("samples", samples); + int numVertices = p.getNextInt(); + int numTriangles = p.getNextInt(); + float[] points = new float[3 * numVertices]; + int[] triangles = new int[3 * numTriangles]; + for (int i = 0; i < numVertices; i++) { + p.checkNextToken("v"); + points[3 * i + 0] = p.getNextFloat(); + points[3 * i + 1] = p.getNextFloat(); + points[3 * i + 2] = p.getNextFloat(); + // ignored + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + p.getNextFloat(); + } + for (int i = 0; i < numTriangles; i++) { + p.checkNextToken("t"); + triangles[3 * i + 0] = p.getNextInt(); + triangles[3 * i + 1] = p.getNextInt(); + triangles[3 * i + 2] = p.getNextInt(); + } + api.parameter("points", "point", "vertex", points); + api.parameter("triangles", triangles); + api.light(name, "triangle_mesh"); + } else if (p.peekNextToken("point")) { + UI.printInfo(Module.API, "Reading point light ..."); + PointLightParameter light = new PointLightParameter(); + light.setName(generateUniqueName("pointlight")); + + Color color; + if (p.peekNextToken("color")) { + color = parseColor(); + p.checkNextToken("power"); + float power = p.getNextFloat(); + color.mul(power); + } else { + UI.printWarning(Module.API, "Deprecated color specification - please use color and power instead"); + p.checkNextToken("power"); + color = parseColor(); + } + light.setColor(color); + + p.checkNextToken("p"); + light.setCenter(parsePoint()); + light.setup(api); + } else if (p.peekNextToken("spherical")) { + UI.printInfo(Module.API, "Reading spherical light ..."); + SphereLightParameter light = new SphereLightParameter(); + light.setName(generateUniqueName("spherelight")); + p.checkNextToken("color"); + Color color = parseColor(); + p.checkNextToken("radiance"); + float power = p.getNextFloat(); + color.mul(power); + light.setRadiance(color); + p.checkNextToken("center"); + light.setCenter(parsePoint()); + p.checkNextToken("radius"); + light.setRadius(p.getNextFloat()); + p.checkNextToken("samples"); + light.setSamples(p.getNextInt()); + light.setup(api); + } else if (p.peekNextToken("directional")) { + UI.printInfo(Module.API, "Reading directional light ..."); + DirectionalLightParameter light = new DirectionalLightParameter(); + light.setName(generateUniqueName("dirlight")); + p.checkNextToken("source"); + light.setSource(parsePoint()); + p.checkNextToken("target"); + light.setDirection(parsePoint()); + p.checkNextToken("radius"); + light.setRadius(p.getNextFloat()); + p.checkNextToken("emit"); + Color color = parseColor(); + if (p.peekNextToken("intensity")) { + float power = p.getNextFloat(); + color.mul(power); + } else { + UI.printWarning(Module.API, "Deprecated color specification - please use emit and intensity instead"); + } + light.setRadiance(color); + light.setup(api); + } else if (p.peekNextToken("ibl")) { + UI.printInfo(Module.API, "Reading image based light ..."); + ImageBasedLightParameter light = new ImageBasedLightParameter(); + light.setName(generateUniqueName("ibl")); + p.checkNextToken("image"); + light.setTexture(p.getNextToken()); + p.checkNextToken("center"); + light.setCenter(parseVector()); + p.checkNextToken("up"); + light.setUp(parseVector()); + p.checkNextToken("lock"); + light.setFixed(p.getNextBoolean()); + + light.setSamples(numLightSamples); + + if (p.peekNextToken("samples")) { + light.setSamples(p.getNextInt()); + } else { + UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", numLightSamples); + } + + if (p.peekNextToken("lowsamples")) { + light.setLowSamples(p.getNextInt()); + } + + light.setup(api); + } else if (p.peekNextToken("meshlight")) { + p.checkNextToken("name"); + TriangleMeshLightParameter light = new TriangleMeshLightParameter(); + light.setName(p.getNextToken()); + + UI.printInfo(Module.API, "Reading meshlight: %s ...", light.getName()); + p.checkNextToken("emit"); + Color color = parseColor(); + if (p.peekNextToken("radiance")) { + float r = p.getNextFloat(); + color.mul(r); + } else { + UI.printWarning(Module.API, "Deprecated color specification - please use emit and radiance instead"); + } + light.setRadiance(color); + light.setSamples(numLightSamples); + + if (p.peekNextToken("samples")) { + light.setSamples(p.getNextInt()); + } else { + UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", light.getSamples()); + } + + // parse vertices + p.checkNextToken("points"); + int np = p.getNextInt(); + float[] points = parseFloatArray(np * 3); + light.setPoints(points); + + // parse triangle indices + p.checkNextToken("triangles"); + int nt = p.getNextInt(); + int[] triangles = parseIntArray(nt * 3); + light.setTriangles(triangles); + light.setup(api); + } else if (p.peekNextToken("sunsky")) { + SunSkyLightParameter light = new SunSkyLightParameter(); + light.setName(generateUniqueName("sunsky")); + p.checkNextToken("up"); + light.setUp(parseVector()); + p.checkNextToken("east"); + light.setEast(parseVector()); + p.checkNextToken("sundir"); + light.setSunDirection(parseVector()); + p.checkNextToken("turbidity"); + light.setTurbidity(p.getNextFloat()); + + // TODO Is possible not to have samples in sun sky? + // light.setSamples(numLightSamples); + if (p.peekNextToken("samples")) { + light.setSamples(p.getNextInt()); + } + + if (p.peekNextToken("ground.extendsky")) { + light.setExtendSky(p.getNextBoolean()); + } else if (p.peekNextToken("ground.color")) { + light.setGroundColor(parseColor()); + } + light.setup(api); + } else if (p.peekNextToken("cornellbox")) { + UI.printInfo(Module.API, "Reading cornell box ..."); + CornellBoxLightParameter light = new CornellBoxLightParameter(); + light.setName(generateUniqueName("cornellbox")); + + p.checkNextToken("corner0"); + light.setMin(parsePoint()); + p.checkNextToken("corner1"); + light.setMax(parsePoint()); + p.checkNextToken("left"); + light.setLeft(parseColor()); + p.checkNextToken("right"); + light.setRight(parseColor()); + p.checkNextToken("top"); + light.setTop(parseColor()); + p.checkNextToken("bottom"); + light.setBottom(parseColor()); + p.checkNextToken("back"); + light.setBack(parseColor()); + p.checkNextToken("emit"); + light.setRadiance(parseColor()); + + // TODO Is possible not to have samples in cornell box? + // light.setSamples(numLightSamples); + if (p.peekNextToken("samples")) { + light.setSamples(p.getNextInt()); + } + light.setup(api); + } else { + UI.printWarning(Module.API, "Unrecognized object type: %s", p.getNextToken()); + } + p.checkNextToken("}"); + } + + private Color parseColor() throws IOException, ParserException, ColorSpecificationException { + if (p.peekNextToken("{")) { + String space = p.getNextToken(); + int req = ColorFactory.getRequiredDataValues(space); + if (req == -2) { + UI.printWarning(Module.API, "Unrecognized color space: %s", space); + return null; + } else if (req == -1) { + // array required, parse how many values are required + req = p.getNextInt(); + } + Color c = ColorFactory.createColor(space, parseFloatArray(req)); + p.checkNextToken("}"); + return c; + } else { + float r = p.getNextFloat(); + float g = p.getNextFloat(); + float b = p.getNextFloat(); + return ColorFactory.createColor(null, r, g, b); + } + } + + private Point3 parsePoint() throws IOException { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + return new Point3(x, y, z); + } + + private Vector3 parseVector() throws IOException { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + return new Vector3(x, y, z); + } + + private int[] parseIntArray(int size) throws IOException { + int[] data = new int[size]; + for (int i = 0; i < size; i++) { + data[i] = p.getNextInt(); + } + return data; + } + + private float[] parseFloatArray(int size) throws IOException { + float[] data = new float[size]; + for (int i = 0; i < size; i++) { + data[i] = p.getNextFloat(); + } + return data; + } + + private Matrix4 parseMatrix() throws IOException, ParserException { + if (p.peekNextToken("row")) { + return new Matrix4(parseFloatArray(16), true); + } else if (p.peekNextToken("col")) { + return new Matrix4(parseFloatArray(16), false); + } else { + Matrix4 m = Matrix4.IDENTITY; + p.checkNextToken("{"); + while (!p.peekNextToken("}")) { + Matrix4 t = null; + if (p.peekNextToken("translate")) { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + t = Matrix4.translation(x, y, z); + } else if (p.peekNextToken("scaleu")) { + float s = p.getNextFloat(); + t = Matrix4.scale(s); + } else if (p.peekNextToken("scale")) { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + t = Matrix4.scale(x, y, z); + } else if (p.peekNextToken("rotatex")) { + float angle = p.getNextFloat(); + t = Matrix4.rotateX((float) Math.toRadians(angle)); + } else if (p.peekNextToken("rotatey")) { + float angle = p.getNextFloat(); + t = Matrix4.rotateY((float) Math.toRadians(angle)); + } else if (p.peekNextToken("rotatez")) { + float angle = p.getNextFloat(); + t = Matrix4.rotateZ((float) Math.toRadians(angle)); + } else if (p.peekNextToken("rotate")) { + float x = p.getNextFloat(); + float y = p.getNextFloat(); + float z = p.getNextFloat(); + float angle = p.getNextFloat(); + t = Matrix4.rotate(x, y, z, (float) Math.toRadians(angle)); + } else + UI.printWarning(Module.API, "Unrecognized transformation type: %s", p.getNextToken()); + if (t != null) + m = t.multiply(m); + } + return m; + } + } } \ No newline at end of file diff --git a/src/org/sunflow/core/parser/ShaveRibParser.java b/src/main/java/org/sunflow/core/parser/ShaveRibParser.java similarity index 100% rename from src/org/sunflow/core/parser/ShaveRibParser.java rename to src/main/java/org/sunflow/core/parser/ShaveRibParser.java diff --git a/src/org/sunflow/core/parser/TriParser.java b/src/main/java/org/sunflow/core/parser/TriParser.java similarity index 100% rename from src/org/sunflow/core/parser/TriParser.java rename to src/main/java/org/sunflow/core/parser/TriParser.java diff --git a/src/org/sunflow/core/photonmap/CausticPhotonMap.java b/src/main/java/org/sunflow/core/photonmap/CausticPhotonMap.java similarity index 100% rename from src/org/sunflow/core/photonmap/CausticPhotonMap.java rename to src/main/java/org/sunflow/core/photonmap/CausticPhotonMap.java diff --git a/src/org/sunflow/core/photonmap/GlobalPhotonMap.java b/src/main/java/org/sunflow/core/photonmap/GlobalPhotonMap.java similarity index 100% rename from src/org/sunflow/core/photonmap/GlobalPhotonMap.java rename to src/main/java/org/sunflow/core/photonmap/GlobalPhotonMap.java diff --git a/src/org/sunflow/core/photonmap/GridPhotonMap.java b/src/main/java/org/sunflow/core/photonmap/GridPhotonMap.java similarity index 100% rename from src/org/sunflow/core/photonmap/GridPhotonMap.java rename to src/main/java/org/sunflow/core/photonmap/GridPhotonMap.java diff --git a/src/org/sunflow/core/primitive/Background.java b/src/main/java/org/sunflow/core/primitive/Background.java similarity index 100% rename from src/org/sunflow/core/primitive/Background.java rename to src/main/java/org/sunflow/core/primitive/Background.java diff --git a/src/org/sunflow/core/primitive/BanchoffSurface.java b/src/main/java/org/sunflow/core/primitive/BanchoffSurface.java similarity index 100% rename from src/org/sunflow/core/primitive/BanchoffSurface.java rename to src/main/java/org/sunflow/core/primitive/BanchoffSurface.java diff --git a/src/org/sunflow/core/primitive/Box.java b/src/main/java/org/sunflow/core/primitive/Box.java similarity index 85% rename from src/org/sunflow/core/primitive/Box.java rename to src/main/java/org/sunflow/core/primitive/Box.java index 3964631..c6e7aea 100644 --- a/src/org/sunflow/core/primitive/Box.java +++ b/src/main/java/org/sunflow/core/primitive/Box.java @@ -7,10 +7,7 @@ import org.sunflow.core.Ray; import org.sunflow.core.ShadingState; import org.sunflow.core.ParameterList.FloatParameter; -import org.sunflow.math.BoundingBox; -import org.sunflow.math.Matrix4; -import org.sunflow.math.OrthoNormalBasis; -import org.sunflow.math.Vector3; +import org.sunflow.math.*; public class Box implements PrimitiveList { private float minX, minY, minZ; @@ -22,19 +19,16 @@ public Box() { } public boolean update(ParameterList pl, SunflowAPI api) { - FloatParameter pts = pl.getPointArray("points"); - if (pts != null) { - BoundingBox bounds = new BoundingBox(); - for (int i = 0; i < pts.data.length; i += 3) - bounds.include(pts.data[i], pts.data[i + 1], pts.data[i + 2]); - // cube extents - minX = bounds.getMinimum().x; - minY = bounds.getMinimum().y; - minZ = bounds.getMinimum().z; - maxX = bounds.getMaximum().x; - maxY = bounds.getMaximum().y; - maxZ = bounds.getMaximum().z; - } + Point3 min = pl.getPoint("min", null); + Point3 max = pl.getPoint("max", null); + + minX = min.x; + minY = min.y; + minZ = min.z; + maxX = max.x; + maxY = max.y; + maxZ = max.z; + return true; } diff --git a/src/org/sunflow/core/primitive/CornellBox.java b/src/main/java/org/sunflow/core/primitive/CornellBox.java similarity index 88% rename from src/org/sunflow/core/primitive/CornellBox.java rename to src/main/java/org/sunflow/core/primitive/CornellBox.java index 6b2c88c..d70540f 100644 --- a/src/org/sunflow/core/primitive/CornellBox.java +++ b/src/main/java/org/sunflow/core/primitive/CornellBox.java @@ -10,6 +10,8 @@ import org.sunflow.core.Ray; import org.sunflow.core.Shader; import org.sunflow.core.ShadingState; +import org.sunflow.core.parameter.light.CornellBoxLightParameter; +import org.sunflow.core.parameter.light.LightParameter; import org.sunflow.image.Color; import org.sunflow.math.BoundingBox; import org.sunflow.math.Matrix4; @@ -66,22 +68,22 @@ private void updateGeometry(Point3 c0, Point3 c1) { } public boolean update(ParameterList pl, SunflowAPI api) { - Point3 corner0 = pl.getPoint("corner0", null); - Point3 corner1 = pl.getPoint("corner1", null); + Point3 corner0 = pl.getPoint(CornellBoxLightParameter.PARAM_MIN_CORNER, null); + Point3 corner1 = pl.getPoint(CornellBoxLightParameter.PARAM_MAX_CORNER, null); if (corner0 != null && corner1 != null) { updateGeometry(corner0, corner1); } // shader colors - left = pl.getColor("leftColor", left); - right = pl.getColor("rightColor", right); - top = pl.getColor("topColor", top); - bottom = pl.getColor("bottomColor", bottom); - back = pl.getColor("backColor", back); + left = pl.getColor(CornellBoxLightParameter.PARAM_LEFT_COLOR, left); + right = pl.getColor(CornellBoxLightParameter.PARAM_RIGHT_COLOR, right); + top = pl.getColor(CornellBoxLightParameter.PARAM_TOP_COLOR, top); + bottom = pl.getColor(CornellBoxLightParameter.PARAM_BOTTOM_COLOR, bottom); + back = pl.getColor(CornellBoxLightParameter.PARAM_BACK_COLOR, back); // light - radiance = pl.getColor("radiance", radiance); - samples = pl.getInt("samples", samples); + radiance = pl.getColor(LightParameter.PARAM_RADIANCE, radiance); + samples = pl.getInt(LightParameter.PARAM_SAMPLES, samples); return true; } @@ -443,4 +445,44 @@ public PrimitiveList getBakingPrimitives() { public Instance createInstance() { return Instance.createTemporary(this, null, this); } + + public Color getLeft() { + return left; + } + + public void setLeft(Color left) { + this.left = left; + } + + public Color getRight() { + return right; + } + + public void setRight(Color right) { + this.right = right; + } + + public Color getTop() { + return top; + } + + public void setTop(Color top) { + this.top = top; + } + + public Color getBottom() { + return bottom; + } + + public void setBottom(Color bottom) { + this.bottom = bottom; + } + + public Color getBack() { + return back; + } + + public void setBack(Color back) { + this.back = back; + } } \ No newline at end of file diff --git a/src/org/sunflow/core/primitive/CubeGrid.java b/src/main/java/org/sunflow/core/primitive/CubeGrid.java similarity index 96% rename from src/org/sunflow/core/primitive/CubeGrid.java rename to src/main/java/org/sunflow/core/primitive/CubeGrid.java index 75b1224..52c8a58 100644 --- a/src/org/sunflow/core/primitive/CubeGrid.java +++ b/src/main/java/org/sunflow/core/primitive/CubeGrid.java @@ -285,4 +285,8 @@ public BoundingBox getWorldBounds(Matrix4 o2w) { return bounds; return o2w.transform(bounds); } + + public PrimitiveList getBakingPrimitives() { + return null; + } } \ No newline at end of file diff --git a/src/org/sunflow/core/primitive/Cylinder.java b/src/main/java/org/sunflow/core/primitive/Cylinder.java similarity index 100% rename from src/org/sunflow/core/primitive/Cylinder.java rename to src/main/java/org/sunflow/core/primitive/Cylinder.java diff --git a/src/org/sunflow/core/primitive/Hair.java b/src/main/java/org/sunflow/core/primitive/Hair.java similarity index 100% rename from src/org/sunflow/core/primitive/Hair.java rename to src/main/java/org/sunflow/core/primitive/Hair.java diff --git a/src/org/sunflow/core/primitive/JuliaFractal.java b/src/main/java/org/sunflow/core/primitive/JuliaFractal.java similarity index 100% rename from src/org/sunflow/core/primitive/JuliaFractal.java rename to src/main/java/org/sunflow/core/primitive/JuliaFractal.java diff --git a/src/org/sunflow/core/primitive/ParticleSurface.java b/src/main/java/org/sunflow/core/primitive/ParticleSurface.java similarity index 100% rename from src/org/sunflow/core/primitive/ParticleSurface.java rename to src/main/java/org/sunflow/core/primitive/ParticleSurface.java diff --git a/src/org/sunflow/core/primitive/Plane.java b/src/main/java/org/sunflow/core/primitive/Plane.java similarity index 100% rename from src/org/sunflow/core/primitive/Plane.java rename to src/main/java/org/sunflow/core/primitive/Plane.java diff --git a/src/org/sunflow/core/primitive/QuadMesh.java b/src/main/java/org/sunflow/core/primitive/QuadMesh.java similarity index 100% rename from src/org/sunflow/core/primitive/QuadMesh.java rename to src/main/java/org/sunflow/core/primitive/QuadMesh.java diff --git a/src/org/sunflow/core/primitive/Sphere.java b/src/main/java/org/sunflow/core/primitive/Sphere.java similarity index 100% rename from src/org/sunflow/core/primitive/Sphere.java rename to src/main/java/org/sunflow/core/primitive/Sphere.java diff --git a/src/org/sunflow/core/primitive/SphereFlake.java b/src/main/java/org/sunflow/core/primitive/SphereFlake.java similarity index 100% rename from src/org/sunflow/core/primitive/SphereFlake.java rename to src/main/java/org/sunflow/core/primitive/SphereFlake.java diff --git a/src/org/sunflow/core/primitive/Torus.java b/src/main/java/org/sunflow/core/primitive/Torus.java similarity index 100% rename from src/org/sunflow/core/primitive/Torus.java rename to src/main/java/org/sunflow/core/primitive/Torus.java diff --git a/src/org/sunflow/core/primitive/TriangleMesh.java b/src/main/java/org/sunflow/core/primitive/TriangleMesh.java similarity index 95% rename from src/org/sunflow/core/primitive/TriangleMesh.java rename to src/main/java/org/sunflow/core/primitive/TriangleMesh.java index 399a043..b314d3b 100644 --- a/src/org/sunflow/core/primitive/TriangleMesh.java +++ b/src/main/java/org/sunflow/core/primitive/TriangleMesh.java @@ -30,12 +30,14 @@ public class TriangleMesh implements PrimitiveList { private FloatParameter normals; private FloatParameter uvs; private byte[] faceShaders; + private boolean backfaceCull = false; public static void setSmallTriangles(boolean smallTriangles) { - if (smallTriangles) + if (smallTriangles) { UI.printInfo(Module.GEOM, "Small trimesh mode: enabled"); - else + } else { UI.printInfo(Module.GEOM, "Small trimesh mode: disabled"); + } TriangleMesh.smallTriangles = smallTriangles; } @@ -50,11 +52,13 @@ public void writeObj(String filename) { try { FileWriter file = new FileWriter(filename); file.write(String.format("o object\n")); - for (int i = 0; i < points.length; i += 3) + for (int i = 0; i < points.length; i += 3) { file.write(String.format("v %g %g %g\n", points[i], points[i + 1], points[i + 2])); + } file.write("s off\n"); - for (int i = 0; i < triangles.length; i += 3) + for (int i = 0; i < triangles.length; i += 3) { file.write(String.format("f %d %d %d\n", triangles[i] + 1, triangles[i + 1] + 1, triangles[i + 2] + 1)); + } file.close(); } catch (IOException e) { e.printStackTrace(); @@ -62,6 +66,7 @@ public void writeObj(String filename) { } public boolean update(ParameterList pl, SunflowAPI api) { + this.backfaceCull = pl.getBoolean("backfaceCull", false); boolean updatedTopology = false; { int[] triangles = pl.getIntArray("triangles"); @@ -122,10 +127,11 @@ public float getPrimitiveBound(int primID, int i) { int b = 3 * triangles[tri + 1]; int c = 3 * triangles[tri + 2]; int axis = i >>> 1; - if ((i & 1) == 0) + if ((i & 1) == 0) { return MathUtils.min(points[a + axis], points[b + axis], points[c + axis]); - else + } else { return MathUtils.max(points[a + axis], points[b + axis], points[c + axis]); + } } public BoundingBox getWorldBounds(Matrix4 o2w) { @@ -192,6 +198,14 @@ public void intersectPrimitive(Ray r, int primID, IntersectionState state) { // alternative test -- disabled for now // intersectPrimitiveRobust(r, primID, state); + + if (backfaceCull && normals != null) { + int tri = primID * 3; + Vector3 normal = new Vector3(normals.data[tri], normals.data[tri + 1], normals.data[tri + 2]); + if (Vector3.dot(normal, r.getDirection()) >= 1e-5) + return; + } + if (triaccel != null) { // optional fast intersection method triaccel[primID].intersect(r, primID, state); @@ -329,8 +343,9 @@ public void init() { return; } triaccel = new WaldTriangle[nt]; - for (int i = 0; i < nt; i++) + for (int i = 0; i < nt; i++) { triaccel[i] = new WaldTriangle(this, i); + } } } diff --git a/src/org/sunflow/core/renderer/BucketRenderer.java b/src/main/java/org/sunflow/core/renderer/BucketRenderer.java similarity index 93% rename from src/org/sunflow/core/renderer/BucketRenderer.java rename to src/main/java/org/sunflow/core/renderer/BucketRenderer.java index 3cea7f9..235fca2 100644 --- a/src/org/sunflow/core/renderer/BucketRenderer.java +++ b/src/main/java/org/sunflow/core/renderer/BucketRenderer.java @@ -1,6 +1,8 @@ package org.sunflow.core.renderer; import org.sunflow.PluginRegistry; +import org.sunflow.core.parameter.BucketParameter; +import org.sunflow.core.parameter.ImageParameter; import org.sunflow.core.BucketOrder; import org.sunflow.core.Display; import org.sunflow.core.Filter; @@ -61,7 +63,7 @@ public class BucketRenderer implements ImageSampler { public BucketRenderer() { bucketSize = 32; - bucketOrderName = "hilbert"; + bucketOrderName = BucketParameter.ORDER_HILBERT; displayAA = false; contrastThreshold = 0.1f; filterName = "box"; @@ -75,14 +77,14 @@ public boolean prepare(Options options, Scene scene, int w, int h) { imageHeight = h; // fetch options - bucketSize = options.getInt("bucket.size", bucketSize); - bucketOrderName = options.getString("bucket.order", bucketOrderName); - minAADepth = options.getInt("aa.min", minAADepth); - maxAADepth = options.getInt("aa.max", maxAADepth); - superSampling = options.getInt("aa.samples", superSampling); - displayAA = options.getBoolean("aa.display", displayAA); - jitter = options.getBoolean("aa.jitter", jitter); - contrastThreshold = options.getFloat("aa.contrast", contrastThreshold); + bucketSize = options.getInt(BucketParameter.PARAM_BUCKET_SIZE, bucketSize); + bucketOrderName = options.getString(BucketParameter.PARAM_BUCKET_ORDER, bucketOrderName); + minAADepth = options.getInt(ImageParameter.PARAM_AA_MIN, minAADepth); + maxAADepth = options.getInt(ImageParameter.PARAM_AA_MAX, maxAADepth); + superSampling = options.getInt(ImageParameter.PARAM_AA_SAMPLES, superSampling); + displayAA = options.getBoolean(ImageParameter.PARAM_AA_DISPLAY, displayAA); + jitter = options.getBoolean(ImageParameter.PARAM_AA_JITTER, jitter); + contrastThreshold = options.getFloat(ImageParameter.PARAM_AA_CONTRAST, contrastThreshold); // limit bucket size and compute number of buckets in each direction bucketSize = MathUtils.clamp(bucketSize, 16, 512); diff --git a/src/org/sunflow/core/renderer/MultipassRenderer.java b/src/main/java/org/sunflow/core/renderer/MultipassRenderer.java similarity index 92% rename from src/org/sunflow/core/renderer/MultipassRenderer.java rename to src/main/java/org/sunflow/core/renderer/MultipassRenderer.java index 6331042..05455ca 100644 --- a/src/org/sunflow/core/renderer/MultipassRenderer.java +++ b/src/main/java/org/sunflow/core/renderer/MultipassRenderer.java @@ -33,6 +33,7 @@ public class MultipassRenderer implements ImageSampler { private int numSamples; private float invNumSamples; private boolean shadingCache; + private float cacheDirTolerance = 1e-5f, cacheNormalTolerance = 1e-4f; public MultipassRenderer() { bucketSize = 32; @@ -51,6 +52,8 @@ public boolean prepare(Options options, Scene scene, int w, int h) { bucketOrderName = options.getString("bucket.order", bucketOrderName); numSamples = options.getInt("aa.samples", numSamples); shadingCache = options.getBoolean("aa.cache", shadingCache); + cacheDirTolerance = options.getFloat("aa.cacheDirTolerance", cacheDirTolerance); + cacheNormalTolerance = options.getFloat("aa.cacheNormalTolerance", cacheNormalTolerance); // limit bucket size and compute number of buckets in each direction bucketSize = MathUtils.clamp(bucketSize, 16, 512); @@ -109,7 +112,7 @@ private class BucketThread extends Thread { BucketThread(int threadID) { this.threadID = threadID; istate = new IntersectionState(); - cache = shadingCache ? new ShadingCache() : null; + cache = shadingCache ? new ShadingCache(cacheDirTolerance, cacheNormalTolerance) : null; } @Override @@ -117,6 +120,9 @@ public void run() { while (true) { int bx, by; synchronized (MultipassRenderer.this) { + if (UI.taskCanceled()) + return; + if (bucketCounter >= bucketCoords.length) return; UI.taskUpdate(bucketCounter); @@ -175,6 +181,9 @@ private void renderBucket(Display display, int bx, int by, int threadID, Interse bucketAlpha[i] = a * invNumSamples; if (cache != null) cache.reset(); + + if (UI.taskCanceled()) + return; } } // update pixels diff --git a/src/org/sunflow/core/renderer/ProgressiveRenderer.java b/src/main/java/org/sunflow/core/renderer/ProgressiveRenderer.java similarity index 100% rename from src/org/sunflow/core/renderer/ProgressiveRenderer.java rename to src/main/java/org/sunflow/core/renderer/ProgressiveRenderer.java diff --git a/src/org/sunflow/core/renderer/SimpleRenderer.java b/src/main/java/org/sunflow/core/renderer/SimpleRenderer.java similarity index 100% rename from src/org/sunflow/core/renderer/SimpleRenderer.java rename to src/main/java/org/sunflow/core/renderer/SimpleRenderer.java diff --git a/src/org/sunflow/core/shader/AmbientOcclusionShader.java b/src/main/java/org/sunflow/core/shader/AmbientOcclusionShader.java similarity index 100% rename from src/org/sunflow/core/shader/AmbientOcclusionShader.java rename to src/main/java/org/sunflow/core/shader/AmbientOcclusionShader.java diff --git a/src/org/sunflow/core/shader/AnisotropicWardShader.java b/src/main/java/org/sunflow/core/shader/AnisotropicWardShader.java similarity index 100% rename from src/org/sunflow/core/shader/AnisotropicWardShader.java rename to src/main/java/org/sunflow/core/shader/AnisotropicWardShader.java diff --git a/src/org/sunflow/core/shader/ConstantShader.java b/src/main/java/org/sunflow/core/shader/ConstantShader.java similarity index 100% rename from src/org/sunflow/core/shader/ConstantShader.java rename to src/main/java/org/sunflow/core/shader/ConstantShader.java diff --git a/src/org/sunflow/core/shader/DiffuseShader.java b/src/main/java/org/sunflow/core/shader/DiffuseShader.java similarity index 100% rename from src/org/sunflow/core/shader/DiffuseShader.java rename to src/main/java/org/sunflow/core/shader/DiffuseShader.java diff --git a/src/org/sunflow/core/shader/GlassShader.java b/src/main/java/org/sunflow/core/shader/GlassShader.java similarity index 100% rename from src/org/sunflow/core/shader/GlassShader.java rename to src/main/java/org/sunflow/core/shader/GlassShader.java diff --git a/src/org/sunflow/core/shader/IDShader.java b/src/main/java/org/sunflow/core/shader/IDShader.java similarity index 100% rename from src/org/sunflow/core/shader/IDShader.java rename to src/main/java/org/sunflow/core/shader/IDShader.java diff --git a/src/org/sunflow/core/shader/MirrorShader.java b/src/main/java/org/sunflow/core/shader/MirrorShader.java similarity index 100% rename from src/org/sunflow/core/shader/MirrorShader.java rename to src/main/java/org/sunflow/core/shader/MirrorShader.java diff --git a/src/org/sunflow/core/shader/NormalShader.java b/src/main/java/org/sunflow/core/shader/NormalShader.java similarity index 100% rename from src/org/sunflow/core/shader/NormalShader.java rename to src/main/java/org/sunflow/core/shader/NormalShader.java diff --git a/src/org/sunflow/core/shader/PhongShader.java b/src/main/java/org/sunflow/core/shader/PhongShader.java similarity index 100% rename from src/org/sunflow/core/shader/PhongShader.java rename to src/main/java/org/sunflow/core/shader/PhongShader.java diff --git a/src/org/sunflow/core/shader/PrimIDShader.java b/src/main/java/org/sunflow/core/shader/PrimIDShader.java similarity index 100% rename from src/org/sunflow/core/shader/PrimIDShader.java rename to src/main/java/org/sunflow/core/shader/PrimIDShader.java diff --git a/src/org/sunflow/core/shader/QuickGrayShader.java b/src/main/java/org/sunflow/core/shader/QuickGrayShader.java similarity index 100% rename from src/org/sunflow/core/shader/QuickGrayShader.java rename to src/main/java/org/sunflow/core/shader/QuickGrayShader.java diff --git a/src/org/sunflow/core/shader/ShinyDiffuseShader.java b/src/main/java/org/sunflow/core/shader/ShinyDiffuseShader.java similarity index 100% rename from src/org/sunflow/core/shader/ShinyDiffuseShader.java rename to src/main/java/org/sunflow/core/shader/ShinyDiffuseShader.java diff --git a/src/org/sunflow/core/shader/SimpleShader.java b/src/main/java/org/sunflow/core/shader/SimpleShader.java similarity index 100% rename from src/org/sunflow/core/shader/SimpleShader.java rename to src/main/java/org/sunflow/core/shader/SimpleShader.java diff --git a/src/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java b/src/main/java/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java similarity index 100% rename from src/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java rename to src/main/java/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java diff --git a/src/org/sunflow/core/shader/TexturedDiffuseShader.java b/src/main/java/org/sunflow/core/shader/TexturedDiffuseShader.java similarity index 100% rename from src/org/sunflow/core/shader/TexturedDiffuseShader.java rename to src/main/java/org/sunflow/core/shader/TexturedDiffuseShader.java diff --git a/src/org/sunflow/core/shader/TexturedPhongShader.java b/src/main/java/org/sunflow/core/shader/TexturedPhongShader.java similarity index 100% rename from src/org/sunflow/core/shader/TexturedPhongShader.java rename to src/main/java/org/sunflow/core/shader/TexturedPhongShader.java diff --git a/src/org/sunflow/core/shader/TexturedShinyDiffuseShader.java b/src/main/java/org/sunflow/core/shader/TexturedShinyDiffuseShader.java similarity index 100% rename from src/org/sunflow/core/shader/TexturedShinyDiffuseShader.java rename to src/main/java/org/sunflow/core/shader/TexturedShinyDiffuseShader.java diff --git a/src/org/sunflow/core/shader/TexturedWardShader.java b/src/main/java/org/sunflow/core/shader/TexturedWardShader.java similarity index 100% rename from src/org/sunflow/core/shader/TexturedWardShader.java rename to src/main/java/org/sunflow/core/shader/TexturedWardShader.java diff --git a/src/org/sunflow/core/shader/UVShader.java b/src/main/java/org/sunflow/core/shader/UVShader.java similarity index 100% rename from src/org/sunflow/core/shader/UVShader.java rename to src/main/java/org/sunflow/core/shader/UVShader.java diff --git a/src/org/sunflow/core/shader/UberShader.java b/src/main/java/org/sunflow/core/shader/UberShader.java similarity index 100% rename from src/org/sunflow/core/shader/UberShader.java rename to src/main/java/org/sunflow/core/shader/UberShader.java diff --git a/src/org/sunflow/core/shader/ViewCausticsShader.java b/src/main/java/org/sunflow/core/shader/ViewCausticsShader.java similarity index 100% rename from src/org/sunflow/core/shader/ViewCausticsShader.java rename to src/main/java/org/sunflow/core/shader/ViewCausticsShader.java diff --git a/src/org/sunflow/core/shader/ViewGlobalPhotonsShader.java b/src/main/java/org/sunflow/core/shader/ViewGlobalPhotonsShader.java similarity index 100% rename from src/org/sunflow/core/shader/ViewGlobalPhotonsShader.java rename to src/main/java/org/sunflow/core/shader/ViewGlobalPhotonsShader.java diff --git a/src/org/sunflow/core/shader/ViewIrradianceShader.java b/src/main/java/org/sunflow/core/shader/ViewIrradianceShader.java similarity index 100% rename from src/org/sunflow/core/shader/ViewIrradianceShader.java rename to src/main/java/org/sunflow/core/shader/ViewIrradianceShader.java diff --git a/src/org/sunflow/core/shader/WireframeShader.java b/src/main/java/org/sunflow/core/shader/WireframeShader.java similarity index 100% rename from src/org/sunflow/core/shader/WireframeShader.java rename to src/main/java/org/sunflow/core/shader/WireframeShader.java diff --git a/src/org/sunflow/core/tesselatable/BezierMesh.java b/src/main/java/org/sunflow/core/tesselatable/BezierMesh.java similarity index 100% rename from src/org/sunflow/core/tesselatable/BezierMesh.java rename to src/main/java/org/sunflow/core/tesselatable/BezierMesh.java diff --git a/src/org/sunflow/core/tesselatable/FileMesh.java b/src/main/java/org/sunflow/core/tesselatable/FileMesh.java similarity index 97% rename from src/org/sunflow/core/tesselatable/FileMesh.java rename to src/main/java/org/sunflow/core/tesselatable/FileMesh.java index a33883d..72e5d14 100644 --- a/src/org/sunflow/core/tesselatable/FileMesh.java +++ b/src/main/java/org/sunflow/core/tesselatable/FileMesh.java @@ -100,8 +100,9 @@ public PrimitiveList tesselate() { tris.add(Integer.parseInt(f[3]) - 1); } } - if (lineNumber % 100000 == 0) + if (lineNumber % 100000 == 0) { UI.printInfo(Module.GEOM, "OBJ - * Parsed %7d lines ...", lineNumber); + } lineNumber++; } file.close(); @@ -161,8 +162,9 @@ public PrimitiveList tesselate() { e.printStackTrace(); UI.printError(Module.GEOM, "Unable to read mesh file \"%s\" - I/O error occured", filename); } - } else + } else { UI.printWarning(Module.GEOM, "Unable to read mesh file \"%s\" - unrecognized format", filename); + } return null; } diff --git a/src/org/sunflow/core/tesselatable/Gumbo.java b/src/main/java/org/sunflow/core/tesselatable/Gumbo.java similarity index 100% rename from src/org/sunflow/core/tesselatable/Gumbo.java rename to src/main/java/org/sunflow/core/tesselatable/Gumbo.java diff --git a/src/org/sunflow/core/tesselatable/Teapot.java b/src/main/java/org/sunflow/core/tesselatable/Teapot.java similarity index 100% rename from src/org/sunflow/core/tesselatable/Teapot.java rename to src/main/java/org/sunflow/core/tesselatable/Teapot.java diff --git a/src/org/sunflow/image/Bitmap.java b/src/main/java/org/sunflow/image/Bitmap.java similarity index 100% rename from src/org/sunflow/image/Bitmap.java rename to src/main/java/org/sunflow/image/Bitmap.java diff --git a/src/org/sunflow/image/BitmapReader.java b/src/main/java/org/sunflow/image/BitmapReader.java similarity index 100% rename from src/org/sunflow/image/BitmapReader.java rename to src/main/java/org/sunflow/image/BitmapReader.java diff --git a/src/org/sunflow/image/BitmapWriter.java b/src/main/java/org/sunflow/image/BitmapWriter.java similarity index 100% rename from src/org/sunflow/image/BitmapWriter.java rename to src/main/java/org/sunflow/image/BitmapWriter.java diff --git a/src/org/sunflow/image/BlackbodySpectrum.java b/src/main/java/org/sunflow/image/BlackbodySpectrum.java similarity index 100% rename from src/org/sunflow/image/BlackbodySpectrum.java rename to src/main/java/org/sunflow/image/BlackbodySpectrum.java diff --git a/src/org/sunflow/image/ChromaticitySpectrum.java b/src/main/java/org/sunflow/image/ChromaticitySpectrum.java similarity index 100% rename from src/org/sunflow/image/ChromaticitySpectrum.java rename to src/main/java/org/sunflow/image/ChromaticitySpectrum.java diff --git a/src/org/sunflow/image/Color.java b/src/main/java/org/sunflow/image/Color.java similarity index 95% rename from src/org/sunflow/image/Color.java rename to src/main/java/org/sunflow/image/Color.java index 9281ef0..ac8b177 100644 --- a/src/org/sunflow/image/Color.java +++ b/src/main/java/org/sunflow/image/Color.java @@ -2,6 +2,8 @@ import org.sunflow.math.MathUtils; +import java.util.Objects; + public final class Color { private float r, g, b; public static final RGBSpace NATIVE_SPACE = RGBSpace.SRGB; @@ -367,4 +369,5 @@ public static final boolean hasContrast(Color c1, Color c2, float thresh) { public String toString() { return String.format("(%.3f, %.3f, %.3f)", r, g, b); } + } \ No newline at end of file diff --git a/src/org/sunflow/image/ColorEncoder.java b/src/main/java/org/sunflow/image/ColorEncoder.java similarity index 100% rename from src/org/sunflow/image/ColorEncoder.java rename to src/main/java/org/sunflow/image/ColorEncoder.java diff --git a/src/org/sunflow/image/ColorFactory.java b/src/main/java/org/sunflow/image/ColorFactory.java similarity index 100% rename from src/org/sunflow/image/ColorFactory.java rename to src/main/java/org/sunflow/image/ColorFactory.java diff --git a/src/org/sunflow/image/ConstantSpectralCurve.java b/src/main/java/org/sunflow/image/ConstantSpectralCurve.java similarity index 100% rename from src/org/sunflow/image/ConstantSpectralCurve.java rename to src/main/java/org/sunflow/image/ConstantSpectralCurve.java diff --git a/src/org/sunflow/image/IrregularSpectralCurve.java b/src/main/java/org/sunflow/image/IrregularSpectralCurve.java similarity index 100% rename from src/org/sunflow/image/IrregularSpectralCurve.java rename to src/main/java/org/sunflow/image/IrregularSpectralCurve.java diff --git a/src/org/sunflow/image/RGBSpace.java b/src/main/java/org/sunflow/image/RGBSpace.java similarity index 100% rename from src/org/sunflow/image/RGBSpace.java rename to src/main/java/org/sunflow/image/RGBSpace.java diff --git a/src/org/sunflow/image/RegularSpectralCurve.java b/src/main/java/org/sunflow/image/RegularSpectralCurve.java similarity index 100% rename from src/org/sunflow/image/RegularSpectralCurve.java rename to src/main/java/org/sunflow/image/RegularSpectralCurve.java diff --git a/src/org/sunflow/image/SpectralCurve.java b/src/main/java/org/sunflow/image/SpectralCurve.java similarity index 100% rename from src/org/sunflow/image/SpectralCurve.java rename to src/main/java/org/sunflow/image/SpectralCurve.java diff --git a/src/org/sunflow/image/XYZColor.java b/src/main/java/org/sunflow/image/XYZColor.java similarity index 100% rename from src/org/sunflow/image/XYZColor.java rename to src/main/java/org/sunflow/image/XYZColor.java diff --git a/src/org/sunflow/image/formats/BitmapBlack.java b/src/main/java/org/sunflow/image/formats/BitmapBlack.java similarity index 100% rename from src/org/sunflow/image/formats/BitmapBlack.java rename to src/main/java/org/sunflow/image/formats/BitmapBlack.java diff --git a/src/org/sunflow/image/formats/BitmapG8.java b/src/main/java/org/sunflow/image/formats/BitmapG8.java similarity index 100% rename from src/org/sunflow/image/formats/BitmapG8.java rename to src/main/java/org/sunflow/image/formats/BitmapG8.java diff --git a/src/org/sunflow/image/formats/BitmapGA8.java b/src/main/java/org/sunflow/image/formats/BitmapGA8.java similarity index 100% rename from src/org/sunflow/image/formats/BitmapGA8.java rename to src/main/java/org/sunflow/image/formats/BitmapGA8.java diff --git a/src/org/sunflow/image/formats/BitmapRGB8.java b/src/main/java/org/sunflow/image/formats/BitmapRGB8.java similarity index 100% rename from src/org/sunflow/image/formats/BitmapRGB8.java rename to src/main/java/org/sunflow/image/formats/BitmapRGB8.java diff --git a/src/org/sunflow/image/formats/BitmapRGBA8.java b/src/main/java/org/sunflow/image/formats/BitmapRGBA8.java similarity index 100% rename from src/org/sunflow/image/formats/BitmapRGBA8.java rename to src/main/java/org/sunflow/image/formats/BitmapRGBA8.java diff --git a/src/org/sunflow/image/formats/BitmapRGBE.java b/src/main/java/org/sunflow/image/formats/BitmapRGBE.java similarity index 100% rename from src/org/sunflow/image/formats/BitmapRGBE.java rename to src/main/java/org/sunflow/image/formats/BitmapRGBE.java diff --git a/src/org/sunflow/image/formats/BitmapXYZ.java b/src/main/java/org/sunflow/image/formats/BitmapXYZ.java similarity index 100% rename from src/org/sunflow/image/formats/BitmapXYZ.java rename to src/main/java/org/sunflow/image/formats/BitmapXYZ.java diff --git a/src/org/sunflow/image/formats/GenericBitmap.java b/src/main/java/org/sunflow/image/formats/GenericBitmap.java similarity index 100% rename from src/org/sunflow/image/formats/GenericBitmap.java rename to src/main/java/org/sunflow/image/formats/GenericBitmap.java diff --git a/src/org/sunflow/image/readers/BMPBitmapReader.java b/src/main/java/org/sunflow/image/readers/BMPBitmapReader.java similarity index 100% rename from src/org/sunflow/image/readers/BMPBitmapReader.java rename to src/main/java/org/sunflow/image/readers/BMPBitmapReader.java diff --git a/src/org/sunflow/image/readers/HDRBitmapReader.java b/src/main/java/org/sunflow/image/readers/HDRBitmapReader.java similarity index 100% rename from src/org/sunflow/image/readers/HDRBitmapReader.java rename to src/main/java/org/sunflow/image/readers/HDRBitmapReader.java diff --git a/src/org/sunflow/image/readers/IGIBitmapReader.java b/src/main/java/org/sunflow/image/readers/IGIBitmapReader.java similarity index 100% rename from src/org/sunflow/image/readers/IGIBitmapReader.java rename to src/main/java/org/sunflow/image/readers/IGIBitmapReader.java diff --git a/src/org/sunflow/image/readers/JPGBitmapReader.java b/src/main/java/org/sunflow/image/readers/JPGBitmapReader.java similarity index 100% rename from src/org/sunflow/image/readers/JPGBitmapReader.java rename to src/main/java/org/sunflow/image/readers/JPGBitmapReader.java diff --git a/src/org/sunflow/image/readers/PNGBitmapReader.java b/src/main/java/org/sunflow/image/readers/PNGBitmapReader.java similarity index 100% rename from src/org/sunflow/image/readers/PNGBitmapReader.java rename to src/main/java/org/sunflow/image/readers/PNGBitmapReader.java diff --git a/src/org/sunflow/image/readers/TGABitmapReader.java b/src/main/java/org/sunflow/image/readers/TGABitmapReader.java similarity index 100% rename from src/org/sunflow/image/readers/TGABitmapReader.java rename to src/main/java/org/sunflow/image/readers/TGABitmapReader.java diff --git a/src/org/sunflow/image/writers/EXRBitmapWriter.java b/src/main/java/org/sunflow/image/writers/EXRBitmapWriter.java similarity index 100% rename from src/org/sunflow/image/writers/EXRBitmapWriter.java rename to src/main/java/org/sunflow/image/writers/EXRBitmapWriter.java diff --git a/src/org/sunflow/image/writers/HDRBitmapWriter.java b/src/main/java/org/sunflow/image/writers/HDRBitmapWriter.java similarity index 100% rename from src/org/sunflow/image/writers/HDRBitmapWriter.java rename to src/main/java/org/sunflow/image/writers/HDRBitmapWriter.java diff --git a/src/org/sunflow/image/writers/IGIBitmapWriter.java b/src/main/java/org/sunflow/image/writers/IGIBitmapWriter.java similarity index 100% rename from src/org/sunflow/image/writers/IGIBitmapWriter.java rename to src/main/java/org/sunflow/image/writers/IGIBitmapWriter.java diff --git a/src/org/sunflow/image/writers/PNGBitmapWriter.java b/src/main/java/org/sunflow/image/writers/PNGBitmapWriter.java similarity index 100% rename from src/org/sunflow/image/writers/PNGBitmapWriter.java rename to src/main/java/org/sunflow/image/writers/PNGBitmapWriter.java diff --git a/src/org/sunflow/image/writers/TGABitmapWriter.java b/src/main/java/org/sunflow/image/writers/TGABitmapWriter.java similarity index 100% rename from src/org/sunflow/image/writers/TGABitmapWriter.java rename to src/main/java/org/sunflow/image/writers/TGABitmapWriter.java diff --git a/src/org/sunflow/math/BoundingBox.java b/src/main/java/org/sunflow/math/BoundingBox.java similarity index 100% rename from src/org/sunflow/math/BoundingBox.java rename to src/main/java/org/sunflow/math/BoundingBox.java diff --git a/src/org/sunflow/math/MathUtils.java b/src/main/java/org/sunflow/math/MathUtils.java similarity index 100% rename from src/org/sunflow/math/MathUtils.java rename to src/main/java/org/sunflow/math/MathUtils.java diff --git a/src/org/sunflow/math/Matrix4.java b/src/main/java/org/sunflow/math/Matrix4.java similarity index 100% rename from src/org/sunflow/math/Matrix4.java rename to src/main/java/org/sunflow/math/Matrix4.java diff --git a/src/org/sunflow/math/MovingMatrix4.java b/src/main/java/org/sunflow/math/MovingMatrix4.java similarity index 100% rename from src/org/sunflow/math/MovingMatrix4.java rename to src/main/java/org/sunflow/math/MovingMatrix4.java diff --git a/src/org/sunflow/math/OrthoNormalBasis.java b/src/main/java/org/sunflow/math/OrthoNormalBasis.java similarity index 100% rename from src/org/sunflow/math/OrthoNormalBasis.java rename to src/main/java/org/sunflow/math/OrthoNormalBasis.java diff --git a/src/org/sunflow/math/PerlinScalar.java b/src/main/java/org/sunflow/math/PerlinScalar.java similarity index 100% rename from src/org/sunflow/math/PerlinScalar.java rename to src/main/java/org/sunflow/math/PerlinScalar.java diff --git a/src/org/sunflow/math/PerlinVector.java b/src/main/java/org/sunflow/math/PerlinVector.java similarity index 100% rename from src/org/sunflow/math/PerlinVector.java rename to src/main/java/org/sunflow/math/PerlinVector.java diff --git a/src/org/sunflow/math/Point2.java b/src/main/java/org/sunflow/math/Point2.java similarity index 100% rename from src/org/sunflow/math/Point2.java rename to src/main/java/org/sunflow/math/Point2.java diff --git a/src/org/sunflow/math/Point3.java b/src/main/java/org/sunflow/math/Point3.java similarity index 81% rename from src/org/sunflow/math/Point3.java rename to src/main/java/org/sunflow/math/Point3.java index cc1bf13..4659877 100644 --- a/src/org/sunflow/math/Point3.java +++ b/src/main/java/org/sunflow/math/Point3.java @@ -129,4 +129,24 @@ public static final Vector3 normal(Point3 p0, Point3 p1, Point3 p2, Vector3 dest public final String toString() { return String.format("(%.2f, %.2f, %.2f)", x, y, z); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Point3 point3 = (Point3) o; + + if (Float.compare(point3.x, x) != 0) return false; + if (Float.compare(point3.y, y) != 0) return false; + return Float.compare(point3.z, z) == 0; + } + + @Override + public int hashCode() { + int result = (x != +0.0f ? Float.floatToIntBits(x) : 0); + result = 31 * result + (y != +0.0f ? Float.floatToIntBits(y) : 0); + result = 31 * result + (z != +0.0f ? Float.floatToIntBits(z) : 0); + return result; + } } \ No newline at end of file diff --git a/src/org/sunflow/math/QMC.java b/src/main/java/org/sunflow/math/QMC.java similarity index 100% rename from src/org/sunflow/math/QMC.java rename to src/main/java/org/sunflow/math/QMC.java diff --git a/src/org/sunflow/math/Solvers.java b/src/main/java/org/sunflow/math/Solvers.java similarity index 100% rename from src/org/sunflow/math/Solvers.java rename to src/main/java/org/sunflow/math/Solvers.java diff --git a/src/org/sunflow/math/Vector3.java b/src/main/java/org/sunflow/math/Vector3.java similarity index 87% rename from src/org/sunflow/math/Vector3.java rename to src/main/java/org/sunflow/math/Vector3.java index 30ed598..681477f 100644 --- a/src/org/sunflow/math/Vector3.java +++ b/src/main/java/org/sunflow/math/Vector3.java @@ -1,5 +1,7 @@ package org.sunflow.math; +import java.util.Objects; + public final class Vector3 { private static final float[] COS_THETA = new float[256]; private static final float[] SIN_THETA = new float[256]; @@ -192,4 +194,19 @@ public static final Vector3 sub(Vector3 v1, Vector3 v2, Vector3 dest) { public final String toString() { return String.format("(%.2f, %.2f, %.2f)", x, y, z); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Vector3 vector3 = (Vector3) o; + return Float.compare(vector3.x, x) == 0 && + Float.compare(vector3.y, y) == 0 && + Float.compare(vector3.z, z) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(x, y, z); + } } \ No newline at end of file diff --git a/src/org/sunflow/system/BenchmarkFramework.java b/src/main/java/org/sunflow/system/BenchmarkFramework.java similarity index 100% rename from src/org/sunflow/system/BenchmarkFramework.java rename to src/main/java/org/sunflow/system/BenchmarkFramework.java diff --git a/src/org/sunflow/system/BenchmarkTest.java b/src/main/java/org/sunflow/system/BenchmarkTest.java similarity index 100% rename from src/org/sunflow/system/BenchmarkTest.java rename to src/main/java/org/sunflow/system/BenchmarkTest.java diff --git a/src/org/sunflow/system/ByteUtil.java b/src/main/java/org/sunflow/system/ByteUtil.java similarity index 100% rename from src/org/sunflow/system/ByteUtil.java rename to src/main/java/org/sunflow/system/ByteUtil.java diff --git a/src/org/sunflow/system/FileUtils.java b/src/main/java/org/sunflow/system/FileUtils.java similarity index 100% rename from src/org/sunflow/system/FileUtils.java rename to src/main/java/org/sunflow/system/FileUtils.java diff --git a/src/org/sunflow/system/ImagePanel.java b/src/main/java/org/sunflow/system/ImagePanel.java similarity index 89% rename from src/org/sunflow/system/ImagePanel.java rename to src/main/java/org/sunflow/system/ImagePanel.java index 77c7e18..67fef2a 100644 --- a/src/org/sunflow/system/ImagePanel.java +++ b/src/main/java/org/sunflow/system/ImagePanel.java @@ -25,6 +25,7 @@ public class ImagePanel extends JPanel implements Display { private float xo, yo; private float w, h; private long repaintCounter; + private final boolean dullPreviousImage; private class ScrollZoomListener extends MouseInputAdapter { int mx; @@ -85,7 +86,12 @@ public void mouseWheelMoved(MouseWheelEvent e) { } public ImagePanel() { + this(false); + } + + public ImagePanel(boolean dullPreviousImage) { setPreferredSize(new Dimension(640, 480)); + this.dullPreviousImage = dullPreviousImage; image = null; xo = yo = 0; w = h = 0; @@ -104,6 +110,10 @@ public void save(String filename) { } } + public BufferedImage getImage() { + return image; + } + private synchronized void drag(int dx, int dy) { xo += dx; yo += dy; @@ -177,11 +187,13 @@ public synchronized void fit() { public synchronized void imageBegin(int w, int h, int bucketSize) { if (image != null && w == image.getWidth() && h == image.getHeight()) { - // dull image if it has same resolution (75%) - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - int rgba = image.getRGB(x, y); - image.setRGB(x, y, ((rgba & 0xFEFEFEFE) >>> 1) + ((rgba & 0xFCFCFCFC) >>> 2)); + if (dullPreviousImage) { + // dull image if it has same resolution (75%) + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int rgba = image.getRGB(x, y); + image.setRGB(x, y, ((rgba & 0xFEFEFEFE) >>> 1) + ((rgba & 0xFCFCFCFC) >>> 2)); + } } } } else { diff --git a/src/org/sunflow/system/Memory.java b/src/main/java/org/sunflow/system/Memory.java similarity index 100% rename from src/org/sunflow/system/Memory.java rename to src/main/java/org/sunflow/system/Memory.java diff --git a/src/org/sunflow/system/Parser.java b/src/main/java/org/sunflow/system/Parser.java similarity index 100% rename from src/org/sunflow/system/Parser.java rename to src/main/java/org/sunflow/system/Parser.java diff --git a/src/org/sunflow/system/Plugins.java b/src/main/java/org/sunflow/system/Plugins.java similarity index 90% rename from src/org/sunflow/system/Plugins.java rename to src/main/java/org/sunflow/system/Plugins.java index 991e9ee..a346cfc 100644 --- a/src/org/sunflow/system/Plugins.java +++ b/src/main/java/org/sunflow/system/Plugins.java @@ -1,9 +1,7 @@ package org.sunflow.system; +import org.codehaus.commons.compiler.CompileException; import org.codehaus.janino.ClassBodyEvaluator; -import org.codehaus.janino.CompileException; -import org.codehaus.janino.Parser.ParseException; -import org.codehaus.janino.Scanner.ScanException; import org.sunflow.system.UI.Module; import org.sunflow.util.FastHashMap; @@ -110,12 +108,6 @@ public boolean registerPlugin(String name, String sourceCode) { } catch (CompileException e) { UI.printError(Module.API, "Plugin \"%s\" could not be declared - %s", name, e.getLocalizedMessage()); return false; - } catch (ParseException e) { - UI.printError(Module.API, "Plugin \"%s\" could not be declared - %s", name, e.getLocalizedMessage()); - return false; - } catch (ScanException e) { - UI.printError(Module.API, "Plugin \"%s\" could not be declared - %s", name, e.getLocalizedMessage()); - return false; } } diff --git a/src/org/sunflow/system/RenderGlobalsPanel.java b/src/main/java/org/sunflow/system/RenderGlobalsPanel.java similarity index 100% rename from src/org/sunflow/system/RenderGlobalsPanel.java rename to src/main/java/org/sunflow/system/RenderGlobalsPanel.java diff --git a/src/org/sunflow/system/SearchPath.java b/src/main/java/org/sunflow/system/SearchPath.java similarity index 100% rename from src/org/sunflow/system/SearchPath.java rename to src/main/java/org/sunflow/system/SearchPath.java diff --git a/src/main/java/org/sunflow/system/SystemUtil.java b/src/main/java/org/sunflow/system/SystemUtil.java new file mode 100644 index 0000000..b93019a --- /dev/null +++ b/src/main/java/org/sunflow/system/SystemUtil.java @@ -0,0 +1,24 @@ +package org.sunflow.system; + +public class SystemUtil { + + /** + * This is a quick system test which verifies that the user has launched + * Java properly. + */ + public static void runSystemCheck() { + final long RECOMMENDED_MAX_SIZE = 800; + long maxMb = Runtime.getRuntime().maxMemory() / 1048576; + if (maxMb < RECOMMENDED_MAX_SIZE) + UI.printError(UI.Module.API, "JVM available memory is below %d MB (found %d MB only).\nPlease make sure you launched the program with the -Xmx command line options.", RECOMMENDED_MAX_SIZE, maxMb); + String compiler = System.getProperty("java.vm.name"); + if (compiler == null || !(compiler.contains("HotSpot") && compiler.contains("Server"))) + UI.printError(UI.Module.API, "You do not appear to be running Sun's server JVM\nPerformance may suffer"); + UI.printDetailed(UI.Module.API, "Java environment settings:"); + UI.printDetailed(UI.Module.API, " * Max memory available : %d MB", maxMb); + UI.printDetailed(UI.Module.API, " * Virtual machine name : %s", compiler == null ? "= 0.0) { - x -= (t * dir.x); - y -= (t * dir.y); - z -= (t * dir.z); - if (((x * x) + (y * y) + (z * z)) <= r2) { - Point3 p = new Point3(); - p.x = src.x + x; - p.y = src.y + y; - p.z = src.z + z; - LightSample dest = new LightSample(); - dest.setShadowRay(new Ray(state.getPoint(), p)); - dest.setRadiance(radiance, radiance); - dest.traceShadow(state); - state.addSample(dest); - } - } - } - } - - public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) { - float phi = (float) (2 * Math.PI * randX1); - float s = (float) Math.sqrt(1.0f - randY1); - dir.x = r * (float) Math.cos(phi) * s; - dir.y = r * (float) Math.sin(phi) * s; - dir.z = 0; - basis.transform(dir); - Point3.add(src, dir, p); - dir.set(this.dir); - power.set(radiance).mul((float) Math.PI * r2); - } - - public float getPower() { - return radiance.copy().mul((float) Math.PI * r2).getLuminance(); - } - - public Instance createInstance() { - return null; - } -} \ No newline at end of file diff --git a/src/test/java/org/sunflow/SunflowAPITest.java b/src/test/java/org/sunflow/SunflowAPITest.java new file mode 100644 index 0000000..3441afd --- /dev/null +++ b/src/test/java/org/sunflow/SunflowAPITest.java @@ -0,0 +1,33 @@ +package org.sunflow; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class SunflowAPITest { + + SunflowAPI api; + + @Before + public void setUp() { + api = new SunflowAPI(); + } + + + @Test + public void testReset() { + Assert.assertNotNull(api.scene); + Assert.assertNotNull(api.includeSearchPath); + Assert.assertNotNull(api.textureSearchPath); + Assert.assertNotNull(api.parameterList); + Assert.assertNotNull(api.renderObjects); + Assert.assertEquals(1, api.currentFrame); + } + + @Test + public void testParameters() { + api.parameter("hello", "world"); + Assert.assertEquals("world", api.parameterList.getString("hello", "")); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/BackgroundParameterTest.java b/src/test/java/org/sunflow/core/parameter/BackgroundParameterTest.java new file mode 100644 index 0000000..e3cd822 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/BackgroundParameterTest.java @@ -0,0 +1,41 @@ +package org.sunflow.core.parameter; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Instance; +import org.sunflow.core.shader.ConstantShader; +import org.sunflow.image.Color; + +public class BackgroundParameterTest { + + SunflowAPI api; + BackgroundParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new BackgroundParameter(); + } + + @Test + public void testSetupAPI() { + parameter.setColor(new Color(1f,0,0)); + + // Set parameters + parameter.setup(api); + + Assert.assertTrue(api.getRenderObjects().has(BackgroundParameter.PARAM_BACKGROUND_INSTANCE)); + Assert.assertTrue(api.getRenderObjects().has(BackgroundParameter.PARAM_BACKGROUND_SHADER)); + Assert.assertTrue(api.getRenderObjects().has(BackgroundParameter.PARAM_BACKGROUND)); + + Instance instance = (Instance) api.getRenderObjects(). + get(BackgroundParameter.PARAM_BACKGROUND_INSTANCE).obj; + ConstantShader constantShader = (ConstantShader) instance.getShader(0); + Color color = constantShader.getRadiance(null); + + Assert.assertArrayEquals(parameter.color.getRGB(), color.getRGB(), 0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/BucketParameterTest.java b/src/test/java/org/sunflow/core/parameter/BucketParameterTest.java new file mode 100644 index 0000000..1112e08 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/BucketParameterTest.java @@ -0,0 +1,35 @@ +package org.sunflow.core.parameter; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Options; + +public class BucketParameterTest { + + SunflowAPI api; + BucketParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new BucketParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setSize(10); + parameter.setOrder(BucketParameter.ORDER_HILBERT); + + // Set parameters + parameter.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(parameter.getSize(), options.getInt(BucketParameter.PARAM_BUCKET_SIZE,0)); + Assert.assertEquals(parameter.getOrder(), options.getString(BucketParameter.PARAM_BUCKET_ORDER,"")); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/ImageParameterTest.java b/src/test/java/org/sunflow/core/parameter/ImageParameterTest.java new file mode 100644 index 0000000..e1d7a7f --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/ImageParameterTest.java @@ -0,0 +1,55 @@ +package org.sunflow.core.parameter; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Options; + +public class ImageParameterTest { + + SunflowAPI api; + ImageParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new ImageParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.resolutionX = 320; + parameter.resolutionY = 240; + + parameter.aaMin = 1; + parameter.aaMax = 1; + parameter.aaSamples = 2; + parameter.aaContrast = 1.1f; + parameter.aaJitter = true; + parameter.aaCache = true; + + parameter.filter = "filter"; + parameter.sampler = "sampler"; + + // Set parameters + parameter.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(parameter.resolutionX, options.getInt(ImageParameter.PARAM_RESOLUTION_X,0)); + Assert.assertEquals(parameter.resolutionY, options.getInt(ImageParameter.PARAM_RESOLUTION_Y,0)); + + Assert.assertEquals(parameter.aaMin, options.getInt(ImageParameter.PARAM_AA_MIN,0)); + Assert.assertEquals(parameter.aaMax, options.getInt(ImageParameter.PARAM_AA_MAX,0)); + Assert.assertEquals(parameter.aaSamples, options.getInt(ImageParameter.PARAM_AA_SAMPLES,0)); + Assert.assertEquals(parameter.aaContrast, options.getFloat(ImageParameter.PARAM_AA_CONTRAST,0), 0); + Assert.assertEquals(parameter.aaCache, options.getBoolean(ImageParameter.PARAM_AA_CACHE,false)); + Assert.assertEquals(parameter.aaJitter, options.getBoolean(ImageParameter.PARAM_AA_JITTER,false)); + + Assert.assertEquals(parameter.filter, options.getString(ImageParameter.PARAM_FILTER,"")); + Assert.assertEquals(parameter.sampler, options.getString(ImageParameter.PARAM_SAMPLER,"")); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/InstanceParameterTest.java b/src/test/java/org/sunflow/core/parameter/InstanceParameterTest.java new file mode 100644 index 0000000..4948e37 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/InstanceParameterTest.java @@ -0,0 +1,30 @@ +package org.sunflow.core.parameter; + +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; + +public class InstanceParameterTest { + SunflowAPI api; + InstanceParameter parameter; + + @Before + public void setUp() { + api = mock(SunflowAPI.class); + api.reset(); + + parameter = new InstanceParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.name("uniqueName"); + parameter.setup(api); + + verify(api, times(1)).instance(anyString(), anyString()); + } +} diff --git a/src/test/java/org/sunflow/core/parameter/OverrideParameterTest.java b/src/test/java/org/sunflow/core/parameter/OverrideParameterTest.java new file mode 100644 index 0000000..436054f --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/OverrideParameterTest.java @@ -0,0 +1,35 @@ +package org.sunflow.core.parameter; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Options; + +public class OverrideParameterTest { + + SunflowAPI api; + OverrideParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new OverrideParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.shader = "shader"; + parameter.photons = true; + + // Set parameters + parameter.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(parameter.shader, options.getString(OverrideParameter.PARAM_OVERRIDE_SHADER,"")); + Assert.assertEquals(parameter.photons, options.getBoolean(OverrideParameter.PARAM_OVERRIDE_PHOTONS,false)); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/PhotonParameterTest.java b/src/test/java/org/sunflow/core/parameter/PhotonParameterTest.java new file mode 100644 index 0000000..55677c1 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/PhotonParameterTest.java @@ -0,0 +1,39 @@ +package org.sunflow.core.parameter; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Options; + +public class PhotonParameterTest { + + SunflowAPI api; + PhotonParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new PhotonParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.caustics.emit = 10; + parameter.caustics.map = "default_value"; + parameter.caustics.gather = 2; + parameter.caustics.radius = 1.2f; + + // Set parameters + parameter.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(parameter.caustics.map, options.getString(PhotonParameter.PARAM_CAUSTICS,"")); + Assert.assertEquals(parameter.caustics.emit, options.getInt(PhotonParameter.PARAM_CAUSTICS_EMIT,0)); + Assert.assertEquals(parameter.caustics.gather, options.getInt(PhotonParameter.PARAM_CAUSTICS_GATHER,0)); + Assert.assertEquals(parameter.caustics.radius, options.getFloat(PhotonParameter.PARAM_CAUSTICS_RADIUS,0), 0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/TraceDepthsParameterTest.java b/src/test/java/org/sunflow/core/parameter/TraceDepthsParameterTest.java new file mode 100644 index 0000000..79cb27e --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/TraceDepthsParameterTest.java @@ -0,0 +1,33 @@ +package org.sunflow.core.parameter; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; + +public class TraceDepthsParameterTest { + + SunflowAPI api; + TraceDepthsParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new TraceDepthsParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.diffuse = 1; + parameter.reflection = 2; + parameter.refraction = 3; + + // Set parameters + parameter.setup(api); + Assert.assertEquals(parameter.diffuse, api.getParameterList().getInt(TraceDepthsParameter.PARAM_DEPTHS_DIFFUSE,0)); + Assert.assertEquals(parameter.reflection, api.getParameterList().getInt(TraceDepthsParameter.PARAM_DEPTHS_REFLECTION,0)); + Assert.assertEquals(parameter.refraction, api.getParameterList().getInt(TraceDepthsParameter.PARAM_DEPTHS_REFRACTION,0)); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/camera/FishEyeCameraParameterTest.java b/src/test/java/org/sunflow/core/parameter/camera/FishEyeCameraParameterTest.java new file mode 100644 index 0000000..d08567e --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/camera/FishEyeCameraParameterTest.java @@ -0,0 +1,33 @@ +package org.sunflow.core.parameter.camera; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Camera; + +public class FishEyeCameraParameterTest { + + SunflowAPI api; + FishEyeCameraParameter camera; + + @Before + public void setUp() { + api = new SunflowAPI(); + camera = new FishEyeCameraParameter(); + } + + @Test + public void testSetupAPI() { + camera.name = "uniqueName"; + camera.shutterOpen = 1.2f; + camera.shutterClose = 3.2f; + + camera.setup(api); + + Camera apiCamera = (Camera) api.getRenderObjects().get(camera.name).obj; + Assert.assertEquals(camera.shutterOpen, apiCamera.getShutterOpen(), 0); + Assert.assertEquals(camera.shutterClose, apiCamera.getShutterClose(), 0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/camera/PinholeCameraParameterTest.java b/src/test/java/org/sunflow/core/parameter/camera/PinholeCameraParameterTest.java new file mode 100644 index 0000000..a55e831 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/camera/PinholeCameraParameterTest.java @@ -0,0 +1,33 @@ +package org.sunflow.core.parameter.camera; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Camera; + +public class PinholeCameraParameterTest { + + SunflowAPI api; + PinholeCameraParameter camera; + + @Before + public void setUp() { + api = new SunflowAPI(); + camera = new PinholeCameraParameter(); + } + + @Test + public void testSetupAPI() { + camera.name = "uniqueName"; + camera.shutterOpen = 1.2f; + camera.shutterClose = 3.2f; + + camera.setup(api); + + Camera apiCamera = (Camera) api.getRenderObjects().get(camera.name).obj; + Assert.assertEquals(camera.shutterOpen, apiCamera.getShutterOpen(), 0); + Assert.assertEquals(camera.shutterClose, apiCamera.getShutterClose(), 0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/camera/SphericalCameraParameterTest.java b/src/test/java/org/sunflow/core/parameter/camera/SphericalCameraParameterTest.java new file mode 100644 index 0000000..d17aaaf --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/camera/SphericalCameraParameterTest.java @@ -0,0 +1,33 @@ +package org.sunflow.core.parameter.camera; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Camera; + +public class SphericalCameraParameterTest { + + SunflowAPI api; + SphericalCameraParameter camera; + + @Before + public void setUp() { + api = new SunflowAPI(); + camera = new SphericalCameraParameter(); + } + + @Test + public void testSetupAPI() { + camera.name = "uniqueName"; + camera.shutterOpen = 1.2f; + camera.shutterClose = 3.2f; + + camera.setup(api); + + Camera apiCamera = (Camera) api.getRenderObjects().get(camera.name).obj; + Assert.assertEquals(camera.shutterOpen, apiCamera.getShutterOpen(), 0); + Assert.assertEquals(camera.shutterClose, apiCamera.getShutterClose(), 0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/camera/ThinLensCameraParameterTest.java b/src/test/java/org/sunflow/core/parameter/camera/ThinLensCameraParameterTest.java new file mode 100644 index 0000000..d8b17e5 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/camera/ThinLensCameraParameterTest.java @@ -0,0 +1,33 @@ +package org.sunflow.core.parameter.camera; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Camera; + +public class ThinLensCameraParameterTest { + + SunflowAPI api; + ThinLensCameraParameter camera; + + @Before + public void setUp() { + api = new SunflowAPI(); + camera = new ThinLensCameraParameter(); + } + + @Test + public void testSetupAPI() { + camera.name = "uniqueName"; + camera.shutterOpen = 1.2f; + camera.shutterClose = 3.2f; + + camera.setup(api); + + Camera apiCamera = (Camera) api.getRenderObjects().get(camera.name).obj; + Assert.assertEquals(camera.shutterOpen, apiCamera.getShutterOpen(), 0); + Assert.assertEquals(camera.shutterClose, apiCamera.getShutterClose(), 0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/BanchoffParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/BanchoffParameterTest.java new file mode 100644 index 0000000..8599c4c --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/BanchoffParameterTest.java @@ -0,0 +1,32 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class BanchoffParameterTest { + + SunflowAPI api; + BanchOffParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new BanchOffParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/BezierMeshParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/BezierMeshParameterTest.java new file mode 100644 index 0000000..02b83b4 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/BezierMeshParameterTest.java @@ -0,0 +1,36 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class BezierMeshParameterTest { + + SunflowAPI api; + BezierMeshParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new BezierMeshParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + parameter.setPoints(new float[]{0, 0, 0, 1, 1, 1, 1, 2, 1, 2, 0, 0}); + parameter.nu = 2; + parameter.nv = 2; + parameter.setSubdivs(2); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/BoxParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/BoxParameterTest.java new file mode 100644 index 0000000..463b45f --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/BoxParameterTest.java @@ -0,0 +1,36 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; +import org.sunflow.math.Point3; + +public class BoxParameterTest { + + SunflowAPI api; + BoxParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new BoxParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + parameter.setMin(new Point3(-1,-1,-1)); + parameter.setMax(new Point3(1,1,1)); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/CylinderParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/CylinderParameterTest.java new file mode 100644 index 0000000..e604d98 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/CylinderParameterTest.java @@ -0,0 +1,32 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class CylinderParameterTest { + + SunflowAPI api; + CylinderParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new CylinderParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/FileMeshParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/FileMeshParameterTest.java new file mode 100644 index 0000000..6d4204a --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/FileMeshParameterTest.java @@ -0,0 +1,33 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class FileMeshParameterTest { + + SunflowAPI api; + FileMeshParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new FileMeshParameter(); + } + + // Ignoring test, a resource file is needed to test + // @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/GenericMeshParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/GenericMeshParameterTest.java new file mode 100644 index 0000000..fb75acf --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/GenericMeshParameterTest.java @@ -0,0 +1,34 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class GenericMeshParameterTest { + + SunflowAPI api; + GenericMeshParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new GenericMeshParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + parameter.setPoints(new float[]{0,0,0}); + parameter.setTriangles(new int[]{0}); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/GumboParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/GumboParameterTest.java new file mode 100644 index 0000000..03e1265 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/GumboParameterTest.java @@ -0,0 +1,32 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class GumboParameterTest { + + SunflowAPI api; + GumboParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new GumboParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/HairParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/HairParameterTest.java new file mode 100644 index 0000000..4d48a97 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/HairParameterTest.java @@ -0,0 +1,36 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class HairParameterTest { + + SunflowAPI api; + HairParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new HairParameter(); + } + + @Test + public void testSetupAPI() { + parameter.setWidth(1f); + parameter.setSegments(3); + parameter.setPoints(new float[]{0, 0, 0, 1, 1, 1, 2, 2, 2}); + + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/JuliaParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/JuliaParameterTest.java new file mode 100644 index 0000000..380eb7d --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/JuliaParameterTest.java @@ -0,0 +1,32 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class JuliaParameterTest { + + SunflowAPI api; + JuliaParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new JuliaParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/ParticlesParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/ParticlesParameterTest.java new file mode 100644 index 0000000..a05eb42 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/ParticlesParameterTest.java @@ -0,0 +1,34 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class ParticlesParameterTest { + + SunflowAPI api; + ParticlesParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new ParticlesParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + parameter.setNum(2); + parameter.setPoints(new float[]{0, 0, 0, 1, 1, 1}); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/PlaneParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/PlaneParameterTest.java new file mode 100644 index 0000000..f34cc47 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/PlaneParameterTest.java @@ -0,0 +1,37 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; +import org.sunflow.math.Point3; + +public class PlaneParameterTest { + + SunflowAPI api; + PlaneParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new PlaneParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + parameter.setCenter(new Point3(0,0,0)); + parameter.setPoint1(new Point3(0,0,0)); + parameter.setPoint2(new Point3(0,1,0)); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/SphereFlakeParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/SphereFlakeParameterTest.java new file mode 100644 index 0000000..42a5e7e --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/SphereFlakeParameterTest.java @@ -0,0 +1,32 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class SphereFlakeParameterTest { + + SunflowAPI api; + SphereFlakeParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new SphereFlakeParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/SphereParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/SphereParameterTest.java new file mode 100644 index 0000000..22046a6 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/SphereParameterTest.java @@ -0,0 +1,35 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; +import org.sunflow.math.Point3; + +public class SphereParameterTest { + + SunflowAPI api; + SphereParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new SphereParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + parameter.setCenter(new Point3(0,0,0)); + parameter.setRadius(1); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/TeapotParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/TeapotParameterTest.java new file mode 100644 index 0000000..4b97636 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/TeapotParameterTest.java @@ -0,0 +1,32 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class TeapotParameterTest { + + SunflowAPI api; + TeapotParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new TeapotParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/TorusParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/TorusParameterTest.java new file mode 100644 index 0000000..32dd020 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/TorusParameterTest.java @@ -0,0 +1,32 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class TorusParameterTest { + + SunflowAPI api; + TorusParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new TorusParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/geometry/TriangleMeshParameterTest.java b/src/test/java/org/sunflow/core/parameter/geometry/TriangleMeshParameterTest.java new file mode 100644 index 0000000..ec46f68 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/geometry/TriangleMeshParameterTest.java @@ -0,0 +1,34 @@ +package org.sunflow.core.parameter.geometry; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Geometry; + +public class TriangleMeshParameterTest { + + SunflowAPI api; + TriangleMeshParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new TriangleMeshParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + parameter.setPoints(new float[]{0,0,0}); + parameter.setTriangles(new int[]{0}); + + // Set parameters + parameter.setup(api); + + Geometry geometry = (Geometry) api.getRenderObjects().get(parameter.getName()).obj; + Assert.assertNotNull(geometry); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/gi/AmbientOcclusionGIParameterTest.java b/src/test/java/org/sunflow/core/parameter/gi/AmbientOcclusionGIParameterTest.java new file mode 100644 index 0000000..4a67c1e --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/gi/AmbientOcclusionGIParameterTest.java @@ -0,0 +1,41 @@ +package org.sunflow.core.parameter.gi; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Options; +import org.sunflow.image.Color; + +public class AmbientOcclusionGIParameterTest { + + SunflowAPI api; + AmbientOcclusionGIParameter gi; + + @Before + public void setUp() { + api = new SunflowAPI(); + gi = new AmbientOcclusionGIParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + gi.dark = new Color(0,1,0); + gi.bright = new Color(1,0,1); + gi.maxDist = 2.222f; + gi.samples = 99; + + // Set parameters + gi.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(GlobalIlluminationParameter.TYPE_AMBOCC, options.getString(GlobalIlluminationParameter.PARAM_ENGINE, "")); + Assert.assertArrayEquals(gi.bright.getRGB(), options.getColor(AmbientOcclusionGIParameter.PARAM_BRIGHT, null).getRGB(), 0); + Assert.assertArrayEquals(gi.dark.getRGB(), options.getColor(AmbientOcclusionGIParameter.PARAM_DARK, null).getRGB(), 0); + Assert.assertEquals(gi.samples, options.getInt(AmbientOcclusionGIParameter.PARAM_SAMPLES,0)); + Assert.assertEquals(gi.maxDist, options.getFloat(AmbientOcclusionGIParameter.PARAM_MAXDIST,0), 0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/gi/FakeGIParameterTest.java b/src/test/java/org/sunflow/core/parameter/gi/FakeGIParameterTest.java new file mode 100644 index 0000000..625ff0c --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/gi/FakeGIParameterTest.java @@ -0,0 +1,40 @@ +package org.sunflow.core.parameter.gi; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Options; +import org.sunflow.image.Color; +import org.sunflow.math.Vector3; + +public class FakeGIParameterTest { + + SunflowAPI api; + FakeGIParameter gi; + + @Before + public void setUp() { + api = new SunflowAPI(); + gi = new FakeGIParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + gi.ground = new Color(0,1,0); + gi.sky = new Color(1,0,1); + gi.up = new Vector3(1,2,4); + + // Set parameters + gi.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(GlobalIlluminationParameter.TYPE_FAKE, options.getString(GlobalIlluminationParameter.PARAM_ENGINE, "")); + Assert.assertArrayEquals(gi.ground.getRGB(), options.getColor(FakeGIParameter.PARAM_GROUND, null).getRGB(), 0); + Assert.assertArrayEquals(gi.sky.getRGB(), options.getColor(FakeGIParameter.PARAM_SKY, null).getRGB(), 0); + Assert.assertEquals(gi.up, options.getVector(FakeGIParameter.PARAM_UP,null)); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/gi/InstantGIParameterTest.java b/src/test/java/org/sunflow/core/parameter/gi/InstantGIParameterTest.java new file mode 100644 index 0000000..eaf6bd0 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/gi/InstantGIParameterTest.java @@ -0,0 +1,40 @@ +package org.sunflow.core.parameter.gi; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Options; + +public class InstantGIParameterTest { + + SunflowAPI api; + InstantGIParameter gi; + + @Before + public void setUp() { + api = new SunflowAPI(); + gi = new InstantGIParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + gi.biasSamples = 1; + gi.samples = 2; + gi.sets = 3; + gi.bias = 123f; + + // Set parameters + gi.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(GlobalIlluminationParameter.TYPE_IGI, options.getString(GlobalIlluminationParameter.PARAM_ENGINE, "")); + Assert.assertEquals(gi.biasSamples, options.getInt(InstantGIParameter.PARAM_BIAS_SAMPLES,0)); + Assert.assertEquals(gi.samples, options.getInt(InstantGIParameter.PARAM_SAMPLES,0)); + Assert.assertEquals(gi.sets, options.getInt(InstantGIParameter.PARAM_SETS,0)); + Assert.assertEquals(gi.bias, options.getFloat(InstantGIParameter.PARAM_BIAS,0),0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/gi/IrrCacheGIParameterTest.java b/src/test/java/org/sunflow/core/parameter/gi/IrrCacheGIParameterTest.java new file mode 100644 index 0000000..3691942 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/gi/IrrCacheGIParameterTest.java @@ -0,0 +1,59 @@ +package org.sunflow.core.parameter.gi; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Options; +import org.sunflow.core.parameter.IlluminationParameter; + +public class IrrCacheGIParameterTest { + + SunflowAPI api; + IrrCacheGIParameter gi; + + @Before + public void setUp() { + api = new SunflowAPI(); + gi = new IrrCacheGIParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + gi.tolerance = 0.2f; + gi.samples = 20; + gi.minSpacing = 0.111f; + gi.maxSpacing = 0.212f; + + // Set parameters + gi.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(GlobalIlluminationParameter.TYPE_IRR_CACHE, options.getString(GlobalIlluminationParameter.PARAM_ENGINE, "")); + Assert.assertEquals(gi.samples, options.getInt(IrrCacheGIParameter.PARAM_SAMPLES, 0)); + Assert.assertEquals(gi.tolerance, options.getFloat(IrrCacheGIParameter.PARAM_TOLERANCE, 0), 0); + Assert.assertEquals(gi.minSpacing, options.getFloat(IrrCacheGIParameter.PARAM_MIN_SPACING, 0), 0); + Assert.assertEquals(gi.maxSpacing, options.getFloat(IrrCacheGIParameter.PARAM_MAX_SPACING, 0), 0); + } + + @Test + public void testSetupAPIWithGlobal() { + // Set values + IlluminationParameter global = new IlluminationParameter(); + gi.global = global; + + // Set parameters + gi.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(GlobalIlluminationParameter.TYPE_IRR_CACHE, options.getString(GlobalIlluminationParameter.PARAM_ENGINE, "")); + Assert.assertEquals(gi.global.getMap(), options.getString(IrrCacheGIParameter.PARAM_GLOBAL, "")); + Assert.assertEquals(gi.global.getEmit(), options.getInt(IrrCacheGIParameter.PARAM_GLOBAL_EMIT, 0)); + Assert.assertEquals(gi.global.getGather(), options.getInt(IrrCacheGIParameter.PARAM_GLOBAL_GATHER, 0)); + Assert.assertEquals(gi.global.getRadius(), options.getFloat(IrrCacheGIParameter.PARAM_GLOBAL_RADIUS, 0), 0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/gi/PathTracingGIParameterTest.java b/src/test/java/org/sunflow/core/parameter/gi/PathTracingGIParameterTest.java new file mode 100644 index 0000000..f730637 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/gi/PathTracingGIParameterTest.java @@ -0,0 +1,34 @@ +package org.sunflow.core.parameter.gi; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Options; + +public class PathTracingGIParameterTest { + + SunflowAPI api; + PathTracingGIParameter gi; + + @Before + public void setUp() { + api = new SunflowAPI(); + gi = new PathTracingGIParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + gi.samples = 99; + + // Set parameters + gi.setup(api); + + Options options = (Options) api.getRenderObjects().get(SunflowAPI.DEFAULT_OPTIONS).obj; + + Assert.assertEquals(GlobalIlluminationParameter.TYPE_PATH, options.getString(GlobalIlluminationParameter.PARAM_ENGINE, "")); + Assert.assertEquals(gi.samples, options.getInt(PathTracingGIParameter.PARAM_SAMPLES,0)); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/light/CornellBoxLightParameterTest.java b/src/test/java/org/sunflow/core/parameter/light/CornellBoxLightParameterTest.java new file mode 100644 index 0000000..9f939fe --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/light/CornellBoxLightParameterTest.java @@ -0,0 +1,63 @@ +package org.sunflow.core.parameter.light; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.primitive.CornellBox; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; + +import java.util.Random; + +public class CornellBoxLightParameterTest { + + CornellBoxLightParameter light; + SunflowAPI api; + + @Before + public void setUp() { + api = new SunflowAPI(); + light = new CornellBoxLightParameter(); + } + + @Test + public void testSetupAPI() { + light.setName("uniqueName"); + light.setSamples(22); + light.setRadiance(randomColor()); + light.setMin(new Point3(-1,-2,-4)); + light.setMax(new Point3(1,3,5)); + light.setTop(randomColor()); + light.setBottom(randomColor()); + light.setLeft(randomColor()); + light.setRight(randomColor()); + light.setBack(randomColor()); + + // Set parameters + light.setup(api); + + CornellBox l = (CornellBox) api.getRenderObjects().get(light.name).obj; + + Assert.assertEquals(light.getSamples(), l.getNumSamples()); + //Assert.assertArrayEquals(light.getRadiance().getRGB(), l.getRadiance(null).getRGB(), 0); + Assert.assertArrayEquals(light.getTop().getRGB(), l.getTop().getRGB(), 0); + Assert.assertArrayEquals(light.getBottom().getRGB(), l.getBottom().getRGB(), 0); + Assert.assertArrayEquals(light.getLeft().getRGB(), l.getLeft().getRGB(), 0); + Assert.assertArrayEquals(light.getRight().getRGB(), l.getRight().getRGB(), 0); + Assert.assertArrayEquals(light.getBack().getRGB(), l.getBack().getRGB(), 0); + + Assert.assertEquals(light.min.x, l.getBounds().getBound(0), 0.1f); + Assert.assertEquals(light.max.x, l.getBounds().getBound(1), 0.1f); + Assert.assertEquals(light.min.y, l.getBounds().getBound(2), 0.1f); + Assert.assertEquals(light.max.y, l.getBounds().getBound(3), 0.1f); + Assert.assertEquals(light.min.z, l.getBounds().getBound(4), 0.1f); + Assert.assertEquals(light.max.z, l.getBounds().getBound(5), 0.1f); + } + + private Color randomColor() { + Random random = new Random(); + return new Color(random.nextFloat(), random.nextFloat(), random.nextFloat()); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/light/DirectionalLightParameterTest.java b/src/test/java/org/sunflow/core/parameter/light/DirectionalLightParameterTest.java new file mode 100644 index 0000000..b53ef94 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/light/DirectionalLightParameterTest.java @@ -0,0 +1,44 @@ +package org.sunflow.core.parameter.light; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.light.DirectionalSpotlight; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; + +public class DirectionalLightParameterTest { + + DirectionalLightParameter light; + SunflowAPI api; + + @Before + public void setUp() { + api = new SunflowAPI(); + light = new DirectionalLightParameter(); + } + + @Test + public void testSetupAPI() { + light.setName("uniqueName"); + light.setRadiance(new Color(1f,0,0)); + light.setRadius(2); + light.setSource(new Point3(1,2,3)); + light.setDirection(new Point3(2,2,3)); + + // Set parameters + light.setup(api); + + DirectionalSpotlight l = (DirectionalSpotlight) api.getRenderObjects().get(light.name).obj; + + Assert.assertEquals(light.getSource(), l.getSource()); + Assert.assertEquals(light.getRadius(), l.getR(), 0); + Assert.assertArrayEquals(light.getRadiance().getRGB(), l.getRadiance().getRGB(), 0); + + Assert.assertEquals(1, l.getDirection().x, 0); + Assert.assertEquals(0, l.getDirection().y, 0); + Assert.assertEquals(0, l.getDirection().z, 0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/light/ImageBaseLightParameterTest.java b/src/test/java/org/sunflow/core/parameter/light/ImageBaseLightParameterTest.java new file mode 100644 index 0000000..2179aaf --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/light/ImageBaseLightParameterTest.java @@ -0,0 +1,35 @@ +package org.sunflow.core.parameter.light; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.light.ImageBasedLight; +import org.sunflow.math.Vector3; + +public class ImageBaseLightParameterTest { + + ImageBasedLightParameter light; + SunflowAPI api; + + @Before + public void setUp() { + api = new SunflowAPI(); + light = new ImageBasedLightParameter(); + } + + @Test + public void testSetupAPI() { + light.setName("uniqueName"); + light.setSamples(88); + light.setCenter(new Vector3(0, 2, 1)); + light.setUp(new Vector3(0, -1, 0)); + light.setFixed(true); + + light.setup(api); + + ImageBasedLight l = (ImageBasedLight) api.getRenderObjects().get(light.name).obj; + + Assert.assertEquals(light.getSamples(), l.getNumSamples()); + } +} diff --git a/src/test/java/org/sunflow/core/parameter/light/PointLightParameterTest.java b/src/test/java/org/sunflow/core/parameter/light/PointLightParameterTest.java new file mode 100644 index 0000000..aeb2922 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/light/PointLightParameterTest.java @@ -0,0 +1,37 @@ +package org.sunflow.core.parameter.light; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.light.ImageBasedLight; +import org.sunflow.core.light.PointLight; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; +import org.sunflow.math.Vector3; + +public class PointLightParameterTest { + + PointLightParameter light; + SunflowAPI api; + + @Before + public void setUp() { + api = new SunflowAPI(); + light = new PointLightParameter(); + } + + @Test + public void testSetupAPI() { + light.setName("uniqueName"); + light.setColor(new Color(1,5,6)); + light.setCenter(new Point3(0, 2, 1)); + + light.setup(api); + + PointLight l = (PointLight) api.getRenderObjects().get(light.name).obj; + + Assert.assertEquals(light.getCenter(), l.getLightPoint()); + Assert.assertArrayEquals(light.getColor().getRGB(), l.getColor().getRGB(), 0); + } +} diff --git a/src/test/java/org/sunflow/core/parameter/light/SphereLightParameterTest.java b/src/test/java/org/sunflow/core/parameter/light/SphereLightParameterTest.java new file mode 100644 index 0000000..bf0237d --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/light/SphereLightParameterTest.java @@ -0,0 +1,40 @@ +package org.sunflow.core.parameter.light; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.light.PointLight; +import org.sunflow.core.light.SphereLight; +import org.sunflow.image.Color; +import org.sunflow.math.Point3; + +public class SphereLightParameterTest { + + SphereLightParameter light; + SunflowAPI api; + + @Before + public void setUp() { + api = new SunflowAPI(); + light = new SphereLightParameter(); + } + + @Test + public void testSetupAPI() { + light.setName("uniqueName"); + light.setSamples(77); + light.setCenter(new Point3(0, 2, 1)); + light.setRadius(5); + light.setRadiance(new Color(3,2,1)); + + light.setup(api); + + SphereLight l = (SphereLight) api.getRenderObjects().get(light.name).obj; + + Assert.assertEquals(light.getSamples(), l.getNumSamples()); + Assert.assertEquals(light.getCenter(), l.getCenter()); + Assert.assertEquals(light.getRadius(), l.getRadius(), 0); + Assert.assertArrayEquals(light.getRadiance().getRGB(), l.getRadiance().getRGB(), 0); + } +} diff --git a/src/test/java/org/sunflow/core/parameter/light/SunSkyLightParameterTest.java b/src/test/java/org/sunflow/core/parameter/light/SunSkyLightParameterTest.java new file mode 100644 index 0000000..ace2624 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/light/SunSkyLightParameterTest.java @@ -0,0 +1,40 @@ +package org.sunflow.core.parameter.light; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.light.SunSkyLight; +import org.sunflow.image.Color; +import org.sunflow.math.Vector3; + +public class SunSkyLightParameterTest { + + SunSkyLightParameter light; + SunflowAPI api; + + @Before + public void setUp() { + api = new SunflowAPI(); + light = new SunSkyLightParameter(); + } + + @Test + public void testSetupAPI() { + light.setName("uniqueName"); + light.setSamples(77); + light.setGroundColor(new Color(1, 3, 2)); + light.setExtendSky(true); + light.setTurbidity(99); + light.setEast(new Vector3(1, 0, 0)); + light.setSunDirection(new Vector3(1, 1, 0)); + light.setUp(new Vector3(0, 1, 0)); + + light.setup(api); + + SunSkyLight l = (SunSkyLight) api.getRenderObjects().get(light.name).obj; + + // Expected result is samples + 1 + Assert.assertEquals(light.getSamples() + 1, l.getNumSamples()); + } +} diff --git a/src/test/java/org/sunflow/core/parameter/light/TriangleMeshLightParameterTest.java b/src/test/java/org/sunflow/core/parameter/light/TriangleMeshLightParameterTest.java new file mode 100644 index 0000000..d0a30bb --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/light/TriangleMeshLightParameterTest.java @@ -0,0 +1,35 @@ +package org.sunflow.core.parameter.light; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.light.TriangleMeshLight; +import org.sunflow.image.Color; + +public class TriangleMeshLightParameterTest { + + TriangleMeshLightParameter light; + SunflowAPI api; + + @Before + public void setUp() { + api = new SunflowAPI(); + light = new TriangleMeshLightParameter(); + } + + @Test + public void testSetupAPI() { + light.setName("uniqueName"); + light.setSamples(77); + light.setPoints(new float[]{0, 0, 0, 1, 1, 1, 1, 0, 0}); + light.setTriangles(new int[]{0, 2, 1}); + light.setRadiance(new Color(0, 1, 1)); + + light.setup(api); + + TriangleMeshLight l = (TriangleMeshLight) api.getRenderObjects().get(light.name).obj; + + Assert.assertEquals(light.getSamples(), l.getNumSamples()); + } +} diff --git a/src/test/java/org/sunflow/core/parameter/modifer/BumpMapModifierParameterTest.java b/src/test/java/org/sunflow/core/parameter/modifer/BumpMapModifierParameterTest.java new file mode 100644 index 0000000..a2595ee --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/modifer/BumpMapModifierParameterTest.java @@ -0,0 +1,37 @@ +package org.sunflow.core.parameter.modifer; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.modifiers.BumpMappingModifier; +import org.sunflow.core.modifiers.PerlinModifier; +import org.sunflow.core.parameter.modifier.BumpMapModifierParameter; +import org.sunflow.core.parameter.modifier.PerlinModifierParameter; + +public class BumpMapModifierParameterTest { + + SunflowAPI api; + BumpMapModifierParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new BumpMapModifierParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + parameter.setScale(2.12f); + + // Set parameters + parameter.setup(api); + + BumpMappingModifier modifier = (BumpMappingModifier) api.getRenderObjects().get(parameter.getName()).obj; + + Assert.assertEquals(parameter.getScale(), modifier.getScale(),0); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/modifer/NormalMapModifierParameterTest.java b/src/test/java/org/sunflow/core/parameter/modifer/NormalMapModifierParameterTest.java new file mode 100644 index 0000000..c186269 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/modifer/NormalMapModifierParameterTest.java @@ -0,0 +1,36 @@ +package org.sunflow.core.parameter.modifer; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.modifiers.BumpMappingModifier; +import org.sunflow.core.modifiers.NormalMapModifier; +import org.sunflow.core.parameter.modifier.BumpMapModifierParameter; +import org.sunflow.core.parameter.modifier.NormalMapModifierParameter; + +public class NormalMapModifierParameterTest { + + SunflowAPI api; + NormalMapModifierParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new NormalMapModifierParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + + // Set parameters + parameter.setup(api); + + NormalMapModifier modifier = (NormalMapModifier) api.getRenderObjects().get(parameter.getName()).obj; + + Assert.assertNotNull(modifier); + } + +} diff --git a/src/test/java/org/sunflow/core/parameter/modifer/PerlinParameterTest.java b/src/test/java/org/sunflow/core/parameter/modifer/PerlinParameterTest.java new file mode 100644 index 0000000..8634831 --- /dev/null +++ b/src/test/java/org/sunflow/core/parameter/modifer/PerlinParameterTest.java @@ -0,0 +1,42 @@ +package org.sunflow.core.parameter.modifer; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.SunflowAPI; +import org.sunflow.core.Modifier; +import org.sunflow.core.Options; +import org.sunflow.core.modifiers.PerlinModifier; +import org.sunflow.core.parameter.PhotonParameter; +import org.sunflow.core.parameter.modifier.PerlinModifierParameter; + +public class PerlinParameterTest { + + SunflowAPI api; + PerlinModifierParameter parameter; + + @Before + public void setUp() { + api = new SunflowAPI(); + parameter = new PerlinModifierParameter(); + } + + @Test + public void testSetupAPI() { + // Set values + parameter.setName("uniqueName"); + parameter.setFunction(99); + parameter.setScale(2.12f); + parameter.setSize(1.543f); + + // Set parameters + parameter.setup(api); + + PerlinModifier modifier = (PerlinModifier) api.getRenderObjects().get(parameter.getName()).obj; + + Assert.assertEquals(parameter.getFunction(), modifier.getFunction()); + Assert.assertEquals(parameter.getScale(), modifier.getScale(),0); + Assert.assertEquals(parameter.getSize(), modifier.getSize(),0); + } + +} diff --git a/src/test/java/org/sunflow/core/primitive/TriangleMeshTest.java b/src/test/java/org/sunflow/core/primitive/TriangleMeshTest.java new file mode 100644 index 0000000..98e0fae --- /dev/null +++ b/src/test/java/org/sunflow/core/primitive/TriangleMeshTest.java @@ -0,0 +1,28 @@ +package org.sunflow.core.primitive; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.sunflow.math.Point3; + +public class TriangleMeshTest { + + TriangleMesh mesh; + + @Before + public void setUp() { + mesh = new TriangleMesh(); + } + + @Test + public void testInit() { + mesh.points = new float[]{0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8}; + mesh.triangles = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8}; + + Assert.assertEquals(3, mesh.getNumPrimitives()); + + Assert.assertEquals(new Point3(0, 0, 0), mesh.getPoint(0)); + Assert.assertEquals(new Point3(1, 1, 1), mesh.getPoint(1)); + Assert.assertEquals(new Point3(2, 2, 2), mesh.getPoint(2)); + } +}