Compare commits

..

11 Commits

Author SHA1 Message Date
coolGi2007 1e52ee15b5 Merge remote-tracking branch 'origin/quilt_test' into quilt_test
# Conflicts:
#	fabric/build.gradle
2022-04-25 16:38:59 +09:30
coolGi2007 b54d478de1 Just a save commit for quilt 2022-04-25 16:36:00 +09:30
Ran 8008d61636 quilt... 2022-04-23 16:47:42 +06:00
coolGi2007 cf38aef742 Fixed quilt running in gradle and updated quilt version 2022-04-23 20:21:45 +10:00
coolGi2007 8621bf631b fixed a bug with a single comma not deleting 2022-04-23 19:29:40 +10:00
coolGi2007 c31c27167f Fixed the quilt authors and added a way to run the fabric module as quilt 2022-04-23 19:19:53 +10:00
Ran 35d97fa98f Please do it like this I want things to be simple 2022-04-23 11:08:28 +06:00
Ran 8627270e5c Basically the simplest way to add quilt support 2022-04-23 11:08:27 +06:00
coolGi2007 69dd7e932d Started adding support for multiple quilt versions (we need to remove quilted fabric api as it is only for 1.18.2) 2022-04-22 18:54:32 +10:00
coolGi2007 74371bd70d Fixed building on quilt (now just the runClient to be fixed) 2022-04-22 17:42:58 +10:00
coolGi2007 4a38b15ece Testing for adding proper quilt support 2022-04-22 11:12:10 +10:00
535 changed files with 18485 additions and 41710 deletions
-19
View File
@@ -1,19 +0,0 @@
**/.git
**/.gitlab
**/.cache
buildAllJars
**/_Misc Files
*.bat
*.md
*.sh
*.txt
coreSubProjects/*.md
coreSubProjects/*.txt
**/.gitignore
**/.gitattributes
**/.gitlab-cy.yml
**/.gitmodules
-700
View File
@@ -1,700 +0,0 @@
# DH Main
root = true
# Note: please keep this and the core .editorconfig in sync
[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = false
max_line_length = 1000
tab_width = 4
trim_trailing_whitespace = false
ij_continuation_indent_size = 4
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = true
ij_smart_tabs = false
ij_visual_guides = none
ij_wrap_on_typing = false
[*.java]
indent_style = tab
ij_smart_tabs = true
ij_java_align_consecutive_assignments = false
ij_java_align_consecutive_variable_declarations = false
ij_java_align_group_field_declarations = false
ij_java_align_multiline_annotation_parameters = false
ij_java_align_multiline_array_initializer_expression = false
ij_java_align_multiline_assignment = false
ij_java_align_multiline_binary_operation = false
ij_java_align_multiline_chained_methods = false
ij_java_align_multiline_deconstruction_list_components = false
ij_java_align_multiline_extends_list = false
ij_java_align_multiline_for = false
ij_java_align_multiline_method_parentheses = false
ij_java_align_multiline_parameters = false
ij_java_align_multiline_parameters_in_calls = false
ij_java_align_multiline_parenthesized_expression = false
ij_java_align_multiline_records = false
ij_java_align_multiline_resources = false
ij_java_align_multiline_ternary_operation = false
ij_java_align_multiline_text_blocks = false
ij_java_align_multiline_throws_list = false
ij_java_align_subsequent_simple_methods = false
ij_java_align_throws_keyword = false
ij_java_align_types_in_multi_catch = false
ij_java_annotation_parameter_wrap = off
ij_java_array_initializer_new_line_after_left_brace = false
ij_java_array_initializer_right_brace_on_new_line = false
ij_java_array_initializer_wrap = normal
ij_java_assert_statement_colon_on_next_line = false
ij_java_assert_statement_wrap = off
ij_java_assignment_wrap = off
ij_java_binary_operation_sign_on_next_line = false
ij_java_binary_operation_wrap = off
ij_java_blank_lines_after_anonymous_class_header = 0
ij_java_blank_lines_after_class_header = 0
ij_java_blank_lines_after_imports = 1
ij_java_blank_lines_after_package = 1
ij_java_blank_lines_around_class = 1
ij_java_blank_lines_around_field = 0
ij_java_blank_lines_around_field_in_interface = 0
ij_java_blank_lines_around_initializer = 0
ij_java_blank_lines_around_method = 0
ij_java_blank_lines_around_method_in_interface = 0
ij_java_blank_lines_before_class_end = 1
ij_java_blank_lines_before_imports = 1
ij_java_blank_lines_before_method_body = 0
ij_java_blank_lines_before_package = 1
ij_java_block_brace_style = next_line
ij_java_block_comment_add_space = false
ij_java_block_comment_at_first_column = true
ij_java_builder_methods = none
ij_java_call_parameters_new_line_after_left_paren = false
ij_java_call_parameters_right_paren_on_new_line = false
ij_java_call_parameters_wrap = normal
ij_java_case_statement_on_separate_line = true
ij_java_catch_on_new_line = true
ij_java_class_annotation_wrap = off
ij_java_class_brace_style = next_line
ij_java_class_count_to_use_import_on_demand = 5
ij_java_class_names_in_javadoc = 1
ij_java_deconstruction_list_wrap = normal
ij_java_do_not_indent_top_level_class_members = false
ij_java_do_not_wrap_after_single_annotation = false
ij_java_do_not_wrap_after_single_annotation_in_parameter = false
ij_java_do_while_brace_force = never
ij_java_doc_add_blank_line_after_description = true
ij_java_doc_add_blank_line_after_param_comments = false
ij_java_doc_add_blank_line_after_return = false
ij_java_doc_add_p_tag_on_empty_lines = false
ij_java_doc_align_exception_comments = false
ij_java_doc_align_param_comments = false
ij_java_doc_do_not_wrap_if_one_line = true
ij_java_doc_enable_formatting = true
ij_java_doc_enable_leading_asterisks = true
ij_java_doc_indent_on_continuation = false
ij_java_doc_keep_empty_lines = true
ij_java_doc_keep_empty_parameter_tag = true
ij_java_doc_keep_empty_return_tag = false
ij_java_doc_keep_empty_throws_tag = true
ij_java_doc_keep_invalid_tags = true
ij_java_doc_param_description_on_new_line = false
ij_java_doc_preserve_line_breaks = false
ij_java_doc_use_throws_not_exception_tag = true
ij_java_else_on_new_line = true
ij_java_enum_constants_wrap = off
ij_java_extends_keyword_wrap = normal
ij_java_extends_list_wrap = normal
ij_java_field_annotation_wrap = off
ij_java_finally_on_new_line = true
ij_java_for_brace_force = always
ij_java_for_statement_new_line_after_left_paren = false
ij_java_for_statement_right_paren_on_new_line = false
ij_java_for_statement_wrap = off
ij_java_generate_final_locals = false
ij_java_generate_final_parameters = false
ij_java_if_brace_force = never
ij_java_imports_layout = *,|,javax.**,java.**,|,$*
ij_java_indent_case_from_switch = true
ij_java_insert_inner_class_imports = false
ij_java_insert_override_annotation = true
ij_java_keep_blank_lines_before_right_brace = 10
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
ij_java_keep_blank_lines_in_code = 10
ij_java_keep_blank_lines_in_declarations = 10
ij_java_keep_builder_methods_indents = false
ij_java_keep_control_statement_in_one_line = true
ij_java_keep_first_column_comment = true
ij_java_keep_indents_on_empty_lines = true
ij_java_keep_line_breaks = true
ij_java_keep_multiple_expressions_in_one_line = true
ij_java_keep_simple_blocks_in_one_line = false
ij_java_keep_simple_classes_in_one_line = true
ij_java_keep_simple_lambdas_in_one_line = true
ij_java_keep_simple_methods_in_one_line = true
ij_java_label_indent_absolute = false
ij_java_label_indent_size = 0
ij_java_lambda_brace_style = end_of_line
ij_java_layout_static_imports_separately = true
ij_java_line_comment_add_space = false
ij_java_line_comment_add_space_on_reformat = false
ij_java_line_comment_at_first_column = false
ij_java_method_annotation_wrap = off
ij_java_method_brace_style = next_line
ij_java_method_call_chain_wrap = normal
ij_java_method_parameters_new_line_after_left_paren = true
ij_java_method_parameters_right_paren_on_new_line = false
ij_java_method_parameters_wrap = normal
ij_java_modifier_list_wrap = false
ij_java_multi_catch_types_wrap = normal
ij_java_names_count_to_use_import_on_demand = 3
ij_java_new_line_after_lparen_in_annotation = false
ij_java_new_line_after_lparen_in_deconstruction_pattern = true
ij_java_new_line_after_lparen_in_record_header = false
ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
ij_java_parameter_annotation_wrap = off
ij_java_parentheses_expression_new_line_after_left_paren = false
ij_java_parentheses_expression_right_paren_on_new_line = false
ij_java_place_assignment_sign_on_next_line = false
ij_java_prefer_longer_names = true
ij_java_prefer_parameters_wrap = false
ij_java_record_components_wrap = normal
ij_java_repeat_synchronized = true
ij_java_replace_instanceof_and_cast = false
ij_java_replace_null_check = false
ij_java_replace_sum_lambda_with_method_ref = false
ij_java_resource_list_new_line_after_left_paren = false
ij_java_resource_list_right_paren_on_new_line = false
ij_java_resource_list_wrap = on_every_item
ij_java_rparen_on_new_line_in_annotation = false
ij_java_rparen_on_new_line_in_deconstruction_pattern = true
ij_java_rparen_on_new_line_in_record_header = false
ij_java_space_after_closing_angle_bracket_in_type_argument = false
ij_java_space_after_colon = true
ij_java_space_after_comma = true
ij_java_space_after_comma_in_type_arguments = true
ij_java_space_after_for_semicolon = true
ij_java_space_after_quest = true
ij_java_space_after_type_cast = true
ij_java_space_before_annotation_array_initializer_left_brace = false
ij_java_space_before_annotation_parameter_list = false
ij_java_space_before_array_initializer_left_brace = false
ij_java_space_before_catch_keyword = true
ij_java_space_before_catch_left_brace = true
ij_java_space_before_catch_parentheses = true
ij_java_space_before_class_left_brace = true
ij_java_space_before_colon = true
ij_java_space_before_colon_in_foreach = true
ij_java_space_before_comma = false
ij_java_space_before_deconstruction_list = false
ij_java_space_before_do_left_brace = true
ij_java_space_before_else_keyword = true
ij_java_space_before_else_left_brace = true
ij_java_space_before_finally_keyword = true
ij_java_space_before_finally_left_brace = true
ij_java_space_before_for_left_brace = true
ij_java_space_before_for_parentheses = true
ij_java_space_before_for_semicolon = false
ij_java_space_before_if_left_brace = true
ij_java_space_before_if_parentheses = true
ij_java_space_before_method_call_parentheses = false
ij_java_space_before_method_left_brace = true
ij_java_space_before_method_parentheses = false
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
ij_java_space_before_quest = true
ij_java_space_before_switch_left_brace = true
ij_java_space_before_switch_parentheses = true
ij_java_space_before_synchronized_left_brace = false
ij_java_space_before_synchronized_parentheses = true
ij_java_space_before_try_left_brace = true
ij_java_space_before_try_parentheses = true
ij_java_space_before_type_parameter_list = false
ij_java_space_before_while_keyword = true
ij_java_space_before_while_left_brace = true
ij_java_space_before_while_parentheses = true
ij_java_space_inside_one_line_enum_braces = false
ij_java_space_within_empty_array_initializer_braces = true
ij_java_space_within_empty_method_call_parentheses = false
ij_java_space_within_empty_method_parentheses = false
ij_java_spaces_around_additive_operators = true
ij_java_spaces_around_annotation_eq = true
ij_java_spaces_around_assignment_operators = true
ij_java_spaces_around_bitwise_operators = true
ij_java_spaces_around_equality_operators = true
ij_java_spaces_around_lambda_arrow = true
ij_java_spaces_around_logical_operators = true
ij_java_spaces_around_method_ref_dbl_colon = false
ij_java_spaces_around_multiplicative_operators = true
ij_java_spaces_around_relational_operators = true
ij_java_spaces_around_shift_operators = true
ij_java_spaces_around_type_bounds_in_type_parameters = true
ij_java_spaces_around_unary_operator = false
ij_java_spaces_within_angle_brackets = false
ij_java_spaces_within_annotation_parentheses = false
ij_java_spaces_within_array_initializer_braces = false
ij_java_spaces_within_braces = true
ij_java_spaces_within_brackets = false
ij_java_spaces_within_cast_parentheses = false
ij_java_spaces_within_catch_parentheses = false
ij_java_spaces_within_deconstruction_list = false
ij_java_spaces_within_for_parentheses = false
ij_java_spaces_within_if_parentheses = false
ij_java_spaces_within_method_call_parentheses = false
ij_java_spaces_within_method_parentheses = false
ij_java_spaces_within_parentheses = false
ij_java_spaces_within_record_header = false
ij_java_spaces_within_switch_parentheses = false
ij_java_spaces_within_synchronized_parentheses = false
ij_java_spaces_within_try_parentheses = false
ij_java_spaces_within_while_parentheses = false
ij_java_special_else_if_treatment = true
ij_java_subclass_name_suffix = Impl
ij_java_ternary_operation_signs_on_next_line = false
ij_java_ternary_operation_wrap = on_every_item
ij_java_test_name_suffix = Test
ij_java_throws_keyword_wrap = normal
ij_java_throws_list_wrap = normal
ij_java_use_external_annotations = false
ij_java_use_fq_class_names = false
ij_java_use_relative_indents = false
ij_java_use_single_class_imports = true
ij_java_variable_annotation_wrap = off
ij_java_visibility = public
ij_java_while_brace_force = always
ij_java_while_on_new_line = true
ij_java_wrap_comments = false
ij_java_wrap_first_method_in_call_chain = false
ij_java_wrap_long_lines = false
[*.nbtt]
indent_style = tab
max_line_length = 150
ij_continuation_indent_size = 4
ij_nbtt_keep_indents_on_empty_lines = false
ij_nbtt_space_after_colon = true
ij_nbtt_space_after_comma = true
ij_nbtt_space_before_colon = true
ij_nbtt_space_before_comma = false
ij_nbtt_spaces_within_brackets = false
ij_nbtt_spaces_within_parentheses = false
[*.properties]
ij_properties_align_group_field_declarations = false
ij_properties_keep_blank_lines = false
ij_properties_key_value_delimiter = equals
ij_properties_spaces_around_key_value_delimiter = false
[.editorconfig]
ij_editorconfig_align_group_field_declarations = false
ij_editorconfig_space_after_colon = false
ij_editorconfig_space_after_comma = true
ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.jspx,*.pom,*.rng,*.tagx,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
ij_xml_align_attributes = true
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_add_space = false
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = true
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = false
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = false
ij_xml_text_wrap = normal
ij_xml_use_custom_settings = false
[{*.bash,*.sh,*.zsh}]
indent_size = 4
tab_width = 4
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
ij_shell_use_unix_line_separator = true
[{*.comp,*.frag,*.fsh,*.geom,*.glsl,*.gsh,*.tesc,*.tese,*.vert,*.vsh}]
ij_glsl_space_after_colon = true
ij_glsl_space_after_comma = true
ij_glsl_space_after_for_semicolon = true
ij_glsl_space_after_quest = true
ij_glsl_space_before_colon = false
ij_glsl_space_before_comma = false
ij_glsl_space_before_for_semicolon = false
ij_glsl_space_before_quest = true
ij_glsl_spaces_around_additive_operators = true
ij_glsl_spaces_around_assignment_operators = true
ij_glsl_spaces_around_bitwise_operators = true
ij_glsl_spaces_around_equality_operators = true
ij_glsl_spaces_around_logical_operators = true
ij_glsl_spaces_around_multiplicative_operators = true
ij_glsl_spaces_around_relational_operators = true
ij_glsl_spaces_around_shift_operators = true
ij_glsl_spaces_within_brackets = false
ij_glsl_spaces_within_parentheses = false
[{*.gant,*.groovy,*.gy}]
ij_groovy_align_group_field_declarations = false
ij_groovy_align_multiline_array_initializer_expression = false
ij_groovy_align_multiline_assignment = false
ij_groovy_align_multiline_binary_operation = false
ij_groovy_align_multiline_chained_methods = false
ij_groovy_align_multiline_extends_list = false
ij_groovy_align_multiline_for = true
ij_groovy_align_multiline_list_or_map = true
ij_groovy_align_multiline_method_parentheses = false
ij_groovy_align_multiline_parameters = true
ij_groovy_align_multiline_parameters_in_calls = false
ij_groovy_align_multiline_resources = true
ij_groovy_align_multiline_ternary_operation = false
ij_groovy_align_multiline_throws_list = false
ij_groovy_align_named_args_in_map = true
ij_groovy_align_throws_keyword = false
ij_groovy_array_initializer_new_line_after_left_brace = false
ij_groovy_array_initializer_right_brace_on_new_line = false
ij_groovy_array_initializer_wrap = off
ij_groovy_assert_statement_wrap = off
ij_groovy_assignment_wrap = off
ij_groovy_binary_operation_wrap = off
ij_groovy_blank_lines_after_class_header = 0
ij_groovy_blank_lines_after_imports = 1
ij_groovy_blank_lines_after_package = 1
ij_groovy_blank_lines_around_class = 1
ij_groovy_blank_lines_around_field = 0
ij_groovy_blank_lines_around_field_in_interface = 0
ij_groovy_blank_lines_around_method = 1
ij_groovy_blank_lines_around_method_in_interface = 1
ij_groovy_blank_lines_before_imports = 1
ij_groovy_blank_lines_before_method_body = 0
ij_groovy_blank_lines_before_package = 0
ij_groovy_block_brace_style = end_of_line
ij_groovy_block_comment_add_space = false
ij_groovy_block_comment_at_first_column = true
ij_groovy_call_parameters_new_line_after_left_paren = false
ij_groovy_call_parameters_right_paren_on_new_line = false
ij_groovy_call_parameters_wrap = off
ij_groovy_catch_on_new_line = false
ij_groovy_class_annotation_wrap = split_into_lines
ij_groovy_class_brace_style = end_of_line
ij_groovy_class_count_to_use_import_on_demand = 5
ij_groovy_do_while_brace_force = never
ij_groovy_else_on_new_line = false
ij_groovy_enable_groovydoc_formatting = true
ij_groovy_enum_constants_wrap = off
ij_groovy_extends_keyword_wrap = off
ij_groovy_extends_list_wrap = off
ij_groovy_field_annotation_wrap = split_into_lines
ij_groovy_finally_on_new_line = false
ij_groovy_for_brace_force = never
ij_groovy_for_statement_new_line_after_left_paren = false
ij_groovy_for_statement_right_paren_on_new_line = false
ij_groovy_for_statement_wrap = off
ij_groovy_ginq_general_clause_wrap_policy = 2
ij_groovy_ginq_having_wrap_policy = 1
ij_groovy_ginq_indent_having_clause = true
ij_groovy_ginq_indent_on_clause = true
ij_groovy_ginq_on_wrap_policy = 1
ij_groovy_ginq_space_after_keyword = true
ij_groovy_if_brace_force = never
ij_groovy_import_annotation_wrap = 2
ij_groovy_imports_layout = *,|,javax.**,java.**,|,$*
ij_groovy_indent_case_from_switch = true
ij_groovy_indent_label_blocks = true
ij_groovy_insert_inner_class_imports = false
ij_groovy_keep_blank_lines_before_right_brace = 2
ij_groovy_keep_blank_lines_in_code = 2
ij_groovy_keep_blank_lines_in_declarations = 2
ij_groovy_keep_control_statement_in_one_line = true
ij_groovy_keep_first_column_comment = true
ij_groovy_keep_indents_on_empty_lines = false
ij_groovy_keep_line_breaks = true
ij_groovy_keep_multiple_expressions_in_one_line = false
ij_groovy_keep_simple_blocks_in_one_line = false
ij_groovy_keep_simple_classes_in_one_line = true
ij_groovy_keep_simple_lambdas_in_one_line = true
ij_groovy_keep_simple_methods_in_one_line = true
ij_groovy_label_indent_absolute = false
ij_groovy_label_indent_size = 0
ij_groovy_lambda_brace_style = end_of_line
ij_groovy_layout_static_imports_separately = true
ij_groovy_line_comment_add_space = false
ij_groovy_line_comment_add_space_on_reformat = false
ij_groovy_line_comment_at_first_column = true
ij_groovy_method_annotation_wrap = split_into_lines
ij_groovy_method_brace_style = end_of_line
ij_groovy_method_call_chain_wrap = off
ij_groovy_method_parameters_new_line_after_left_paren = false
ij_groovy_method_parameters_right_paren_on_new_line = false
ij_groovy_method_parameters_wrap = off
ij_groovy_modifier_list_wrap = false
ij_groovy_names_count_to_use_import_on_demand = 3
ij_groovy_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
ij_groovy_parameter_annotation_wrap = off
ij_groovy_parentheses_expression_new_line_after_left_paren = false
ij_groovy_parentheses_expression_right_paren_on_new_line = false
ij_groovy_prefer_parameters_wrap = false
ij_groovy_resource_list_new_line_after_left_paren = false
ij_groovy_resource_list_right_paren_on_new_line = false
ij_groovy_resource_list_wrap = off
ij_groovy_space_after_assert_separator = true
ij_groovy_space_after_colon = true
ij_groovy_space_after_comma = true
ij_groovy_space_after_comma_in_type_arguments = true
ij_groovy_space_after_for_semicolon = true
ij_groovy_space_after_quest = true
ij_groovy_space_after_type_cast = true
ij_groovy_space_before_annotation_parameter_list = false
ij_groovy_space_before_array_initializer_left_brace = false
ij_groovy_space_before_assert_separator = false
ij_groovy_space_before_catch_keyword = true
ij_groovy_space_before_catch_left_brace = true
ij_groovy_space_before_catch_parentheses = true
ij_groovy_space_before_class_left_brace = true
ij_groovy_space_before_closure_left_brace = true
ij_groovy_space_before_colon = true
ij_groovy_space_before_comma = false
ij_groovy_space_before_do_left_brace = true
ij_groovy_space_before_else_keyword = true
ij_groovy_space_before_else_left_brace = true
ij_groovy_space_before_finally_keyword = true
ij_groovy_space_before_finally_left_brace = true
ij_groovy_space_before_for_left_brace = true
ij_groovy_space_before_for_parentheses = true
ij_groovy_space_before_for_semicolon = false
ij_groovy_space_before_if_left_brace = true
ij_groovy_space_before_if_parentheses = true
ij_groovy_space_before_method_call_parentheses = false
ij_groovy_space_before_method_left_brace = true
ij_groovy_space_before_method_parentheses = false
ij_groovy_space_before_quest = true
ij_groovy_space_before_record_parentheses = false
ij_groovy_space_before_switch_left_brace = true
ij_groovy_space_before_switch_parentheses = true
ij_groovy_space_before_synchronized_left_brace = true
ij_groovy_space_before_synchronized_parentheses = true
ij_groovy_space_before_try_left_brace = true
ij_groovy_space_before_try_parentheses = true
ij_groovy_space_before_while_keyword = true
ij_groovy_space_before_while_left_brace = true
ij_groovy_space_before_while_parentheses = true
ij_groovy_space_in_named_argument = true
ij_groovy_space_in_named_argument_before_colon = false
ij_groovy_space_within_empty_array_initializer_braces = false
ij_groovy_space_within_empty_method_call_parentheses = false
ij_groovy_spaces_around_additive_operators = true
ij_groovy_spaces_around_assignment_operators = true
ij_groovy_spaces_around_bitwise_operators = true
ij_groovy_spaces_around_equality_operators = true
ij_groovy_spaces_around_lambda_arrow = true
ij_groovy_spaces_around_logical_operators = true
ij_groovy_spaces_around_multiplicative_operators = true
ij_groovy_spaces_around_regex_operators = true
ij_groovy_spaces_around_relational_operators = true
ij_groovy_spaces_around_shift_operators = true
ij_groovy_spaces_within_annotation_parentheses = false
ij_groovy_spaces_within_array_initializer_braces = false
ij_groovy_spaces_within_braces = true
ij_groovy_spaces_within_brackets = false
ij_groovy_spaces_within_cast_parentheses = false
ij_groovy_spaces_within_catch_parentheses = false
ij_groovy_spaces_within_for_parentheses = false
ij_groovy_spaces_within_gstring_injection_braces = false
ij_groovy_spaces_within_if_parentheses = false
ij_groovy_spaces_within_list_or_map = false
ij_groovy_spaces_within_method_call_parentheses = false
ij_groovy_spaces_within_method_parentheses = false
ij_groovy_spaces_within_parentheses = false
ij_groovy_spaces_within_switch_parentheses = false
ij_groovy_spaces_within_synchronized_parentheses = false
ij_groovy_spaces_within_try_parentheses = false
ij_groovy_spaces_within_tuple_expression = false
ij_groovy_spaces_within_while_parentheses = false
ij_groovy_special_else_if_treatment = true
ij_groovy_ternary_operation_wrap = off
ij_groovy_throws_keyword_wrap = off
ij_groovy_throws_list_wrap = off
ij_groovy_use_flying_geese_braces = false
ij_groovy_use_fq_class_names = false
ij_groovy_use_fq_class_names_in_javadoc = true
ij_groovy_use_relative_indents = false
ij_groovy_use_single_class_imports = true
ij_groovy_variable_annotation_wrap = off
ij_groovy_while_brace_force = never
ij_groovy_while_on_new_line = false
ij_groovy_wrap_chain_calls_after_dot = false
ij_groovy_wrap_long_lines = false
[{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}]
indent_size = 4
ij_json_array_wrapping = split_into_lines
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_keep_trailing_comma = false
ij_json_object_wrapping = split_into_lines
ij_json_property_alignment = do_not_align
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = false
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
ij_html_block_comment_add_space = false
ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot
ij_html_enforce_quotes = false
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span,pre,textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
[{*.kt,*.kts}]
ij_kotlin_align_in_columns_case_branch = false
ij_kotlin_align_multiline_binary_operation = false
ij_kotlin_align_multiline_extends_list = false
ij_kotlin_align_multiline_method_parentheses = false
ij_kotlin_align_multiline_parameters = true
ij_kotlin_align_multiline_parameters_in_calls = false
ij_kotlin_allow_trailing_comma = false
ij_kotlin_allow_trailing_comma_on_call_site = false
ij_kotlin_assignment_wrap = off
ij_kotlin_blank_lines_after_class_header = 0
ij_kotlin_blank_lines_around_block_when_branches = 0
ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1
ij_kotlin_block_comment_add_space = false
ij_kotlin_block_comment_at_first_column = true
ij_kotlin_call_parameters_new_line_after_left_paren = false
ij_kotlin_call_parameters_right_paren_on_new_line = false
ij_kotlin_call_parameters_wrap = off
ij_kotlin_catch_on_new_line = false
ij_kotlin_class_annotation_wrap = split_into_lines
ij_kotlin_continuation_indent_for_chained_calls = true
ij_kotlin_continuation_indent_for_expression_bodies = true
ij_kotlin_continuation_indent_in_argument_lists = true
ij_kotlin_continuation_indent_in_elvis = true
ij_kotlin_continuation_indent_in_if_conditions = true
ij_kotlin_continuation_indent_in_parameter_lists = true
ij_kotlin_continuation_indent_in_supertype_lists = true
ij_kotlin_else_on_new_line = false
ij_kotlin_enum_constants_wrap = off
ij_kotlin_extends_list_wrap = off
ij_kotlin_field_annotation_wrap = split_into_lines
ij_kotlin_finally_on_new_line = false
ij_kotlin_if_rparen_on_new_line = false
ij_kotlin_import_nested_classes = false
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^
ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
ij_kotlin_keep_blank_lines_before_right_brace = 2
ij_kotlin_keep_blank_lines_in_code = 2
ij_kotlin_keep_blank_lines_in_declarations = 2
ij_kotlin_keep_first_column_comment = true
ij_kotlin_keep_indents_on_empty_lines = false
ij_kotlin_keep_line_breaks = true
ij_kotlin_lbrace_on_next_line = false
ij_kotlin_line_break_after_multiline_when_entry = true
ij_kotlin_line_comment_add_space = false
ij_kotlin_line_comment_add_space_on_reformat = false
ij_kotlin_line_comment_at_first_column = true
ij_kotlin_method_annotation_wrap = split_into_lines
ij_kotlin_method_call_chain_wrap = off
ij_kotlin_method_parameters_new_line_after_left_paren = false
ij_kotlin_method_parameters_right_paren_on_new_line = false
ij_kotlin_method_parameters_wrap = off
ij_kotlin_name_count_to_use_star_import = 5
ij_kotlin_name_count_to_use_star_import_for_members = 3
ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.**
ij_kotlin_parameter_annotation_wrap = off
ij_kotlin_space_after_comma = true
ij_kotlin_space_after_extend_colon = true
ij_kotlin_space_after_type_colon = true
ij_kotlin_space_before_catch_parentheses = true
ij_kotlin_space_before_comma = false
ij_kotlin_space_before_extend_colon = true
ij_kotlin_space_before_for_parentheses = true
ij_kotlin_space_before_if_parentheses = true
ij_kotlin_space_before_lambda_arrow = true
ij_kotlin_space_before_type_colon = false
ij_kotlin_space_before_when_parentheses = true
ij_kotlin_space_before_while_parentheses = true
ij_kotlin_spaces_around_additive_operators = true
ij_kotlin_spaces_around_assignment_operators = true
ij_kotlin_spaces_around_equality_operators = true
ij_kotlin_spaces_around_function_type_arrow = true
ij_kotlin_spaces_around_logical_operators = true
ij_kotlin_spaces_around_multiplicative_operators = true
ij_kotlin_spaces_around_range = false
ij_kotlin_spaces_around_relational_operators = true
ij_kotlin_spaces_around_unary_operator = false
ij_kotlin_spaces_around_when_arrow = true
ij_kotlin_variable_annotation_wrap = off
ij_kotlin_while_on_new_line = false
ij_kotlin_wrap_elvis_expressions = 1
ij_kotlin_wrap_expression_body_functions = 0
ij_kotlin_wrap_first_method_in_call_chain = false
[{*.markdown,*.md}]
ij_markdown_force_one_space_after_blockquote_symbol = true
ij_markdown_force_one_space_after_header_symbol = true
ij_markdown_force_one_space_after_list_bullet = true
ij_markdown_force_one_space_between_words = true
ij_markdown_format_tables = true
ij_markdown_insert_quote_arrows_on_wrap = true
ij_markdown_keep_indents_on_empty_lines = false
ij_markdown_keep_line_breaks_inside_text_blocks = true
ij_markdown_max_lines_around_block_elements = 1
ij_markdown_max_lines_around_header = 1
ij_markdown_max_lines_between_paragraphs = 1
ij_markdown_min_lines_around_block_elements = 1
ij_markdown_min_lines_around_header = 1
ij_markdown_min_lines_between_paragraphs = 1
ij_markdown_wrap_text_if_long = true
ij_markdown_wrap_text_inside_blockquotes = true
[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}]
ij_toml_keep_indents_on_empty_lines = false
[{*.yaml,*.yml}]
indent_size = 4
ij_yaml_align_values_properties = do_not_align
ij_yaml_autoinsert_sequence_marker = true
ij_yaml_block_mapping_on_new_line = false
ij_yaml_indent_sequence_value = true
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
ij_yaml_sequence_on_new_line = false
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true
+28 -18
View File
@@ -1,3 +1,31 @@
# eclipse
bin
*.launch
.settings
.metadata
.classpath
.project
# idea
out
*.ipr
*.iws
*.iml
.idea
# gradle
build
.gradle
# other
eclipse
run
# Files from Forge MDK
logs
forge*changelog.txt
.architectury-transformer/
build/ build/
*.ipr *.ipr
run/ run/
@@ -5,11 +33,9 @@ run/
out/ out/
*.iml *.iml
.gradle/ .gradle/
.gradle-cache/
output/ output/
bin/ bin/
libs/ libs/
.architectury-transformer/
.classpath .classpath
.project .project
@@ -19,28 +45,12 @@ classes/
.vscode .vscode
.settings .settings
*.launch *.launch
hs_err_pid*
**/src/generated/ **/src/generated/
Merged/ Merged/
# Folder created by the buildAll scripts
buildAllJars/
relocate_natives/.venv/
relocate_natives/__pycache__/
relocate_natives/apple-codesign/
# file from notepad++ # file from notepad++
*.bak *.bak
# file genearated via MC version switching using preprocessor # file genearated via MC version switching using preprocessor
build.properties build.properties
# Sqlite databases
*.sqlite
*.sqlite-journal
*.sqlite-shm
*.sqlite-wal
# Don't add access transformers to git as they're dynamically generated
accesstransformer.cfg
+115 -80
View File
@@ -1,103 +1,138 @@
# use Eclipse's JDK # use Eclipse's JDK
# The ci should always use a unix(-like) OS to work image: gradle:eclipse-temurin
image: eclipse-temurin:25
# all stages need to be defined here # all stages need to be defined here
stages: stages:
- build - build_18_2
- api - build_18_1
- pages - build_17_1
- build_16_5
variables: variables:
# Pull core when building # Pull core when building
GIT_SUBMODULE_STRATEGY: recursive GIT_SUBMODULE_STRATEGY: recursive
# These can be extended so code is a bit less duplicated before_script:
.build_java: - echo $CI_JOB_ID
#image: eclipse-temurin:17 # Writing GE_JOB_ID variable to environment file, will need the value in the next stage.
- echo GE_JOB_ID=$CI_JOB_ID >> generate_jars.env
# 1.16.5 build
build_16_5:
stage: build_16_5
script:
- ./gradlew deleteMerged --gradle-user-home cache/;
- ./gradlew build -PmcVer=1.16.5 --gradle-user-home cache/;
- ./gradlew merge --gradle-user-home cache/;
image: eclipse-temurin:16
artifacts:
name: "Merged_NightlyBuild_1_16_5-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
- Merged
expire_in: 1 day
when: always
cache: cache:
key: "gradleCache_$CI_JOB_NAME_SLUG" key: "gradleCache"
policy: pull-push policy: pull-push
paths: paths:
- .gradle - .gradle
- cache/ - cache/
allow_failure: true allow_failure: true
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure
# 1.17.1 build
build: build_17_1:
stage: build stage: build_17_1
parallel:
matrix:
- MC_VER: [
"1.26.1",
"1.21.11", "1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
"1.20.6", "1.20.4", "1.20.2", "1.20.1",
"1.19.4", "1.19.2",
"1.18.2",
"1.17.1",
"1.16.5"
]
script: script:
# this both runs the unit tests and assembles the code - ./gradlew deleteMerged --gradle-user-home cache/;
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/; - ./gradlew build -PmcVer=1.17.1 --gradle-user-home cache/;
- ./gradlew build -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/; - ./gradlew merge --gradle-user-home cache/;
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./build/forgix/* . || true image: eclipse-temurin:16
artifacts: artifacts:
name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}" name: "Merged_NightlyBuild_1_17_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths: paths:
- ./*.jar - Merged
exclude: expire_in: 1 day
- ./*-all.jar # even if one build fails, upload the successful jars
- ./*-dev.jar
- ./*-sources.jar
expire_in: 14 days
when: always when: always
extends: .build_java cache:
key: "gradleCache"
policy: pull-push
api:
stage: api
needs: []
script:
# this should only run for the API
- ./gradlew api:clean --gradle-user-home cache/;
# this also runs unit tests
- ./gradlew api:build --gradle-user-home cache/;
- ./gradlew api:addSourcesToCompiledJar --gradle-user-home cache/;
- cp ./coreSubProjects/api/build/libs/merged/* .
artifacts:
name: "NightlyBuild_Api-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths: paths:
- ./*.jar - .gradle
exclude: - cache/
- ./*-all.jar allow_failure: true
- ./*-dev.jar
- ./*-sources.jar # 1.18.1 build
build_18_1:
stage: build_18_1
script:
- ./gradlew deleteMerged --gradle-user-home cache/; # make sure any previously merged jars are removed before running this job
- ./gradlew build -PmcVer=1.18.1 --gradle-user-home cache/;
- ./gradlew merge --gradle-user-home cache/;
# build using Java 17
image: eclipse-temurin:17
artifacts:
name: "Merged_NightlyBuild_1_18_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
# relative to the root directory
- Merged
expire_in: 1 day expire_in: 1 day
when: always when: always
extends: .build_java cache:
key: "gradleCache"
policy: pull-push
# generate and publish API javadocs
pages:
stage: pages
needs: []
script:
# this should only run for the API
- ./gradlew api:clean --gradle-user-home cache/;
# this also runs unit tests
- ./gradlew api:build --gradle-user-home cache/;
- ./gradlew api:javadoc --gradle-user-home cache/;
- mkdir public
- cp -r $CI_PROJECT_DIR/coreSubProjects/api/build/docs/javadoc/. public
artifacts:
paths: paths:
- public - .gradle
allow_failure: false - cache/
extends: .build_java allow_failure: true
# 1.18.2 build
build_18_2:
stage: build_18_2
script:
- ./gradlew deleteMerged --gradle-user-home cache/;
- ./gradlew build -PmcVer=1.18.2 --gradle-user-home cache/;
- ./gradlew merge --gradle-user-home cache/;
image: eclipse-temurin:17
artifacts:
name: "Merged_NightlyBuild_1_18_2-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
paths:
- Merged
expire_in: 1 day
when: always
cache:
key: "gradleCache"
policy: pull-push
paths:
- .gradle
- cache/
allow_failure: true
# unused deployment stage
#deploy:
# stage: deploy
# image: registry.gitlab.com/gitlab-org/release-cli:latest
# script:
# - echo 'running release_job'
# - echo 'Previous Job ID is printed below'
# - echo $GE_JOB_ID
# # Specifying that this job requires artifacts from the previous job to succeed
# needs:
# - job: build
# artifacts: true
# release:
# name: 'Unstable Jars for Latest Commit' #: $CI_COMMIT_SHORT_SHA'
# description: 'Created automatically using the release-cli.'
# # tag_name is a mendatory field and can not be an empty string
# tag_name: 'Unstable-$CI_COMMIT_SHORT_SHA'
# assets:
# links:
# - name: 'Fabric Jars'
# url: 'https://gitlab.com/jeseibel/minecraft-lod-mod/cw/-/jobs/${GE_JOB_ID}/artifacts/file/fabric/build/libs'
# - name: 'Forge Jars'
# url: 'https://gitlab.com/jeseibel/minecraft-lod-mod/cw/-/jobs/${GE_JOB_ID}/artifacts/file/forge/build/libs'
-37
View File
@@ -1,37 +0,0 @@
## Check off each item in this list before submitting:
<!--
To mark a section as complete either put an "x" in between the square brackets, example: "[x]"
Or click the checkbox once the issue has been created.
-->
1. [ ] Check the FAQ to see if your issue has already been reported and has a solution:
[Problems-and-solutions](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
2. [ ] Make sure you are not using any mods on the incompatible list:
[Mod support FAQ](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/4-mod-support/Mod-Support)
3. [ ] Check the existing issues to verify that your bug hasn't already been submitted:
[Issues](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues)
4. [ ] Upload Minecraft's crash report and/or log. \
Minecraft crash reports are located in: `.minecraft/crash-reports` \
Minecraft logs are located in: `.minecraft/logs`
5. [ ] Upload your Distant Horizons Config. \
The config is found in: `.minecraft/configs/DistantHorizons.toml`
6. [ ] Fill out the information below:
* **minecraft version**:
* **Distant Horizons version**:
* **Mod loader**:
* **Installed mods (list the smallest number of mods that you can use to re-create the bug)**:
* **Describe the bug**:
* **Steps to reproduce the bug**:
-37
View File
@@ -1,37 +0,0 @@
## Check off each item in this list before submitting:
<!--
To mark a section as complete either put an "x" in between the square brackets, example: "[x]"
Or click the checkbox once the issue has been created.
-->
1. [ ] Check the FAQ to see if your issue has already been reported and has a solution:
[Problems-and-solutions](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
2. [ ] Make sure you are not using any mods on the incompatible list:
[Mod support FAQ](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/4-mod-support/Mod-Support)
3. [ ] Check the existing issues to verify that your bug hasn't already been submitted:
[Issues](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues)
4. [ ] Upload Minecraft's crash report and/or log. \
Minecraft crash reports are located in: `.minecraft/crash-reports` \
Minecraft logs are located in: `.minecraft/logs`
5. [ ] Upload your Distant Horizons Config. \
The config is found in: `.minecraft/configs/DistantHorizons.toml`
6. [ ] Fill out the information below:
* **minecraft version**:
* **Distant Horizons version**:
* **Mod loader**:
* **Installed mods (list the smallest number of mods that you can use to re-create the bug)**:
* **Describe the bug**:
* **Steps to reproduce the bug**:
@@ -1,5 +0,0 @@
- [ ] Check the existing [feature requests](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues?sort=updated_desc&state=opened&label_name%5B%5D=Feature) to verify that your feature hasn't already been suggested.
1. **Describe the feature**:
2. **Describe why this feature should be added**:
@@ -1,3 +0,0 @@
1. Check the existing [improvement requests](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues?sort=updated_desc&state=all&label_name%5B%5D=Improvement) to verify that your improvement hasn't already been suggested.
2. **Describe the improvement**:
+3 -2
View File
@@ -1,3 +1,4 @@
[submodule "coreSubProjects"] [submodule "core"]
path = coreSubProjects path = core
url = https://gitlab.com/jeseibel/distant-horizons-core.git url = https://gitlab.com/jeseibel/distant-horizons-core.git
branch = main
-16
View File
@@ -1,16 +0,0 @@
# See mailmap docs: https://git-scm.com/docs/gitmailmap
# Test with git shortlog --summary --email
# Keep sorted for easier editing and smaller diffs
Ada Aster <an.ada.poirier@gmail.com>
CodeF53 <fseusb@gmail.com> <37855219+CodeF53@users.noreply.github.com>
coolGi <me@coolgi.dev> <sasanaps@hotmail.com>
James Seibel <jeseibel@gondtc.com> <jseibel@vertsys.com>
Morippi <leoleo97@libero.it> <leoloe97@libero.it>
Morippi <leoleo97@libero.it> <Morippi>
Ran <43445785+Ran-Mewo@users.noreply.github.com> <10044908-_Ran@users.noreply.gitlab.com>
Ran <43445785+Ran-Mewo@users.noreply.github.com> <43445785+Ran-Mewo@users.noreply.github.com>
Ran <43445785+Ran-Mewo@users.noreply.github.com> <43445785+RanCraftPlayz@users.noreply.github.com>
TomTheFurry <tomlee92502@yahoo.com>
TomTheFurry <tomlee92502@yahoo.com> <46843632+TomTheFurry@users.noreply.github.com>
Yeshi <yeshi@newengine.org>
-7
View File
@@ -1,7 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Fabric Client &amp; Server" type="CompoundRunConfigurationType">
<toRun name="Fabric Client (:fabric)" type="Application" />
<toRun name="Fabric Server (:fabric)" type="Application" />
<method v="2" />
</configuration>
</component>
-7
View File
@@ -1,7 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Forge Client &amp; Server" type="CompoundRunConfigurationType">
<toRun name="Forge Client (gradle)" type="GradleRunConfiguration" />
<toRun name="Forge Server (gradle)" type="GradleRunConfiguration" />
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Forge Client (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="forge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Forge Server (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="forge:runServer" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-7
View File
@@ -1,7 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Neoforge Client &amp; Server" type="CompoundRunConfigurationType">
<toRun name="Neoforge Client (gradle)" type="GradleRunConfiguration" />
<toRun name="Neoforge Server (gradle)" type="GradleRunConfiguration" />
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Neoforge Client (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="neoforge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Neoforge Server (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="neoforge:runServer" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [build]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="build" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [clean]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="clean" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [core:build]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="core:build" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [fabric:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="fabric:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [forge:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="forge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [mergeJars]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="mergeJars" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [neoforge:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="neoforge:runClient" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-24
View File
@@ -1,24 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="distant-horizons [test]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="test" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
+46
View File
@@ -0,0 +1,46 @@
# 1.16.5 version
java_version=8
minecraft_version=1.16.5
parchment_version=2022.03.06
compatible_minecraft_versions=["1.16.4", "1.16.5"]
# Fabric loader
fabric_loader_version=0.13.2
fabric_api_version=0.42.0+1.16
# Fabric mod versions
modmenu_version=1.16.22
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=mc1.16.5-0.6.6
sodium_version=3488820
iris_version=1.16.x-v1.1.4
bclib_version=
immersive_portals_version =
# Fabric mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_lithium=0
enable_sodium=1
enable_iris=0
enable_bclib=0
# Forge loader
forge_version=36.2.28
# Forge mod versions
starlight_version_forge=
terraforged_version=3285909
# Forge mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight_forge=0
enable_terraforged=2
# Quilt loader
quilt_loader_version=0.16.0-beta.10
+46
View File
@@ -0,0 +1,46 @@
# 1.17.1 version
java_version=16
minecraft_version=1.17.1
parchment_version=2021.12.12
compatible_minecraft_versions=["1.17", "1.17.1"]
# Fabric loader
fabric_loader_version=0.13.2
fabric_api_version=0.46.1+1.17
# Fabric mod versions
modmenu_version=2.0.14
starlight_version_fabric=3442770
phosphor_version_fabric=
lithium_version=mc1.17.1-0.7.5
sodium_version=3605275
iris_version=1.17.x-v1.1.4
bclib_version=
immersive_portals_version = 0.14-1.17
# Fabric mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_lithium=0
enable_sodium=1
enable_iris=0
enable_bclib=0
# Forge loader
forge_version=37.1.1
# Forge mod versions
starlight_version_forge=3457784
terraforged_version=
# Forge mod run
# 0 = Dont enable and dont run
# 1 = Can be refranced in code but dosnt run
# 2 = Can be refranced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
# Quilt loader
quilt_loader_version=0.16.0-beta.10
+46
View File
@@ -0,0 +1,46 @@
# 1.18.1 version
java_version=17
minecraft_version=1.18.1
parchment_version=2022.03.06
compatible_minecraft_versions=["1.18", "1.18.1"]
# Fabric loader
fabric_loader_version=0.13.3
fabric_api_version=0.46.6+1.18
# Fabric mod versions
modmenu_version=3.0.1
starlight_version_fabric=3554912
phosphor_version_fabric=3573395
lithium_version=mc1.18.1-0.7.7
sodium_version=3605309
iris_version=1.18.x-v1.1.4
bclib_version=1.2.5
immersive_portals_version = v1.0.4-1.18
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=0
enable_bclib=0
# Forge loader
forge_version=39.1.2
# Forge mod versions
starlight_version_forge=3559934
terraforged_version=
# Forge mod run
# 0 = Dont enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
# Quilt loader
quilt_loader_version=0.16.0-beta.10
+46
View File
@@ -0,0 +1,46 @@
# 1.18.2 version based stuff
java_version=17
minecraft_version=1.18.2
parchment_version=2022.03.13
compatible_minecraft_versions=["1.18.2"]
# Fabric loader
fabric_loader_version=0.13.3
fabric_api_version=0.48.0+1.18.2
# Fabric mod versions
modmenu_version=3.1.0
starlight_version_fabric=3667443
phosphor_version_fabric=3573395
lithium_version=mc1.18.2-0.7.9
sodium_version=3669187
iris_version=1.18.x-v1.2.2
immersive_portals_version = v1.0.4-1.18
bclib_version=0
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=0
enable_bclib=0
# Forge loader
forge_version=40.0.18
# Forge mod versions
starlight_version_forge=0
terraforged_version=
# Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
# Quilt loader
quilt_loader_version=0.16.0-beta.10
-12
View File
@@ -1,12 +0,0 @@
FROM eclipse-temurin:25-jdk
WORKDIR /home/build/
COPY ./gradlew .
RUN chmod +x ./gradlew
CMD echo "\r========== [CLEAN: $MC_VER] ==========" && \
./gradlew clean -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
echo "\r========== [BUILD: $MC_VER] ==========" && \
./gradlew build -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
echo "\r========== [MERGE: $MC_VER] ==========" && \
./gradlew mergeJars -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
echo "\r========== [DONE: $MC_VER] =========="
-1
View File
@@ -1 +0,0 @@
Distant Horizons logos © 2024 by Pankakes are licensed under CC BY-SA 4.0
-165
View File
@@ -1,165 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+91 -149
View File
@@ -1,171 +1,129 @@
# <img src="https://gitlab.com/distant-horizons-team/distant-horizons-core/-/raw/main/_Misc%20Files/logo%20files/new/SVG/Distant-Horizons.svg" height="128px"> # <img src="https://gitlab.com/jeseibel/distant-horizons-core/-/raw/main/_logo%20files/LOD%20logo%20flat%20-%20with%20boarder.png" width="32"> Distant Horizons
_See farther without turning your game into a slide show._
> A mod that adds a Level of Detail System to Minecraft
<br>
# What is Distant Horizons? # What is Distant Horizons?
Distant Horizons is a mod which implements a [Level of Detail](https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics)) system to Minecraft.\ This mod adds a Level Of Detail (LOD) system to Minecraft.\
This allows for far greater render distances without harming performance by gradually lowering the quality of distant terrain. This implementation renders simplified chunks outside the normal render distance\
allowing for an increased view distance without harming performance.
Below is a video demonstrating the system: Or in other words: this mod lets you see farther without turning your game into a slide show.\
If you want to see a quick demo, check out a video covering the mod here:
<a href="https://youtu.be/SxQdbtjGEsc" target="_blank">![Distant Horizons - Alpha 2.0](https://i.ytimg.com/vi/SxQdbtjGEsc/hqdefault.jpg)</a> <a href="https://www.youtube.com/watch?v=H2tnvEVbO1c" target="_blank">![Minecraft Level Of Detail (LOD) mod - Alpha 1.5](https://i.ytimg.com/vi_webp/H2tnvEVbO1c/mqdefault.webp)</a>
<br> ## About this branch
This is a test branch to add support for the quilt mod loader (https://quiltmc.org/)
## Minecraft and Library Versions ### Versions
### This branch supports the following versions of Minecraft: This branch is for these versions of Minecraft
- 1.18.2
- 1.18.1 & 1.18
- 1.17.1 & 1.17
- 1.16.5 & 1.16.4
#### 1.20.4, 1.20.3 (Default) Architectury version: 3.4-SNAPSHOT\
Fabric: 0.15.1\ Java Compiler plugin: Manifold Preprocessor
Fabric API: 0.91.2+1.20.4\
Forge: 49.0.30\
NeoForge: 118-beta\
Parchment: 1.20.2:2023.12.10\
Modmenu: 9.0.0-pre.1
#### 1.20.2 #### 1.18.2 mods
Fabric: 0.14.24\ Forge version: 40.0.18\
Fabric API: 0.90.4+1.20.2\ Fabric version: 0.13.3\
Forge: 48.0.13\ Fabric API version: 0.48.0+1.18.2\
Parchment: 1.20.1:2023.09.03\ Modmenu version: 3.1.0
Modmenu: 8.0.0
#### 1.20.1, 1.20 #### 1.18.1 mods
Fabric: 0.14.24\ Forge version: 39.1.2\
Fabric API: 0.90.4+1.20.1\ Fabric version: 0.13.3\
Forge: 47.2.1\ Fabric API version: 0.42.6+1.18\
Parchment: 1.20.1:2023.09.03\ Modmenu version: 3.0.1
Modmenu: 7.2.2
#### 1.19.4 #### 1.17.1 mods
Fabric: 0.14.24\ Forge version: 37.1.1\
Fabric API: 0.87.1+1.19.4\ Fabric version: 0.13.2\
Forge: 45.2.4\ Fabric API version: 0.46.1+1.17\
Parchment: 1.19.4:2023.06.26\ Modmenu version: 2.0.14
Modmenu: 6.3.1
#### 1.19.2 #### 1.16.5 mods
Fabric: 0.14.24\ Forge version: 36.2.28\
Fabric API: 0.76.1+1.19.2\ Fabric vetsion: 0.13.2\
Forge: 43.3.2\ Fabric API version: 0.42.0+1.16\
Parchment: 1.19.2:2022.11.27\ Modmenu version: 1.16.22
Modmenu: 4.2.0-beta.2
#### 1.18.2
Fabric: 0.14.24\
Fabric API: 0.76.0+1.18.2\
Forge: 40.2.10\
Parchment: 1.18.2:2022.11.06\
Modmenu: 3.2.5
#### 1.17.1, 1.17
Fabric: 0.14.24\
Fabric API: 0.46.1+1.17\
Forge: 37.1.1\
Parchment: 1.17.1:2021.12.12\
Modmenu: 2.0.14
#### 1.16.5, 1.16.4 Notes:\
Fabric: 0.14.24\ This version has been confirmed to work in IDE and Retail Minecraft with ether the Fabric or Forge mod-loader.
Fabric API: 0.42.0+1.16\
Forge: 36.2.39\
Parchment: 1.16.5:2022.03.06\
Modmenu: 1.16.22
### Versions no longer supported
- 1.18.1, 1.18
- 1.19.1, 1.19
- 1.19.3
<br>
### Plugin and Library versions
Gradle: 8.5\
Fabric loom: 1.4-SNAPSHOT\
Architectury loom (Forge gradle replacement): 1.4-SNAPSHOT\
Sponge vanilla gradle: 0.2.1-SNAPSHOT\
Java Preprocessor plugin: Manifold Preprocessor
<br>
## Source Code Installation ## Source Code Installation
#### Nightlly builds
This mod has an autobuild system to automatically build the mod on each commit
- 1.18.2: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/main/download?job=build_18_2
- 1.18.1: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/main/download?job=build_18_1
- 1.17.1: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/main/download?job=build_17_1
- 1.16.5: https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/main/download?job=build_16_5
See the Fabric Documentation online for more detailed instructions:\
https://fabricmc.net/wiki/tutorial:setup
### Prerequisites ### Prerequisites
* A Java Development Kit (JDK) for Java 17 (recommended) or newer. <br> * A Java Development Kit (JDK) for Java 17 (recommended) or newer. Visit https://www.oracle.com/java/technologies/downloads/ for installers.
Visit https://www.oracle.com/java/technologies/downloads/ for installers. * Git or someway to clone git projects. Visit https://git-scm.com/ for installers.
* Git or someway to clone git projects. <br> * (Not required) Any Java IDE with plugins that support Manifold, for example Intellij IDEA.
Visit https://git-scm.com/ for installers.
* (Not required) Any Java IDE with plugins that support Manifold, for example IntelliJ IDEA.
**If using IntelliJ:** **If using IntelliJ:**
1. Install the Manifold plugin 0. Install Manifold plugin
2. Open IDEA and import the build.gradle 1. open IDEA and import the build.gradle
3. Refresh the Gradle project in IDEA if required 2. refresh the Gradle project in IDEA if required
**If using Eclipse: (Note that Eclipse doesn't support Manifold's preprocessor!)** **If using Ecplise: (Note that Eclispe currently doesn't support Manifold's preprocessor!)**
1. Run the command: `./gradlew geneclipseruns` 1. run the command: `./gradlew geneclipseruns`
2. Run the command: `./gradlew eclipse` 2. run the command: `./gradlew eclipse`
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft) 3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
4. Import the project into eclipse 4. Import the project into eclipse
<br>
## Switching Versions ## Switching Versions
This branch support 4 built versions:
- 1.18.2
- 1.18.1 (which also runs on 1.18)
- 1.17.1 (which also runs on 1.17)
- 1.16.5 (which also runs 1.16.5)
To switch between different Minecraft versions, change `mcVer=1.?` in the `gradle.properties` file. To switch between active versions, change `mcVer=1.?` in `gradle.properties` file.
If running in an IDE, to ensure the IDE noticed the version change, run any gradle command to refresh gradle.\ If running on IDE, to ensure IDE pickup the changed versions, you will need to run a gradle command again to allow gradle to update all the libs. (In IntellJ you will also need to do a gradle sync again if it didn't start it automatically.)
In IntelliJ, you will also need to do a gradle sync if it didn't happen automatically. >Note: There may be a `java.nio.file.FileSystemException` thrown on running the command after switching versions. To fix it, either restart your IDE (as your IDE is locking up a file) or use tools like LockHunter to unlock the linked file. (Often a lib file under `common\build\lib` or `forge\build\lib` or `fabric\build\lib`). If anyone knows how to solve this issue please comment to this issue: https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/233
<br>
## Compiling ## Compiling
Prerequisites: **Using GUI**
- JDK 17 or newer 1. Download the zip of the project and extract it
2. Download the core from https://gitlab.com/jeseibel/distant-horizons-core and extract into a folder called `core`
From the File Explorer: 3. Open a command line in the project folder
1. Download and extract the project zip 4. Run the command: `./gradlew assemble`
2. Download the core from https://gitlab.com/distant-horizons-team/distant-horizons-core and extract into a folder called `coreSubProjects` 5. Then run command: `./gradlew mergeJars`
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
5. Merge the jars with `./gradlew mergeJars`
6. The compiled jar file will be in the folder `Merged` 6. The compiled jar file will be in the folder `Merged`
From the command line: **If in terminal:**
1. `git clone --recurse-submodules https://gitlab.com/distant-horizons-team/distant-horizons.git` 1. `git clone --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
2. `cd distant-horizons` 2. `cd minecraft-lod-mod`
3. `./gradlew assemble` 3. `./gradlew assemble`
4. `./gradlew mergeJars` 4. `./gradlew mergeJars`
5. The compiled jar file will be in the folder `Merged` 5. The compiled jar file will be in the folder `Merged`
>Note: You can add the arg: `-PmcVer=1.?` to tell gradle to build a selected MC version instead of having to manually modify the `gradle.properties` file.
Run tests with: `./gradlew test`
>Note: You can add the argument `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file.\
> For example: `./gradlew assemble -PmcVer=1.18.2`
<br>
## Compiling with Docker
`./compile <version>`
You can also locally compile the DH jars without a Java environment by using Docker. Where `<version>` is the version of Minecraft to compile for (ie `1.20.1`), or the keyword `all`. See [Versions](#minecraft-and-library-versions) for a list of all supported values.
<br>
## Other commands ## Other commands
`./gradlew --refresh-dependencies` to refresh local dependencies. `./gradlew --refresh-dependencies` to refresh local dependencies.
`./gradlew clean` to delete any compiled code. `./gradlew clean` to reset everything (this does not affect your code) and then start the process again.
<br>
## Note to self ## Note to self
@@ -173,38 +131,22 @@ The Minecraft source code is NOT added to your workspace in an editable way. Min
Source code uses Mojang mappings & [Parchment](https://parchmentmc.org/) mappings. Source code uses Mojang mappings & [Parchment](https://parchmentmc.org/) mappings.
To generate the source code run `./gradlew genSources` <br> To generate the source code run `./gradlew genSources`\
If your IDE fails to auto-detect the source jars when browsing Minecraft classes; manually select the JAR file ending with -sources.jar when prompted by your IDE. <br> If your IDE fails to auto-detect the sources JAR when browsing Minecraft classes manually select the JAR file ending with -sources.jar when prompted by your IDE
(In IntelliJ it's at the top where it says "choose sources" when browsing a Minecraft class)
<br> In IntelliJ it's at the top where it says choose sources when browsing Minecraft classes
## Other Useful commands ## Useful commands
Run the standalone jar: `./gradlew run` <br> Build only Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build`\
Build the standalone jar: `./gradlew core:build` <br> Build only Forge: `./gradlew fabric:assemble` or `./gradlew forge:build`\
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build` <br> Run the Fabric client (for debugging): `./gradlew fabric:runClient`\
Only build Forge: `./gradlew forge:assemble` or `./gradlew forge:build` <br> Run the Forge client (for debugging): `./gradlew forge:runClient`
Run the Fabric client (for debugging): `./gradlew fabric:runClient` <br>
Run the Forge client (for debugging): `./gradlew forge:runClient` <br>
To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
<br>
## Open Source Acknowledgements ## Open Source Acknowledgements
Forgix (To merge multiple mod versions into one jar) [_Formerly_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\ XZ for Java (data compression)\
https://github.com/PacifistMC/Forgix https://tukaani.org/xz/java.html
LZ4 for Java (data compression)\ DHJarMerger (To merge multiple mod versions into one jar)\
https://github.com/lz4/lz4-java https://github.com/Ran-helo/DHJarMerger
NightConfig for JSON & TOML (config handling)\
https://github.com/TheElectronWill/night-config
SVG Salamander for SVG support (not being used atm)\
https://github.com/blackears/svgSalamander
sqlite-jdbc\
https://github.com/xerial/sqlite-jdbc
+355 -5
View File
@@ -1,8 +1,358 @@
plugins { import io.github.ran.jarmerger.JarMergerPlugin
id 'root'
id 'io.github.pacifistmc.forgix' version '2.+'
buildscript {
dependencies{
classpath files('plugins/DHJarMerger-1.0.jar')
}
} }
forgix { plugins {
autoRun = true id "architectury-plugin" version "3.4-SNAPSHOT"
id "dev.architectury.loom" version "0.11.0-SNAPSHOT" apply false
}
def writeBuildGradlePredefine(List<String> mcVers, int mcIndex) {
ArrayList<String> redefineList = new ArrayList<String>()
for (int i=0; i<mcVers.size(); i++) {
String mcStr = mcVers.get(i).replace(".", "_")
if (mcIndex<i) {
redefineList.add("PRE_MC_"+mcStr)
}
if (mcIndex==i) {
redefineList.add("MC_"+mcStr)
}
if (mcIndex>=i) {
redefineList.add("POST_MC_"+mcStr)
}
}
StringBuilder sb = new StringBuilder()
for (String s : redefineList) {
sb.append(s)
sb.append("=\n")
}
new File(projectDir, "build.properties").text = sb.toString()
}
// Sets up the variables for Manifold in the code
def loadProperties() {
def defaultMcVersion = "1.18.2"
def mcVersion = ""
def mcVers = mcVersions.split(",")
int mcIndex = -1
println "Avalible MC versions: ${mcVersions}"
if (project.hasProperty("mcVer")) {
mcVersion = mcVer
mcIndex = Arrays.asList(mcVers).indexOf(mcVer)
}
if (mcIndex == -1) {
println "No mcVer set or the set mcVer is invalid! Defaulting to ${defaultMcVersion}."
println "Tip: Use -PmcVer='${defaultMcVersion}' in cmd arg to set mcVer."
mcVersion = defaultMcVersion
mcIndex = Arrays.asList(mcVers).indexOf(defaultMcVersion)
assert mcIndex != -1
}
println "Loading properties file at " + mcVersion + ".properties"
def props = new Properties()
props.load(new FileInputStream("$rootProject.rootDir/"+"$mcVersion"+".properties"))
props.each { prop ->
rootProject.ext.set(prop.key, prop.value)
// println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
}
writeBuildGradlePredefine(Arrays.asList(mcVers), mcIndex)
// Stuff for access wideners
def mcVersionToAcsessWidenerVersion = [
"1.16.5": "1_16",
"1.17.1": "1_17",
"1.18.1": "1_18",
"1.18.2": "1_18",
]
// Use this as sometimes multiple versions use the same access wideners
rootProject.ext.set("acsessWidenerVersion", mcVersionToAcsessWidenerVersion.get(mcVersion))
}
loadProperties()
apply plugin: JarMergerPlugin
architectury {
minecraft = rootProject.minecraft_version
}
subprojects { p ->
apply plugin: "dev.architectury.loom"
loom {
silentMojangMappingsLicense()
if (p != project(":core")) {
accessWidenerPath = project(":common").file("src/main/resources/${acsessWidenerVersion}.lod.accesswidener")
}
}
configurations {
common
shadowMe
implementation.extendsFrom shadowMe
}
dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
// The following line declares the mojmap mappings & parchment mappings
mappings loom.layered() {
// Mojmap mappings
officialMojangMappings()
// Parchment mappings (it adds parameter mappings & javadoc)
parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip")
}
//Manifold
annotationProcessor "systems.manifold:manifold-preprocessor:${rootProject.manifold_version}"
// Toml
implementation("com.electronwill.night-config:toml:${rootProject.toml_version}")
if (p != project(":forge") && p != project(":fabric")) {
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
// Do NOT use other classes from fabric loader unless working with fabric
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
}
if (p == project(":fabric")) {
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
// Do NOT use other classes from fabric loader unless working with fabric
if (rootProject.use_quilt_rather_than_fabric == "true") {
// Quilt loader
modImplementation "org.quiltmc:quilt-loader:${rootProject.quilt_loader_version}"
modImplementation "org.quiltmc:quilt-json5:1.0.0" // Needed for quilt loader but for some reason it dosnt come with it
} else {
// Fabric loader
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
}
}
if (p != project(":core")) {
common(project(":core")) { transitive false }
shadowMe(project(":core")) { transitive false }
}
}
// Allows the jar to run standalone
jar {
manifest {
attributes 'Implementation-Title': rootProject.archives_base_name,
'Implementation-Version': rootProject.mod_version,
'Main-Class': 'com.seibel.lod.core.JarMain' // When changing the main of the jar change this line
}
}
}
allprojects { p ->
apply plugin: "java"
apply plugin: "architectury-plugin"
apply plugin: "maven-publish"
archivesBaseName = rootProject.archives_base_name
version = rootProject.mod_version
group = rootProject.maven_group
repositories {
mavenCentral()
// For parchment mappings
maven { url "https://maven.parchmentmc.org" }
// used to download and compile dependencies from git repos
maven { url 'https://jitpack.io' }
// For Manifold Preprocessor
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
// Required for ModMenu
maven { url "https://maven.terraformersmc.com/" }
// Required for importing Modrinth mods
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
content {
includeGroup "maven.modrinth"
}
}
// Required for importing CursedForge mods
maven {
url "https://www.cursemaven.com"
content {
includeGroup "curse.maven"
}
}
// Required for Quilt
maven {
name 'Quilt'
url 'https://maven.quiltmc.org/repository/release'
}
// These 2 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
flatDir {
dirs "${rootDir}/mods/fabric"
content {
includeGroup "fabric-mod"
}
}
flatDir {
dirs "${rootDir}/mods/forge"
content {
includeGroup "forge-mod"
}
}
flatDir {
dirs "${rootDir}/mods/quilt"
content {
includeGroup "quilt-mod"
}
}
}
// Make a new author thing for quilt as quilt uses a different layout for their authors
// The output to look something like this {"James":"Developer","coolGi":"Developer}
def currentAuthor = ""
def quiltAuthors = "{"
def authorCounter = false;
for (reader in rootProject.mod_authors) {
if (authorCounter)
currentAuthor = currentAuthor + reader
if (reader == "\"") {
authorCounter = !authorCounter
if (!authorCounter) {
currentAuthor = currentAuthor.substring(0, currentAuthor.length() - 1); // Delete the qotation mark at the end of the authors name
quiltAuthors = quiltAuthors + "\"" + currentAuthor + "\":\"Developer\"," // Add the author to the string
currentAuthor = ""
}
}
}
quiltAuthors = quiltAuthors.substring(0, quiltAuthors.length() - 1) // Delete the final comma
quiltAuthors = quiltAuthors + "}"
// Put stuff from gradle.properties into the mod info
processResources {
def resourceTargets = ["fabric.mod.json", "quilt.mod.json", "META-INF/mods.toml"] // Location of where to put
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
def replaceProperties = [
version : mod_version,
mod_name : mod_name,
authors : mod_authors,
quilt_authors : quiltAuthors,
description : mod_description,
homepage : mod_homepage,
source : mod_source,
issues : mod_issues,
minecraft_version : minecraft_version,
compatible_minecraft_versions: compatible_minecraft_versions,
java_version : java_version
]
// The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
//TODO: Make Forge loader version also be relaced with non hardcoded value instead of "[36,41)"
inputs.properties replaceProperties
replaceProperties.put 'project', project
filesMatching(resourceTargets) {
expand replaceProperties
}
intoTargets.each { target ->
if (file(target).exists()) {
copy {
from(sourceSets.main.resources) {
include resourceTargets
expand replaceProperties
}
into target
}
}
}
}
// Copies the correct accesswidener and renames it
task copyAccessWidener(type: Copy) {
from project(":common").file("src/main/resources/${rootProject.acsessWidenerVersion}.lod.accesswidener")
into(file(p.file("build/resources/main")))
rename "${rootProject.acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
}
task copyCoreResources(type: Copy) {
from fileTree(project(":core").file("src/main/resources"))
into p.file("build/resources/main")
}
task copyCommonResources(type: Copy) {
from fileTree(project(":common").file("src/main/resources"))
into p.file("build/resources/main")
}
// Is this necessary for running the fabric build
if (p == project(":common")) {
println "Copying [common/src/main/resources/${acsessWidenerVersion}.lod.accesswidner] to [fabric/build/resources/main]."
copy {
from project(":common").file("src/main/resources/${acsessWidenerVersion}.lod.accesswidener")
into project(":fabric").file("build/resources/main")
rename "${acsessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
}
}
tasks.withType(JavaCompile) {
// Add Manifold Preprocessor
// def excapedMCVersion = rootProject.minecraft_version.replace(".", "_")
// options.compilerArgs += ['-Xplugin:Manifold', "-AMC_VERSION_${excapedMCVersion}"]
//
//options.compilerArgs += ['-deprecation']
//options.compilerArgs += ['-verbose']
//options.compilerArgs += ['-Xlint:unchecked']
//options.compilerArgs += ['-Xdiags:verbose']
//options.compilerArgs += ['-Xprint']
//options.compilerArgs += ['-XprintProcessorInfo']
//options.compilerArgs += ['-XprintRounds']
// println options.compilerArgs
options.encoding = "UTF-8"
// Set the java version
if (p != project(":core")) {
options.compilerArgs += ['-Xplugin:Manifold']
options.release = rootProject.java_version as Integer
} else if (p == project(":core")) {
options.release = 8; // Core should use Java 8 no matter what
}
// TODO: make everything use java 8
// options.release = 8 // Use Java 8 for everything so back porting is easier
}
java {
withSourcesJar()
}
// Disable running the core and common
if (p == project(":core") || p == project(":common")) {
runClient.enabled = false
runServer.enabled = false
}
}
// this deletes the merged folder so we don't carry over
// the previous merges to each new build job in the CI/CD pipeline
task deleteMerged(type: Delete) {
delete files("./Merged")
} }
-28
View File
@@ -1,28 +0,0 @@
#!/bin/sh
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
mkdir -p buildAllJars
rm -rf buildAllJars/*
# Loop trough everything in the version properties folder
for d in versionProperties/*; do
# Get the name of the version that is going to be compiled
version=$(echo "$d" | sed "s/versionProperties\///" | sed "s/.properties//")
# Clean out the folders, build it, and merge it
# (We could use "./" to run gradlew, but as it is a shell script im going to be running it with the "sh" command)
echo "==================== Cleaning workspace to build $version ===================="
sh gradlew clean -PmcVer=$version
if [ $? != 0 ]; then continue; fi
echo "====================Building $version ===================="
sh gradlew build -PmcVer=$version
if [ $? != 0 ]; then continue; fi
echo "==================== Merging $version ===================="
sh gradlew mergeJars -PmcVer=$version
if [ $? != 0 ]; then continue; fi
echo "==================== Moving jar ===================="
mv build/merged/*.jar buildAllJars/
done
-29
View File
@@ -1,29 +0,0 @@
@echo off & setlocal enabledelayedexpansion
@rem Note for devs: If this script doesnt work, please look at the unix buildAll script
@rem This script was originally created on linux, so there may be some problems with this translation
echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ====================
mkdir buildAllJars
del buildAllJars/*
@rem Loop trough everything in the version properties folder
for %%f in (versionProperties\*) do (
@rem Get the name of the version that is going to be compiled
set version=%%~nf
@rem Clean out the folders, build it, and merge it
echo ==================== Cleaning workspace to build !version! ====================
call .\gradlew.bat clean
echo ==================== Building !version! ====================
call .\gradlew.bat build -PmcVer="!version!"
echo ==================== Merging !version! ====================
call .\gradlew.bat mergeJars -PmcVer="!version!"
echo ==================== Moving jar ====================
move build\merged\*.jar buildAllJars\
)
endlocal
-24
View File
@@ -1,24 +0,0 @@
plugins {
id 'groovy-gradle-plugin'
}
repositories {
gradlePluginPortal()
mavenCentral()
maven { url = 'https://maven.wagyourtail.xyz/releases' } // Jvmdowngrader & unimined libs
maven { url = 'https://maven.outlands.top/releases' } // Hosts the kappa fork of unimined
maven { url = 'https://maven.wagyourtail.xyz/snapshots' } // The manifold gradle plugin we use
maven { url = 'https://maven.architectury.dev/' } // Minecraft mod libs
maven { url = 'https://maven.fabricmc.net/' } // Fabric
maven { url = 'https://maven.neoforged.net/releases/' } // NeoForge
maven { url = 'https://maven.minecraftforge.net/' } // Forge
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } // Hosts minecraft libs
maven { url = 'https://oss.sonatype.org/content/repositories/snapshots/' } // Hosts a few dependencies we use
}
dependencies {
implementation 'com.gradleup.shadow:shadow-gradle-plugin:9.0.0'
implementation 'xyz.wagyourtail.unimined:xyz.wagyourtail.unimined.gradle.plugin:1.4.17-kappa'
implementation 'xyz.wagyourtail:manifold-gradle:1.0.0-SNAPSHOT'
implementation 'xyz.wagyourtail.jvmdowngrader:xyz.wagyourtail.jvmdowngrader.gradle.plugin:1.3.4'
}
-467
View File
@@ -1,467 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipOutputStream
import javax.annotation.Nonnull
import java.util.function.Function
import java.util.function.Predicate
// Convention plugin for all MC-facing subprojects (common + loaders).
// Common uses this directly; loaders use it via unimined-fabric/forge/neoforge.
// IMPORTANT: unimined MUST be applied before shadow/jvmdowngrader
// so its afterEvaluate runs first and can modify configs.
plugins {
id 'java'
id 'maven-publish'
id 'xyz.wagyourtail.unimined'
id 'com.gradleup.shadow'
id 'xyz.wagyourtail.manifold'
id 'xyz.wagyourtail.jvmdowngrader'
}
def isNotCommonProject = project.name != "common"
// ==================== Version Properties ====================
project.gradle.ext.getProperties().each { prop ->
rootProject.ext.set(prop.key, prop.value)
}
manifold {
version = rootProject.manifold_version
}
// ==================== Repositories ====================
repositories {
maven { url "https://libraries.minecraft.net/" }
mavenCentral()
maven { url "https://repo.enonic.com/public/" }
maven { url "https://maven.parchmentmc.org" }
maven { url "https://maven.architectury.dev" }
maven { url "https://jitpack.io" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
content { includeGroup "maven.modrinth" }
}
maven {
url "https://www.cursemaven.com"
content { includeGroup "curse.maven" }
}
maven { url "https://repo.spongepowered.org/maven/" }
maven { url "https://maven.terraformersmc.com/" }
maven { url "https://maven.neoforged.net/releases/" }
flatDir {
dirs "${rootDir}/mods/fabric"
content { includeGroup "fabric-mod" }
}
flatDir {
dirs "${rootDir}/mods/quilt"
content { includeGroup "quilt-mod" }
}
flatDir {
dirs "${rootDir}/mods/forge"
content { includeGroup "forge-mod" }
}
}
// ==================== Java Config ====================
tasks.withType(JavaCompile).configureEach {
options.release = rootProject.java_version as Integer
options.encoding = "UTF-8"
}
java {
sourceCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
targetCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
withSourcesJar()
}
// ==================== Loader-Only Config ====================
if (isNotCommonProject) {
base { archivesName = rootProject.mod_name }
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
version = project.name + "-" + rootProject.versionStr
group = rootProject.maven_group
javadoc.title = rootProject.mod_name + "-" + project.name
tasks.withType(GenerateModuleMetadata).configureEach {
enabled = false
}
tasks.withType(Test).configureEach {
enabled = false
}
compileTestJava.enabled = false
tasks.withType(Sign).configureEach {
enabled = false
}
jar {
from "LICENSE.txt"
manifest {
attributes(
'Implementation-Title': rootProject.mod_name,
'Implementation-Version': rootProject.mod_version,
'Multi-Release': true,
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain',
)
}
}
}
// ==================== Unimined Minecraft Config ====================
unimined.minecraft(sourceSets.main, true) {
version gradle.ext.minecraft_version
if (gradle.ext.minecraft_version.startsWith("1.")) { // 26.1+ doesn't use obfuscation
mappings {
mojmap()
devNamespace "mojmap"
}
}
}
if (isNotCommonProject) {
// Mixin remapping and common project wiring
unimined.minecraft(sourceSets.main, true) {
mods.modImplementation {
mixinRemap {
reset()
enableBaseMixin()
enableMixinExtra()
}
// Some Fabric API modules ship AW in 'named' namespace instead of 'intermediary'
catchAWNamespaceAssertion()
}
}
dependencies {
implementation(project(":common"))
}
processResources {
from project(":common").sourceSets.main.resources
}
tasks.withType(JavaCompile).configureEach {
source(project(":common").sourceSets.main.allSource)
}
} else {
// Common: fabric for compilation + access widener, no jar remapping or runs
unimined.minecraft {
fabric {
loader gradle.ext.fabric_loader_version
accessWidener project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
}
defaultRemapJar = false
runs.off = true
}
}
// ==================== Configurations ====================
evaluationDependsOn(":core")
configurations {
shadowMe
coreProjects
shadowMe.extendsFrom(coreProjects)
implementation.extendsFrom(shadowMe)
common
implementation.extendsFrom(common)
}
// ==================== Dependencies ====================
// Copy core's compileOnly deps so MC-provided deps are visible without redeclaring them.
project(":core").configurations.compileOnly.allDependencies.each { dep ->
if (!(dep instanceof ProjectDependency))
dependencies.add("compileOnly", dep)
}
dependencies {
// Manifold preprocessor & strings
annotationProcessor(manifold.module("preprocessor"))
// NightConfig: implementation in core (bundled) but Unimined strips it from compile classpath
compileOnly("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
// Core & API projects — bundled into shadow jar
coreProjects(project(":core"))
coreProjects(project(":api"))
// JOML: shadow for old MC versions that don't bundle it (core has it compileOnly already)
if (project.hasProperty("embed_joml") && embed_joml == "true")
shadowMe("org.joml:joml:${rootProject.joml_version}")
// Common project dependency
if (isNotCommonProject)
common(project(":common")) { transitive false }
}
// ==================== NativeTransformer ====================
class NativeTransformer implements ResourceTransformer {
private Predicate<String> fileMatcher
private Function<String, String> filePathMapper
private final HashMap<String, String> replacements = new HashMap()
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
private nativeRelocator
public File rootDir
void matchFiles(Predicate<String> matcher) {
fileMatcher = matcher
}
void mapPaths(Function<String, String> mapper) {
filePathMapper = mapper
}
void relocateNative(String target, String replacement) {
if (replacement.length() > target.length()) {
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
}
replacements.put(target, replacement)
}
@Override
boolean canTransformResource(@Nonnull FileTreeElement element) {
return fileMatcher != null && fileMatcher.test(element.relativePath.pathString)
}
@Override
void transform(@Nonnull TransformerContext context) {
byte[] content = context.inputStream.readAllBytes()
if (nativeRelocator == null) {
nativeRelocator = new NativeRelocator(rootDir.toPath().resolve("relocate_natives"))
}
try {
String path = filePathMapper != null
? filePathMapper.apply(context.path)
: context.path
content = nativeRelocator.processBinary(path, content, replacements)
rewrittenFiles.put(path, content)
}
catch (Throwable e) {
throw new GradleException("Failed to relocate", e)
}
}
@Override
boolean hasTransformedResource() { return !rewrittenFiles.isEmpty() }
@Override
void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {
for (Map.Entry<String, byte[]> rewrittenFile : rewrittenFiles.entrySet()) {
os.putNextEntry(new ZipEntry(rewrittenFile.key))
os.write(rewrittenFile.value)
}
}
}
// ==================== Shadow JAR (loaders only) ====================
if (isNotCommonProject) {
shadowJar {
configurations = [project.configurations.shadowMe]
relocate "com.seibel.distanthorizons.common", "loaderCommon.${project.name}.com.seibel.distanthorizons.common"
def librariesLocation = "DistantHorizons.libraries"
// LZ4
relocate "net.jpountz", "${librariesLocation}.jpountz"
// SLF4J
relocate "org.slf4j", "${librariesLocation}.slf4j"
// SQLite
relocate "org.sqlite", "dh_sqlite", { exclude "org/sqlite/native/**" }
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
transform(NativeTransformer) {
rootDir = project.rootDir
matchFiles { it.startsWith("org/sqlite") }
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
relocateNative "org/sqlite", "dh_sqlite"
relocateNative "org_sqlite", "dh_1sqlite"
}
// ZStd
relocate "com.github.luben", "dhcomgithubluben"
relocate "libzstd-jni", "libzstd-jni_dh"
relocate "zstd-jni", "zstd-jni_dh"
transform(NativeTransformer) {
rootDir = project.rootDir
matchFiles { it.contains("libzstd-jni") && !it.contains("aix/ppc64") }
mapPaths { it.replace("libzstd-jni", "libzstd-jni_dh") }
relocateNative "com/github/luben", "dhcomgithubluben"
relocateNative "com_github_luben", "dhcomgithubluben"
}
// JOML (conditional)
if (project.hasProperty("embed_joml") && embed_joml == "true")
relocate "org.joml", "${librariesLocation}.joml"
// NightConfig
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
mergeServiceFiles()
}
afterEvaluate {
tasks.named("remapJar").configure {
dependsOn(shadowJar)
inputFile.set(shadowJar.archiveFile)
}
// Make run tasks use the shadow jar so relocated deps work in dev.
// Filter out jars bundled in the shadow jar, but keep jars that the loader also
// needs (e.g. NightConfig — DH relocates it, but NeoForge needs the original).
def shadowedPaths = configurations.shadowMe.resolve().collect { it.path }.toSet()
def loaderPaths = configurations.minecraftLibraries.resolve().collect { it.path }.toSet()
tasks.withType(JavaExec).configureEach { runTask ->
dependsOn(shadowJar)
classpath = files(shadowJar.archiveFile) + classpath.filter { file ->
!file.path.contains(project.buildDir.path) &&
!file.path.contains("core${File.separator}build") &&
!file.path.contains("api${File.separator}build") &&
!file.path.contains("common${File.separator}build") &&
!(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
}
// Shared run directory so all loaders use the same worlds
def isClient = runTask.name.toLowerCase().contains("client")
runTask.workingDir = rootProject.file("run/${isClient ? 'client' : 'server'}")
// JVM args
runTask.jvmArgs(
"-Dio.netty.leakDetection.level=advanced",
//"-XX:+UseZGC",
//"-XX:+ZGenerational",
)
if (isClient) {
runTask.jvmArgs(
"-Dminecraft.api.auth.host=https://nope.invalid",
"-Dminecraft.api.account.host=https://nope.invalid",
"-Dminecraft.api.session.host=https://nope.invalid",
"-Dminecraft.api.services.host=https://nope.invalid",
)
runTask.args("--username", "Dev", "--renderDebugLabels", "--tracy")
}
}
}
}
// ==================== Process Resources (loaders only) ====================
if (isNotCommonProject) {
processResources {
def resourceTargets = [
"build_info.json",
"fabric.mod.json",
"quilt.mod.json",
"META-INF/mods.toml",
"META-INF/neoforge.mods.toml",
]
def compatible_forgemc_versions = "${rootProject.compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
// Quilt contributors
def quilt_contributors = []
def mod_author_list = rootProject.mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
for (dev in mod_author_list) {
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
}
quilt_contributors.reverse()
try {
if (rootProject.infoGitCommit == "null")
rootProject.ext.infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
if (rootProject.infoGitBranch == "null")
rootProject.ext.infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
} catch (Exception e) {
rootProject.ext.infoGitCommit = "Git not found"
rootProject.ext.infoGitBranch = "Git not found"
}
def replaceProperties = [
version : rootProject.mod_version,
mod_name : rootProject.mod_readable_name,
group : rootProject.maven_group,
authors : rootProject.mod_authors,
description : rootProject.mod_description,
homepage : rootProject.mod_homepage,
source : rootProject.mod_source,
issues : rootProject.mod_issues,
discord : rootProject.mod_discord,
minecraft_version : rootProject.minecraft_version,
compatible_minecraft_versions: rootProject.compatible_minecraft_versions,
compatible_forgemc_versions : compatible_forgemc_versions,
java_version : rootProject.java_version,
quilt_contributors : "{" + quilt_contributors.join(", ") + "}",
info_git_commit : rootProject.infoGitBranch,
info_git_branch : rootProject.infoGitCommit,
info_build_source : rootProject.infoBuildSource,
fabric_incompatibility_list : rootProject.fabric_incompatibility_list,
fabric_recommend_list : rootProject.fabric_recommend_list,
neoforge_version_range : rootProject.neoforge_version_range,
]
inputs.properties replaceProperties
replaceProperties.put "project", project
filesMatching(resourceTargets) {
expand replaceProperties
}
// Remove unused access wideners
exclude { file ->
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener") {
return true
}
return false
}
}
// ==================== Resource Copy Tasks ====================
task copyCommonLoaderResources(type: Copy) {
from project(":common").file("src/main/resources/${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")
into(file(project.file("build/resources/main")))
rename "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
}
task copyCoreResources(type: Copy) {
from fileTree(project(":core").file("src/main/resources"))
into project.file("build/resources/main")
}
// ==================== JVMDowngrader ====================
jvmdg.downgradeTo = JavaVersion.toVersion(rootProject.java_version)
downgradeJar.archiveClassifier.set(null)
shadeDowngradedApi.archiveClassifier.set(null)
}
-56
View File
@@ -1,56 +0,0 @@
plugins {
id 'java'
}
// Transfer version properties from settings.gradle to project
project.gradle.ext.getProperties().each { prop ->
rootProject.ext.set(prop.key, prop.value)
}
// Version string for archives
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
rootProject.allprojects {
version = (it == rootProject ? "" : it.name + "-") + rootProject.versionStr
group = rootProject.maven_group
// Custom javadoc tags for all subprojects
plugins.withType(JavaPlugin) {
javadoc {
options.tags(
'todo:X"',
'apiNote:a:API Note:',
'implSpec:a:Implementation Requirements:',
'implNote:a:Implementation Note:'
)
}
}
}
// Create build.properties with preprocessor definitions
def writePreprocessorDefinitions() {
StringBuilder sb = new StringBuilder()
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n")
gradle.ext.mcVers.eachWithIndex { ver, idx ->
sb.append("MC_${ver.replace('.', '_')}=${idx}\n")
if (gradle.ext.mcIndex == idx)
sb.append("MC_VER=${idx}\n")
}
if (rootProject.mod_version.toLowerCase().contains("dev")) {
sb.append("DEV_BUILD=\n")
}
new File(rootDir, "build.properties").text = sb.toString()
}
writePreprocessorDefinitions()
// Wire JVMDowngrader to process remapped jars
gradle.projectsEvaluated {
rootProject.subprojects.each {
if (it.tasks.findByName('remapJar') == null) return
it.tasks.downgradeJar.inputFile = it.tasks.remapJar.archiveFile
it.tasks.jar.finalizedBy(it.tasks.remapJar)
it.tasks.remapJar.finalizedBy(it.tasks.shadeDowngradedApi)
}
}
@@ -1,13 +0,0 @@
plugins {
id 'dh-loader'
}
unimined.minecraft {
fabric {
loader gradle.ext.fabric_loader_version
accessWidener project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
}
}
runClient.javaLauncher = null
runServer.javaLauncher = null
@@ -1,17 +0,0 @@
plugins {
id 'dh-loader'
}
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
unimined.minecraft {
forge {
loader gradle.ext.forge_version
useToolchains = false
mixinConfig("DistantHorizons.forge.mixins.json")
accessTransformer aw2at(awFile)
}
}
runClient.javaLauncher = null
runServer.javaLauncher = null
@@ -1,16 +0,0 @@
plugins {
id 'dh-loader'
}
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
unimined.minecraft {
neoForged {
loader gradle.ext.neoforge_version
useToolchains = false
accessTransformer aw2at(awFile)
}
}
runClient.javaLauncher = null
runServer.javaLauncher = null
-239
View File
@@ -1,239 +0,0 @@
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AWToAT {
private static final Map<String, String> ACCESS_POINT_MAP = new HashMap<>();
static {
ACCESS_POINT_MAP.put("accessible", "public");
ACCESS_POINT_MAP.put("extendable", "public-f");
ACCESS_POINT_MAP.put("mutable", "public-f");
}
public String minecraftVersion;
public File remap(File file, String minecraftVersion) {
this.minecraftVersion = minecraftVersion.replace("_", ".");
File atFile = createATFile(file);
processFile(file, atFile);
return atFile;
}
private File createATFile(File file) {
File metaInf = new File(file.getParentFile(), "META-INF");
if (!metaInf.exists() && !metaInf.mkdir()) throw new RuntimeException("Error creating META-INF folder");
File atFile = new File(metaInf, "accesstransformer.cfg");
try {
atFile.createNewFile();
} catch (IOException e) {
throw new RuntimeException("Error creating new file", e);
}
return atFile;
}
private void processFile(File file, File atFile) {
/* Validates if we need to recreate the Access Transformer file if it's out of date */
// Get the hash of the file
String fileHash = getFileHash(file);
try (Scanner atScanner = new Scanner(atFile)) {
// Check if the AT file is up-to-date by comparing the hash of the file with the hash stored in the AT file
boolean hashFound = false;
while (atScanner.hasNextLine()) {
String line = atScanner.nextLine();
if (hashCheck(line, fileHash)) {
hashFound = true;
}
}
// If the AT file is up-to-date, print a message and return
if (hashFound) {
System.out.println("Access Transformer file is already up to date.");
return;
}
} catch (FileNotFoundException ignored) {
// If the AT file does not exist, continue
}
/* Creates the Access Transformer file */
// Opens a scanner for reading the Access Widener file and a writer for writing to the Access Transformer file
try (Scanner scanner = new Scanner(file); FileWriter writer = new FileWriter(atFile)) {
// Create an ExecutorService with a fixed thread pool size equal to the number of available processors
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// List to hold Future objects representing results of computation
List<Future<String>> futures = new ArrayList<>();
// Write the hash of the file to the AT file
writer.write("#DH_MAPPING_HASH:" + fileHash + "\n");
// Read each line from the file
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
// Skip lines starting with "accessWidener", "#" or blank lines
if (line.startsWith("accessWidener") || line.startsWith("#") || line.isBlank()) continue;
// Submit the line to the executor service for processing
// The processing is done by the processLine method
futures.add(executor.submit(() -> processLine(line.split(" "))));
}
// Write the results to the output file
// The results are obtained by calling the get method on each Future
for (Future<String> future : futures) {
writer.write(future.get());
}
// Shutdown the executor service to free up resources
executor.shutdown();
} catch (Exception e) {
throw new RuntimeException("Error reading or writing to file", e);
}
}
private String processLine(String[] fields) {
// fields[0] = access point like "accessible", "extendable", "mutable"
// fields[1] = type like "field", "method", "class"
// fields[2] = class name
// fields[3] = field/method name
// fields[4] = field/method descriptor
try {
// Store the original field/method name
String originalName = "";
// If there is a class name, replace the slashes with dots in the package name
if (fields.length > 2) fields[2] = fields[2].replace("/", ".");
// If there is a field/method name, store the original name and remap it to SRG
if (fields.length > 3) {
originalName = fields[3];
fields[3] = remapToSRG(fields[2], fields[3]);
}
StringBuilder line = new StringBuilder(ACCESS_POINT_MAP.getOrDefault(fields[0], "public")).append(" ");
switch (fields[1]) {
case "field":
line.append(fields[2]).append(" ").append(fields[3]).append(" #").append(originalName);
// It'll be like: access-point class-name field-name-SRG # field-name-Mojmap
// Eg: public net.minecraft.client.Minecraft f_90981_ # instance
break;
case "method":
line.append(fields[2]).append(" ").append(fields[3]).append(fields[4]).append(" #").append(originalName);
// It'll be like: access-point class-name method-name-SRG method-descriptor # method-name-Mojmap
// Eg: public net.minecraft.client.Minecraft m_172797_()Lnet/minecraft/client/Minecraft; # getInstance
break;
default:
line.append(fields[2]);
// It'll be like: access-point class-name
// Eg: public net.minecraft.client.Minecraft
break;
}
line.append("\n");
return line.toString();
} catch (Exception e) {
throw new RuntimeException("Error processing line", e);
}
}
private boolean hashCheck(String line, String fileHash) {
if (line.startsWith("#DH_MAPPING_HASH:")) {
String hash = line.substring(17);
return hash.equals(fileHash);
}
return false;
}
public String getFileHash(File file) {
try {
MessageDigest shaDigest = MessageDigest.getInstance("SHA-256");
try (InputStream fis = new FileInputStream(file)) {
byte[] byteArray = new byte[1024];
int bytesCount;
// Read file data and update in message digest
while ((bytesCount = fis.read(byteArray)) != -1) {
shaDigest.update(byteArray, 0, bytesCount);
}
}
byte[] bytes = shaDigest.digest();
// Convert byte array into signum representation
StringBuilder sb = new StringBuilder();
for (byte aByte : bytes) {
sb.append(Integer.toString((aByte & 0xff) + 0x100, 16).substring(1));
}
// Return complete hash
return sb.toString();
} catch (NoSuchAlgorithmException | IOException e) {
throw new RuntimeException(e);
}
}
// WARNING: BELOW LIES HIGHLY CURSED CODE AND MIGHT EVEN BE ILLEGAL
// Flag to track if there was an error in the GET request
boolean error = false;
/**
* This method returns a field or method name from Mojang mappings as SRG mappings.
* It makes a GET request to the Linkie API to fetch the SRG name.
*
* @param clazz The class name
* @param name The field or method name
* @return The SRG name
* @throws Exception If there is an error in the GET request or the SRG name is not found in the response
*/
private String remapToSRG(String clazz, String name) throws Exception {
// Encode the class and field/method name to be used in the URL
String query = URLEncoder.encode(clazz + "." + name, StandardCharsets.UTF_8);
// Construct the URL for the GET request
String urlString = "https://linkieapi.shedaniel.me/api/search?namespace=mojang&query=" + query + "&version=" + this.minecraftVersion + "&limit=1&allowClasses=false&allowFields=true&allowMethods=true&translate=mojang_srg";
URL url = new URI(urlString).toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuilder content = new StringBuilder();
// Read the response line by line
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
conn.disconnect();
// Regex to find the SRG name in the response
Pattern pattern = Pattern.compile("\"l\"\\s*:\\s*\\{[^}]*\"i\"\\s*:\\s*\"([^\"]*)\"");
Matcher matcher = pattern.matcher(content.toString());
if (matcher.find()) return matcher.group(1);
else throw new Exception("Couldn't find the SRG mapping for name: " + name + "\nCould not find 'i' in 'l' object in the response"); // `i` is the SRG name which is stored in the `l` JSON object
} else {
if (error) {
// If there was an error in the GET request, and we already tried again, throw an exception
throw new Exception("The GET request failed");
}
// If there was an error in the GET request, wait 2.5 seconds and try again as we probably got rate limited
error = true;
Thread.sleep(2500);
return remapToSRG(clazz, name);
}
}
}
-214
View File
@@ -1,214 +0,0 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
class NativeRelocator
{
private final Path rootDirectory;
private final Path cacheRoot;
/**
* Initializes the NativeRelocator by preparing the environment if necessary.
* Executes the appropriate preparation script based on the OS.
*/
NativeRelocator(Path rootDirectory)
{
this.rootDirectory = rootDirectory;
this.cacheRoot = this.rootDirectory.resolve("cache");
}
private void prepare() throws Exception
{
if (this.rootDirectory.resolve(".venv").toFile().exists())
{
return;
}
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(this.rootDirectory.toFile());
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win"))
{
processBuilder.command("powershell", "-ExecutionPolicy", "Bypass", "./prepare.ps1");
}
else if (os.contains("nix")
|| os.contains("nux")
|| os.contains("mac")
|| os.contains("freebsd"))
{
processBuilder.command("./prepare.sh");
}
else
{
throw new IllegalStateException("Unsupported operating system: " + os);
}
Process process = processBuilder.start();
CompletableFuture<Void> outputFuture = readOutputStreams(process);
int exitCode = process.waitFor();
outputFuture.get();
if (exitCode != 0)
{
throw new Exception("Prepare failed: " + exitCode);
}
}
/**
* Reads and prints the output and error streams of a process asynchronously.
*
* @param process The process whose streams should be read.
* @return A CompletableFuture that completes once all output has been processed.
*/
private static CompletableFuture<Void> readOutputStreams(Process process)
{
return CompletableFuture.runAsync(() -> {
try
{
while (process.isAlive() || process.getInputStream().available() > 0 || process.getErrorStream().available() > 0)
{
if (process.getInputStream().available() > 0)
{
byte[] data = new byte[process.getInputStream().available()];
//noinspection ResultOfMethodCallIgnored
process.getInputStream().read(data);
System.out.write(data);
}
if (process.getErrorStream().available() > 0)
{
byte[] data = new byte[process.getErrorStream().available()];
//noinspection ResultOfMethodCallIgnored
process.getErrorStream().read(data);
System.err.write(data);
}
//noinspection BusyWait
Thread.sleep(100);
}
}
catch (Throwable ignored)
{
}
});
}
/**
* Replaces occurrences of a target string in a byte array, ensuring null termination.
*
* @param byteArray The byte array where replacements should occur.
* @param target The string to replace.
* @param replacement The replacement string (must not be longer than the target).
* @throws IllegalArgumentException if the replacement is longer than the target.
*/
private void replaceInNullTerminatedStrings(byte[] byteArray, String target, String replacement)
{
if (target.length() < replacement.length())
{
throw new IllegalArgumentException("Replacement must be the same length or shorter than the target.");
}
byte[] targetBytes = target.getBytes(StandardCharsets.US_ASCII);
byte[] replacementBytes = replacement.getBytes(StandardCharsets.US_ASCII);
byte nullByte = 0;
for (int endPos = 0; endPos < byteArray.length - targetBytes.length - 1; endPos++)
{
int startPos = endPos;
int targetPos = 0;
while (targetPos < targetBytes.length && byteArray[endPos] == targetBytes[targetPos])
{
targetPos++;
endPos++;
}
if (targetPos == targetBytes.length)
{
System.arraycopy(replacementBytes, 0, byteArray, startPos, replacementBytes.length);
startPos = startPos + replacementBytes.length;
while (byteArray[endPos] != nullByte)
{
byteArray[startPos] = byteArray[endPos];
endPos++;
startPos++;
}
byteArray[startPos] = nullByte;
}
}
}
/**
* Runs an external script to fix a modified binary and returns the processed content.
*
* @param outputFilePath Path to store the processed binary.
* @param content The original binary content.
* @return The modified binary content.
* @throws Exception if the process execution fails.
*/
public byte[] fixModifiedBinary(Path outputFilePath, byte[] content) throws Exception
{
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(this.rootDirectory.toFile());
processBuilder.command(
this.rootDirectory.resolve(".venv/Scripts").toFile().exists()
? this.rootDirectory.resolve(".venv/Scripts/python.exe").toString()
: this.rootDirectory.resolve(".venv/bin/python").toString(),
"./fix_modified_binary.py",
outputFilePath.toString()
);
Process process = processBuilder.start();
CompletableFuture<Void> outputFuture = readOutputStreams(process);
process.getOutputStream().write(content);
process.getOutputStream().close();
int exitCode = process.waitFor();
outputFuture.get();
if (exitCode != 0)
{
throw new Exception("Process failed: " + exitCode);
}
return Files.readAllBytes(outputFilePath);
}
/**
* Processes a binary file, applying string replacements and fixing modifications.
*
* @param outputPath The output file path relative to the cache directory.
* @param content The binary content to process.
* @param replacements A map of string replacements to apply.
* @return The modified binary content.
* @throws Exception if processing fails.
*/
public byte[] processBinary(String outputPath, byte[] content, Map<String, String> replacements) throws Exception
{
Path outputFilePath = this.cacheRoot.resolve(outputPath);
//noinspection ResultOfMethodCallIgnored
outputFilePath.getParent().toFile().mkdirs();
if (outputFilePath.toFile().exists())
{
return Files.readAllBytes(outputFilePath);
}
System.out.println("Relocating to " + outputPath + "...");
this.prepare();
for (Map.Entry<String, String> replacement : replacements.entrySet())
{
this.replaceInNullTerminatedStrings(content, replacement.getKey(), replacement.getValue());
}
return this.fixModifiedBinary(outputFilePath, content);
}
}
-78
View File
@@ -1,78 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the team lead James Seibel through Discord at `@backsun`. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
+16 -2
View File
@@ -1,3 +1,17 @@
plugins { architectury {
id 'dh-loader' common(rootProject.enabled_platforms.split(","))
}
publishing {
publications {
mavenCommon(MavenPublication) {
artifactId = rootProject.archives_base_name
from components.java
}
}
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
repositories {
// Add repositories to publish to here.
}
} }
@@ -1,414 +0,0 @@
package com.seibel.distanthorizons.common;
import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
import com.seibel.distanthorizons.common.commands.CommandInitializer;
import com.seibel.distanthorizons.common.wrappers.DependencySetup;
import com.seibel.distanthorizons.common.wrappers.gui.DhDebugScreenEntry;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
import com.seibel.distanthorizons.core.jar.ModJarInfo;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.render.renderer.StubDebugWireframeRenderer;
import com.seibel.distanthorizons.core.util.NativeDialogUtil;
import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.util.threading.DhThreadFactory;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import com.seibel.distanthorizons.core.logging.DhLogger;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* Base for all mod loader initializers
* and handles most setup.
*/
public abstract class AbstractModInitializer
{
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
private CommandInitializer commandInitializer;
//==================//
// abstract methods //
//==================//
//region
protected abstract void createInitialSharedBindings();
protected abstract void createInitialClientBindings();
protected abstract IEventProxy createClientProxy();
protected abstract IEventProxy createServerProxy(boolean isDedicated);
protected abstract void initializeModCompat();
protected abstract void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler);
protected abstract void subscribeClientStartedEvent(Runnable eventHandler);
protected abstract void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler);
protected abstract void runDelayedSetup();
//endregion
//===================//
// initialize events //
//===================//
//region
public void onInitializeClient()
{
DependencySetup.createClientBindings();
this.createInitialClientBindings();
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " client, firing DhApiBeforeDhInitEvent...");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
this.startup();
this.logBuildInfo();
this.createClientProxy().registerEvents();
this.createServerProxy(false).registerEvents();
this.initializeModCompat();
// Client uses config for auto-updater, so it's initialized here instead of post-init stage
this.initConfig();
logModIncompatibilityWarnings(); // needs to be called after config loading
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
#if MC_VER < MC_1_21_9
// debug screen rendering handled via a mixin
#else
DhDebugScreenEntry.register();
#endif
this.subscribeClientStartedEvent(this::postInit);
this.subscribeClientStartedEvent(this::postClientInit);
}
public void onInitializeServer()
{
DependencySetup.createServerBindings();
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " server, firing DhApiBeforeDhInitEvent event...");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
this.startup();
this.logBuildInfo();
// This prevents returning uninitialized Config values,
// resulting from a circular reference mid-initialization in a static class
// noinspection ResultOfMethodCallIgnored
ThreadPresetConfigEventHandler.INSTANCE.toString();
this.createServerProxy(true).registerEvents();
this.initializeModCompat();
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
this.commandInitializer = new CommandInitializer();
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer.initCommands(dispatcher); });
this.subscribeServerStartingEvent(server ->
{
MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
this.initConfig();
this.postInit();
this.postServerInit();
this.commandInitializer.onServerReady();
this.checkForUpdates();
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + server.getServerDirectory());
});
}
//endregion
//===========================//
// inner initializer methods //
//===========================//
//region
private void startup()
{
DependencySetup.createSharedBindings();
SharedApi.init();
this.createInitialSharedBindings();
}
private void logBuildInfo()
{
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
// if the build is stable the branch/commit/etc shouldn't be needed
if (ModInfo.IS_DEV_BUILD)
{
LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch);
LOGGER.info("DH Commit: " + ModJarInfo.Git_Commit);
LOGGER.info("DH Jar Build Source: " + ModJarInfo.Build_Source);
}
}
protected <T extends IModAccessor> void tryCreateModCompatAccessor(String modId, Class<? super T> accessorClass, Supplier<T> accessorConstructor)
{
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
if (modChecker.isModLoaded(modId))
{
//noinspection unchecked
ModAccessorInjector.INSTANCE.bind((Class<? extends IModAccessor>) accessorClass, accessorConstructor.get());
}
else
{
LOGGER.debug("Skipping mod compatibility accessor for: ["+modId+"]");
}
}
private void initConfig()
{
ConfigHandler.tryRunFirstTimeSetup();
Config.completeDelayedSetup();
DhLogger.runDelayedConfigSetup();
}
private void checkForUpdates()
{
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get())
{
if (Config.Client.Advanced.AutoUpdater.enableSilentUpdates.get())
{
LOGGER.info("Silent updates are not allowed for dedicated servers; force disabling.");
Config.Client.Advanced.AutoUpdater.enableSilentUpdates.set(false);
}
SelfUpdater.onStart();
}
}
private void postInit()
{
LOGGER.info("Running Delayed setup...");
this.runDelayedSetup();
if (ConfigHandler.INSTANCE == null)
{
throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
}
LOGGER.info("Delayed setup complete, firing DhApiAfterDhInitEvent event...");
// should be fired after all delayed setup so singletons and config can be accessed
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
}
private void postClientInit()
{
CompletableFuture<Void> future = new CompletableFuture<>();
// This method may be called from either the render thread,
// or some other random setup thread depending on the mod loader.
// In order to avoid confusion/inconsistent problems, we're always going
// to run setup on our own thread.
Thread dhSetupThread = new Thread(() ->
{
try
{
DependencySetup.setRenderingApiBindings();
}
catch (Exception e)
{
future.completeExceptionally(e);
}
finally
{
future.complete(null);
}
});
dhSetupThread.setName(ThreadUtil.THREAD_NAME_PREFIX + "PostClientInit Thread");
dhSetupThread.start();
future.join();
}
private void postServerInit() { SingletonInjector.INSTANCE.bind(AbstractDebugWireframeRenderer.class, new StubDebugWireframeRenderer()); }
//endregion
//==================================//
// mod partial compatibility checks //
//==================================//
//region
/**
* Some mods will work with a few tweaks
* or will partially work but have some known issues we can't solve.
* This method will log (and display to chat if enabled)
* these warnings and potential fixes.
*/
private static void logModIncompatibilityWarnings()
{
boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get();
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
String startingString = "Partially Incompatible Distant Horizons mod detected: ";
// Alex's caves
//region
if (modChecker.isModLoaded("alexscaves"))
{
// There've been a few reports about this mod breaking DH at a few different points in time
// the fixes for said breakage changes depending on the version so unfortunately
// all we can do is log a warning so the user can handle it.
if (showChatWarnings)
{
String message =
MinecraftTextFormat.ORANGE + "Distant Horizons: Alex's Cave detected." + MinecraftTextFormat.CLEAR_FORMATTING +
"You may have to change Alex's config for DH to render. ";
ClientApi.INSTANCE.showChatMessageNextFrame(message);
}
LOGGER.warn(startingString + "[Alex's Caves] may require some config changes in order to render Distant Horizons correctly.");
}
//endregion
// William Wythers' Overhauled Overworld (WWOO)
//region
if (modChecker.isModLoaded("wwoo"))
{
// WWOO has a bug with it's world gen that can't be fixed by DH or WWOO
// (at least that is what James learned after talking with WWOO)
// WWOO will cause grid lines to appear in the world when DH generates the chunks
// this might be due to how WWOO uses features for everything when generating
// and said features don't always get to the edge of said chunks.
String wwooWarning = "LODs generated by DH may have grid lines between sections. Disabling either WWOO or DH's distant generator will fix the problem.";
if (showChatWarnings)
{
String message =
MinecraftTextFormat.ORANGE + "Distant Horizons: WWOO detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
wwooWarning;
ClientApi.INSTANCE.showChatMessageNextFrame(message);
}
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning);
}
//endregion
// Chunky //
//region
boolean chunkyPresent = false;
try
{
Class.forName("org.popcraft.chunky.api.ChunkyAPI");
chunkyPresent = true;
}
catch (ClassNotFoundException ignore) { }
if (chunkyPresent)
{
// Chunky can generate chunks faster than DH can process them,
// causing holes in the LODs.
// Generally it's better and faster to use DH's world generator.
String chunkyWarning = "Chunky can cause DH LODs to have holes " +
"since Chunky can generate chunks faster than DH can process them. \n" +
"Using DH's distant generator instead of chunky or increasing DH's CPU thread count can resolve the issue.";
if (showChatWarnings)
{
String message =
MinecraftTextFormat.ORANGE + "Distant Horizons: Chunky detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
chunkyWarning;
ClientApi.INSTANCE.showChatMessageNextFrame(message);
}
LOGGER.warn(startingString + "[Chunky] "+ chunkyWarning);
}
//endregion
// iris //
//region
IIrisAccessor iris = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
if (iris != null)
{
// get the currently selected rendering API
EDhApiRenderApi renderApi = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
if (renderApi == EDhApiRenderApi.AUTO)
{
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
renderApi = versionConstants.getDefaultRenderingApi();
}
// Iris only supports nataive OpenGL
if (renderApi != EDhApiRenderApi.OPEN_GL)
{
String irisUnsupportedMessage = "Iris doesn't support DH when using the ["+EDhApiRenderApi.BLAZE_3D+"] rendering API, this will need to be fixed on Iris' end. As a temporary fix please change the rendering API to ["+EDhApiRenderApi.OPEN_GL+"] in DH's config file.";
LOGGER.fatal(irisUnsupportedMessage);
NativeDialogUtil.showDialog(ModInfo.READABLE_NAME, irisUnsupportedMessage, "ok", "error");
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
String errorMessage = "loading Distant Horizons. "+irisUnsupportedMessage;
String exceptionError = "Distant Horizons conditional mod config Exception";
mc.crashMinecraft(errorMessage, new Exception(exceptionError));
}
}
//endregion
}
//endregion
//================//
// helper classes //
//================//
//region
public interface IEventProxy
{
void registerEvents();
}
//endregion
}
@@ -1,138 +0,0 @@
package com.seibel.distanthorizons.common;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent;
import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorInternalEvent;
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import io.netty.buffer.ByteBufUtil;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
#if MC_VER <= MC_1_21_10
import net.minecraft.resources.ResourceLocation;
#else
import net.minecraft.resources.Identifier;
#endif
import java.io.IOException;
import java.util.Objects;
public abstract class AbstractPluginPacketSender implements IPluginPacketSender
{
private static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
.build();
#if MC_VER <= MC_1_20_6
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
#elif MC_VER <= MC_1_21_10
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
#else
public static final Identifier WRAPPER_PACKET_RESOURCE = Identifier.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
#endif
// "Forge byte" is an unused packet ID. We have our own system which works with all mod loaders,
// so we're just accounting for it by reading the protocol version as a byte instead of a short in Forge, to keep cross-loader compatibility
private final boolean forgeByteInProtocolVersion;
public AbstractPluginPacketSender() { this(false); }
public AbstractPluginPacketSender(boolean forgeByteInProtocolVersion)
{
this.forgeByteInProtocolVersion = forgeByteInProtocolVersion;
}
@Override
public final void sendToClient(IServerPlayerWrapper serverPlayer, AbstractNetworkMessage message)
{
this.sendToClient((ServerPlayer) serverPlayer.getWrappedMcObject(), message);
}
public abstract void sendToClient(ServerPlayer serverPlayer, AbstractNetworkMessage message);
@Override
public abstract void sendToServer(AbstractNetworkMessage message);
public AbstractNetworkMessage decodeMessage(FriendlyByteBuf in)
{
AbstractNetworkMessage message = null;
try
{
in.markReaderIndex();
int protocolVersion = this.forgeByteInProtocolVersion ? in.readByte() : in.readShort();
if (protocolVersion != ModInfo.PROTOCOL_VERSION)
{
return new IncompatibleMessageInternalEvent(protocolVersion);
}
message = MessageRegistry.INSTANCE.createMessage(in.readUnsignedShort());
message.decode(in);
if (in.isReadable())
{
throw new IOException("Buffer has not been fully read");
}
return message;
}
catch (Exception e)
{
in.resetReaderIndex();
LOGGER.error("Failed to decode message", e);
LOGGER.error("Buffer: ["+in+"]");
LOGGER.error("Buffer contents: ["+ByteBufUtil.hexDump(in)+"]");
return new ProtocolErrorInternalEvent(e, message, true);
}
finally
{
// Prevent connection crashing if not entire buffer has been read
in.readerIndex(in.writerIndex());
}
}
public void encodeMessage(FriendlyByteBuf out, AbstractNetworkMessage message)
{
// This is intentionally unhandled, because errors related to this are unlikely to appear in wild
Objects.requireNonNull(message);
if (this.forgeByteInProtocolVersion)
{
out.writeByte(ModInfo.PROTOCOL_VERSION);
}
else
{
out.writeShort(ModInfo.PROTOCOL_VERSION);
}
try
{
out.markWriterIndex();
out.writeShort(MessageRegistry.INSTANCE.getMessageId(message));
message.encode(out);
}
catch (Exception e)
{
LOGGER.error("Failed to encode message", e);
LOGGER.error("Message: ["+message+"]");
message.getSession().tryHandleMessage(new ProtocolErrorInternalEvent(e, message, false));
// Encode close reason message instead
out.resetWriterIndex();
message = new CloseReasonMessage("Internal error on other side");
out.writeShort(MessageRegistry.INSTANCE.getMessageId(message));
message.encode(out);
}
}
}
@@ -1,39 +0,0 @@
package com.seibel.distanthorizons.common;
#if MC_VER >= MC_1_20_6
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public record CommonPacketPayload(@Nullable AbstractNetworkMessage message) implements CustomPacketPayload
{
public static final Type<CommonPacketPayload> TYPE = new Type<>(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE);
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
@NotNull
@Override
public Type<? extends CustomPacketPayload> type() { return TYPE; }
public static class Codec implements StreamCodec<FriendlyByteBuf, CommonPacketPayload>
{
@NotNull
@Override
public CommonPacketPayload decode(@NotNull FriendlyByteBuf in)
{ return new CommonPacketPayload(PACKET_SENDER.decodeMessage(in)); }
@Override
public void encode(@NotNull FriendlyByteBuf out, CommonPacketPayload payload)
{ PACKET_SENDER.encodeMessage(out, payload.message()); }
}
}
#endif
@@ -1,102 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import net.minecraft.commands.CommandSourceStack;
#if MC_VER >= MC_1_19_2
import net.minecraft.network.chat.Component;
import java.util.Objects;
#else // < 1.19.2
import net.minecraft.network.chat.TranslatableComponent;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
#endif
/**
* Abstract class providing common functionality for DH's commands.
*/
public abstract class AbstractCommand
{
public abstract LiteralArgumentBuilder<CommandSourceStack> buildCommand();
/**
* Sends a success response to the player with the given text.
*
* @param commandContext The command context to send the response to.
* @param text The text to display in the success message.
* @return 1, indicating that the command was successful.
*/
protected int sendSuccessResponse(CommandContext<CommandSourceStack> commandContext, String text, boolean notifyAdmins)
{
#if MC_VER >= MC_1_20_1
commandContext.getSource().sendSuccess(() -> Component.literal(text), notifyAdmins);
#elif MC_VER >= MC_1_19_2
commandContext.getSource().sendSuccess(Component.literal(text), notifyAdmins);
#else
commandContext.getSource().sendSuccess(new TranslatableComponent(text), notifyAdmins);
#endif
return 1;
}
/**
* Sends a failure response to the player with the given text.
*
* @param commandContext The command context to send the response to.
* @param text The text to display in the failure message.
* @return 1, indicating that the command was successful.
*/
protected int sendFailureResponse(CommandContext<CommandSourceStack> commandContext, String text)
{
#if MC_VER >= MC_1_20_1
commandContext.getSource().sendFailure(Component.literal(text));
#elif MC_VER >= MC_1_19_2
commandContext.getSource().sendFailure(Component.literal(text));
#else
commandContext.getSource().sendFailure(new TranslatableComponent(text));
#endif
return 1;
}
/**
* Gets the server player from a command context.
*
* @param commandContext The command context to get the server player from.
* @return The server player wrapper for the player who sent the command.
*/
protected IServerPlayerWrapper getSourcePlayer(CommandContext<CommandSourceStack> commandContext) #if MC_VER < MC_1_19_2 throws CommandSyntaxException #endif
{
#if MC_VER >= MC_1_19_2
return ServerPlayerWrapper.getWrapper(Objects.requireNonNull(commandContext.getSource().getPlayer()));
#else
return ServerPlayerWrapper.getWrapper(commandContext.getSource().getPlayerOrException());
#endif
}
/**
* Checks if the source of a command is a player.
*
* @param source The source of the command to check.
* @return True if the source is a player, false otherwise.
*/
protected boolean isPlayerSource(CommandSourceStack source)
{
#if MC_VER >= MC_1_19_2
return source.isPlayer();
#else
try
{
source.getPlayerOrException();
return true;
}
catch (CommandSyntaxException e)
{
return false;
}
#endif
}
}
@@ -1,84 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.commands.CommandSourceStack;
import org.jetbrains.annotations.Nullable;
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
import static net.minecraft.commands.Commands.literal;
#if MC_VER <= MC_1_21_10
#else
import net.minecraft.server.permissions.PermissionCheck;
import net.minecraft.server.permissions.Permissions;
#endif
public class CommandInitializer
{
private boolean serverReady = false;
#if MC_VER <= MC_1_21_10
private static final int REQUIRED_PERMISSION_LEVEL = 4;
#else
private static final PermissionCheck COMMAND_PERMISSION_CHECK = new PermissionCheck.Require(Permissions.COMMANDS_OWNER);
#endif
/**
* A received command dispatcher, which is held until the server is ready to initialize the commands.
*/
@Nullable
private CommandDispatcher<CommandSourceStack> commandDispatcher;
/**
* Notify the command initializer that the game is ready to accept commands.
* If {@link CommandInitializer#initCommands(CommandDispatcher)} has been fired before it was ready, it will also initialize the commands.
*/
public void onServerReady()
{
this.serverReady = true;
if (this.commandDispatcher != null)
{
this.initCommands(this.commandDispatcher);
this.commandDispatcher = null;
}
}
/**
* Initializes all available commands.
* If the game is not ready yet, it stores the dispatcher to initialize the commands later.
*
* @param commandDispatcher The command dispatcher to register commands to.
*/
public void initCommands(CommandDispatcher<CommandSourceStack> commandDispatcher)
{
if (!this.serverReady)
{
this.commandDispatcher = commandDispatcher;
return;
}
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dh")
.requires((source) ->
{
#if MC_VER <= MC_1_21_10
return source.hasPermission(REQUIRED_PERMISSION_LEVEL);
#else
return COMMAND_PERMISSION_CHECK.check(source.permissions());
#endif
});
builder.then(new ConfigCommand().buildCommand());
builder.then(new DebugCommand().buildCommand());
builder.then(new PregenCommand().buildCommand());
if (DEBUG_CODEC_CRASH_MESSAGE)
{
builder.then(new CrashCommand().buildCommand());
}
commandDispatcher.register(builder);
}
}
@@ -1,154 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
import net.minecraft.commands.CommandSourceStack;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.ToIntBiFunction;
import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;
/**
* Command for managing config.
*/
public class ConfigCommand extends AbstractCommand
{
private static final List<CommandArgumentData<?>> commandArguments = Arrays.asList(
new CommandArgumentData<>(Integer.class, configEntry -> integer(configEntry.getMin(), configEntry.getMax()), IntegerArgumentType::getInteger),
new CommandArgumentData<>(Double.class, configEntry -> doubleArg(configEntry.getMin(), configEntry.getMax()), DoubleArgumentType::getDouble),
new CommandArgumentData<>(Boolean.class, BoolArgumentType::bool, BoolArgumentType::getBool),
new CommandArgumentData<>(String.class, StringArgumentType::string, StringArgumentType::getString)
);
/**
* Builds a command tree.
*/
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
LiteralArgumentBuilder<CommandSourceStack> builder = literal("config");
HashSet<String> addedCommands = new HashSet<>();
for (AbstractConfigBase<?> type : ConfigHandler.INSTANCE.configBaseList)
{
// Skip non-config entries
if (!(type instanceof ConfigEntry))
{
continue;
}
//noinspection PatternVariableCanBeUsed
ConfigEntry configEntry = (ConfigEntry) type;
if (configEntry.getChatCommandName() == null)
{
continue;
}
if (!addedCommands.add(configEntry.getChatCommandName()))
{
throw new IllegalStateException("Duplicate command name: " + configEntry.getChatCommandName());
}
LiteralArgumentBuilder<CommandSourceStack> subcommand = literal(configEntry.getChatCommandName())
.executes(commandContext -> this.sendSuccessResponse(commandContext,
"\n" +
"Description of §l" + configEntry.getChatCommandName() + "§r:\n" +
"§o" + configEntry.getComment().trim() + "§r\n" +
"§7Config file name: §f" + configEntry.name + "§7, category: §f" + configEntry.category + "\n" +
"\n" +
"Current value of " + configEntry.getChatCommandName() + " is §n" + configEntry.get() + "§r",
false
));
ToIntBiFunction<CommandContext<CommandSourceStack>, Object> updateConfigValue = (commandContext, value) -> {
configEntry.set(value);
return this.sendSuccessResponse(commandContext, "Changed the value of [" + configEntry.getChatCommandName() + "] to [" + value + "]", true);
};
// Enum type needs a special case since enums aren't represented by existing argument type
// and need literals for each individual value
if (Enum.class.isAssignableFrom(configEntry.getType()))
{
for (Object choice : configEntry.getType().getEnumConstants())
{
subcommand.then(
literal(choice.toString())
.executes(c -> updateConfigValue.applyAsInt(c, choice))
);
}
}
else
{
boolean setterAdded = false;
for (CommandArgumentData<?> commandArgumentData : commandArguments)
{
if (!commandArgumentData.argumentClass.isAssignableFrom(configEntry.getType()))
{
continue;
}
subcommand.then(argument("value", commandArgumentData.getArgumentType(configEntry))
.executes(c -> updateConfigValue.applyAsInt(c, commandArgumentData.getValue(c, "value"))));
setterAdded = true;
break;
}
if (!setterAdded)
{
throw new RuntimeException("Config type of " + type.getName() + " is not supported: " + configEntry.getType().getSimpleName());
}
}
builder.then(subcommand);
}
return builder;
}
private static class CommandArgumentData<T>
{
public final Class<T> argumentClass;
public final Function<ConfigEntry<T>, ArgumentType<T>> argumentTypeFunction;
private final BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter;
public CommandArgumentData(Class<T> argumentClass, Supplier<ArgumentType<T>> argumentTypeSupplier, BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter)
{
this(argumentClass, configEntry -> argumentTypeSupplier.get(), valueGetter);
}
public CommandArgumentData(Class<T> argumentClass, Function<ConfigEntry<T>, ArgumentType<T>> argumentTypeFunction, BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter)
{
this.argumentClass = argumentClass;
this.argumentTypeFunction = argumentTypeFunction;
this.valueGetter = valueGetter;
}
public ArgumentType<T> getArgumentType(ConfigEntry<T> configEntry)
{
return this.argumentTypeFunction.apply(configEntry);
}
public T getValue(CommandContext<CommandSourceStack> commandContext, String argumentName)
{
return this.valueGetter.apply(commandContext, argumentName);
}
}
}
@@ -1,44 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
import net.minecraft.commands.CommandSourceStack;
import static net.minecraft.commands.Commands.literal;
public class CrashCommand extends AbstractCommand
{
@Override
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
return literal("crash")
.requires(this::isPlayerSource)
.then(literal("encode")
.executes(c -> {
assert SharedApi.tryGetDhServerWorld() != null;
ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld().getServerPlayerStateManager()
.getConnectedPlayer(this.getSourcePlayer(c));
if (serverPlayerState != null)
{
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE));
}
return 1;
}))
.then(literal("decode")
.executes(c -> {
assert SharedApi.tryGetDhServerWorld() != null;
ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld().getServerPlayerStateManager()
.getConnectedPlayer(this.getSourcePlayer(c));
if (serverPlayerState != null)
{
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE));
}
return 1;
}));
}
}
@@ -1,25 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import net.minecraft.commands.CommandSourceStack;
import java.util.ArrayList;
import java.util.List;
import static net.minecraft.commands.Commands.literal;
public class DebugCommand extends AbstractCommand
{
@Override
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
return literal("debug")
.executes(c -> {
List<String> lines = new ArrayList<>();
F3Screen.addStringToDisplay(lines);
return this.sendSuccessResponse(c, String.join("\n", lines), false);
});
}
}
@@ -1,114 +0,0 @@
package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.generation.PregenManager;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
import com.seibel.distanthorizons.core.world.DhServerWorld;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.DimensionArgument;
import net.minecraft.commands.arguments.coordinates.ColumnPosArgument;
import net.minecraft.server.level.ColumnPos;
import net.minecraft.server.level.ServerLevel;
import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;
public class PregenCommand extends AbstractCommand
{
private PregenManager getPregenManager()
{
DhServerWorld world = (DhServerWorld) Objects.requireNonNull(SharedApi.getAbstractDhWorld());
return world.getPregenManager();
}
@Override
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
{
LiteralArgumentBuilder<CommandSourceStack> statusCommand = literal("status")
.executes(this::pregenStatus);
LiteralArgumentBuilder<CommandSourceStack> startCommand = literal("start")
.then(argument("dimension", DimensionArgument.dimension())
.then(argument("origin", ColumnPosArgument.columnPos())
.then(argument("chunkRadius", integer(32))
.executes(this::pregenStart))));
LiteralArgumentBuilder<CommandSourceStack> stopCommand = literal("stop")
.executes(this::pregenStop);
return literal("pregen")
.then(statusCommand)
.then(startCommand)
.then(stopCommand);
}
private int pregenStatus(CommandContext<CommandSourceStack> c)
{
String statusString = this.getPregenManager().getStatusString();
//noinspection ReplaceNullCheck
if (statusString != null)
{
return this.sendSuccessResponse(c, statusString, false);
}
else
{
return this.sendSuccessResponse(c, "Pregen is not running", false);
}
}
private int pregenStart(CommandContext<CommandSourceStack> c) throws CommandSyntaxException
{
this.sendSuccessResponse(c, "Starting pregen. Progress will be in the server console.", true);
ServerLevel level = DimensionArgument.getDimension(c, "dimension");
ColumnPos origin = ColumnPosArgument.getColumnPos(c, "origin");
int chunkRadius = getInteger(c, "chunkRadius");
CompletableFuture<Void> future = this.getPregenManager().startPregen(
ServerLevelWrapper.getWrapper(level),
new DhBlockPos2D(#if MC_VER >= MC_1_19_2 origin.x(), origin.z() #else origin.x, origin.z #endif),
chunkRadius
);
future.whenComplete((result, throwable) -> {
if (throwable instanceof CancellationException)
{
this.sendSuccessResponse(c, "Pregen is cancelled", true);
return;
}
else if (throwable != null)
{
this.sendFailureResponse(c, "Pregen failed: " + throwable.getMessage() + "\n Check the logs for more details.");
return;
}
this.sendSuccessResponse(c, "Pregen is complete", true);
});
return 1;
}
private int pregenStop(CommandContext<CommandSourceStack> c)
{
CompletableFuture<Void> runningPregen = this.getPregenManager().getRunningPregen();
if (runningPregen == null)
{
return this.sendFailureResponse(c, "Pregen is not running");
}
runningPregen.cancel(true);
return 1;
}
}
@@ -1,88 +0,0 @@
package com.seibel.distanthorizons.common.commonMixins;
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen;
import java.util.ArrayList;
public class DhUpdateScreenBase
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final Minecraft MC = Minecraft.getInstance();
public static void tryShowUpdateScreenAndRunAutoUpdateStartup(Runnable runnable)
{
// always needs to be called, otherwise auto update setup won't be completed
boolean newUpdateAvailable = SelfUpdater.onStart();
if (!newUpdateAvailable)
{
return;
}
if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get())
{
LOGGER.info("Auto update disabled, ignoring new version...");
return;
}
runnable = () ->
{
String versionId;
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
if (updateBranch == EDhApiUpdateBranch.STABLE)
{
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
}
else
{
ArrayList<com.electronwill.nightconfig.core.Config> pipelines = GitlabGetter.INSTANCE.projectPipelines;
if (pipelines != null
&& pipelines.size() > 0)
{
versionId = pipelines.get(0).get("sha");
}
else
{
versionId = null;
}
}
if (versionId == null)
{
LOGGER.info("Unable to find new DH update for the ["+updateBranch+"] branch. Assuming DH is up to date...");
return;
}
try
{
MC.setScreen(new UpdateModScreen(
new TitleScreen(false),
versionId
));
}
catch (Exception e)
{
// info instead of error since this can be ignored and probably just means
// there isn't a new DH version available
LOGGER.info("Unable to show DH update screen, reason: ["+e.getMessage()+"].");
}
};
runnable.run();
}
}
@@ -1,96 +0,0 @@
package com.seibel.distanthorizons.common.commonMixins;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class MixinChunkMapCommon
{
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
{
IServerLevelWrapper levelWrapper = ServerLevelWrapper.getWrapper(level);
int chunkPosX;
int chunkPosZ;
#if MC_VER <= MC_1_21_11
chunkPosX = chunk.getPos().x;
chunkPosZ = chunk.getPos().z;
#else
chunkPosX = chunk.getPos().x();
chunkPosZ = chunk.getPos().z();
#endif
// is this position already being updated?
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(levelWrapper, chunkPosX, chunkPosZ))
{
return;
}
// is this chunk being saved to disk?
boolean savingChunkToDisk = ci.getReturnValue();
// true means a chunk was saved to disk
if (!savingChunkToDisk)
{
return;
}
// corrupt/incomplete chunk validation //
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
// this logic should prevent that from happening
#if MC_VER <= MC_1_17_1
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
{
return;
}
#else
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect() || chunk instanceof ProtoChunk)
{
return;
}
#endif
// biome validation //
// some chunks may be missing their biomes, which cause issues when attempting to save them
#if MC_VER <= MC_1_17_1
if (chunk.getBiomes() == null)
{
return;
}
#else
try
{
// this will throw an exception if the biomes aren't set up
chunk.getNoiseBiome(0,0,0);
}
catch (Exception e)
{
return;
}
#endif
// submit the update event
ServerApi.INSTANCE.serverChunkSaveEvent(
new ChunkWrapper(chunk, levelWrapper),
levelWrapper
);
}
}
@@ -1,331 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDebugWireframeRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import net.minecraft.resources.Identifier;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Handles rendering the wireframe particles
* that are used for seeing what the system's doing.
*/
public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
public static BlazeDebugWireframeRenderer INSTANCE = new BlazeDebugWireframeRenderer();
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
//region
// Pos x y z
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1,
//endregion
};
private static final int[] BOX_OUTLINE_INDICES = {
//region
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
//endregion
};
// rendering setup
private boolean init = false;
private RenderPipeline pipeline;
private GpuBuffer boxVertexBuffer;
private GpuBuffer boxIndexBuffer;
private GpuBuffer uniformBuffer;
//=============//
// constructor //
//=============//
//region
public BlazeDebugWireframeRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.createPipelines();
this.createBuffers();
}
private void createPipelines()
{
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(true);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.WIREFRAME);
pipelineBuilder.withName("debug_wireframe_renderer");
pipelineBuilder.withVertexShader("debug/blaze/vert");
pipelineBuilder.withFragmentShader("debug/blaze/frag");
pipelineBuilder.withUniformBuffer("uniformBlock");
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.LINES);
}
this.pipeline = pipelineBuilder.build();
}
private void createBuffers()
{
GpuDevice GPU_DEVICE = RenderSystem.getDevice();
CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
// box vertices
ByteBuffer boxVerticesBuffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
MemoryUtil.memFree(boxVerticesBuffer);
// upload vertex data
{
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = BOX_VERTICES.length * Float.BYTES;
this.boxVertexBuffer = GPU_DEVICE.createBuffer(() -> "distantHorizons:McDebugWireframeBox", usage, size);
{
int length = BOX_VERTICES.length * Float.BYTES;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxVertexBuffer, /*offset*/ 0, length);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.asFloatBuffer().put(BOX_VERTICES);
byteBuffer.rewind();
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
}
}
// box vertex indexes
{
ByteBuffer buffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
buffer.order(ByteOrder.nativeOrder());
buffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
buffer.rewind();
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_INDEX
| GpuBuffer.USAGE_UNIFORM;
this.boxIndexBuffer = GPU_DEVICE.createBuffer(() -> "DH Debug Index Buffer", usage, buffer.capacity());
int offset = 0;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxIndexBuffer, offset, buffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
}
//endregion
//===========//
// rendering //
//===========//
//region
@Override
public void renderBox(Box box)
{
this.init();
//if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
// || BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
//{
// return;
//}
// shouldn't happen, but just in case
if (box == null)
{
return;
}
// delayed getters since this class may be initialized before
// the GPU device has been set
GpuDevice gpuDevice = RenderSystem.getDevice();
CommandEncoder commandEncoder = gpuDevice.createCommandEncoder();
// uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putMat4f() // uTransform
.putVec4() // uColor
.get();
// create data //
Vec3d camPos = MC_RENDER.getCameraExactPosition();
Vec3f camPosFloatThisFrame = new Vec3f((float) camPos.x, (float) camPos.y, (float) camPos.z);
Mat4f boxTransform = Mat4f.createTranslateMatrix(
box.minPos.x - camPosFloatThisFrame.x,
box.minPos.y - camPosFloatThisFrame.y,
box.minPos.z - camPosFloatThisFrame.z);
boxTransform.multiply(Mat4f.createScaleMatrix(
box.maxPos.x - box.minPos.x,
box.maxPos.y - box.minPos.y,
box.maxPos.z - box.minPos.z));
Mat4f transformMatrix = this.dhMvmProjMatrixThisFrame.copy();
transformMatrix.multiply(boxTransform);
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putMat4f(transformMatrix.createJomlMatrix()) // uTransform
.putVec4(
box.color.getRed() / 255.0f,
box.color.getGreen() / 255.0f,
box.color.getBlue() / 255.0f,
box.color.getAlpha() / 255.0f) // uColor
.get()
;
this.uniformBuffer = BlazeUniformUtil.createBuffer("uniformBlock", uniformBufferSize, this.uniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.uniformBuffer, 0, uniformBufferSize);
commandEncoder.writeToBuffer(bufferSlice, buffer);
}
// render //
//try (RenderPass renderPass = commandEncoder.createRenderPass(
// this::getRenderPassName,
// BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
// /*optionalClearColorAsInt*/ OptionalInt.empty(),
// BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
// /*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
//{
// // Bind instance data //
// renderPass.setUniform("uniformBlock", this.uniformBuffer);
//
// renderPass.setPipeline(this.pipeline);
// renderPass.setIndexBuffer(this.boxIndexBuffer, VertexFormat.IndexType.INT);
//
// renderPass.setVertexBuffer(0, this.boxVertexBuffer);
//
// renderPass.drawIndexed(
// /*indexStart*/ 0,
// /*firstIndex*/0,
// /*indexCount*/BOX_OUTLINE_INDICES.length,
// /*instanceCount*/1);
//}
}
private String getRenderPassName() { return "distantHorizons:McDebugRenderer"; }
//endregion
}
#endif
@@ -1,624 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhGenericObjectRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericObjectRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderCleanupEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderSetupEvent;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.common.render.blaze.objects.BlazeGenericObjectVertexContainer;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.resources.Identifier;
import java.awt.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.concurrent.ConcurrentHashMap;
/**
* Handles rendering generic groups of {@link DhApiRenderableBox}.
*
* @see IDhApiCustomRenderRegister
* @see DhApiRenderableBox
*/
public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded();
/**
* Can be used to troubleshoot the renderer.
* If enabled several debug objects will render around (0,150,0).
*/
public static final boolean RENDER_DEBUG_OBJECTS = false;
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
// rendering setup
private boolean init = false;
private RenderPipeline pipeline;
private GpuBuffer vertUniformBuffer;
//=============//
// constructor //
//=============//
//region
public BlazeDhGenericObjectRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.createPipelines();
if (RENDER_DEBUG_OBJECTS)
{
this.addGenericDebugObjects();
}
}
private void createPipelines()
{
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(true);
pipelineBuilder.withDepthWrite(true);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT); // TRANSLUCENT = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("generic_objects");
pipelineBuilder.withVertexShader("generic/blaze/vert");
pipelineBuilder.withFragmentShader("generic/blaze/frag");
pipelineBuilder.withSampler("uLightMap");
pipelineBuilder.withUniformBuffer("vertUniformBlock");
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
.add("aColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
.add("aMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
.add("paddingOne", BlazeDhVertexFormatUtil.BYTE_PAD)
.add("paddingTwo", BlazeDhVertexFormatUtil.BYTE_PAD)
.add("paddingThree", BlazeDhVertexFormatUtil.BYTE_PAD)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
}
this.pipeline = pipelineBuilder.build();
}
private void addGenericDebugObjects()
{
GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE;
// single giant box
IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":CyanChunkBox",
new DhApiRenderableBox(
new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16),
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125),
EDhApiBlockMaterial.WATER)
);
singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleGiantBoxGroup);
// single slender box
IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":GreenBeacon",
new DhApiRenderableBox(
new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32),
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125),
EDhApiBlockMaterial.ILLUMINATED)
);
singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleTallBoxGroup);
// absolute box group
ArrayList<DhApiRenderableBox> absBoxList = new ArrayList<>();
for (int i = 0; i < 18; i++)
{
absBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25),
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()),
EDhApiBlockMaterial.LAVA
)
);
}
IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList);
this.add(absolutePosBoxGroup);
// relative box group
ArrayList<DhApiRenderableBox> relBoxList = new ArrayList<>();
for (int i = 0; i < 8; i+=2)
{
relBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1),
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()),
EDhApiBlockMaterial.METAL
)
);
}
IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MovingMagentaGroup",
new DhApiVec3d(24, 140, 24),
relBoxList);
relativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos();
pos.x += event.partialTicks / 2;
pos.x %= 32;
relativePosBoxGroup.setOriginBlockPos(pos);
});
this.add(relativePosBoxGroup);
// massive relative box group
ArrayList<DhApiRenderableBox> massRelBoxList = new ArrayList<>();
for (int x = 0; x < 50*2; x+=2)
{
for (int z = 0; z < 50*2; z+=2)
{
massRelBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z),
new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()),
EDhApiBlockMaterial.TERRACOTTA
)
);
}
}
IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MassRedGroup",
new DhApiVec3d(-25, 140, 0),
massRelBoxList);
massRelativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos();
blockPos.y += event.partialTicks / 4;
if (blockPos.y > 150f)
{
blockPos.y = 140f;
Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED;
massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; });
massRelativePosBoxGroup.triggerBoxChange();
}
massRelativePosBoxGroup.setOriginBlockPos(blockPos);
});
this.add(massRelativePosBoxGroup);
}
//endregion
//==============//
// registration //
//==============//
//region
@Override
public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException
{
if (!(iBoxGroup instanceof RenderableBoxGroup))
{
throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"].");
}
RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup;
if (boxGroup.size() != 0)
{
// trigger a box change to make sure the initial data is uploaded
boxGroup.triggerBoxChange();
}
long id = boxGroup.getId();
if (this.boxGroupById.containsKey(id))
{
throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present.");
}
this.boxGroupById.put(id, boxGroup);
}
@Override
public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); }
public void clear() { this.boxGroupById.clear(); }
//endregion
//===========//
// rendering //
//===========//
//region
/**
* @param renderingWithSsao
* if true that means this render call is happening before the SSAO pass
* and any objects rendered in this pass will have SSAO applied to them.
*/
@Override
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
{
//==============//
// render setup //
//==============//
//#region
profiler.push("setup");
this.init();
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
Vec3d camPos = MC_RENDER.getCameraExactPosition();
//#endregion
if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
{
return;
}
//===========//
// rendering //
//===========//
//#region
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
for (RenderableBoxGroup boxGroup : boxList)
{
// validation //
// shouldn't happen, but just in case
if (boxGroup == null)
{
continue;
}
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled != renderingWithSsao)
{
continue;
}
profiler.popPush("render prep");
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
// ignore inactive groups
if (!boxGroup.active)
{
continue;
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
if (cancelRendering)
{
continue;
}
// update instanced data if needed
{
boxGroup.tryUpdateInstancedDataAsync();
// skip groups that haven't been uploaded yet
if (boxGroup.vertexBufferContainer.getState() != IDhGenericObjectVertexBufferContainer.EState.RENDER)
{
continue;
}
}
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DEFAULT_SHADING;
}
// uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putIVec3() // uOffsetChunk
.putVec3() // uOffsetSubChunk
.putIVec3() // uCameraPosChunk
.putVec3() // uCameraPosSubChunk
.putVec3() // aTranslateChunk
.putVec3() // aTranslateSubChunk
.putMat4f() // uProjectionMvm
.putInt() // uSkyLight
.putInt() // uBlockLight
.putFloat() // uNorthShading
.putFloat() // uSouthShading
.putFloat() // uEastShading
.putFloat() // uWestShading
.putFloat() // uTopShading
.putFloat() // uBottomShading
.get();
// create data //
Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix);
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putIVec3(
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetChunk
.putVec3(
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetSubChunk
.putIVec3(
LodUtil.getChunkPosFromDouble(camPos.x),
LodUtil.getChunkPosFromDouble(camPos.y),
LodUtil.getChunkPosFromDouble(camPos.z)
) // uCameraPosChunk
.putVec3(
LodUtil.getSubChunkPosFromDouble(camPos.x),
LodUtil.getSubChunkPosFromDouble(camPos.y),
LodUtil.getSubChunkPosFromDouble(camPos.z)
) // uCameraPosSubChunk
.putMat4f(projectionMvmMatrix.createJomlMatrix()) // uProjectionMvm
.putInt(boxGroup.getSkyLight()) // uSkyLight
.putInt(boxGroup.getBlockLight()) // uBlockLight
.putFloat(shading.north)
.putFloat(shading.south)
.putFloat(shading.east)
.putFloat(shading.west)
.putFloat(shading.top)
.putFloat(shading.bottom)
.get()
;
this.vertUniformBuffer = BlazeUniformUtil.createBuffer("vertUniformBlock", uniformBufferSize, this.vertUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
// render //
profiler.popPush("rendering");
profiler.push(boxGroup.getResourceLocationNamespace());
profiler.push(boxGroup.getResourceLocationPath());
this.renderBoxGroupInstanced(renderEventParam, boxGroup, profiler);
profiler.pop(); // resource path
profiler.pop(); // resource namespace
boxGroup.postRender(renderEventParam);
}
//#endregion
//==========//
// clean up //
//==========//
//region
profiler.popPush("cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
profiler.pop();
//endregion
}
private String getRenderPassName() { return "distantHorizons:McGenericObjectRenderer"; }
//endregion
//=====================//
// instanced rendering //
//=====================//
//region
private void renderBoxGroupInstanced(
RenderParams renderEventParam,
RenderableBoxGroup boxGroup,
IProfilerWrapper profiler)
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
// update instance data //
profiler.push("vertex setup");
BlazeGenericObjectVertexContainer container = (BlazeGenericObjectVertexContainer) boxGroup.vertexBufferContainer;
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
// Bind instance data //
profiler.popPush("binding");
renderPass.setUniform("vertUniformBlock", this.vertUniformBuffer);
// set pipeline
renderPass.setPipeline(this.pipeline);
renderPass.setIndexBuffer(container.indexGpuBuffer, VertexFormat.IndexType.INT);
renderPass.setVertexBuffer(0, container.vboGpuBuffer);
// Draw instanced
profiler.popPush("render");
if (container.uploadedBoxCount > 0)
{
renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
/*indexCount*/container.uploadedBoxCount * 36, // 36 = 6 faces * 6 verticies per face
/*instanceCount*/1);
}
}
profiler.pop();
}
//endregion
//=========//
// F3 menu //
//=========//
//region
public String getVboRenderDebugMenuString()
{
// get counts
int totalGroupCount = this.boxGroupById.size();
int totalBoxCount = 0;
int activeGroupCount = 0;
int activeBoxCount = 0;
for (long key : this.boxGroupById.keySet())
{
RenderableBoxGroup renderGroup = this.boxGroupById.get(key);
if (renderGroup.active)
{
activeGroupCount++;
activeBoxCount += renderGroup.size();
}
totalBoxCount += renderGroup.size();
}
return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " +
"Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount);
}
//endregion
}
#endif
@@ -1,97 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhMetaRenderer {}
#else
import com.mojang.blaze3d.textures.GpuTexture;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
import net.minecraft.client.Minecraft;
import java.awt.*;
public class BlazeDhMetaRenderer implements IDhMetaRenderer
{
public static final BlazeDhMetaRenderer INSTANCE = new BlazeDhMetaRenderer();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private BlazeDhApplyRenderer applyRenderer;
public final BlazeTextureWrapper dhDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhDepthTexture");
public final BlazeTextureWrapper dhColorTextureWrapper = BlazeTextureWrapper.createColor("DhColorTexture");
//=============//
// constructor //
//=============//
//region
private BlazeDhMetaRenderer()
{
this.applyRenderer = new BlazeDhApplyRenderer(
"dh_apply_to_mc",
null,
"apply/blaze/vert", "apply/blaze/frag"
);
}
//endregion
//=================//
// pre/post render //
//=================//
//region
@Override
public void runRenderPassSetup(RenderParams renderParams)
{
// textures
this.dhDepthTextureWrapper.tryCreateOrResize();
this.dhColorTextureWrapper.tryCreateOrResize();
}
@Override
public void runRenderPassCleanup(RenderParams renderParams) {}
@Override
public void applyToMcTexture(RenderParams renderParams)
{
GpuTexture mcColorTexture = Minecraft.getInstance().getMainRenderTarget().getColorTexture();
this.applyRenderer.render(this.dhColorTextureWrapper.texture, this.dhDepthTextureWrapper.texture, mcColorTexture);
}
//endregion
//================//
// clear textures //
//================//
//region
@Override
public void clearDhDepthAndColorTextures(RenderParams renderParams)
{
this.dhDepthTextureWrapper.clearDepth(1.0f);
Color color = MC_RENDER.getSkyColor();
this.dhColorTextureWrapper.clearColor(ColorUtil.toColorInt(color));
}
//endregion
}
#endif
@@ -1,71 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhRenderApiDefinition {}
#else
import com.seibel.distanthorizons.common.render.blaze.objects.BlazeGenericObjectVertexContainer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhFarFadeRenderer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhFogRenderer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhSsaoRenderer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeVanillaFadeRenderer;
import com.seibel.distanthorizons.common.render.blaze.test.BlazeDhTestTriangleRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVertexBufferWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeLodUniformBufferWrapper;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.*;
public class BlazeDhRenderApiDefinition extends AbstractDhRenderApiDefinition
{
//=========//
// getters //
//=========//
//region
public String getApiName() { return "Blaze3D"; }
//endregion
//============//
// singletons //
//============//
//region
@Override public IDhMetaRenderer getMetaRenderer() { return BlazeDhMetaRenderer.INSTANCE; }
@Override public IDhTerrainRenderer getTerrainRenderer() { return BlazeDhTerrainRenderer.INSTANCE; }
@Override public IDhSsaoRenderer getSsaoRenderer() { return BlazeDhSsaoRenderer.INSTANCE; }
@Override public IDhFogRenderer getFogRenderer() { return BlazeDhFogRenderer.INSTANCE; }
@Override public IDhFarFadeRenderer getFarFadeRenderer() { return BlazeDhFarFadeRenderer.INSTANCE; }
@Override public AbstractDebugWireframeRenderer getDebugWireframeRenderer() { return BlazeDebugWireframeRenderer.INSTANCE; }
@Override public IDhVanillaFadeRenderer getVanillaFadeRenderer() { return BlazeVanillaFadeRenderer.INSTANCE; }
@Override public IDhTestTriangleRenderer getTestTriangleRenderer() { return BlazeDhTestTriangleRenderer.INSTANCE; }
//endregion
//===========//
// factories //
//===========//
//region
@Override public IDhGenericRenderer createGenericRenderer() { return new BlazeDhGenericObjectRenderer(); }
@Override public IVertexBufferWrapper createVboWrapper(String name) { return new BlazeVertexBufferWrapper(name); }
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return new BlazeLodUniformBufferWrapper(); }
@Override public IDhGenericObjectVertexBufferContainer createGenericVboContainer() { return new BlazeGenericObjectVertexContainer(); }
//endregion
}
#endif
@@ -1,367 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhTerrainRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeLodUniformBufferWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVertexBufferWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import net.minecraft.resources.Identifier;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/** Renders rendering DH's LOD terrain. */
public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhTerrainRenderer INSTANCE = new BlazeDhTerrainRenderer();
private RenderPipeline opaquePipeline;
private RenderPipeline transparentPipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer vertSharedUniformBuffer;
//=============//
// constructor //
//=============//
//region
private BlazeDhTerrainRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(true);
pipelineBuilder.withDepthWrite(true);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("terrain");
pipelineBuilder.withSampler("uLightMap");
pipelineBuilder.withVertexShader("lod/blaze/vert");
pipelineBuilder.withFragmentShader("lod/blaze/frag");
pipelineBuilder.withUniformBuffer("vertUniqueUniformBlock");
pipelineBuilder.withUniformBuffer("vertSharedUniformBlock");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.SHORT_XYZ_POS)
.add("meta", BlazeDhVertexFormatUtil.META)
.add("vColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
.add("irisMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
.add("irisNormal", BlazeDhVertexFormatUtil.IRIS_NORMAL)
.add("paddingTwo", BlazeDhVertexFormatUtil.BYTE_PAD)
.add("paddingThree", BlazeDhVertexFormatUtil.BYTE_PAD) // padding is to make sure the format is a multiple of 4
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
}
// opaque
{
pipelineBuilder.withoutBlend();
this.opaquePipeline = pipelineBuilder.build();
}
// transparent
{
// TRANSLUCENT = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
this.transparentPipeline = pipelineBuilder.build();
}
this.init = true;
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(
RenderParams renderEventParam,
boolean opaquePass,
SortedArraySet<LodBufferContainer> bufferContainers,
IProfilerWrapper profiler)
{
this.tryInit();
profiler.push("vert unique uniforms");
{
// create data //
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
bufferContainer.uniformContainer.tryUpload();
}
}
profiler.popPush("vert share uniforms");
{
Mat4f combinedMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
combinedMatrix.multiply(renderEventParam.dhModelViewMatrix);
float earthCurveRatio = Config.Client.Advanced.Graphics.Experimental.earthCurveRatio.get();
if (earthCurveRatio < -1.0f || earthCurveRatio > 1.0f)
{
earthCurveRatio = /*6371KM*/ 6371000.0f / earthCurveRatio;
}
else
{
// disable curvature if the config value is between -1 and 1
earthCurveRatio = 0.0f;
}
// upload data //
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uIsWhiteWorld
.putFloat() // uWorldYOffset
.putFloat() // uMircoOffset
.putFloat() // uEarthRadius
.putVec3() // uCameraPos
.putMat4f() // uCombinedMatrix
.get();
ByteBuffer buffer = MemoryUtil.memAlloc(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
Std140Builder.intoBuffer(buffer)
.putInt(0) // uIsWhiteWorld
.putFloat((float) renderEventParam.worldYOffset) // uWorldYOffset
.putFloat(0.01f) // uMircoOffset // 0.01 block offset
.putFloat(earthCurveRatio) // uEarthRadius
.putVec3(
(float)renderEventParam.exactCameraPosition.x,
(float)renderEventParam.exactCameraPosition.y,
(float)renderEventParam.exactCameraPosition.z) // uCameraPos
.putMat4f(combinedMatrix.createJomlMatrix()) // uCombinedMatrix
.get();
this.vertSharedUniformBuffer = BlazeUniformUtil.createBuffer("vertSharedUniformBlock", uniformBufferSize, this.vertSharedUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertSharedUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
MemoryUtil.memFree(buffer);
}
profiler.popPush("set frag uniforms");
{
int uniformBufferSize = new Std140SizeCalculator()
.putFloat() // uClipDistance
.putFloat() // uNoiseIntensity
.putInt() // uNoiseSteps
.putInt() // uNoiseDropoff
.putInt() // uDitherDhRendering
.putInt() // uNoiseEnabled
.get();
// create data //
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
if (!Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
}
// upload data //
ByteBuffer buffer = MemoryUtil.memAlloc(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putFloat(dhNearClipDistance) // uClipDistance
.putFloat(Config.Client.Advanced.Graphics.NoiseTexture.noiseIntensity.get()) // uNoiseIntensity
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseSteps.get()) // uNoiseSteps
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseDropoff.get()) // uNoiseDropoff
.putInt(Config.Client.Advanced.Graphics.Quality.ditherDhFade.get() ? 1 : 0) // uDitherDhRendering
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.enableNoiseTexture.get() ? 1 : 0) // uNoiseEnabled
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
MemoryUtil.memFree(buffer);
}
// render pass setup
{
profiler.popPush("setup");
// create a render pass
try(RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty())
)
{
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
// set pipeline
renderPass.setPipeline(opaquePass ? this.opaquePipeline : this.transparentPipeline);
// shared uniforms
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setUniform("vertSharedUniformBlock", this.vertSharedUniformBuffer);
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
profiler.popPush("binding");
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
BlazeLodUniformBufferWrapper uniformWrapper = (BlazeLodUniformBufferWrapper)bufferContainer.uniformContainer;
boolean columnBuilderDebugEnabled = Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugEnable.get();
if (columnBuilderDebugEnabled)
{
if (DhSectionPos.getDetailLevel(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugDetailLevel.get()
&& DhSectionPos.getX(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugXPos.get()
&& DhSectionPos.getZ(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugZPos.get())
{
int breakpoint = 0;
}
else
{
continue;
}
}
renderPass.setUniform("vertUniqueUniformBlock", uniformWrapper.gpuBuffer);
profiler.popPush("rendering");
// render each buffer
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers;
for (int i = 0; i < bufferWrapperList.length; i++)
{
BlazeVertexBufferWrapper bufferWrapper = (BlazeVertexBufferWrapper) bufferWrapperList[i];
if (!bufferWrapper.uploaded
|| bufferWrapper.vertexCount == 0)
{
continue;
}
// fire render event
{
Vec3d camPos = renderEventParam.exactCameraPosition;
Vec3f modelPos = new Vec3f(
(float) (bufferContainer.minCornerBlockPos.getX() - camPos.x),
(float) (bufferContainer.minCornerBlockPos.getY() - camPos.y),
(float) (bufferContainer.minCornerBlockPos.getZ() - camPos.z));
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
}
renderPass.setIndexBuffer(bufferWrapper.getIndexGpuBuffer(), VertexFormat.IndexType.INT);
renderPass.setVertexBuffer(0, bufferWrapper.vertexGpuBuffer); // vertex buffer can only be "0" lol
if (!bufferWrapper.vertexGpuBuffer.isClosed())
{
renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
/*indexCount*/bufferWrapper.indexCount,
/*instanceCount*/1);
}
}
}
}
}
profiler.pop();
}
private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
private String getRenderPassName() { return "distantHorizons:McLodRenderer"; }
//endregion
}
#endif
@@ -1,270 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.blaze.apply;
#if MC_VER <= MC_1_21_10
public class BlazeDhApplyRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Copies the given color texture
* where the depth (or another attribute) is valid.
* Often used to apply post processing effects or
* the DH texture to MC's color texture. <br><br>
*
* @see BlazeDhCopyRenderer
*/
public class BlazeDhApplyRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private RenderPipeline pipeline;
protected GpuBuffer vboGpuBuffer;
protected final String name;
protected final String identifierName;
public String getIdentifierName() { return this.identifierName; }
@Nullable
private final BlendFunction blendFunction;
private final String vertexShaderPath;
private final String fragmentShaderPath;
private final BlazeTextureViewWrapper sourceColorTextureViewWrapper = new BlazeTextureViewWrapper();
private final BlazeTextureViewWrapper sourceDepthTextureViewWrapper = new BlazeTextureViewWrapper();
private final BlazeTextureViewWrapper destinationColorTextureViewWrapper = new BlazeTextureViewWrapper();
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper dummyDepthTextureWrapper = BlazeTextureWrapper.createDepth("apply_dummy_depth");
/**
* Can be set for special application shaders that need
* extra information. <br><br>
*
* will be an empty array if unneeded
*/
private final String[] uniformNames;
/** will be an empty array if unneeded */
private final GpuBuffer[] uniformBuffers;
//=============//
// constructor //
//=============//
//region
public BlazeDhApplyRenderer(
String name,
@Nullable BlendFunction blendFunction,
String vertexShaderPath, String fragmentShaderPath
)
{
this(
name,
blendFunction,
vertexShaderPath, fragmentShaderPath,
new String[0] // no extra uniforms
);
}
public BlazeDhApplyRenderer(
String name,
@Nullable BlendFunction blendFunction,
String vertexShaderPath, String fragmentShaderPath,
String[] uniformNames
)
{
this.name = name;
this.identifierName = "distanthorizons:"+this.name;
this.blendFunction = blendFunction;
this.vertexShaderPath = vertexShaderPath;
this.fragmentShaderPath = fragmentShaderPath;
this.uniformNames = uniformNames;
this.uniformBuffers = new GpuBuffer[this.uniformNames.length];
}
private void tryInit(
GpuTexture sourceColorTexture,
GpuTexture sourceDepthTexture,
GpuTexture destinationColorTexture)
{
// one-time setup
if (this.pipeline == null)
{
this.createPipeline();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData(this.name);
}
this.sourceColorTextureViewWrapper.tryWrap(sourceColorTexture);
this.sourceDepthTextureViewWrapper.tryWrap(sourceDepthTexture);
this.destinationColorTextureViewWrapper.tryWrap(destinationColorTexture);
}
private void createPipeline()
{
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
if (this.blendFunction != null)
{
pipelineBuilder.withBlend(this.blendFunction);
}
else
{
pipelineBuilder.withoutBlend();
}
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName(this.name);
pipelineBuilder.withVertexShader(this.vertexShaderPath);
pipelineBuilder.withFragmentShader(this.fragmentShaderPath);
for (int i = 0; i < this.uniformNames.length; i++)
{
String uniformName = this.uniformNames[i];
pipelineBuilder.withUniformBuffer(uniformName);
}
pipelineBuilder.withSampler("uSourceColorTexture");
pipelineBuilder.withSampler("uSourceDepthTexture");
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
}
//endregion
//========//
// render //
//========//
//region
public void setUniform(String uniformName, GpuBuffer uniformBuffer)
{
// the uniform array should be short enough (less than 10 items)
// where a sequential search should be plenty fast
for (int i = 0; i < this.uniformNames.length; i++)
{
String nameAtIndex = this.uniformNames[i];
if (nameAtIndex.equals(uniformName))
{
this.uniformBuffers[i] = uniformBuffer;
break;
}
}
}
public void render(
GpuTexture sourceColorTexture,
GpuTexture sourceDepthTexture,
GpuTexture destinationColorTexture)
{
this.tryInit(sourceColorTexture, sourceDepthTexture, destinationColorTexture);
this.dummyDepthTextureWrapper.tryCreateOrResize();
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getIdentifierName,
this.destinationColorTextureViewWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.dummyDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uSourceColorTexture", this.sourceColorTextureViewWrapper.textureView, this.sourceColorTextureViewWrapper.textureSampler);
renderPass.bindTexture("uSourceDepthTexture", this.sourceDepthTextureViewWrapper.textureView, this.sourceDepthTextureViewWrapper.textureSampler);
for (int i = 0; i < this.uniformNames.length; i++)
{
String uniformName = this.uniformNames[i];
GpuBuffer uniformBuffer = this.uniformBuffers[i];
if (uniformBuffer == null)
{
throw new IllegalStateException("Missing uniform ["+uniformName+"], please set the uniform before rendering.");
}
renderPass.setUniform(uniformName, uniformBuffer);
}
renderPass.setVertexBuffer(0, this.vboGpuBuffer);
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
// clear the uniforms after rendering
// so we can check if they're missing during next frame's rendering
if (ModInfo.IS_DEV_BUILD)
{
Arrays.fill(this.uniformBuffers, null);
}
}
//endregion
}
#endif
@@ -1,168 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.blaze.apply;
#if MC_VER <= MC_1_21_10
public class BlazeDhCopyRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Blindly copies one texture into another.
*
* @see BlazeDhApplyRenderer
*/
public class BlazeDhCopyRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhCopyRenderer INSTANCE = new BlazeDhCopyRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer vboGpuBuffer;
private BlazeTextureWrapper dummyDepthTextureWrapper;
//=============//
// constructor //
//=============//
//region
private BlazeDhCopyRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
this.dummyDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_copy_depth_texture");
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("copy");
pipelineBuilder.withVertexShader("copy/blaze/vert");
pipelineBuilder.withFragmentShader("copy/blaze/frag");
pipelineBuilder.withSampler("uCopyTexture");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McCopyRenderer");
}
//endregion
//========//
// render //
//========//
//region
public void render(
BlazeTextureWrapper sourceColorTextureWrapper,
BlazeTextureViewWrapper destinationColorTextureWrapper)
{
this.render(
sourceColorTextureWrapper.textureView, sourceColorTextureWrapper.textureSampler,
destinationColorTextureWrapper.textureView);
}
public void render(
BlazeTextureWrapper sourceColorTextureWrapper,
BlazeTextureWrapper destinationColorTextureWrapper)
{
this.render(
sourceColorTextureWrapper.textureView, sourceColorTextureWrapper.textureSampler,
destinationColorTextureWrapper.textureView);
}
private void render(
GpuTextureView sourceTextureView,
GpuSampler sourceTextureSampler,
GpuTextureView destinationTextureView)
{
this.tryInit();
this.dummyDepthTextureWrapper.tryCreateOrResize();
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
destinationTextureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.dummyDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uCopyTexture", sourceTextureView, sourceTextureSampler);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McCopyRenderer"; }
//endregion
}
#endif
@@ -1,299 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.objects;
#if MC_VER <= MC_1_21_10
public class BlazeGenericObjectVertexContainer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.ColorUtil;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
/**
* For use by {@link RenderableBoxGroup}
*
* @see RenderableBoxGroup
*/
public class BlazeGenericObjectVertexContainer implements IDhGenericObjectVertexBufferContainer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private static final int[] BOX_INDICES = {
//region
// min X, vertical face
2, 1, 0,
0, 3, 2,
// max X, vertical face
6, 5, 4,
4, 7, 6,
// min Z, vertical face
10, 9, 8,
8, 11, 10,
// max Z, vertical face
14, 13, 12,
12, 15, 14,
// min Y, horizontal face
18, 17, 16,
16, 19, 18,
// max Y, horizontal face
20, 21, 22,
22, 23, 20,
//endregion
};
public GpuBuffer vboGpuBuffer;
public GpuBuffer indexGpuBuffer;
private ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(0);
private ByteBuffer indexBuffer = ByteBuffer.allocateDirect(0);
public int uploadedBoxCount = 0;
private EState state = EState.NEW;
@Override
public IDhGenericObjectVertexBufferContainer.EState getState() { return this.state; }
@Override
public void setState(IDhGenericObjectVertexBufferContainer.EState state) { this.state = state; }
//===========================//
// render building/uploading //
//===========================//
//region
@Override
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
{
int boxCount = uploadBoxList.size();
// recreate the data arrays if their size is different
if (this.uploadedBoxCount != boxCount)
{
this.uploadedBoxCount = boxCount;
int vertexBufferSize = this.vertexBufferSize();
this.vertexBuffer = ByteBuffer.allocateDirect(vertexBufferSize);
this.vertexBuffer.order(ByteOrder.nativeOrder());
int indexBufferSize = this.indexBufferSize();
this.indexBuffer = ByteBuffer.allocateDirect(indexBufferSize);
this.indexBuffer.order(ByteOrder.nativeOrder());
}
this.vertexBuffer.position(0);
this.indexBuffer.position(0);
for (int boxIndex = 0; boxIndex < boxCount; boxIndex++)
{
// index
int indexOffset = (boxIndex * 24 /*24 is the number of vertices in a box*/);
for (int i = 0; i < BOX_INDICES.length; i++)
{
this.indexBuffer.putInt(BOX_INDICES[i] + indexOffset);
}
// vertex
DhApiRenderableBox box = uploadBoxList.get(boxIndex);
final double[] boxVertices =
{
//region
// Pos x y z
// min X, vertical face
box.minPos.x, box.minPos.y, box.minPos.z,
box.maxPos.x, box.minPos.y, box.minPos.z,
box.maxPos.x, box.maxPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.minPos.z,
// max X, vertical face
box.minPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.minPos.y, box.maxPos.z,
box.minPos.x, box.minPos.y, box.maxPos.z,
// min Z, vertical face
box.minPos.x, box.minPos.y, box.maxPos.z,
box.minPos.x, box.minPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.maxPos.z,
// max Z, vertical face
box.maxPos.x, box.minPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.minPos.z,
box.maxPos.x, box.minPos.y, box.minPos.z,
// min Y, horizontal face
box.minPos.x, box.minPos.y, box.maxPos.z,
box.maxPos.x, box.minPos.y, box.maxPos.z,
box.maxPos.x, box.minPos.y, box.minPos.z,
box.minPos.x, box.minPos.y, box.minPos.z,
// max Y, horizontal face
box.minPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.minPos.z,
//endregion
};
for (int vertexIndex = 0; vertexIndex < boxVertices.length; vertexIndex+=3)
{
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex]); // x
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+1]); // y
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+2]); // z
int color = ColorUtil.toColorInt(box.color);
byte r = (byte) ColorUtil.getRed(color);
byte g = (byte) ColorUtil.getGreen(color);
byte b = (byte) ColorUtil.getBlue(color);
byte a = (byte) ColorUtil.getAlpha(color);
this.vertexBuffer.put(r);
this.vertexBuffer.put(g);
this.vertexBuffer.put(b);
this.vertexBuffer.put(a);
this.vertexBuffer.put(box.material);
// padding so the vertex format's byte count is a multiple of 4
this.vertexBuffer.put((byte)0);
this.vertexBuffer.put((byte)0);
this.vertexBuffer.put((byte)0);
}
}
this.vertexBuffer.flip();
this.indexBuffer.flip();
}
private int vertexBufferSize()
{
// minimum of 1 box to prevent trying to create a buffer of size 0
int boxCount = Math.max(this.uploadedBoxCount, 1);
int faceCount = boxCount * 6; // 6 faces on a cube
int vertexCount = faceCount * 6; // 6 vertices per cube
int byteSize = vertexCount * 3 * Float.BYTES; // x,y,z
byteSize += vertexCount * 4; // r,g,b,a
byteSize += 1; // material
return byteSize;
}
private int indexBufferSize()
{
// minimum of 1 box to prevent trying to create a buffer of size 0
int boxCount = Math.max(this.uploadedBoxCount, 1);
int quadCount = boxCount * 6 * 6; // 6 faces with 6 vertices each
int byteSize = quadCount * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT);
return byteSize;
}
@Override
public void uploadDataToGpu()
{
// vertex
{
int totalVertexByteSize = this.vertexBufferSize();
if (this.vboGpuBuffer == null
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|| this.vboGpuBuffer.size() != totalVertexByteSize)
{
if (this.vboGpuBuffer != null)
{
this.vboGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getVertexBufferName, usage, totalVertexByteSize);
}
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, /*offset*/0, totalVertexByteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.vertexBuffer);
}
// index
{
int totalVertexByteSize = this.indexBufferSize();
if (this.indexGpuBuffer == null
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|| this.indexGpuBuffer.size() != totalVertexByteSize)
{
if (this.indexGpuBuffer != null)
{
this.indexGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_INDEX;
this.indexGpuBuffer = GPU_DEVICE.createBuffer(this::getIndexBufferName, usage, totalVertexByteSize);
}
int offset = 0;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, offset, totalVertexByteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.indexBuffer);
}
}
private String getVertexBufferName() { return "distantHorizons:GenericVertexBuffer"; }
private String getIndexBufferName() { return "distantHorizons:GenericIndexBuffer"; }
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("BlazeGenericObjectVertexContainer close", () ->
{
if (this.vboGpuBuffer != null)
{
this.vboGpuBuffer.close();
}
if (this.indexGpuBuffer != null)
{
this.indexGpuBuffer.close();
}
});
}
//endregion
}
#endif
@@ -1,237 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeDhFarFadeRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhCopyRenderer;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFarFadeRenderer;
import net.minecraft.client.Minecraft;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Fades out DH's far clip plane
*/
public class BlazeDhFarFadeRenderer implements IDhFarFadeRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhFarFadeRenderer INSTANCE = new BlazeDhFarFadeRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer vboGpuBuffer;
private final BlazeTextureWrapper dhFadeColorTextureWrapper = BlazeTextureWrapper.createColor("dh_far_fade_color_texture");
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper dhFadeDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_far_fade_depth_texture");
private final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
//=============//
// constructor //
//=============//
//region
private BlazeDhFarFadeRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("far_fade");
pipelineBuilder.withVertexShader("fade/blaze/vert");
pipelineBuilder.withFragmentShader("fade/blaze/dh_fade");
pipelineBuilder.withSampler("uMcColorTexture");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withSampler("uDhColorTexture");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFadeRenderer");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
// textures
this.dhFadeColorTextureWrapper.tryCreateOrResize();
this.mcColorTextureViewWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
this.dhFadeDepthTextureWrapper.tryCreateOrResize();
{
int uniformBufferSize = new Std140SizeCalculator()
.putFloat() // uStartFadeBlockDistance
.putFloat() // uEndFadeBlockDistance
.putMat4f() // uDhInvMvmProj
.get();
// create data //
float dhFarClipDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
float fadeStartDistance = dhFarClipDistance * 0.5f;
float fadeEndDistance = dhFarClipDistance * 0.9f;
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(renderParams.mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(renderParams.mcModelViewMatrix);
Mat4f inverseDhMvmProjMatrix = new Mat4f(dhProjectionMatrix);
inverseDhMvmProjMatrix.multiply(dhModelViewMatrix);
inverseDhMvmProjMatrix.invert();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
.putMat4f(inverseDhMvmProjMatrix.createJomlMatrix()) // uDhInvMvmProj
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
this.renderFadeToTexture();
BlazeDhCopyRenderer.INSTANCE.render(this.dhFadeColorTextureWrapper, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
}
private void renderFadeToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.dhFadeColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.dhFadeDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
// MC texture
renderPass.bindTexture("uMcColorTexture", this.mcColorTextureViewWrapper.textureView, this.mcColorTextureViewWrapper.textureSampler);
// DH textures
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureSampler);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McFadeRenderer"; }
//endregion
}
#endif
@@ -1,362 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeDhFogRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.SourceFactor;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogColorMode;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFogRenderer;
import java.awt.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Renders fog onto the LODs.
*/
public class BlazeDhFogRenderer implements IDhFogRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhFogRenderer INSTANCE = new BlazeDhFogRenderer();
private BlazeDhApplyRenderer applyRenderer;
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer vboGpuBuffer;
private final BlazeTextureWrapper fogColorTextureWrapper = BlazeTextureWrapper.createColor("dh_fog_color_texture");
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper fogDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_fog_depth_texture");
//=============//
// constructor //
//=============//
//region
private BlazeDhFogRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
this.applyRenderer = new BlazeDhApplyRenderer(
"fog_apply_to_dh",
new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA),
"apply/blaze/vert", "apply/blaze/frag"
);
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("fog_render");
pipelineBuilder.withVertexShader("fog/blaze/vert");
pipelineBuilder.withFragmentShader("fog/blaze/frag");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFogRenderer");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
this.fogColorTextureWrapper.tryCreateOrResize();
this.fogDepthTextureWrapper.tryCreateOrResize();
{
int uniformBufferSize = new Std140SizeCalculator()
// fog uniforms
.putVec4() // uFogColor
.putFloat() //uFogScale
.putFloat() //uFogVerticalScale
// only used for debugging
.putInt() //uFogDebugMode // 1 = render everything with fog color // 7 = use debug rendering
.putInt() //uFogFalloffType
// fog config
.putFloat() // uFarFogStart
.putFloat() // uFarFogLength
.putFloat() // uFarFogMin
.putFloat() // uFarFogRange
.putFloat() // uFarFogDensity
// height fog config
.putFloat() // uHeightFogStart
.putFloat() // uHeightFogLength
.putFloat() // uHeightFogMin
.putFloat() // uHeightFogRange
.putFloat() // uHeightFogDensity
// ??
.putInt() // uHeightFogEnabled
.putInt() // uHeightFogFalloffType
.putInt() // uHeightBasedOnCamera
.putFloat() // uHeightFogBaseHeight
.putInt() // uHeightFogAppliesUp
.putInt() // uHeightFogAppliesDown
.putInt() // uUseSphericalFog
.putInt() // uHeightFogMixingMode
.putFloat() // uCameraBlockYPos
.putMat4f() // uInvMvmProj
.get();
// create data //
int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH;
Mat4f inverseMvmProjMatrix = new Mat4f(renderParams.dhMvmProjMatrix);
inverseMvmProjMatrix.invert();
if (renderParams.dhMvmProjMatrix == null)
{
return;
}
Color fogColor = this.getFogColor(renderParams.partialTicks);
// fog config
float farFogStart = Config.Client.Advanced.Graphics.Fog.farFogStart.get();
float farFogEnd = Config.Client.Advanced.Graphics.Fog.farFogEnd.get();
float farFogMin = Config.Client.Advanced.Graphics.Fog.farFogMin.get();
float farFogMax = Config.Client.Advanced.Graphics.Fog.farFogMax.get();
float farFogDensity = Config.Client.Advanced.Graphics.Fog.farFogDensity.get();
// override fog if underwater
if (MC_RENDER.isFogStateSpecial())
{
// hide everything behind fog
farFogStart = 0.0f;
farFogEnd = 0.0f;
}
// height config
EDhApiHeightFogMixMode heightFogMixingMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get();
boolean heightFogEnabled = heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL && heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL;
EDhApiHeightFogDirection heightFogCameraDirection = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection.get();
float heightFogStart = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogStart.get();
float heightFogEnd = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get();
float heightFogMin = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get();
float heightFogMax = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get();
float heightFogDensity = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
// fog uniforms
.putVec4(
fogColor.getRed() / 255.0f,
fogColor.getGreen() / 255.0f,
fogColor.getBlue() / 255.0f,
fogColor.getAlpha() / 255.0f) // uFogColor
.putFloat(1.f / lodDrawDistance) //uFogScale
.putFloat(1.f / MC.getWrappedClientLevel().getMaxHeight()) //uFogVerticalScale
// only used for debugging
.putInt(0) //uFogDebugMode // 1 = render everything with fog color // 7 = use debug rendering
.putInt(Config.Client.Advanced.Graphics.Fog.farFogFalloff.get().value) //uFogFalloffType
// fog config
.putFloat(farFogStart) // uFarFogStart
.putFloat(farFogEnd - farFogStart) // uFarFogLength
.putFloat(farFogMin) // uFarFogMin
.putFloat(farFogMax - farFogMin) // uFarFogRange
.putFloat(farFogDensity) // uFarFogDensity
// height fog config
.putFloat(heightFogStart) // uHeightFogStart
.putFloat(heightFogEnd - heightFogStart) // uHeightFogLength
.putFloat(heightFogMin) // uHeightFogMin
.putFloat(heightFogMax - heightFogMin) // uHeightFogRange
.putFloat(heightFogDensity) // uHeightFogDensity
// ??
.putInt(heightFogEnabled ? 1 : 0) // uHeightFogEnabled
.putInt(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get().value) // uHeightFogFalloffType
.putInt(heightFogCameraDirection.basedOnCamera ? 1 : 0) // uHeightBasedOnCamera
.putFloat(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get()) // uHeightFogBaseHeight
.putInt(heightFogCameraDirection.fogAppliesUp ? 1 : 0) // uHeightFogAppliesUp
.putInt(heightFogCameraDirection.fogAppliesDown ? 1 : 0) // uHeightFogAppliesDown
.putInt(useSphericalFog ? 1 : 0) // uUseSphericalFog
.putInt(heightFogMixingMode.value) // uHeightFogMixingMode
.putFloat((float)MC_RENDER.getCameraExactPosition().y) // uCameraBlockYPos
.putMat4f(inverseMvmProjMatrix.createJomlMatrix()) // uInvMvmProj
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
this.renderFogToTexture();
this.applyRenderer.render(this.fogColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
}
private Color getFogColor(float partialTicks)
{
Color fogColor;
if (Config.Client.Advanced.Graphics.Fog.colorMode.get() == EDhApiFogColorMode.USE_SKY_COLOR)
{
fogColor = MC_RENDER.getSkyColor();
}
else
{
fogColor = MC_RENDER.getFogColor(partialTicks);
}
return fogColor;
}
private void renderFogToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.fogColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.fogDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McFogRenderer"; }
//endregion
}
#endif
@@ -1,283 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeDhSsaoRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.SourceFactor;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhSsaoRenderer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/** Renders SSAO to the DH LODs. */
public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhSsaoRenderer INSTANCE = new BlazeDhSsaoRenderer();
private BlazeDhApplyRenderer applyRenderer;
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer applyFragUniformBuffer;
private GpuBuffer vboGpuBuffer;
private final BlazeTextureWrapper ssaoColorTextureWrapper = BlazeTextureWrapper.createColor("dh_ssao_color_texture");
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper ssaoDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_ssao_depth_texture");
//=============//
// constructor //
//=============//
//region
private BlazeDhSsaoRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
this.applyRenderer = new BlazeDhApplyRenderer(
"ssao_apply_to_dh",
new BlendFunction(SourceFactor.ZERO, DestFactor.SRC_ALPHA, SourceFactor.ZERO, DestFactor.ONE),
"apply/blaze/vert", "ssao/blaze/apply",
/*uniforms*/ new String[] { "applyFragUniformBlock" }
);
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("ssao_render");
pipelineBuilder.withVertexShader("ssao/blaze/vert");
pipelineBuilder.withFragmentShader("ssao/blaze/frag");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McSsao");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
// textures
this.ssaoColorTextureWrapper.tryCreateOrResize();
this.ssaoDepthTextureWrapper.tryCreateOrResize();
// frag uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uSampleCount\
.putFloat() // uRadius
.putFloat() // uStrength
.putFloat() // uMinLight
.putFloat() // uBias
.putFloat() // uFadeDistanceInBlocks
.putMat4f() // uInvProj
.putMat4f() // uProj
.get();
// create data //
Mat4f projMatrix = new Mat4f(renderParams.dhProjectionMatrix);
Mat4f invertedProjMatrix = new Mat4f(renderParams.dhProjectionMatrix);
invertedProjMatrix.invert();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putInt(6) // uSampleCount
.putFloat(4.0f) // uRadius
.putFloat(0.2f) // uStrength
.putFloat(0.25f) // uMinLight
.putFloat(0.02f) // uBias
.putFloat(1_600.0f) // uFadeDistanceInBlocks
.putMat4f(invertedProjMatrix.createJomlMatrix())
.putMat4f(projMatrix.createJomlMatrix())
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
// apply frag uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putVec2() // uViewSize
.putInt() // uBlurRadius
.putFloat() // uNearClipPlane
.putFloat() // uFarClipPlane
.get();
// create data //
float viewWidth = (float)MC_RENDER.getTargetFramebufferViewportWidth();
float viewHeight = (float)MC_RENDER.getTargetFramebufferViewportHeight();
float nearClipPlane = RenderUtil.getNearClipPlaneInBlocks();
float farClipPlane = RenderUtil.getFarClipPlaneDistanceInBlocks();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putVec2(viewWidth, viewHeight) // uViewSize
.putInt(2) // uBlurRadius
.putFloat(nearClipPlane) // uNearClipPlane
.putFloat(farClipPlane) // uFarClipPlane
.get()
;
this.applyFragUniformBuffer = BlazeUniformUtil.createBuffer("applyFragUniformBlock", uniformBufferSize, this.applyFragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.applyFragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
this.renderSsaoToTexture();
this.applyRenderer.setUniform("applyFragUniformBlock", this.applyFragUniformBuffer);
this.applyRenderer.render(this.ssaoColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
}
private void renderSsaoToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.ssaoColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.ssaoDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McSsaoRenderer"; }
//endregion
}
#endif
@@ -1,267 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeVanillaFadeRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhCopyRenderer;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhVanillaFadeRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.Identifier;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Fades the vanilla chunks
* into DH's LODs.
*/
public class BlazeVanillaFadeRenderer implements IDhVanillaFadeRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeVanillaFadeRenderer INSTANCE = new BlazeVanillaFadeRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer vboGpuBuffer;
public final BlazeTextureWrapper fadeColorTextureWrapper = BlazeTextureWrapper.createColor("DhVanillaFadeColorTexture");
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
private final BlazeTextureWrapper fadeDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhVanillaFadeDepthTexture");
public final BlazeTextureViewWrapper mcDepthTextureWrapper = new BlazeTextureViewWrapper();
public final BlazeTextureViewWrapper mcColorTextureWrapper = new BlazeTextureViewWrapper();
//=============//
// constructor //
//=============//
//region
private BlazeVanillaFadeRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
pipelineBuilder.withName("vanilla_fade");
pipelineBuilder.withVertexShader("fade/blaze/vert");
pipelineBuilder.withFragmentShader("fade/blaze/vanilla_fade");
pipelineBuilder.withSampler("uMcDepthTexture");
pipelineBuilder.withSampler("uCombinedMcDhColorTexture");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withSampler("uDhColorTexture");
pipelineBuilder.withUniformBuffer("fragUniformBlock");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFadeRenderer");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
// textures
this.fadeColorTextureWrapper.tryCreateOrResize();
this.fadeDepthTextureWrapper.tryCreateOrResize();
this.mcDepthTextureWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getDepthTexture());
this.mcColorTextureWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
{
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uOnlyRenderLods
.putFloat() // uStartFadeBlockDistance
.putFloat() // uEndFadeBlockDistance
.putFloat() // uMaxLevelHeight
.putMat4f() // uDhInvMvmProj
.putMat4f() // uMcInvMvmProj
.get();
// create data //
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
// measured in blocks
// these multipliers in James' tests should provide a fairly smooth transition
// without having underdraw issues
float fadeStartDistance = dhNearClipDistance * 1.5f;
float fadeEndDistance = dhNearClipDistance * 1.9f;
Mat4f inverseMcModelViewProjectionMatrix = new Mat4f(renderParams.mcProjectionMatrix);
inverseMcModelViewProjectionMatrix.multiply(renderParams.mcModelViewMatrix);
inverseMcModelViewProjectionMatrix.invert();
Mat4f inverseMcMvmProjMatrix = inverseMcModelViewProjectionMatrix;
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(renderParams.mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(renderParams.mcModelViewMatrix);
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
inverseDhModelViewProjectionMatrix.invert();
Mat4f inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putInt(Config.Client.Advanced.Debugging.lodOnlyMode.get() ? 1 : 0) // uOnlyRenderLods
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
.putFloat(renderParams.clientLevelWrapper.getMaxHeight()) // uMaxLevelHeight
.putMat4f(inverseDhMvmProjMatrix.createJomlMatrix()) // uDhInvMvmProj
.putMat4f(inverseMcMvmProjMatrix.createJomlMatrix()) // uMcInvMvmProj
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
this.renderFadeToTexture();
BlazeDhCopyRenderer.INSTANCE.render(this.fadeColorTextureWrapper, this.mcColorTextureWrapper);
}
private void renderFadeToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.fadeColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.fadeDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uMcDepthTexture", this.mcDepthTextureWrapper.textureView, this.mcDepthTextureWrapper.textureSampler);
renderPass.bindTexture("uCombinedMcDhColorTexture", this.mcColorTextureWrapper.textureView, this.mcColorTextureWrapper.textureSampler);
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureSampler);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McFadeRenderer"; }
//endregion
}
#endif
@@ -1,189 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.blaze.test;
#if MC_VER <= MC_1_21_10
public class BlazeDhTestTriangleRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTestTriangleRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.Identifier;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
#if MC_VER <= MC_1_21_11
#else
import com.mojang.blaze3d.pipeline.DepthStencilState;
import com.mojang.blaze3d.platform.CompareOp;
#endif
/**
* Renders the OpenGL/Vulkan triangle
* to the center of the screen to confirm DH's
* apply shader is running correctly
*/
public class BlazeDhTestTriangleRenderer implements IDhTestTriangleRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhTestTriangleRenderer INSTANCE = new BlazeDhTestTriangleRenderer();
private RenderPipeline pipeline;
private boolean init = false;
public final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
public final BlazeTextureViewWrapper mcDepthTextureViewWrapper = new BlazeTextureViewWrapper();
private GpuBuffer vboGpuBuffer;
//=============//
// constructor //
//=============//
//region
private BlazeDhTestTriangleRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
{
pipelineBuilder.withFaceCulling(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withName("triangle_test");
pipelineBuilder.withVertexShader("test/blaze/vert");
pipelineBuilder.withFragmentShader("test/blaze/frag");
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.add("vColor", BlazeDhVertexFormatUtil.RGBA_FLOAT_COLOR)
.build();
pipelineBuilder.withVertexFormat(vertexFormat);
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
}
this.pipeline = pipelineBuilder.build();
this.uploadVertexData();
}
private void uploadVertexData()
{
// vertices for the OpenGL/Vulkan Triangle
float[] vertices = new float[]
{
// PosX,Y, ColorR,G,B,A
-0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
};
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = vertices.length * Float.BYTES;
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getRenderPassName, usage, size);
{
int offset = 0;
int length = vertices.length * Float.BYTES;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, offset, length);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES);
// Fill buffer with vertices.
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.asFloatBuffer().put(vertices);
byteBuffer.rewind();
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
}
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
this.mcColorTextureViewWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
this.mcDepthTextureViewWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getDepthTexture());
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.mcColorTextureViewWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
this.mcDepthTextureViewWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.setVertexBuffer(0, this.vboGpuBuffer);
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 3);
}
}
private String getRenderPassName() { return "distantHorizons:DhTestRenderer"; }
//endregion
}
#endif
@@ -1,122 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.util;
#if MC_VER <= MC_1_21_10
public class BlazeDhVertexFormatUtil {}
#else
import com.mojang.blaze3d.vertex.VertexFormatElement;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import org.jetbrains.annotations.NotNull;
/**
* @see LodQuadBuilder
*/
@SuppressWarnings("DataFlowIssue") // ignore null setter warnings in the static constructor (those will only be null if the render API is GL and in that case we should never use these objects)
public class BlazeDhVertexFormatUtil
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@NotNull public static final VertexFormatElement SCREEN_POS;
@NotNull public static final VertexFormatElement RGBA_FLOAT_COLOR;
@NotNull public static final VertexFormatElement SHORT_XYZ_POS;
@NotNull public static final VertexFormatElement BYTE_PAD;
/** contains light and micro-offset */
@NotNull public static final VertexFormatElement META;
@NotNull public static final VertexFormatElement RGBA_UBYTE_COLOR;
@NotNull public static final VertexFormatElement IRIS_MATERIAL;
@NotNull public static final VertexFormatElement IRIS_NORMAL;
@NotNull public static final VertexFormatElement FLOAT_XYZ_POS;
static
{
EDhApiRenderApi renderingApi = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
if (renderingApi == EDhApiRenderApi.AUTO)
{
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
renderingApi = versionConstants.getDefaultRenderingApi();
}
boolean register = (renderingApi == EDhApiRenderApi.BLAZE_3D);
if (register)
{
LOGGER.debug("Attempting to register ["+VertexFormatElement.class.getSimpleName()+"]...");
try
{
#if MC_VER <= MC_1_21_11
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 2);
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.COLOR, /*count*/ 4);
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
META = VertexFormatElement.register(/*id*/26, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, VertexFormatElement.Type.UBYTE, VertexFormatElement.Usage.COLOR, /*count*/ 4);
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
#else
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 2);
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 4);
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, VertexFormatElement.Type.USHORT, false, /*count*/ 3);
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
META = VertexFormatElement.register(/*id*/26, /*index*/0, VertexFormatElement.Type.USHORT, false, /*count*/ 1);
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, VertexFormatElement.Type.UBYTE, true, /*count*/ 4);
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 3);
#endif
}
catch (Exception e)
{
String message = "Unable to register one or more ["+VertexFormatElement.class.getSimpleName()+"] this is likely caused by another mod registering their own custom ["+VertexFormatElement.class.getSimpleName()+"]'s. This should be fixed in the next major Minecraft version.";
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
mc.crashMinecraft(message, new Exception(message, e));
// here to make the compiler happy, the process should shut down before this
throw new RuntimeException(e);
}
LOGGER.debug("Successfully registered ["+VertexFormatElement.class.getSimpleName()+"].");
}
else
{
// set to null so we can fail fast with a null pointer if we ever attempt to incorrectly use these
SCREEN_POS = null;
RGBA_FLOAT_COLOR = null;
SHORT_XYZ_POS = null;
BYTE_PAD = null;
META = null;
RGBA_UBYTE_COLOR = null;
IRIS_MATERIAL = null;
IRIS_NORMAL = null;
FLOAT_XYZ_POS = null;
}
}
}
#endif
@@ -1,81 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.util;
#if MC_VER <= MC_1_21_10
public class BlazePostProcessUtil {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.function.Supplier;
/** Contains code that's used by all post-processing effects. */
public class BlazePostProcessUtil
{
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
// vertices for a full-screen quad
private static final float[] VERTICES = new float[]
{
// PosX,Y,
-1f, -1f,
1f, -1f,
1f, 1f,
-1f, 1f,
};
//=========//
// methods //
//=========//
//region
public static GpuBuffer createAndUploadScreenVertexData(String name)
{
Supplier<String> labelSupplier = () -> "distantHorizons:"+name;
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = VERTICES.length * Float.BYTES;
GpuBuffer vboGpuBuffer = GPU_DEVICE.createBuffer(labelSupplier, usage, size);
{
int length = VERTICES.length * Float.BYTES;
GpuBufferSlice bufferSlice = new GpuBufferSlice(vboGpuBuffer, /*offset*/ 0, length);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(VERTICES.length * Float.BYTES);
// Fill buffer with vertices.
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.asFloatBuffer().put(VERTICES);
byteBuffer.rewind();
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
}
return vboGpuBuffer;
}
public static VertexFormat createVertexFormat()
{
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.build();
return vertexFormat;
}
//endregion
}
#endif
@@ -1,46 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.util;
#if MC_VER <= MC_1_21_10
public class BlazeUniformUtil {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
public class BlazeUniformUtil
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static GpuBuffer createBuffer(String uniformName, int size, GpuBuffer vboGpuBuffer)
{
// create VBO if needed
if (vboGpuBuffer == null
|| vboGpuBuffer.size() < size)
{
if (vboGpuBuffer != null)
{
vboGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_UNIFORM;
vboGpuBuffer = GPU_DEVICE.createBuffer(() -> uniformName, usage, size);
}
return vboGpuBuffer;
}
}
#endif
@@ -1,351 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.ColorTargetState;
import com.mojang.blaze3d.pipeline.DepthStencilState;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.CompareOp;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.resources.Identifier;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
public class RenderPipelineBuilderWrapper
{
public static final String NAME_PREFIX = "distanthorizons:";
private static final String SHADER_RESOURCE_FOLDER = "assets/distanthorizons/shaders/";
private static final ClassLoader CLASS_LOADER = RenderPipelineBuilderWrapper.class.getClassLoader();
private final RenderPipeline.Builder blazePipelineBuilder;
// variables for specific builder options should be put next to their builder methods for simpler organization
//=============//
// constructor //
//=============//
//region
public RenderPipelineBuilderWrapper()
{
this.blazePipelineBuilder = RenderPipeline.builder();
}
//endregion
//==========//
// building //
//==========//
//region
private boolean writeDepth = false;
public RenderPipelineBuilderWrapper withDepthWrite(boolean write)
{
this.writeDepth = write;
return this;
}
private boolean writeColor = false;
public RenderPipelineBuilderWrapper withColorWrite(boolean write)
{
this.writeColor = write;
return this;
}
private BlendFunction blendFunction = null;
public RenderPipelineBuilderWrapper withBlend(BlendFunction blendFunction)
{
this.blendFunction = blendFunction;
return this;
}
public RenderPipelineBuilderWrapper withoutBlend()
{
this.blendFunction = null;
return this;
}
private EDhDepthTest depthTest;
public RenderPipelineBuilderWrapper withDepthTest(EDhDepthTest depthTest)
{
this.depthTest = depthTest;
return this;
}
public RenderPipelineBuilderWrapper withFaceCulling(boolean culling)
{
this.blazePipelineBuilder.withCull(culling);
return this;
}
public RenderPipelineBuilderWrapper withPolygonMode(EDhPolygonMode dhMode)
{
PolygonMode blazeMode;
switch (dhMode)
{
case FILL:
blazeMode = PolygonMode.FILL;
break;
case WIREFRAME:
blazeMode = PolygonMode.WIREFRAME;
break;
default:
throw new UnsupportedOperationException("No polygonMode defined for type ["+dhMode+"].");
}
this.blazePipelineBuilder.withPolygonMode(blazeMode);
return this;
}
public RenderPipelineBuilderWrapper withName(String name) throws IllegalArgumentException
{
// Identifiers must be of a specific format
if (!isValidIdentifier(name))
{
throw new IllegalArgumentException("Non [a-z0-9/._-] character in name: ["+name+"].");
}
this.blazePipelineBuilder.withLocation(Identifier.parse(NAME_PREFIX + name));
return this;
}
public RenderPipelineBuilderWrapper withSampler(String name) throws IllegalArgumentException
{
this.blazePipelineBuilder.withSampler(name);
return this;
}
public RenderPipelineBuilderWrapper withUniformBuffer(String name) throws IllegalArgumentException
{
this.blazePipelineBuilder.withUniform(name, UniformType.UNIFORM_BUFFER);
return this;
}
private VertexFormat vertexFormat = null;
public RenderPipelineBuilderWrapper withVertexFormat(VertexFormat vertexFormat)
{
this.vertexFormat = vertexFormat;
return this;
}
private EDhVertexMode vertexMode = null;
public RenderPipelineBuilderWrapper withVertexMode(EDhVertexMode vertexMode)
{
this.vertexMode = vertexMode;
return this;
}
public RenderPipelineBuilderWrapper withVertexShader(String scriptResourcePath) { return this.withShader(EDhShaderType.VERTEX, scriptResourcePath); }
public RenderPipelineBuilderWrapper withFragmentShader(String scriptResourcePath) { return this.withShader(EDhShaderType.FRAGMENT, scriptResourcePath); }
private RenderPipelineBuilderWrapper withShader(EDhShaderType shaderType, String scriptResourcePath)
{
String fullShaderResourcePath = SHADER_RESOURCE_FOLDER + scriptResourcePath + shaderType.fileExtension;
// confirm the shader file exists
try (InputStream scriptListInputStream = CLASS_LOADER.getResourceAsStream(fullShaderResourcePath))
{
if (scriptListInputStream == null)
{
throw new NullPointerException("Failed to find the SQL Script list file [" + fullShaderResourcePath + "], no auto update scripts can be run.");
}
}
catch (IOException e)
{
// shouldn't happen, but just in case
throw new RuntimeException("Unexpected issue closing resource stream for shader type: ["+shaderType+"] at: ["+fullShaderResourcePath+"], error: ["+e.getMessage()+"].", e);
}
if (shaderType == EDhShaderType.VERTEX)
{
this.blazePipelineBuilder.withVertexShader(Identifier.parse(NAME_PREFIX + scriptResourcePath));
}
else
{
this.blazePipelineBuilder.withFragmentShader(Identifier.parse(NAME_PREFIX + scriptResourcePath));
}
return this;
}
//endregion
//=====//
// end //
//=====//
//region
public RenderPipeline build() throws UnsupportedOperationException
{
// depth/color
{
#if MC_VER <= MC_1_21_11
this.blazePipelineBuilder.withDepthWrite(this.writeDepth);
this.blazePipelineBuilder.withColorWrite(this.writeColor);
if (this.blendFunction != null)
{
this.blazePipelineBuilder.withBlend(this.blendFunction);
}
else
{
this.blazePipelineBuilder.withoutBlend();
}
switch (this.depthTest)
{
case NONE:
break;
case LESS:
break;
}
this.blazepipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
#else
CompareOp compareOp;
switch (this.depthTest)
{
case NONE:
compareOp = CompareOp.ALWAYS_PASS;
break;
case LESS:
compareOp = CompareOp.LESS_THAN;
break;
default:
throw new UnsupportedOperationException("No depth test defined for type ["+this.depthTest+"].");
}
this.blazePipelineBuilder.withDepthStencilState(new DepthStencilState(compareOp, this.writeDepth));
this.blazePipelineBuilder.withColorTargetState(
new ColorTargetState(
Optional.ofNullable(this.blendFunction),
this.writeColor ? ColorTargetState.WRITE_ALL : ColorTargetState.WRITE_NONE
)
);
#endif
}
// vertex format
{
VertexFormat.Mode blazeVertexMode;
switch (this.vertexMode)
{
case TRIANGLES:
blazeVertexMode = VertexFormat.Mode.TRIANGLES;
break;
case TRIANGLE_FAN:
blazeVertexMode = VertexFormat.Mode.TRIANGLE_FAN;
break;
case LINES:
blazeVertexMode = VertexFormat.Mode.DEBUG_LINES;
break;
default:
throw new UnsupportedOperationException("No vertex mode defined for type ["+this.vertexMode+"].");
}
this.blazePipelineBuilder.withVertexFormat(vertexFormat, blazeVertexMode);
}
return this.blazePipelineBuilder.build();
}
//endregion
//================//
// helper methods //
//================//
//region
private static boolean isValidIdentifier(String identifier)
{
for (int i = 0; i < identifier.length(); i++)
{
char ch = identifier.charAt(i);
if (!isValidNamespaceChar(ch))
{
return false;
}
}
return true;
}
private static boolean isValidNamespaceChar(final char ch)
{
return ch == '_'
|| ch == '-'
// only lower case characters
|| (ch >= 'a' && ch <= 'z')
|| (ch >= '0' && ch <= '9')
|| ch == '.';
}
//endregion
//================//
// helper classes //
//================//
//region
public enum EDhPolygonMode
{
FILL,
WIREFRAME;
}
public enum EDhVertexMode
{
TRIANGLES,
TRIANGLE_FAN,
LINES;
}
public enum EDhDepthTest
{
NONE,
LESS;
}
private enum EDhShaderType
{
FRAGMENT(".fsh"),
VERTEX(".vsh");
public final String fileExtension;
EDhShaderType(String fileExtension)
{
this.fileExtension = fileExtension;
}
}
//endregion
}
@@ -1,219 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.buffer;
#if MC_VER <= MC_1_21_10
public class BlazeVertexBufferWrapper {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;
public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final AbstractDhRenderApiDefinition RENDER_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private static final AtomicInteger BUFFER_COUNT_REF = new AtomicInteger(0);
public final String name;
public String getName() { return this.name; }
public GpuBuffer vertexGpuBuffer = null;
public int vertexCount = -1;
public int indexCount = -1;
public boolean uploaded = false;
private GpuBuffer indexGpuBuffer = null;
private static GpuBuffer GLOBAL_INDEX_GPU_BUFFER = null;
public GpuBuffer getIndexGpuBuffer()
{
if (RENDER_DEF.useSingleIbo())
{
return GLOBAL_INDEX_GPU_BUFFER;
}
else
{
return this.indexGpuBuffer;
}
}
//=============//
// constructor //
//=============//
//region
static
{
if (RENDER_DEF.useSingleIbo())
{
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Global IBO Creation", () ->
{
int maxSize = LodQuadBuilder.getMaxBufferByteSize();
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
int maxQuadCount = (maxVertexCount / 4);
ByteBuffer indexBuffer = IndexBufferBuilder.createBuffer(maxQuadCount);
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_INDEX;
GLOBAL_INDEX_GPU_BUFFER = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
GpuBufferSlice bufferSlice = new GpuBufferSlice(GLOBAL_INDEX_GPU_BUFFER, /*offset*/ 0, indexBuffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
MemoryUtil.memFree(indexBuffer);
});
}
}
public BlazeVertexBufferWrapper(String name) { this.name = name; }
//endregion
//========//
// upload //
//========//
//region
@Override
public void uploadVertexBuffer(ByteBuffer vertexBuffer, int vertexCount)
{
int oldVertexCount = this.vertexCount;
this.vertexCount = vertexCount;
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
this.indexCount = (int)(vertexCount * 1.5);
this.uploaded = true;
if (this.vertexGpuBuffer == null
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|| oldVertexCount != vertexCount)
{
if (this.vertexGpuBuffer == null)
{
BUFFER_COUNT_REF.incrementAndGet();
//LOGGER.info("Create, count: ["+BUFFER_COUNT_REF.get()+"]");
}
if (this.vertexGpuBuffer != null)
{
this.vertexGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int byteSize = (vertexBuffer.limit() - vertexBuffer.position());
this.vertexGpuBuffer = GPU_DEVICE.createBuffer(this::getName, usage, byteSize);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertexGpuBuffer, /*offset*/0, byteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, vertexBuffer);
}
}
@Override
public void uploadIndexBuffer(ByteBuffer buffer, int vertexCount)
{
int oldIndexCount = this.indexCount;
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
this.indexCount = (int)(vertexCount * 1.5);
if (RENDER_DEF.useSingleIbo())
{
// ignore index uploading when running a single IBO
return;
}
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
if (this.indexGpuBuffer == null
|| oldIndexCount != this.indexCount)
{
if (this.indexGpuBuffer == null)
{
BUFFER_COUNT_REF.incrementAndGet();
}
if (this.indexGpuBuffer != null)
{
this.indexGpuBuffer.close();
}
ByteBuffer indexBuffer = IndexBufferBuilder.createBuffer(this.vertexCount);
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_INDEX;
this.indexGpuBuffer = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, /*offset*/ 0, indexBuffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
MemoryUtil.memFree(indexBuffer);
}
}
private static String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
if (this.vertexGpuBuffer != null)
{
BUFFER_COUNT_REF.decrementAndGet();
this.vertexGpuBuffer.close();
}
if (this.indexGpuBuffer != null)
{
BUFFER_COUNT_REF.decrementAndGet();
this.indexGpuBuffer.close();
}
//LOGGER.info("Close, count: ["+BUFFER_COUNT_REF.get()+"]");
}
//endregion
}
#endif
@@ -1,72 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
#if MC_VER <= MC_1_21_10
public class BlazeTextureViewWrapper {}
#else
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import java.util.OptionalDouble;
public class BlazeTextureViewWrapper
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public GpuTextureView textureView = null;
public GpuSampler textureSampler = null;
//=======//
// setup //
//=======//
//region
/** does nothing if the texture is already wrapped */
public void tryWrap(GpuTexture texture)
{
this.tryRecreateTextureView(texture);
this.tryCreateSampler();
}
private void tryRecreateTextureView(GpuTexture texture)
{
if (this.textureView == null
|| this.textureView.texture() != texture)
{
if (this.textureView != null)
{
this.textureView.close();
}
this.textureView = GPU_DEVICE.createTextureView(texture);
}
}
private void tryCreateSampler()
{
if (this.textureSampler == null)
{
this.textureSampler = GPU_DEVICE.createSampler(
AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V
FilterMode.LINEAR, FilterMode.LINEAR, // minFilter, magFilter
1, // maxAnisotropy
OptionalDouble.empty() // maxLod
);
}
}
//endregion
}
#endif
@@ -1,167 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
#if MC_VER <= MC_1_21_10
public class BlazeTextureWrapper {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import java.util.OptionalDouble;
public class BlazeTextureWrapper
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public final String name;
public final TextureFormat textureFormat;
public GpuTexture texture = null;
public GpuTextureView textureView = null;
public GpuSampler textureSampler = null;
private int width = -1;
private int height = -1;
//==============//
// constructors //
//==============//
//region
public static BlazeTextureWrapper createDepth(String name) { return new BlazeTextureWrapper(name, TextureFormat.DEPTH32); }
public static BlazeTextureWrapper createColor(String name) { return new BlazeTextureWrapper(name, TextureFormat.RGBA8); }
private BlazeTextureWrapper(String name, TextureFormat textureFormat)
{
this.name = name;
this.textureFormat = textureFormat;
}
//endregion
//=========//
// getters //
//=========//
//region
public boolean isEmpty() { return this.texture == null; }
/** @return -1 if the texture is null */
public int getWidth() { return this.width; }
/** @return -1 if the texture is null */
public int getHeight() { return this.height; }
//endregion
//=======//
// setup //
//=======//
//region
/** does nothing if the texture is already created and the correct size */
public void tryCreateOrResize()
{
this.tryCreateTexture();
this.tryCreateSampler();
}
private void tryCreateTexture()
{
int viewWidth = MC_RENDER.getTargetFramebufferViewportWidth();
int viewHeight = MC_RENDER.getTargetFramebufferViewportHeight();
if (this.texture == null
|| this.width != viewWidth
|| this.height != viewHeight)
{
if (this.texture != null)
{
this.texture.close();
this.textureView.close();
}
this.width = viewWidth;
this.height = viewHeight;
int usage = GpuTexture.USAGE_COPY_DST
| GpuTexture.USAGE_TEXTURE_BINDING
| GpuTexture.USAGE_COPY_SRC
| GpuTexture.USAGE_RENDER_ATTACHMENT;
this.texture = GPU_DEVICE.createTexture(this.name,
usage,
this.textureFormat,
viewWidth, viewHeight,
/*depthOrLayers*/ 1, /*mipLevels*/ 1
);
this.textureView = GPU_DEVICE.createTextureView(this.texture);
}
}
private void tryCreateSampler()
{
if (this.textureSampler == null)
{
this.textureSampler = GPU_DEVICE.createSampler(
AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V
FilterMode.LINEAR, FilterMode.LINEAR, // minFilter, magFilter
1, // maxAnisotropy
OptionalDouble.empty() // maxLod
);
}
}
//endregion
//==========//
// clearing //
//==========//
//region
/**
* Will throw an exception if not a color texture.
* @see ColorUtil#argbToInt
*/
public void clearColor(int clearArgbColor)
{
if (this.texture != null)
{
COMMAND_ENCODER.clearColorTexture(this.texture, clearArgbColor);
}
}
/** Will throw an exception if not a depth texture. */
public void clearDepth(float depth)
{
if (this.texture != null)
{
COMMAND_ENCODER.clearDepthTexture(this.texture, depth);
}
}
//endregion
}
#endif
@@ -1,78 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.uniform;
#if MC_VER <= MC_1_21_10
public class BlazeLodUniformBufferWrapper {}
#else
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
import java.nio.ByteBuffer;
public class BlazeLodUniformBufferWrapper extends BlazeUniformBufferWrapper implements ILodContainerUniformBufferWrapper
{
private boolean uploaded = false;
//=============//
// constructor //
//=============//
//region
public BlazeLodUniformBufferWrapper() { super(BlazeLodUniformBufferWrapper.class.getName()); }
//endregion
//========//
// upload //
//========//
//region
@Override
public void createUniformData(LodBufferContainer bufferContainer)
{
Vec3f modelOffset = new Vec3f(
(float) (bufferContainer.minCornerBlockPos.getX()),
(float) (bufferContainer.minCornerBlockPos.getY()),
(float) (bufferContainer.minCornerBlockPos.getZ()));
// upload data //
int uniformBufferSize = new Std140SizeCalculator()
.putVec3() // uModelOffset
.get();
ByteBuffer buffer = this.getOrCreateBuffer(uniformBufferSize);
Std140Builder.intoBuffer(buffer)
.putVec3(modelOffset.x, modelOffset.y, modelOffset.z) // uModelOffset
.get();
}
@Override
public void tryUpload()
{
if (this.uploaded)
{
return;
}
this.upload();
this.uploaded = true;
}
//endregion
}
#endif
@@ -1,130 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.uniform;
#if MC_VER <= MC_1_21_10
public class BlazeUniformBufferWrapper {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IUniformBufferWrapper;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class BlazeUniformBufferWrapper implements IUniformBufferWrapper
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private final String name;
private int cpuBufferSize = 0;
private int gpuBufferSize = 0;
private ByteBuffer cpuBuffer = null;
public GpuBuffer gpuBuffer = null;
//=============//
// constructor //
//=============//
//region
public BlazeUniformBufferWrapper(String name) { this.name = name; }
//endregion
//========//
// render //
//========//
//region
protected ByteBuffer getOrCreateBuffer(int size)
{
if (this.cpuBuffer == null
|| this.cpuBufferSize != size)
{
this.cpuBuffer = ByteBuffer.allocateDirect(size);
this.cpuBuffer.order(ByteOrder.nativeOrder());
this.cpuBufferSize = size;
}
return this.cpuBuffer;
}
@Override
public void upload() throws IllegalStateException
{
if (this.cpuBuffer == null)
{
throw new IllegalStateException("Upload called before buffer was created");
}
if (this.gpuBuffer == null
|| this.gpuBufferSize != this.cpuBufferSize)
{
if (this.gpuBuffer != null)
{
this.gpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_UNIFORM;
this.gpuBuffer = GPU_DEVICE.createBuffer(this::getBufferName, usage, this.cpuBufferSize);
this.gpuBufferSize = this.cpuBufferSize;
}
int byteSize = (this.cpuBuffer.limit() - this.cpuBuffer.position());
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.gpuBuffer, /*offset*/0, byteSize);
if (!bufferSlice.buffer().isClosed())
{
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.cpuBuffer);
}
else
{
LOGGER.warn("Uploading to buffer ["+this.name+"] failed due to already being closed");
}
}
private String getBufferName() { return this.name; }
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
if (this.gpuBuffer != null)
{
this.gpuBuffer.close();
}
}
//endregion
}
#endif
@@ -1,197 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLIndexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Handles rendering the wireframe particles
* that are used for seeing what the system's doing.
*/
public class GlDhDebugWireframeRenderer extends AbstractDebugWireframeRenderer
{
public static GlDhDebugWireframeRenderer INSTANCE = new GlDhDebugWireframeRenderer();
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
// rendering setup
private GlShaderProgram basicShader;
private GLVertexBuffer vertexBuffer;
private GLIndexBuffer indexBuffer;
private GlAbstractVertexAttribute va;
private boolean init = false;
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
//region
// Pos x y z
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1,
//endregion
};
private static final int[] BOX_OUTLINE_INDICES = {
//region
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
//endregion
};
//=============//
// constructor //
//=============//
//region
private GlDhDebugWireframeRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.va = GlAbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.basicShader = new GlShaderProgram(
"assets/distanthorizons/shaders/debug/gl/vert.vert",
"assets/distanthorizons/shaders/debug/gl/frag.frag",
"vPosition"
);
this.createBuffer();
}
private void createBuffer()
{
// box vertices
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.order(ByteOrder.nativeOrder());
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
this.vertexBuffer = new GLVertexBuffer(false);
this.vertexBuffer.bind();
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
// outline vertex indexes
ByteBuffer boxOutlineBuffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
boxOutlineBuffer.order(ByteOrder.nativeOrder());
boxOutlineBuffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
boxOutlineBuffer.rewind();
this.indexBuffer = new GLIndexBuffer(false);
this.indexBuffer.uploadBuffer(boxOutlineBuffer, EDhApiGpuUploadMethod.DATA, BOX_OUTLINE_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
}
//endregion
//===========//
// rendering //
//===========//
//region
@Override
public void render(RenderParams renderParams)
{
this.init();
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
GLMC.enableDepthTest();
this.basicShader.bind();
this.va.bind();
this.va.bindBufferToAllBindingPoints(this.vertexBuffer.getId());
this.indexBuffer.bind();
super.render(renderParams);
// revert to prevent issues with the following passes
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
}
@Override
public void renderBox(Box box)
{
Mat4f boxTransform = Mat4f.createTranslateMatrix(box.minPos.x - this.camPosFloatThisFrame.x, box.minPos.y - this.camPosFloatThisFrame.y, box.minPos.z - this.camPosFloatThisFrame.z);
boxTransform.multiply(Mat4f.createScaleMatrix(box.maxPos.x - box.minPos.x, box.maxPos.y - box.minPos.y, box.maxPos.z - box.minPos.z));
Mat4f transformMatrix = this.dhMvmProjMatrixThisFrame.copy();
transformMatrix.multiply(boxTransform);
this.basicShader.setUniform(this.basicShader.getUniformLocation("uTransform"), transformMatrix);
this.basicShader.setUniform(this.basicShader.getUniformLocation("uColor"), box.color);
GL32.glDrawElements(GL32.GL_LINES, BOX_OUTLINE_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
}
//endregion
}
@@ -1,468 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShaderProgram;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiTextureCreatedParam;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDhFramebuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.texture.*;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.apply.GlDhApplyShader;
import com.seibel.distanthorizons.common.render.openGl.terrain.GlDhTerrainShaderProgram;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL32;
public class GlDhMetaRenderer implements IDhMetaRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
.build();
public static final DhLogger RATE_LIMITED_LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
.maxCountPerSecond(4)
.build();
public static final GlDhMetaRenderer INSTANCE = new GlDhMetaRenderer();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private int activeFramebufferId = -1;
private int activeColorTextureId = -1;
private int activeDepthTextureId = -1;
private int textureWidth;
private int textureHeight;
// framebuffer and texture ID's for this renderer
private IDhApiFramebuffer framebuffer;
/** will be null if MC's framebuffer is being used since MC already has a color texture */
@Nullable
private GlDhColorTexture nullableColorTexture;
private GlDhDepthTexture depthTexture;
/**
* If true the {@link GlDhMetaRenderer#framebuffer} is the same as MC's.
* This should only be true in the case of Optifine so LODs won't be overwritten when shaders are enabled.
*/
private boolean usingMcFramebuffer = false;
private boolean renderObjectsCreated = false;
/** used in case there's an API override */
public IDhApiShaderProgram shaderProgramForThisFrame;
//============//
// pre render //
//============//
//region
@Override
public void runRenderPassSetup(RenderParams renderParams)
{
boolean firstPass =
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
if (!this.renderObjectsCreated)
{
boolean setupSuccess = this.createRenderObjects();
if (!setupSuccess)
{
// shouldn't normally happen, but just in case
return;
}
this.renderObjectsCreated = true;
}
this.shaderProgramForThisFrame = GlDhTerrainRenderer.INSTANCE.getTerrainShaderProgram();
IDhApiShaderProgram lodShaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
if (lodShaderProgramOverride != null && this.shaderProgramForThisFrame.overrideThisFrame())
{
this.shaderProgramForThisFrame = lodShaderProgramOverride;
}
this.setGLState(renderParams, firstPass);
this.bindLightmap(renderParams.lightmap);
}
private void setGLState(
DhApiRenderParam renderEventParam,
boolean firstPass)
{
//===================//
// framebuffer setup //
//===================//
// get the active framebuffer
IDhApiFramebuffer framebuffer = this.framebuffer;
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
if (framebufferOverride != null && framebufferOverride.overrideThisFrame())
{
framebuffer = framebufferOverride;
}
this.setActiveFramebufferId(framebuffer.getId());
framebuffer.bind();
//==========//
// bindings //
//==========//
// by default draw everything as triangles
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
GLMC.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ZERO);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
// Enable depth test and depth mask
GLMC.enableDepthTest();
GLMC.glDepthFunc(GL32.GL_LESS);
GLMC.enableDepthMask();
// This is required for MC versions 1.21.5+
// due to MC updating the lightmap by changing the viewport size
GL32.glViewport(0, 0, this.textureWidth, this.textureHeight);
this.shaderProgramForThisFrame.bind();
//==========//
// uniforms //
//==========//
IDhApiShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
if (shaderProgramOverride != null)
{
shaderProgramOverride.fillUniformData(renderEventParam);
}
this.shaderProgramForThisFrame.fillUniformData(renderEventParam);
//===============//
// texture setup //
//===============//
// resize the textures if needed
if (MC_RENDER.getTargetFramebufferViewportWidth() != this.textureWidth
|| MC_RENDER.getTargetFramebufferViewportHeight() != this.textureHeight)
{
// just resizing the textures doesn't work when Optifine is present,
// so recreate the textures with the new size instead
this.createAndBindTextures();
}
// set the active textures
int depthTextureId = this.depthTexture.getTextureId();
this.setActiveDepthTextureId(depthTextureId);
if (this.nullableColorTexture != null)
{
int colorTextureId = this.nullableColorTexture.getTextureId();
this.setActiveColorTextureId(colorTextureId);
}
else
{
// get MC's color texture
int colorTextureId = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.setActiveColorTextureId(colorTextureId);
}
// needs to be fired after all the textures have been created/bound
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderEventParam);
if (clearTextures)
{
GL32.glClearDepth(1.0);
float[] clearColorValues = new float[4];
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
if (this.usingMcFramebuffer && framebufferOverride == null)
{
// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
// don't clear the color texture, that removes the sky
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
}
else if (firstPass)
{
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
}
}
}
private boolean createRenderObjects()
{
if (this.renderObjectsCreated)
{
LOGGER.warn("Renderer setup called but it has already completed setup!");
return false;
}
// GLProxy should have already been created by this point, but just in case create it now
GLProxy.getInstance();
LOGGER.info("Setting up renderer");
// create or get the frame buffer
if (AbstractOptifineAccessor.optifinePresent())
{
// use MC/Optifine's default Framebuffer so shaders won't remove the LODs
int currentFramebufferId = MC_RENDER.getTargetFramebuffer();
this.framebuffer = new GlDhFramebuffer(currentFramebufferId);
this.usingMcFramebuffer = true;
}
else
{
// normal use case
this.framebuffer = new GlDhFramebuffer();
this.usingMcFramebuffer = false;
}
// create and bind the necessary textures
this.createAndBindTextures();
if(this.framebuffer.getStatus() != GL32.GL_FRAMEBUFFER_COMPLETE)
{
// This generally means something wasn't bound, IE missing either the color or depth texture
LOGGER.warn("Framebuffer ["+this.framebuffer.getId()+"] isn't complete.");
return false;
}
LOGGER.info("Renderer setup complete");
return true;
}
@SuppressWarnings( "deprecation" ) // done to ignore DhApiColorDepthTextureCreatedEvent
private void createAndBindTextures()
{
int oldWidth = this.textureWidth;
int oldHeight = this.textureHeight;
this.textureWidth = MC_RENDER.getTargetFramebufferViewportWidth();
this.textureHeight = MC_RENDER.getTargetFramebufferViewportHeight();
DhApiTextureCreatedParam textureCreatedParam = new DhApiTextureCreatedParam(
oldWidth, oldHeight,
this.textureWidth, this.textureHeight
);
// DhApiColorDepthTextureCreatedEvent needs to be kept around since old versions of Iris need it
ApiEventInjector.INSTANCE.fireAllEvents(DhApiColorDepthTextureCreatedEvent.class, new DhApiColorDepthTextureCreatedEvent.EventParam(textureCreatedParam));
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeColorDepthTextureCreatedEvent.class, textureCreatedParam);
// also update the framebuffer override if present
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
this.depthTexture = new GlDhDepthTexture(this.textureWidth, this.textureHeight, EGlDhDepthBufferFormat.DEPTH32F);
this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
if (framebufferOverride != null)
{
framebufferOverride.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
}
// if we are using MC's frame buffer, a color texture is already present and shouldn't need to be bound
if (!this.usingMcFramebuffer)
{
this.nullableColorTexture = GlDhColorTexture.builder()
.setDimensions(this.textureWidth, this.textureHeight)
.setInternalFormat(EGlDhInternalTextureFormat.RGBA8)
.setPixelType(EGlDhPixelType.UNSIGNED_BYTE)
.setPixelFormat(EGlDhPixelFormat.RGBA)
.build();
this.framebuffer.addColorAttachment(0, this.nullableColorTexture.getTextureId());
if (framebufferOverride != null)
{
framebufferOverride.addColorAttachment(0, this.nullableColorTexture.getTextureId());
}
}
else
{
this.nullableColorTexture = null;
}
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterColorDepthTextureCreatedEvent.class, textureCreatedParam);
}
//endregion
//=============//
// post render //
//=============//
//region
@Override
public void runRenderPassCleanup(RenderParams renderParams)
{
boolean runningDeferredPass = (renderParams.renderPass == EDhApiRenderPass.TRANSPARENT);
if (!runningDeferredPass)
{
//===================//
// optifine clean up //
//===================//
if (this.usingMcFramebuffer)
{
// If MC's framebuffer is being used the depth needs to be cleared to prevent rendering on top of MC.
// This should only happen when Optifine shaders are being used.
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
}
}
this.unbindLightmap();
this.shaderProgramForThisFrame.unbind();
}
@Override
public void applyToMcTexture(RenderParams renderParams) { GlDhApplyShader.INSTANCE.render(renderParams); }
//endregion
//================//
// clear textures //
//================//
//region
@Override
public void clearDhDepthAndColorTextures(RenderParams renderParams)
{
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
boolean firstPass =
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
// needs to be fired after all the textures have been created/bound
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderParams);
if (clearTextures)
{
GL32.glClearDepth(1.0);
float[] clearColorValues = new float[4];
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
if (this.usingMcFramebuffer
&& framebufferOverride == null)
{
//// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
//// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
//this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
// don't clear the color texture, that removes the sky
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
}
else if (firstPass)
{
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
}
}
}
//endregion
//===============//
// API functions //
//===============//
//region
public void setActiveFramebufferId(int id) { this.activeFramebufferId = id; }
/** @return -1 if no frame buffer has been bound yet */
public int getActiveFramebufferId() { return this.activeFramebufferId; }
public void setActiveColorTextureId(int id)
{
this.activeColorTextureId = id;
DhApiRenderProxy.activeOpenGlDhColorTextureId = id;
}
/** @return -1 if no texture has been bound yet */
public int getActiveColorTextureId() { return this.activeColorTextureId; }
public void setActiveDepthTextureId(int id)
{
this.activeDepthTextureId = id;
DhApiRenderProxy.activeOpenGlDhDepthTextureId = id;
}
/** @return -1 if no texture has been bound yet */
public int getActiveDepthTextureId() { return this.activeDepthTextureId; }
//endregion
//================//
// helper methods //
//================//
//region
public void bindLightmap(ILightMapWrapper lightMapWrapper)
{
LightMapWrapper lightMap = (LightMapWrapper)lightMapWrapper;
GLMC.glActiveTexture(GL32.GL_TEXTURE0 + LightMapWrapper.GL_BOUND_INDEX);
GLMC.glBindTexture(lightMap.getOpenGlId());
}
public void unbindLightmap()
{
// strange that we don't call "glActiveTexture" here but since it's working James isn't going to change it right now (2026-03-10)
GLMC.glBindTexture(0);
}
//endregion
}
@@ -1,67 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl;
import com.seibel.distanthorizons.common.render.openGl.generic.GlGenericObjectRenderer;
import com.seibel.distanthorizons.common.render.openGl.generic.GlGenericObjectVertexContainer;
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDummyUniformData;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fade.GlDhFarFadeRenderer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fade.GlVanillaFadeRenderer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fog.GlDhFogRenderer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.ssao.GlDhSSAORenderer;
import com.seibel.distanthorizons.common.render.openGl.terrain.GlDhTerrainShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.test.GlTestTriangleRenderer;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.*;
public class GlDhRenderApiDefinition extends AbstractDhRenderApiDefinition
{
//=========//
// getters //
//=========//
//region
public String getApiName() { return "OpenGL"; }
//endregion
//============//
// singletons //
//============//
//region
@Override public IDhMetaRenderer getMetaRenderer() { return GlDhMetaRenderer.INSTANCE; }
@Override public IDhTerrainRenderer getTerrainRenderer() { return GlDhTerrainRenderer.INSTANCE; }
@Override public IDhSsaoRenderer getSsaoRenderer() { return GlDhSSAORenderer.INSTANCE; }
@Override public IDhFogRenderer getFogRenderer() { return GlDhFogRenderer.INSTANCE; }
@Override public IDhFarFadeRenderer getFarFadeRenderer() { return GlDhFarFadeRenderer.INSTANCE; }
@Override public AbstractDebugWireframeRenderer getDebugWireframeRenderer() { return GlDhDebugWireframeRenderer.INSTANCE; }
@Override public IDhVanillaFadeRenderer getVanillaFadeRenderer() { return GlVanillaFadeRenderer.INSTANCE; }
@Override public IDhTestTriangleRenderer getTestTriangleRenderer() { return GlTestTriangleRenderer.INSTANCE; }
//endregion
//===========//
// factories //
//===========//
//region
@Override public IDhGenericRenderer createGenericRenderer() { return new GlGenericObjectRenderer(); }
@Override public IVertexBufferWrapper createVboWrapper(String name) { return new GLVertexBuffer(); }
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return new GlDummyUniformData(); }
@Override public IDhGenericObjectVertexBufferContainer createGenericVboContainer() { return new GlGenericObjectVertexContainer(); }
//endregion
}
@@ -1,67 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl;
import com.seibel.distanthorizons.common.render.openGl.terrain.GlDhTerrainShaderProgram;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer;
public class GlDhTerrainRenderer implements IDhTerrainRenderer
{
public static final GlDhTerrainRenderer INSTANCE = new GlDhTerrainRenderer();
private GlDhTerrainShaderProgram terrainShaderProgram = null;
//=============//
// constructor //
//=============//
//region
private GlDhTerrainRenderer() {}
//endregion
//=========//
// getters //
//=========//
//region
/** must be called on the render thread the first time so GL can run it's setup */
public GlDhTerrainShaderProgram getTerrainShaderProgram()
{
if (this.terrainShaderProgram == null)
{
this.terrainShaderProgram = new GlDhTerrainShaderProgram();
}
return this.terrainShaderProgram;
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderEventParam, boolean opaquePass, SortedArraySet<LodBufferContainer> bufferContainers, IProfilerWrapper profiler)
{
this.getTerrainShaderProgram();
this.terrainShaderProgram.tryInit();
this.terrainShaderProgram.render(renderEventParam, opaquePass, bufferContainers, profiler);
}
//endregion
}
@@ -1,754 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.generic;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLIndexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.lwjgl.opengl.ARBInstancedArrays;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL33;
import org.lwjgl.system.MemoryUtil;
import java.awt.*;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Handles rendering generic groups of {@link DhApiRenderableBox}.
*
* @see IDhApiCustomRenderRegister
* @see DhApiRenderableBox
*/
public class GlGenericObjectRenderer implements IDhGenericRenderer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded();
/**
* Can be used to troubleshoot the renderer.
* If enabled several debug objects will render around (0,150,0).
*/
public static final boolean RENDER_DEBUG_OBJECTS = false;
// rendering setup
private boolean init = false;
private IDhApiGenericObjectShaderProgram instancedShaderProgram;
private IDhApiGenericObjectShaderProgram directShaderProgram;
private GLVertexBuffer boxVertexBuffer;
private GLIndexBuffer boxIndexBuffer;
private boolean instancedRenderingAvailable;
private boolean vertexAttribDivisorSupported;
private boolean instancedArraysSupported;
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
//region
// Pos x y z
// min X, vertical face
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
// max X, vertical face
0, 1, 1,
1, 1, 1,
1, 0, 1,
0, 0, 1,
// min Z, vertical face
0, 0, 1,
0, 0, 0,
0, 1, 0,
0, 1, 1,
// max Z, vertical face
1, 0, 1,
1, 1, 1,
1, 1, 0,
1, 0, 0,
// min Y, horizontal face
0, 0, 1,
1, 0, 1,
1, 0, 0,
0, 0, 0,
// max Y, horizontal face
0, 1, 1,
1, 1, 1,
1, 1, 0,
0, 1, 0,
//endregion
};
private static final int[] BOX_INDICES = {
//region
// min X, vertical face
2, 1, 0,
0, 3, 2,
// max X, vertical face
6, 5, 4,
4, 7, 6,
// min Z, vertical face
10, 9, 8,
8, 11, 10,
// max Z, vertical face
14, 13, 12,
12, 15, 14,
// min Y, horizontal face
18, 17, 16,
16, 19, 18,
// max Y, horizontal face
20, 21, 22,
22, 23, 20,
//endregion
};
//=============//
// constructor //
//=============//
//region
public GlGenericObjectRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
//===================================//
// is instanced rendering available? //
//===================================//
this.vertexAttribDivisorSupported = GLProxy.getInstance().vertexAttribDivisorSupported;
this.instancedArraysSupported = GLProxy.getInstance().instancedArraysSupported;
boolean isMac = (EPlatform.get() == EPlatform.MACOS);
if (isMac)
{
LOGGER.warn("Generic rendering not supported by Mac. Clouds, beacons, and some other effects will be disabled.");
Config.Client.Advanced.Graphics.GenericRendering.enableGenericRendering.setApiValue(false);
return;
}
this.instancedRenderingAvailable = (this.vertexAttribDivisorSupported || this.instancedArraysSupported) && !isMac;
if (!this.instancedRenderingAvailable)
{
LOGGER.warn("Instanced rendering not supported by this GPU, falling back to direct rendering. Generic object rendering will be slow and some effects may be disabled.");
}
//======================//
// startup the renderer //
//======================//
this.instancedShaderProgram = new GlGenericObjectShaderProgram(true);
this.directShaderProgram = new GlGenericObjectShaderProgram(false);
this.createBuffers();
if (RENDER_DEBUG_OBJECTS)
{
this.addGenericDebugObjects();
}
}
private void createBuffers()
{
// box vertices
ByteBuffer boxVerticesBuffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
this.boxVertexBuffer = new GLVertexBuffer(false);
this.boxVertexBuffer.bind();
this.boxVertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
MemoryUtil.memFree(boxVerticesBuffer);
// box vertex indexes
ByteBuffer solidIndexBuffer = MemoryUtil.memAlloc(BOX_INDICES.length * Integer.BYTES);
solidIndexBuffer.asIntBuffer().put(BOX_INDICES);
solidIndexBuffer.rewind();
this.boxIndexBuffer = new GLIndexBuffer(false);
this.boxIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
this.boxIndexBuffer.bind();
MemoryUtil.memFree(solidIndexBuffer);
}
private void addGenericDebugObjects()
{
GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE;
// single giant box
IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":CyanChunkBox",
new DhApiRenderableBox(
new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16),
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125),
EDhApiBlockMaterial.WATER)
);
singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleGiantBoxGroup);
// single slender box
IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":GreenBeacon",
new DhApiRenderableBox(
new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32),
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125),
EDhApiBlockMaterial.ILLUMINATED)
);
singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleTallBoxGroup);
// absolute box group
ArrayList<DhApiRenderableBox> absBoxList = new ArrayList<>();
for (int i = 0; i < 18; i++)
{
absBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25),
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()),
EDhApiBlockMaterial.LAVA
)
);
}
IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList);
this.add(absolutePosBoxGroup);
// relative box group
ArrayList<DhApiRenderableBox> relBoxList = new ArrayList<>();
for (int i = 0; i < 8; i+=2)
{
relBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1),
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()),
EDhApiBlockMaterial.METAL
)
);
}
IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MovingMagentaGroup",
new DhApiVec3d(24, 140, 24),
relBoxList);
relativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos();
pos.x += event.partialTicks / 2;
pos.x %= 32;
relativePosBoxGroup.setOriginBlockPos(pos);
});
this.add(relativePosBoxGroup);
// massive relative box group
ArrayList<DhApiRenderableBox> massRelBoxList = new ArrayList<>();
for (int x = 0; x < 50*2; x+=2)
{
for (int z = 0; z < 50*2; z+=2)
{
massRelBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z),
new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()),
EDhApiBlockMaterial.TERRACOTTA
)
);
}
}
IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MassRedGroup",
new DhApiVec3d(-25, 140, 0),
massRelBoxList);
massRelativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos();
blockPos.y += event.partialTicks / 4;
if (blockPos.y > 150f)
{
blockPos.y = 140f;
Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED;
massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; });
massRelativePosBoxGroup.triggerBoxChange();
}
massRelativePosBoxGroup.setOriginBlockPos(blockPos);
});
this.add(massRelativePosBoxGroup);
}
//endregion
//==============//
// registration //
//==============//
//region
@Override
public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException
{
if (!(iBoxGroup instanceof RenderableBoxGroup))
{
throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"].");
}
RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup;
if (boxGroup.size() != 0)
{
// trigger a box change to make sure the initial data is uploaded
boxGroup.triggerBoxChange();
}
long id = boxGroup.getId();
if (this.boxGroupById.containsKey(id))
{
throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present.");
}
this.boxGroupById.put(id, boxGroup);
}
@Override
public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); }
public void clear() { this.boxGroupById.clear(); }
//endregion
//===========//
// rendering //
//===========//
//region
/**
* @param renderingWithSsao
* if true that means this render call is happening before the SSAO pass
* and any objects rendered in this pass will have SSAO applied to them.
*/
@Override
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
{
// generic rendering (both instanced and direct) is extremely unstable on Mac, so don't render anything
if (EPlatform.get() == EPlatform.MACOS)
{
return;
}
// render setup //
profiler.push("setup");
this.init();
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
if (renderWireframe)
{
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
GLMC.disableFaceCulling();
}
else
{
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
}
GLMC.enableBlend();
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
IDhApiGenericObjectShaderProgram shaderProgram = this.instancedRenderingAvailable ? this.instancedShaderProgram : this.directShaderProgram;
IDhApiGenericObjectShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiGenericObjectShaderProgram.class);
if (shaderProgramOverride != null && shaderProgram.overrideThisFrame())
{
shaderProgram = shaderProgramOverride;
}
shaderProgram.bind(renderEventParam);
shaderProgram.bindVertexBuffer(this.boxVertexBuffer.getId());
this.boxIndexBuffer.bind();
Vec3d camPos = MC_RENDER.getCameraExactPosition();
// rendering //
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
for (RenderableBoxGroup boxGroup : boxList)
{
// validation //
// shouldn't happen, but just in case
if (boxGroup == null)
{
continue;
}
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled != renderingWithSsao)
{
continue;
}
profiler.popPush("render prep");
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
// ignore inactive groups
if (!boxGroup.active)
{
continue;
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
if (cancelRendering)
{
continue;
}
// update instanced data if needed
if (this.instancedRenderingAvailable)
{
boxGroup.tryUpdateInstancedDataAsync();
// skip groups that haven't been uploaded yet
if (boxGroup.vertexBufferContainer.getState() != GlGenericObjectVertexContainer.EState.RENDER)
{
continue;
}
}
// render //
profiler.popPush("rendering");
profiler.push(boxGroup.getResourceLocationNamespace());
profiler.push(boxGroup.getResourceLocationPath());
if (this.instancedRenderingAvailable)
{
this.renderBoxGroupInstanced(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
}
else
{
this.renderBoxGroupDirect(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
}
profiler.pop(); // resource path
profiler.pop(); // resource namespace
boxGroup.postRender(renderEventParam);
}
//==========//
// clean up //
//==========//
profiler.popPush("cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
if (renderWireframe)
{
// default back to GL_FILL since all other rendering uses it
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
}
shaderProgram.unbind();
profiler.pop();
}
//endregion
//=====================//
// instanced rendering //
//=====================//
//region
private void renderBoxGroupInstanced(
IDhApiGenericObjectShaderProgram shaderProgram, DhApiRenderParam renderEventParam,
RenderableBoxGroup boxGroup, Vec3d camPos,
IProfilerWrapper profiler)
{
// update instance data //
profiler.push("vertex setup");
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DEFAULT_SHADING;
}
shaderProgram.fillIndirectUniformData(
renderEventParam,
shading, boxGroup,
camPos);
// Bind instance data //
profiler.popPush("binding");
GlGenericObjectVertexContainer container = (GlGenericObjectVertexContainer)(boxGroup.vertexBufferContainer);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.color);
GL32.glEnableVertexAttribArray(1);
GL32.glVertexAttribPointer(1, 4, GL32.GL_FLOAT, false, 4 * Float.BYTES, 0);
this.vertexAttribDivisor(1, 1);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.scale);
GL32.glEnableVertexAttribArray(2);
this.vertexAttribDivisor(2, 1);
GL32.glVertexAttribPointer(2, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.chunkPos);
GL32.glEnableVertexAttribArray(3);
this.vertexAttribDivisor(3, 1);
GL32.glVertexAttribIPointer(3, 3, GL32.GL_INT, 3 * Integer.BYTES, 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.subChunkPos);
GL32.glEnableVertexAttribArray(4);
this.vertexAttribDivisor(4, 1);
GL32.glVertexAttribPointer(4, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.material);
GL32.glEnableVertexAttribArray(5);
this.vertexAttribDivisor(5, 1);
GL32.glVertexAttribIPointer(5, 1, GL32.GL_BYTE, Byte.BYTES, 0);
// Draw instanced
profiler.popPush("render");
if (container.uploadedBoxCount > 0)
{
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, container.uploadedBoxCount);
}
// Clean up
profiler.popPush("cleanup");
GL32.glDisableVertexAttribArray(1);
GL32.glDisableVertexAttribArray(2);
GL32.glDisableVertexAttribArray(3);
GL32.glDisableVertexAttribArray(4);
GL32.glDisableVertexAttribArray(5);
profiler.pop();
}
/**
* Clean way to handle both {@link GL33#glVertexAttribDivisor} and {@link ARBInstancedArrays#glVertexAttribDivisorARB}
* based on which one is supported.
*/
private void vertexAttribDivisor(int index, int divisor)
{
if (this.vertexAttribDivisorSupported)
{
GL33.glVertexAttribDivisor(index, divisor);
}
else if(this.instancedArraysSupported)
{
ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor);
}
else
{
throw new IllegalStateException("Instanced rendering isn't supported by this machine. Direct rendering should have been used instead.");
}
}
//endregion
//==================//
// direct rendering //
//==================//
//region
private void renderBoxGroupDirect(
IDhApiGenericObjectShaderProgram shaderProgram,
DhApiRenderParam renderEventParam,
RenderableBoxGroup boxGroup, Vec3d camPos,
IProfilerWrapper profiler)
{
profiler.popPush("shared uniforms");
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DhApiRenderableBoxGroupShading.getUnshaded();
}
shaderProgram.fillSharedDirectUniformData(renderEventParam, shading, boxGroup, camPos);
for (int i = 0; i < boxGroup.size(); i++)
{
try
{
DhApiRenderableBox box = boxGroup.get(i);
if (box != null)
{
profiler.popPush("direct uniforms");
shaderProgram.fillDirectUniformData(renderEventParam, boxGroup, box, camPos);
profiler.popPush("render");
GL32.glDrawElements(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
}
}
catch (IndexOutOfBoundsException e)
{
// Concurrency issue, the list was modified while rendering
// this can probably be ignored.
// However, if it does become a problem we can add locks to the box group.
break;
}
}
profiler.pop();
}
//endregion
//=========//
// getters //
//=========//
//region
/** @throws IllegalStateException if {@link #init()} function hasn't been called yet */
public boolean getInstancedRenderingAvailable() throws IllegalStateException
{
if (!this.init)
{
throw new IllegalStateException("GL initialization hasn't been completed.");
}
return this.instancedRenderingAvailable;
}
//endregion
//=========//
// F3 menu //
//=========//
//region
public String getVboRenderDebugMenuString()
{
// get counts
int totalGroupCount = this.boxGroupById.size();
int totalBoxCount = 0;
int activeGroupCount = 0;
int activeBoxCount = 0;
for (long key : this.boxGroupById.keySet())
{
RenderableBoxGroup renderGroup = this.boxGroupById.get(key);
if (renderGroup.active)
{
activeGroupCount++;
activeBoxCount += renderGroup.size();
}
totalBoxCount += renderGroup.size();
}
return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " +
"Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount);
}
//endregion
}
@@ -1,231 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.generic;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3f;
public class GlGenericObjectShaderProgram extends GlShaderProgram implements IDhApiGenericObjectShaderProgram
{
public static final String VERTEX_SHADER_INSTANCED_PATH = "assets/distanthorizons/shaders/generic/gl/instanced/vert.vert";
public static final String VERTEX_SHADER_DIRECT_PATH = "assets/distanthorizons/shaders/generic/gl/direct/vert.vert";
public static final String FRAGMENT_SHADER_INSTANCED_PATH = "assets/distanthorizons/shaders/generic/gl/instanced/frag.frag";
public static final String FRAGMENT_SHADER_DIRECT_PATH = "assets/distanthorizons/shaders/generic/gl/direct/frag.frag";
public final GlAbstractVertexAttribute va;
// shader uniforms
private final int directShaderTransformUniform;
private final int directShaderColorUniform;
private final int instancedShaderOffsetChunkUniform;
private final int instancedShaderOffsetSubChunkUniform;
private final int instancedShaderCameraChunkPosUniform;
private final int instancedShaderCameraSubChunkPosUniform;
private final int instancedShaderProjectionModelViewMatrixUniform;
private final int lightMapUniform;
private final int skyLightUniform;
private final int blockLightUniform;
private final int northShadingUniform;
private final int southShadingUniform;
private final int eastShadingUniform;
private final int westShadingUniform;
private final int topShadingUniform;
private final int bottomShadingUniform;
//=============//
// constructor //
//=============//
public GlGenericObjectShaderProgram(boolean useInstancedRendering)
{
super(
useInstancedRendering ? VERTEX_SHADER_INSTANCED_PATH : VERTEX_SHADER_DIRECT_PATH,
useInstancedRendering ? FRAGMENT_SHADER_INSTANCED_PATH : FRAGMENT_SHADER_DIRECT_PATH,
"vPosition"
);
this.va = GlAbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.directShaderTransformUniform = this.tryGetUniformLocation("uTransform");
this.directShaderColorUniform = this.tryGetUniformLocation("uColor");
this.instancedShaderOffsetChunkUniform = this.tryGetUniformLocation("uOffsetChunk");
this.instancedShaderOffsetSubChunkUniform = this.tryGetUniformLocation("uOffsetSubChunk");
this.instancedShaderCameraChunkPosUniform = this.tryGetUniformLocation("uCameraPosChunk");
this.instancedShaderCameraSubChunkPosUniform = this.tryGetUniformLocation("uCameraPosSubChunk");
this.instancedShaderProjectionModelViewMatrixUniform = this.tryGetUniformLocation("uProjectionMvm");
this.lightMapUniform = this.getUniformLocation("uLightMap");
this.skyLightUniform = this.getUniformLocation("uSkyLight");
this.blockLightUniform = this.getUniformLocation("uBlockLight");
this.northShadingUniform = this.getUniformLocation("uNorthShading");
this.southShadingUniform = this.getUniformLocation("uSouthShading");
this.eastShadingUniform = this.getUniformLocation("uEastShading");
this.westShadingUniform = this.getUniformLocation("uWestShading");
this.topShadingUniform = this.getUniformLocation("uTopShading");
this.bottomShadingUniform = this.getUniformLocation("uBottomShading");
}
//=========//
// methods //
//=========//
@Override
public void bind(DhApiRenderParam renderEventParam)
{
super.bind();
this.va.bind();
}
@Override
public void unbind()
{
super.unbind();
this.va.unbind();
}
@Override
public void free()
{
this.va.free();
super.free();
}
@Override
public void bindVertexBuffer(int vbo) { this.va.bindBufferToAllBindingPoints(vbo); }
@Override
public void fillIndirectUniformData(
DhApiRenderParam renderParameters,
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
DhApiVec3d camPos
)
{
Mat4f projectionMvmMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderParameters.dhModelViewMatrix);
super.bind();
this.setUniform(this.instancedShaderOffsetChunkUniform,
new DhApiVec3i(
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
));
this.setUniform(this.instancedShaderOffsetSubChunkUniform,
new Vec3f(
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
));
this.setUniform(this.instancedShaderCameraChunkPosUniform,
new DhApiVec3i(
LodUtil.getChunkPosFromDouble(camPos.x),
LodUtil.getChunkPosFromDouble(camPos.y),
LodUtil.getChunkPosFromDouble(camPos.z)
));
this.setUniform(this.instancedShaderCameraSubChunkPosUniform,
new Vec3f(
LodUtil.getSubChunkPosFromDouble(camPos.x),
LodUtil.getSubChunkPosFromDouble(camPos.y),
LodUtil.getSubChunkPosFromDouble(camPos.z)
));
this.setUniform(this.instancedShaderProjectionModelViewMatrixUniform, projectionMvmMatrix);
this.setUniform(this.lightMapUniform, LightMapWrapper.GL_BOUND_INDEX);
this.setUniform(this.skyLightUniform, boxGroup.getSkyLight());
this.setUniform(this.blockLightUniform, boxGroup.getBlockLight());
this.setUniform(this.northShadingUniform, shading.north);
this.setUniform(this.southShadingUniform, shading.south);
this.setUniform(this.eastShadingUniform, shading.east);
this.setUniform(this.westShadingUniform, shading.west);
this.setUniform(this.topShadingUniform, shading.top);
this.setUniform(this.bottomShadingUniform, shading.bottom);
}
@Override
public void fillSharedDirectUniformData(
DhApiRenderParam renderParameters,
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
DhApiVec3d camPos)
{
this.setUniform(this.lightMapUniform, LightMapWrapper.GL_BOUND_INDEX);
this.setUniform(this.skyLightUniform, boxGroup.getSkyLight());
this.setUniform(this.blockLightUniform, boxGroup.getBlockLight());
this.setUniform(this.northShadingUniform, shading.north);
this.setUniform(this.southShadingUniform, shading.south);
this.setUniform(this.eastShadingUniform, shading.east);
this.setUniform(this.westShadingUniform, shading.west);
this.setUniform(this.topShadingUniform, shading.top);
this.setUniform(this.bottomShadingUniform, shading.bottom);
}
public void fillDirectUniformData(
DhApiRenderParam renderParameters,
IDhApiRenderableBoxGroup boxGroup, DhApiRenderableBox box,
DhApiVec3d camPos)
{
Mat4f projectionMvmMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderParameters.dhModelViewMatrix);
Mat4f boxTransform = Mat4f.createTranslateMatrix(
(float) (box.minPos.x + boxGroup.getOriginBlockPos().x - camPos.x),
(float) (box.minPos.y + boxGroup.getOriginBlockPos().y - camPos.y),
(float) (box.minPos.z + boxGroup.getOriginBlockPos().z - camPos.z));
boxTransform.multiply(Mat4f.createScaleMatrix(
(float) (box.maxPos.x - box.minPos.x),
(float) (box.maxPos.y - box.minPos.y),
(float) (box.maxPos.z - box.minPos.z)));
projectionMvmMatrix.multiply(boxTransform);
this.setUniform(this.directShaderTransformUniform, projectionMvmMatrix);
this.setUniform(this.directShaderColorUniform, box.color);
}
@Override
public int getId() { return this.id; }
/** The base DH render program should always render */
@Override
public boolean overrideThisFrame() { return true; }
}
@@ -1,177 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.generic;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import org.lwjgl.opengl.GL32;
import java.awt.*;
import java.util.List;
/**
* For use by {@link RenderableBoxGroup}
*
* @see RenderableBoxGroup
*/
public class GlGenericObjectVertexContainer implements IDhGenericObjectVertexBufferContainer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int chunkPos = 0;
public int subChunkPos = 0;
public int scale = 0;
public int color = 0;
public int material = 0;
public int[] chunkPosData = new int[0];
public float[] subChunkPosData = new float[0];
public float[] scalingData = new float[0];
public float[] colorData = new float[0];
public int[] materialData = new int[0];
public int uploadedBoxCount = 0;
private EState state = EState.NEW;
@Override
public EState getState() { return this.state; }
@Override
public void setState(EState state) { this.state = state; }
//===========================//
// render building/uploading //
//===========================//
//region
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
{
int boxCount = uploadBoxList.size();
// recreate the data arrays if their size is different
if (this.uploadedBoxCount != boxCount)
{
this.uploadedBoxCount = boxCount;
this.chunkPosData = new int[boxCount * 3]; // 3 elements XYZ
this.subChunkPosData = new float[boxCount * 3]; // 3 elements XYZ
this.scalingData = new float[boxCount * 3]; // 3 elements XYZ
this.colorData = new float[boxCount * 4]; // 4 elements, RGBA
this.materialData = new int[boxCount];
}
// transformation / scaling //
for (int i = 0; i < boxCount; i++)
{
DhApiRenderableBox box = uploadBoxList.get(i);
int dataIndex = i * 3;
this.chunkPosData[dataIndex] = LodUtil.getChunkPosFromDouble(box.minPos.x);
this.chunkPosData[dataIndex + 1] = LodUtil.getChunkPosFromDouble(box.minPos.y);
this.chunkPosData[dataIndex + 2] = LodUtil.getChunkPosFromDouble(box.minPos.z);
this.subChunkPosData[dataIndex] = LodUtil.getSubChunkPosFromDouble(box.minPos.x);
this.subChunkPosData[dataIndex + 1] = LodUtil.getSubChunkPosFromDouble(box.minPos.y);
this.subChunkPosData[dataIndex + 2] = LodUtil.getSubChunkPosFromDouble(box.minPos.z);
this.scalingData[dataIndex] = (float) (box.maxPos.x - box.minPos.x);
this.scalingData[dataIndex + 1] = (float) (box.maxPos.y - box.minPos.y);
this.scalingData[dataIndex + 2] = (float) (box.maxPos.z - box.minPos.z);
}
// colors/materials //
for (int i = 0; i < boxCount; i++)
{
DhApiRenderableBox box = uploadBoxList.get(i);
Color color = box.color;
int colorIndex = i * 4;
this.colorData[colorIndex] = color.getRed() / 255.0f;
this.colorData[colorIndex + 1] = color.getGreen() / 255.0f;
this.colorData[colorIndex + 2] = color.getBlue() / 255.0f;
this.colorData[colorIndex + 3] = color.getAlpha() / 255.0f;
this.materialData[i] = box.material;
}
}
@Override
public void uploadDataToGpu()
{
this.tryCreateBuffers();
// Upload transformation matrices
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.chunkPos);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.chunkPosData, GL32.GL_DYNAMIC_DRAW);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.subChunkPos);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.subChunkPosData, GL32.GL_DYNAMIC_DRAW);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.scale);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.scalingData, GL32.GL_DYNAMIC_DRAW);
// Upload colors
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.color);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.colorData, GL32.GL_DYNAMIC_DRAW);
// Upload materials
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.material);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.materialData, GL32.GL_DYNAMIC_DRAW);
}
/** needs to be done on the render thread */
private void tryCreateBuffers()
{
if (this.chunkPos == 0)
{
this.chunkPos = GLMC.glGenBuffers();
this.subChunkPos = GLMC.glGenBuffers();
this.scale = GLMC.glGenBuffers();
this.color = GLMC.glGenBuffers();
this.material = GLMC.glGenBuffers();
}
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
tryDeleteBuffer(this.chunkPos);
tryDeleteBuffer(this.subChunkPos);
tryDeleteBuffer(this.scale);
tryDeleteBuffer(this.color);
tryDeleteBuffer(this.material);
}
private static void tryDeleteBuffer(int bufferId)
{
// usually unnecessary, but just in case
if (bufferId != 0)
{
GLMC.glDeleteBuffers(bufferId);
}
}
//endregion
}
@@ -1,338 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.glObject;
import com.seibel.distanthorizons.api.enums.config.EDhApiGLErrorHandlingMode;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.opengl.GLUtil;
import java.io.PrintStream;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* A singleton that holds references to different openGL contexts
* and GPU capabilities.
*/
public class GLProxy
{
public static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
.build();
public static final Set<String> LOGGED_GL_MESSAGES = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
private static GLProxy instance = null;
/** Minecraft's GL capabilities */
public final GLCapabilities glCapabilities;
public boolean namedObjectSupported = false; // ~OpenGL 4.5 (UNUSED CURRENTLY)
public boolean bufferStorageSupported = false; // ~OpenGL 4.4
public boolean vertexAttributeBufferBindingSupported = false; // ~OpenGL 4.3
public boolean instancedArraysSupported = false;
public boolean vertexAttribDivisorSupported = false; // OpenGL 3.3 or newer
private final EDhApiGpuUploadMethod preferredUploadMethod;
public final GLMessageBuilder vanillaDebugMessageBuilder =
new GLMessageBuilder(
(type) ->
{
if (type == EGLMessageType.POP_GROUP)
return false;
else if (type == EGLMessageType.PUSH_GROUP)
return false;
else if (type == EGLMessageType.MARKER)
return false;
else
return true;
},
(severity) ->
{
// notifications can generally be ignored (if they are logged at all)
if (severity == EGLMessageSeverity.NOTIFICATION)
return false;
else
return true;
},
null
);
//=============//
// constructor //
//=============//
//region
private GLProxy() throws IllegalStateException
{
// this must be created on minecraft's render context to work correctly
if (GLFW.glfwGetCurrentContext() == 0L)
{
throw new IllegalStateException(GLProxy.class.getSimpleName() + " was created outside the render thread!");
}
LOGGER.info("Creating " + GLProxy.class.getSimpleName() + "... If this is the last message you see there must have been an OpenGL error.");
LOGGER.info("Lod Render OpenGL version [" + GL32.glGetString(GL32.GL_VERSION) + "].");
//============================//
// get Minecraft's GL context //
//============================//
// get Minecraft's capabilities
this.glCapabilities = GL.getCapabilities();
// crash the game if the GPU doesn't support OpenGL 3.2
if (!this.glCapabilities.OpenGL32)
{
String supportedVersionInfo = this.getFailedVersionInfo(this.glCapabilities);
// See full requirement at above.
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GLProxy.class.getSimpleName()
+ " and discovered this GPU doesn't meet the OpenGL requirements. Sorry I couldn't tell you sooner :(\n" +
"Additional info:\n" + supportedVersionInfo;
IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
MC.crashMinecraft(errorMessage, new UnsupportedOperationException("Distant Horizon OpenGL requirements not met"));
}
LOGGER.info("minecraftGlCapabilities:\n" + this.versionInfoToString(this.glCapabilities));
if (Config.Client.Advanced.Debugging.OpenGl.overrideVanillaGLLogger.get())
{
GLUtil.setupDebugMessageCallback(new PrintStream(new GLMessageOutputStream(GLProxy::logMessage, this.vanillaDebugMessageBuilder), true));
}
//======================//
// get GPU capabilities //
//======================//
// UNUSED currently
// Check if we can use the named version of all calls, which is available in GL4.5 or after
this.namedObjectSupported = this.glCapabilities.glNamedBufferData != 0L; //Nullptr
// Check if we can use the Buffer Storage, which is available in GL4.4 or after
this.bufferStorageSupported = this.glCapabilities.glBufferStorage != 0L; // Nullptr
if (!this.bufferStorageSupported)
{
LOGGER.info("This GPU doesn't support Buffer Storage (OpenGL 4.4), falling back to using other methods.");
}
// Check if we can use the make-over version of Vertex Attribute, which is available in GL4.3 or after
this.vertexAttributeBufferBindingSupported = this.glCapabilities.glBindVertexBuffer != 0L; // Nullptr
// used by instanced rendering
this.vertexAttribDivisorSupported = this.glCapabilities.OpenGL33;
// denotes if ARBInstancedArrays.glVertexAttribDivisorARB() is available or not
// can be used as a backup if MC didn't create a GL 3.3+ context
this.instancedArraysSupported = this.glCapabilities.GL_ARB_instanced_arrays;
// get the best automatic upload method
String vendor = GL32.glGetString(GL32.GL_VENDOR).toUpperCase(); // example return: "NVIDIA CORPORATION"
if (EPlatform.get() != EPlatform.MACOS)
{
if (vendor.contains("NVIDIA") || vendor.contains("GEFORCE"))
{
// NVIDIA card
this.preferredUploadMethod = this.bufferStorageSupported ? EDhApiGpuUploadMethod.BUFFER_STORAGE : EDhApiGpuUploadMethod.SUB_DATA;
}
else
{
// AMD or Intel card
this.preferredUploadMethod = this.bufferStorageSupported ? EDhApiGpuUploadMethod.BUFFER_STORAGE : EDhApiGpuUploadMethod.DATA;
}
}
else
{
// Mac may have an issue with Buffer Storage, so default to the most basic
// form of uploading
this.preferredUploadMethod = EDhApiGpuUploadMethod.DATA;
}
LOGGER.info("GPU Vendor [" + vendor + "] with OS [" + EPlatform.get().getName() + "], Preferred upload method is [" + this.preferredUploadMethod + "].");
//==========//
// clean up //
//==========//
// GLProxy creation success
LOGGER.info(GLProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
}
//endregion
//=========//
// getters //
//=========//
//region
public static boolean hasInstance() { return instance != null; }
/** @throws IllegalStateException if the Proxy hasn't been created yet and this is called outside the render thread */
public static GLProxy getInstance() throws IllegalStateException
{
if (instance == null)
{
instance = new GLProxy();
}
return instance;
}
public EDhApiGpuUploadMethod getGpuUploadMethod() { return this.preferredUploadMethod; }
public static boolean runningOnRenderThread()
{
long currentContext = GLFW.glfwGetCurrentContext();
return currentContext != 0L; // if the context isn't null, it's the MC context
}
//endregion
//=========//
// logging //
//=========//
//region
/** this method is called on the render thread at the point of the GL Error */
private static void logMessage(GLMessage msg)
{
EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get();
if (errorHandlingMode == EDhApiGLErrorHandlingMode.IGNORE)
{
return;
}
boolean onlyLogOnce = Config.Client.Advanced.Debugging.OpenGl.onlyLogGlErrorsOnce.get();
String errorMessage = "GL ERROR [" + msg.id + "] from [" + msg.source + "]: [" + msg.message + "]"+(onlyLogOnce ? " this message will only be logged once" : "")+".";
if (onlyLogOnce
&& !LOGGED_GL_MESSAGES.add(errorMessage))
{
// this message has already been logged
return;
}
// create an exception so we get a stacktrace of where the message was triggered from
RuntimeException exception = new RuntimeException(errorMessage);
if (msg.type == EGLMessageType.ERROR || msg.type == EGLMessageType.UNDEFINED_BEHAVIOR)
{
// critical error
LOGGER.error(exception.getMessage(), exception);
if (errorHandlingMode == EDhApiGLErrorHandlingMode.LOG_THROW)
{
// will probably crash the game,
// good for quickly checking if there's a problem while preventing log spam
throw exception;
}
}
else
{
// non-critical log
EGLMessageSeverity severity = msg.severity;
if (severity == null)
{
// just in case the message was malformed
severity = EGLMessageSeverity.LOW;
}
switch (severity)
{
case HIGH:
LOGGER.error(exception.getMessage(), exception);
break;
case MEDIUM:
LOGGER.warn(exception.getMessage(), exception);
break;
case LOW:
LOGGER.info(exception.getMessage(), exception);
break;
case NOTIFICATION:
LOGGER.debug(exception.getMessage(), exception);
break;
}
}
}
//endregion
//================//
// helper methods //
//================//
//region
private String getFailedVersionInfo(GLCapabilities c)
{
return "Your OpenGL support:\n" +
"openGL version 3.2+: [" + c.OpenGL32 + "] <- REQUIRED\n" +
"Vertex Attribute Buffer Binding: [" + (c.glVertexAttribBinding != 0) + "] <- optional improvement\n" +
"Buffer Storage: [" + (c.glBufferStorage != 0) + "] <- optional improvement\n" +
"If you noticed that your computer supports higher OpenGL versions"
+ " but not the required version, try running the game in compatibility mode."
+ " (How you turn that on, I have no clue~)";
}
private String versionInfoToString(GLCapabilities c)
{
return "Your OpenGL support:\n" +
"openGL version 3.2+: [" + c.OpenGL32 + "] <- REQUIRED\n" +
"Vertex Attribute Buffer Binding: [" + (c.glVertexAttribBinding != 0) + "] <- optional improvement\n" +
"Buffer Storage: [" + (c.glBufferStorage != 0) + "] <- optional improvement\n";
}
//endregion
}
@@ -1,259 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.glObject;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import org.lwjgl.opengl.GL32;
public class GLState implements AutoCloseable
{
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int program;
public int vao;
public int vbo;
public int ebo;
public int fbo;
public int texture2D;
/** IE: GL_TEXTURE0, GL_TEXTURE1, etc. */
public int activeTextureNumber;
public int texture0;
public int texture1;
public int texture2;
public int texture3;
public int frameBufferTexture0;
public int frameBufferTexture1;
public int frameBufferDepthTexture;
public boolean blend;
public boolean scissor;
public int blendEqRGB;
public int blendEqAlpha;
public int blendSrcColor;
public int blendSrcAlpha;
public int blendDstColor;
public int blendDstAlpha;
public boolean depth;
public boolean writeToDepthBuffer;
public int depthFunc;
public boolean stencil;
public int stencilFunc;
public int stencilRef;
public int stencilMask;
public int[] view;
public boolean cull;
public int cullMode;
public int polyMode;
public GLState() { this.saveState(); }
public void saveState()
{
this.program = GL32.glGetInteger(GL32.GL_CURRENT_PROGRAM);
this.vao = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING);
this.vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
this.ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
this.fbo = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
this.texture2D = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
this.activeTextureNumber = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE);
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
this.texture0 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
this.texture1 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
GLMC.glActiveTexture(GL32.GL_TEXTURE2); // problem with Iris
this.texture2 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
GLMC.glActiveTexture(GL32.GL_TEXTURE3);
this.texture3 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
GLMC.glActiveTexture(this.activeTextureNumber);
if (this.fbo != 0)
{
this.frameBufferTexture0 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.frameBufferTexture1 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.frameBufferDepthTexture = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
}
else
{
// attempting to get values from the default framebuffer can throw errors on Linux
this.frameBufferTexture0 = 0;
this.frameBufferTexture1 = 0;
this.frameBufferDepthTexture = 0;
}
this.blend = GL32.glIsEnabled(GL32.GL_BLEND);
this.scissor = GL32.glIsEnabled(GL32.GL_SCISSOR_TEST);
this.blendEqRGB = GL32.glGetInteger(GL32.GL_BLEND_EQUATION_RGB);
this.blendEqAlpha = GL32.glGetInteger(GL32.GL_BLEND_EQUATION_ALPHA);
this.blendSrcColor = GL32.glGetInteger(GL32.GL_BLEND_SRC_RGB);
this.blendSrcAlpha = GL32.glGetInteger(GL32.GL_BLEND_SRC_ALPHA);
this.blendDstColor = GL32.glGetInteger(GL32.GL_BLEND_DST_RGB);
this.blendDstAlpha = GL32.glGetInteger(GL32.GL_BLEND_DST_ALPHA);
this.depth = GL32.glIsEnabled(GL32.GL_DEPTH_TEST);
this.writeToDepthBuffer = GL32.glGetInteger(GL32.GL_DEPTH_WRITEMASK) == GL32.GL_TRUE;
this.depthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC);
this.stencil = GL32.glIsEnabled(GL32.GL_STENCIL_TEST);
this.stencilFunc = GL32.glGetInteger(GL32.GL_STENCIL_FUNC);
this.stencilRef = GL32.glGetInteger(GL32.GL_STENCIL_REF);
this.stencilMask = GL32.glGetInteger(GL32.GL_STENCIL_VALUE_MASK);
this.view = new int[4];
GL32.glGetIntegerv(GL32.GL_VIEWPORT, this.view);
this.cull = GL32.glIsEnabled(GL32.GL_CULL_FACE);
this.cullMode = GL32.glGetInteger(GL32.GL_CULL_FACE_MODE);
this.polyMode = GL32.glGetInteger(GL32.GL_POLYGON_MODE);
}
@Override
public void close()
{
// explicitly unbinding the frame buffer is necessary to prevent GL_CLEAR calls from hitting the wrong buffer
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, 0);
boolean frameBufferSet = false;
if (this.fbo != 0 && GL32.glIsFramebuffer(this.fbo))
{
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fbo);
frameBufferSet = true;
}
if (this.blend)
{
GLMC.enableBlend();
}
else
{
GLMC.disableBlend();
}
if (this.scissor)
{
GLMC.enableScissorTest();
}
else
{
GLMC.disableScissorTest();
}
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(GL32.glIsTexture(this.texture0) ? this.texture0 : 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
GLMC.glBindTexture(GL32.glIsTexture(this.texture1) ? this.texture1 : 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE2);
GLMC.glBindTexture(GL32.glIsTexture(this.texture2) ? this.texture2 : 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE3);
GLMC.glBindTexture(GL32.glIsTexture(this.texture3) ? this.texture3 : 0);
GLMC.glActiveTexture(this.activeTextureNumber);
GLMC.glBindTexture(GL32.glIsTexture(this.texture2D) ? this.texture2D : 0);
// attempting to set textures on the default frame buffer (ID 0) will throw errors
if (frameBufferSet)
{
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
}
GL32.glBindVertexArray(GL32.glIsVertexArray(this.vao) ? this.vao : 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(this.vbo) ? this.vbo : 0);
GL32.glBindBuffer(GL32.GL_ELEMENT_ARRAY_BUFFER, GL32.glIsBuffer(this.ebo) ? this.ebo: 0);
GL32.glUseProgram(GL32.glIsProgram(this.program) ? this.program : 0);
if (this.writeToDepthBuffer)
{
GLMC.enableDepthMask();
}
else
{
GLMC.disableDepthMask();
}
GLMC.glBlendFunc(this.blendSrcColor, this.blendDstColor);
GL32.glBlendEquationSeparate(this.blendEqRGB, this.blendEqAlpha);
GLMC.glBlendFuncSeparate(this.blendSrcColor, this.blendDstColor, this.blendSrcAlpha, this.blendDstAlpha);
if (this.depth)
{
GLMC.enableDepthTest();
}
else
{
GLMC.disableDepthTest();
}
GLMC.glDepthFunc(this.depthFunc);
if (this.stencil)
{
GL32.glEnable(GL32.GL_STENCIL_TEST);
}
else
{
GL32.glDisable(GL32.GL_STENCIL_TEST);
}
GL32.glStencilFunc(this.stencilFunc, this.stencilRef, this.stencilMask);
GL32.glViewport(this.view[0], this.view[1], this.view[2], this.view[3]);
if (this.cull)
{
GLMC.enableFaceCulling();
}
else
{
GLMC.disableFaceCulling();
}
GL32.glCullFace(this.cullMode);
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, this.polyMode);
}
@Override
public String toString()
{
return "GLState{" +
"program=" + this.program + ", vao=" + this.vao + ", vbo=" + this.vbo + ", ebo=" + this.ebo + ", fbo=" + this.fbo +
", text=" + GLEnums.getString(this.texture2D) + "@" + this.activeTextureNumber + ", text0=" + GLEnums.getString(this.texture0) +
", FB text0=" + this.frameBufferTexture0 +
", FB text1=" + this.frameBufferTexture1 +
", FB depth=" + this.frameBufferDepthTexture +
", blend=" + this.blend + ", scissor=" + this.scissor + ", blendMode=" + GLEnums.getString(this.blendSrcColor) + "," + GLEnums.getString(this.blendDstColor) +
", depth=" + this.depth +
", depthFunc=" + GLEnums.getString(this.depthFunc) + ", stencil=" + this.stencil +
", stencilFunc=" + GLEnums.getString(this.stencilFunc) + ", stencilRef=" + this.stencilRef + ", stencilMask=" + this.stencilMask +
", view={x:" + this.view[0] + ", y:" + this.view[1] +
", w:" + this.view[2] + ", h:" + this.view[3] + "}" + ", cull=" + this.cull +
", cullMode=" + GLEnums.getString(this.cullMode) + ", polyMode=" + GLEnums.getString(this.polyMode) +
'}';
}
}
@@ -1,94 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import org.lwjgl.opengl.GL32;
public class GlDhFramebuffer implements IDhApiFramebuffer
{
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private int id;
//=============//
// constructor //
//=============//
//region
public GlDhFramebuffer() { this.id = GL32.glGenFramebuffers(); }
/** For internal use by Iris, do not remove. */
public GlDhFramebuffer(int id) { this.id = id; }
//endregion
//=========//
// methods //
//=========//
//region
@Override
public void addDepthAttachment(int textureId, boolean isCombinedStencil)
{
this.bind();
int depthAttachment = isCombinedStencil ? GL32.GL_DEPTH_STENCIL_ATTACHMENT : GL32.GL_DEPTH_ATTACHMENT;
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, depthAttachment, GL32.GL_TEXTURE_2D, textureId, 0);
}
@Override
public void addColorAttachment(int textureIndex, int textureId)
{
this.bind();
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0 + textureIndex, GL32.GL_TEXTURE_2D, textureId, 0);
}
@Override
public void bind()
{
if (this.id == -1)
{
throw new IllegalStateException("Framebuffer does not exist!");
}
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.id);
}
@Override
public void destroy()
{
GL32.glDeleteFramebuffers(this.id);
this.id = -1;
}
@Override
public int getStatus()
{
this.bind();
int status = GL32.glCheckFramebufferStatus(GL32.GL_FRAMEBUFFER);
return status;
}
@Override
public int getId() { return this.id; }
//endregion
//=============//
// API methods //
//=============//
//region
public boolean overrideThisFrame() { return true; }
//endregion
}
@@ -1,17 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
/**
* With OpenGL all uniform data is uploaded during the rendering phase
* so nothing is needed here.
*/
public class GlDummyUniformData implements ILodContainerUniformBufferWrapper
{
@Override public void createUniformData(LodBufferContainer bufferContainer) { }
@Override public void tryUpload() { }
@Override public void upload() { }
@Override public void close() { }
}
@@ -1,383 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.ThreadUtil;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL44;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
public class GLBuffer implements AutoCloseable
{
private static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
.build();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.3;
public static final double BUFFER_SHRINK_TRIGGER = BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER;
/** the number of active buffers, can be used for debugging */
public static AtomicInteger bufferCount = new AtomicInteger(0);
private static final int PHANTOM_REF_CHECK_TIME_IN_MS = 5 * 1000;
private static final ConcurrentHashMap<PhantomReference<? extends GLBuffer>, Integer> PHANTOM_TO_BUFFER_ID = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Integer, PhantomReference<? extends GLBuffer>> BUFFER_ID_TO_PHANTOM = new ConcurrentHashMap<>();
private static final ReferenceQueue<GLBuffer> PHANTOM_REFERENCE_QUEUE = new ReferenceQueue<>();
private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup");
protected int id;
public final int getId() { return this.id; }
protected int size = 0;
public int getSize() { return this.size; }
protected boolean bufferStorage;
public final boolean isBufferStorage() { return this.bufferStorage; }
protected boolean isMapped = false;
//==============//
// constructors //
//==============//
//region
static { CLEANUP_THREAD.execute(() -> runPhantomReferenceCleanupLoop()); }
public GLBuffer(boolean isBufferStorage) { this.destroyOldAndCreate(isBufferStorage); }
//endregion
//=========//
// methods //
//=========//
//region
// Should be override by subclasses
public int getBufferBindingTarget() { return GL32.GL_COPY_READ_BUFFER; }
public void bind() { GL32.glBindBuffer(this.getBufferBindingTarget(), this.id); }
public void unbind() { GL32.glBindBuffer(this.getBufferBindingTarget(), 0); }
//endregion
//====================//
// create and destroy //
//====================//
//region
protected void destroyOldAndCreate(boolean asBufferStorage)
{
if (!GLProxy.runningOnRenderThread())
{
LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread.");
}
// destroy the old buffer if one is present
if (this.id != 0)
{
destroyBufferIdNow(this.id);
}
this.id = GLMC.glGenBuffers();
this.bufferStorage = asBufferStorage;
bufferCount.getAndIncrement();
PhantomReference<GLBuffer> phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE);
PHANTOM_TO_BUFFER_ID.put(phantom, this.id);
BUFFER_ID_TO_PHANTOM.put(this.id, phantom);
}
protected void destroyAsync()
{
if (this.id == 0)
{
// the buffer has already been closed
return;
}
final int idToDelete = this.id; // saving the ID to a separate variable is necessary so it can be captured by the lambda
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete); });
this.id = 0;
this.size = 0;
}
private static void destroyBufferIdNow(int id)
{
// only delete valid buffers
if (id == 0)
{
LOGGER.warn("Attempted to destroy a buffer with ID 0, VRAM memory leaks may occur.");
return;
}
// remove and clear the phantom reference if present
if (BUFFER_ID_TO_PHANTOM.containsKey(id))
{
Reference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.get(id);
// if we are manually closing this buffer, we don't want the phantom reference to accidentally close it again
// this can cause a race condition were we accidentally delete an in-use buffer and cause NVIDIA
// to throw an EXCEPTION_ACCESS_VIOLATION when we attempt to render it
phantom.clear();
PHANTOM_TO_BUFFER_ID.remove(phantom);
BUFFER_ID_TO_PHANTOM.remove(id);
}
bufferCount.decrementAndGet();
// destroy the buffer if it exists,
// the buffer may not exist if the destroy method is called twice
if (GL32.glIsBuffer(id))
{
GLMC.glDeleteBuffers(id);
if (Config.Client.Advanced.Debugging.logBufferGarbageCollection.get())
{
LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "]");
}
}
}
//endregion
//==================//
// buffer uploading //
//==================//
//region
/**
* Assumes the GL Context is already bound. <br>
* Will create the VBO if one exist.
*/
public void uploadBuffer(ByteBuffer bb, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize, int bufferHint)
{
LodUtil.assertTrue(!uploadMethod.useEarlyMapping, "UploadMethod signal that this should use Mapping instead of uploadBuffer!");
int bbSize = bb.limit() - bb.position();
if (bbSize > maxExpansionSize)
{
LodUtil.assertNotReach("maxExpansionSize is [" + maxExpansionSize + "] but buffer size is [" + bbSize + "]!");
}
// Don't upload an empty buffer
if (bbSize == 0)
{
return;
}
// re-binding the old VBO is necessary for old MC versions (IE 1.16.5 and older)
// otherwise the screen may be black when on the home menu
int previousBoundVbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
try
{
// make sure the buffer is ready for uploading
this.createOrChangeBufferTypeForUpload(uploadMethod);
switch (uploadMethod)
{
case AUTO:
LodUtil.assertNotReach("GpuUploadMethod AUTO must be resolved before call to uploadBuffer()!");
case BUFFER_STORAGE:
this.uploadBufferStorage(bb);
break;
case DATA:
this.uploadBufferData(bb, bufferHint);
break;
case SUB_DATA:
this.uploadSubData(bb, maxExpansionSize, bufferHint);
break;
default:
LodUtil.assertNotReach("Unknown GpuUploadMethod!");
}
}
finally
{
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(previousBoundVbo) ? previousBoundVbo : 0);
}
}
/** Requires the buffer to be bound */
protected void uploadBufferStorage(ByteBuffer bb)
{
LodUtil.assertTrue(this.bufferStorage, "Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
int bbSize = bb.limit() - bb.position();
this.destroyOldAndCreate(true);
this.bind();
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, 0);
this.size = bbSize;
}
/** Requires the buffer to be bound */
protected void uploadBufferData(ByteBuffer bb, int bufferDataHint)
{
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use bufferData upload method!");
int bbSize = bb.limit() - bb.position();
GL32.glBufferData(this.getBufferBindingTarget(), bb, bufferDataHint);
this.size = bbSize;
}
/** Requires the buffer to be bound */
protected void uploadSubData(ByteBuffer bb, int maxExpansionSize, int bufferDataHint)
{
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use subData upload method!");
int bbSize = bb.limit() - bb.position();
if (this.size < bbSize || this.size > bbSize * BUFFER_SHRINK_TRIGGER)
{
int newSize = (int) (bbSize * BUFFER_EXPANSION_MULTIPLIER);
if (newSize > maxExpansionSize) newSize = maxExpansionSize;
GL32.glBufferData(this.getBufferBindingTarget(), newSize, bufferDataHint);
this.size = newSize;
}
GL32.glBufferSubData(this.getBufferBindingTarget(), 0, bb);
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close() { this.destroyAsync(); }
@Override
public String toString()
{
return (this.bufferStorage ? "" : "Static-") + this.getClass().getSimpleName() +
"[id:" + this.id + ",size:" + this.size + (this.isMapped ? ",MAPPED" : "") + "]";
}
//endregion
//================//
// helper methods //
//================//
//region
/**
* Makes sure the buffer exists and is of the correct format
* before uploading.
*/
private void createOrChangeBufferTypeForUpload(EDhApiGpuUploadMethod uploadMethod)
{
// create/change the buffer type if necessary
if (uploadMethod.useBufferStorage != this.bufferStorage)
{
// recreate if the buffer storage type changed
this.bind();
destroyBufferIdNow(this.id);
this.destroyOldAndCreate(uploadMethod.useBufferStorage);
this.bind();
}
else
{
// Prevent uploading to the null buffer (ID 0).
// This can happen if the buffer was deleted previously.
if (this.id == 0)
{
this.destroyOldAndCreate(this.bufferStorage);
}
this.bind();
}
}
//endregion
//================//
// static cleanup //
//================//
//region
private static void runPhantomReferenceCleanupLoop()
{
while (true)
{
try
{
try
{
Thread.sleep(PHANTOM_REF_CHECK_TIME_IN_MS);
}
catch (InterruptedException ignore) { }
Reference<? extends GLBuffer> phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
while (phantomRef != null)
{
// destroy the buffer if it hasn't been cleared yet
if (PHANTOM_TO_BUFFER_ID.containsKey(phantomRef))
{
int id = PHANTOM_TO_BUFFER_ID.get(phantomRef);
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer phantom destroy", () -> { destroyBufferIdNow(id); });
//LOGGER.warn("Buffer Phantom collected, ID: ["+id+"]");
}
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
}
}
catch (Exception e)
{
LOGGER.error("Unexpected error in buffer cleanup thread: [" + e.getMessage() + "].", e);
}
}
}
//endregion
}
@@ -1,55 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
import org.lwjgl.opengl.GL32;
/**
* AKA the GLElementBuffer
*
* @author James Seibel
* @version 11-20-2021
*/
public class GLIndexBuffer extends GLBuffer
{
/**
* When uploading to a buffer that is too small, recreate it this many times
* bigger than the upload payload
*/
protected int indicesCount = 0;
protected int glType = GL32.GL_UNSIGNED_INT;
public int getGlType() { return this.glType; }
public GLIndexBuffer(boolean isBufferStorage)
{
super(isBufferStorage);
}
@Override
public void destroyAsync()
{
super.destroyAsync();
this.indicesCount = 0;
}
@Override
public int getBufferBindingTarget() { return GL32.GL_ELEMENT_ARRAY_BUFFER; }
}
@@ -1,190 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
import java.nio.ByteBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import org.lwjgl.opengl.GL32;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
/**
* This is a container for a OpenGL
* VBO (Vertex Buffer Object).
*
* @author James Seibel
* @version 11-20-2021
*/
public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
{
private static final AbstractDhRenderApiDefinition RENDER_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
/**
* When uploading to a buffer that is too small, recreate it this many times
* bigger than the upload payload
*/
protected int vertexCount = 0;
public int getVertexCount() { return this.vertexCount; }
private GlQuadIndexBuffer quadIBO = null;
private static GlQuadIndexBuffer GLOBAL_QUAD_IBO = null;
public GlQuadIndexBuffer getQuadIBO()
{
if (RENDER_DEF.useSingleIbo())
{
return GLOBAL_QUAD_IBO;
}
else
{
return this.quadIBO;
}
}
//=============//
// constructor //
//=============//
//region
static
{
if (RENDER_DEF.useSingleIbo())
{
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Global IBO Creation", () ->
{
GLOBAL_QUAD_IBO = new GlQuadIndexBuffer();
int maxSize = LodQuadBuilder.getMaxBufferByteSize();
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
int maxQuadCount = (maxVertexCount / 4);
GLOBAL_QUAD_IBO.upload(maxQuadCount);
});
}
}
public GLVertexBuffer() { this(GLProxy.getInstance().getGpuUploadMethod() == EDhApiGpuUploadMethod.BUFFER_STORAGE); }
public GLVertexBuffer(boolean isBufferStorage) { super(isBufferStorage); }
//endregion
//======================//
// uploading/destroying //
//======================//
//region
@Override
public int getBufferBindingTarget() { return GL32.GL_ARRAY_BUFFER; }
@Override
public void uploadVertexBuffer(ByteBuffer buffer, int vertexCount)
{
EDhApiGpuUploadMethod uploadMethod = GLProxy.getInstance().getGpuUploadMethod();
int maxBufferSize = LodQuadBuilder.getMaxBufferByteSize();
this.uploadBuffer(buffer, vertexCount, uploadMethod, maxBufferSize);
}
/**
* bufferSize is the number of shared verticies. <br>
* This number will be higher when actually rendered since each box's face needs 2 triangles
* with 2 shared verticies.
*/
public void uploadBuffer(ByteBuffer byteBuffer, int vertexCount, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize)
{
if (vertexCount < 0)
{
throw new IllegalArgumentException("vertexCount is negative!");
}
// If size is zero, just ignore it.
if (byteBuffer.limit() - byteBuffer.position() != 0)
{
super.uploadBuffer(byteBuffer, uploadMethod, maxExpansionSize, uploadMethod.useBufferStorage ? 0 : GL32.GL_STATIC_DRAW);
}
this.vertexCount = vertexCount;
}
@Override
public void uploadIndexBuffer(ByteBuffer buffer, int vertexCount)
{
if (RENDER_DEF.useSingleIbo())
{
// ignore index uploading when running a single IBO
return;
}
// If size is zero, just ignore it.
if (vertexCount == 0)
{
return;
}
if (this.quadIBO != null)
{
this.quadIBO.close();
}
this.quadIBO = new GlQuadIndexBuffer();
int quadCount = (vertexCount / 4);
this.quadIBO.upload(quadCount);
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close() { this.destroyAsync(); }
@Override
public void destroyAsync()
{
super.destroyAsync();
if (this.quadIBO != null)
{
this.quadIBO.destroyAsync();
}
this.vertexCount = 0;
}
//endregion
}
@@ -1,89 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
/** aka GlQuadElementBuffer */
public class GlQuadIndexBuffer extends GLIndexBuffer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
//=============//
// constructor //
//=============//
//region
public GlQuadIndexBuffer() { super(false); }
public void upload(int quadCount)
{
if (quadCount < 0)
{
throw new IllegalArgumentException("quadCount must be greater than 0");
}
if (quadCount == 0)
{
// shouldn't happen, but just in case
return;
}
this.indicesCount = quadCount * 6; // 2 triangles per quad
if (this.indicesCount >= this.getCapacity()
&& this.indicesCount < this.getCapacity() * BUFFER_SHRINK_TRIGGER)
{
return;
}
this.glType = GL32.GL_UNSIGNED_INT;
ByteBuffer buffer = IndexBufferBuilder.createBuffer(quadCount);
this.bind();
super.uploadBuffer(buffer, EDhApiGpuUploadMethod.DATA,
this.indicesCount * GLEnums.getTypeSize(this.glType), GL32.GL_STATIC_DRAW);
MemoryUtil.memFree(buffer);
}
//endregion
//=========//
// getters //
//=========//
//region
public int getCapacity() { return super.getSize() / GLEnums.getTypeSize(this.getGlType()); }
//endregion
}
@@ -1,9 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.enums;
public enum EGlVersion
{
GL_11,
GL_12,
GL_30,
GL_31
}
@@ -1,261 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.glObject.enums;
import static org.lwjgl.opengl.GL46.*;
// Turns GL int enums back to readable strings
public class GLEnums
{
public static String getString(int glEnum)
{
// blend stuff
switch (glEnum)
{
case GL_ZERO:
return "GL_ZERO";
case GL_ONE:
return "GL_ONE";
case GL_SRC_COLOR:
return "GL_SRC_COLOR";
case GL_ONE_MINUS_SRC_COLOR:
return "GL_ONE_MINUS_SRC_COLOR";
case GL_DST_COLOR:
return "GL_DST_COLOR";
case GL_ONE_MINUS_DST_COLOR:
return "GL_ONE_MINUS_DST_COLOR";
case GL_SRC_ALPHA:
return "GL_SRC_ALPHA";
case GL_ONE_MINUS_SRC_ALPHA:
return "GL_ONE_MINUS_SRC_ALPHA";
case GL_DST_ALPHA:
return "GL_DST_ALPHA";
case GL_ONE_MINUS_DST_ALPHA:
return "GL_ONE_MINUS_DST_ALPHA";
case GL_CONSTANT_COLOR:
return "GL_CONSTANT_COLOR";
case GL_ONE_MINUS_CONSTANT_COLOR:
return "GL_ONE_MINUS_CONSTANT_COLOR";
case GL_CONSTANT_ALPHA:
return "GL_CONSTANT_ALPHA";
case GL_ONE_MINUS_CONSTANT_ALPHA:
return "GL_ONE_MINUS_CONSTANT_ALPHA";
default:
}
// shader stuff
switch (glEnum)
{
case GL_VERTEX_SHADER:
return "GL_VERTEX_SHADER";
case GL_GEOMETRY_SHADER:
return "GL_GEOMETRY_SHADER";
case GL_FRAGMENT_SHADER:
return "GL_FRAGMENT_SHADER";
default:
}
// stencil stuff
switch (glEnum)
{
case GL_KEEP:
return "GL_KEEP";
case GL_ZERO:
return "GL_ZERO";
case GL_REPLACE:
return "GL_REPLACE";
case GL_INCR:
return "GL_INCR";
case GL_DECR:
return "GL_DECR";
case GL_INVERT:
return "GL_INVERT";
case GL_INCR_WRAP:
return "GL_INCR_WRAP";
case GL_DECR_WRAP:
return "GL_DECR_WRAP";
default:
}
// depth stuff
switch (glEnum)
{
case GL_NEVER:
return "GL_NEVER";
case GL_LESS:
return "GL_LESS";
case GL_EQUAL:
return "GL_EQUAL";
case GL_LEQUAL:
return "GL_LEQUAL";
case GL_GREATER:
return "GL_GREATER";
case GL_NOTEQUAL:
return "GL_NOTEQUAL";
case GL_GEQUAL:
return "GL_GEQUAL";
case GL_ALWAYS:
return "GL_ALWAYS";
default:
}
// Texture binding points
switch (glEnum)
{
case GL_TEXTURE0:
return "GL_TEXTURE0";
case GL_TEXTURE1:
return "GL_TEXTURE1";
case GL_TEXTURE2:
return "GL_TEXTURE2";
case GL_TEXTURE3:
return "GL_TEXTURE3";
case GL_TEXTURE4:
return "GL_TEXTURE4";
case GL_TEXTURE5:
return "GL_TEXTURE5";
case GL_TEXTURE6:
return "GL_TEXTURE6";
case GL_TEXTURE7:
return "GL_TEXTURE7";
case GL_TEXTURE8:
return "GL_TEXTURE8";
case GL_TEXTURE9:
return "GL_TEXTURE9";
case GL_TEXTURE10:
return "GL_TEXTURE10";
case GL_TEXTURE11:
return "GL_TEXTURE11";
case GL_TEXTURE12:
return "GL_TEXTURE12";
case GL_TEXTURE13:
return "GL_TEXTURE13";
case GL_TEXTURE14:
return "GL_TEXTURE14";
case GL_TEXTURE15:
return "GL_TEXTURE15";
case GL_TEXTURE16:
return "GL_TEXTURE16";
case GL_TEXTURE17:
return "GL_TEXTURE17";
case GL_TEXTURE18:
return "GL_TEXTURE18";
case GL_TEXTURE19:
return "GL_TEXTURE19";
case GL_TEXTURE20:
return "GL_TEXTURE20";
case GL_TEXTURE21:
return "GL_TEXTURE21";
case GL_TEXTURE22:
return "GL_TEXTURE22";
case GL_TEXTURE23:
return "GL_TEXTURE23";
case GL_TEXTURE24:
return "GL_TEXTURE24";
case GL_TEXTURE25:
return "GL_TEXTURE25";
case GL_TEXTURE26:
return "GL_TEXTURE26";
case GL_TEXTURE27:
return "GL_TEXTURE27";
case GL_TEXTURE28:
return "GL_TEXTURE28";
case GL_TEXTURE29:
return "GL_TEXTURE29";
case GL_TEXTURE30:
return "GL_TEXTURE30";
case GL_TEXTURE31:
return "GL_TEXTURE31";
default:
}
// Polygon modes
switch (glEnum)
{
case GL_POINT:
return "GL_POINT";
case GL_LINE:
return "GL_LINE";
case GL_FILL:
return "GL_FILL";
default:
}
// Culling modes
switch (glEnum)
{
case GL_FRONT:
return "GL_FRONT";
case GL_BACK:
return "GL_BACK";
case GL_FRONT_AND_BACK:
return "GL_FRONT_AND_BACK";
default:
}
// Types
switch (glEnum)
{
case GL_BYTE:
return "GL_BYTE";
case GL_UNSIGNED_BYTE:
return "GL_UNSIGNED_BYTE";
case GL_SHORT:
return "GL_SHORT";
case GL_UNSIGNED_SHORT:
return "GL_UNSIGNED_SHORT";
case GL_INT:
return "GL_INT";
case GL_UNSIGNED_INT:
return "GL_UNSIGNED_INT";
case GL_FLOAT:
return "GL_FLOAT";
case GL_DOUBLE:
return "GL_DOUBLE";
default:
}
return "GL_UNKNOWN(" + glEnum + ")";
}
public static int getTypeSize(int glTypeEnum)
{
switch (glTypeEnum)
{
case GL_BYTE:
case GL_UNSIGNED_BYTE:
return 1;
case GL_SHORT:
case GL_UNSIGNED_SHORT:
return 2;
case GL_INT:
case GL_UNSIGNED_INT:
return 4;
case GL_FLOAT:
return 4;
case GL_DOUBLE:
return 8;
default:
throw new IllegalArgumentException("Unknown type enum: " + getString(glTypeEnum));
}
}
}
@@ -1,184 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.glObject.shader;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import org.lwjgl.PointerBuffer;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL32C;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.system.NativeType;
/**
* This object holds a OpenGL reference to a shader
* and allows for reading in and compiling a shader file.
*/
public class GlShader
{
private static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
.build();
/** OpenGL shader ID */
public final int id;
//==============//
// constructors //
//==============//
//region
/**
* Creates a shader with specified type.
*
* @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
* @param sourceString File path of the shader
* @throws RuntimeException if the shader fails to compile
*/
public GlShader(int type, String sourceString)
{
LOGGER.info("Loading shader with type: ["+type+"]");
LOGGER.debug("Source: \n["+sourceString+"]");
if (sourceString == null || sourceString.isEmpty())
{
throw new IllegalArgumentException("No shader source given.");
}
// Create an empty shader object
this.id = GL32.glCreateShader(type);
if (this.id == 0)
{
throw new IllegalArgumentException("Failed to create shader with type ["+type+"] and Source: \n["+sourceString+"].");
}
safeShaderSource(this.id, sourceString);
GL32.glCompileShader(this.id);
// check if the shader compiled
int status = GL32.glGetShaderi(this.id, GL32.GL_COMPILE_STATUS);
if (status != GL32.GL_TRUE)
{
String message = "Shader compiler error. Details: [" + GL32.glGetShaderInfoLog(this.id) + "]\n";
message += "Source: \n[" + sourceString + "]";
this.free(); // important!
throw new RuntimeException(message);
}
LOGGER.info("Shader loaded sucessfully.");
}
//endregion
//=========//
// helpers //
//=========//
//region
/**
* Identical in function to {@link GL32C#glShaderSource(int, CharSequence)} but
* passes a null pointer for string length to force the driver to rely on the null
* terminator for string length. This is a workaround for an apparent flaw with some
* AMD drivers that don't receive or interpret the length correctly, resulting in
* an access violation when the driver tries to read past the string memory.
*
* <p>Hat tip to fewizz for the find and the fix.
*
* <p>Source: https://github.com/vram-guild/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96
*/
private static void safeShaderSource(@NativeType("GLuint") int glId, @NativeType("GLchar const **") CharSequence source)
{
final MemoryStack stack = MemoryStack.stackGet();
final int stackPointer = stack.getPointer();
try
{
final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true);
final PointerBuffer pointers = stack.mallocPointer(1);
pointers.put(sourceBuffer);
GL32.nglShaderSource(glId, 1, pointers.address0(), 0);
org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1);
}
finally
{
stack.setPointer(stackPointer);
}
}
public void free() { GL32.glDeleteShader(this.id); }
public static String loadFile(String path, boolean absoluteFilePath)
{
StringBuilder stringBuilder = new StringBuilder();
try
{
// open the file
InputStream in;
if (absoluteFilePath)
{
// Throws FileNotFoundException
in = new FileInputStream(path); // Note: this should use OS path seperator
}
else
{
in = GlShader.class.getClassLoader().getResourceAsStream(path); // Note: path seperator should be '/'
if (in == null)
{
throw new FileNotFoundException("Shader file not found in resource: " + path);
}
}
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
// read in the file
String line;
while ((line = reader.readLine()) != null)
{
stringBuilder.append(line).append("\n");
}
}
catch (IOException e)
{
throw new RuntimeException("Unable to load shader from file [" + path + "]. Error: " + e.getMessage());
}
return stringBuilder.toString();
}
//endregion
}
@@ -1,225 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.common.render.openGl.glObject.shader;
import java.awt.Color;
import java.nio.FloatBuffer;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryStack;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3f;
/**
* This object holds the reference to a OpenGL shader program
* and contains a few methods that can be used with OpenGL shader programs.
* The reason for many of these simple wrapper methods is as reminders of what
* can (and needs to be) done with a shader program.
*/
public class GlShaderProgram
{
/** Stores the handle of the program. */
public final int id;
//=============//
// constructor //
//=============//
//region
public GlShaderProgram(String vertResourcePath, String fragResourcePath, String attribute) { this(vertResourcePath, fragResourcePath, new String[]{ attribute }); }
/**
* @param vertResourcePath the relative path the vertex shader should be found
* @param fragResourcePath the relative path the fragment shader should be found
*/
public GlShaderProgram(String vertResourcePath, String fragResourcePath, String[] attributes)
{
this.id = GL32.glCreateProgram();
{
String shaderString = GlShader.loadFile(vertResourcePath, false);
GlShader vertShader = new GlShader(GL32.GL_VERTEX_SHADER, shaderString);
GL32.glAttachShader(this.id, vertShader.id);
vertShader.free();
}
{
String shaderString = GlShader.loadFile(fragResourcePath, false);
GlShader fragShader = new GlShader(GL32.GL_FRAGMENT_SHADER, shaderString);
GL32.glAttachShader(this.id, fragShader.id);
fragShader.free();
}
for (int i = 0; i < attributes.length; i++)
{
GL32.glBindAttribLocation(this.id, i, attributes[i]);
}
GL32.glLinkProgram(this.id);
int status = GL32.glGetProgrami(this.id, GL32.GL_LINK_STATUS);
if (status != GL32.GL_TRUE)
{
String message = "Shader Link Error. Details: " + GL32.glGetProgramInfoLog(this.id);
this.free(); // important!
throw new RuntimeException(message);
}
GL32.glUseProgram(this.id); // This HAVE to be a direct call to prevent calling the overloaded version
}
//endregion
//=========//
// binding //
//=========//
//region
public void bind() { GL32.glUseProgram(this.id); }
public void unbind() { GL32.glUseProgram(0); }
public void free() { GL32.glDeleteProgram(this.id); }
//endregion
//============//
// attributes //
//============//
//region
/**
* WARNING: Slow native call! Cache it if possible!
* Gets the location of an attribute variable with specified name.
* Calls GL20.glGetAttribLocation(id, name)
*
* @param name Attribute name
* @return Location of the attribute
* @throws RuntimeException if attribute not found
*/
public int getAttributeLocation(CharSequence name)
{
int i = GL32.glGetAttribLocation(id, name);
if (i == -1) throw new RuntimeException("Attribute name not found: " + name);
return i;
}
/**
* Same as above but without throwing errors. <br>
* Returns -1 if the attribute doesn't exist or has been optimized out.
*/
public int tryGetAttributeLocation(CharSequence name)
{ return GL32.glGetAttribLocation(this.id, name); }
//endregion
//==========//
// uniforms //
//==========//
//region
/**
* WARNING: Slow native call! Cache it if possible!
* Gets the location of a uniform variable with specified name.
* Calls GL20.glGetUniformLocation(id, name)
*
* @param name Uniform name
* @return Location of the Uniform
* @throws RuntimeException if uniform not found
*/
public int getUniformLocation(CharSequence name) throws RuntimeException
{
int i = GL32.glGetUniformLocation(id, name);
if (i == -1)
{
throw new RuntimeException("Uniform name not found: " + name);
}
return i;
}
// Same as above but without throwing errors.
// Return -1 if uniform doesn't exist or has been optimized out
public int tryGetUniformLocation(CharSequence name)
{ return GL32.glGetUniformLocation(this.id, name); }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, boolean value) { GL32.glUniform1i(location, value ? 1 : 0); }
/** @see GlShaderProgram#setUniform(int, boolean) */
public void trySetUniform(int location, boolean value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, int value) { GL32.glUniform1i(location, value); }
/** @see GlShaderProgram#setUniform(int, int) */
public void trySetUniform(int location, int value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, float value) { GL32.glUniform1f(location, value); }
/** @see GlShaderProgram#setUniform(int, float) */
public void trySetUniform(int location, float value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, Vec3f value) { GL32.glUniform3f(location, value.x, value.y, value.z); }
/** @see GlShaderProgram#setUniform(int, Vec3f) */
public void trySetUniform(int location, Vec3f value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, DhApiVec3i value) { GL32.glUniform3i(location, value.x, value.y, value.z); }
/** @see GlShaderProgram#setUniform(int, Mat4f) */
public void trySetUniform(int location, DhApiVec3i value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, Mat4f value)
{
try (MemoryStack stack = MemoryStack.stackPush())
{
FloatBuffer buffer = stack.mallocFloat(4 * 4);
value.store(buffer);
GL32.glUniformMatrix4fv(location, false, buffer);
}
}
/** @see GlShaderProgram#setUniform(int, Mat4f) */
public void trySetUniform(int location, Mat4f value) { if (location != -1) { this.setUniform(location, value); } }
/**
* Converts the color's RGBA values into values between 0 and 1. <br>
* Requires a bound ShaderProgram.
*/
public void setUniform(int location, Color value)
{
GL32.glUniform4f(location,
value.getRed() / 256.0f,
value.getGreen() / 256.0f,
value.getBlue() / 256.0f,
value.getAlpha() / 256.0f);
}
/** @see GlShaderProgram#setUniform(int, Color) */
public void trySetUniform(int location, Color value) { if (location != -1) { this.setUniform(location, value); } }
//endregion
}
@@ -1,114 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL30C;
import org.lwjgl.opengl.GL43C;
public enum EGlDhDepthBufferFormat
{
DEPTH(false),
DEPTH16(false),
DEPTH24(false),
DEPTH32(false),
DEPTH32F(false),
DEPTH_STENCIL(true),
DEPTH24_STENCIL8(true),
DEPTH32F_STENCIL8(true);
private final boolean combinedStencil;
EGlDhDepthBufferFormat(boolean combinedStencil) { this.combinedStencil = combinedStencil; }
@Nullable
public static EGlDhDepthBufferFormat fromGlEnum(int glenum)
{
switch (glenum)
{
case GL30C.GL_DEPTH_COMPONENT:
return EGlDhDepthBufferFormat.DEPTH;
case GL30C.GL_DEPTH_COMPONENT16:
return EGlDhDepthBufferFormat.DEPTH16;
case GL30C.GL_DEPTH_COMPONENT24:
return EGlDhDepthBufferFormat.DEPTH24;
case GL30C.GL_DEPTH_COMPONENT32:
return EGlDhDepthBufferFormat.DEPTH32;
case GL30C.GL_DEPTH_COMPONENT32F:
return EGlDhDepthBufferFormat.DEPTH32F;
case GL30C.GL_DEPTH_STENCIL:
return EGlDhDepthBufferFormat.DEPTH_STENCIL;
case GL30C.GL_DEPTH24_STENCIL8:
return EGlDhDepthBufferFormat.DEPTH24_STENCIL8;
case GL30C.GL_DEPTH32F_STENCIL8:
return EGlDhDepthBufferFormat.DEPTH32F_STENCIL8;
default:
return null;
}
}
public static EGlDhDepthBufferFormat fromGlEnumOrDefault(int glenum)
{
EGlDhDepthBufferFormat format = fromGlEnum(glenum);
if (format == null)
{
// yolo, just assume it's GL_DEPTH_COMPONENT
return EGlDhDepthBufferFormat.DEPTH;
}
return format;
}
public int getGlInternalFormat()
{
switch (this)
{
case DEPTH:
return GL30C.GL_DEPTH_COMPONENT;
case DEPTH16:
return GL30C.GL_DEPTH_COMPONENT16;
case DEPTH24:
return GL30C.GL_DEPTH_COMPONENT24;
case DEPTH32:
return GL30C.GL_DEPTH_COMPONENT32;
case DEPTH32F:
return GL30C.GL_DEPTH_COMPONENT32F;
case DEPTH_STENCIL:
return GL30C.GL_DEPTH_STENCIL;
case DEPTH24_STENCIL8:
return GL30C.GL_DEPTH24_STENCIL8;
case DEPTH32F_STENCIL8:
return GL30C.GL_DEPTH32F_STENCIL8;
}
throw new AssertionError("unreachable");
}
public int getGlType() { return isCombinedStencil() ? GL30C.GL_DEPTH_STENCIL : GL30C.GL_DEPTH_COMPONENT; }
public int getGlFormat()
{
switch (this)
{
case DEPTH:
case DEPTH16:
return GL43C.GL_UNSIGNED_SHORT;
case DEPTH24:
case DEPTH32:
return GL43C.GL_UNSIGNED_INT;
case DEPTH32F:
return GL30C.GL_FLOAT;
case DEPTH_STENCIL:
case DEPTH24_STENCIL8:
return GL30C.GL_UNSIGNED_INT_24_8;
case DEPTH32F_STENCIL8:
return GL30C.GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
}
throw new AssertionError("unreachable");
}
public boolean isCombinedStencil() { return combinedStencil; }
}
@@ -1,131 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.EGlVersion;
import org.lwjgl.opengl.GL11C;
import org.lwjgl.opengl.GL30C;
import org.lwjgl.opengl.GL31C;
import java.util.Locale;
import java.util.Optional;
public enum EGlDhInternalTextureFormat
{
RGBA(GL11C.GL_RGBA, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
// 8-bit normalized
R8(GL30C.GL_R8, EGlVersion.GL_30, EGlDhPixelFormat.RED),
RG8(GL30C.GL_RG8, EGlVersion.GL_30, EGlDhPixelFormat.RG),
RGB8(GL11C.GL_RGB8, EGlVersion.GL_11, EGlDhPixelFormat.RGB),
RGBA8(GL11C.GL_RGBA8, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
// 8-bit signed normalized
R8_SNORM(GL31C.GL_R8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RED),
RG8_SNORM(GL31C.GL_RG8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RG),
RGB8_SNORM(GL31C.GL_RGB8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGB),
RGBA8_SNORM(GL31C.GL_RGBA8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGBA),
// 16-bit normalized
R16(GL30C.GL_R16, EGlVersion.GL_30, EGlDhPixelFormat.RED),
RG16(GL30C.GL_RG16, EGlVersion.GL_30, EGlDhPixelFormat.RG),
RGB16(GL11C.GL_RGB16, EGlVersion.GL_11, EGlDhPixelFormat.RGB),
RGBA16(GL11C.GL_RGBA16, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
// 16-bit signed normalized
R16_SNORM(GL31C.GL_R16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RED),
RG16_SNORM(GL31C.GL_RG16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RG),
RGB16_SNORM(GL31C.GL_RGB16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGB),
RGBA16_SNORM(GL31C.GL_RGBA16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGBA),
// 16-bit float
R16F(GL30C.GL_R16F, EGlVersion.GL_30, EGlDhPixelFormat.RED),
RG16F(GL30C.GL_RG16F, EGlVersion.GL_30, EGlDhPixelFormat.RG),
RGB16F(GL30C.GL_RGB16F, EGlVersion.GL_30, EGlDhPixelFormat.RGB),
RGBA16F(GL30C.GL_RGBA16F, EGlVersion.GL_30, EGlDhPixelFormat.RGBA),
// 32-bit float
R32F(GL30C.GL_R32F, EGlVersion.GL_30, EGlDhPixelFormat.RED),
RG32F(GL30C.GL_RG32F, EGlVersion.GL_30, EGlDhPixelFormat.RG),
RGB32F(GL30C.GL_RGB32F, EGlVersion.GL_30, EGlDhPixelFormat.RGB),
RGBA32F(GL30C.GL_RGBA32F, EGlVersion.GL_30, EGlDhPixelFormat.RGBA),
// 8-bit integer
R8I(GL30C.GL_R8I, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG8I(GL30C.GL_RG8I, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB8I(GL30C.GL_RGB8I, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA8I(GL30C.GL_RGBA8I, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 8-bit unsigned integer
R8UI(GL30C.GL_R8UI, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG8UI(GL30C.GL_RG8UI, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB8UI(GL30C.GL_RGB8UI, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA8UI(GL30C.GL_RGBA8UI, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 16-bit integer
R16I(GL30C.GL_R16I, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG16I(GL30C.GL_RG16I, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB16I(GL30C.GL_RGB16I, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA16I(GL30C.GL_RGBA16I, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 16-bit unsigned integer
R16UI(GL30C.GL_R16UI, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG16UI(GL30C.GL_RG16UI, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB16UI(GL30C.GL_RGB16UI, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA16UI(GL30C.GL_RGBA16UI, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 32-bit integer
R32I(GL30C.GL_R32I, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG32I(GL30C.GL_RG32I, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB32I(GL30C.GL_RGB32I, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA32I(GL30C.GL_RGBA32I, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 32-bit unsigned integer
R32UI(GL30C.GL_R32UI, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG32UI(GL30C.GL_RG32UI, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB32UI(GL30C.GL_RGB32UI, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA32UI(GL30C.GL_RGBA32UI, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// Mixed
R3_G3_B2(GL11C.GL_R3_G3_B2, EGlVersion.GL_11, EGlDhPixelFormat.RGB),
RGB5_A1(GL11C.GL_RGB5_A1, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
RGB10_A2(GL11C.GL_RGB10_A2, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
R11F_G11F_B10F(GL30C.GL_R11F_G11F_B10F, EGlVersion.GL_30, EGlDhPixelFormat.RGB),
RGB9_E5(GL30C.GL_RGB9_E5, EGlVersion.GL_30, EGlDhPixelFormat.RGB);
private final int glFormat;
private final EGlVersion minimumGlVersion;
private final EGlDhPixelFormat expectedPixelFormat;
EGlDhInternalTextureFormat(int glFormat, EGlVersion minimumGlVersion, EGlDhPixelFormat expectedPixelFormat)
{
this.glFormat = glFormat;
this.minimumGlVersion = minimumGlVersion;
this.expectedPixelFormat = expectedPixelFormat;
}
public static Optional<EGlDhInternalTextureFormat> fromString(String name)
{
try
{
return Optional.of(EGlDhInternalTextureFormat.valueOf(name.toUpperCase(Locale.US)));
}
catch (IllegalArgumentException e)
{
return Optional.empty();
}
}
public int getGlFormat() { return this.glFormat; }
public EGlDhPixelFormat getPixelFormat() { return this.expectedPixelFormat; }
public EGlVersion getMinimumGlVersion() { return this.minimumGlVersion; }
}

Some files were not shown because too many files have changed in this diff Show More