diff options
Diffstat (limited to 'ardor3d-jogl')
41 files changed, 10733 insertions, 0 deletions
diff --git a/ardor3d-jogl/.settings/org.eclipse.jdt.core.prefs b/ardor3d-jogl/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..7858c9b --- /dev/null +++ b/ardor3d-jogl/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,276 @@ +#Tue Apr 06 11:30:42 CDT 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.codeComplete.argumentPrefixes= +org.eclipse.jdt.core.codeComplete.argumentSuffixes= +org.eclipse.jdt.core.codeComplete.fieldPrefixes=_ +org.eclipse.jdt.core.codeComplete.fieldSuffixes= +org.eclipse.jdt.core.codeComplete.localPrefixes= +org.eclipse.jdt.core.codeComplete.localSuffixes= +org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=1 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=120 +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=120 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true diff --git a/ardor3d-jogl/.settings/org.eclipse.jdt.ui.prefs b/ardor3d-jogl/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000..f479490 --- /dev/null +++ b/ardor3d-jogl/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,114 @@ +#Sun Jan 04 11:43:23 CST 2009
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=true
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_serial_version_id=true
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=true
+cleanup.format_source_code=true
+cleanup.format_source_code_changes_only=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup_profile=_ArdorLabs
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_ArdorLabs
+formatter_settings_version=11
+org.eclipse.jdt.ui.exception.name=ex
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.javadoc=false
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\r\n * @return the ${bare_field_name}\r\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\r\n * @param ${param} the ${bare_field_name} to set\r\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\r\n * \r\n */</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\r\n * ${tags}\r\n * ${see_to_target}\r\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">/**\r\n * Copyright (c) 2008-2010 Ardor Labs, Inc.\r\n *\r\n * This file is part of Ardor3D.\r\n *\r\n * Ardor3D is free software\: you can redistribute it and/or modify it \r\n * under the terms of its license which may be found in the accompanying\r\n * LICENSE file or at <http\://www.ardor3d.com/LICENSE>.\r\n */\r\n\r\n${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\r\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\r\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\r\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\r\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\r\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\r\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=true
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=true
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/ardor3d-jogl/pom.xml b/ardor3d-jogl/pom.xml new file mode 100644 index 0000000..56c0800 --- /dev/null +++ b/ardor3d-jogl/pom.xml @@ -0,0 +1,52 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.ardor3d</groupId>
+ <artifactId>ardor3d</artifactId>
+ <relativePath>../pom.xml</relativePath>
+ <version>0.9-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>ardor3d-jogl</artifactId>
+ <packaging>bundle</packaging>
+ <name>Ardor 3D JOGL</name>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ardor3d-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jogamp.gluegen</groupId>
+ <artifactId>gluegen-rt-main</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jogamp.jogl</groupId>
+ <artifactId>jogl-all-main</artifactId>
+ </dependency>
+ <!--
+ <dependency>
+ <groupId>org.jogamp.joal</groupId>
+ <artifactId>joal-main</artifactId>
+ <version>2.0-rc11</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jogamp.jocl</groupId>
+ <artifactId>jocl-main</artifactId>
+ <version>2.0-rc11</version>
+ </dependency> -->
+ </dependencies>
+</project>
+
diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/CapsUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/CapsUtil.java new file mode 100644 index 0000000..c23b8a0 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/CapsUtil.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.framework.jogl; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; + +import com.ardor3d.framework.DisplaySettings; +import com.ardor3d.util.Ardor3dException; + +public class CapsUtil { + + public static GLCapabilities getCapsForSettings(final DisplaySettings settings) { + + // Validate window dimensions. + if (settings.getWidth() <= 0 || settings.getHeight() <= 0) { + throw new Ardor3dException("Invalid resolution values: " + settings.getWidth() + " " + settings.getHeight()); + } + + // Validate bit depth. + if ((settings.getColorDepth() != 32) && (settings.getColorDepth() != 16) && (settings.getColorDepth() != 24) + && (settings.getColorDepth() != -1)) { + throw new Ardor3dException("Invalid pixel depth: " + settings.getColorDepth()); + } + + final GLCapabilities caps = new GLCapabilities(GLProfile.getMaxFixedFunc(true)); + caps.setHardwareAccelerated(true); + caps.setDoubleBuffered(true); + caps.setAlphaBits(settings.getAlphaBits()); + caps.setDepthBits(settings.getDepthBits()); + caps.setNumSamples(settings.getSamples()); + caps.setSampleBuffers(settings.getSamples() != 0); + caps.setStereo(settings.isStereo()); + caps.setStencilBits(settings.getStencilBits()); + return caps; + } + +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglAwtCanvas.java b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglAwtCanvas.java new file mode 100644 index 0000000..5c95cd8 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglAwtCanvas.java @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.framework.jogl; + +import java.util.concurrent.CountDownLatch; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLRunnable; +import javax.media.opengl.awt.GLCanvas; +import com.ardor3d.annotation.MainThread; +import com.ardor3d.framework.Canvas; +import com.ardor3d.framework.DisplaySettings; + +/** + * FIXME there is still a deadlock when using several instances of this class in the same container, see JOGL bug 572 + * Rather use JoglNewtAwtCanvas in this case. + * + */ +public class JoglAwtCanvas extends GLCanvas implements Canvas { + + private static final long serialVersionUID = 1L; + + private final JoglCanvasRenderer _canvasRenderer; + private boolean _inited = false; + + private final DisplaySettings _settings; + + private final JoglDrawerRunnable _drawerGLRunnable; + + public JoglAwtCanvas(final DisplaySettings settings, final JoglCanvasRenderer canvasRenderer) { + super(CapsUtil.getCapsForSettings(settings)); + _drawerGLRunnable = new JoglDrawerRunnable(canvasRenderer); + _settings = settings; + _canvasRenderer = canvasRenderer; + + setFocusable(true); + requestFocus(); + setSize(_settings.getWidth(), _settings.getHeight()); + setIgnoreRepaint(true); + setAutoSwapBufferMode(false); + } + + @MainThread + public void init() { + if (_inited) { + return; + } + + // Make the window visible to realize the OpenGL surface. + setVisible(true); + + // Request the focus here as it cannot work when the window is not visible + requestFocus(); + + _canvasRenderer.setContext(getContext()); + + invoke(true, new GLRunnable() { + @Override + public boolean run(GLAutoDrawable glAutoDrawable) { + _canvasRenderer.init(_settings, true);// true - do swap in renderer. + return true; + } + }); + _inited = true; + } + + public void draw(final CountDownLatch latch) { + if (!_inited) { + init(); + } + + if (isShowing()) { + invoke(true, _drawerGLRunnable); + } + if (latch != null) { + latch.countDown(); + } + } + + public JoglCanvasRenderer getCanvasRenderer() { + return _canvasRenderer; + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglCanvas.java b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglCanvas.java new file mode 100644 index 0000000..c08396b --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglCanvas.java @@ -0,0 +1,285 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.framework.jogl; + +import java.awt.Dimension; +import java.awt.DisplayMode; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Toolkit; +import java.awt.event.FocusListener; +import java.awt.event.KeyListener; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.concurrent.CountDownLatch; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLException; +import javax.media.opengl.GLRunnable; + +import com.ardor3d.annotation.MainThread; +import com.ardor3d.framework.CanvasRenderer; +import com.ardor3d.framework.DisplaySettings; +import com.ardor3d.framework.NativeCanvas; +import com.ardor3d.image.Image; +import com.ardor3d.renderer.jogl.JoglPbufferTextureRenderer; + +/** + * A canvas implementation for use with native JOGL windows. + */ +public class JoglCanvas extends Frame implements NativeCanvas { + + private static final long serialVersionUID = 1L; + + private static final Logger logger = Logger.getLogger(JoglCanvas.class.getName()); + + private final DisplaySettings _settings; + private boolean _inited = false; + private boolean _isClosing = false; + + private JoglAwtCanvas _glCanvas; + + public JoglCanvas(final JoglCanvasRenderer canvasRenderer, final DisplaySettings settings) { + _settings = settings; + + // Create the OpenGL canvas + _glCanvas = new JoglAwtCanvas(_settings, canvasRenderer); + + // Default is not-resizeable. If you turn on resizeable, know what you are doing. + setResizable(false); + } + + @Override + public void addKeyListener(final KeyListener l) { + _glCanvas.addKeyListener(l); + } + + @Override + public void addMouseListener(final MouseListener l) { + _glCanvas.addMouseListener(l); + } + + @Override + public void addMouseMotionListener(final MouseMotionListener l) { + _glCanvas.addMouseMotionListener(l); + } + + @Override + public void addMouseWheelListener(final MouseWheelListener l) { + _glCanvas.addMouseWheelListener(l); + } + + @Override + public void addFocusListener(final FocusListener l) { + _glCanvas.addFocusListener(l); + } + + @MainThread + public void init() { + privateInit(); + } + + @MainThread + protected void privateInit() { + if (_inited) { + return; + } + + // FIXME: remove need for directly setting _parentContext. + JoglPbufferTextureRenderer._parentContext = _glCanvas.getContext(); + + this.add(_glCanvas); + + final boolean isDisplayModeModified; + final GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); + // Get the current display mode + final DisplayMode previousDisplayMode = gd.getDisplayMode(); + // Handle full screen mode if requested. + if (_settings.isFullScreen()) { + setUndecorated(true); + // Check if the full-screen mode is supported by the OS + boolean isFullScreenSupported = gd.isFullScreenSupported(); + if (isFullScreenSupported) { + gd.setFullScreenWindow(this); + // Check if display mode changes are supported by the OS + if (gd.isDisplayChangeSupported()) { + // Get all available display modes + final DisplayMode[] displayModes = gd.getDisplayModes(); + DisplayMode multiBitsDepthSupportedDisplayMode = null; + DisplayMode refreshRateUnknownDisplayMode = null; + DisplayMode multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode = null; + DisplayMode matchingDisplayMode = null; + DisplayMode currentDisplayMode; + // Look for the display mode that matches with our parameters + // Look for some display modes that are close to these parameters + // and that could be used as substitutes + // On some machines, the refresh rate is unknown and/or multi bit + // depths are supported. If you try to force a particular refresh + // rate or a bit depth, you might find no available display mode + // that matches exactly with your parameters + for (int i = 0; i < displayModes.length && matchingDisplayMode == null; i++) { + currentDisplayMode = displayModes[i]; + if (currentDisplayMode.getWidth() == _settings.getWidth() + && currentDisplayMode.getHeight() == _settings.getHeight()) { + if (currentDisplayMode.getBitDepth() == _settings.getColorDepth()) { + if (currentDisplayMode.getRefreshRate() == _settings.getFrequency()) { + matchingDisplayMode = currentDisplayMode; + } else if (currentDisplayMode.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN) { + refreshRateUnknownDisplayMode = currentDisplayMode; + } + } else if (currentDisplayMode.getBitDepth() == DisplayMode.BIT_DEPTH_MULTI) { + if (currentDisplayMode.getRefreshRate() == _settings.getFrequency()) { + multiBitsDepthSupportedDisplayMode = currentDisplayMode; + } else if (currentDisplayMode.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN) { + multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode = currentDisplayMode; + } + } + } + } + DisplayMode nextDisplayMode = null; + if (matchingDisplayMode != null) { + nextDisplayMode = matchingDisplayMode; + } else if (multiBitsDepthSupportedDisplayMode != null) { + nextDisplayMode = multiBitsDepthSupportedDisplayMode; + } else if (refreshRateUnknownDisplayMode != null) { + nextDisplayMode = refreshRateUnknownDisplayMode; + } else if (multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode != null) { + nextDisplayMode = multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode; + } else { + isFullScreenSupported = false; + } + // If we have found a display mode that approximatively matches + // with the input parameters, use it + if (nextDisplayMode != null) { + gd.setDisplayMode(nextDisplayMode); + isDisplayModeModified = true; + } else { + isDisplayModeModified = false; + } + } else { + isDisplayModeModified = false; + // Resize the canvas if the display mode cannot be changed + // and the screen size is not equal to the canvas size + final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + if (screenSize.width != _settings.getWidth() || screenSize.height != _settings.getHeight()) { + _glCanvas.setSize(screenSize); + } + } + } else { + isDisplayModeModified = false; + } + + // Software windowed full-screen mode + if (!isFullScreenSupported) { + final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + // Resize the canvas + _glCanvas.setSize(screenSize); + // Resize the frame so that it occupies the whole screen + this.setSize(screenSize); + // Set its location at the top left corner + this.setLocation(0, 0); + } + } + // Otherwise, center the window on the screen. + else { + isDisplayModeModified = false; + pack(); + + int x, y; + x = (Toolkit.getDefaultToolkit().getScreenSize().width - _settings.getWidth()) / 2; + y = (Toolkit.getDefaultToolkit().getScreenSize().height - _settings.getHeight()) / 2; + this.setLocation(x, y); + } + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(final WindowEvent e) { + _isClosing = true; + // If required, restore the previous display mode + if (isDisplayModeModified) { + gd.setDisplayMode(previousDisplayMode); + } + // If required, get back to the windowed mode + if (gd.getFullScreenWindow() == JoglCanvas.this) { + gd.setFullScreenWindow(null); + } + } + }); + + // Make the window visible to realize the OpenGL surface. + setVisible(true); + + _glCanvas.init(); // true - do swap in renderer. + _inited = true; + } + + public void draw(final CountDownLatch latch) { + if (!_inited) { + privateInit(); + } + + _glCanvas.draw(latch); + } + + public CanvasRenderer getCanvasRenderer() { + return _glCanvas.getCanvasRenderer(); + } + + public void close() { + try { + if (GLContext.getCurrent() != null) { + // Release the OpenGL resources. + GLContext.getCurrent().release(); + } + } catch (final GLException releaseFailure) { + logger.log(Level.WARNING, "Failed to release OpenGL Context: " + _glCanvas, releaseFailure); + } finally { + _glCanvas = null; + } + + // Dispose of any window resources. + dispose(); + } + + @Override + public boolean isActive() { + return hasFocus(); + } + + public boolean isClosing() { + return _isClosing; + } + + public void moveWindowTo(final int locX, final int locY) { + setLocation(locX, locY); + } + + public void setIcon(final Image[] iconImages) { + // FIXME not implemented + } + + public void setVSyncEnabled(final boolean enabled) { + _glCanvas.invoke(true, new GLRunnable() { + @Override + public boolean run(GLAutoDrawable glAutoDrawable) { + _glCanvas.getGL().setSwapInterval(enabled ? 1 : 0); + return false; + } + }); + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglCanvasRenderer.java b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglCanvasRenderer.java new file mode 100644 index 0000000..e6d8b00 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglCanvasRenderer.java @@ -0,0 +1,250 @@ +/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.framework.jogl;
+
+import java.util.logging.Logger;
+
+import javax.media.opengl.DebugGL2;
+import javax.media.opengl.GL;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.glu.GLU;
+
+import com.ardor3d.annotation.MainThread;
+import com.ardor3d.framework.CanvasRenderer;
+import com.ardor3d.framework.DisplaySettings;
+import com.ardor3d.framework.Scene;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.RenderContext;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.Camera.ProjectionMode;
+import com.ardor3d.renderer.jogl.JoglContextCapabilities;
+import com.ardor3d.renderer.jogl.JoglRenderer;
+import com.ardor3d.util.Ardor3dException;
+
+public class JoglCanvasRenderer implements CanvasRenderer {
+
+ private static final Logger LOGGER = Logger.getLogger(JoglCanvasRenderer.class.getName());
+
+ protected Scene _scene;
+ protected Camera _camera;
+ protected boolean _doSwap;
+ protected GLContext _context;
+ protected JoglRenderer _renderer;
+ protected int _frameClear = Renderer.BUFFER_COLOR_AND_DEPTH;
+
+ private RenderContext _currentContext;
+
+ /**
+ * <code>true</code> if debugging (checking for error codes on each GL call) is desired.
+ */
+ private final boolean _useDebug;
+
+ /**
+ * <code>true</code> if debugging is currently enabled for this GLContext.
+ */
+ private boolean _debugEnabled = false;
+
+ public JoglCanvasRenderer(final Scene scene) {
+ this(scene, false);
+ }
+
+ public JoglCanvasRenderer(final Scene scene, final boolean useDebug) {
+ _scene = scene;
+ _useDebug = useDebug;
+ }
+
+ public void makeCurrentContext() throws Ardor3dException {
+ int value = GLContext.CONTEXT_NOT_CURRENT;
+ int attempt = 0;
+ do {
+ try {
+ value = _context.makeCurrent();
+ } catch(GLException gle) {
+ gle.printStackTrace();
+ } finally {
+ attempt++;
+ if (attempt == MAX_CONTEXT_GRAB_ATTEMPTS) {
+ // failed, throw exception
+ throw new Ardor3dException("Failed to claim OpenGL context.");
+ }
+ }
+ try {
+ Thread.sleep(5);
+ } catch (final InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ }
+ while(value == GLContext.CONTEXT_NOT_CURRENT);
+ if (value == GLContext.CONTEXT_CURRENT_NEW) {
+ ContextManager.getCurrentContext().contextLost();
+
+ // Whenever the context is created or replaced, the GL chain
+ // is lost. Debug will have to be added if desired.
+ _debugEnabled = false;
+ }
+
+ ContextManager.switchContext(_context);
+ }
+
+ public void releaseCurrentContext() {
+ if (_context.equals(GLContext.getCurrent())) {
+ try {
+ _context.release();
+ } catch(GLException gle) {
+ gle.printStackTrace();
+ }
+ }
+ }
+
+ @MainThread
+ protected ContextCapabilities createContextCapabilities() {
+ return new JoglContextCapabilities(_context.getGL());
+ }
+
+ @MainThread
+ public void init(final DisplaySettings settings, final boolean doSwap) {
+ _doSwap = doSwap;
+ if (_context == null) {
+ _context = GLDrawableFactory.getFactory(GLProfile.getMaxFixedFunc(true)).createExternalGLContext();
+ }
+
+ _context.makeCurrent();
+
+ try {
+
+ // Look up a shared context, if a shared JoglCanvasRenderer is given.
+ RenderContext sharedContext = null;
+ if (settings.getShareContext() != null) {
+ sharedContext = ContextManager.getContextForKey(settings.getShareContext().getRenderContext()
+ .getContextKey());
+ }
+
+ final ContextCapabilities caps = createContextCapabilities();
+ _currentContext = new RenderContext(_context, caps, sharedContext);
+
+ ContextManager.addContext(_context, _currentContext);
+ ContextManager.switchContext(_context);
+
+ _renderer = new JoglRenderer();
+
+ if (settings.getSamples() != 0 && caps.isMultisampleSupported()) {
+ final GL gl = GLU.getCurrentGL();
+ gl.glEnable(GL.GL_MULTISAMPLE);
+ }
+
+ _renderer.setBackgroundColor(ColorRGBA.BLACK);
+
+ if (_camera == null) {
+ /** Set up how our camera sees. */
+ _camera = new Camera(settings.getWidth(), settings.getHeight());
+ _camera.setFrustumPerspective(45.0f, (float) settings.getWidth() / (float) settings.getHeight(), 1, 1000);
+ _camera.setProjectionMode(ProjectionMode.Perspective);
+
+ final Vector3 loc = new Vector3(0.0f, 0.0f, 10.0f);
+ final Vector3 left = new Vector3(-1.0f, 0.0f, 0.0f);
+ final Vector3 up = new Vector3(0.0f, 1.0f, 0.0f);
+ final Vector3 dir = new Vector3(0.0f, 0f, -1.0f);
+ /** Move our camera to a correct place and orientation. */
+ _camera.setFrame(loc, left, up, dir);
+ } else {
+ // use new width and height to set ratio.
+ _camera.setFrustumPerspective(_camera.getFovY(),
+ (float) settings.getWidth() / (float) settings.getHeight(), _camera.getFrustumNear(), _camera
+ .getFrustumFar());
+ }
+ } finally {
+ _context.release();
+ }
+ }
+
+ public GLContext getContext() {
+ return _context;
+ }
+
+ public void setContext(final GLContext context) {
+ _context = context;
+ }
+
+ public int MAX_CONTEXT_GRAB_ATTEMPTS = 10;
+
+ @MainThread
+ public boolean draw() {
+
+ // set up context for rendering this canvas
+ makeCurrentContext();
+
+ // Enable Debugging if requested.
+ if (_useDebug != _debugEnabled) {
+ _context.setGL(new DebugGL2(_context.getGL().getGL2()));
+ _debugEnabled = true;
+
+ LOGGER.info("DebugGL Enabled");
+ }
+
+ // render stuff, first apply our camera if we have one
+ if (_camera != null) {
+ if (Camera.getCurrentCamera() != _camera) {
+ _camera.update();
+ }
+ _camera.apply(_renderer);
+ }
+ _renderer.clearBuffers(_frameClear);
+
+ final boolean drew = _scene.renderUnto(_renderer);
+ _renderer.flushFrame(drew && _doSwap);
+
+ // release the context if we're done (swapped and all)
+ if (_doSwap) {
+ releaseCurrentContext();
+ }
+
+ return drew;
+ }
+
+ public Camera getCamera() {
+ return _camera;
+ }
+
+ public Scene getScene() {
+ return _scene;
+ }
+
+ public void setScene(final Scene scene) {
+ _scene = scene;
+ }
+
+ public Renderer getRenderer() {
+ return _renderer;
+ }
+
+ public void setCamera(final Camera camera) {
+ _camera = camera;
+ }
+
+ public RenderContext getRenderContext() {
+ return _currentContext;
+ }
+
+ public int getFrameClear() {
+ return _frameClear;
+ }
+
+ public void setFrameClear(final int buffers) {
+ _frameClear = buffers;
+ }
+}
diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglDrawerRunnable.java b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglDrawerRunnable.java new file mode 100644 index 0000000..a3c00e8 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglDrawerRunnable.java @@ -0,0 +1,19 @@ +package com.ardor3d.framework.jogl; + +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLRunnable; + +public class JoglDrawerRunnable implements GLRunnable { + + private final JoglCanvasRenderer _canvasRenderer; + + public JoglDrawerRunnable(final JoglCanvasRenderer canvasRenderer) { + _canvasRenderer = canvasRenderer; + } + + @Override + public boolean run(GLAutoDrawable glAutoDrawable) { + _canvasRenderer.draw(); + return true; + } +}
\ No newline at end of file diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglLibraryPaths.java b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglLibraryPaths.java new file mode 100644 index 0000000..668e74e --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglLibraryPaths.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.framework.jogl; + +/** + * TODO: document this class! + * + */ +public enum JoglLibraryPaths { + MACOSX("Mac OS X", null, new String[] { + "/macosx/libgluegen-rt.jnilib", + "/macosx/libjogl.jnilib", + "/macosx/libjogl_awt.jnilib", + "/macosx/libjogl_cg.jnilib", + }), + WINDOWS_XP("Windows XP", null, new String[] { + "/win32/gluegen-rt.dll", + "/win32/jogl.dll", + "/win32/jogl_awt.dll", + "/win32/jogl_cg.dll", + }); + + private final String _operatingSystem; + private final String _architecture; + private final String[] _libraryPaths; + + + JoglLibraryPaths(String operatingSystem, String architecture, String[] libraryPaths) { + _operatingSystem = operatingSystem; + _architecture = architecture; + _libraryPaths = libraryPaths; + } + + public static String[] getLibraryPaths(String operatingSystem, String architecture) { + for (JoglLibraryPaths libraryPath : JoglLibraryPaths.values()) { + if (operatingSystem.equals(libraryPath._operatingSystem) && + (libraryPath._architecture == null || architecture.equals(libraryPath._architecture))) { + return libraryPath._libraryPaths; + } + } + + throw new IllegalStateException("No matching set of library paths found for " + operatingSystem + ", " + architecture); + } + + public static void main(String[] args) { + System.out.println(System.getProperty("os.name")); + System.out.println(System.getProperty("os.arch")); + + System.getProperties(); + } +}
\ No newline at end of file diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglNewtAwtCanvas.java b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglNewtAwtCanvas.java new file mode 100644 index 0000000..8b2517a --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglNewtAwtCanvas.java @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.framework.jogl; + +import java.util.concurrent.CountDownLatch; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLRunnable; +import com.ardor3d.annotation.MainThread; +import com.ardor3d.framework.Canvas; +import com.ardor3d.framework.DisplaySettings; +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.opengl.GLWindow; + + +public class JoglNewtAwtCanvas extends NewtCanvasAWT implements Canvas, NewtWindowContainer { + + private static final long serialVersionUID = 1L; + + private final JoglCanvasRenderer _canvasRenderer; + private boolean _inited = false; + + private final DisplaySettings _settings; + + private final JoglDrawerRunnable _drawerGLRunnable; + + public JoglNewtAwtCanvas(final DisplaySettings settings, final JoglCanvasRenderer canvasRenderer) { + super(GLWindow.create(CapsUtil.getCapsForSettings(settings))); + _drawerGLRunnable = new JoglDrawerRunnable(canvasRenderer); + getNewtWindow().setUndecorated(true); + _settings = settings; + _canvasRenderer = canvasRenderer; + + setFocusable(true); + setSize(_settings.getWidth(), _settings.getHeight()); + setIgnoreRepaint(true); + getNewtWindow().setAutoSwapBufferMode(false); + } + + @MainThread + public void init() { + if (_inited) { + return; + } + + // Make the window visible to realize the OpenGL surface. + setVisible(true); + // Request the focus here as it cannot work when the window is not visible + requestFocus(); + /** + * I do not understand why I cannot get the context earlier, I failed in + * getting it from addNotify() and setVisible(true) + * */ + _canvasRenderer.setContext(getNewtWindow().getContext()); + + getNewtWindow().invoke(true, new GLRunnable() { + @Override + public boolean run(GLAutoDrawable glAutoDrawable) { + _canvasRenderer.init(_settings, true);// true - do swap in renderer. + return true; + } + }); + _inited = true; + } + + public void draw(final CountDownLatch latch) { + if (!_inited) { + init(); + } + + if (isShowing()) { + getNewtWindow().invoke(true, _drawerGLRunnable); + } + if (latch != null) { + latch.countDown(); + } + } + + public JoglCanvasRenderer getCanvasRenderer() { + return _canvasRenderer; + } + + @Override + public GLWindow getNewtWindow() { + return (GLWindow) getNEWTChild(); + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglNewtWindow.java b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglNewtWindow.java new file mode 100644 index 0000000..3333d90 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/JoglNewtWindow.java @@ -0,0 +1,240 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.framework.jogl; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import javax.media.nativewindow.util.Dimension; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLRunnable; +import com.ardor3d.annotation.MainThread; +import com.ardor3d.framework.DisplaySettings; +import com.ardor3d.framework.NativeCanvas; +import com.ardor3d.image.Image; +import com.jogamp.newt.Screen; +import com.jogamp.newt.ScreenMode; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.WindowListener; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.util.ScreenModeUtil; + + +public class JoglNewtWindow implements NativeCanvas, NewtWindowContainer { + + private final JoglCanvasRenderer _canvasRenderer; + private boolean _inited = false; + private boolean _isClosing = false; + + private final DisplaySettings _settings; + + private final JoglDrawerRunnable _drawerGLRunnable; + + private final GLWindow _newtWindow; + + public JoglNewtWindow(final JoglCanvasRenderer canvasRenderer, final DisplaySettings settings) { + _newtWindow = GLWindow.create(CapsUtil.getCapsForSettings(settings)); + _drawerGLRunnable = new JoglDrawerRunnable(canvasRenderer); + _settings = settings; + _canvasRenderer = canvasRenderer; + setAutoSwapBufferMode(false); + } + + /** + * Applies all settings not related to OpenGL (screen resolution, + * screen size, etc...) + * */ + private void applySettings() { + _newtWindow.setUndecorated(_settings.isFullScreen()); + _newtWindow.setFullscreen(_settings.isFullScreen()); + //FIXME Ardor3D does not allow to change the resolution + /** + * uses the filtering relying on resolution with the size to fetch only the screen + * mode matching with the current resolution + */ + if (_settings.isFullScreen()) { + Screen screen = _newtWindow.getScreen(); + List<ScreenMode> screenModes = screen.getScreenModes(); + //the resolution is provided by the user + Dimension dimension=new Dimension(_settings.getWidth(),_settings.getHeight()); + screenModes = ScreenModeUtil.filterByResolution(screenModes,dimension); + screenModes = ScreenModeUtil.getHighestAvailableBpp(screenModes); + if (_settings.getFrequency() > 0) { + screenModes = ScreenModeUtil.filterByRate(screenModes, _settings.getFrequency()); + } else { + screenModes = ScreenModeUtil.getHighestAvailableRate(screenModes); + } + screen.setCurrentScreenMode(screenModes.get(0)); + } + } + + public void addKeyListener(KeyListener keyListener) { + _newtWindow.addKeyListener(keyListener); + } + + public void addMouseListener(MouseListener mouseListener) { + _newtWindow.addMouseListener(mouseListener); + } + + public void addWindowListener(WindowListener windowListener) { + _newtWindow.addWindowListener(windowListener); + } + + public GLContext getContext() { + return _newtWindow.getContext(); + } + + public int getWidth() { + return _newtWindow.getWidth(); + } + + public int getHeight() { + return _newtWindow.getHeight(); + } + + public int getX() { + return _newtWindow.getX(); + } + + public int getY() { + return _newtWindow.getY(); + } + + public boolean isVisible() { + return _newtWindow.isVisible(); + } + + public void setSize(int width, int height) { + _newtWindow.setTopLevelSize(width, height); + } + + public void setVisible(boolean visible) { + _newtWindow.setVisible(visible); + } + + public void setAutoSwapBufferMode(boolean autoSwapBufferModeEnabled) { + _newtWindow.setAutoSwapBufferMode(autoSwapBufferModeEnabled); + } + + @MainThread + public void init() { + if (_inited) { + return; + } + + _newtWindow.addWindowListener(new WindowAdapter() { + @Override + public void windowDestroyNotify(final WindowEvent e) { + _isClosing = true; + } + +// public void windowResized(final WindowEvent e) { +// _newtWindow.invoke(true, new GLRunnable() { +// +// @Override +// public boolean run(GLAutoDrawable glAutoDrawable) { +// _canvasRenderer._camera.resize(_newtWindow.getWidth(), _newtWindow.getHeight()); +// _canvasRenderer._camera.setFrustumPerspective(_canvasRenderer._camera.getFovY(), +// (float) _newtWindow.getWidth() / (float) _newtWindow.getHeight(), +// _canvasRenderer._camera.getFrustumNear(), +// _canvasRenderer._camera.getFrustumFar()); +// return true; +// } +// }); +// } + }); + + // Set the size very early to prevent the default one from being used (typically when exiting full screen mode) + setSize(_settings.getWidth(), _settings.getHeight()); + // Make the window visible to realize the OpenGL surface. + setVisible(true); + // Request the focus here as it cannot work when the window is not visible + _newtWindow.requestFocus(); + applySettings(); + + _canvasRenderer.setContext(getContext()); + + _newtWindow.invoke(true, new GLRunnable() { + @Override + public boolean run(GLAutoDrawable glAutoDrawable) { + _canvasRenderer.init(_settings, true);// true - do swap in renderer. + return true; + } + }); + _inited = true; + } + + public void draw(final CountDownLatch latch) { + if (!_inited) { + init(); + } + + if (/*isShowing()*/isVisible()) { + _newtWindow.invoke(true, _drawerGLRunnable); + } + if (latch != null) { + latch.countDown(); + } + } + + public JoglCanvasRenderer getCanvasRenderer() { + return _canvasRenderer; + } + + @Override + public void close() { + _newtWindow.destroy(); + } + + @Override + public boolean isActive() { + return _newtWindow.hasFocus(); + } + + @Override + public boolean isClosing() { + return _isClosing; + } + + @Override + public void setVSyncEnabled(final boolean enabled) { + _newtWindow.invoke(true, new GLRunnable() { + @Override + public boolean run(GLAutoDrawable glAutoDrawable) { + _newtWindow.getGL().setSwapInterval(enabled ? 1 : 0); + return false; + } + }); + } + + @Override + public void setTitle(String title) { + _newtWindow.setTitle(title); + } + + @Override + public void setIcon(Image[] iconImages) { + //FIXME not supported by NEWT + } + + @Override + public void moveWindowTo(int locX, int locY) { + _newtWindow.setPosition(locX, locY); + } + + @Override + public GLWindow getNewtWindow() { + return _newtWindow; + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/NewtWindowContainer.java b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/NewtWindowContainer.java new file mode 100644 index 0000000..5470a36 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/framework/jogl/NewtWindowContainer.java @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.framework.jogl; + +import com.jogamp.newt.opengl.GLWindow; + + +public interface NewtWindowContainer{ + public GLWindow getNewtWindow(); +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtFocusWrapper.java b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtFocusWrapper.java new file mode 100644 index 0000000..5068e6c --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtFocusWrapper.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.input.jogl; + +import com.ardor3d.framework.jogl.NewtWindowContainer; +import com.ardor3d.input.FocusWrapper; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; + + +public class JoglNewtFocusWrapper extends WindowAdapter implements FocusWrapper { + + protected volatile boolean _focusLost = false; + + protected final GLWindow _newtWindow; + + public JoglNewtFocusWrapper(final NewtWindowContainer newtWindowContainer) { + _newtWindow = newtWindowContainer.getNewtWindow(); + } + + @Override + public void windowGainedFocus(final WindowEvent e) { + // do nothing + } + + @Override + public void windowLostFocus(final WindowEvent e) { + _focusLost = true; + } + + @Override + public boolean getAndClearFocusLost() { + final boolean result = _focusLost; + + _focusLost = false; + + return result; + } + + @Override + public void init() { + _newtWindow.addWindowListener(this); + } + +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtKey.java b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtKey.java new file mode 100644 index 0000000..30861a4 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtKey.java @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.input.jogl; + +import com.jogamp.newt.event.KeyEvent; +import com.ardor3d.input.Key; + + +public enum JoglNewtKey { + + ZERO(KeyEvent.VK_0, Key.ZERO), // + ONE(KeyEvent.VK_1, Key.ONE), // + TWO(KeyEvent.VK_2, Key.TWO), // + THREE(KeyEvent.VK_3, Key.THREE), // + FOUR(KeyEvent.VK_4, Key.FOUR), // + FIVE(KeyEvent.VK_5, Key.FIVE), // + SIX(KeyEvent.VK_6, Key.SIX), // + SEVEN(KeyEvent.VK_7, Key.SEVEN), // + EIGHT(KeyEvent.VK_8, Key.EIGHT), // + NINE(KeyEvent.VK_9, Key.NINE), // + A(KeyEvent.VK_A, Key.A), // + ADD(KeyEvent.VK_ADD, Key.NUMPADADD), // + AT(KeyEvent.VK_AT, Key.AT), // + B(KeyEvent.VK_B, Key.B), // + BACK_QUOTE(KeyEvent.VK_BACK_QUOTE, Key.GRAVE), // + BACK_SPACE(KeyEvent.VK_BACK_SPACE, Key.BACK), // + BACK_SLASH(KeyEvent.VK_BACK_SLASH, Key.BACKSLASH), // + C(KeyEvent.VK_C, Key.C), // + CAPS_LOCK(KeyEvent.VK_CAPS_LOCK, Key.CAPITAL), // + CIRCUMFLEX(KeyEvent.VK_CIRCUMFLEX, Key.CIRCUMFLEX), // + COLON(KeyEvent.VK_COLON, Key.COLON), // + COMMA(KeyEvent.VK_COMMA, Key.COMMA), // + CONVERT(KeyEvent.VK_CONVERT, Key.CONVERT), // + D(KeyEvent.VK_D, Key.D), // + DECIMAL(KeyEvent.VK_DECIMAL, Key.DECIMAL), // + DELETE(KeyEvent.VK_DELETE, Key.DELETE), // + DIVIDE(KeyEvent.VK_DIVIDE, Key.DIVIDE), // + DOWN(KeyEvent.VK_DOWN, Key.DOWN), // + E(KeyEvent.VK_E, Key.E), // + END(KeyEvent.VK_END, Key.END), // + EQUALS(KeyEvent.VK_EQUALS, Key.EQUALS), // + ESCAPE(KeyEvent.VK_ESCAPE, Key.ESCAPE), // + F(KeyEvent.VK_F, Key.F), // + F1(KeyEvent.VK_F1, Key.F1), // + F2(KeyEvent.VK_F2, Key.F2), // + F3(KeyEvent.VK_F3, Key.F3), // + F4(KeyEvent.VK_F4, Key.F4), // + F5(KeyEvent.VK_F5, Key.F5), // + F6(KeyEvent.VK_F6, Key.F6), // + F7(KeyEvent.VK_F7, Key.F7), // + F8(KeyEvent.VK_F8, Key.F8), // + F9(KeyEvent.VK_F9, Key.F9), // + F10(KeyEvent.VK_F10, Key.F10), // + F11(KeyEvent.VK_F11, Key.F11), // + F12(KeyEvent.VK_F12, Key.F12), // + F13(KeyEvent.VK_F13, Key.F13), // + F14(KeyEvent.VK_F14, Key.F14), // + F15(KeyEvent.VK_F15, Key.F15), // + G(KeyEvent.VK_G, Key.G), // + H(KeyEvent.VK_H, Key.H), // + HOME(KeyEvent.VK_HOME, Key.HOME), // + I(KeyEvent.VK_I, Key.I), // + INSERT(KeyEvent.VK_INSERT, Key.INSERT), // + J(KeyEvent.VK_J, Key.J), // + K(KeyEvent.VK_K, Key.K), // + KANA(KeyEvent.VK_KANA, Key.KANA), // + KANJI(KeyEvent.VK_KANJI, Key.KANJI), // + L(KeyEvent.VK_L, Key.L), // + OPEN_BRACKET(KeyEvent.VK_OPEN_BRACKET, Key.LBRACKET), // + CONTROL(KeyEvent.VK_CONTROL, Key.LCONTROL), // + LEFT(KeyEvent.VK_LEFT, Key.LEFT), // + ALT(KeyEvent.VK_ALT, Key.LMENU), // + META(KeyEvent.VK_META, Key.LMETA), // + SHIFT(KeyEvent.VK_SHIFT, Key.LSHIFT), // + M(KeyEvent.VK_M, Key.M), // + MINUS(KeyEvent.VK_MINUS, Key.MINUS), // + MULTIPLY(KeyEvent.VK_MULTIPLY, Key.MULTIPLY), // + N(KeyEvent.VK_N, Key.N), // + PAGE_DOWN(KeyEvent.VK_PAGE_DOWN, Key.PAGEDOWN_NEXT), // + NONCONVERT(KeyEvent.VK_NONCONVERT, Key.NOCONVERT), // + NUM_LOCK(KeyEvent.VK_NUM_LOCK, Key.NUMLOCK), // + NUMPAD0(KeyEvent.VK_NUMPAD0, Key.NUMPAD0), // + NUMPAD1(KeyEvent.VK_NUMPAD1, Key.NUMPAD1), // + NUMPAD2(KeyEvent.VK_NUMPAD2, Key.NUMPAD2), // + NUMPAD3(KeyEvent.VK_NUMPAD3, Key.NUMPAD3), // + NUMPAD4(KeyEvent.VK_NUMPAD4, Key.NUMPAD4), // + NUMPAD5(KeyEvent.VK_NUMPAD5, Key.NUMPAD5), // + NUMPAD6(KeyEvent.VK_NUMPAD6, Key.NUMPAD6), // + NUMPAD7(KeyEvent.VK_NUMPAD7, Key.NUMPAD7), // + NUMPAD8(KeyEvent.VK_NUMPAD8, Key.NUMPAD8), // + NUMPAD9(KeyEvent.VK_NUMPAD9, Key.NUMPAD9), // + O(KeyEvent.VK_O, Key.O), // + P(KeyEvent.VK_P, Key.P), // + PAUSE(KeyEvent.VK_PAUSE, Key.PAUSE), // + PERIOD(KeyEvent.VK_PERIOD, Key.PERIOD), // + PAGE_UP(KeyEvent.VK_PAGE_UP, Key.PAGEUP_PRIOR), // + Q(KeyEvent.VK_Q, Key.Q), // + QUOTE(KeyEvent.VK_QUOTE, Key.APOSTROPHE), // + R(KeyEvent.VK_R, Key.R), // + CLOSE_BRACKET(KeyEvent.VK_CLOSE_BRACKET, Key.RBRACKET), // + ENTER(KeyEvent.VK_ENTER, Key.RETURN), // + RIGHT(KeyEvent.VK_RIGHT, Key.RIGHT), // + S(KeyEvent.VK_S, Key.S), // + SCROLL_LOCK(KeyEvent.VK_SCROLL_LOCK, Key.SCROLL), // + SEMICOLON(KeyEvent.VK_SEMICOLON, Key.SEMICOLON), // + SLASH(KeyEvent.VK_SLASH, Key.SLASH), // + SPACE(KeyEvent.VK_SPACE, Key.SPACE), // + STOP(KeyEvent.VK_STOP, Key.STOP), // + PRINTSCREEN(KeyEvent.VK_PRINTSCREEN, Key.SYSRQ), // + T(KeyEvent.VK_T, Key.T), // + TAB(KeyEvent.VK_TAB, Key.TAB), // + U(KeyEvent.VK_U, Key.U), // + UNDERSCORE(KeyEvent.VK_UNDERSCORE, Key.UNDERLINE), // + UP(KeyEvent.VK_UP, Key.UP), // + V(KeyEvent.VK_V, Key.V), // + W(KeyEvent.VK_W, Key.W), // + X(KeyEvent.VK_X, Key.X), // + Y(KeyEvent.VK_Y, Key.Y), // + Z(KeyEvent.VK_Z, Key.Z), // + UNDEFINED(KeyEvent.VK_UNDEFINED, Key.UNKNOWN); + + private final int _newtCode; + private final Key _key; + + private JoglNewtKey(final int newtCode, final Key key) { + _newtCode = newtCode; + _key = key; + } + + public static Key findByCode(final int newtCode) { + for (final JoglNewtKey ak : values()) { + if (ak._newtCode == newtCode) { + return ak._key; + } + } + + return Key.UNKNOWN; + } + + public int getNewtCode() { + return _newtCode; + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtKeyboardWrapper.java b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtKeyboardWrapper.java new file mode 100644 index 0000000..43bd01a --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtKeyboardWrapper.java @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.input.jogl; + +import java.util.EnumSet; +import java.util.LinkedList; +import com.ardor3d.annotation.GuardedBy; +import com.ardor3d.framework.jogl.NewtWindowContainer; +import com.ardor3d.input.Key; +import com.ardor3d.input.KeyEvent; +import com.ardor3d.input.KeyState; +import com.ardor3d.input.KeyboardWrapper; +import com.google.common.base.Preconditions; +import com.google.common.collect.AbstractIterator; +import com.google.common.collect.PeekingIterator; +import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; + + +public class JoglNewtKeyboardWrapper implements KeyboardWrapper, KeyListener { + + @GuardedBy("this") + protected final LinkedList<KeyEvent> _upcomingEvents = new LinkedList<KeyEvent>(); + + @GuardedBy("this") + protected JoglNewtKeyboardIterator _currentIterator = null; + + protected final GLWindow _newtWindow; + + protected boolean _consumeEvents = false; + + protected final EnumSet<Key> _pressedList = EnumSet.noneOf(Key.class); + + public JoglNewtKeyboardWrapper(final NewtWindowContainer newtWindowContainer) { + _newtWindow = Preconditions.checkNotNull(newtWindowContainer.getNewtWindow(), "newtWindow"); + } + + public void init() { + _newtWindow.addKeyListener(this); + _newtWindow.addWindowListener(new WindowAdapter() { + public void windowLostFocus(final WindowEvent e) {} + + public void windowGainedFocus(final WindowEvent e) { + _pressedList.clear(); + } + }); + } + + public synchronized PeekingIterator<KeyEvent> getEvents() { + if (_currentIterator == null || !_currentIterator.hasNext()) { + _currentIterator = new JoglNewtKeyboardIterator(); + } + + return _currentIterator; + } + + public synchronized void keyTyped(final com.jogamp.newt.event.KeyEvent e) { + if (_consumeEvents) { + e.setAttachment(InputEvent.consumedTag); + // ignore this event + } + } + + public synchronized void keyPressed(final com.jogamp.newt.event.KeyEvent e) { + final Key pressed = fromKeyEventToKey(e); + if (!_pressedList.contains(pressed)) { + _upcomingEvents.add(new KeyEvent(pressed, KeyState.DOWN, e.getKeyChar())); + _pressedList.add(pressed); + } + if (_consumeEvents) { + e.setAttachment(InputEvent.consumedTag); + // ignore this event + } + } + + public synchronized void keyReleased(final com.jogamp.newt.event.KeyEvent e) { + final Key released = fromKeyEventToKey(e); + _upcomingEvents.add(new KeyEvent(released, KeyState.UP, e.getKeyChar())); + _pressedList.remove(released); + if (_consumeEvents) { + e.setAttachment(InputEvent.consumedTag); + // ignore this event + } + } + + /** + * Convert from NEWT key event to Ardor3D Key. Override to provide additional or custom behavior. + * + * @param e + * the NEWT KeyEvent received by the input system. + * @return an Ardor3D Key, to be forwarded to the Predicate/Trigger system. + */ + public synchronized Key fromKeyEventToKey(final com.jogamp.newt.event.KeyEvent e) { + return JoglNewtKey.findByCode(e.getKeyCode()); + } + + private class JoglNewtKeyboardIterator extends AbstractIterator<KeyEvent> implements PeekingIterator<KeyEvent> { + @Override + protected KeyEvent computeNext() { + synchronized (JoglNewtKeyboardWrapper.this) { + if (_upcomingEvents.isEmpty()) { + return endOfData(); + } + + return _upcomingEvents.poll(); + } + } + } + + public boolean isConsumeEvents() { + return _consumeEvents; + } + + public void setConsumeEvents(final boolean consumeEvents) { + _consumeEvents = consumeEvents; + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtMouseManager.java b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtMouseManager.java new file mode 100644 index 0000000..1a9f8cc --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtMouseManager.java @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.input.jogl; + +import com.ardor3d.framework.jogl.NewtWindowContainer; +import com.ardor3d.input.GrabbedState; +import com.ardor3d.input.MouseCursor; +import com.ardor3d.input.MouseManager; +import com.jogamp.newt.opengl.GLWindow; + + +public class JoglNewtMouseManager implements MouseManager{ + + /** our current grabbed state */ + private GrabbedState _grabbedState; + + private GLWindow _newtWindow; + + public JoglNewtMouseManager(final NewtWindowContainer newtWindowContainer) { + _newtWindow = newtWindowContainer.getNewtWindow(); + } + + @Override + public void setCursor(MouseCursor cursor) { + //FIXME not supported by NEWT + } + + @Override + public void setPosition(final int x, final int y) { + _newtWindow.warpPointer(x, _newtWindow.getHeight() - y); + } + + @Override + public void setGrabbed(GrabbedState grabbedState) { + // check if we should be here. + if (_grabbedState == grabbedState) { + return; + } + + // remember our grabbed state mode. + _grabbedState = grabbedState; + if (grabbedState == GrabbedState.GRABBED) { + //FIXME remember our old cursor + + // set our cursor to be invisible + _newtWindow.setPointerVisible(false); + } + else { + //FIXME restore our old cursor + + // set our cursor to be visible + _newtWindow.setPointerVisible(true); + } + } + + @Override + public GrabbedState getGrabbed() { + return _grabbedState; + } + + @Override + public boolean isSetPositionSupported() { + return true; + } + + @Override + public boolean isSetGrabbedSupported() { + return true; + } + +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtMouseWrapper.java b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtMouseWrapper.java new file mode 100644 index 0000000..6ecf6bb --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/input/jogl/JoglNewtMouseWrapper.java @@ -0,0 +1,310 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.input.jogl; + +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.LinkedList; +import com.ardor3d.annotation.GuardedBy; +import com.ardor3d.framework.jogl.NewtWindowContainer; +import com.ardor3d.input.ButtonState; +import com.ardor3d.input.GrabbedState; +import com.ardor3d.input.MouseButton; +import com.ardor3d.input.MouseManager; +import com.ardor3d.input.MouseState; +import com.ardor3d.input.MouseWrapper; +import com.google.common.collect.AbstractIterator; +import com.google.common.collect.EnumMultiset; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multiset; +import com.google.common.collect.PeekingIterator; +import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.opengl.GLWindow; + +import static com.google.common.base.Preconditions.checkNotNull; + + +public class JoglNewtMouseWrapper implements MouseWrapper, MouseListener { + + @GuardedBy("this") + protected final LinkedList<MouseState> _upcomingEvents = Lists.newLinkedList(); + + @GuardedBy("this") + protected JoglNewtMouseIterator _currentIterator = null; + + @GuardedBy("this") + protected MouseState _lastState = null; + + protected final GLWindow _newtWindow; + + protected final MouseManager _manager; + + protected boolean _consumeEvents = false; + + protected final Multiset<MouseButton> _clicks = EnumMultiset.create(MouseButton.class); + protected final EnumMap<MouseButton, Long> _lastClickTime = Maps.newEnumMap(MouseButton.class); + protected final EnumSet<MouseButton> _clickArmed = EnumSet.noneOf(MouseButton.class); + + protected int _ignoreX = Integer.MAX_VALUE; + protected int _ignoreY = Integer.MAX_VALUE; + + public JoglNewtMouseWrapper(final NewtWindowContainer newtWindowContainer, final MouseManager manager) { + _newtWindow = checkNotNull(newtWindowContainer.getNewtWindow(), "newtWindow"); + _manager = manager; + for (final MouseButton mb : MouseButton.values()) { + _lastClickTime.put(mb, 0L); + } + } + + @Override + public void init() { + _newtWindow.addMouseListener(this); + } + + @Override + public synchronized PeekingIterator<MouseState> getEvents() { + expireClickEvents(); + + if (_currentIterator == null || !_currentIterator.hasNext()) { + _currentIterator = new JoglNewtMouseIterator(); + } + + return _currentIterator; + } + + private void expireClickEvents() { + if (!_clicks.isEmpty()) { + for (final MouseButton mb : MouseButton.values()) { + if (System.currentTimeMillis() - _lastClickTime.get(mb) > MouseState.CLICK_TIME_MS) { + _clicks.setCount(mb, 0); + } + } + } + } + + @Override + public synchronized void mousePressed(MouseEvent me) { + final MouseButton b = getButtonForEvent(me); + if (_clickArmed.contains(b)) { + _clicks.setCount(b, 0); + } + _clickArmed.add(b); + _lastClickTime.put(b, System.currentTimeMillis()); + + initState(me); + if (_consumeEvents) { + me.setAttachment(InputEvent.consumedTag); + } + + final EnumMap<MouseButton, ButtonState> buttons = _lastState.getButtonStates(); + + setStateForButton(me, buttons, ButtonState.DOWN); + + addNewState(me, buttons, null); + } + + @Override + public synchronized void mouseReleased(MouseEvent me) { + initState(me); + if (_consumeEvents) { + me.setAttachment(InputEvent.consumedTag); + } + + final EnumMap<MouseButton, ButtonState> buttons = _lastState.getButtonStates(); + + setStateForButton(me, buttons, ButtonState.UP); + + final MouseButton b = getButtonForEvent(me); + if (_clickArmed.contains(b) && (System.currentTimeMillis() - _lastClickTime.get(b) <= MouseState.CLICK_TIME_MS)) { + _clicks.add(b); // increment count of clicks for button b. + // XXX: Note the double event add... this prevents sticky click counts, but is it the best way? + addNewState(me, buttons, EnumMultiset.create(_clicks)); + } else { + _clicks.setCount(b, 0); // clear click count for button b. + } + _clickArmed.remove(b); + + addNewState(me, buttons, null); + } + + @Override + public synchronized void mouseDragged(MouseEvent me) { + mouseMoved(me); + } + + @Override + public synchronized void mouseMoved(MouseEvent me) { + _clickArmed.clear(); + _clicks.clear(); + + // check that we have a valid _lastState + initState(me); + if (_consumeEvents) { + me.setAttachment(InputEvent.consumedTag); + } + + // remember our current ardor3d position + final int oldX = _lastState.getX(), oldY = _lastState.getY(); + + // check the state against the "ignore next" values + if (_ignoreX != Integer.MAX_VALUE // shortcut to prevent dx/dy calculations + && (_ignoreX == getDX(me) && _ignoreY == getDY(me))) { + + // we matched, so we'll consider this a "mouse pointer reset move" + // so reset ignore to let the next move event through. + _ignoreX = Integer.MAX_VALUE; + _ignoreY = Integer.MAX_VALUE; + + // exit without adding an event to our queue + return; + } + + // save our old "last state." + final MouseState _savedState = _lastState; + + // Add our latest state info to the queue + addNewState(me, _lastState.getButtonStates(), null); + + // If we have a valid move... should always be the case, but occasionally something slips through. + if (_lastState.getDx() != 0 || _lastState.getDy() != 0) { + + // Ask our manager if we're currently "captured" + if (_manager.getGrabbed() == GrabbedState.GRABBED) { + + // if so, set "ignore next" to the inverse of this move + _ignoreX = -_lastState.getDx(); + _ignoreY = -_lastState.getDy(); + + // Move us back to our last position. + _manager.setPosition(oldX, oldY); + + // And finally, revert our _lastState. + _lastState = _savedState; + } else { + // otherwise, set us to not ignore anything. This may be unnecessary, but prevents any possible + // "ignore" bleeding. + _ignoreX = Integer.MAX_VALUE; + _ignoreY = Integer.MAX_VALUE; + } + } + } + + @Override + public void mouseWheelMoved(MouseEvent me) { + initState(me); + + addNewState(me, _lastState.getButtonStates(), null); + if (_consumeEvents) { + me.setAttachment(InputEvent.consumedTag); + } + } + + private void initState(final MouseEvent mouseEvent) { + if (_lastState == null) { + _lastState = new MouseState(mouseEvent.getX(), getArdor3DY(mouseEvent), 0, 0, 0, null, null); + } + } + + private void addNewState(final MouseEvent mouseEvent, final EnumMap<MouseButton, ButtonState> enumMap, + final Multiset<MouseButton> clicks) { + final MouseState newState = new MouseState(mouseEvent.getX(), getArdor3DY(mouseEvent), getDX(mouseEvent), + getDY(mouseEvent), mouseEvent.getWheelRotation(), enumMap, clicks); + + synchronized (JoglNewtMouseWrapper.this) { + _upcomingEvents.add(newState); + } + _lastState = newState; + } + + private int getDX(final MouseEvent me) { + return me.getX() - _lastState.getX(); + } + + private int getDY(final MouseEvent me) { + return getArdor3DY(me) - _lastState.getY(); + } + + /** + * @param e + * our mouseEvent + * @return the Y coordinate of the event, flipped relative to the component since we expect an origin in the lower + * left corner. + */ + private int getArdor3DY(final MouseEvent me) { + return _newtWindow.getHeight() - me.getY(); + } + + private void setStateForButton(final MouseEvent e, final EnumMap<MouseButton, ButtonState> buttons, + final ButtonState buttonState) { + final MouseButton button = getButtonForEvent(e); + buttons.put(button, buttonState); + } + + private MouseButton getButtonForEvent(final MouseEvent me) { + MouseButton button; + switch(me.getButton()) { + case MouseEvent.BUTTON1: + button = MouseButton.LEFT; + break; + case MouseEvent.BUTTON2: + button = MouseButton.MIDDLE; + break; + case MouseEvent.BUTTON3: + button = MouseButton.RIGHT; + break; + default: + throw new RuntimeException("unknown button: " + me.getButton()); + } + return button; + } + + private class JoglNewtMouseIterator extends AbstractIterator<MouseState> implements PeekingIterator<MouseState> { + + @Override + protected MouseState computeNext() { + synchronized (JoglNewtMouseWrapper.this) { + if (_upcomingEvents.isEmpty()) { + return endOfData(); + } + return _upcomingEvents.poll(); + } + } + } + + @Override + public synchronized void mouseClicked(MouseEvent me) { + // Yes, we could use the click count here, but in the interests of this working the same way as SWT and Native, + // we + // will do it the same way they do it. + + } + + @Override + public synchronized void mouseEntered(MouseEvent me) { + // ignore this + } + + @Override + public synchronized void mouseExited(MouseEvent me) { + // ignore this + } + + public boolean isConsumeEvents() { + return _consumeEvents; + } + + public void setConsumeEvents(final boolean consumeEvents) { + _consumeEvents = consumeEvents; + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglContextCapabilities.java b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglContextCapabilities.java new file mode 100644 index 0000000..7bc4e01 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglContextCapabilities.java @@ -0,0 +1,247 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.renderer.jogl; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLAutoDrawable; + +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.util.geom.BufferUtils; + +public class JoglContextCapabilities extends ContextCapabilities { + + public JoglContextCapabilities(final GLAutoDrawable autodrawable) { + init(autodrawable.getGL()); + } + + public JoglContextCapabilities(final GL gl) { + init(gl); + } + + public JoglContextCapabilities(final ContextCapabilities caps) { + super(caps); + } + + public void init(final GL gl) { + final IntBuffer buf = BufferUtils.createIntBuffer(16); + + _supportsVBO = gl.isExtensionAvailable("GL_ARB_vertex_buffer_object"); + _supportsGL1_2 = gl.isExtensionAvailable("GL_VERSION_1_2"); + _supportsMultisample = gl.isExtensionAvailable("GL_ARB_multisample"); + + _supportsConstantColor = _supportsEq = gl.isExtensionAvailable("GL_ARB_imaging"); + _supportsSeparateFunc = gl.isExtensionAvailable("GL_EXT_blend_func_separate"); + _supportsSeparateEq = gl.isExtensionAvailable("GL_EXT_blend_equation_separate"); + _supportsMinMax = gl.isExtensionAvailable("GL_EXT_blend_minmax"); + _supportsSubtract = gl.isExtensionAvailable("GL_EXT_blend_subtract"); + + _supportsFogCoords = gl.isExtensionAvailable("GL_EXT_fog_coord"); + _supportsFragmentProgram = gl.isExtensionAvailable("GL_ARB_fragment_program"); + _supportsVertexProgram = gl.isExtensionAvailable("GL_ARB_vertex_program"); + + _supportsPointSprites = gl.isExtensionAvailable("GL_ARB_point_sprite"); + _supportsPointParameters = gl.isExtensionAvailable("GL_ARB_point_parameters"); + + _supportsTextureLodBias = gl.isExtensionAvailable("GL_EXT_texture_lod_bias"); + if (_supportsTextureLodBias) { + gl.glGetIntegerv(GL2GL3.GL_MAX_TEXTURE_LOD_BIAS, buf); + _maxTextureLodBias = buf.get(0); + } else { + _maxTextureLodBias = 0f; + } + + gl.glGetIntegerv(GL2ES1.GL_MAX_CLIP_PLANES, buf); + _maxUserClipPlanes = buf.get(0); + + _glslSupported = gl.isExtensionAvailable("GL_ARB_shader_objects") + && gl.isExtensionAvailable("GL_ARB_fragment_shader") && gl.isExtensionAvailable("GL_ARB_vertex_shader") + && gl.isExtensionAvailable("GL_ARB_shading_language_100"); + + _geometryShader4Supported = gl.isExtensionAvailable("GL_ARB_geometry_shader4") && _glslSupported; + + _geometryInstancingSupported = gl.isExtensionAvailable("GL_EXT_draw_instanced") || gl.isExtensionAvailable("GL_VERSION_3_0"); + + _tessellationShadersSupported = gl.isExtensionAvailable("GL_ARB_tessellation_shader") && _glslSupported; + + if (_glslSupported) { + gl.glGetIntegerv(GL2.GL_MAX_VERTEX_ATTRIBS_ARB, buf); + _maxGLSLVertexAttribs = buf.get(0); + } + + // Pbuffer + _pbufferSupported = gl.isExtensionAvailable("GL_ARB_pixel_buffer_object"); + + // FBO + _fboSupported = gl.isExtensionAvailable("GL_EXT_framebuffer_object"); + if (_fboSupported) { + if (gl.isExtensionAvailable("GL_ARB_draw_buffers")) { + gl.glGetIntegerv(GL2ES2.GL_MAX_COLOR_ATTACHMENTS, buf); + _maxFBOColorAttachments = buf.get(0); + } else { + _maxFBOColorAttachments = 1; + } + + // Max multisample samples. + if (gl.isExtensionAvailable("GL_EXT_framebuffer_multisample") + && gl.isExtensionAvailable("GL_EXT_framebuffer_blit")) { + gl.glGetIntegerv(GL2GL3.GL_MAX_SAMPLES, buf); + _maxFBOSamples = buf.get(0); + } else { + _maxFBOSamples = 0; + } + } else { + _maxFBOColorAttachments = 0; + } + + _twoSidedStencilSupport = gl.isExtensionAvailable("GL_EXT_stencil_two_side"); + _stencilWrapSupport = gl.isExtensionAvailable("GL_EXT_stencil_wrap"); + + // number of available auxiliary draw buffers + gl.glGetIntegerv(GL2.GL_AUX_BUFFERS, buf); + _numAuxDrawBuffers = buf.get(0); + + // max texture size. + gl.glGetIntegerv(GL.GL_MAX_TEXTURE_SIZE, buf); + _maxTextureSize = buf.get(0); + + // Check for support of multitextures. + _supportsMultiTexture = gl.isExtensionAvailable("GL_ARB_multitexture"); + + // Support for texture formats + _supportsFloatTextures = gl.isExtensionAvailable("GL_ARB_texture_float"); + _supportsIntegerTextures = gl.isExtensionAvailable("GL_EXT_texture_integer"); + _supportsOneTwoComponentTextures = gl.isExtensionAvailable("GL_ARB_texture_rg"); + + // Check for support of fixed function dot3 environment settings + _supportsEnvDot3 = gl.isExtensionAvailable("GL_ARB_texture_env_dot3"); + + // Check for support of fixed function dot3 environment settings + _supportsEnvCombine = gl.isExtensionAvailable("GL_ARB_texture_env_combine"); + + // Check for support of automatic mipmap generation + _automaticMipMaps = gl.isExtensionAvailable("GL_SGIS_generate_mipmap"); + + _supportsDepthTexture = gl.isExtensionAvailable("GL_ARB_depth_texture"); + _supportsShadow = gl.isExtensionAvailable("GL_ARB_shadow"); + + // If we do support multitexturing, find out how many textures we + // can handle. + if (_supportsMultiTexture) { + gl.glGetIntegerv(GL2ES1.GL_MAX_TEXTURE_UNITS, buf); + _numFixedTexUnits = buf.get(0); + } else { + _numFixedTexUnits = 1; + } + + // Go on to check number of texture units supported for vertex and + // fragment shaders + if (gl.isExtensionAvailable("GL_ARB_shader_objects") && gl.isExtensionAvailable("GL_ARB_vertex_shader") + && gl.isExtensionAvailable("GL_ARB_fragment_shader")) { + gl.glGetIntegerv(GL2ES2.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, buf); + _numVertexTexUnits = buf.get(0); + gl.glGetIntegerv(GL2ES2.GL_MAX_TEXTURE_IMAGE_UNITS, buf); + _numFragmentTexUnits = buf.get(0); + gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_COORDS, buf); + _numFragmentTexCoordUnits = buf.get(0); + } else { + // based on nvidia dev doc: + // http://developer.nvidia.com/object/General_FAQ.html#t6 + // "For GPUs that do not support GL_ARB_fragment_program and + // GL_NV_fragment_program, those two limits are set equal to + // GL_MAX_TEXTURE_UNITS." + _numFragmentTexCoordUnits = _numFixedTexUnits; + _numFragmentTexUnits = _numFixedTexUnits; + + // We'll set this to 0 for now since we do not know: + _numVertexTexUnits = 0; + } + + // Now determine the maximum number of supported texture units + _numTotalTexUnits = Math.max(_numFragmentTexCoordUnits, Math.max(_numFixedTexUnits, Math.max( + _numFragmentTexUnits, _numVertexTexUnits))); + + // Check for S3 texture compression capability. + _supportsS3TCCompression = gl.isExtensionAvailable("GL_EXT_texture_compression_s3tc"); + + // Check for LA texture compression capability. + _supportsLATCCompression = gl.isExtensionAvailable("GL_EXT_texture_compression_latc"); + + // Check for generic texture compression capability. + _supportsGenericCompression = gl.isExtensionAvailable("GL_ARB_texture_compression"); + + // Check for 3D texture capability. + _supportsTexture3D = _supportsGL1_2; + + // Check for cubemap capability. + _supportsTextureCubeMap = gl.isExtensionAvailable("GL_ARB_texture_cube_map"); + + // See if we support anisotropic filtering + _supportsAniso = gl.isExtensionAvailable("GL_EXT_texture_filter_anisotropic"); + + if (_supportsAniso) { + final FloatBuffer max_a = BufferUtils.createFloatBuffer(1); + max_a.rewind(); + + // Grab the maximum anisotropic filter. + gl.glGetFloatv(GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_a); + + // set max. + _maxAnisotropic = max_a.get(0); + } + + // See if we support textures that are not power of 2 in size. + _supportsNonPowerTwo = gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two"); + + // See if we support textures that do not have width == height. + _supportsRectangular = gl.isExtensionAvailable("GL_ARB_texture_rectangle"); + + _supportsMirroredRepeat = gl.isExtensionAvailable("GL_ARB_texture_mirrored_repeat"); + _supportsMirrorClamp = _supportsMirrorBorderClamp = _supportsMirrorEdgeClamp = gl + .isExtensionAvailable("GL_EXT_texture_mirror_clamp"); + _supportsBorderClamp = gl.isExtensionAvailable("GL_ARB_texture_border_clamp"); + _supportsEdgeClamp = _supportsGL1_2; + + try { + _displayVendor = gl.glGetString(GL.GL_VENDOR); + } catch (final Exception e) { + _displayVendor = "Unable to retrieve vendor."; + } + + try { + _displayRenderer = gl.glGetString(GL.GL_RENDERER); + } catch (final Exception e) { + _displayRenderer = "Unable to retrieve adapter details."; + } + + try { + _displayVersion = gl.glGetString(GL.GL_VERSION); + } catch (final Exception e) { + _displayVersion = "Unable to retrieve API version."; + } + + if (_glslSupported) { + try { + _shadingLanguageVersion = gl.glGetString(GL2ES2.GL_SHADING_LANGUAGE_VERSION); + } catch (final Exception e) { + _shadingLanguageVersion = "Unable to retrieve shading language version."; + } + } else { + _shadingLanguageVersion = "Not supported."; + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglPbufferTextureRenderer.java b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglPbufferTextureRenderer.java new file mode 100644 index 0000000..63eb6ee --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglPbufferTextureRenderer.java @@ -0,0 +1,368 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.renderer.jogl; + +import java.nio.IntBuffer; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.media.opengl.GL; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLPbuffer; +import javax.media.opengl.GLProfile; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.framework.DisplaySettings; +import com.ardor3d.framework.Scene; +import com.ardor3d.image.Texture; +import com.ardor3d.image.Texture.Type; +import com.ardor3d.renderer.AbstractPbufferTextureRenderer; +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.TextureRendererFactory; +import com.ardor3d.renderer.state.RenderState; +import com.ardor3d.renderer.state.record.TextureRecord; +import com.ardor3d.renderer.state.record.TextureStateRecord; +import com.ardor3d.scene.state.jogl.JoglTextureStateUtil; +import com.ardor3d.scene.state.jogl.util.JoglTextureUtil; +import com.ardor3d.scenegraph.Spatial; +import com.ardor3d.util.Ardor3dException; +import com.ardor3d.util.TextureKey; +import com.ardor3d.util.geom.BufferUtils; + +/** + * <p> + * This class is used by Ardor3D's JOGL implementation to render textures. Users should <b>not </b> create this class + * directly. + * </p> + * + * @see TextureRendererFactory + */ +public class JoglPbufferTextureRenderer extends AbstractPbufferTextureRenderer { + private static final Logger logger = Logger.getLogger(JoglPbufferTextureRenderer.class.getName()); + + /* Pbuffer instance */ + private GLPbuffer _pbuffer; + + private GLContext _context; + + // HACK: needed to get the parent context in here somehow... + public static GLContext _parentContext; + + public JoglPbufferTextureRenderer(final DisplaySettings settings, final Renderer parentRenderer, + final ContextCapabilities caps) { + super(settings, parentRenderer, caps); + setMultipleTargets(false); + } + + /** + * <code>setupTexture</code> initializes a new Texture object for use with TextureRenderer. Generates a valid gl + * texture id for this texture and inits the data type for the texture. + */ + public void setupTexture(final Texture tex) { + if (tex.getType() != Type.TwoDimensional) { + throw new IllegalArgumentException("Unsupported type: " + tex.getType()); + } + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(RenderState.StateType.Texture); + + // check if we are already setup... if so, throw error. + if (tex.getTextureKey() == null) { + tex.setTextureKey(TextureKey.getRTTKey(tex.getMinificationFilter())); + } else if (tex.getTextureIdForContext(context.getGlContextRep()) != 0) { + throw new Ardor3dException("Texture is already setup and has id."); + } + + // Create the texture + final IntBuffer ibuf = BufferUtils.createIntBuffer(1); + gl.glGenTextures(1, ibuf); + final int textureId = ibuf.get(0); + tex.setTextureIdForContext(context.getGlContextRep(), textureId); + + JoglTextureStateUtil.doTextureBind(tex, 0, true); + + // Initialize our texture with some default data. + final int internalFormat = JoglTextureUtil.getGLInternalFormat(tex.getTextureStoreFormat()); + final int dataFormat = JoglTextureUtil.getGLPixelFormatFromStoreFormat(tex.getTextureStoreFormat()); + final int pixelDataType = JoglTextureUtil.getGLPixelDataType(tex.getRenderedTexturePixelDataType()); + + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, internalFormat, _width, _height, 0, dataFormat, pixelDataType, null); + + // Setup filtering and wrap + final TextureRecord texRecord = record.getTextureRecord(textureId, tex.getType()); + JoglTextureStateUtil.applyFilter(tex, texRecord, 0, record, context.getCapabilities()); + JoglTextureStateUtil.applyWrap(tex, texRecord, 0, record, context.getCapabilities()); + + logger.fine("setup pbuffer tex" + textureId + ": " + _width + "," + _height); + } + + public void render(final Spatial spat, final Texture tex, final int clear) { + render(null, spat, null, tex, clear); + } + + public void render(final List<? extends Spatial> spat, final Texture tex, final int clear) { + render(spat, null, null, tex, clear); + } + + public void render(final Scene scene, final Texture tex, final int clear) { + render(null, null, scene, tex, clear); + } + + private void render(final List<? extends Spatial> toDrawA, final Spatial toDrawB, final Scene toDrawC, + final Texture tex, final int clear) { + try { + if (_pbuffer == null) { + initPbuffer(); + } + + if (_useDirectRender && !tex.getTextureStoreFormat().isDepthFormat()) { + // setup and render directly to a 2d texture. + _pbuffer.releaseTexture(); + activate(); + switchCameraIn(clear); + + if (toDrawA != null) { + doDraw(toDrawA); + } else { + doDraw(toDrawB); + } + + deactivate(); + switchCameraOut(); + JoglTextureStateUtil.doTextureBind(tex, 0, true); + _pbuffer.bindTexture(); + } else { + // render and copy to a texture + activate(); + switchCameraIn(clear); + + if (toDrawA != null) { + doDraw(toDrawA); + } else if (toDrawB != null) { + doDraw(toDrawB); + } else { + doDraw(toDrawC); + } + + switchCameraOut(); + + copyToTexture(tex, 0, 0, _width, _height, 0, 0); + + deactivate(); + } + + } catch (final Exception e) { + logger.logp(Level.SEVERE, this.getClass().toString(), "render(Spatial, Texture)", "Exception", e); + } + } + + public void render(final Spatial spat, final List<Texture> texs, final int clear) { + render(null, spat, null, texs, clear); + } + + public void render(final List<? extends Spatial> spat, final List<Texture> texs, final int clear) { + render(spat, null, null, texs, clear); + } + + public void render(final Scene scene, final List<Texture> texs, final int clear) { + render(null, null, scene, texs, clear); + } + + private void render(final List<? extends Spatial> toDrawA, final Spatial toDrawB, final Scene toDrawC, + final List<Texture> texs, final int clear) { + try { + if (_pbuffer == null) { + initPbuffer(); + } + + if (texs.size() == 1 && _useDirectRender && !texs.get(0).getTextureStoreFormat().isDepthFormat()) { + // setup and render directly to a 2d texture. + JoglTextureStateUtil.doTextureBind(texs.get(0), 0, true); + activate(); + switchCameraIn(clear); + _pbuffer.releaseTexture(); + + if (toDrawA != null) { + doDraw(toDrawA); + } else if (toDrawB != null) { + doDraw(toDrawB); + } else { + doDraw(toDrawC); + } + + switchCameraOut(); + + deactivate(); + _pbuffer.bindTexture(); + } else { + // render and copy to a texture + activate(); + switchCameraIn(clear); + + if (toDrawA != null) { + doDraw(toDrawA); + } else { + doDraw(toDrawB); + } + + switchCameraOut(); + + for (int i = 0; i < texs.size(); i++) { + copyToTexture(texs.get(i), 0, 0, _width, _height, 0, 0); + } + + deactivate(); + } + + } catch (final Exception e) { + logger.logp(Level.SEVERE, this.getClass().toString(), "render(Spatial, Texture)", "Exception", e); + } + } + + public void copyToTexture(final Texture tex, final int x, final int y, final int width, final int height, + final int xoffset, final int yoffset) { + final GL gl = GLU.getCurrentGL(); + + JoglTextureStateUtil.doTextureBind(tex, 0, true); + + gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, width, height); + } + + @Override + protected void clearBuffers(final int clear) { + final GL gl = GLU.getCurrentGL(); + + gl.glDisable(GL.GL_SCISSOR_TEST); + _parentRenderer.clearBuffers(clear); + } + + private void initPbuffer() { + + try { + if (_pbuffer != null) { + _context.destroy(); + _pbuffer.destroy(); + giveBackContext(); + ContextManager.removeContext(_pbuffer); + } + + // Make our GLPbuffer... + final GLDrawableFactory fac = GLDrawableFactory.getFactory(GLProfile.getMaxFixedFunc(true)); + final GLCapabilities caps = new GLCapabilities(GLProfile.getMaxFixedFunc(true)); + caps.setHardwareAccelerated(true); + caps.setDoubleBuffered(true); + caps.setAlphaBits(_settings.getAlphaBits()); + caps.setDepthBits(_settings.getDepthBits()); + caps.setNumSamples(_settings.getSamples()); + caps.setSampleBuffers(_settings.getSamples() != 0); + caps.setStencilBits(_settings.getStencilBits()); + caps.setDoubleBuffered(false); + _pbuffer = fac.createGLPbuffer(null, caps, null, _width, _height, _parentContext); + _context = _pbuffer.getContext(); + + _context.makeCurrent(); + + final JoglContextCapabilities contextCaps = new JoglContextCapabilities(_pbuffer.getGL()); + ContextManager.addContext(_context, + new RenderContext(_context, contextCaps, ContextManager.getCurrentContext())); + + } catch (final Exception e) { + logger.logp(Level.SEVERE, this.getClass().toString(), "initPbuffer()", "Exception", e); + + if (_useDirectRender) { + logger.warning("Your card claims to support Render to Texture but fails to enact it. Updating your driver might solve this problem."); + logger.warning("Attempting to fall back to Copy Texture."); + _useDirectRender = false; + initPbuffer(); + return; + } + + logger.log(Level.WARNING, "Failed to create Pbuffer.", e); + return; + } + + try { + activate(); + + _width = _pbuffer.getWidth(); + _height = _pbuffer.getHeight(); + + deactivate(); + } catch (final Exception e) { + logger.log(Level.WARNING, "Failed to initialize created Pbuffer.", e); + return; + } + } + + private void activate() { + if (_active == 0) { + _oldContext = ContextManager.getCurrentContext(); + _context.makeCurrent(); + + ContextManager.switchContext(_context); + + ContextManager.getCurrentContext().clearEnforcedStates(); + ContextManager.getCurrentContext().enforceStates(_enforcedStates); + + if (_bgColorDirty) { + final GL gl = GLU.getCurrentGL(); + + gl.glClearColor(_backgroundColor.getRed(), _backgroundColor.getGreen(), _backgroundColor.getBlue(), + _backgroundColor.getAlpha()); + _bgColorDirty = false; + } + } + _active++; + } + + private void deactivate() { + if (_active == 1) { + giveBackContext(); + } + _active--; + } + + private void giveBackContext() { + _parentContext.makeCurrent(); + ContextManager.switchContext(_oldContext.getContextKey()); + } + + public void cleanup() { + ContextManager.removeContext(_pbuffer); + _pbuffer.destroy(); + } + + public void setMultipleTargets(final boolean force) { + if (force) { + logger.fine("Copy Texture Pbuffer used!"); + _useDirectRender = false; + if (_pbuffer != null) { + giveBackContext(); + ContextManager.removeContext(_pbuffer); + } + } else { + // XXX: Is this WGL specific query right? + if (GLU.getCurrentGL().isExtensionAvailable("WGL_ARB_render_texture")) { + logger.fine("Render to Texture Pbuffer supported!"); + _useDirectRender = true; + } else { + logger.fine("Copy Texture Pbuffer supported!"); + } + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglRenderer.java b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglRenderer.java new file mode 100644 index 0000000..7812aa6 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglRenderer.java @@ -0,0 +1,1757 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.renderer.jogl; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.Collection; +import java.util.List; +import java.util.logging.Logger; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLException; +import javax.media.opengl.fixedfunc.GLLightingFunc; +import javax.media.opengl.fixedfunc.GLMatrixFunc; +import javax.media.opengl.fixedfunc.GLPointerFunc; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.image.ImageDataFormat; +import com.ardor3d.image.Texture; +import com.ardor3d.image.Texture1D; +import com.ardor3d.image.Texture2D; +import com.ardor3d.image.Texture3D; +import com.ardor3d.image.TextureCubeMap; +import com.ardor3d.image.TextureCubeMap.Face; +import com.ardor3d.math.Matrix4; +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.math.type.ReadOnlyRectangle2; +import com.ardor3d.math.type.ReadOnlyTransform; +import com.ardor3d.math.type.ReadOnlyVector3; +import com.ardor3d.renderer.AbstractRenderer; +import com.ardor3d.renderer.Camera; +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.DrawBufferTarget; +import com.ardor3d.renderer.IndexMode; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.queue.RenderBucketType; +import com.ardor3d.renderer.state.BlendState; +import com.ardor3d.renderer.state.ClipState; +import com.ardor3d.renderer.state.ColorMaskState; +import com.ardor3d.renderer.state.CullState; +import com.ardor3d.renderer.state.FogState; +import com.ardor3d.renderer.state.FragmentProgramState; +import com.ardor3d.renderer.state.GLSLShaderObjectsState; +import com.ardor3d.renderer.state.LightState; +import com.ardor3d.renderer.state.MaterialState; +import com.ardor3d.renderer.state.OffsetState; +import com.ardor3d.renderer.state.RenderState; +import com.ardor3d.renderer.state.ShadingState; +import com.ardor3d.renderer.state.StencilState; +import com.ardor3d.renderer.state.TextureState; +import com.ardor3d.renderer.state.VertexProgramState; +import com.ardor3d.renderer.state.WireframeState; +import com.ardor3d.renderer.state.ZBufferState; +import com.ardor3d.renderer.state.record.LineRecord; +import com.ardor3d.renderer.state.record.RendererRecord; +import com.ardor3d.scene.state.jogl.JoglBlendStateUtil; +import com.ardor3d.scene.state.jogl.JoglClipStateUtil; +import com.ardor3d.scene.state.jogl.JoglColorMaskStateUtil; +import com.ardor3d.scene.state.jogl.JoglCullStateUtil; +import com.ardor3d.scene.state.jogl.JoglFogStateUtil; +import com.ardor3d.scene.state.jogl.JoglFragmentProgramStateUtil; +import com.ardor3d.scene.state.jogl.JoglLightStateUtil; +import com.ardor3d.scene.state.jogl.JoglMaterialStateUtil; +import com.ardor3d.scene.state.jogl.JoglOffsetStateUtil; +import com.ardor3d.scene.state.jogl.JoglShaderObjectsStateUtil; +import com.ardor3d.scene.state.jogl.JoglShadingStateUtil; +import com.ardor3d.scene.state.jogl.JoglStencilStateUtil; +import com.ardor3d.scene.state.jogl.JoglTextureStateUtil; +import com.ardor3d.scene.state.jogl.JoglVertexProgramStateUtil; +import com.ardor3d.scene.state.jogl.JoglWireframeStateUtil; +import com.ardor3d.scene.state.jogl.JoglZBufferStateUtil; +import com.ardor3d.scene.state.jogl.util.JoglRendererUtil; +import com.ardor3d.scene.state.jogl.util.JoglTextureUtil; +import com.ardor3d.scenegraph.AbstractBufferData; +import com.ardor3d.scenegraph.FloatBufferData; +import com.ardor3d.scenegraph.IndexBufferData; +import com.ardor3d.scenegraph.Mesh; +import com.ardor3d.scenegraph.Renderable; +import com.ardor3d.scenegraph.Spatial; +import com.ardor3d.scenegraph.AbstractBufferData.VBOAccessMode; +import com.ardor3d.scenegraph.hint.NormalsMode; +import com.ardor3d.util.Ardor3dException; +import com.ardor3d.util.Constants; +import com.ardor3d.util.geom.BufferUtils; +import com.ardor3d.util.stat.StatCollector; +import com.ardor3d.util.stat.StatType; + +/** + * <code>JoglRenderer</code> provides an implementation of the <code>Renderer</code> interface using the JOGL API. + * + * @see com.ardor3d.renderer.Renderer + */ +public class JoglRenderer extends AbstractRenderer { + private static final Logger logger = Logger.getLogger(JoglRenderer.class.getName()); + + private final FloatBuffer _transformBuffer = BufferUtils.createFloatBuffer(16); + private final Matrix4 _transformMatrix = new Matrix4(); + + /** + * Constructor instantiates a new <code>JoglRenderer</code> object. + */ + public JoglRenderer() { + logger.fine("JoglRenderer created."); + } + + public void setBackgroundColor(final ReadOnlyColorRGBA c) { + final GL gl = GLU.getCurrentGL(); + + _backgroundColor.set(c); + gl.glClearColor(_backgroundColor.getRed(), _backgroundColor.getGreen(), _backgroundColor.getBlue(), + _backgroundColor.getAlpha()); + } + + @Override + public void renderBuckets() { + renderBuckets(true, true); + } + + @Override + public void renderBuckets(final boolean doSort, final boolean doClear) { + _processingQueue = true; + if (doSort && doClear) { + _queue.renderBuckets(this); + } else { + if (doSort) { + _queue.sortBuckets(); + } + _queue.renderOnly(this); + if (doClear) { + _queue.clearBuckets(); + } + } + _processingQueue = false; + } + + /** + * clear the render queue + */ + public void clearQueue() { + _queue.clearBuckets(); + } + + public void clearBuffers(final int buffers) { + clearBuffers(buffers, false); + } + + public void clearBuffers(final int buffers, final boolean strict) { + final GL gl = GLU.getCurrentGL(); + + int clear = 0; + + if ((buffers & Renderer.BUFFER_COLOR) != 0) { + clear |= GL.GL_COLOR_BUFFER_BIT; + } + + if ((buffers & Renderer.BUFFER_DEPTH) != 0) { + clear |= GL.GL_DEPTH_BUFFER_BIT; + + // make sure no funny business is going on in the z before clearing. + if (defaultStateList.containsKey(RenderState.StateType.ZBuffer)) { + defaultStateList.get(RenderState.StateType.ZBuffer).setNeedsRefresh(true); + doApplyState(defaultStateList.get(RenderState.StateType.ZBuffer)); + } + } + + if ((buffers & Renderer.BUFFER_STENCIL) != 0) { + clear |= GL.GL_STENCIL_BUFFER_BIT; + + gl.glClearStencil(_stencilClearValue); + gl.glStencilMask(~0); + gl.glClear(GL.GL_STENCIL_BUFFER_BIT); + } + + if ((buffers & Renderer.BUFFER_ACCUMULATION) != 0) { + clear |= GL2.GL_ACCUM_BUFFER_BIT; + } + + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord record = context.getRendererRecord(); + + if (strict) { + // grab our camera to get width and height info. + final Camera cam = Camera.getCurrentCamera(); + + gl.glEnable(GL.GL_SCISSOR_TEST); + gl.glScissor(0, 0, cam.getWidth(), cam.getHeight()); + record.setClippingTestEnabled(true); + } + + gl.glClear(clear); + + if (strict) { + // put us back. + JoglRendererUtil.applyScissors(record); + } + } + + public void flushFrame(final boolean doSwap) { + final GL gl = GLU.getCurrentGL(); + + renderBuckets(); + + gl.glFlush(); + if (doSwap) { + + doApplyState(defaultStateList.get(RenderState.StateType.ColorMask)); + + if (Constants.stats) { + StatCollector.startStat(StatType.STAT_DISPLAYSWAP_TIMER); + } + + checkCardError(); + GLContext.getCurrent().getGLDrawable().swapBuffers(); + if (Constants.stats) { + StatCollector.endStat(StatType.STAT_DISPLAYSWAP_TIMER); + } + } + + if (Constants.stats) { + StatCollector.addStat(StatType.STAT_FRAMES, 1); + } + } + + public void setOrtho() { + final GL gl = GLU.getCurrentGL(); + + if (_inOrthoMode) { + throw new Ardor3dException("Already in Orthographic mode."); + } + // set up ortho mode + final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord(); + JoglRendererUtil.switchMode(matRecord, GLMatrixFunc.GL_PROJECTION); + gl.getGL2().glPushMatrix(); + gl.getGL2().glLoadIdentity(); + final Camera camera = Camera.getCurrentCamera(); + final double viewportWidth = camera.getWidth() * (camera.getViewPortRight() - camera.getViewPortLeft()); + final double viewportHeight = camera.getHeight() * (camera.getViewPortTop() - camera.getViewPortBottom()); + gl.getGL2().glOrtho(0, viewportWidth, 0, viewportHeight, -1, 1); + JoglRendererUtil.switchMode(matRecord, GLMatrixFunc.GL_MODELVIEW); + gl.getGL2().glPushMatrix(); + gl.getGL2().glLoadIdentity(); + _inOrthoMode = true; + } + + public void unsetOrtho() { + final GL gl = GLU.getCurrentGL(); + + if (!_inOrthoMode) { + throw new Ardor3dException("Not in Orthographic mode."); + } + // remove ortho mode, and go back to original + // state + final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord(); + JoglRendererUtil.switchMode(matRecord, GLMatrixFunc.GL_PROJECTION); + gl.getGL2().glPopMatrix(); + JoglRendererUtil.switchMode(matRecord, GLMatrixFunc.GL_MODELVIEW); + gl.getGL2().glPopMatrix(); + _inOrthoMode = false; + } + + public void grabScreenContents(final ByteBuffer store, final ImageDataFormat format, final int x, final int y, + final int w, final int h) { + final GL gl = GLU.getCurrentGL(); + + final int pixFormat = JoglTextureUtil.getGLPixelFormat(format); + gl.glReadPixels(x, y, w, h, pixFormat, GL.GL_UNSIGNED_BYTE, store); + } + + public void draw(final Spatial s) { + if (s != null) { + s.onDraw(this); + } + } + + public boolean checkAndAdd(final Spatial s) { + final RenderBucketType rqMode = s.getSceneHints().getRenderBucketType(); + if (rqMode != RenderBucketType.Skip) { + getQueue().addToQueue(s, rqMode); + return true; + } + return false; + } + + /** + * re-initializes the GL context for rendering of another piece of geometry. + */ + protected void postdrawGeometry(final Mesh g) { + // Nothing to do here yet + } + + public void flushGraphics() { + final GL gl = GLU.getCurrentGL(); + + gl.glFlush(); + } + + public void finishGraphics() { + final GL gl = GLU.getCurrentGL(); + + gl.glFinish(); + } + + public void applyNormalsMode(final NormalsMode normalsMode, final ReadOnlyTransform worldTransform) { + final GL gl = GLU.getCurrentGL(); + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord rendRecord = context.getRendererRecord(); + if (normalsMode != NormalsMode.Off) { + final ContextCapabilities caps = context.getCapabilities(); + switch (normalsMode) { + case NormalizeIfScaled: + if (worldTransform.isRotationMatrix()) { + final ReadOnlyVector3 scale = worldTransform.getScale(); + if (!(scale.getX() == 1.0 && scale.getY() == 1.0 && scale.getZ() == 1.0)) { + if (scale.getX() == scale.getY() && scale.getY() == scale.getZ() + && caps.isOpenGL1_2Supported() + && rendRecord.getNormalMode() != GL2ES1.GL_RESCALE_NORMAL) { + if (rendRecord.getNormalMode() == GLLightingFunc.GL_NORMALIZE) { + gl.glDisable(GLLightingFunc.GL_NORMALIZE); + } + gl.glEnable(GL2ES1.GL_RESCALE_NORMAL); + rendRecord.setNormalMode(GL2ES1.GL_RESCALE_NORMAL); + } else if (rendRecord.getNormalMode() != GLLightingFunc.GL_NORMALIZE) { + if (rendRecord.getNormalMode() == GL2ES1.GL_RESCALE_NORMAL) { + gl.glDisable(GL2ES1.GL_RESCALE_NORMAL); + } + gl.glEnable(GLLightingFunc.GL_NORMALIZE); + rendRecord.setNormalMode(GLLightingFunc.GL_NORMALIZE); + } + } else { + if (rendRecord.getNormalMode() == GL2ES1.GL_RESCALE_NORMAL) { + gl.glDisable(GL2ES1.GL_RESCALE_NORMAL); + } else if (rendRecord.getNormalMode() == GLLightingFunc.GL_NORMALIZE) { + gl.glDisable(GLLightingFunc.GL_NORMALIZE); + } + rendRecord.setNormalMode(GL.GL_ZERO); + } + } else { + if (!worldTransform.getMatrix().isIdentity()) { + // *might* be scaled... + if (rendRecord.getNormalMode() != GLLightingFunc.GL_NORMALIZE) { + if (rendRecord.getNormalMode() == GL2ES1.GL_RESCALE_NORMAL) { + gl.glDisable(GL2ES1.GL_RESCALE_NORMAL); + } + gl.glEnable(GLLightingFunc.GL_NORMALIZE); + rendRecord.setNormalMode(GLLightingFunc.GL_NORMALIZE); + } + } else { + // not scaled + if (rendRecord.getNormalMode() == GL2ES1.GL_RESCALE_NORMAL) { + gl.glDisable(GL2ES1.GL_RESCALE_NORMAL); + } else if (rendRecord.getNormalMode() == GLLightingFunc.GL_NORMALIZE) { + gl.glDisable(GLLightingFunc.GL_NORMALIZE); + } + rendRecord.setNormalMode(GL.GL_ZERO); + } + } + break; + case AlwaysNormalize: + if (rendRecord.getNormalMode() != GLLightingFunc.GL_NORMALIZE) { + if (rendRecord.getNormalMode() == GL2ES1.GL_RESCALE_NORMAL) { + gl.glDisable(GL2ES1.GL_RESCALE_NORMAL); + } + gl.glEnable(GLLightingFunc.GL_NORMALIZE); + rendRecord.setNormalMode(GLLightingFunc.GL_NORMALIZE); + } + break; + case UseProvided: + default: + if (rendRecord.getNormalMode() == GL2ES1.GL_RESCALE_NORMAL) { + gl.glDisable(GL2ES1.GL_RESCALE_NORMAL); + } else if (rendRecord.getNormalMode() == GLLightingFunc.GL_NORMALIZE) { + gl.glDisable(GLLightingFunc.GL_NORMALIZE); + } + rendRecord.setNormalMode(GL.GL_ZERO); + break; + } + } else { + if (rendRecord.getNormalMode() == GL2ES1.GL_RESCALE_NORMAL) { + gl.glDisable(GL2ES1.GL_RESCALE_NORMAL); + } else if (rendRecord.getNormalMode() == GLLightingFunc.GL_NORMALIZE) { + gl.glDisable(GLLightingFunc.GL_NORMALIZE); + } + rendRecord.setNormalMode(GL.GL_ZERO); + } + } + + public void applyDefaultColor(final ReadOnlyColorRGBA defaultColor) { + final GL gl = GLU.getCurrentGL(); + if (defaultColor != null) { + gl.getGL2().glColor4f(defaultColor.getRed(), defaultColor.getGreen(), defaultColor.getBlue(), defaultColor + .getAlpha()); + } else { + gl.getGL2().glColor4f(1, 1, 1, 1); + } + } + + public void deleteVBOs(final Collection<Integer> ids) { + final GL gl = GLU.getCurrentGL(); + final IntBuffer idBuffer = BufferUtils.createIntBuffer(ids.size()); + idBuffer.clear(); + for (final Integer i : ids) { + if (i != null && i != 0) { + idBuffer.put(i); + } + } + idBuffer.flip(); + if (idBuffer.remaining() > 0) { + gl.glDeleteBuffers(idBuffer.remaining(), idBuffer); + } + } + + public void deleteDisplayLists(final Collection<Integer> ids) { + final GL gl = GLU.getCurrentGL(); + for (final Integer i : ids) { + if (i != null && i != 0) { + gl.getGL2().glDeleteLists(i, 1); + } + } + } + + public void deleteVBOs(final AbstractBufferData<?> buffer) { + if (buffer == null) { + return; + } + + final GL gl = GLU.getCurrentGL(); + + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + + final int id = buffer.getVBOID(context.getGlContextRep()); + if (id == 0) { + // Not on card... return. + return; + } + + buffer.removeVBOID(context.getGlContextRep()); + + final IntBuffer idBuff = BufferUtils.createIntBuffer(1); + idBuff.put(id); + idBuff.flip(); + gl.glDeleteBuffers(1, idBuff); + } + + public void updateTexture1DSubImage(final Texture1D destination, final int dstOffsetX, final int dstWidth, + final ByteBuffer source, final int srcOffsetX) { + updateTexSubImage(destination, dstOffsetX, 0, 0, dstWidth, 0, 0, source, srcOffsetX, 0, 0, 0, 0, null); + } + + public void updateTexture2DSubImage(final Texture2D destination, final int dstOffsetX, final int dstOffsetY, + final int dstWidth, final int dstHeight, final ByteBuffer source, final int srcOffsetX, + final int srcOffsetY, final int srcTotalWidth) { + updateTexSubImage(destination, dstOffsetX, dstOffsetY, 0, dstWidth, dstHeight, 0, source, srcOffsetX, + srcOffsetY, 0, srcTotalWidth, 0, null); + } + + public void updateTexture3DSubImage(final Texture3D destination, final int dstOffsetX, final int dstOffsetY, + final int dstOffsetZ, final int dstWidth, final int dstHeight, final int dstDepth, final ByteBuffer source, + final int srcOffsetX, final int srcOffsetY, final int srcOffsetZ, final int srcTotalWidth, + final int srcTotalHeight) { + updateTexSubImage(destination, dstOffsetX, dstOffsetY, dstOffsetZ, dstWidth, dstHeight, dstDepth, source, + srcOffsetX, srcOffsetY, srcOffsetZ, srcTotalWidth, srcTotalHeight, null); + } + + public void updateTextureCubeMapSubImage(final TextureCubeMap destination, final TextureCubeMap.Face dstFace, + final int dstOffsetX, final int dstOffsetY, final int dstWidth, final int dstHeight, + final ByteBuffer source, final int srcOffsetX, final int srcOffsetY, final int srcTotalWidth) { + updateTexSubImage(destination, dstOffsetX, dstOffsetY, 0, dstWidth, dstHeight, 0, source, srcOffsetX, + srcOffsetY, 0, srcTotalWidth, 0, dstFace); + } + + private void updateTexSubImage(final Texture destination, final int dstOffsetX, final int dstOffsetY, + final int dstOffsetZ, final int dstWidth, final int dstHeight, final int dstDepth, final ByteBuffer source, + final int srcOffsetX, final int srcOffsetY, final int srcOffsetZ, final int srcTotalWidth, + final int srcTotalHeight, final Face dstFace) { + + final GL gl = GLU.getCurrentGL(); + + // Ignore textures that do not have an id set + if (destination.getTextureIdForContext(ContextManager.getCurrentContext().getGlContextRep()) == 0) { + logger.warning("Attempting to update a texture that is not currently on the card."); + return; + } + + // Determine the original texture configuration, so that this method can + // restore the texture configuration to its original state. + final int origAlignment[] = new int[1]; + gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, origAlignment, 0); + final int origRowLength = 0; + final int origImageHeight = 0; + final int origSkipPixels = 0; + final int origSkipRows = 0; + final int origSkipImages = 0; + + final int alignment = 1; + + int rowLength; + if (srcTotalWidth == dstWidth) { + // When the row length is zero, then the width parameter is used. + // We use zero in these cases in the hope that we can avoid two + // unnecessary calls to glPixelStorei. + rowLength = 0; + } else { + // The number of pixels in a row is different than the number of + // pixels in the region to be uploaded to the texture. + rowLength = srcTotalWidth; + } + + int imageHeight; + if (srcTotalHeight == dstHeight) { + // When the image height is zero, then the height parameter is used. + // We use zero in these cases in the hope that we can avoid two + // unnecessary calls to glPixelStorei. + imageHeight = 0; + } else { + // The number of pixels in a row is different than the number of + // pixels in the region to be uploaded to the texture. + imageHeight = srcTotalHeight; + } + + // Grab pixel format + final int pixelFormat; + if (destination.getImage() != null) { + pixelFormat = JoglTextureUtil.getGLPixelFormat(destination.getImage().getDataFormat()); + } else { + pixelFormat = JoglTextureUtil.getGLPixelFormatFromStoreFormat(destination.getTextureStoreFormat()); + } + + // bind... + JoglTextureStateUtil.doTextureBind(destination, 0, false); + + // Update the texture configuration (when necessary). + + if (origAlignment[0] != alignment) { + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, alignment); + } + if (origRowLength != rowLength) { + gl.glPixelStorei(GL2ES2.GL_UNPACK_ROW_LENGTH, rowLength); + } + if (origSkipPixels != srcOffsetX) { + gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_PIXELS, srcOffsetX); + } + // NOTE: The below will be skipped for texture types that don't support them because we are passing in 0's. + if (origSkipRows != srcOffsetY) { + gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_ROWS, srcOffsetY); + } + if (origImageHeight != imageHeight) { + gl.glPixelStorei(GL2GL3.GL_UNPACK_IMAGE_HEIGHT, imageHeight); + } + if (origSkipImages != srcOffsetZ) { + gl.glPixelStorei(GL2GL3.GL_UNPACK_SKIP_IMAGES, srcOffsetZ); + } + + // Upload the image region into the texture. + try { + switch (destination.getType()) { + case TwoDimensional: + gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, dstOffsetX, dstOffsetY, dstWidth, dstHeight, pixelFormat, + GL.GL_UNSIGNED_BYTE, source); + break; + case OneDimensional: + gl.getGL2GL3().glTexSubImage1D(GL2GL3.GL_TEXTURE_1D, 0, dstOffsetX, dstWidth, pixelFormat, GL.GL_UNSIGNED_BYTE, + source); + break; + case ThreeDimensional: + gl.getGL2GL3().glTexSubImage3D(GL2ES2.GL_TEXTURE_3D, 0, dstOffsetX, dstOffsetY, dstOffsetZ, dstWidth, dstHeight, + dstDepth, pixelFormat, GL.GL_UNSIGNED_BYTE, source); + break; + case CubeMap: + gl.glTexSubImage2D(JoglTextureStateUtil.getGLCubeMapFace(dstFace), 0, dstOffsetX, dstOffsetY, + dstWidth, dstHeight, pixelFormat, GL.GL_UNSIGNED_BYTE, source); + break; + default: + throw new Ardor3dException("Unsupported type for updateTextureSubImage: " + destination.getType()); + } + } finally { + // Restore the texture configuration (when necessary)... + // Restore alignment. + if (origAlignment[0] != alignment) { + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, origAlignment[0]); + } + // Restore row length. + if (origRowLength != rowLength) { + gl.glPixelStorei(GL2ES2.GL_UNPACK_ROW_LENGTH, origRowLength); + } + // Restore skip pixels. + if (origSkipPixels != srcOffsetX) { + gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_PIXELS, origSkipPixels); + } + // Restore skip rows. + if (origSkipRows != srcOffsetY) { + gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_ROWS, origSkipRows); + } + // Restore image height. + if (origImageHeight != imageHeight) { + gl.glPixelStorei(GL2GL3.GL_UNPACK_IMAGE_HEIGHT, origImageHeight); + } + // Restore skip images. + if (origSkipImages != srcOffsetZ) { + gl.glPixelStorei(GL2GL3.GL_UNPACK_SKIP_IMAGES, origSkipImages); + } + } + } + + public void checkCardError() throws Ardor3dException { + final GL gl = GLU.getCurrentGL(); + final GLU glu = new GLU(); + + try { + final int errorCode = gl.glGetError(); + if (errorCode != GL.GL_NO_ERROR) { + throw new GLException(glu.gluErrorString(errorCode)); + } + } catch (final GLException exception) { + throw new Ardor3dException("Error in opengl: " + exception.getMessage(), exception); + } + } + + public void draw(final Renderable renderable) { + if (renderLogic != null) { + renderLogic.apply(renderable); + } + renderable.render(this); + if (renderLogic != null) { + renderLogic.restore(renderable); + } + } + + public boolean doTransforms(final ReadOnlyTransform transform) { + final GL gl = GLU.getCurrentGL(); + + // set world matrix + if (!transform.isIdentity()) { + synchronized (_transformMatrix) { + transform.getGLApplyMatrix(_transformBuffer); + + final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord(); + JoglRendererUtil.switchMode(matRecord, GLMatrixFunc.GL_MODELVIEW); + gl.getGL2().glPushMatrix(); + gl.getGL2().glMultMatrixf(_transformBuffer); + return true; + } + } + return false; + } + + public void undoTransforms(final ReadOnlyTransform transform) { + final GL gl = GLU.getCurrentGL(); + + final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord(); + JoglRendererUtil.switchMode(matRecord, GLMatrixFunc.GL_MODELVIEW); + gl.getGL2().glPopMatrix(); + } + + public void setupVertexData(final FloatBufferData vertexBufferData) { + final GL gl = GLU.getCurrentGL(); + + final FloatBuffer vertexBuffer = vertexBufferData != null ? vertexBufferData.getBuffer() : null; + + if (vertexBuffer == null) { + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + } else { + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + vertexBuffer.rewind(); + gl.getGL2().glVertexPointer(vertexBufferData.getValuesPerTuple(), GL.GL_FLOAT, 0, vertexBuffer); + } + } + + public void setupNormalData(final FloatBufferData normalBufferData) { + final GL gl = GLU.getCurrentGL(); + + final FloatBuffer normalBuffer = normalBufferData != null ? normalBufferData.getBuffer() : null; + + if (normalBuffer == null) { + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY); + } else { + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY); + normalBuffer.rewind(); + gl.getGL2().glNormalPointer(GL.GL_FLOAT, 0, normalBuffer); + } + } + + public void setupColorData(final FloatBufferData colorBufferData) { + final GL gl = GLU.getCurrentGL(); + + final FloatBuffer colorBuffer = colorBufferData != null ? colorBufferData.getBuffer() : null; + + if (colorBuffer == null) { + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY); + } else { + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY); + colorBuffer.rewind(); + gl.getGL2().glColorPointer(colorBufferData.getValuesPerTuple(), GL.GL_FLOAT, 0, colorBuffer); + } + } + + public void setupFogData(final FloatBufferData fogBufferData) { + final GL gl = GLU.getCurrentGL(); + + final FloatBuffer fogBuffer = fogBufferData != null ? fogBufferData.getBuffer() : null; + + if (fogBuffer == null) { + gl.getGL2GL3().glDisableClientState(GL2.GL_FOG_COORDINATE_ARRAY); + } else { + gl.getGL2GL3().glEnableClientState(GL2.GL_FOG_COORDINATE_ARRAY); + fogBuffer.rewind(); + gl.getGL2().glFogCoordPointer(GL.GL_FLOAT, 0, fogBuffer); + } + } + + public void setupTextureData(final List<FloatBufferData> textureCoords) { + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + final RendererRecord rendRecord = context.getRendererRecord(); + + final TextureState ts = (TextureState) context.getCurrentState(RenderState.StateType.Texture); + int enabledTextures = rendRecord.getEnabledTextures(); + final boolean valid = rendRecord.isTexturesValid(); + boolean isOn, wasOn; + if (ts != null) { + final int max = caps.isMultitextureSupported() ? Math.min(caps.getNumberOfFragmentTexCoordUnits(), + TextureState.MAX_TEXTURES) : 1; + for (int i = 0; i < max; i++) { + wasOn = (enabledTextures & (2 << i)) != 0; + isOn = textureCoords != null && i < textureCoords.size() && textureCoords.get(i) != null + && textureCoords.get(i).getBuffer() != null; + + if (!isOn) { + if (valid && !wasOn) { + continue; + } else { + checkAndSetTextureArrayUnit(i, gl, rendRecord, caps); + + // disable bit in tracking int + enabledTextures &= ~(2 << i); + + // disable state + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + + continue; + } + } else { + checkAndSetTextureArrayUnit(i, gl, rendRecord, caps); + + if (!valid || !wasOn) { + // enable state + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + + // enable bit in tracking int + enabledTextures |= (2 << i); + } + + final FloatBufferData textureBufferData = textureCoords.get(i); + final FloatBuffer textureBuffer = textureBufferData.getBuffer(); + + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + textureBuffer.rewind(); + gl.getGL2().glTexCoordPointer(textureBufferData.getValuesPerTuple(), GL.GL_FLOAT, 0, textureBuffer); + } + } + } + + rendRecord.setEnabledTextures(enabledTextures); + rendRecord.setTexturesValid(true); + } + + public void drawElements(final IndexBufferData<?> indices, final int[] indexLengths, final IndexMode[] indexModes, + final int primcount) { + if (indices == null || indices.getBuffer() == null) { + logger.severe("Missing indices for drawElements call without VBO"); + return; + } + + final GL gl = GLU.getCurrentGL(); + + final int type = getGLDataType(indices); + if (indexLengths == null) { + final int glIndexMode = getGLIndexMode(indexModes[0]); + + indices.position(0); + + if (primcount < 0) { + gl.glDrawElements(glIndexMode, indices.getBufferLimit(), type, indices.getBuffer()); + } else { + gl.getGL2GL3().glDrawElementsInstanced(glIndexMode, indices.getBufferLimit(), type, indices.getBuffer(), + primcount); + } + + if (Constants.stats) { + addStats(indexModes[0], indices.getBufferLimit()); + } + } else { + int offset = 0; + int indexModeCounter = 0; + for (int i = 0; i < indexLengths.length; i++) { + final int count = indexLengths[i]; + + final int glIndexMode = getGLIndexMode(indexModes[indexModeCounter]); + + indices.getBuffer().position(offset); + indices.getBuffer().limit(offset + count); + + if (primcount < 0) { + gl.glDrawElements(glIndexMode, count, type, indices.getBuffer()); + } else { + gl.getGL2GL3().glDrawElementsInstanced(glIndexMode, count, type, indices.getBuffer(), primcount); + } + + if (Constants.stats) { + addStats(indexModes[indexModeCounter], count); + } + + offset += count; + + if (indexModeCounter < indexModes.length - 1) { + indexModeCounter++; + } + } + } + } + + public static int setupVBO(final AbstractBufferData<? extends Buffer> data, final RenderContext context) { + if (data == null) { + return 0; + } + + final GL gl = GLU.getCurrentGL(); + + final RendererRecord rendRecord = context.getRendererRecord(); + int vboID = data.getVBOID(context.getGlContextRep()); + if (vboID != 0) { + updateVBO(data, rendRecord, vboID, 0); + return vboID; + } + + final Buffer dataBuffer = data.getBuffer(); + if (dataBuffer != null) { + // XXX: should we be rewinding? Maybe make that the programmer's responsibility. + dataBuffer.rewind(); + vboID = makeVBOId(); + data.setVBOID(context.getGlContextRep(), vboID); + + rendRecord.invalidateVBO(); + JoglRendererUtil.setBoundVBO(rendRecord, vboID); + gl.glBufferData(GL.GL_ARRAY_BUFFER, dataBuffer.limit() * data.getByteCount(), dataBuffer, + getGLVBOAccessMode(data.getVboAccessMode())); + } else { + throw new Ardor3dException("Attempting to create a vbo id for an AbstractBufferData with no Buffer value."); + } + return vboID; + } + + private static void updateVBO(final AbstractBufferData<? extends Buffer> data, final RendererRecord rendRecord, + final int vboID, final int offsetBytes) { + if (data.isNeedsRefresh()) { + final GL gl = GLU.getCurrentGL(); + final Buffer dataBuffer = data.getBuffer(); + dataBuffer.rewind(); + JoglRendererUtil.setBoundVBO(rendRecord, vboID); + gl.glBufferSubData(GL.GL_ARRAY_BUFFER, offsetBytes, dataBuffer.limit() * data.getByteCount(), + dataBuffer); + data.setNeedsRefresh(false); + } + } + + private int setupIndicesVBO(final IndexBufferData<?> data, final RenderContext context, + final RendererRecord rendRecord) { + if (data == null) { + return 0; + } + + final GL gl = GLU.getCurrentGL(); + + int vboID = data.getVBOID(context.getGlContextRep()); + if (vboID != 0) { + if (data.isNeedsRefresh()) { + final Buffer dataBuffer = data.getBuffer(); + dataBuffer.rewind(); + JoglRendererUtil.setBoundElementVBO(rendRecord, vboID); + gl.glBufferSubData(GL.GL_ELEMENT_ARRAY_BUFFER, 0, dataBuffer.limit() * data.getByteCount(), + dataBuffer); + data.setNeedsRefresh(false); + } + + return vboID; + } + + final Buffer dataBuffer = data.getBuffer(); + if (dataBuffer != null) { + // XXX: should we be rewinding? Maybe make that the programmer's responsibility. + dataBuffer.rewind(); + vboID = makeVBOId(); + data.setVBOID(context.getGlContextRep(), vboID); + + rendRecord.invalidateVBO(); + JoglRendererUtil.setBoundElementVBO(rendRecord, vboID); + gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, dataBuffer.limit() * data.getByteCount(), dataBuffer, + getGLVBOAccessMode(data.getVboAccessMode())); + } else { + throw new Ardor3dException("Attempting to create a vbo id for a IndexBufferData with no Buffer value."); + } + return vboID; + } + + public void setupVertexDataVBO(final FloatBufferData data) { + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord rendRecord = context.getRendererRecord(); + + final int vboID = setupVBO(data, context); + + if (vboID != 0) { + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + JoglRendererUtil.setBoundVBO(rendRecord, vboID); + gl.getGL2().glVertexPointer(data.getValuesPerTuple(), GL.GL_FLOAT, 0, 0); + } else { + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + } + } + + public void setupNormalDataVBO(final FloatBufferData data) { + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord rendRecord = context.getRendererRecord(); + + final int vboID = setupVBO(data, context); + + if (vboID != 0) { + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY); + JoglRendererUtil.setBoundVBO(rendRecord, vboID); + gl.getGL2().glNormalPointer(GL.GL_FLOAT, 0, 0); + } else { + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY); + } + } + + public void setupColorDataVBO(final FloatBufferData data) { + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord rendRecord = context.getRendererRecord(); + + final int vboID = setupVBO(data, context); + + if (vboID != 0) { + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY); + JoglRendererUtil.setBoundVBO(rendRecord, vboID); + gl.getGL2().glColorPointer(data.getValuesPerTuple(), GL.GL_FLOAT, 0, 0); + } else { + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY); + } + } + + public void setupFogDataVBO(final FloatBufferData data) { + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + + if (!caps.isFogCoordinatesSupported()) { + return; + } + + final RendererRecord rendRecord = context.getRendererRecord(); + final int vboID = setupVBO(data, context); + + if (vboID != 0) { + gl.getGL2GL3().glEnableClientState(GL2.GL_FOG_COORDINATE_ARRAY); + JoglRendererUtil.setBoundVBO(rendRecord, vboID); + gl.getGL2().glFogCoordPointer(GL.GL_FLOAT, 0, 0); + } else { + gl.getGL2GL3().glDisableClientState(GL2.GL_FOG_COORDINATE_ARRAY); + } + } + + public void setupTextureDataVBO(final List<FloatBufferData> textureCoords) { + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord rendRecord = context.getRendererRecord(); + final ContextCapabilities caps = context.getCapabilities(); + + final TextureState ts = (TextureState) context.getCurrentState(RenderState.StateType.Texture); + int enabledTextures = rendRecord.getEnabledTextures(); + final boolean valid = rendRecord.isTexturesValid(); + boolean exists, wasOn; + if (ts != null) { + final int max = caps.isMultitextureSupported() ? Math.min(caps.getNumberOfFragmentTexCoordUnits(), + TextureState.MAX_TEXTURES) : 1; + for (int i = 0; i < max; i++) { + wasOn = (enabledTextures & (2 << i)) != 0; + exists = textureCoords != null && i < textureCoords.size(); + + if (!exists) { + if (valid && !wasOn) { + continue; + } else { + checkAndSetTextureArrayUnit(i, gl, rendRecord, caps); + + // disable bit in tracking int + enabledTextures &= ~(2 << i); + + // disable state + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + + continue; + } + } else { + checkAndSetTextureArrayUnit(i, gl, rendRecord, caps); + + // grab a vboID and make sure it exists and is up to date. + final FloatBufferData data = textureCoords.get(i); + final int vboID = setupVBO(data, context); + + // Found good vbo + if (vboID != 0) { + if (!valid || !wasOn) { + // enable bit in tracking int + enabledTextures |= (2 << i); + + // enable state + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + } + + // set our active vbo + JoglRendererUtil.setBoundVBO(rendRecord, vboID); + + // send data + gl.getGL2().glTexCoordPointer(data.getValuesPerTuple(), GL.GL_FLOAT, 0, 0); + } + // Not a good vbo, disable it. + else { + if (!valid || wasOn) { + // disable bit in tracking int + enabledTextures &= ~(2 << i); + + // disable state + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + } + } + } + } + } + + rendRecord.setEnabledTextures(enabledTextures); + rendRecord.setTexturesValid(true); + } + + public void setupInterleavedDataVBO(final FloatBufferData interleaved, final FloatBufferData vertexCoords, + final FloatBufferData normalCoords, final FloatBufferData colorCoords, + final List<FloatBufferData> textureCoords) { + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord rendRecord = context.getRendererRecord(); + final ContextCapabilities caps = context.getCapabilities(); + + final int lengthBytes = getTotalInterleavedSize(context, vertexCoords, normalCoords, colorCoords, textureCoords); + int currLengthBytes = 0; + if (interleaved.getBufferLimit() > 0) { + interleaved.getBuffer().rewind(); + currLengthBytes = Math.round(interleaved.getBuffer().get()); + } + + if (lengthBytes != currLengthBytes || interleaved.getVBOID(context.getGlContextRep()) == 0 + || interleaved.isNeedsRefresh()) { + initializeInterleavedVBO(context, interleaved, vertexCoords, normalCoords, colorCoords, textureCoords, + lengthBytes); + } + + final int vboID = interleaved.getVBOID(context.getGlContextRep()); + JoglRendererUtil.setBoundVBO(rendRecord, vboID); + + int offsetBytes = 0; + + if (normalCoords != null) { + updateVBO(normalCoords, rendRecord, vboID, offsetBytes); + gl.getGL2().glNormalPointer(GL.GL_FLOAT, 0, offsetBytes); + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY); + offsetBytes += normalCoords.getBufferLimit() * 4; + } else { + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY); + } + + if (colorCoords != null) { + updateVBO(colorCoords, rendRecord, vboID, offsetBytes); + gl.getGL2().glColorPointer(colorCoords.getValuesPerTuple(), GL.GL_FLOAT, 0, offsetBytes); + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY); + offsetBytes += colorCoords.getBufferLimit() * 4; + } else { + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY); + } + + if (textureCoords != null) { + final TextureState ts = (TextureState) context.getCurrentState(RenderState.StateType.Texture); + int enabledTextures = rendRecord.getEnabledTextures(); + final boolean valid = rendRecord.isTexturesValid(); + boolean exists, wasOn; + if (ts != null) { + final int max = caps.isMultitextureSupported() ? Math.min(caps.getNumberOfFragmentTexCoordUnits(), + TextureState.MAX_TEXTURES) : 1; + for (int i = 0; i < max; i++) { + wasOn = (enabledTextures & (2 << i)) != 0; + exists = textureCoords != null && i < textureCoords.size() && textureCoords.get(i) != null + && i <= ts.getMaxTextureIndexUsed(); + + if (!exists) { + if (valid && !wasOn) { + continue; + } else { + checkAndSetTextureArrayUnit(i, gl, rendRecord, caps); + + // disable bit in tracking int + enabledTextures &= ~(2 << i); + + // disable state + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + + continue; + } + + } else { + checkAndSetTextureArrayUnit(i, gl, rendRecord, caps); + + // grab a vboID and make sure it exists and is up to date. + final FloatBufferData textureBufferData = textureCoords.get(i); + updateVBO(textureBufferData, rendRecord, vboID, offsetBytes); + + if (!valid || !wasOn) { + // enable bit in tracking int + enabledTextures |= (2 << i); + + // enable state + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + } + + // send data + gl.getGL2().glTexCoordPointer(textureBufferData.getValuesPerTuple(), GL.GL_FLOAT, 0, offsetBytes); + offsetBytes += textureBufferData.getBufferLimit() * 4; + } + } + } + + rendRecord.setEnabledTextures(enabledTextures); + rendRecord.setTexturesValid(true); + } + + if (vertexCoords != null) { + updateVBO(vertexCoords, rendRecord, vboID, offsetBytes); + gl.getGL2().glVertexPointer(vertexCoords.getValuesPerTuple(), GL.GL_FLOAT, 0, offsetBytes); + gl.getGL2GL3().glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + } else { + gl.getGL2GL3().glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + } + } + + private void initializeInterleavedVBO(final RenderContext context, final FloatBufferData interleaved, + final FloatBufferData vertexCoords, final FloatBufferData normalCoords, final FloatBufferData colorCoords, + final List<FloatBufferData> textureCoords, final int bufferSize) { + + // keep around buffer size + if (interleaved.getBufferCapacity() != 1) { + final FloatBuffer buffer = BufferUtils.createFloatBufferOnHeap(1); + interleaved.setBuffer(buffer); + } + interleaved.getBuffer().rewind(); + interleaved.getBuffer().put(bufferSize); + + final GL gl = GLU.getCurrentGL(); + + final RendererRecord rendRecord = context.getRendererRecord(); + final ContextCapabilities caps = context.getCapabilities(); + + final int vboID = makeVBOId(); + interleaved.setVBOID(context.getGlContextRep(), vboID); + + rendRecord.invalidateVBO(); + JoglRendererUtil.setBoundVBO(rendRecord, vboID); + gl + .glBufferData(GL.GL_ARRAY_BUFFER, bufferSize, null, getGLVBOAccessMode(interleaved + .getVboAccessMode())); + + int offset = 0; + if (normalCoords != null) { + normalCoords.getBuffer().rewind(); + gl.glBufferSubData(GL.GL_ARRAY_BUFFER, offset, normalCoords.getBufferLimit() * 4, normalCoords + .getBuffer()); + offset += normalCoords.getBufferLimit() * 4; + } + if (colorCoords != null) { + colorCoords.getBuffer().rewind(); + gl.glBufferSubData(GL.GL_ARRAY_BUFFER, offset, colorCoords.getBufferLimit() * 4, colorCoords + .getBuffer()); + offset += colorCoords.getBufferLimit() * 4; + } + if (textureCoords != null) { + final TextureState ts = (TextureState) context.getCurrentState(RenderState.StateType.Texture); + if (ts != null) { + for (int i = 0; i <= ts.getMaxTextureIndexUsed() && i < caps.getNumberOfFragmentTexCoordUnits(); i++) { + if (textureCoords == null || i >= textureCoords.size()) { + continue; + } + + final FloatBufferData textureBufferData = textureCoords.get(i); + final FloatBuffer textureBuffer = textureBufferData != null ? textureBufferData.getBuffer() : null; + if (textureBuffer != null) { + textureBuffer.rewind(); + gl.glBufferSubData(GL.GL_ARRAY_BUFFER, offset, textureBufferData.getBufferLimit() * 4, + textureBuffer); + offset += textureBufferData.getBufferLimit() * 4; + } + } + } + } + if (vertexCoords != null) { + vertexCoords.getBuffer().rewind(); + gl.glBufferSubData(GL.GL_ARRAY_BUFFER, offset, vertexCoords.getBufferLimit() * 4, vertexCoords + .getBuffer()); + } + + interleaved.setNeedsRefresh(false); + } + + public void drawElementsVBO(final IndexBufferData<?> indices, final int[] indexLengths, + final IndexMode[] indexModes, final int primcount) { + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord rendRecord = context.getRendererRecord(); + + final int vboID = setupIndicesVBO(indices, context, rendRecord); + + JoglRendererUtil.setBoundElementVBO(rendRecord, vboID); + + if (indexLengths == null) { + final int glIndexMode = getGLIndexMode(indexModes[0]); + + final int type = getGLDataType(indices); + + if (primcount < 0) { + gl.glDrawElements(glIndexMode, indices.getBufferLimit(), type, 0); + } else { + gl.getGL2GL3().glDrawElementsInstanced(glIndexMode, indices.getBufferLimit(), type, indices.getBuffer(), + primcount); + } + + if (Constants.stats) { + addStats(indexModes[0], indices.getBufferLimit()); + } + } else { + int offset = 0; + int indexModeCounter = 0; + for (int i = 0; i < indexLengths.length; i++) { + final int count = indexLengths[i]; + + final int glIndexMode = getGLIndexMode(indexModes[indexModeCounter]); + + final int type = getGLDataType(indices); + final int byteSize = indices.getByteCount(); + // offset in this call is done in bytes. + gl.glDrawElements(glIndexMode, count, type, offset * byteSize); + + if (primcount < 0) { + gl.glDrawElements(glIndexMode, count, type, offset * byteSize); + } else { + final int previousPos = indices.getBuffer().position(); + indices.getBuffer().position(offset * byteSize); + gl.getGL2GL3().glDrawElementsInstanced(glIndexMode, count, type, indices.getBuffer(), primcount); + indices.getBuffer().position(previousPos); + } + + if (Constants.stats) { + addStats(indexModes[indexModeCounter], count); + } + + offset += count; + + if (indexModeCounter < indexModes.length - 1) { + indexModeCounter++; + } + } + } + } + + public void drawArrays(final FloatBufferData vertexBuffer, final int[] indexLengths, final IndexMode[] indexModes, + final int primcount) { + final GL gl = GLU.getCurrentGL(); + + if (indexLengths == null) { + final int glIndexMode = getGLIndexMode(indexModes[0]); + + if (primcount < 0) { + gl.glDrawArrays(glIndexMode, 0, vertexBuffer.getTupleCount()); + } else { + gl.getGL2GL3().glDrawArraysInstanced(glIndexMode, 0, vertexBuffer.getTupleCount(), primcount); + } + + if (Constants.stats) { + addStats(indexModes[0], vertexBuffer.getTupleCount()); + } + } else { + int offset = 0; + int indexModeCounter = 0; + for (int i = 0; i < indexLengths.length; i++) { + final int count = indexLengths[i]; + + final int glIndexMode = getGLIndexMode(indexModes[indexModeCounter]); + + if (primcount < 0) { + gl.glDrawArrays(glIndexMode, offset, count); + } else { + gl.getGL2GL3().glDrawArraysInstanced(glIndexMode, offset, count, primcount); + } + + if (Constants.stats) { + addStats(indexModes[indexModeCounter], count); + } + + offset += count; + + if (indexModeCounter < indexModes.length - 1) { + indexModeCounter++; + } + } + } + } + + private static int makeVBOId() { + final GL gl = GLU.getCurrentGL(); + + final IntBuffer idBuff = BufferUtils.createIntBuffer(1); + gl.glGenBuffers(1, idBuff); + return idBuff.get(0); + } + + public void unbindVBO() { + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord rendRecord = context.getRendererRecord(); + JoglRendererUtil.setBoundVBO(rendRecord, 0); + JoglRendererUtil.setBoundElementVBO(rendRecord, 0); + } + + private static int getGLVBOAccessMode(final VBOAccessMode vboAccessMode) { + int glMode = GL.GL_STATIC_DRAW; + switch (vboAccessMode) { + case StaticDraw: + glMode = GL.GL_STATIC_DRAW; + break; + case StaticRead: + glMode = GL2GL3.GL_STATIC_READ; + break; + case StaticCopy: + glMode = GL2GL3.GL_STATIC_COPY; + break; + case DynamicDraw: + glMode = GL.GL_DYNAMIC_DRAW; + break; + case DynamicRead: + glMode = GL2GL3.GL_DYNAMIC_READ; + break; + case DynamicCopy: + glMode = GL2GL3.GL_DYNAMIC_COPY; + break; + case StreamDraw: + glMode = GL2ES2.GL_STREAM_DRAW; + break; + case StreamRead: + glMode = GL2GL3.GL_STREAM_READ; + break; + case StreamCopy: + glMode = GL2GL3.GL_STREAM_COPY; + break; + } + return glMode; + } + + private int getGLIndexMode(final IndexMode indexMode) { + int glMode = GL.GL_TRIANGLES; + switch (indexMode) { + case Triangles: + glMode = GL.GL_TRIANGLES; + break; + case TriangleStrip: + glMode = GL.GL_TRIANGLE_STRIP; + break; + case TriangleFan: + glMode = GL.GL_TRIANGLE_FAN; + break; + case Quads: + glMode = GL2.GL_QUADS; + break; + case QuadStrip: + glMode = GL2.GL_QUAD_STRIP; + break; + case Lines: + glMode = GL.GL_LINES; + break; + case LineStrip: + glMode = GL.GL_LINE_STRIP; + break; + case LineLoop: + glMode = GL.GL_LINE_LOOP; + break; + case Points: + glMode = GL.GL_POINTS; + break; + } + return glMode; + } + + private int getGLDataType(final IndexBufferData<?> indices) { + if (indices.getBuffer() instanceof ByteBuffer) { + return GL.GL_UNSIGNED_BYTE; + } else if (indices.getBuffer() instanceof ShortBuffer) { + return GL.GL_UNSIGNED_SHORT; + } else if (indices.getBuffer() instanceof IntBuffer) { + return GL.GL_UNSIGNED_INT; + } + + throw new IllegalArgumentException("Unknown buffer type: " + indices.getBuffer()); + } + + public void setModelViewMatrix(final FloatBuffer matrix) { + final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord(); + JoglRendererUtil.switchMode(matRecord, GLMatrixFunc.GL_MODELVIEW); + + loadMatrix(matrix); + } + + public void setProjectionMatrix(final FloatBuffer matrix) { + final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord(); + JoglRendererUtil.switchMode(matRecord, GLMatrixFunc.GL_PROJECTION); + + loadMatrix(matrix); + } + + private void loadMatrix(final FloatBuffer matrix) { + GLU.getCurrentGL().getGL2().glLoadMatrixf(matrix); + } + + public FloatBuffer getModelViewMatrix(final FloatBuffer store) { + return getMatrix(GLMatrixFunc.GL_MODELVIEW_MATRIX, store); + } + + public FloatBuffer getProjectionMatrix(final FloatBuffer store) { + return getMatrix(GLMatrixFunc.GL_PROJECTION_MATRIX, store); + } + + private FloatBuffer getMatrix(final int matrixType, final FloatBuffer store) { + FloatBuffer result = store; + if (result.remaining() < 16) { + result = BufferUtils.createFloatBuffer(16); + } + GLU.getCurrentGL().glGetFloatv(matrixType, store); + return result; + } + + public void setViewport(final int x, final int y, final int width, final int height) { + GLU.getCurrentGL().glViewport(x, y, width, height); + } + + public void setDepthRange(final double depthRangeNear, final double depthRangeFar) { + GLU.getCurrentGL().glDepthRange(depthRangeNear, depthRangeFar); + } + + public void setDrawBuffer(final DrawBufferTarget target) { + final RendererRecord record = ContextManager.getCurrentContext().getRendererRecord(); + if (record.getDrawBufferTarget() != target) { + int buffer = GL.GL_BACK; + switch (target) { + case None: + case Back: + break; + case Front: + buffer = GL.GL_FRONT; + break; + case BackLeft: + buffer = GL2GL3.GL_BACK_LEFT; + break; + case BackRight: + buffer = GL2GL3.GL_BACK_RIGHT; + break; + case FrontLeft: + buffer = GL2GL3.GL_FRONT_LEFT; + break; + case FrontRight: + buffer = GL2GL3.GL_FRONT_RIGHT; + break; + case FrontAndBack: + buffer = GL.GL_FRONT_AND_BACK; + break; + case Left: + buffer = GL2GL3.GL_LEFT; + break; + case Right: + buffer = GL2GL3.GL_RIGHT; + break; + case Aux0: + buffer = GL2.GL_AUX0; + break; + case Aux1: + buffer = GL2.GL_AUX1; + break; + case Aux2: + buffer = GL2.GL_AUX2; + break; + case Aux3: + buffer = GL2.GL_AUX3; + break; + } + + GLU.getCurrentGL().getGL2GL3().glDrawBuffer(buffer); + record.setDrawBufferTarget(target); + } + } + + public void setupLineParameters(final float lineWidth, final int stippleFactor, final short stipplePattern, + final boolean antialiased) { + final GL gl = GLU.getCurrentGL(); + + final LineRecord lineRecord = ContextManager.getCurrentContext().getLineRecord(); + + if (!lineRecord.isValid() || lineRecord.width != lineWidth) { + gl.glLineWidth(lineWidth); + lineRecord.width = lineWidth; + } + + if (stipplePattern != (short) 0xFFFF) { + if (!lineRecord.isValid() || !lineRecord.stippled) { + gl.glEnable(GL2.GL_LINE_STIPPLE); + lineRecord.stippled = true; + } + + if (!lineRecord.isValid() || stippleFactor != lineRecord.stippleFactor + || stipplePattern != lineRecord.stipplePattern) { + gl.getGL2().glLineStipple(stippleFactor, stipplePattern); + lineRecord.stippleFactor = stippleFactor; + lineRecord.stipplePattern = stipplePattern; + } + } else if (!lineRecord.isValid() || lineRecord.stippled) { + gl.glDisable(GL2.GL_LINE_STIPPLE); + lineRecord.stippled = false; + } + + if (antialiased) { + if (!lineRecord.isValid() || !lineRecord.smoothed) { + gl.glEnable(GL.GL_LINE_SMOOTH); + lineRecord.smoothed = true; + } + if (!lineRecord.isValid() || lineRecord.smoothHint != GL.GL_NICEST) { + gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST); + lineRecord.smoothHint = GL.GL_NICEST; + } + } else if (!lineRecord.isValid() || lineRecord.smoothed) { + gl.glDisable(GL.GL_LINE_SMOOTH); + lineRecord.smoothed = false; + } + + if (!lineRecord.isValid()) { + lineRecord.validate(); + } + } + + @Override + public void setupPointParameters(final float pointSize, final boolean antialiased, final boolean isSprite, + final boolean useDistanceAttenuation, final FloatBuffer attenuationCoefficients, final float minPointSize, + final float maxPointSize) { + final RenderContext context = ContextManager.getCurrentContext(); + final GL gl = GLU.getCurrentGL(); + + // TODO: make this into a pointrecord call + gl.getGL2GL3().glPointSize(pointSize); + if (antialiased) { + gl.glEnable(GL2ES1.GL_POINT_SMOOTH); + gl.glHint(GL2ES1.GL_POINT_SMOOTH_HINT, GL.GL_NICEST); + } + + if (isSprite && context.getCapabilities().isPointSpritesSupported()) { + gl.glEnable(GL2ES1.GL_POINT_SPRITE); + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_POINT_SPRITE, GL2ES1.GL_COORD_REPLACE, GL.GL_TRUE); + } + + if (useDistanceAttenuation && context.getCapabilities().isPointParametersSupported()) { + gl.getGL2GL3().glPointParameterfv(GL2ES1.GL_POINT_DISTANCE_ATTENUATION, attenuationCoefficients); + gl.getGL2GL3().glPointParameterf(GL2ES1.GL_POINT_SIZE_MIN, minPointSize); + gl.getGL2GL3().glPointParameterf(GL2ES1.GL_POINT_SIZE_MAX, maxPointSize); + } + } + + @Override + protected void doApplyState(final RenderState state) { + switch (state.getType()) { + case Texture: + JoglTextureStateUtil.apply(this, (TextureState) state); + return; + case Light: + JoglLightStateUtil.apply(this, (LightState) state); + return; + case Blend: + JoglBlendStateUtil.apply(this, (BlendState) state); + return; + case Clip: + JoglClipStateUtil.apply(this, (ClipState) state); + return; + case ColorMask: + JoglColorMaskStateUtil.apply(this, (ColorMaskState) state); + return; + case Cull: + JoglCullStateUtil.apply(this, (CullState) state); + return; + case Fog: + JoglFogStateUtil.apply(this, (FogState) state); + return; + case FragmentProgram: + JoglFragmentProgramStateUtil.apply(this, (FragmentProgramState) state); + return; + case GLSLShader: + JoglShaderObjectsStateUtil.apply(this, (GLSLShaderObjectsState) state); + return; + case Material: + JoglMaterialStateUtil.apply(this, (MaterialState) state); + return; + case Offset: + JoglOffsetStateUtil.apply(this, (OffsetState) state); + return; + case Shading: + JoglShadingStateUtil.apply(this, (ShadingState) state); + return; + case Stencil: + JoglStencilStateUtil.apply(this, (StencilState) state); + return; + case VertexProgram: + JoglVertexProgramStateUtil.apply(this, (VertexProgramState) state); + return; + case Wireframe: + JoglWireframeStateUtil.apply(this, (WireframeState) state); + return; + case ZBuffer: + JoglZBufferStateUtil.apply(this, (ZBufferState) state); + return; + } + throw new IllegalArgumentException("Unknown state: " + state); + } + + public void deleteTexture(final Texture texture) { + JoglTextureStateUtil.deleteTexture(texture); + } + + public void loadTexture(final Texture texture, final int unit) { + JoglTextureStateUtil.load(texture, unit); + } + + public void deleteTextureIds(final Collection<Integer> ids) { + JoglTextureStateUtil.deleteTextureIds(ids); + } + + /** + * Start a new display list. All further renderer commands that can be stored in a display list are part of this new + * list until {@link #endDisplayList()} is called. + * + * @return id of new display list + */ + public int startDisplayList() { + final GL gl = GLU.getCurrentGL(); + + final int id = gl.getGL2().glGenLists(1); + + gl.getGL2().glNewList(id, GL2.GL_COMPILE); + + return id; + } + + /** + * Ends a display list. Will likely cause an OpenGL exception is a display list is not currently being generated. + */ + public void endDisplayList() { + GLU.getCurrentGL().getGL2().glEndList(); + } + + /** + * Draw the given display list. + */ + public void renderDisplayList(final int displayListID) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2().glCallList(displayListID); + } + + public void clearClips() { + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord record = context.getRendererRecord(); + record.getScissorClips().clear(); + + JoglRendererUtil.applyScissors(record); + } + + public void popClip() { + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord record = context.getRendererRecord(); + record.getScissorClips().pop(); + + JoglRendererUtil.applyScissors(record); + } + + public void pushClip(final ReadOnlyRectangle2 rectangle) { + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord record = context.getRendererRecord(); + record.getScissorClips().push(rectangle); + + JoglRendererUtil.applyScissors(record); + } + + public void pushEmptyClip() { + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord record = context.getRendererRecord(); + record.getScissorClips().push(null); + + JoglRendererUtil.applyScissors(record); + } + + public void setClipTestEnabled(final boolean enabled) { + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord record = context.getRendererRecord(); + + JoglRendererUtil.setClippingEnabled(record, enabled); + } + + public void checkAndSetTextureArrayUnit(final int unit, final GL gl, final RendererRecord record, + final ContextCapabilities caps) { + if (record.getCurrentTextureArraysUnit() != unit && caps.isMultitextureSupported()) { + gl.getGL2().glClientActiveTexture(GL.GL_TEXTURE0 + unit); + record.setCurrentTextureArraysUnit(unit); + } + } +}
\ No newline at end of file diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglTextureRenderer.java b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglTextureRenderer.java new file mode 100644 index 0000000..99719df --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglTextureRenderer.java @@ -0,0 +1,571 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.renderer.jogl; + +import java.nio.IntBuffer; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Logger; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.framework.Scene; +import com.ardor3d.image.Texture; +import com.ardor3d.image.Texture.Type; +import com.ardor3d.image.TextureCubeMap; +import com.ardor3d.image.TextureCubeMap.Face; +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.renderer.AbstractFBOTextureRenderer; +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.TextureRendererFactory; +import com.ardor3d.renderer.state.RenderState; +import com.ardor3d.renderer.state.record.RendererRecord; +import com.ardor3d.renderer.state.record.TextureRecord; +import com.ardor3d.renderer.state.record.TextureStateRecord; +import com.ardor3d.scene.state.jogl.JoglTextureStateUtil; +import com.ardor3d.scene.state.jogl.util.JoglTextureUtil; +import com.ardor3d.scenegraph.Spatial; +import com.ardor3d.util.Ardor3dException; +import com.ardor3d.util.TextureKey; +import com.ardor3d.util.geom.BufferUtils; + +/** + * <p> + * This class is used by Ardor3D's JOGL implementation to render textures. Users should <b>not</b> create this class + * directly. + * </p> + * + * @see TextureRendererFactory + */ +public class JoglTextureRenderer extends AbstractFBOTextureRenderer { + private static final Logger logger = Logger.getLogger(JoglTextureRenderer.class.getName()); + + public JoglTextureRenderer(final int width, final int height, final int depthBits, final int samples, + final Renderer parentRenderer, final ContextCapabilities caps) { + super(width, height, depthBits, samples, parentRenderer, caps); + + if (caps.getMaxFBOColorAttachments() > 1) { + _attachBuffer = BufferUtils.createIntBuffer(caps.getMaxFBOColorAttachments()); + for (int i = 0; i < caps.getMaxFBOColorAttachments(); i++) { + _attachBuffer.put(GL.GL_COLOR_ATTACHMENT0 + i); + } + } + } + + /** + * <code>setupTexture</code> initializes a new Texture object for use with TextureRenderer. Generates a valid OpenGL + * texture id for this texture and initializes the data type for the texture. + */ + public void setupTexture(final Texture tex) { + if (tex.getType() != Type.TwoDimensional && tex.getType() != Type.CubeMap) { + throw new IllegalArgumentException("Texture type not supported: " + tex.getType()); + } + + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(RenderState.StateType.Texture); + + // check if we are already setup... if so, throw error. + if (tex.getTextureKey() == null) { + tex.setTextureKey(TextureKey.getRTTKey(tex.getMinificationFilter())); + } else if (tex.getTextureIdForContext(context.getGlContextRep()) != 0) { + throw new Ardor3dException("Texture is already setup and has id."); + } + + // Create the texture + final IntBuffer ibuf = BufferUtils.createIntBuffer(1); + gl.glGenTextures(ibuf.limit(), ibuf); // TODO Check <size> + final int textureId = ibuf.get(0); + tex.setTextureIdForContext(context.getGlContextRep(), textureId); + + JoglTextureStateUtil.doTextureBind(tex, 0, true); + + // Initialize our texture with some default data. + final int internalFormat = JoglTextureUtil.getGLInternalFormat(tex.getTextureStoreFormat()); + final int dataFormat = JoglTextureUtil.getGLPixelFormatFromStoreFormat(tex.getTextureStoreFormat()); + final int pixelDataType = JoglTextureUtil.getGLPixelDataType(tex.getRenderedTexturePixelDataType()); + + if (tex.getType() == Type.TwoDimensional) { + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, internalFormat, _width, _height, 0, dataFormat, pixelDataType, + null); + } else { + for (final Face face : Face.values()) { + gl.glTexImage2D(JoglTextureStateUtil.getGLCubeMapFace(face), 0, internalFormat, _width, _height, 0, + dataFormat, pixelDataType, null); + } + } + + // Initialize mipmapping for this texture, if requested + if (tex.getMinificationFilter().usesMipMapLevels()) { + gl.glGenerateMipmap(JoglTextureStateUtil.getGLType(tex.getType())); + } + + // Setup filtering and wrap + final TextureRecord texRecord = record.getTextureRecord(textureId, tex.getType()); + JoglTextureStateUtil.applyFilter(tex, texRecord, 0, record, context.getCapabilities()); + JoglTextureStateUtil.applyWrap(tex, texRecord, 0, record, context.getCapabilities()); + + logger.fine("setup fbo tex with id " + textureId + ": " + _width + "," + _height); + } + + public void render(final Spatial spat, final List<Texture> texs, final int clear) { + render(null, spat, null, texs, clear); + } + + public void render(final List<? extends Spatial> spat, final List<Texture> texs, final int clear) { + render(spat, null, null, texs, clear); + } + + @Override + public void render(final Scene scene, final List<Texture> texs, final int clear) { + render(null, null, scene, texs, clear); + } + + private void render(final List<? extends Spatial> toDrawA, final Spatial toDrawB, final Scene toDrawC, + final List<Texture> texs, final int clear) { + final GL gl = GLU.getCurrentGL(); + + final int maxDrawBuffers = ContextManager.getCurrentContext().getCapabilities().getMaxFBOColorAttachments(); + + // if we only support 1 draw buffer at a time anyway, we'll have to render to each texture individually... + if (maxDrawBuffers == 1 || texs.size() == 1) { + try { + ContextManager.getCurrentContext().pushFBOTextureRenderer(this); + + for (int i = 0; i < texs.size(); i++) { + final Texture tex = texs.get(i); + + setupForSingleTexDraw(tex); + + if (_samples > 0 && _supportsMultisample) { + setMSFBO(); + } + + switchCameraIn(clear); + if (toDrawA != null) { + doDraw(toDrawA); + } else { + doDraw(toDrawB); + } + switchCameraOut(); + + if (_samples > 0 && _supportsMultisample) { + blitMSFBO(); + } + + takedownForSingleTexDraw(tex); + } + } finally { + ContextManager.getCurrentContext().popFBOTextureRenderer(); + } + return; + } + try { + ContextManager.getCurrentContext().pushFBOTextureRenderer(this); + + // Otherwise, we can streamline this by rendering to multiple textures at once. + // first determine how many groups we need + final LinkedList<Texture> depths = new LinkedList<Texture>(); + final LinkedList<Texture> colors = new LinkedList<Texture>(); + for (int i = 0; i < texs.size(); i++) { + final Texture tex = texs.get(i); + if (tex.getTextureStoreFormat().isDepthFormat()) { + depths.add(tex); + } else { + colors.add(tex); + } + } + // we can only render to 1 depth texture at a time, so # groups is at minimum == numDepth + final int groups = Math.max(depths.size(), (int) Math.ceil(colors.size() / (float) maxDrawBuffers)); + + final RenderContext context = ContextManager.getCurrentContext(); + for (int i = 0; i < groups; i++) { + // First handle colors + int colorsAdded = 0; + while (colorsAdded < maxDrawBuffers && !colors.isEmpty()) { + final Texture tex = colors.removeFirst(); + if (tex.getType() == Type.TwoDimensional) { + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0 + colorsAdded, + GL.GL_TEXTURE_2D, tex.getTextureIdForContext(context.getGlContextRep()), 0); + } else if (tex.getType() == Type.CubeMap) { + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0 + colorsAdded, + JoglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), + tex.getTextureIdForContext(context.getGlContextRep()), 0); + } else { + throw new IllegalArgumentException("Invalid texture type: " + tex.getType()); + } + colorsAdded++; + } + + // Now take care of depth. + if (!depths.isEmpty()) { + final Texture tex = depths.removeFirst(); + // Set up our depth texture + if (tex.getType() == Type.TwoDimensional) { + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, + GL.GL_TEXTURE_2D, tex.getTextureIdForContext(context.getGlContextRep()), 0); + } else if (tex.getType() == Type.CubeMap) { + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, + JoglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), + tex.getTextureIdForContext(context.getGlContextRep()), 0); + } else { + throw new IllegalArgumentException("Invalid texture type: " + tex.getType()); + } + _usingDepthRB = false; + } else if (!_usingDepthRB) { + // setup our default depth render buffer if not already set + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, _depthRBID); + _usingDepthRB = true; + } + + setDrawBuffers(colorsAdded); + setReadBuffer(colorsAdded != 0 ? GL.GL_COLOR_ATTACHMENT0 : GL.GL_NONE); + + // Check FBO complete + checkFBOComplete(_fboID); + + switchCameraIn(clear); + + if (toDrawA != null) { + doDraw(toDrawA); + } else { + doDraw(toDrawB); + } + + switchCameraOut(); + } + + // automatically generate mipmaps for our textures. + for (int x = 0, max = texs.size(); x < max; x++) { + final Texture tex = texs.get(x); + if (tex.getMinificationFilter().usesMipMapLevels()) { + JoglTextureStateUtil.doTextureBind(tex, 0, true); + gl.glGenerateMipmap(JoglTextureStateUtil.getGLType(tex.getType())); + } + } + } finally { + ContextManager.getCurrentContext().popFBOTextureRenderer(); + } + } + + @Override + protected void setupForSingleTexDraw(final Texture tex) { + final GL gl = GLU.getCurrentGL(); + + final RenderContext context = ContextManager.getCurrentContext(); + final int textureId = tex.getTextureIdForContext(context.getGlContextRep()); + + if (tex.getTextureStoreFormat().isDepthFormat()) { + // No color buffer + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_RENDERBUFFER, + 0); + + // Setup depth texture into FBO + if (tex.getType() == Type.TwoDimensional) { + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_TEXTURE_2D, + textureId, 0); + } else if (tex.getType() == Type.CubeMap) { + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, + JoglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), textureId, 0); + } else { + throw new IllegalArgumentException("Can not render to texture of type: " + tex.getType()); + } + + setDrawBuffer(GL.GL_NONE); + setReadBuffer(GL.GL_NONE); + } else { + // Set color texture into FBO + if (tex.getType() == Type.TwoDimensional) { + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, + textureId, 0); + } else if (tex.getType() == Type.CubeMap) { + gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, + JoglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), textureId, 0); + } else { + throw new IllegalArgumentException("Can not render to texture of type: " + tex.getType()); + } + + // setup depth RB + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, + _depthRBID); + + setDrawBuffer(GL.GL_COLOR_ATTACHMENT0); + setReadBuffer(GL.GL_COLOR_ATTACHMENT0); + } + + // Check FBO complete + checkFBOComplete(_fboID); + } + + private void setReadBuffer(final int attachVal) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glReadBuffer(attachVal); + } + + private void setDrawBuffer(final int attachVal) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glDrawBuffer(attachVal); + } + + private void setDrawBuffers(final int maxEntry) { + final GL gl = GLU.getCurrentGL(); + + if (maxEntry <= 1) { + setDrawBuffer(maxEntry != 0 ? GL.GL_COLOR_ATTACHMENT0 : GL.GL_NONE); + } else { + // We should only get to this point if we support ARBDrawBuffers. + _attachBuffer.clear(); + _attachBuffer.limit(maxEntry); + gl.getGL2GL3().glDrawBuffers(_attachBuffer.limit(), _attachBuffer); // TODO Check <size> + } + } + + @Override + protected void takedownForSingleTexDraw(final Texture tex) { + final GL gl = GLU.getCurrentGL(); + + // automatically generate mipmaps for our texture. + if (tex.getMinificationFilter().usesMipMapLevels()) { + JoglTextureStateUtil.doTextureBind(tex, 0, true); + gl.glGenerateMipmap(JoglTextureStateUtil.getGLType(tex.getType())); + } + } + + @Override + protected void setMSFBO() { + final GL gl = GLU.getCurrentGL(); + + gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, _msfboID); + } + + @Override + protected void blitMSFBO() { + final GL gl = GLU.getCurrentGL(); + + gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, _msfboID); + gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, _fboID); + gl.getGL2GL3().glBlitFramebuffer(0, 0, _width, _height, 0, 0, _width, _height, GL.GL_COLOR_BUFFER_BIT + | GL.GL_DEPTH_BUFFER_BIT, GL.GL_NEAREST); + + gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, 0); + gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, 0); + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); + } + + /** + * Check the currently bound FBO status for completeness. The passed in fboID is for informational purposes only. + * + * @param fboID + * an id to use for log messages, particularly if there are any issues. + */ + public static void checkFBOComplete(final int fboID) { + final GL gl = GLU.getCurrentGL(); + + final int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); + switch (status) { + case GL.GL_FRAMEBUFFER_COMPLETE: + break; + case GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + throw new IllegalStateException("FrameBuffer: " + fboID + + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT exception"); + case GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + throw new IllegalStateException("FrameBuffer: " + fboID + + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT exception"); + case GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + throw new IllegalStateException("FrameBuffer: " + fboID + + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT exception"); + case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + throw new IllegalStateException("FrameBuffer: " + fboID + + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT exception"); + case GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS: + throw new IllegalStateException("FrameBuffer: " + fboID + + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT exception"); + case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + throw new IllegalStateException("FrameBuffer: " + fboID + + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT exception"); + case GL.GL_FRAMEBUFFER_UNSUPPORTED: + throw new IllegalStateException("FrameBuffer: " + fboID + + ", has caused a GL_FRAMEBUFFER_UNSUPPORTED_EXT exception"); + case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + throw new IllegalStateException("FrameBuffer: " + fboID + + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT exception."); + default: + throw new RuntimeException("Unexpected reply from glCheckFramebufferStatusEXT: " + status); + } + } + + public void copyToTexture(final Texture tex, final int x, final int y, final int width, final int height, + final int xoffset, final int yoffset) { + final GL gl = GLU.getCurrentGL(); + + JoglTextureStateUtil.doTextureBind(tex, 0, true); + + if (tex.getType() == Type.TwoDimensional) { + gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, width, height); + } else if (tex.getType() == Type.CubeMap) { + gl.glCopyTexSubImage2D(JoglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), + 0, xoffset, yoffset, x, y, width, height); + } else { + throw new IllegalArgumentException("Invalid texture type: " + tex.getType()); + } + } + + @Override + protected void clearBuffers(final int clear) { + final GL gl = GLU.getCurrentGL(); + + gl.glDisable(GL.GL_SCISSOR_TEST); + _parentRenderer.clearBuffers(clear); + } + + @Override + protected void activate() { + final GL gl = GLU.getCurrentGL(); + + // Lazy init + if (_fboID == 0) { + final IntBuffer buffer = BufferUtils.createIntBuffer(1); + + // Create our texture binding FBO + gl.glGenFramebuffers(1, buffer); // generate id + _fboID = buffer.get(0); + + // Create a depth renderbuffer to use for RTT use + gl.glGenRenderbuffers(1, buffer); // generate id + _depthRBID = buffer.get(0); + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, _depthRBID); + int format = GL2ES2.GL_DEPTH_COMPONENT; + if (_supportsDepthTexture && _depthBits > 0) { + switch (_depthBits) { + case 16: + format = GL.GL_DEPTH_COMPONENT16; + break; + case 24: + format = GL.GL_DEPTH_COMPONENT24; + break; + case 32: + format = GL.GL_DEPTH_COMPONENT32; + break; + default: + // stick with the "undefined" GL_DEPTH_COMPONENT + } + } + gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, format, _width, _height); + + // unbind... + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0); + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); + + // If we support it, rustle up a multisample framebuffer + renderbuffers + if (_samples != 0 && _supportsMultisample) { + // create ms framebuffer object + gl.glGenFramebuffers(1, buffer); + _msfboID = buffer.get(0); + + // create ms renderbuffers + gl.glGenRenderbuffers(1, buffer); // generate id + _mscolorRBID = buffer.get(0); + gl.glGenRenderbuffers(1, buffer); // generate id + _msdepthRBID = buffer.get(0); + + // set up renderbuffer properties + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, _mscolorRBID); + gl.getGL2GL3().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, _samples, GL.GL_RGBA, _width, _height); + + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, _msdepthRBID); + gl.getGL2GL3().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, _samples, format, _width, _height); + + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0); + + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, _msfboID); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, + GL.GL_RENDERBUFFER, _mscolorRBID); + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, _msdepthRBID); + + // check for errors + checkFBOComplete(_msfboID); + + // release + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); + } + + } + + if (_active == 0) { + + final RenderContext context = ContextManager.getCurrentContext(); + final RendererRecord record = context.getRendererRecord(); + + // needed as FBOs do not share this flag it seems + record.setClippingTestValid(false); + + // push a delimiter onto the clip stack + _neededClip = _parentRenderer.isClipTestEnabled(); + if (_neededClip) { + _parentRenderer.pushEmptyClip(); + } + + gl.glClearColor(_backgroundColor.getRed(), _backgroundColor.getGreen(), _backgroundColor.getBlue(), + _backgroundColor.getAlpha()); + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, _fboID); + ContextManager.getCurrentContext().pushEnforcedStates(); + ContextManager.getCurrentContext().clearEnforcedStates(); + ContextManager.getCurrentContext().enforceStates(_enforcedStates); + } + _active++; + } + + @Override + protected void deactivate() { + final GL gl = GLU.getCurrentGL(); + + if (_active == 1) { + final ReadOnlyColorRGBA bgColor = _parentRenderer.getBackgroundColor(); + gl.glClearColor(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), bgColor.getAlpha()); + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); + ContextManager.getCurrentContext().popEnforcedStates(); + + if (_neededClip) { + _parentRenderer.popClip(); + } + } + _active--; + } + + public void cleanup() { + final GL gl = GLU.getCurrentGL(); + + if (_fboID != 0) { + final IntBuffer id = BufferUtils.createIntBuffer(1); + id.put(_fboID); + id.rewind(); + gl.glDeleteFramebuffers(id.limit(), id); + } + + if (_depthRBID != 0) { + final IntBuffer id = BufferUtils.createIntBuffer(1); + id.put(_depthRBID); + id.rewind(); + gl.glDeleteRenderbuffers(id.limit(), id); + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglTextureRendererProvider.java b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglTextureRendererProvider.java new file mode 100644 index 0000000..b2d433c --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/renderer/jogl/JoglTextureRendererProvider.java @@ -0,0 +1,49 @@ +/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.renderer.jogl;
+
+import java.util.logging.Logger;
+
+import com.ardor3d.framework.DisplaySettings;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.TextureRenderer;
+import com.ardor3d.renderer.TextureRendererProvider;
+
+public class JoglTextureRendererProvider implements TextureRendererProvider {
+
+ private static final Logger logger = Logger.getLogger(JoglTextureRendererProvider.class.getName());
+
+ public TextureRenderer createTextureRenderer(final int width, final int height, final Renderer renderer,
+ final ContextCapabilities caps) {
+ return createTextureRenderer(width, height, 0, 0, renderer, caps);
+ }
+
+ public TextureRenderer createTextureRenderer(final int width, final int height, final int depthBits,
+ final int samples, final Renderer renderer, final ContextCapabilities caps) {
+ return createTextureRenderer(new DisplaySettings(width, height, depthBits, samples), false, renderer, caps);
+ }
+
+ public TextureRenderer createTextureRenderer(final DisplaySettings settings, final boolean forcePbuffer,
+ final Renderer renderer, final ContextCapabilities caps) {
+ if (!forcePbuffer && caps.isFBOSupported()) {
+ return new JoglTextureRenderer(settings.getWidth(), settings.getHeight(), settings.getDepthBits(), settings
+ .getSamples(), renderer, caps);
+ } else if (caps.isPbufferSupported()) {
+ return new JoglPbufferTextureRenderer(settings, renderer, caps);
+ } else {
+ logger.severe("No texture renderer support (FBO or Pbuffer).");
+ return null;
+ }
+
+ }
+
+}
diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglBlendStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglBlendStateUtil.java new file mode 100644 index 0000000..39f0221 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglBlendStateUtil.java @@ -0,0 +1,424 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.BlendState; +import com.ardor3d.renderer.state.BlendState.BlendEquation; +import com.ardor3d.renderer.state.BlendState.DestinationFunction; +import com.ardor3d.renderer.state.BlendState.SourceFunction; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.BlendStateRecord; + +public abstract class JoglBlendStateUtil { + + public static void apply(final JoglRenderer renderer, final BlendState state) { + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final BlendStateRecord record = (BlendStateRecord) context.getStateRecord(StateType.Blend); + final ContextCapabilities caps = context.getCapabilities(); + context.setCurrentState(StateType.Blend, state); + + final GL gl = GLU.getCurrentGL(); + + if (state.isEnabled()) { + applyBlendEquations(gl, state.isBlendEnabled(), state, record, caps); + applyBlendColor(gl, state.isBlendEnabled(), state, record, caps); + applyBlendFunctions(gl, state.isBlendEnabled(), state, record, caps); + + applyTest(gl, state.isTestEnabled(), state, record); + + if (caps.isMultisampleSupported()) { + applyAlphaCoverage(gl, state.isSampleAlphaToCoverageEnabled(), state.isSampleAlphaToOneEnabled(), + record, caps); + applySampleCoverage(gl, state.isSampleCoverageEnabled(), state, record, caps); + } + } else { + // disable blend + applyBlendEquations(gl, false, state, record, caps); + + // disable alpha test + applyTest(gl, false, state, record); + + // disable sample coverage + if (caps.isMultisampleSupported()) { + applyAlphaCoverage(gl, false, false, record, caps); + applySampleCoverage(gl, false, state, record, caps); + } + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static void applyBlendEquations(final GL gl, final boolean enabled, final BlendState state, + final BlendStateRecord record, final ContextCapabilities caps) { + if (record.isValid()) { + if (enabled) { + if (!record.blendEnabled) { + gl.glEnable(GL.GL_BLEND); + record.blendEnabled = true; + } + final int blendEqRGB = getGLEquationValue(state.getBlendEquationRGB(), caps); + if (caps.isSeparateBlendEquationsSupported()) { + final int blendEqAlpha = getGLEquationValue(state.getBlendEquationAlpha(), caps); + if (record.blendEqRGB != blendEqRGB || record.blendEqAlpha != blendEqAlpha) { + gl.glBlendEquationSeparate(blendEqRGB, blendEqAlpha); + record.blendEqRGB = blendEqRGB; + record.blendEqAlpha = blendEqAlpha; + } + } else if (caps.isBlendEquationSupported()) { + if (record.blendEqRGB != blendEqRGB) { + gl.glBlendEquation(blendEqRGB); + record.blendEqRGB = blendEqRGB; + } + } + } else if (record.blendEnabled) { + gl.glDisable(GL.GL_BLEND); + record.blendEnabled = false; + } + + } else { + if (enabled) { + gl.glEnable(GL.GL_BLEND); + record.blendEnabled = true; + final int blendEqRGB = getGLEquationValue(state.getBlendEquationRGB(), caps); + if (caps.isSeparateBlendEquationsSupported()) { + final int blendEqAlpha = getGLEquationValue(state.getBlendEquationAlpha(), caps); + gl.glBlendEquationSeparate(blendEqRGB, blendEqAlpha); + record.blendEqRGB = blendEqRGB; + record.blendEqAlpha = blendEqAlpha; + } else if (caps.isBlendEquationSupported()) { + gl.glBlendEquation(blendEqRGB); + record.blendEqRGB = blendEqRGB; + } + } else { + gl.glDisable(GL.GL_BLEND); + record.blendEnabled = false; + } + } + } + + private static void applyBlendColor(final GL gl, final boolean enabled, final BlendState state, + final BlendStateRecord record, final ContextCapabilities caps) { + if (enabled) { + final boolean applyConstant = state.getDestinationFunctionRGB().usesConstantColor() + || state.getSourceFunctionRGB().usesConstantColor() + || (caps.isConstantBlendColorSupported() && (state.getDestinationFunctionAlpha() + .usesConstantColor() || state.getSourceFunctionAlpha().usesConstantColor())); + if (applyConstant && caps.isConstantBlendColorSupported()) { + final ReadOnlyColorRGBA constant = state.getConstantColor(); + if (!record.isValid() || (caps.isConstantBlendColorSupported() && !record.blendColor.equals(constant))) { + gl.getGL2GL3().glBlendColor(constant.getRed(), constant.getGreen(), constant.getBlue(), constant.getAlpha()); + record.blendColor.set(constant); + } + } + } + } + + private static void applyBlendFunctions(final GL gl, final boolean enabled, final BlendState state, + final BlendStateRecord record, final ContextCapabilities caps) { + if (record.isValid()) { + if (enabled) { + final int glSrcRGB = getGLSrcValue(state.getSourceFunctionRGB(), caps); + final int glDstRGB = getGLDstValue(state.getDestinationFunctionRGB(), caps); + if (caps.isSeparateBlendFunctionsSupported()) { + final int glSrcAlpha = getGLSrcValue(state.getSourceFunctionAlpha(), caps); + final int glDstAlpha = getGLDstValue(state.getDestinationFunctionAlpha(), caps); + if (record.srcFactorRGB != glSrcRGB || record.dstFactorRGB != glDstRGB + || record.srcFactorAlpha != glSrcAlpha || record.dstFactorAlpha != glDstAlpha) { + gl.glBlendFuncSeparate(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha); + record.srcFactorRGB = glSrcRGB; + record.dstFactorRGB = glDstRGB; + record.srcFactorAlpha = glSrcAlpha; + record.dstFactorAlpha = glDstAlpha; + } + } else if (record.srcFactorRGB != glSrcRGB || record.dstFactorRGB != glDstRGB) { + gl.glBlendFunc(glSrcRGB, glDstRGB); + record.srcFactorRGB = glSrcRGB; + record.dstFactorRGB = glDstRGB; + } + } + } else { + if (enabled) { + final int glSrcRGB = getGLSrcValue(state.getSourceFunctionRGB(), caps); + final int glDstRGB = getGLDstValue(state.getDestinationFunctionRGB(), caps); + if (caps.isSeparateBlendFunctionsSupported()) { + final int glSrcAlpha = getGLSrcValue(state.getSourceFunctionAlpha(), caps); + final int glDstAlpha = getGLDstValue(state.getDestinationFunctionAlpha(), caps); + gl.glBlendFuncSeparate(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha); + record.srcFactorRGB = glSrcRGB; + record.dstFactorRGB = glDstRGB; + record.srcFactorAlpha = glSrcAlpha; + record.dstFactorAlpha = glDstAlpha; + } else { + gl.glBlendFunc(glSrcRGB, glDstRGB); + record.srcFactorRGB = glSrcRGB; + record.dstFactorRGB = glDstRGB; + } + } + } + } + + protected static void applyAlphaCoverage(final GL gl, final boolean sampleAlphaToCoverageEnabled, + final boolean sampleAlphaToOneEnabled, final BlendStateRecord record, final ContextCapabilities caps) { + if (record.isValid()) { + if (sampleAlphaToCoverageEnabled != record.sampleAlphaToCoverageEnabled) { + if (sampleAlphaToCoverageEnabled) { + gl.glEnable(GL.GL_SAMPLE_ALPHA_TO_COVERAGE); + } else { + gl.glDisable(GL.GL_SAMPLE_ALPHA_TO_COVERAGE); + } + record.sampleAlphaToCoverageEnabled = sampleAlphaToCoverageEnabled; + } + if (sampleAlphaToOneEnabled != record.sampleAlphaToOneEnabled) { + if (sampleAlphaToOneEnabled) { + gl.glEnable(GL.GL_SAMPLE_ALPHA_TO_ONE); + } else { + gl.glDisable(GL.GL_SAMPLE_ALPHA_TO_ONE); + } + record.sampleAlphaToOneEnabled = sampleAlphaToOneEnabled; + } + } else { + if (sampleAlphaToCoverageEnabled) { + gl.glEnable(GL.GL_SAMPLE_ALPHA_TO_COVERAGE); + } else { + gl.glDisable(GL.GL_SAMPLE_ALPHA_TO_COVERAGE); + } + record.sampleAlphaToCoverageEnabled = sampleAlphaToCoverageEnabled; + if (sampleAlphaToOneEnabled) { + gl.glEnable(GL.GL_SAMPLE_ALPHA_TO_ONE); + } else { + gl.glDisable(GL.GL_SAMPLE_ALPHA_TO_ONE); + } + record.sampleAlphaToOneEnabled = sampleAlphaToOneEnabled; + } + } + + protected static void applySampleCoverage(final GL gl, final boolean enabled, final BlendState state, + final BlendStateRecord record, final ContextCapabilities caps) { + + final boolean coverageInverted = state.isSampleCoverageInverted(); + final float coverageValue = state.getSampleCoverage(); + + if (record.isValid()) { + if (enabled) { + if (!record.sampleCoverageEnabled) { + gl.glEnable(GL.GL_SAMPLE_COVERAGE); + record.sampleCoverageEnabled = true; + } + if (record.sampleCoverageInverted != coverageInverted || record.sampleCoverage != coverageValue) { + gl.glSampleCoverage(coverageValue, coverageInverted); + record.sampleCoverageInverted = coverageInverted; + record.sampleCoverage = coverageValue; + } + } else { + if (record.sampleCoverageEnabled) { + gl.glDisable(GL.GL_SAMPLE_COVERAGE); + record.sampleCoverageEnabled = false; + } + } + } else { + if (enabled) { + gl.glEnable(GL.GL_SAMPLE_COVERAGE); + record.sampleCoverageEnabled = true; + gl.glSampleCoverage(coverageValue, coverageInverted); + record.sampleCoverageInverted = coverageInverted; + record.sampleCoverage = coverageValue; + } else { + gl.glDisable(GL.GL_SAMPLE_COVERAGE); + record.sampleCoverageEnabled = false; + } + } + } + + private static int getGLSrcValue(final SourceFunction function, final ContextCapabilities caps) { + switch (function) { + case Zero: + return GL.GL_ZERO; + case DestinationColor: + return GL.GL_DST_COLOR; + case OneMinusDestinationColor: + return GL.GL_ONE_MINUS_DST_COLOR; + case SourceAlpha: + return GL.GL_SRC_ALPHA; + case OneMinusSourceAlpha: + return GL.GL_ONE_MINUS_SRC_ALPHA; + case DestinationAlpha: + return GL.GL_DST_ALPHA; + case OneMinusDestinationAlpha: + return GL.GL_ONE_MINUS_DST_ALPHA; + case SourceAlphaSaturate: + return GL.GL_SRC_ALPHA_SATURATE; + case ConstantColor: + if (caps.isConstantBlendColorSupported()) { + return GL2ES2.GL_CONSTANT_COLOR; + } + // FALLS THROUGH + case OneMinusConstantColor: + if (caps.isConstantBlendColorSupported()) { + return GL2ES2.GL_ONE_MINUS_CONSTANT_COLOR; + } + // FALLS THROUGH + case ConstantAlpha: + if (caps.isConstantBlendColorSupported()) { + return GL2ES2.GL_CONSTANT_ALPHA; + } + // FALLS THROUGH + case OneMinusConstantAlpha: + if (caps.isConstantBlendColorSupported()) { + return GL2ES2.GL_ONE_MINUS_CONSTANT_ALPHA; + } + // FALLS THROUGH + case One: + return GL.GL_ONE; + } + throw new IllegalArgumentException("Invalid source function type: " + function); + } + + private static int getGLDstValue(final DestinationFunction function, final ContextCapabilities caps) { + switch (function) { + case Zero: + return GL.GL_ZERO; + case SourceColor: + return GL.GL_SRC_COLOR; + case OneMinusSourceColor: + return GL.GL_ONE_MINUS_SRC_COLOR; + case SourceAlpha: + return GL.GL_SRC_ALPHA; + case OneMinusSourceAlpha: + return GL.GL_ONE_MINUS_SRC_ALPHA; + case DestinationAlpha: + return GL.GL_DST_ALPHA; + case OneMinusDestinationAlpha: + return GL.GL_ONE_MINUS_DST_ALPHA; + case ConstantColor: + if (caps.isConstantBlendColorSupported()) { + return GL2ES2.GL_CONSTANT_COLOR; + } + // FALLS THROUGH + case OneMinusConstantColor: + if (caps.isConstantBlendColorSupported()) { + return GL2ES2.GL_ONE_MINUS_CONSTANT_COLOR; + } + // FALLS THROUGH + case ConstantAlpha: + if (caps.isConstantBlendColorSupported()) { + return GL2ES2.GL_CONSTANT_ALPHA; + } + // FALLS THROUGH + case OneMinusConstantAlpha: + if (caps.isConstantBlendColorSupported()) { + return GL2ES2.GL_ONE_MINUS_CONSTANT_ALPHA; + } + // FALLS THROUGH + case One: + return GL.GL_ONE; + } + throw new IllegalArgumentException("Invalid destination function type: " + function); + } + + private static int getGLEquationValue(final BlendEquation eq, final ContextCapabilities caps) { + switch (eq) { + case Min: + if (caps.isMinMaxBlendEquationsSupported()) { + return GL2GL3.GL_MIN; + } + // FALLS THROUGH + case Max: + if (caps.isMinMaxBlendEquationsSupported()) { + return GL2GL3.GL_MAX; + } else { + return GL.GL_FUNC_ADD; + } + case Subtract: + if (caps.isSubtractBlendEquationsSupported()) { + return GL.GL_FUNC_SUBTRACT; + } + // FALLS THROUGH + case ReverseSubtract: + if (caps.isSubtractBlendEquationsSupported()) { + return GL.GL_FUNC_REVERSE_SUBTRACT; + } + // FALLS THROUGH + case Add: + return GL.GL_FUNC_ADD; + } + throw new IllegalArgumentException("Invalid blend equation: " + eq); + } + + private static void applyTest(final GL gl, final boolean enabled, final BlendState state, + final BlendStateRecord record) { + if (record.isValid()) { + if (enabled) { + if (!record.testEnabled) { + gl.glEnable(GL2ES1.GL_ALPHA_TEST); + record.testEnabled = true; + } + final int glFunc = getGLFuncValue(state.getTestFunction()); + if (record.alphaFunc != glFunc || record.alphaRef != state.getReference()) { + gl.getGL2().glAlphaFunc(glFunc, state.getReference()); + record.alphaFunc = glFunc; + record.alphaRef = state.getReference(); + } + } else if (record.testEnabled) { + gl.glDisable(GL2ES1.GL_ALPHA_TEST); + record.testEnabled = false; + } + + } else { + if (enabled) { + gl.glEnable(GL2ES1.GL_ALPHA_TEST); + record.testEnabled = true; + final int glFunc = getGLFuncValue(state.getTestFunction()); + gl.getGL2().glAlphaFunc(glFunc, state.getReference()); + record.alphaFunc = glFunc; + record.alphaRef = state.getReference(); + } else { + gl.glDisable(GL2ES1.GL_ALPHA_TEST); + record.testEnabled = false; + } + } + } + + private static int getGLFuncValue(final BlendState.TestFunction function) { + switch (function) { + case Never: + return GL.GL_NEVER; + case LessThan: + return GL.GL_LESS; + case EqualTo: + return GL.GL_EQUAL; + case LessThanOrEqualTo: + return GL.GL_LEQUAL; + case GreaterThan: + return GL.GL_GREATER; + case NotEqualTo: + return GL.GL_NOTEQUAL; + case GreaterThanOrEqualTo: + return GL.GL_GEQUAL; + case Always: + return GL.GL_ALWAYS; + } + throw new IllegalArgumentException("Invalid test function type: " + function); + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglClipStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglClipStateUtil.java new file mode 100644 index 0000000..df673aa --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglClipStateUtil.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.ClipState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.ClipStateRecord; + +public abstract class JoglClipStateUtil { + + public static void apply(final JoglRenderer renderer, final ClipState state) { + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final ClipStateRecord record = (ClipStateRecord) context.getStateRecord(StateType.Clip); + context.setCurrentState(StateType.Clip, state); + + final ContextCapabilities caps = context.getCapabilities(); + final int max = Math.min(ClipState.MAX_CLIP_PLANES, caps.getMaxUserClipPlanes()); + + if (state.isEnabled()) { + for (int i = 0; i < max; i++) { + enableClipPlane(i, state.getPlaneEnabled(i), state, record); + } + } else { + for (int i = 0; i < max; i++) { + enableClipPlane(i, false, state, record); + } + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static void enableClipPlane(final int planeIndex, final boolean enable, final ClipState state, + final ClipStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (enable) { + if (!record.isValid() || !record.planeEnabled[planeIndex]) { + gl.glEnable(GL2ES1.GL_CLIP_PLANE0 + planeIndex); + record.planeEnabled[planeIndex] = true; + } + + record.buf.rewind(); + record.buf.put(state.getPlaneEquations(planeIndex)); + record.buf.flip(); + gl.getGL2().glClipPlane(GL2ES1.GL_CLIP_PLANE0 + planeIndex, record.buf); + + } else { + if (!record.isValid() || record.planeEnabled[planeIndex]) { + gl.glDisable(GL2ES1.GL_CLIP_PLANE0 + planeIndex); + record.planeEnabled[planeIndex] = false; + } + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglColorMaskStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglColorMaskStateUtil.java new file mode 100644 index 0000000..a0316e0 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglColorMaskStateUtil.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.ColorMaskState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.ColorMaskStateRecord; + +public abstract class JoglColorMaskStateUtil { + + public static void apply(final JoglRenderer renderer, final ColorMaskState state) { + final GL gl = GLU.getCurrentGL(); + + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final ColorMaskStateRecord record = (ColorMaskStateRecord) context.getStateRecord(StateType.ColorMask); + context.setCurrentState(StateType.ColorMask, state); + + if (state.isEnabled()) { + if (!record.isValid() || !record.is(state.getRed(), state.getGreen(), state.getBlue(), state.getAlpha())) { + gl.glColorMask(state.getRed(), state.getGreen(), state.getBlue(), state.getAlpha()); + record.set(state.getRed(), state.getGreen(), state.getBlue(), state.getAlpha()); + } + } else if (!record.isValid() || !record.is(true, true, true, true)) { + gl.glColorMask(true, true, true, true); + record.set(true, true, true, true); + } + + if (!record.isValid()) { + record.validate(); + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglCullStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglCullStateUtil.java new file mode 100644 index 0000000..d93eb33 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglCullStateUtil.java @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.CullState; +import com.ardor3d.renderer.state.CullState.Face; +import com.ardor3d.renderer.state.CullState.PolygonWind; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.CullStateRecord; + +public abstract class JoglCullStateUtil { + + public static void apply(final JoglRenderer renderer, final CullState state) { + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final CullStateRecord record = (CullStateRecord) context.getStateRecord(StateType.Cull); + context.setCurrentState(StateType.Cull, state); + + if (state.isEnabled()) { + final Face useCullMode = state.getCullFace(); + + switch (useCullMode) { + case Front: + setCull(GL.GL_FRONT, state, record); + setCullEnabled(true, state, record); + break; + case Back: + setCull(GL.GL_BACK, state, record); + setCullEnabled(true, state, record); + break; + case FrontAndBack: + setCull(GL.GL_FRONT_AND_BACK, state, record); + setCullEnabled(true, state, record); + break; + case None: + setCullEnabled(false, state, record); + break; + } + setGLPolygonWind(state.getPolygonWind(), state, record); + } else { + setCullEnabled(false, state, record); + setGLPolygonWind(PolygonWind.CounterClockWise, state, record); + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static void setCullEnabled(final boolean enable, final CullState state, final CullStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || record.enabled != enable) { + if (enable) { + gl.glEnable(GL.GL_CULL_FACE); + } else { + gl.glDisable(GL.GL_CULL_FACE); + } + record.enabled = enable; + } + } + + private static void setCull(final int face, final CullState state, final CullStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || record.face != face) { + gl.glCullFace(face); + record.face = face; + } + } + + private static void setGLPolygonWind(final PolygonWind windOrder, final CullState state, + final CullStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || record.windOrder != windOrder) { + switch (windOrder) { + case CounterClockWise: + gl.glFrontFace(GL.GL_CCW); + break; + case ClockWise: + gl.glFrontFace(GL.GL_CW); + break; + } + record.windOrder = windOrder; + } + } + +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglFogStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglFogStateUtil.java new file mode 100644 index 0000000..19b1b0f --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglFogStateUtil.java @@ -0,0 +1,169 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.FogState; +import com.ardor3d.renderer.state.FogState.CoordinateSource; +import com.ardor3d.renderer.state.FogState.DensityFunction; +import com.ardor3d.renderer.state.FogState.Quality; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.FogStateRecord; + +public abstract class JoglFogStateUtil { + + public static void apply(final JoglRenderer renderer, final FogState state) { + final GL gl = GLU.getCurrentGL(); + + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + final FogStateRecord record = (FogStateRecord) context.getStateRecord(StateType.Fog); + context.setCurrentState(StateType.Fog, state); + + if (state.isEnabled()) { + enableFog(true, record); + + if (record.isValid()) { + if (record.fogStart != state.getStart()) { + gl.getGL2ES1().glFogf(GL2ES1.GL_FOG_START, state.getStart()); + record.fogStart = state.getStart(); + } + if (record.fogEnd != state.getEnd()) { + gl.getGL2ES1().glFogf(GL2ES1.GL_FOG_END, state.getEnd()); + record.fogEnd = state.getEnd(); + } + if (record.density != state.getDensity()) { + gl.getGL2ES1().glFogf(GL2ES1.GL_FOG_DENSITY, state.getDensity()); + record.density = state.getDensity(); + } + } else { + gl.getGL2ES1().glFogf(GL2ES1.GL_FOG_START, state.getStart()); + record.fogStart = state.getStart(); + gl.getGL2ES1().glFogf(GL2ES1.GL_FOG_END, state.getEnd()); + record.fogEnd = state.getEnd(); + gl.getGL2ES1().glFogf(GL2ES1.GL_FOG_DENSITY, state.getDensity()); + record.density = state.getDensity(); + } + + final ReadOnlyColorRGBA fogColor = state.getColor(); + applyFogColor(fogColor, record); + applyFogMode(state.getDensityFunction(), record); + applyFogHint(state.getQuality(), record); + applyFogSource(state.getSource(), record, caps); + } else { + enableFog(false, record); + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static void enableFog(final boolean enable, final FogStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (record.isValid()) { + if (enable && !record.enabled) { + gl.glEnable(GL2ES1.GL_FOG); + record.enabled = true; + } else if (!enable && record.enabled) { + gl.glDisable(GL2ES1.GL_FOG); + record.enabled = false; + } + } else { + if (enable) { + gl.glEnable(GL2ES1.GL_FOG); + } else { + gl.glDisable(GL2ES1.GL_FOG); + } + record.enabled = enable; + } + } + + private static void applyFogColor(final ReadOnlyColorRGBA color, final FogStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || !color.equals(record.fogColor)) { + record.fogColor.set(color); + record.colorBuff.clear(); + record.colorBuff.put(record.fogColor.getRed()).put(record.fogColor.getGreen()).put( + record.fogColor.getBlue()).put(record.fogColor.getAlpha()); + record.colorBuff.flip(); + gl.getGL2ES1().glFogfv(GL2ES1.GL_FOG_COLOR, record.colorBuff); + } + } + + private static void applyFogSource(final CoordinateSource source, final FogStateRecord record, + final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (caps.isFogCoordinatesSupported()) { + if (!record.isValid() || !source.equals(record.source)) { + if (source == CoordinateSource.Depth) { + gl.getGL2().glFogi(GL2.GL_FOG_COORDINATE_SOURCE, GL2.GL_FRAGMENT_DEPTH); + } else { + gl.getGL2().glFogi(GL2.GL_FOG_COORDINATE_SOURCE, GL2.GL_FOG_COORDINATE); + } + } + } + } + + private static void applyFogMode(final DensityFunction densityFunction, final FogStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + int glMode = 0; + switch (densityFunction) { + case Exponential: + glMode = GL2ES1.GL_EXP; + break; + case Linear: + glMode = GL.GL_LINEAR; + break; + case ExponentialSquared: + glMode = GL2ES1.GL_EXP2; + break; + } + + if (!record.isValid() || record.fogMode != glMode) { + gl.getGL2().glFogi(GL2ES1.GL_FOG_MODE, glMode); + record.fogMode = glMode; + } + } + + private static void applyFogHint(final Quality quality, final FogStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + int glHint = 0; + switch (quality) { + case PerVertex: + glHint = GL.GL_FASTEST; + break; + case PerPixel: + glHint = GL.GL_NICEST; + break; + } + + if (!record.isValid() || record.fogHint != glHint) { + gl.glHint(GL2ES1.GL_FOG_HINT, glHint); + record.fogHint = glHint; + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglFragmentProgramStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglFragmentProgramStateUtil.java new file mode 100644 index 0000000..5b8d068 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglFragmentProgramStateUtil.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.logging.Logger; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.FragmentProgramState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.FragmentProgramStateRecord; +import com.ardor3d.util.geom.BufferUtils; + +public final class JoglFragmentProgramStateUtil { + private static final Logger logger = Logger.getLogger(JoglFragmentProgramStateUtil.class.getName()); + + /** + * Queries OpenGL for errors in the fragment program. Errors are logged as SEVERE, noting both the line number and + * message. + */ + private static void checkProgramError() { + final GL gl = GLU.getCurrentGL(); + + if (gl.glGetError() == GL.GL_INVALID_OPERATION) { + // retrieve the error position + final IntBuffer errorloc = BufferUtils.createIntBuffer(16); + gl.glGetIntegerv(GL2.GL_PROGRAM_ERROR_POSITION_ARB, errorloc); // TODO Check for integer + + logger.severe("Error " + gl.glGetString(GL2.GL_PROGRAM_ERROR_STRING_ARB) + " in fragment program on line " + + errorloc.get(0)); + } + } + + private static int create(final ByteBuffer program) { + final GL gl = GLU.getCurrentGL(); + + final IntBuffer buf = BufferUtils.createIntBuffer(1); + + gl.getGL2().glGenProgramsARB(buf.limit(), buf); // TODO Check <size> + gl.getGL2().glBindProgramARB(GL2.GL_FRAGMENT_PROGRAM_ARB, buf.get(0)); + + final byte array[] = new byte[program.limit()]; + program.rewind(); + program.get(array); + gl.getGL2().glProgramStringARB(GL2.GL_FRAGMENT_PROGRAM_ARB, GL2.GL_PROGRAM_FORMAT_ASCII_ARB, array.length, new String( + array)); // TODO Check cost of using non-buffer + + checkProgramError(); + + return buf.get(0); + } + + public static void apply(final JoglRenderer renderer, final FragmentProgramState state) { + final GL gl = GLU.getCurrentGL(); + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + + if (caps.isFragmentProgramSupported()) { + final FragmentProgramStateRecord record = (FragmentProgramStateRecord) context + .getStateRecord(StateType.FragmentProgram); + context.setCurrentState(StateType.FragmentProgram, state); + + if (!record.isValid() || record.getReference() != state) { + record.setReference(state); + if (state.isEnabled()) { + // Fragment program not yet loaded + if (state._getProgramID() == -1) { + if (state.getProgramAsBuffer() != null) { + final int id = create(state.getProgramAsBuffer()); + state._setProgramID(id); + } else { + return; + } + } + + gl.glEnable(GL2.GL_FRAGMENT_PROGRAM_ARB); + gl.getGL2().glBindProgramARB(GL2.GL_FRAGMENT_PROGRAM_ARB, state._getProgramID()); + + // load environmental parameters... + // TODO: Reevaluate how this is done. + /* + * for (int i = 0; i < envparameters.length; i++) if (envparameters[i] != null) + * gl.glProgramEnvParameter4fARB( GL.GL_FRAGMENT_PROGRAM_ARB, i, envparameters[i][0], + * envparameters[i][1], envparameters[i][2], envparameters[i][3]); + */ + + // load local parameters... + if (state.isUsingParameters()) { + // no parameters are used + for (int i = 0; i < state._getParameters().length; i++) { + if (state._getParameters()[i] != null) { + gl.getGL2().glProgramLocalParameter4fARB(GL2.GL_FRAGMENT_PROGRAM_ARB, i, + state._getParameters()[i][0], state._getParameters()[i][1], state + ._getParameters()[i][2], state._getParameters()[i][3]); + } + } + } + + } else { + gl.glDisable(GL2.GL_FRAGMENT_PROGRAM_ARB); + } + } + + if (!record.isValid()) { + record.validate(); + } + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglLightStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglLightStateUtil.java new file mode 100644 index 0000000..3050d67 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglLightStateUtil.java @@ -0,0 +1,412 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.fixedfunc.GLLightingFunc; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.light.DirectionalLight; +import com.ardor3d.light.Light; +import com.ardor3d.light.PointLight; +import com.ardor3d.light.SpotLight; +import com.ardor3d.math.ColorRGBA; +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.math.type.ReadOnlyMatrix4; +import com.ardor3d.math.type.ReadOnlyVector3; +import com.ardor3d.renderer.Camera; +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.LightState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.LightRecord; +import com.ardor3d.renderer.state.record.LightStateRecord; + +public abstract class JoglLightStateUtil { + + public static void apply(final JoglRenderer renderer, final LightState state) { + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + final LightStateRecord record = (LightStateRecord) context.getStateRecord(StateType.Light); + context.setCurrentState(StateType.Light, state); + + if (state.isEnabled() && LightState.LIGHTS_ENABLED) { + setLightEnabled(true, record); + setTwoSided(state.getTwoSidedLighting(), record); + setLocalViewer(state.getLocalViewer(), record); + if (caps.isOpenGL1_2Supported()) { + setSpecularControl(state.getSeparateSpecular(), record); + } + + for (int i = 0, max = state.getNumberOfChildren(); i < max; i++) { + final Light light = state.get(i); + LightRecord lr = record.getLightRecord(i); + // TODO: use the reference to get the lightrecord - rherlitz + + if (lr == null) { + lr = new LightRecord(); + record.setLightRecord(lr, i); + } + + if (light == null) { + setSingleLightEnabled(false, i, record, lr); + } else { + if (light.isEnabled()) { + setLight(i, light, record, state, lr); + } else { + setSingleLightEnabled(false, i, record, lr); + } + } + } + + // disable lights at and above the max count in this state + for (int i = state.getNumberOfChildren(); i < LightState.MAX_LIGHTS_ALLOWED; i++) { + LightRecord lr = record.getLightRecord(i); + + if (lr == null) { + lr = new LightRecord(); + record.setLightRecord(lr, i); + } + setSingleLightEnabled(false, i, record, lr); + } + + if ((state.getLightMask() & LightState.MASK_GLOBALAMBIENT) == 0) { + setModelAmbient(record, state.getGlobalAmbient()); + } else { + setModelAmbient(record, ColorRGBA.BLACK_NO_ALPHA); + } + } else { + setLightEnabled(false, record); + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static void setLight(final int index, final Light light, final LightStateRecord record, + final LightState state, final LightRecord lr) { + setSingleLightEnabled(true, index, record, lr); + + if ((state.getLightMask() & LightState.MASK_AMBIENT) == 0 + && (light.getLightMask() & LightState.MASK_AMBIENT) == 0) { + setAmbient(index, record, light.getAmbient(), lr); + } else { + setAmbient(index, record, ColorRGBA.BLACK_NO_ALPHA, lr); + } + + if ((state.getLightMask() & LightState.MASK_DIFFUSE) == 0 + && (light.getLightMask() & LightState.MASK_DIFFUSE) == 0) { + + setDiffuse(index, record, light.getDiffuse(), lr); + } else { + setDiffuse(index, record, ColorRGBA.BLACK_NO_ALPHA, lr); + } + + if ((state.getLightMask() & LightState.MASK_SPECULAR) == 0 + && (light.getLightMask() & LightState.MASK_SPECULAR) == 0) { + + setSpecular(index, record, light.getSpecular(), lr); + } else { + setSpecular(index, record, ColorRGBA.BLACK_NO_ALPHA, lr); + } + + if (light.isAttenuate()) { + setAttenuate(true, index, light, record, lr); + + } else { + setAttenuate(false, index, light, record, lr); + + } + + switch (light.getType()) { + case Directional: { + final DirectionalLight dirLight = (DirectionalLight) light; + + final ReadOnlyVector3 direction = dirLight.getDirection(); + setPosition(index, record, -direction.getXf(), -direction.getYf(), -direction.getZf(), 0, lr); + break; + } + case Point: + case Spot: { + final PointLight pointLight = (PointLight) light; + final ReadOnlyVector3 location = pointLight.getLocation(); + setPosition(index, record, location.getXf(), location.getYf(), location.getZf(), 1, lr); + break; + } + } + + if (light.getType() == Light.Type.Spot) { + final SpotLight spot = (SpotLight) light; + final ReadOnlyVector3 direction = spot.getDirection(); + setSpotCutoff(index, record, spot.getAngle(), lr); + setSpotDirection(index, record, direction.getXf(), direction.getYf(), direction.getZf(), 0); + setSpotExponent(index, record, spot.getExponent(), lr); + } else { + // set the cutoff to 180, which causes the other spot params to be + // ignored. + setSpotCutoff(index, record, 180, lr); + } + } + + private static void setSingleLightEnabled(final boolean enable, final int index, final LightStateRecord record, + final LightRecord lr) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || lr.isEnabled() != enable) { + if (enable) { + gl.glEnable(GLLightingFunc.GL_LIGHT0 + index); + } else { + gl.glDisable(GLLightingFunc.GL_LIGHT0 + index); + } + + lr.setEnabled(enable); + } + } + + private static void setLightEnabled(final boolean enable, final LightStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || record.isEnabled() != enable) { + if (enable) { + gl.glEnable(GLLightingFunc.GL_LIGHTING); + } else { + gl.glDisable(GLLightingFunc.GL_LIGHTING); + } + record.setEnabled(enable); + } + } + + private static void setTwoSided(final boolean twoSided, final LightStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || record.isTwoSidedOn() != twoSided) { + if (twoSided) { + gl.getGL2().glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_TRUE); + } else { + gl.getGL2().glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_FALSE); + } + record.setTwoSidedOn(twoSided); + } + } + + private static void setLocalViewer(final boolean localViewer, final LightStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || record.isLocalViewer() != localViewer) { + if (localViewer) { + gl.getGL2().glLightModeli(GL2.GL_LIGHT_MODEL_LOCAL_VIEWER, GL.GL_TRUE); + } else { + gl.getGL2().glLightModeli(GL2.GL_LIGHT_MODEL_LOCAL_VIEWER, GL.GL_FALSE); + } + record.setLocalViewer(localViewer); + } + } + + private static void setSpecularControl(final boolean separateSpecularOn, final LightStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || record.isSeparateSpecular() != separateSpecularOn) { + if (separateSpecularOn) { + gl.getGL2().glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SEPARATE_SPECULAR_COLOR); + } else { + gl.getGL2().glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SINGLE_COLOR); + } + record.setSeparateSpecular(separateSpecularOn); + } + } + + private static void setModelAmbient(final LightStateRecord record, final ReadOnlyColorRGBA globalAmbient) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || !record.globalAmbient.equals(globalAmbient)) { + record.lightBuffer.clear(); + record.lightBuffer.put(globalAmbient.getRed()); + record.lightBuffer.put(globalAmbient.getGreen()); + record.lightBuffer.put(globalAmbient.getBlue()); + record.lightBuffer.put(globalAmbient.getAlpha()); + record.lightBuffer.flip(); + gl.getGL2().glLightModelfv(GL2ES1.GL_LIGHT_MODEL_AMBIENT, record.lightBuffer); // TODO Check for float + record.globalAmbient.set(globalAmbient); + } + } + + private static void setAmbient(final int index, final LightStateRecord record, final ReadOnlyColorRGBA ambient, + final LightRecord lr) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || !lr.ambient.equals(ambient)) { + record.lightBuffer.clear(); + record.lightBuffer.put(ambient.getRed()); + record.lightBuffer.put(ambient.getGreen()); + record.lightBuffer.put(ambient.getBlue()); + record.lightBuffer.put(ambient.getAlpha()); + record.lightBuffer.flip(); + gl.getGL2().glLightfv(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_AMBIENT, record.lightBuffer); // TODO Check for float + lr.ambient.set(ambient); + } + } + + private static void setDiffuse(final int index, final LightStateRecord record, final ReadOnlyColorRGBA diffuse, + final LightRecord lr) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || !lr.diffuse.equals(diffuse)) { + record.lightBuffer.clear(); + record.lightBuffer.put(diffuse.getRed()); + record.lightBuffer.put(diffuse.getGreen()); + record.lightBuffer.put(diffuse.getBlue()); + record.lightBuffer.put(diffuse.getAlpha()); + record.lightBuffer.flip(); + gl.getGL2().glLightfv(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_DIFFUSE, record.lightBuffer); // TODO Check for float + lr.diffuse.set(diffuse); + } + } + + private static void setSpecular(final int index, final LightStateRecord record, final ReadOnlyColorRGBA specular, + final LightRecord lr) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || !lr.specular.equals(specular)) { + record.lightBuffer.clear(); + record.lightBuffer.put(specular.getRed()); + record.lightBuffer.put(specular.getGreen()); + record.lightBuffer.put(specular.getBlue()); + record.lightBuffer.put(specular.getAlpha()); + record.lightBuffer.flip(); + gl.getGL2().glLightfv(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_SPECULAR, record.lightBuffer); // TODO Check for float + lr.specular.set(specular); + } + } + + private static void setPosition(final int index, final LightStateRecord record, final float positionX, + final float positionY, final float positionZ, final float positionW, final LightRecord lr) { + final GL gl = GLU.getCurrentGL(); + + // From OpenGL Docs: + // The light position is transformed by the contents of the current top + // of the ModelView matrix stack when you specify the light position + // with a call to glLightfv(GL_LIGHT_POSITION,...). If you later change + // the ModelView matrix, such as when the view changes for the next + // frame, the light position isn't automatically retransformed by the + // new contents of the ModelView matrix. If you want to update the + // light's position, you must again specify the light position with a + // call to glLightfv(GL_LIGHT_POSITION,...). + + // XXX: This is a hack until we get a better lighting model up + final ReadOnlyMatrix4 modelViewMatrix = Camera.getCurrentCamera().getModelViewMatrix(); + + if (!record.isValid() || lr.position.getXf() != positionX || lr.position.getYf() != positionY + || lr.position.getZf() != positionZ || lr.position.getWf() != positionW + || !lr.modelViewMatrix.equals(modelViewMatrix)) { + + record.lightBuffer.clear(); + record.lightBuffer.put(positionX); + record.lightBuffer.put(positionY); + record.lightBuffer.put(positionZ); + record.lightBuffer.put(positionW); + record.lightBuffer.flip(); + gl.getGL2().glLightfv(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_POSITION, record.lightBuffer); + + lr.position.set(positionX, positionY, positionZ, positionW); + if (!Camera.getCurrentCamera().isFrameDirty()) { + lr.modelViewMatrix.set(modelViewMatrix); + } + } + } + + private static void setSpotDirection(final int index, final LightStateRecord record, final float directionX, + final float directionY, final float directionZ, final float value) { + final GL gl = GLU.getCurrentGL(); + + // From OpenGL Docs: + // The light position is transformed by the contents of the current top + // of the ModelView matrix stack when you specify the light position + // with a call to glLightfv(GL_LIGHT_POSITION,...). If you later change + // the ModelView matrix, such as when the view changes for the next + // frame, the light position isn't automatically retransformed by the + // new contents of the ModelView matrix. If you want to update the + // light's position, you must again specify the light position with a + // call to glLightfv(GL_LIGHT_POSITION,...). + record.lightBuffer.clear(); + record.lightBuffer.put(directionX); + record.lightBuffer.put(directionY); + record.lightBuffer.put(directionZ); + record.lightBuffer.put(value); + record.lightBuffer.flip(); + gl.getGL2().glLightfv(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_SPOT_DIRECTION, record.lightBuffer); // TODO Check for float + } + + private static void setConstant(final int index, final float constant, final LightRecord lr, final boolean force) { + final GL gl = GLU.getCurrentGL(); + + if (force || constant != lr.getConstant()) { + gl.getGL2().glLightf(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_CONSTANT_ATTENUATION, constant); + lr.setConstant(constant); + } + } + + private static void setLinear(final int index, final float linear, final LightRecord lr, final boolean force) { + final GL gl = GLU.getCurrentGL(); + + if (force || linear != lr.getLinear()) { + gl.getGL2().glLightf(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_LINEAR_ATTENUATION, linear); + lr.setLinear(linear); + } + } + + private static void setQuadratic(final int index, final float quad, final LightRecord lr, final boolean force) { + final GL gl = GLU.getCurrentGL(); + + if (force || quad != lr.getQuadratic()) { + gl.getGL2().glLightf(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_QUADRATIC_ATTENUATION, quad); + lr.setQuadratic(quad); + } + } + + private static void setAttenuate(final boolean attenuate, final int index, final Light light, + final LightStateRecord record, final LightRecord lr) { + if (attenuate) { + setConstant(index, light.getConstant(), lr, !record.isValid()); + setLinear(index, light.getLinear(), lr, !record.isValid()); + setQuadratic(index, light.getQuadratic(), lr, !record.isValid()); + } else { + setConstant(index, 1, lr, !record.isValid()); + setLinear(index, 0, lr, !record.isValid()); + setQuadratic(index, 0, lr, !record.isValid()); + } + lr.setAttenuate(attenuate); + } + + private static void setSpotExponent(final int index, final LightStateRecord record, final float exponent, + final LightRecord lr) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || lr.getSpotExponent() != exponent) { + gl.getGL2().glLightf(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_SPOT_EXPONENT, exponent); + lr.setSpotExponent(exponent); + } + } + + private static void setSpotCutoff(final int index, final LightStateRecord record, final float cutoff, + final LightRecord lr) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || lr.getSpotCutoff() != cutoff) { + gl.getGL2().glLightf(GLLightingFunc.GL_LIGHT0 + index, GLLightingFunc.GL_SPOT_CUTOFF, cutoff); + lr.setSpotCutoff(cutoff); + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglMaterialStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglMaterialStateUtil.java new file mode 100644 index 0000000..4a20143 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglMaterialStateUtil.java @@ -0,0 +1,214 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.fixedfunc.GLLightingFunc; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.MaterialState; +import com.ardor3d.renderer.state.MaterialState.ColorMaterial; +import com.ardor3d.renderer.state.MaterialState.MaterialFace; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.MaterialStateRecord; + +public abstract class JoglMaterialStateUtil { + + public static void apply(final JoglRenderer renderer, final MaterialState state) { + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final MaterialStateRecord record = (MaterialStateRecord) context.getStateRecord(StateType.Material); + context.setCurrentState(StateType.Material, state); + + if (state.isEnabled()) { + // setup colormaterial, if changed. + applyColorMaterial(state.getColorMaterial(), state.getColorMaterialFace(), record); + + // apply colors, if needed and not what is currently set. + applyColor(ColorMaterial.Ambient, state.getAmbient(), state.getBackAmbient(), record); + applyColor(ColorMaterial.Diffuse, state.getDiffuse(), state.getBackDiffuse(), record); + applyColor(ColorMaterial.Emissive, state.getEmissive(), state.getBackEmissive(), record); + applyColor(ColorMaterial.Specular, state.getSpecular(), state.getBackSpecular(), record); + + // set our shine + applyShininess(state.getShininess(), state.getBackShininess(), record); + } else { + // apply defaults + applyColorMaterial(MaterialState.DEFAULT_COLOR_MATERIAL, MaterialState.DEFAULT_COLOR_MATERIAL_FACE, record); + + applyColor(ColorMaterial.Ambient, MaterialState.DEFAULT_AMBIENT, MaterialState.DEFAULT_AMBIENT, record); + applyColor(ColorMaterial.Diffuse, MaterialState.DEFAULT_DIFFUSE, MaterialState.DEFAULT_DIFFUSE, record); + applyColor(ColorMaterial.Emissive, MaterialState.DEFAULT_EMISSIVE, MaterialState.DEFAULT_EMISSIVE, record); + applyColor(ColorMaterial.Specular, MaterialState.DEFAULT_SPECULAR, MaterialState.DEFAULT_SPECULAR, record); + + applyShininess(MaterialState.DEFAULT_SHININESS, MaterialState.DEFAULT_SHININESS, record); + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static void applyColor(final ColorMaterial glMatColor, final ReadOnlyColorRGBA frontColor, + final ReadOnlyColorRGBA backColor, final MaterialStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + final int glMat = getGLColorMaterial(glMatColor); + if (frontColor.equals(backColor)) { + // consolidate to one call + if (!isVertexProvidedColor(MaterialFace.FrontAndBack, glMatColor, record)) { + if (!record.isValid() || !record.isSetColor(MaterialFace.FrontAndBack, glMatColor, frontColor, record)) { + record.tempColorBuff.clear(); + record.tempColorBuff.put(frontColor.getRed()).put(frontColor.getGreen()).put(frontColor.getBlue()) + .put(frontColor.getAlpha()); + record.tempColorBuff.flip(); + gl.getGL2().glMaterialfv(getGLMaterialFace(MaterialFace.FrontAndBack), glMat, record.tempColorBuff); + record.setColor(MaterialFace.FrontAndBack, glMatColor, frontColor); + } + } + } else { + if (!isVertexProvidedColor(MaterialFace.Front, glMatColor, record)) { + if (!record.isValid() || !record.isSetColor(MaterialFace.Front, glMatColor, frontColor, record)) { + record.tempColorBuff.clear(); + record.tempColorBuff.put(frontColor.getRed()).put(frontColor.getGreen()).put(frontColor.getBlue()) + .put(frontColor.getAlpha()); + record.tempColorBuff.flip(); + gl.getGL2().glMaterialfv(getGLMaterialFace(MaterialFace.Front), glMat, record.tempColorBuff); + record.setColor(MaterialFace.Front, glMatColor, frontColor); + } + } + + if (!isVertexProvidedColor(MaterialFace.Back, glMatColor, record)) { + if (!record.isValid() || !record.isSetColor(MaterialFace.Back, glMatColor, backColor, record)) { + record.tempColorBuff.clear(); + record.tempColorBuff.put(backColor.getRed()).put(backColor.getGreen()).put(backColor.getBlue()) + .put(backColor.getAlpha()); + record.tempColorBuff.flip(); + gl.getGL2().glMaterialfv(getGLMaterialFace(MaterialFace.Back), glMat, record.tempColorBuff); + record.setColor(MaterialFace.Back, glMatColor, backColor); + } + } + } + } + + private static boolean isVertexProvidedColor(final MaterialFace face, final ColorMaterial glMatColor, + final MaterialStateRecord record) { + if (face != record.colorMaterialFace) { + return false; + } + switch (glMatColor) { + case Ambient: + return record.colorMaterial == ColorMaterial.Ambient + || record.colorMaterial == ColorMaterial.AmbientAndDiffuse; + case Diffuse: + return record.colorMaterial == ColorMaterial.Diffuse + || record.colorMaterial == ColorMaterial.AmbientAndDiffuse; + case Specular: + return record.colorMaterial == ColorMaterial.Specular; + case Emissive: + return record.colorMaterial == ColorMaterial.Emissive; + case AmbientAndDiffuse: + break; + case None: + break; + default: + break; + } + return false; + } + + private static void applyColorMaterial(final ColorMaterial colorMaterial, final MaterialFace face, + final MaterialStateRecord record) { + if (!record.isValid() || face != record.colorMaterialFace || colorMaterial != record.colorMaterial) { + final GL gl = GLU.getCurrentGL(); + + if (colorMaterial == ColorMaterial.None) { + gl.glDisable(GLLightingFunc.GL_COLOR_MATERIAL); + } else { + final int glMat = getGLColorMaterial(colorMaterial); + final int glFace = getGLMaterialFace(face); + + gl.getGL2().glColorMaterial(glFace, glMat); + gl.glEnable(GLLightingFunc.GL_COLOR_MATERIAL); + record.resetColorsForCM(face, colorMaterial); + } + record.colorMaterial = colorMaterial; + record.colorMaterialFace = face; + } + } + + private static void applyShininess(final float frontShininess, final float backShininess, + final MaterialStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (frontShininess == backShininess) { + // consolidate to one call + if (!record.isValid() || frontShininess != record.frontShininess || record.backShininess != backShininess) { + gl.getGL2().glMaterialf(getGLMaterialFace(MaterialFace.FrontAndBack), GLLightingFunc.GL_SHININESS, frontShininess); + record.backShininess = record.frontShininess = frontShininess; + } + } else { + if (!record.isValid() || frontShininess != record.frontShininess) { + gl.getGL2().glMaterialf(getGLMaterialFace(MaterialFace.Front), GLLightingFunc.GL_SHININESS, frontShininess); + record.frontShininess = frontShininess; + } + + if (!record.isValid() || backShininess != record.backShininess) { + gl.getGL2().glMaterialf(getGLMaterialFace(MaterialFace.Back), GLLightingFunc.GL_SHININESS, backShininess); + record.backShininess = backShininess; + } + } + } + + /** + * Converts the color material setting of this state to a GL constant. + * + * @return the GL constant + */ + private static int getGLColorMaterial(final ColorMaterial material) { + switch (material) { + case None: + return GL.GL_NONE; + case Ambient: + return GLLightingFunc.GL_AMBIENT; + case Diffuse: + return GLLightingFunc.GL_DIFFUSE; + case AmbientAndDiffuse: + return GLLightingFunc.GL_AMBIENT_AND_DIFFUSE; + case Emissive: + return GLLightingFunc.GL_EMISSION; + case Specular: + return GLLightingFunc.GL_SPECULAR; + } + throw new IllegalArgumentException("invalid color material setting: " + material); + } + + /** + * Converts the material face setting of this state to a GL constant. + * + * @return the GL constant + */ + private static int getGLMaterialFace(final MaterialFace face) { + switch (face) { + case Front: + return GL.GL_FRONT; + case Back: + return GL.GL_BACK; + case FrontAndBack: + return GL.GL_FRONT_AND_BACK; + } + throw new IllegalArgumentException("invalid material face setting: " + face); + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglOffsetStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglOffsetStateUtil.java new file mode 100644 index 0000000..b2cd05a --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglOffsetStateUtil.java @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.OffsetState; +import com.ardor3d.renderer.state.OffsetState.OffsetType; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.OffsetStateRecord; + +public abstract class JoglOffsetStateUtil { + + public static void apply(final JoglRenderer renderer, final OffsetState state) { + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final OffsetStateRecord record = (OffsetStateRecord) context.getStateRecord(StateType.Offset); + context.setCurrentState(StateType.Offset, state); + + if (state.isEnabled()) { + // enable any set offset types + setOffsetEnabled(OffsetType.Fill, state.isTypeEnabled(OffsetType.Fill), record); + setOffsetEnabled(OffsetType.Line, state.isTypeEnabled(OffsetType.Line), record); + setOffsetEnabled(OffsetType.Point, state.isTypeEnabled(OffsetType.Point), record); + + // set factor and units. + setOffset(state.getFactor(), state.getUnits(), record); + } else { + // disable all offset types + setOffsetEnabled(OffsetType.Fill, false, record); + setOffsetEnabled(OffsetType.Line, false, record); + setOffsetEnabled(OffsetType.Point, false, record); + + // set factor and units to default 0, 0. + setOffset(0, 0, record); + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static void setOffsetEnabled(final OffsetType type, final boolean typeEnabled, + final OffsetStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + final int glType = getGLType(type); + if (!record.isValid() || typeEnabled != record.enabledOffsets.contains(type)) { + if (typeEnabled) { + gl.glEnable(glType); + } else { + gl.glDisable(glType); + } + } + } + + private static void setOffset(final float factor, final float units, final OffsetStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (!record.isValid() || record.factor != factor || record.units != units) { + gl.glPolygonOffset(factor, units); + record.factor = factor; + record.units = units; + } + } + + private static int getGLType(final OffsetType type) { + switch (type) { + case Fill: + return GL.GL_POLYGON_OFFSET_FILL; + case Line: + return GL2GL3.GL_POLYGON_OFFSET_LINE; + case Point: + return GL2GL3.GL_POLYGON_OFFSET_POINT; + } + throw new IllegalArgumentException("invalid type: " + type); + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglShaderObjectsStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglShaderObjectsStateUtil.java new file mode 100644 index 0000000..f254b29 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglShaderObjectsStateUtil.java @@ -0,0 +1,384 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.List; +import java.util.logging.Logger; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL3; +import javax.media.opengl.GL4; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.GLSLShaderObjectsState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.ShaderObjectsStateRecord; +import com.ardor3d.scene.state.jogl.shader.JoglShaderUtil; +import com.ardor3d.util.Ardor3dException; +import com.ardor3d.util.geom.BufferUtils; +import com.ardor3d.util.shader.ShaderVariable; + +public abstract class JoglShaderObjectsStateUtil { + private static final Logger logger = Logger.getLogger(JoglShaderObjectsStateUtil.class.getName()); + + protected static void sendToGL(final GLSLShaderObjectsState state, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (state.getVertexShader() == null && state.getFragmentShader() == null) { + logger.warning("Could not find shader resources!" + "(both inputbuffers are null)"); + state._needSendShader = false; + return; + } + + if (state._programID == -1) { + state._programID = gl.getGL2().glCreateProgramObjectARB(); + } + + if (state.getVertexShader() != null) { + if (state._vertexShaderID != -1) { + removeVertShader(state); + } + + state._vertexShaderID = gl.getGL2().glCreateShaderObjectARB(GL2ES2.GL_VERTEX_SHADER); + + // Create the sources + final byte array[] = new byte[state.getVertexShader().limit()]; + state.getVertexShader().rewind(); + state.getVertexShader().get(array); + gl.getGL2().glShaderSourceARB(state._vertexShaderID, 1, new String[] { new String(array) }, + new int[] { array.length }, 0); + + // Compile the vertex shader + final IntBuffer compiled = BufferUtils.createIntBuffer(1); + gl.getGL2().glCompileShaderARB(state._vertexShaderID); + gl.getGL2().glGetObjectParameterivARB(state._vertexShaderID, GL2.GL_OBJECT_COMPILE_STATUS_ARB, compiled); + checkProgramError(compiled, state._vertexShaderID, state._vertexShaderName); + + // Attach the program + gl.getGL2().glAttachObjectARB(state._programID, state._vertexShaderID); + } else if (state._vertexShaderID != -1) { + removeVertShader(state); + state._vertexShaderID = -1; + } + + if (state.getFragmentShader() != null) { + if (state._fragmentShaderID != -1) { + removeFragShader(state); + } + + state._fragmentShaderID = gl.getGL2().glCreateShaderObjectARB(GL2ES2.GL_FRAGMENT_SHADER); + + // Create the sources + final byte array[] = new byte[state.getFragmentShader().limit()]; + state.getFragmentShader().rewind(); + state.getFragmentShader().get(array); + gl.getGL2().glShaderSourceARB(state._fragmentShaderID, 1, new String[] { new String(array) }, + new int[] { array.length }, 0); + + // Compile the fragment shader + final IntBuffer compiled = BufferUtils.createIntBuffer(1); + gl.getGL2().glCompileShaderARB(state._fragmentShaderID); + gl.getGL2().glGetObjectParameterivARB(state._fragmentShaderID, GL2.GL_OBJECT_COMPILE_STATUS_ARB, compiled); + checkProgramError(compiled, state._fragmentShaderID, state._vertexShaderName); + + // Attach the program + gl.getGL2().glAttachObjectARB(state._programID, state._fragmentShaderID); + } else if (state._fragmentShaderID != -1) { + removeFragShader(state); + state._fragmentShaderID = -1; + } + + if (caps.isGeometryShader4Supported()) { + if (state.getGeometryShader() != null) { + if (state._geometryShaderID != -1) { + removeGeomShader(state); + } + + state._geometryShaderID = gl.getGL2().glCreateShaderObjectARB(GL3.GL_GEOMETRY_SHADER); + + // Create the sources + final byte array[] = new byte[state.getGeometryShader().limit()]; + state.getGeometryShader().rewind(); + state.getGeometryShader().get(array); + gl.getGL2().glShaderSourceARB(state._geometryShaderID, 1, new String[] { new String(array) }, + new int[] { array.length }, 0); + + // Compile the geometry shader + final IntBuffer compiled = BufferUtils.createIntBuffer(1); + gl.getGL2().glCompileShaderARB(state._geometryShaderID); + gl.getGL2().glGetObjectParameterivARB(state._geometryShaderID, GL2.GL_OBJECT_COMPILE_STATUS_ARB, compiled); + checkProgramError(compiled, state._geometryShaderID, state._geometryShaderName); + + // Attach the program + gl.getGL2().glAttachObjectARB(state._programID, state._geometryShaderID); + } else if (state._geometryShaderID != -1) { + removeGeomShader(state); + state._geometryShaderID = -1; + } + } + + if (caps.isTessellationShadersSupported()) { + if (state.getTessellationControlShader() != null) { + if (state._tessellationControlShaderID != -1) { + removeTessControlShader(state); + } + + state._tessellationControlShaderID = gl.getGL2().glCreateShaderObjectARB(GL3.GL_TESS_CONTROL_SHADER); + + // Create the sources + final byte array[] = new byte[state.getTessellationControlShader().limit()]; + state.getTessellationControlShader().rewind(); + state.getTessellationControlShader().get(array); + gl.getGL2().glShaderSourceARB(state._tessellationControlShaderID, 1, new String[] { new String(array) }, + new int[] { array.length }, 0); + + // Compile the tessellation control shader + final IntBuffer compiled = BufferUtils.createIntBuffer(1); + gl.getGL2().glCompileShaderARB(state._tessellationControlShaderID); + gl.getGL2().glGetObjectParameterivARB(state._tessellationControlShaderID, GL2.GL_OBJECT_COMPILE_STATUS_ARB, compiled); + checkProgramError(compiled, state._tessellationControlShaderID, state._tessellationControlShaderName); + + // Attach the program + gl.getGL2().glAttachObjectARB(state._programID, state._tessellationControlShaderID); + } else if (state._tessellationControlShaderID != -1) { + removeTessControlShader(state); + state._tessellationControlShaderID = -1; + } + if (state.getTessellationEvaluationShader() != null) { + if (state._tessellationEvaluationShaderID != -1) { + removeTessEvalShader(state); + } + + state._tessellationEvaluationShaderID = gl.getGL2().glCreateShaderObjectARB(GL4.GL_TESS_CONTROL_SHADER); + + // Create the sources + final byte array[] = new byte[state.getTessellationEvaluationShader().limit()]; + state.getTessellationEvaluationShader().rewind(); + state.getTessellationEvaluationShader().get(array); + gl.getGL2().glShaderSourceARB(state._tessellationEvaluationShaderID, 1, new String[] { new String(array) }, + new int[] { array.length }, 0); + + // Compile the tessellation control shader + final IntBuffer compiled = BufferUtils.createIntBuffer(1); + gl.getGL2().glCompileShaderARB(state._tessellationEvaluationShaderID); + gl.getGL2().glGetObjectParameterivARB(state._tessellationEvaluationShaderID, GL2.GL_OBJECT_COMPILE_STATUS_ARB, compiled); + checkProgramError(compiled, state._tessellationEvaluationShaderID, state._tessellationEvaluationShaderName); + + // Attach the program + gl.getGL2().glAttachObjectARB(state._programID, state._tessellationEvaluationShaderID); + } else if (state._tessellationEvaluationShaderID != -1) { + removeTessEvalShader(state); + state._tessellationEvaluationShaderID = -1; + } + } + + gl.getGL2().glLinkProgramARB(state._programID); + checkLinkError(state._programID); + state.setNeedsRefresh(true); + state._needSendShader = false; + } + + private static void checkLinkError(final int programId) { + final GL gl = GLU.getCurrentGL(); + + final IntBuffer compiled = BufferUtils.createIntBuffer(1); + gl.getGL2().glGetObjectParameterivARB(programId, GL2ES2.GL_LINK_STATUS, compiled); + if (compiled.get(0) == GL.GL_FALSE) { + gl.getGL2().glGetObjectParameterivARB(programId, GL2ES2.GL_INFO_LOG_LENGTH, compiled); + final int length = compiled.get(0); + String out = null; + if (length > 0) { + final ByteBuffer infoLog = BufferUtils.createByteBuffer(length); + + gl.getGL2().glGetInfoLogARB(programId, infoLog.limit(), compiled, infoLog); + + final byte[] infoBytes = new byte[length]; + infoLog.get(infoBytes); + out = new String(infoBytes); + } + + logger.severe(out); + + // throw new Ardor3dException("Error linking GLSL shader: " + out); + } + } + + /** Removes the fragment shader */ + private static void removeFragShader(final GLSLShaderObjectsState state) { + final GL gl = GLU.getCurrentGL(); + + if (state._fragmentShaderID != -1) { + gl.getGL2().glDetachObjectARB(state._programID, state._fragmentShaderID); + gl.getGL2().glDeleteObjectARB(state._fragmentShaderID); + } + } + + /** Removes the vertex shader */ + private static void removeVertShader(final GLSLShaderObjectsState state) { + final GL gl = GLU.getCurrentGL(); + + if (state._vertexShaderID != -1) { + gl.getGL2().glDetachObjectARB(state._programID, state._vertexShaderID); + gl.getGL2().glDeleteObjectARB(state._vertexShaderID); + } + } + + /** Removes the geometry shader */ + private static void removeGeomShader(final GLSLShaderObjectsState state) { + final GL gl = GLU.getCurrentGL(); + + if (state._geometryShaderID != -1) { + gl.getGL2().glDetachObjectARB(state._programID, state._geometryShaderID); + gl.getGL2().glDeleteObjectARB(state._geometryShaderID); + } + } + + /** Removes the tessellation control shader */ + private static void removeTessControlShader(final GLSLShaderObjectsState state) { + final GL gl = GLU.getCurrentGL(); + + if (state._tessellationControlShaderID != -1) { + gl.getGL2().glDetachObjectARB(state._programID, state._tessellationControlShaderID); + gl.getGL2().glDeleteObjectARB(state._tessellationControlShaderID); + } + } + + /** Removes the tessellation evaluation shader */ + private static void removeTessEvalShader(final GLSLShaderObjectsState state) { + final GL gl = GLU.getCurrentGL(); + + if (state._tessellationEvaluationShaderID != -1) { + gl.getGL2().glDetachObjectARB(state._programID, state._tessellationEvaluationShaderID); + gl.getGL2().glDeleteObjectARB(state._tessellationEvaluationShaderID); + } + } + + /** + * Check for program errors. If an error is detected, program exits. + * + * @param compiled + * the compiler state for a given shader + * @param id + * shader's id + */ + private static void checkProgramError(final IntBuffer compiled, final int id, final String shaderName) { + final GL gl = GLU.getCurrentGL(); + + if (compiled.get(0) == GL.GL_FALSE) { + final IntBuffer iVal = BufferUtils.createIntBuffer(1); + gl.getGL2().glGetObjectParameterivARB(id, GL2.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal); + final int length = iVal.get(0); + String out = null; + + if (length > 0) { + final ByteBuffer infoLog = BufferUtils.createByteBuffer(length); + + gl.getGL2().glGetInfoLogARB(id, infoLog.limit(), iVal, infoLog); + + final byte[] infoBytes = new byte[length]; + infoLog.get(infoBytes); + out = new String(infoBytes); + } + + logger.severe(out); + + final String nameString = shaderName.equals("") ? "" : " [ " + shaderName + " ]"; + throw new Ardor3dException("Error compiling GLSL shader " + nameString + ": " + out); + } + } + + public static void apply(final JoglRenderer renderer, final GLSLShaderObjectsState state) { + final GL gl = GLU.getCurrentGL(); + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + + if (caps.isGLSLSupported()) { + // Ask for the current state record + final ShaderObjectsStateRecord record = (ShaderObjectsStateRecord) context + .getStateRecord(StateType.GLSLShader); + context.setCurrentState(StateType.GLSLShader, state); + + if (state.isEnabled()) { + if (state._needSendShader) { + sendToGL(state, caps); + } + + if (state._shaderDataLogic != null) { + state._shaderDataLogic.applyData(state, state._mesh, renderer); + } + } + + if (!record.isValid() || record.getReference() != state || state.needsRefresh()) { + record.setReference(state); + if (state.isEnabled() && state._programID != -1) { + // clear any previously existing attributes + clearEnabledAttributes(record, gl); + + // set our current shader + JoglShaderUtil.useShaderProgram(state._programID, record); + + final List<ShaderVariable> attribs = state.getShaderAttributes(); + for (int i = attribs.size(); --i >= 0;) { + final ShaderVariable shaderVariable = attribs.get(i); + if (shaderVariable.needsRefresh) { + JoglShaderUtil.updateAttributeLocation(shaderVariable, state._programID); + shaderVariable.needsRefresh = false; + } + JoglShaderUtil.updateShaderAttribute(renderer, shaderVariable, state.isUseAttributeVBO()); + } + + final List<ShaderVariable> uniforms = state.getShaderUniforms(); + for (int i = uniforms.size(); --i >= 0;) { + final ShaderVariable shaderVariable = uniforms.get(i); + if (shaderVariable.needsRefresh) { + JoglShaderUtil.updateUniformLocation(shaderVariable, state._programID); + JoglShaderUtil.updateShaderUniform(shaderVariable); + shaderVariable.needsRefresh = false; + } + } + } else { + JoglShaderUtil.useShaderProgram(0, record); + + clearEnabledAttributes(record, gl); + } + } + + if (!record.isValid()) { + record.validate(); + } + } + } + + private static void clearEnabledAttributes(final ShaderObjectsStateRecord record, final GL gl) { + // go through and disable any enabled attributes + if (!record.enabledAttributes.isEmpty()) { + for (int i = 0, maxI = record.enabledAttributes.size(); i < maxI; i++) { + final ShaderVariable var = record.enabledAttributes.get(i); + if (var.getSize() == 1) { + gl.getGL2().glDisableVertexAttribArrayARB(var.variableID); + } else { + for (int j = 0, maxJ = var.getSize(); j < maxJ; j++) { + gl.getGL2().glDisableVertexAttribArrayARB(var.variableID + j); + } + } + } + record.enabledAttributes.clear(); + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglShadingStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglShadingStateUtil.java new file mode 100644 index 0000000..ba3dea0 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglShadingStateUtil.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.fixedfunc.GLLightingFunc; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.ShadingState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.ShadingState.ShadingMode; +import com.ardor3d.renderer.state.record.ShadingStateRecord; + +public abstract class JoglShadingStateUtil { + + public static void apply(final JoglRenderer renderer, final ShadingState state) { + final GL gl = GLU.getCurrentGL(); + + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final ShadingStateRecord record = (ShadingStateRecord) context.getStateRecord(StateType.Shading); + context.setCurrentState(StateType.Shading, state); + + // If not enabled, we'll use smooth + final int toApply = state.isEnabled() ? getGLShade(state.getShadingMode()) : GLLightingFunc.GL_SMOOTH; + // only apply if we're different. Update record to reflect any changes. + if (!record.isValid() || toApply != record.lastShade) { + gl.getGL2().glShadeModel(toApply); + record.lastShade = toApply; + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static int getGLShade(final ShadingMode shadeMode) { + switch (shadeMode) { + case Smooth: + return GLLightingFunc.GL_SMOOTH; + case Flat: + return GLLightingFunc.GL_FLAT; + } + throw new IllegalStateException("unknown shade mode: " + shadeMode); + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglStencilStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglStencilStateUtil.java new file mode 100644 index 0000000..fd7204f --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglStencilStateUtil.java @@ -0,0 +1,198 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.StencilState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.StencilState.StencilFunction; +import com.ardor3d.renderer.state.StencilState.StencilOperation; +import com.ardor3d.renderer.state.record.StencilStateRecord; + +public abstract class JoglStencilStateUtil { + + public static void apply(final JoglRenderer renderer, final StencilState state) { + final GL gl = GLU.getCurrentGL(); + + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + final StencilStateRecord record = (StencilStateRecord) context.getStateRecord(StateType.Stencil); + context.setCurrentState(StateType.Stencil, state); + + setEnabled(state.isEnabled(), caps.isTwoSidedStencilSupported() ? state.isUseTwoSided() : false, record, caps); + if (state.isEnabled()) { + if (state.isUseTwoSided() && caps.isTwoSidedStencilSupported()) { + gl.getGL2().glActiveStencilFaceEXT(GL.GL_BACK); + applyMask(state.getStencilWriteMaskBack(), record, 2); + applyFunc(getGLStencilFunction(state.getStencilFunctionBack()), state.getStencilReferenceBack(), state + .getStencilFuncMaskBack(), record, 2); + applyOp(getGLStencilOp(state.getStencilOpFailBack(), caps), getGLStencilOp(state + .getStencilOpZFailBack(), caps), getGLStencilOp(state.getStencilOpZPassBack(), caps), record, 2); + + gl.getGL2().glActiveStencilFaceEXT(GL.GL_FRONT); + applyMask(state.getStencilWriteMaskFront(), record, 1); + applyFunc(getGLStencilFunction(state.getStencilFunctionFront()), state.getStencilReferenceFront(), + state.getStencilFuncMaskFront(), record, 1); + applyOp(getGLStencilOp(state.getStencilOpFailFront(), caps), getGLStencilOp(state + .getStencilOpZFailFront(), caps), getGLStencilOp(state.getStencilOpZPassFront(), caps), record, + 1); + } else { + applyMask(state.getStencilWriteMaskFront(), record, 0); + applyFunc(getGLStencilFunction(state.getStencilFunctionFront()), state.getStencilReferenceFront(), + state.getStencilFuncMaskFront(), record, 0); + applyOp(getGLStencilOp(state.getStencilOpFailFront(), caps), getGLStencilOp(state + .getStencilOpZFailFront(), caps), getGLStencilOp(state.getStencilOpZPassFront(), caps), record, + 0); + } + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static int getGLStencilFunction(final StencilFunction function) { + switch (function) { + case Always: + return GL.GL_ALWAYS; + case Never: + return GL.GL_NEVER; + case EqualTo: + return GL.GL_EQUAL; + case NotEqualTo: + return GL.GL_NOTEQUAL; + case GreaterThan: + return GL.GL_GREATER; + case GreaterThanOrEqualTo: + return GL.GL_GEQUAL; + case LessThan: + return GL.GL_LESS; + case LessThanOrEqualTo: + return GL.GL_LEQUAL; + } + throw new IllegalArgumentException("unknown function: " + function); + } + + private static int getGLStencilOp(final StencilOperation operation, final ContextCapabilities caps) { + switch (operation) { + case Keep: + return GL.GL_KEEP; + case DecrementWrap: + if (caps.isStencilWrapSupported()) { + return GL.GL_DECR_WRAP; + } + // FALLS THROUGH + case Decrement: + return GL.GL_DECR; + case IncrementWrap: + if (caps.isStencilWrapSupported()) { + return GL.GL_INCR_WRAP; + } + // FALLS THROUGH + case Increment: + return GL.GL_INCR; + case Invert: + return GL.GL_INVERT; + case Replace: + return GL.GL_REPLACE; + case Zero: + return GL.GL_ZERO; + } + throw new IllegalArgumentException("unknown operation: " + operation); + } + + private static void setEnabled(final boolean enable, final boolean twoSided, final StencilStateRecord record, + final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (record.isValid()) { + if (enable && !record.enabled) { + gl.glEnable(GL.GL_STENCIL_TEST); + } else if (!enable && record.enabled) { + gl.glDisable(GL.GL_STENCIL_TEST); + } + } else { + if (enable) { + gl.glEnable(GL.GL_STENCIL_TEST); + } else { + gl.glDisable(GL.GL_STENCIL_TEST); + } + } + + setTwoSidedEnabled(enable ? twoSided : false, record, caps); + record.enabled = enable; + } + + private static void setTwoSidedEnabled(final boolean enable, final StencilStateRecord record, + final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (caps.isTwoSidedStencilSupported()) { + if (record.isValid()) { + if (enable && !record.useTwoSided) { + gl.glEnable(GL2.GL_STENCIL_TEST_TWO_SIDE_EXT); + } else if (!enable && record.useTwoSided) { + gl.glDisable(GL2.GL_STENCIL_TEST_TWO_SIDE_EXT); + } + } else { + if (enable) { + gl.glEnable(GL2.GL_STENCIL_TEST_TWO_SIDE_EXT); + } else { + gl.glDisable(GL2.GL_STENCIL_TEST_TWO_SIDE_EXT); + } + } + } + record.useTwoSided = enable; + } + + private static void applyMask(final int writeMask, final StencilStateRecord record, final int face) { + final GL gl = GLU.getCurrentGL(); + + // if (!record.isValid() || writeMask != record.writeMask[face]) { + gl.glStencilMask(writeMask); + // record.writeMask[face] = writeMask; + // } + } + + private static void applyFunc(final int glfunc, final int stencilRef, final int funcMask, + final StencilStateRecord record, final int face) { + final GL gl = GLU.getCurrentGL(); + + // if (!record.isValid() || glfunc != record.func[face] || stencilRef != record.ref[face] + // || funcMask != record.funcMask[face]) { + gl.glStencilFunc(glfunc, stencilRef, funcMask); + // record.func[face] = glfunc; + // record.ref[face] = stencilRef; + // record.funcMask[face] = funcMask; + // } + } + + private static void applyOp(final int fail, final int zfail, final int zpass, final StencilStateRecord record, + final int face) { + final GL gl = GLU.getCurrentGL(); + + // if (!record.isValid() || fail != record.fail[face] || zfail != record.zfail[face] + // || zpass != record.zpass[face]) { + gl.glStencilOp(fail, zfail, zpass); + // record.fail[face] = fail; + // record.zfail[face] = zfail; + // record.zpass[face] = zpass; + // } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglTextureStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglTextureStateUtil.java new file mode 100644 index 0000000..e98ced2 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglTextureStateUtil.java @@ -0,0 +1,1730 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.Collection; +import java.util.logging.Logger; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLException; +import javax.media.opengl.fixedfunc.GLMatrixFunc; +import javax.media.opengl.glu.GLU; +import javax.media.opengl.glu.gl2.GLUgl2; + +import com.ardor3d.image.Image; +import com.ardor3d.image.Texture; +import com.ardor3d.image.Texture1D; +import com.ardor3d.image.Texture2D; +import com.ardor3d.image.Texture3D; +import com.ardor3d.image.TextureCubeMap; +import com.ardor3d.image.Texture.ApplyMode; +import com.ardor3d.image.Texture.CombinerFunctionAlpha; +import com.ardor3d.image.Texture.CombinerFunctionRGB; +import com.ardor3d.image.Texture.CombinerOperandAlpha; +import com.ardor3d.image.Texture.CombinerOperandRGB; +import com.ardor3d.image.Texture.CombinerSource; +import com.ardor3d.image.Texture.Type; +import com.ardor3d.image.Texture.WrapAxis; +import com.ardor3d.image.Texture.WrapMode; +import com.ardor3d.image.util.ImageUtils; +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.TextureState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.RendererRecord; +import com.ardor3d.renderer.state.record.TextureRecord; +import com.ardor3d.renderer.state.record.TextureStateRecord; +import com.ardor3d.renderer.state.record.TextureUnitRecord; +import com.ardor3d.scene.state.jogl.util.JoglRendererUtil; +import com.ardor3d.scene.state.jogl.util.JoglTextureUtil; +import com.ardor3d.util.Constants; +import com.ardor3d.util.TextureKey; +import com.ardor3d.util.TextureManager; +import com.ardor3d.util.geom.BufferUtils; +import com.ardor3d.util.stat.StatCollector; +import com.ardor3d.util.stat.StatType; + +public class JoglTextureStateUtil { + private static final Logger logger = Logger.getLogger(JoglTextureStateUtil.class.getName()); + + public final static void load(final Texture texture, final int unit) { + if (texture == null) { + return; + } + + final GL gl = GLU.getCurrentGL(); + final RenderContext context = ContextManager.getCurrentContext(); + if (context == null) { + logger.warning("RenderContext is null for texture: " + texture); + return; + } + + final ContextCapabilities caps = context.getCapabilities(); + final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture); + + // Check we are in the right unit + if (record != null) { + checkAndSetUnit(unit, record, caps); + } + + // Create the texture... + if (texture.getTextureKey() != null) { + + // Look for a texture in the cache just like ours + final TextureKey texKey = texture.getTextureKey(); + final Texture cached = TextureManager.findCachedTexture(texKey); + + if (cached == null) { + TextureManager.addToCache(texture); + } else { + final int textureId = cached.getTextureIdForContext(context.getGlContextRep()); + if (textureId != 0) { + doTextureBind(cached, unit, false); + return; + } + } + } + + final IntBuffer id = BufferUtils.createIntBuffer(1); + id.clear(); + gl.glGenTextures(id.limit(), id); + final int textureId = id.get(0); + + // store the new id by our current gl context. + texture.setTextureIdForContext(context.getGlContextRep(), textureId); + + update(texture, unit); + } + + /** + * bind texture and upload image data to card + */ + public static void update(final Texture texture, final int unit) { + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + + texture.getTextureKey().setClean(context.getGlContextRep()); + + // our texture type: + final Texture.Type type = texture.getType(); + + final GL gl = GLU.getCurrentGL(); + final GLU glu = new GLUgl2(); + + // bind our texture id to this unit. + doTextureBind(texture, unit, false); + + // pass image data to OpenGL + final Image image = texture.getImage(); + final boolean hasBorder = texture.hasBorder(); + if (image == null) { + logger.warning("Image data for texture is null."); + } + + // set alignment to support images with width % 4 != 0, as images are + // not aligned + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + + // Get texture image data. Not all textures have image data. + // For example, ApplyMode.Combine modes can use primary colors, + // texture output, and constants to modify fragments via the + // texture units. + if (image != null) { + final int maxSize = caps.getMaxTextureSize(); + final int actualWidth = image.getWidth(); + final int actualHeight = image.getHeight(); + + final boolean needsPowerOfTwo = !caps.isNonPowerOfTwoTextureSupported() + && (!MathUtils.isPowerOfTwo(image.getWidth()) || !MathUtils.isPowerOfTwo(image.getHeight())); + if (actualWidth > maxSize || actualHeight > maxSize || needsPowerOfTwo) { + if (needsPowerOfTwo) { + logger.warning("(card unsupported) Attempted to apply texture with size that is not power of 2: " + + image.getWidth() + " x " + image.getHeight()); + } + if (actualWidth > maxSize || actualHeight > maxSize) { + logger + .warning("(card unsupported) Attempted to apply texture with size bigger than max texture size [" + + maxSize + "]: " + image.getWidth() + " x " + image.getHeight()); + } + + int w = actualWidth; + if (needsPowerOfTwo) { + w = MathUtils.nearestPowerOfTwo(actualWidth); + } + if (w > maxSize) { + w = maxSize; + } + + int h = actualHeight; + if (needsPowerOfTwo) { + h = MathUtils.nearestPowerOfTwo(actualHeight); + } + if (h > maxSize) { + h = maxSize; + } + logger.warning("Rescaling image to " + w + " x " + h + " !!!"); + + // must rescale image to get "top" mipmap texture image + final int pixFormat = JoglTextureUtil.getGLPixelFormat(image.getDataFormat()); + final int pixDataType = JoglTextureUtil.getGLPixelDataType(image.getDataType()); + final int bpp = ImageUtils.getPixelByteSize(image.getDataFormat(), image.getDataType()); + final ByteBuffer scaledImage = BufferUtils.createByteBuffer((w + 4) * h * bpp); + final int error = glu.gluScaleImage(pixFormat, actualWidth, actualHeight, pixDataType, + image.getData(0), w, h, pixDataType, scaledImage); + if (error != 0) { + final int errorCode = gl.glGetError(); + if (errorCode != GL.GL_NO_ERROR) { + throw new GLException(glu.gluErrorString(errorCode)); + } + } + + image.setWidth(w); + image.setHeight(h); + image.setData(scaledImage); + } + + if (!texture.getMinificationFilter().usesMipMapLevels() && !texture.getTextureStoreFormat().isCompressed()) { + + // Load textures which do not need mipmap auto-generating and + // which aren't using compressed images. + + switch (texture.getType()) { + case TwoDimensional: + // ensure the buffer is ready for reading + image.getData(0).rewind(); + // send top level to card + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), image.getWidth(), image.getHeight(), hasBorder ? 1 : 0, + JoglTextureUtil.getGLPixelFormat(image.getDataFormat()), JoglTextureUtil + .getGLPixelDataType(image.getDataType()), image.getData(0)); + break; + case OneDimensional: + // ensure the buffer is ready for reading + image.getData(0).rewind(); + // send top level to card + gl.getGL2GL3().glTexImage1D(GL2GL3.GL_TEXTURE_1D, 0, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), image.getWidth(), hasBorder ? 1 : 0, JoglTextureUtil + .getGLPixelFormat(image.getDataFormat()), JoglTextureUtil.getGLPixelDataType(image + .getDataType()), image.getData(0)); + break; + case ThreeDimensional: + if (caps.isTexture3DSupported()) { + // concat data into single buffer: + int dSize = 0; + int count = 0; + ByteBuffer data = null; + for (int x = 0; x < image.getData().size(); x++) { + if (image.getData(x) != null) { + data = image.getData(x); + dSize += data.limit(); + count++; + } + } + // reuse buffer if we can. + if (count != 1) { + data = BufferUtils.createByteBuffer(dSize); + for (int x = 0; x < image.getData().size(); x++) { + if (image.getData(x) != null) { + data.put(image.getData(x)); + } + } + // ensure the buffer is ready for reading + data.flip(); + } + // send top level to card + gl.getGL2GL3().glTexImage3D(GL2.GL_TEXTURE_3D, 0, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), image.getWidth(), image.getHeight(), image.getDepth(), + hasBorder ? 1 : 0, JoglTextureUtil.getGLPixelFormat(image.getDataFormat()), + JoglTextureUtil.getGLPixelDataType(image.getDataType()), data); + } else { + logger.warning("This card does not support Texture3D."); + } + break; + case CubeMap: + // NOTE: Cubemaps MUST be square, so height is ignored + // on purpose. + if (caps.isTextureCubeMapSupported()) { + for (final TextureCubeMap.Face face : TextureCubeMap.Face.values()) { + // ensure the buffer is ready for reading + image.getData(face.ordinal()).rewind(); + // send top level to card + gl.glTexImage2D(getGLCubeMapFace(face), 0, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), image.getWidth(), image.getWidth(), hasBorder ? 1 + : 0, JoglTextureUtil.getGLPixelFormat(image.getDataFormat()), JoglTextureUtil + .getGLPixelDataType(image.getDataType()), image.getData(face.ordinal())); + } + } else { + logger.warning("This card does not support Cubemaps."); + } + break; + case Rectangle: + break; + default: + break; + } + } else if (texture.getMinificationFilter().usesMipMapLevels() && !image.hasMipmaps() + && !texture.getTextureStoreFormat().isCompressed()) { + + // For textures which need mipmaps auto-generating and which + // aren't using compressed images, generate the mipmaps. + // A new mipmap builder may be needed to build mipmaps for + // compressed textures. + + if (caps.isAutomaticMipmapsSupported()) { + // Flag the card to generate mipmaps + gl.glTexParameteri(getGLType(type), GL2ES1.GL_GENERATE_MIPMAP, GL.GL_TRUE); + } + + switch (type) { + case TwoDimensional: + // ensure the buffer is ready for reading + image.getData(0).rewind(); + if (caps.isAutomaticMipmapsSupported()) { + // send top level to card + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), image.getWidth(), image.getHeight(), hasBorder ? 1 : 0, + JoglTextureUtil.getGLPixelFormat(image.getDataFormat()), JoglTextureUtil + .getGLPixelDataType(image.getDataType()), image.getData(0)); + } else { + // send to card + glu.gluBuild2DMipmaps(GL.GL_TEXTURE_2D, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), image.getWidth(), image.getHeight(), JoglTextureUtil + .getGLPixelFormat(image.getDataFormat()), JoglTextureUtil.getGLPixelDataType(image + .getDataType()), image.getData(0)); + } + break; + case OneDimensional: + // ensure the buffer is ready for reading + image.getData(0).rewind(); + if (caps.isAutomaticMipmapsSupported()) { + // send top level to card + gl.getGL2GL3().glTexImage1D(GL2GL3.GL_TEXTURE_1D, 0, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), image.getWidth(), hasBorder ? 1 : 0, JoglTextureUtil + .getGLPixelFormat(image.getDataFormat()), JoglTextureUtil.getGLPixelDataType(image + .getDataType()), image.getData(0)); + } else { + // Note: JOGL's GLU class does not support + // gluBuild1DMipmaps. + logger + .warning("non-fbo 1d mipmap generation is not currently supported. Use DDS or a non-mipmap minification filter."); + return; + } + break; + case ThreeDimensional: + if (caps.isTexture3DSupported()) { + if (caps.isAutomaticMipmapsSupported()) { + // concat data into single buffer: + int dSize = 0; + int count = 0; + ByteBuffer data = null; + for (int x = 0; x < image.getData().size(); x++) { + if (image.getData(x) != null) { + data = image.getData(x); + dSize += data.limit(); + count++; + } + } + // reuse buffer if we can. + if (count != 1) { + data = BufferUtils.createByteBuffer(dSize); + for (int x = 0; x < image.getData().size(); x++) { + if (image.getData(x) != null) { + data.put(image.getData(x)); + } + } + // ensure the buffer is ready for reading + data.flip(); + } + // send top level to card + gl.getGL2GL3().glTexImage3D(GL2ES2.GL_TEXTURE_3D, 0, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), image.getWidth(), image.getHeight(), image + .getDepth(), hasBorder ? 1 : 0, JoglTextureUtil.getGLPixelFormat(image + .getDataFormat()), JoglTextureUtil.getGLPixelDataType(image.getDataType()), + data); + } else { + // Note: JOGL's GLU class does not support + // gluBuild3DMipmaps. + logger + .warning("non-fbo 3d mipmap generation is not currently supported. Use DDS or a non-mipmap minification filter."); + return; + } + } else { + logger.warning("This card does not support Texture3D."); + return; + } + break; + case CubeMap: + // NOTE: Cubemaps MUST be square, so height is ignored + // on purpose. + if (caps.isTextureCubeMapSupported()) { + if (caps.isAutomaticMipmapsSupported()) { + for (final TextureCubeMap.Face face : TextureCubeMap.Face.values()) { + // ensure the buffer is ready for reading + image.getData(face.ordinal()).rewind(); + // send top level to card + gl.glTexImage2D(getGLCubeMapFace(face), 0, JoglTextureUtil + .getGLInternalFormat(texture.getTextureStoreFormat()), image.getWidth(), + image.getWidth(), hasBorder ? 1 : 0, JoglTextureUtil.getGLPixelFormat(image + .getDataFormat()), JoglTextureUtil.getGLPixelDataType(image + .getDataType()), image.getData(face.ordinal())); + } + } else { + for (final TextureCubeMap.Face face : TextureCubeMap.Face.values()) { + // ensure the buffer is ready for reading + image.getData(face.ordinal()).rewind(); + // send to card + glu.gluBuild2DMipmaps(getGLCubeMapFace(face), JoglTextureUtil + .getGLInternalFormat(texture.getTextureStoreFormat()), image.getWidth(), + image.getWidth(), JoglTextureUtil.getGLPixelFormat(image.getDataFormat()), + JoglTextureUtil.getGLPixelDataType(image.getDataType()), image.getData(face + .ordinal())); + } + } + } else { + logger.warning("This card does not support Cubemaps."); + return; + } + break; + case Rectangle: + break; + default: + break; + } + + if (texture.getTextureMaxLevel() >= 0) { + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2GL3.GL_TEXTURE_MAX_LEVEL, texture.getTextureMaxLevel()); + } + } else { + // Here we handle textures that are either compressed or have predefined mipmaps. + // Get mipmap data sizes and amount of mipmaps to send to opengl. Then loop through all mipmaps and send + // them. + int[] mipSizes = image.getMipMapByteSizes(); + ByteBuffer data = null; + if (type == Type.CubeMap) { + if (caps.isTextureCubeMapSupported()) { + for (final TextureCubeMap.Face face : TextureCubeMap.Face.values()) { + data = image.getData(face.ordinal()); + int pos = 0; + int max = 1; + + if (mipSizes == null) { + mipSizes = new int[] { data.capacity() }; + } else if (texture.getMinificationFilter().usesMipMapLevels()) { + max = mipSizes.length; + } + + // set max mip level + gl.glTexParameteri(getGLCubeMapFace(face), GL2.GL_TEXTURE_MAX_LEVEL, max - 1); + + for (int m = 0; m < max; m++) { + final int width = Math.max(1, image.getWidth() >> m); + final int height = Math.max(1, image.getHeight() >> m); + + data.position(pos); + data.limit(pos + mipSizes[m]); + + if (texture.getTextureStoreFormat().isCompressed()) { + gl.glCompressedTexImage2D(getGLCubeMapFace(face), m, JoglTextureUtil + .getGLInternalFormat(texture.getTextureStoreFormat()), width, height, + hasBorder ? 1 : 0, mipSizes[m], data); + } else { + gl.glTexImage2D(getGLCubeMapFace(face), m, JoglTextureUtil + .getGLInternalFormat(texture.getTextureStoreFormat()), width, height, + hasBorder ? 1 : 0, JoglTextureUtil.getGLPixelFormat(image.getDataFormat()), + JoglTextureUtil.getGLPixelDataType(image.getDataType()), data); + } + pos += mipSizes[m]; + } + } + } else { + logger.warning("This card does not support CubeMaps."); + return; + } + } else { + data = image.getData(0); + int pos = 0; + int max = 1; + + if (mipSizes == null) { + mipSizes = new int[] { data.capacity() }; + } else if (texture.getMinificationFilter().usesMipMapLevels()) { + max = mipSizes.length; + } + + // Set max mip level + switch (type) { + case TwoDimensional: + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL2GL3.GL_TEXTURE_MAX_LEVEL, max - 1); + break; + case ThreeDimensional: + gl.glTexParameteri(GL2ES2.GL_TEXTURE_3D, GL2GL3.GL_TEXTURE_MAX_LEVEL, max - 1); + break; + case OneDimensional: + gl.glTexParameteri(GL2GL3.GL_TEXTURE_1D, GL2GL3.GL_TEXTURE_MAX_LEVEL, max - 1); + break; + case CubeMap: + break; + case Rectangle: + break; + default: + break; + } + + if (type == Type.ThreeDimensional) { + if (caps.isTexture3DSupported()) { + // concat data into single buffer: + int dSize = 0; + int count = 0; + for (int x = 0; x < image.getData().size(); x++) { + if (image.getData(x) != null) { + data = image.getData(x); + dSize += data.limit(); + count++; + } + } + // reuse buffer if we can. + if (count != 1) { + data = BufferUtils.createByteBuffer(dSize); + for (int x = 0; x < image.getData().size(); x++) { + if (image.getData(x) != null) { + data.put(image.getData(x)); + } + } + // ensure the buffer is ready for reading + data.flip(); + } + } else { + logger.warning("This card does not support Texture3D."); + return; + } + } + + for (int m = 0; m < max; m++) { + final int width = Math.max(1, image.getWidth() >> m); + final int height = Math.max(1, image.getHeight() >> m); + + data.position(pos); + data.limit(pos + mipSizes[m]); + + switch (type) { + case TwoDimensional: + if (texture.getTextureStoreFormat().isCompressed()) { + gl.glCompressedTexImage2D(GL.GL_TEXTURE_2D, m, JoglTextureUtil + .getGLInternalFormat(texture.getTextureStoreFormat()), width, height, + hasBorder ? 1 : 0, mipSizes[m], data); + } else { + gl.glTexImage2D(GL.GL_TEXTURE_2D, m, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), width, height, hasBorder ? 1 : 0, + JoglTextureUtil.getGLPixelFormat(image.getDataFormat()), JoglTextureUtil + .getGLPixelDataType(image.getDataType()), data); + } + break; + case OneDimensional: + if (texture.getTextureStoreFormat().isCompressed()) { + gl.getGL2GL3().glCompressedTexImage1D(GL2GL3.GL_TEXTURE_1D, m, JoglTextureUtil + .getGLInternalFormat(texture.getTextureStoreFormat()), width, hasBorder ? 1 + : 0, mipSizes[m], data); + } else { + gl.getGL2GL3().glTexImage1D(GL2GL3.GL_TEXTURE_1D, m, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), width, hasBorder ? 1 : 0, JoglTextureUtil + .getGLPixelFormat(image.getDataFormat()), JoglTextureUtil + .getGLPixelDataType(image.getDataType()), data); + } + break; + case ThreeDimensional: + final int depth = Math.max(1, image.getDepth() >> m); + // already checked for support above... + if (texture.getTextureStoreFormat().isCompressed()) { + gl.getGL2GL3().glCompressedTexImage3D(GL2ES2.GL_TEXTURE_3D, m, JoglTextureUtil + .getGLInternalFormat(texture.getTextureStoreFormat()), width, height, + depth, hasBorder ? 1 : 0, mipSizes[m], data); + } else { + gl.getGL2GL3().glTexImage3D(GL2ES2.GL_TEXTURE_3D, m, JoglTextureUtil.getGLInternalFormat(texture + .getTextureStoreFormat()), width, height, depth, hasBorder ? 1 : 0, + JoglTextureUtil.getGLPixelFormat(image.getDataFormat()), JoglTextureUtil + .getGLPixelDataType(image.getDataType()), data); + } + break; + case CubeMap: + break; + case Rectangle: + break; + default: + break; + } + + pos += mipSizes[m]; + } + } + if (data != null) { + data.clear(); + } + } + } + } + + public static void apply(final JoglRenderer renderer, final TextureState state) { + final GL gl = GLU.getCurrentGL(); + + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture); + context.setCurrentState(StateType.Texture, state); + + if (state.isEnabled()) { + + Texture texture; + Texture.Type type; + TextureUnitRecord unitRecord; + TextureRecord texRecord; + + final int glHint = JoglTextureUtil.getPerspHint(state.getCorrectionType()); + if (!record.isValid() || record.hint != glHint) { + // set up correction mode + gl.glHint(GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT, glHint); + record.hint = glHint; + } + + // loop through all available texture units... + for (int i = 0; i < caps.getNumberOfTotalTextureUnits(); i++) { + unitRecord = record.units[i]; + + // grab a texture for this unit, if available + texture = state.getTexture(i); + + // pull our texture id for this texture, for this context. + int textureId = texture != null ? texture.getTextureIdForContext(context.getGlContextRep()) : 0; + + // check for invalid textures - ones that have no opengl id and + // no image data + if (texture != null && textureId == 0 && texture.getImage() == null) { + texture = null; + } + + // null textures above fixed limit do not need to be disabled + // since they are not really part of the pipeline. + if (texture == null) { + if (i >= caps.getNumberOfFixedTextureUnits()) { + continue; + } else { + // a null texture indicates no texturing at this unit + // Disable texturing on this unit if enabled. + disableTexturing(unitRecord, record, i, caps); + + if (i < state._keyCache.length) { + state._keyCache[i] = null; + } + + // next texture! + continue; + } + } + + type = texture.getType(); + + // disable other texturing types for this unit, if enabled. + disableTexturing(unitRecord, record, i, type, caps); + + // Time to bind the texture, so see if we need to load in image + // data for this texture. + if (textureId == 0) { + // texture not yet loaded. + // this will load and bind and set the records... + load(texture, i); + textureId = texture.getTextureIdForContext(context.getGlContextRep()); + if (textureId == 0) { + continue; + } + } else if (texture.isDirty(context.getGlContextRep())) { + update(texture, i); + textureId = texture.getTextureIdForContext(context.getGlContextRep()); + if (textureId == 0) { + continue; + } + } else { + // texture already exists in OpenGL, just bind it if needed + if (!unitRecord.isValid() || unitRecord.boundTexture != textureId) { + checkAndSetUnit(i, record, caps); + gl.glBindTexture(getGLType(type), textureId); + if (Constants.stats) { + StatCollector.addStat(StatType.STAT_TEXTURE_BINDS, 1); + } + unitRecord.boundTexture = textureId; + } + } + + // Use the Java Integer object for the getTextureRecord call to avoid + // boxing/unboxing ints for map lookups. + final Integer textureIdInteger = texture.getTextureIdForContextAsInteger(context.getGlContextRep()); + + // Grab our record for this texture + texRecord = record.getTextureRecord(textureIdInteger, texture.getType()); + + // Set the keyCache value for this unit of this texture state + // This is done so during state comparison we don't have to + // spend a lot of time pulling out classes and finding field + // data. + state._keyCache[i] = texture.getTextureKey(); + + // Some texture things only apply to fixed function pipeline + if (i < caps.getNumberOfFixedTextureUnits()) { + + // Enable 2D texturing on this unit if not enabled. + if (!unitRecord.isValid() || !unitRecord.enabled[type.ordinal()]) { + checkAndSetUnit(i, record, caps); + gl.glEnable(getGLType(type)); + unitRecord.enabled[type.ordinal()] = true; + } + + // Set our blend color, if needed. + applyBlendColor(texture, unitRecord, i, record, caps); + + // Set the texture environment mode if this unit isn't + // already set properly + applyEnvMode(texture.getApply(), unitRecord, i, record, caps); + + // If our mode is combine, and we support multitexturing + // apply combine settings. + if (texture.getApply() == ApplyMode.Combine && caps.isMultitextureSupported() + && caps.isEnvCombineSupported()) { + applyCombineFactors(texture, unitRecord, i, record, caps); + } + } + + // Other items only apply to textures below the frag unit limit + if (i < caps.getNumberOfFragmentTextureUnits()) { + + // texture specific params + applyFilter(texture, texRecord, i, record, caps); + applyWrap(texture, texRecord, i, record, caps); + applyShadow(texture, texRecord, i, record, caps); + + // Set our border color, if needed. + applyBorderColor(texture, texRecord, i, record, caps); + + // all states have now been applied for a tex record, so we + // can safely make it valid + if (!texRecord.isValid()) { + texRecord.validate(); + } + + } + + // Other items only apply to textures below the frag tex coord + // unit limit + if (i < caps.getNumberOfFragmentTexCoordUnits()) { + + // Now time to play with texture matrices + // Determine which transforms to do. + applyTextureTransforms(texture, i, record, caps); + + // Now let's look at automatic texture coordinate + // generation. + applyTexCoordGeneration(texture, unitRecord, i, record, caps); + + // Set our texture lod bias, if needed. + applyLodBias(texture, unitRecord, i, record, caps); + } + + } + + } else { + // turn off texturing + TextureUnitRecord unitRecord; + + if (caps.isMultitextureSupported()) { + for (int i = 0; i < caps.getNumberOfFixedTextureUnits(); i++) { + unitRecord = record.units[i]; + disableTexturing(unitRecord, record, i, caps); + } + } else { + unitRecord = record.units[0]; + disableTexturing(unitRecord, record, 0, caps); + } + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static void disableTexturing(final TextureUnitRecord unitRecord, final TextureStateRecord record, + final int unit, final Type exceptedType, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (exceptedType != Type.TwoDimensional) { + if (!unitRecord.isValid() || unitRecord.enabled[Type.TwoDimensional.ordinal()]) { + // Check we are in the right unit + checkAndSetUnit(unit, record, caps); + gl.glDisable(GL.GL_TEXTURE_2D); + unitRecord.enabled[Type.TwoDimensional.ordinal()] = false; + } + } + + if (exceptedType != Type.OneDimensional) { + if (!unitRecord.isValid() || unitRecord.enabled[Type.OneDimensional.ordinal()]) { + // Check we are in the right unit + checkAndSetUnit(unit, record, caps); + gl.glDisable(GL2GL3.GL_TEXTURE_1D); + unitRecord.enabled[Type.OneDimensional.ordinal()] = false; + } + } + + if (caps.isTexture3DSupported() && exceptedType != Type.ThreeDimensional) { + if (!unitRecord.isValid() || unitRecord.enabled[Type.ThreeDimensional.ordinal()]) { + // Check we are in the right unit + checkAndSetUnit(unit, record, caps); + gl.glDisable(GL2ES2.GL_TEXTURE_3D); + unitRecord.enabled[Type.ThreeDimensional.ordinal()] = false; + } + } + + if (caps.isTextureCubeMapSupported() && exceptedType != Type.CubeMap) { + if (!unitRecord.isValid() || unitRecord.enabled[Type.CubeMap.ordinal()]) { + // Check we are in the right unit + checkAndSetUnit(unit, record, caps); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + unitRecord.enabled[Type.CubeMap.ordinal()] = false; + } + } + + } + + private static void disableTexturing(final TextureUnitRecord unitRecord, final TextureStateRecord record, + final int unit, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (!unitRecord.isValid() || unitRecord.enabled[Type.TwoDimensional.ordinal()]) { + // Check we are in the right unit + checkAndSetUnit(unit, record, caps); + gl.glDisable(GL.GL_TEXTURE_2D); + unitRecord.enabled[Type.TwoDimensional.ordinal()] = false; + } + + if (!unitRecord.isValid() || unitRecord.enabled[Type.OneDimensional.ordinal()]) { + // Check we are in the right unit + checkAndSetUnit(unit, record, caps); + gl.glDisable(GL2GL3.GL_TEXTURE_1D); + unitRecord.enabled[Type.OneDimensional.ordinal()] = false; + } + + if (caps.isTexture3DSupported()) { + if (!unitRecord.isValid() || unitRecord.enabled[Type.ThreeDimensional.ordinal()]) { + // Check we are in the right unit + checkAndSetUnit(unit, record, caps); + gl.glDisable(GL2ES2.GL_TEXTURE_3D); + unitRecord.enabled[Type.ThreeDimensional.ordinal()] = false; + } + } + + if (caps.isTextureCubeMapSupported()) { + if (!unitRecord.isValid() || unitRecord.enabled[Type.CubeMap.ordinal()]) { + // Check we are in the right unit + checkAndSetUnit(unit, record, caps); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + unitRecord.enabled[Type.CubeMap.ordinal()] = false; + } + } + + } + + public static void applyCombineFactors(final Texture texture, final TextureUnitRecord unitRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + // check that this is a valid fixed function unit. glTexEnv is only + // supported for unit < GL_MAX_TEXTURE_UNITS + if (unit >= caps.getNumberOfFixedTextureUnits()) { + return; + } + + // first thing's first... if we are doing dot3 and don't + // support it, disable this texture. + boolean checked = false; + if (!caps.isEnvDot3TextureCombineSupported() + && (texture.getCombineFuncRGB() == CombinerFunctionRGB.Dot3RGB || texture.getCombineFuncRGB() == CombinerFunctionRGB.Dot3RGBA)) { + + // disable + disableTexturing(unitRecord, record, unit, caps); + + // No need to continue + return; + } + + // Okay, now let's set our scales if we need to: + // First RGB Combine scale + if (!unitRecord.isValid() || unitRecord.envRGBScale != texture.getCombineScaleRGB()) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvf(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_RGB_SCALE, texture.getCombineScaleRGB().floatValue()); + unitRecord.envRGBScale = texture.getCombineScaleRGB(); + } // Then Alpha Combine scale + if (!unitRecord.isValid() || unitRecord.envAlphaScale != texture.getCombineScaleAlpha()) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvf(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_ALPHA_SCALE, texture.getCombineScaleAlpha().floatValue()); + unitRecord.envAlphaScale = texture.getCombineScaleAlpha(); + } + + // Time to set the RGB combines + final CombinerFunctionRGB rgbCombineFunc = texture.getCombineFuncRGB(); + if (!unitRecord.isValid() || unitRecord.rgbCombineFunc != rgbCombineFunc) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_COMBINE_RGB, JoglTextureUtil.getGLCombineFuncRGB(rgbCombineFunc)); + unitRecord.rgbCombineFunc = rgbCombineFunc; + } + + CombinerSource combSrcRGB = texture.getCombineSrc0RGB(); + if (!unitRecord.isValid() || unitRecord.combSrcRGB0 != combSrcRGB) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2.GL_SOURCE0_RGB, JoglTextureUtil.getGLCombineSrc(combSrcRGB)); + unitRecord.combSrcRGB0 = combSrcRGB; + } + + CombinerOperandRGB combOpRGB = texture.getCombineOp0RGB(); + if (!unitRecord.isValid() || unitRecord.combOpRGB0 != combOpRGB) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_OPERAND0_RGB, JoglTextureUtil.getGLCombineOpRGB(combOpRGB)); + unitRecord.combOpRGB0 = combOpRGB; + } + + // We only need to do Arg1 or Arg2 if we aren't in Replace mode + if (rgbCombineFunc != CombinerFunctionRGB.Replace) { + + combSrcRGB = texture.getCombineSrc1RGB(); + if (!unitRecord.isValid() || unitRecord.combSrcRGB1 != combSrcRGB) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2.GL_SOURCE1_RGB, JoglTextureUtil.getGLCombineSrc(combSrcRGB)); + unitRecord.combSrcRGB1 = combSrcRGB; + } + + combOpRGB = texture.getCombineOp1RGB(); + if (!unitRecord.isValid() || unitRecord.combOpRGB1 != combOpRGB) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_OPERAND1_RGB, JoglTextureUtil.getGLCombineOpRGB(combOpRGB)); + unitRecord.combOpRGB1 = combOpRGB; + } + + // We only need to do Arg2 if we are in Interpolate mode + if (rgbCombineFunc == CombinerFunctionRGB.Interpolate) { + + combSrcRGB = texture.getCombineSrc2RGB(); + if (!unitRecord.isValid() || unitRecord.combSrcRGB2 != combSrcRGB) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2.GL_SOURCE2_RGB, JoglTextureUtil.getGLCombineSrc(combSrcRGB)); + unitRecord.combSrcRGB2 = combSrcRGB; + } + + combOpRGB = texture.getCombineOp2RGB(); + if (!unitRecord.isValid() || unitRecord.combOpRGB2 != combOpRGB) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_OPERAND2_RGB, JoglTextureUtil.getGLCombineOpRGB(combOpRGB)); + unitRecord.combOpRGB2 = combOpRGB; + } + + } + } + + // Now Alpha combines + final CombinerFunctionAlpha alphaCombineFunc = texture.getCombineFuncAlpha(); + if (!unitRecord.isValid() || unitRecord.alphaCombineFunc != alphaCombineFunc) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_COMBINE_ALPHA, JoglTextureUtil + .getGLCombineFuncAlpha(alphaCombineFunc)); + unitRecord.alphaCombineFunc = alphaCombineFunc; + } + + CombinerSource combSrcAlpha = texture.getCombineSrc0Alpha(); + if (!unitRecord.isValid() || unitRecord.combSrcAlpha0 != combSrcAlpha) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2.GL_SOURCE0_ALPHA, JoglTextureUtil.getGLCombineSrc(combSrcAlpha)); + unitRecord.combSrcAlpha0 = combSrcAlpha; + } + + CombinerOperandAlpha combOpAlpha = texture.getCombineOp0Alpha(); + if (!unitRecord.isValid() || unitRecord.combOpAlpha0 != combOpAlpha) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_OPERAND0_ALPHA, JoglTextureUtil.getGLCombineOpAlpha(combOpAlpha)); + unitRecord.combOpAlpha0 = combOpAlpha; + } + + // We only need to do Arg1 or Arg2 if we aren't in Replace mode + if (alphaCombineFunc != CombinerFunctionAlpha.Replace) { + + combSrcAlpha = texture.getCombineSrc1Alpha(); + if (!unitRecord.isValid() || unitRecord.combSrcAlpha1 != combSrcAlpha) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2.GL_SOURCE1_ALPHA, JoglTextureUtil.getGLCombineSrc(combSrcAlpha)); + unitRecord.combSrcAlpha1 = combSrcAlpha; + } + + combOpAlpha = texture.getCombineOp1Alpha(); + if (!unitRecord.isValid() || unitRecord.combOpAlpha1 != combOpAlpha) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_OPERAND1_ALPHA, JoglTextureUtil.getGLCombineOpAlpha(combOpAlpha)); + unitRecord.combOpAlpha1 = combOpAlpha; + } + + // We only need to do Arg2 if we are in Interpolate mode + if (alphaCombineFunc == CombinerFunctionAlpha.Interpolate) { + + combSrcAlpha = texture.getCombineSrc2Alpha(); + if (!unitRecord.isValid() || unitRecord.combSrcAlpha2 != combSrcAlpha) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2.GL_SOURCE2_ALPHA, JoglTextureUtil.getGLCombineSrc(combSrcAlpha)); + unitRecord.combSrcAlpha2 = combSrcAlpha; + } + + combOpAlpha = texture.getCombineOp2Alpha(); + if (!unitRecord.isValid() || unitRecord.combOpAlpha2 != combOpAlpha) { + if (!checked) { + checkAndSetUnit(unit, record, caps); + checked = true; + } + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_OPERAND2_ALPHA, JoglTextureUtil + .getGLCombineOpAlpha(combOpAlpha)); + unitRecord.combOpAlpha2 = combOpAlpha; + } + } + } + } + + public static void applyEnvMode(final ApplyMode mode, final TextureUnitRecord unitRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (!unitRecord.isValid() || unitRecord.envMode != mode) { + checkAndSetUnit(unit, record, caps); + gl.getGL2ES1().glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_TEXTURE_ENV_MODE, JoglTextureUtil.getGLEnvMode(mode)); + unitRecord.envMode = mode; + } + } + + public static void applyBlendColor(final Texture texture, final TextureUnitRecord unitRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + final ReadOnlyColorRGBA texBlend = texture.getConstantColor(); + if (!unitRecord.isValid() || !unitRecord.blendColor.equals(texBlend)) { + checkAndSetUnit(unit, record, caps); + TextureRecord.colorBuffer.clear(); + TextureRecord.colorBuffer.put(texBlend.getRed()).put(texBlend.getGreen()).put(texBlend.getBlue()).put( + texBlend.getAlpha()); + TextureRecord.colorBuffer.rewind(); + gl.getGL2ES1().glTexEnvfv(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_TEXTURE_ENV_COLOR, TextureRecord.colorBuffer); + unitRecord.blendColor.set(texBlend); + } + } + + public static void applyLodBias(final Texture texture, final TextureUnitRecord unitRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (caps.isTextureLodBiasSupported()) { + final float bias = texture.getLodBias() < caps.getMaxLodBias() ? texture.getLodBias() : caps + .getMaxLodBias(); + if (!unitRecord.isValid() || unitRecord.lodBias != bias) { + checkAndSetUnit(unit, record, caps); + gl.getGL2ES1().glTexEnvf(GL2.GL_TEXTURE_FILTER_CONTROL, GL2GL3.GL_TEXTURE_LOD_BIAS, bias); + unitRecord.lodBias = bias; + } + } + } + + public static void applyBorderColor(final Texture texture, final TextureRecord texRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + final ReadOnlyColorRGBA texBorder = texture.getBorderColor(); + if (!texRecord.isValid() || !texRecord.borderColor.equals(texBorder)) { + TextureRecord.colorBuffer.clear(); + TextureRecord.colorBuffer.put(texBorder.getRed()).put(texBorder.getGreen()).put(texBorder.getBlue()).put( + texBorder.getAlpha()); + TextureRecord.colorBuffer.rewind(); + gl.glTexParameterfv(getGLType(texture.getType()), GL2GL3.GL_TEXTURE_BORDER_COLOR, TextureRecord.colorBuffer); + texRecord.borderColor.set(texBorder); + } + } + + public static void applyTextureTransforms(final Texture texture, final int unit, final TextureStateRecord record, + final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + final boolean needsReset = !record.units[unit].identityMatrix; + + // Should we apply the transform? + final boolean doTrans = !texture.getTextureMatrix().isIdentity(); + + // Now do them. + final RendererRecord matRecord = ContextManager.getCurrentContext().getRendererRecord(); + if (doTrans) { + checkAndSetUnit(unit, record, caps); + JoglRendererUtil.switchMode(matRecord, GL.GL_TEXTURE); + + record.tmp_matrixBuffer.rewind(); + texture.getTextureMatrix().toDoubleBuffer(record.tmp_matrixBuffer, true); + record.tmp_matrixBuffer.rewind(); + gl.getGL2().glLoadMatrixd(record.tmp_matrixBuffer); + + record.units[unit].identityMatrix = false; + } else if (needsReset) { + checkAndSetUnit(unit, record, caps); + JoglRendererUtil.switchMode(matRecord, GL.GL_TEXTURE); + gl.getGL2().glLoadIdentity(); + record.units[unit].identityMatrix = true; + } + // Switch back to the modelview matrix for further operations + JoglRendererUtil.switchMode(matRecord, GLMatrixFunc.GL_MODELVIEW); + } + + public static void applyTexCoordGeneration(final Texture texture, final TextureUnitRecord unitRecord, + final int unit, final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + switch (texture.getEnvironmentalMapMode()) { + case None: + // No coordinate generation + setTextureGen(unitRecord, unit, record, caps, false, false, false, false); + break; + case SphereMap: + // generate spherical texture coordinates + if (!unitRecord.isValid() || unitRecord.textureGenSMode != GL2.GL_SPHERE_MAP) { + checkAndSetUnit(unit, record, caps); + + gl.getGL2().glTexGeni(GL2.GL_S, GL2ES1.GL_TEXTURE_GEN_MODE, GL2.GL_SPHERE_MAP); + unitRecord.textureGenSMode = GL2.GL_SPHERE_MAP; + + gl.getGL2().glTexGeni(GL2.GL_T, GL2ES1.GL_TEXTURE_GEN_MODE, GL2.GL_SPHERE_MAP); + unitRecord.textureGenTMode = GL2.GL_SPHERE_MAP; + } + + setTextureGen(unitRecord, unit, record, caps, true, true, false, false); + break; + case NormalMap: + // generate normals based texture coordinates + if (!unitRecord.isValid() || unitRecord.textureGenSMode != GL2ES1.GL_NORMAL_MAP) { + checkAndSetUnit(unit, record, caps); + gl.getGL2().glTexGeni(GL2.GL_S, GL2ES1.GL_TEXTURE_GEN_MODE, GL2ES1.GL_NORMAL_MAP); + unitRecord.textureGenSMode = GL2ES1.GL_NORMAL_MAP; + + gl.getGL2().glTexGeni(GL2.GL_T, GL2ES1.GL_TEXTURE_GEN_MODE, GL2ES1.GL_NORMAL_MAP); + unitRecord.textureGenTMode = GL2ES1.GL_NORMAL_MAP; + + gl.getGL2().glTexGeni(GL2.GL_R, GL2ES1.GL_TEXTURE_GEN_MODE, GL2ES1.GL_NORMAL_MAP); + unitRecord.textureGenRMode = GL2ES1.GL_NORMAL_MAP; + } + + setTextureGen(unitRecord, unit, record, caps, true, true, true, false); + break; + case ReflectionMap: + // generate reflection texture coordinates + if (!unitRecord.isValid() || unitRecord.textureGenSMode != GL2ES1.GL_REFLECTION_MAP) { + checkAndSetUnit(unit, record, caps); + + gl.getGL2ES1().glTexGeni(GL2.GL_S, GL2ES1.GL_TEXTURE_GEN_MODE, GL2ES1.GL_REFLECTION_MAP); + unitRecord.textureGenSMode = GL2ES1.GL_REFLECTION_MAP; + + gl.getGL2ES1().glTexGeni(GL2.GL_T, GL2ES1.GL_TEXTURE_GEN_MODE, GL2ES1.GL_REFLECTION_MAP); + unitRecord.textureGenTMode = GL2ES1.GL_REFLECTION_MAP; + + gl.getGL2ES1().glTexGeni(GL2.GL_R, GL2ES1.GL_TEXTURE_GEN_MODE, GL2ES1.GL_REFLECTION_MAP); + unitRecord.textureGenRMode = GL2ES1.GL_REFLECTION_MAP; + } + + setTextureGen(unitRecord, unit, record, caps, true, true, true, false); + break; + case EyeLinear: + // do here because we don't check planes + checkAndSetUnit(unit, record, caps); + + // generate eye linear texture coordinates + if (!unitRecord.isValid() || unitRecord.textureGenSMode != GL2.GL_EYE_LINEAR) { + gl.getGL2ES1().glTexGeni(GL2.GL_S, GL2ES1.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR); + unitRecord.textureGenSMode = GL2.GL_EYE_LINEAR; + + gl.getGL2ES1().glTexGeni(GL2.GL_T, GL2ES1.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR); + unitRecord.textureGenTMode = GL2.GL_EYE_LINEAR; + + gl.getGL2ES1().glTexGeni(GL2.GL_R, GL2ES1.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR); + unitRecord.textureGenRMode = GL2.GL_EYE_LINEAR; + + gl.getGL2ES1().glTexGeni(GL2.GL_Q, GL2ES1.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR); + unitRecord.textureGenQMode = GL2.GL_EYE_LINEAR; + } + + record.prepPlane(texture.getEnvPlaneS(), TextureStateRecord.DEFAULT_S_PLANE); + gl.getGL2ES1().glTexGenfv(GL2.GL_S, GL2.GL_EYE_PLANE, record.plane); + record.prepPlane(texture.getEnvPlaneT(), TextureStateRecord.DEFAULT_T_PLANE); + gl.getGL2ES1().glTexGenfv(GL2.GL_T, GL2.GL_EYE_PLANE, record.plane); + record.prepPlane(texture.getEnvPlaneR(), TextureStateRecord.DEFAULT_R_PLANE); + gl.getGL2ES1().glTexGenfv(GL2.GL_R, GL2.GL_EYE_PLANE, record.plane); + record.prepPlane(texture.getEnvPlaneQ(), TextureStateRecord.DEFAULT_Q_PLANE); + gl.getGL2ES1().glTexGenfv(GL2.GL_Q, GL2.GL_EYE_PLANE, record.plane); + + setTextureGen(unitRecord, unit, record, caps, true, true, true, true); + break; + case ObjectLinear: + // do here because we don't check planes + checkAndSetUnit(unit, record, caps); + + // generate object linear texture coordinates + if (!unitRecord.isValid() || unitRecord.textureGenSMode != GL2.GL_OBJECT_LINEAR) { + gl.getGL2ES1().glTexGeni(GL2.GL_S, GL2ES1.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR); + unitRecord.textureGenSMode = GL2.GL_OBJECT_LINEAR; + + gl.getGL2ES1().glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR); + unitRecord.textureGenTMode = GL2.GL_OBJECT_LINEAR; + + gl.getGL2ES1().glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR); + unitRecord.textureGenRMode = GL2.GL_OBJECT_LINEAR; + + gl.getGL2ES1().glTexGeni(GL2.GL_Q, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR); + unitRecord.textureGenQMode = GL2.GL_OBJECT_LINEAR; + } + + record.prepPlane(texture.getEnvPlaneS(), TextureStateRecord.DEFAULT_S_PLANE); + gl.getGL2ES1().glTexGenfv(GL2.GL_S, GL2.GL_OBJECT_PLANE, record.plane); + record.prepPlane(texture.getEnvPlaneT(), TextureStateRecord.DEFAULT_T_PLANE); + gl.getGL2ES1().glTexGenfv(GL2.GL_T, GL2.GL_OBJECT_PLANE, record.plane); + record.prepPlane(texture.getEnvPlaneR(), TextureStateRecord.DEFAULT_R_PLANE); + gl.getGL2ES1().glTexGenfv(GL2.GL_R, GL2.GL_OBJECT_PLANE, record.plane); + record.prepPlane(texture.getEnvPlaneQ(), TextureStateRecord.DEFAULT_Q_PLANE); + gl.getGL2ES1().glTexGenfv(GL2.GL_Q, GL2.GL_OBJECT_PLANE, record.plane); + + setTextureGen(unitRecord, unit, record, caps, true, true, true, true); + break; + } + } + + private static void setTextureGen(final TextureUnitRecord unitRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps, final boolean genS, final boolean genT, + final boolean genR, final boolean genQ) { + final GL gl = GLU.getCurrentGL(); + + if (!unitRecord.isValid()) { + checkAndSetUnit(unit, record, caps); + + if (genS) { + gl.glEnable(GL2.GL_TEXTURE_GEN_S); + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_S); + } + if (genT) { + gl.glEnable(GL2.GL_TEXTURE_GEN_T); + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_T); + } + if (genR) { + gl.glEnable(GL2.GL_TEXTURE_GEN_R); + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_R); + } + if (genQ) { + gl.glEnable(GL2.GL_TEXTURE_GEN_Q); + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_Q); + } + } else { + if (genS != unitRecord.textureGenS) { + checkAndSetUnit(unit, record, caps); + if (genS) { + gl.glEnable(GL2.GL_TEXTURE_GEN_S); + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_S); + } + } + if (genT != unitRecord.textureGenT) { + checkAndSetUnit(unit, record, caps); + if (genT) { + gl.glEnable(GL2.GL_TEXTURE_GEN_T); + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_T); + } + } + if (genR != unitRecord.textureGenR) { + checkAndSetUnit(unit, record, caps); + if (genR) { + gl.glEnable(GL2.GL_TEXTURE_GEN_R); + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_R); + } + } + if (genQ != unitRecord.textureGenQ) { + checkAndSetUnit(unit, record, caps); + if (genQ) { + gl.glEnable(GL2.GL_TEXTURE_GEN_Q); + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_Q); + } + } + } + + unitRecord.textureGenS = genS; + unitRecord.textureGenT = genT; + unitRecord.textureGenR = genR; + unitRecord.textureGenQ = genQ; + } + + // If we support multitexturing, specify the unit we are affecting. + public static void checkAndSetUnit(final int unit, final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + // No need to worry about valid record, since invalidate sets record's + // currentUnit to -1. + if (record.currentUnit != unit) { + if (unit >= caps.getNumberOfTotalTextureUnits() || !caps.isMultitextureSupported() || unit < 0) { + // ignore this request as it is not valid for the user's hardware. + return; + } + gl.glActiveTexture(GL.GL_TEXTURE0 + unit); + record.currentUnit = unit; + } + } + + /** + * Check if the filter settings of this particular texture have been changed and apply as needed. + * + * @param texture + * our texture object + * @param texRecord + * our record of the last state of the texture in gl + * @param record + */ + public static void applyShadow(final Texture texture, final TextureRecord texRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + final Type type = texture.getType(); + + if (caps.isDepthTextureSupported()) { + final int depthMode = JoglTextureUtil.getGLDepthTextureMode(texture.getDepthMode()); + // set up magnification filter + if (!texRecord.isValid() || texRecord.depthTextureMode != depthMode) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(getGLType(type), GL2.GL_DEPTH_TEXTURE_MODE, depthMode); + texRecord.depthTextureMode = depthMode; + } + } + + if (caps.isARBShadowSupported()) { + final int depthCompareMode = JoglTextureUtil.getGLDepthTextureCompareMode(texture.getDepthCompareMode()); + // set up magnification filter + if (!texRecord.isValid() || texRecord.depthTextureCompareMode != depthCompareMode) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(getGLType(type), GL2ES2.GL_TEXTURE_COMPARE_MODE, depthCompareMode); + texRecord.depthTextureCompareMode = depthCompareMode; + } + + final int depthCompareFunc = JoglTextureUtil.getGLDepthTextureCompareFunc(texture.getDepthCompareFunc()); + // set up magnification filter + if (!texRecord.isValid() || texRecord.depthTextureCompareFunc != depthCompareFunc) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(getGLType(type), GL2ES2.GL_TEXTURE_COMPARE_FUNC, depthCompareFunc); + texRecord.depthTextureCompareFunc = depthCompareFunc; + } + } + } + + /** + * Check if the filter settings of this particular texture have been changed and apply as needed. + * + * @param texture + * our texture object + * @param texRecord + * our record of the last state of the texture in gl + * @param record + */ + public static void applyFilter(final Texture texture, final TextureRecord texRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + final Type type = texture.getType(); + + final int magFilter = JoglTextureUtil.getGLMagFilter(texture.getMagnificationFilter()); + // set up magnification filter + if (!texRecord.isValid() || texRecord.magFilter != magFilter) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(getGLType(type), GL.GL_TEXTURE_MAG_FILTER, magFilter); + texRecord.magFilter = magFilter; + } + + final int minFilter = JoglTextureUtil.getGLMinFilter(texture.getMinificationFilter()); + // set up mipmap filter + if (!texRecord.isValid() || texRecord.minFilter != minFilter) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(getGLType(type), GL.GL_TEXTURE_MIN_FILTER, minFilter); + texRecord.minFilter = minFilter; + } + + // set up aniso filter + if (caps.isAnisoSupported()) { + float aniso = texture.getAnisotropicFilterPercent() * (caps.getMaxAnisotropic() - 1.0f); + aniso += 1.0f; + if (!texRecord.isValid() || texRecord.anisoLevel != aniso) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameterf(getGLType(type), GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso); + texRecord.anisoLevel = aniso; + } + } + } + + /** + * Check if the wrap mode of this particular texture has been changed and apply as needed. + * + * @param texture + * our texture object + * @param texRecord + * our record of the last state of the unit in gl + * @param record + */ + public static void applyWrap(final Texture3D texture, final TextureRecord texRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (!caps.isTexture3DSupported()) { + return; + } + + final int wrapS = getGLWrap(texture.getWrap(WrapAxis.S), caps); + final int wrapT = getGLWrap(texture.getWrap(WrapAxis.T), caps); + final int wrapR = getGLWrap(texture.getWrap(WrapAxis.R), caps); + + if (!texRecord.isValid() || texRecord.wrapS != wrapS) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(GL2ES2.GL_TEXTURE_3D, GL.GL_TEXTURE_WRAP_S, wrapS); + texRecord.wrapS = wrapS; + } + if (!texRecord.isValid() || texRecord.wrapT != wrapT) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(GL2ES2.GL_TEXTURE_3D, GL.GL_TEXTURE_WRAP_T, wrapT); + texRecord.wrapT = wrapT; + } + if (!texRecord.isValid() || texRecord.wrapR != wrapR) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(GL2ES2.GL_TEXTURE_3D, GL2ES2.GL_TEXTURE_WRAP_R, wrapR); + texRecord.wrapR = wrapR; + } + + } + + /** + * Check if the wrap mode of this particular texture has been changed and apply as needed. + * + * @param texture + * our texture object + * @param texRecord + * our record of the last state of the unit in gl + * @param record + */ + public static void applyWrap(final Texture1D texture, final TextureRecord texRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + final int wrapS = getGLWrap(texture.getWrap(WrapAxis.S), caps); + + if (!texRecord.isValid() || texRecord.wrapS != wrapS) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(GL2GL3.GL_TEXTURE_1D, GL.GL_TEXTURE_WRAP_S, wrapS); + texRecord.wrapS = wrapS; + } + } + + /** + * Check if the wrap mode of this particular texture has been changed and apply as needed. + * + * @param texture + * our texture object + * @param texRecord + * our record of the last state of the unit in gl + * @param record + */ + public static void applyWrap(final Texture texture, final TextureRecord texRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + if (texture instanceof Texture2D) { + applyWrap((Texture2D) texture, texRecord, unit, record, caps); + } else if (texture instanceof Texture1D) { + applyWrap((Texture1D) texture, texRecord, unit, record, caps); + } else if (texture instanceof Texture3D) { + applyWrap((Texture3D) texture, texRecord, unit, record, caps); + } else if (texture instanceof TextureCubeMap) { + applyWrap((TextureCubeMap) texture, texRecord, unit, record, caps); + } + } + + /** + * Check if the wrap mode of this particular texture has been changed and apply as needed. + * + * @param texture + * our texture object + * @param texRecord + * our record of the last state of the unit in gl + * @param record + */ + public static void applyWrap(final Texture2D texture, final TextureRecord texRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + final int wrapS = getGLWrap(texture.getWrap(WrapAxis.S), caps); + final int wrapT = getGLWrap(texture.getWrap(WrapAxis.T), caps); + + if (!texRecord.isValid() || texRecord.wrapS != wrapS) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, wrapS); + texRecord.wrapS = wrapS; + } + if (!texRecord.isValid() || texRecord.wrapT != wrapT) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, wrapT); + texRecord.wrapT = wrapT; + } + + } + + /** + * Check if the wrap mode of this particular texture has been changed and apply as needed. + * + * @param cubeMap + * our texture object + * @param texRecord + * our record of the last state of the unit in gl + * @param record + */ + public static void applyWrap(final TextureCubeMap cubeMap, final TextureRecord texRecord, final int unit, + final TextureStateRecord record, final ContextCapabilities caps) { + final GL gl = GLU.getCurrentGL(); + + if (!caps.isTextureCubeMapSupported()) { + return; + } + + final int wrapS = getGLWrap(cubeMap.getWrap(WrapAxis.S), caps); + final int wrapT = getGLWrap(cubeMap.getWrap(WrapAxis.T), caps); + final int wrapR = getGLWrap(cubeMap.getWrap(WrapAxis.R), caps); + + if (!texRecord.isValid() || texRecord.wrapS != wrapS) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(GL.GL_TEXTURE_CUBE_MAP, GL.GL_TEXTURE_WRAP_S, wrapS); + texRecord.wrapS = wrapS; + } + if (!texRecord.isValid() || texRecord.wrapT != wrapT) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(GL.GL_TEXTURE_CUBE_MAP, GL.GL_TEXTURE_WRAP_T, wrapT); + texRecord.wrapT = wrapT; + } + if (!texRecord.isValid() || texRecord.wrapR != wrapR) { + checkAndSetUnit(unit, record, caps); + gl.glTexParameteri(GL.GL_TEXTURE_CUBE_MAP, GL2ES2.GL_TEXTURE_WRAP_R, wrapR); + texRecord.wrapR = wrapR; + } + } + + public static void deleteTexture(final Texture texture) { + final GL gl = GLU.getCurrentGL(); + + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture); + + final Integer id = texture.getTextureIdForContextAsInteger(context.getGlContextRep()); + if (id.intValue() == 0) { + // Not on card... return. + return; + } + + final IntBuffer idBuffer = BufferUtils.createIntBuffer(1); + idBuffer.clear(); + idBuffer.put(id.intValue()); + idBuffer.rewind(); + gl.glDeleteTextures(idBuffer.limit(), idBuffer); + record.removeTextureRecord(id); + texture.removeFromIdCache(context.getGlContextRep()); + } + + public static void deleteTextureIds(final Collection<Integer> ids) { + final GL gl = GLU.getCurrentGL(); + + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture); + + final IntBuffer idBuffer = BufferUtils.createIntBuffer(ids.size()); + idBuffer.clear(); + for (final Integer i : ids) { + if (i != null) { + idBuffer.put(i); + record.removeTextureRecord(i); + } + } + idBuffer.flip(); + if (idBuffer.remaining() > 0) { + gl.glDeleteTextures(idBuffer.remaining(), idBuffer); + } + } + + /** + * Useful for external jogl based classes that need to safely set the current texture. + */ + public static void doTextureBind(final Texture texture, final int unit, final boolean invalidateState) { + final GL gl = GLU.getCurrentGL(); + + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture); + if (invalidateState) { + // Set this to null because no current state really matches anymore + context.setCurrentState(StateType.Texture, null); + } + checkAndSetUnit(unit, record, caps); + + final int id = texture.getTextureIdForContext(context.getGlContextRep()); + gl.glBindTexture(getGLType(texture.getType()), id); + if (Constants.stats) { + StatCollector.addStat(StatType.STAT_TEXTURE_BINDS, 1); + } + if (record != null) { + record.units[unit].boundTexture = id; + } + } + + public static int getGLType(final Type type) { + switch (type) { + case TwoDimensional: + return GL.GL_TEXTURE_2D; + case OneDimensional: + return GL2GL3.GL_TEXTURE_1D; + case ThreeDimensional: + return GL2ES2.GL_TEXTURE_3D; + case CubeMap: + return GL.GL_TEXTURE_CUBE_MAP; + case Rectangle: + break; + default: + break; + } + throw new IllegalArgumentException("invalid texture type: " + type); + } + + public static int getGLCubeMapFace(final TextureCubeMap.Face face) { + switch (face) { + case PositiveX: + return GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X; + case NegativeX: + return GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; + case PositiveY: + return GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; + case NegativeY: + return GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; + case PositiveZ: + return GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; + case NegativeZ: + return GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + } + throw new IllegalArgumentException("invalid cubemap face: " + face); + } + + private static int getGLWrap(final WrapMode wrap, final ContextCapabilities caps) { + switch (wrap) { + case Repeat: + return GL.GL_REPEAT; + case MirroredRepeat: + if (caps.isTextureMirroredRepeatSupported()) { + return GL.GL_MIRRORED_REPEAT; + } else { + return GL.GL_REPEAT; + } + case MirrorClamp: + if (caps.isTextureMirrorClampSupported()) { + return GL2.GL_MIRROR_CLAMP_EXT; + } + // FALLS THROUGH + case Clamp: + return GL2.GL_CLAMP; + case MirrorBorderClamp: + if (caps.isTextureMirrorBorderClampSupported()) { + return GL2.GL_MIRROR_CLAMP_TO_BORDER_EXT; + } + // FALLS THROUGH + case BorderClamp: + if (caps.isTextureBorderClampSupported()) { + return GL2GL3.GL_CLAMP_TO_BORDER; + } else { + return GL2.GL_CLAMP; + } + case MirrorEdgeClamp: + if (caps.isTextureMirrorEdgeClampSupported()) { + return GL2.GL_MIRROR_CLAMP_TO_EDGE_EXT; + } + // FALLS THROUGH + case EdgeClamp: + if (caps.isTextureEdgeClampSupported()) { + return GL.GL_CLAMP_TO_EDGE; + } else { + return GL2.GL_CLAMP; + } + } + throw new IllegalArgumentException("invalid WrapMode type: " + wrap); + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglVertexProgramStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglVertexProgramStateUtil.java new file mode 100644 index 0000000..50258b8 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglVertexProgramStateUtil.java @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.logging.Logger; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.VertexProgramState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.VertexProgramStateRecord; +import com.ardor3d.util.geom.BufferUtils; + +public abstract class JoglVertexProgramStateUtil { + private static final Logger logger = Logger.getLogger(JoglVertexProgramStateUtil.class.getName()); + + /** + * Queries OpenGL for errors in the vertex program. Errors are logged as SEVERE, noting both the line number and + * message. + */ + private static void checkProgramError() { + final GL gl = GLU.getCurrentGL(); + + if (gl.glGetError() == GL.GL_INVALID_OPERATION) { + // retrieve the error position + final IntBuffer errorloc = BufferUtils.createIntBuffer(16); + gl.glGetIntegerv(GL2.GL_PROGRAM_ERROR_POSITION_ARB, errorloc); // TODO Check for integer + + logger.severe("Error " + gl.glGetString(GL2.GL_PROGRAM_ERROR_STRING_ARB) + " in vertex program on line " + + errorloc.get(0)); + } + } + + private static int create(final ByteBuffer program) { + final GL gl = GLU.getCurrentGL(); + + final IntBuffer buf = BufferUtils.createIntBuffer(1); + + gl.getGL2().glGenProgramsARB(buf.limit(), buf); + gl.getGL2().glBindProgramARB(GL2.GL_VERTEX_PROGRAM_ARB, buf.get(0)); + + final byte array[] = new byte[program.limit()]; + program.rewind(); + program.get(array); + gl.getGL2() + .glProgramStringARB(GL2.GL_VERTEX_PROGRAM_ARB, GL2.GL_PROGRAM_FORMAT_ASCII_ARB, array.length, new String( + array)); + + checkProgramError(); + + return buf.get(0); + } + + public static void apply(final JoglRenderer renderer, final VertexProgramState state) { + final GL gl = GLU.getCurrentGL(); + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + + if (caps.isVertexProgramSupported()) { + // ask for the current state record + final VertexProgramStateRecord record = (VertexProgramStateRecord) context + .getStateRecord(StateType.VertexProgram); + context.setCurrentState(StateType.VertexProgram, state); + + if (!record.isValid() || record.getReference() != state) { + record.setReference(state); + if (state.isEnabled()) { + // Vertex program not yet loaded + if (state._getProgramID() == -1) { + if (state.getProgramAsBuffer() != null) { + final int id = create(state.getProgramAsBuffer()); + state._setProgramID(id); + } else { + return; + } + } + + gl.glEnable(GL2.GL_VERTEX_PROGRAM_ARB); + gl.getGL2().glBindProgramARB(GL2.GL_VERTEX_PROGRAM_ARB, state._getProgramID()); + + // load environmental parameters... + for (int i = 0; i < VertexProgramState._getEnvParameters().length; i++) { + if (VertexProgramState._getEnvParameters()[i] != null) { + gl.getGL2().glProgramEnvParameter4fARB(GL2.GL_VERTEX_PROGRAM_ARB, i, VertexProgramState + ._getEnvParameters()[i][0], VertexProgramState._getEnvParameters()[i][1], + VertexProgramState._getEnvParameters()[i][2], VertexProgramState + ._getEnvParameters()[i][3]); + } + } + + // load local parameters... + if (state.isUsingParameters()) { + // no parameters are used + for (int i = 0; i < state._getParameters().length; i++) { + if (state._getParameters()[i] != null) { + gl.getGL2().glProgramLocalParameter4fARB(GL2.GL_VERTEX_PROGRAM_ARB, i, + state._getParameters()[i][0], state._getParameters()[i][1], state + ._getParameters()[i][2], state._getParameters()[i][3]); + } + } + } + + } else { + gl.glDisable(GL2.GL_VERTEX_PROGRAM_ARB); + } + } + + if (!record.isValid()) { + record.validate(); + } + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglWireframeStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglWireframeStateUtil.java new file mode 100644 index 0000000..bf8b026 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglWireframeStateUtil.java @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.WireframeState; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.WireframeStateRecord; + +public abstract class JoglWireframeStateUtil { + + public static void apply(final JoglRenderer renderer, final WireframeState state) { + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final WireframeStateRecord record = (WireframeStateRecord) context.getStateRecord(StateType.Wireframe); + context.setCurrentState(StateType.Wireframe, state); + + if (state.isEnabled()) { + renderer.setupLineParameters(state.getLineWidth(), 1, (short) 0xFFFF, state.isAntialiased()); + + switch (state.getFace()) { + case Front: + applyPolyMode(GL2GL3.GL_LINE, GL2GL3.GL_FILL, record); + break; + case Back: + applyPolyMode(GL2GL3.GL_FILL, GL2GL3.GL_LINE, record); + break; + case FrontAndBack: + default: + applyPolyMode(GL2GL3.GL_LINE, GL2GL3.GL_LINE, record); + break; + } + } else { + applyPolyMode(GL2GL3.GL_FILL, GL2GL3.GL_FILL, record); + } + + if (!record.isValid()) { + record.validate(); + } + } + + private static void applyPolyMode(final int frontMode, final int backMode, final WireframeStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (record.isValid()) { + if (frontMode == backMode && (record.frontMode != frontMode || record.backMode != backMode)) { + gl.getGL2GL3().glPolygonMode(GL.GL_FRONT_AND_BACK, frontMode); + record.frontMode = frontMode; + record.backMode = backMode; + } else if (frontMode != backMode) { + if (record.frontMode != frontMode) { + gl.getGL2GL3().glPolygonMode(GL.GL_FRONT, frontMode); + record.frontMode = frontMode; + } + if (record.backMode != backMode) { + gl.getGL2GL3().glPolygonMode(GL.GL_BACK, backMode); + record.backMode = backMode; + } + } + + } else { + if (frontMode == backMode) { + gl.getGL2GL3().glPolygonMode(GL.GL_FRONT_AND_BACK, frontMode); + } else if (frontMode != backMode) { + gl.getGL2GL3().glPolygonMode(GL.GL_FRONT, frontMode); + gl.getGL2GL3().glPolygonMode(GL.GL_BACK, backMode); + } + record.frontMode = frontMode; + record.backMode = backMode; + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglZBufferStateUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglZBufferStateUtil.java new file mode 100644 index 0000000..b806b02 --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/JoglZBufferStateUtil.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.RenderState; +import com.ardor3d.renderer.state.ZBufferState; +import com.ardor3d.renderer.state.record.ZBufferStateRecord; + +public abstract class JoglZBufferStateUtil { + + public static void apply(final JoglRenderer renderer, final ZBufferState state) { + // ask for the current state record + final RenderContext context = ContextManager.getCurrentContext(); + final ZBufferStateRecord record = (ZBufferStateRecord) context.getStateRecord(RenderState.StateType.ZBuffer); + context.setCurrentState(RenderState.StateType.ZBuffer, state); + + enableDepthTest(state.isEnabled(), record); + if (state.isEnabled()) { + int depthFunc = 0; + switch (state.getFunction()) { + case Never: + depthFunc = GL.GL_NEVER; + break; + case LessThan: + depthFunc = GL.GL_LESS; + break; + case EqualTo: + depthFunc = GL.GL_EQUAL; + break; + case LessThanOrEqualTo: + depthFunc = GL.GL_LEQUAL; + break; + case GreaterThan: + depthFunc = GL.GL_GREATER; + break; + case NotEqualTo: + depthFunc = GL.GL_NOTEQUAL; + break; + case GreaterThanOrEqualTo: + depthFunc = GL.GL_GEQUAL; + break; + case Always: + depthFunc = GL.GL_ALWAYS; + } + applyFunction(depthFunc, record); + } + + enableWrite(state.isWritable(), record); + + if (!record.isValid()) { + record.validate(); + } + } + + private static void enableDepthTest(final boolean enable, final ZBufferStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (enable && (!record.depthTest || !record.isValid())) { + gl.glEnable(GL.GL_DEPTH_TEST); + record.depthTest = true; + } else if (!enable && (record.depthTest || !record.isValid())) { + gl.glDisable(GL.GL_DEPTH_TEST); + record.depthTest = false; + } + } + + private static void applyFunction(final int depthFunc, final ZBufferStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (depthFunc != record.depthFunc || !record.isValid()) { + gl.glDepthFunc(depthFunc); + record.depthFunc = depthFunc; + } + } + + private static void enableWrite(final boolean enable, final ZBufferStateRecord record) { + final GL gl = GLU.getCurrentGL(); + + if (enable != record.writable || !record.isValid()) { + gl.glDepthMask(enable); + record.writable = enable; + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/shader/JoglShaderUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/shader/JoglShaderUtil.java new file mode 100644 index 0000000..96927ae --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/shader/JoglShaderUtil.java @@ -0,0 +1,418 @@ +/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl.shader; + +import java.util.logging.Logger; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.RenderContext; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.jogl.JoglRenderer; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.record.ShaderObjectsStateRecord; +import com.ardor3d.scene.state.jogl.util.JoglRendererUtil; +import com.ardor3d.util.shader.ShaderVariable; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat2; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat3; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat4; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloatArray; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt2; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt3; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt4; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableIntArray; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix2; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix3; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix4; +import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix4Array; +import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerByte; +import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerFloat; +import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerFloatMatrix; +import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerInt; +import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerShort; + +/** Utility class for updating shadervariables(uniforms and attributes) */ +public abstract class JoglShaderUtil { + private static final Logger logger = Logger.getLogger(JoglShaderUtil.class.getName()); + + /** + * Updates a uniform shadervariable. + * + * @param shaderVariable + * variable to update + */ + public static void updateShaderUniform(final ShaderVariable shaderVariable) { + if (!shaderVariable.hasData()) { + throw new IllegalArgumentException("shaderVariable has no data: " + shaderVariable.name + " type: " + + shaderVariable.getClass().getName()); + } + + if (shaderVariable instanceof ShaderVariableInt) { + updateShaderUniform((ShaderVariableInt) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableInt2) { + updateShaderUniform((ShaderVariableInt2) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableInt3) { + updateShaderUniform((ShaderVariableInt3) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableInt4) { + updateShaderUniform((ShaderVariableInt4) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableIntArray) { + updateShaderUniform((ShaderVariableIntArray) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableFloat) { + updateShaderUniform((ShaderVariableFloat) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableFloat2) { + updateShaderUniform((ShaderVariableFloat2) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableFloat3) { + updateShaderUniform((ShaderVariableFloat3) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableFloat4) { + updateShaderUniform((ShaderVariableFloat4) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableFloatArray) { + updateShaderUniform((ShaderVariableFloatArray) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableMatrix2) { + updateShaderUniform((ShaderVariableMatrix2) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableMatrix3) { + updateShaderUniform((ShaderVariableMatrix3) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableMatrix4) { + updateShaderUniform((ShaderVariableMatrix4) shaderVariable); + } else if (shaderVariable instanceof ShaderVariableMatrix4Array) { + updateShaderUniform((ShaderVariableMatrix4Array) shaderVariable); + } else { + logger.warning("updateShaderUniform: Unknown shaderVariable type!"); + } + } + + /** + * Update variableID for uniform shadervariable if needed. + * + * @param variable + * shadervaribale to update ID on + * @param programID + * shader program context ID + */ + public static void updateUniformLocation(final ShaderVariable variable, final int programID) { + final GL gl = GLU.getCurrentGL(); + + if (variable.variableID == -1) { + variable.variableID = gl.getGL2GL3().glGetUniformLocation(programID, variable.name); // TODO Check variable.name + + if (variable.variableID == -1 && !variable.errorLogged) { + logger.severe("Shader uniform [" + variable.name + "] could not be located in shader"); + variable.errorLogged = true; + } + } + } + + private static void updateShaderUniform(final ShaderVariableInt shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glUniform1i(shaderUniform.variableID, shaderUniform.value1); + } + + private static void updateShaderUniform(final ShaderVariableInt2 shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glUniform2i(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2); + } + + private static void updateShaderUniform(final ShaderVariableInt3 shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glUniform3i(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2, shaderUniform.value3); + } + + private static void updateShaderUniform(final ShaderVariableInt4 shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glUniform4i(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2, shaderUniform.value3, + shaderUniform.value4); + } + + private static void updateShaderUniform(final ShaderVariableIntArray shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + switch (shaderUniform.size) { + case 1: + gl.getGL2GL3().glUniform1iv(shaderUniform.variableID, shaderUniform.value.remaining(), shaderUniform.value); + break; + case 2: + gl.getGL2GL3().glUniform2iv(shaderUniform.variableID, shaderUniform.value.remaining(), shaderUniform.value); + break; + case 3: + gl.getGL2GL3().glUniform3iv(shaderUniform.variableID, shaderUniform.value.remaining(), shaderUniform.value); + break; + case 4: + gl.getGL2GL3().glUniform4iv(shaderUniform.variableID, shaderUniform.value.remaining(), shaderUniform.value); + break; + default: + throw new IllegalArgumentException("Wrong size: " + shaderUniform.size); + } + } + + private static void updateShaderUniform(final ShaderVariableFloat shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glUniform1f(shaderUniform.variableID, shaderUniform.value1); + } + + private static void updateShaderUniform(final ShaderVariableFloat2 shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glUniform2f(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2); + } + + private static void updateShaderUniform(final ShaderVariableFloat3 shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glUniform3f(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2, shaderUniform.value3); + } + + private static void updateShaderUniform(final ShaderVariableFloat4 shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + gl.getGL2GL3().glUniform4f(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2, shaderUniform.value3, + shaderUniform.value4); + } + + private static void updateShaderUniform(final ShaderVariableFloatArray shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + switch (shaderUniform.size) { + case 1: + gl.getGL2GL3().glUniform1fv(shaderUniform.variableID, shaderUniform.value.remaining(), shaderUniform.value); + break; + case 2: + gl.getGL2GL3().glUniform2fv(shaderUniform.variableID, shaderUniform.value.remaining(), shaderUniform.value); + break; + case 3: + gl.getGL2GL3().glUniform3fv(shaderUniform.variableID, shaderUniform.value.remaining(), shaderUniform.value); + break; + case 4: + gl.getGL2GL3().glUniform4fv(shaderUniform.variableID, shaderUniform.value.remaining(), shaderUniform.value); + break; + default: + throw new IllegalArgumentException("Wrong size: " + shaderUniform.size); + } + } + + private static void updateShaderUniform(final ShaderVariableMatrix2 shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + shaderUniform.matrixBuffer.rewind(); + gl.getGL2GL3().glUniformMatrix2fv(shaderUniform.variableID, 1, shaderUniform.rowMajor, shaderUniform.matrixBuffer); + } + + private static void updateShaderUniform(final ShaderVariableMatrix3 shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + shaderUniform.matrixBuffer.rewind(); + gl.getGL2GL3().glUniformMatrix3fv(shaderUniform.variableID, 1, shaderUniform.rowMajor, shaderUniform.matrixBuffer); + } + + private static void updateShaderUniform(final ShaderVariableMatrix4 shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + shaderUniform.matrixBuffer.rewind(); + gl.getGL2GL3().glUniformMatrix4fv(shaderUniform.variableID, 1, shaderUniform.rowMajor, shaderUniform.matrixBuffer); + } + + private static void updateShaderUniform(final ShaderVariableMatrix4Array shaderUniform) { + final GL gl = GLU.getCurrentGL(); + + shaderUniform.matrixBuffer.rewind(); + // count == number of matrices we are sending, or iotw, limit / 16 + gl.getGL2GL3().glUniformMatrix4fv(shaderUniform.variableID, shaderUniform.matrixBuffer.limit() >> 4, + shaderUniform.rowMajor, shaderUniform.matrixBuffer); + } + + /** + * Update variableID for attribute shadervariable if needed. + * + * @param variable + * shadervaribale to update ID on + * @param programID + * shader program context ID + */ + public static void updateAttributeLocation(final ShaderVariable variable, final int programID) { + final GL gl = GLU.getCurrentGL(); + + if (variable.variableID == -1) { + variable.variableID = gl.getGL2GL3().glGetAttribLocation(programID, variable.name); // TODO Check variable.name + + if (variable.variableID == -1 && !variable.errorLogged) { + logger.severe("Shader attribute [" + variable.name + "] could not be located in shader"); + variable.errorLogged = true; + } + } + } + + /** + * Updates an vertex attribute pointer. + * + * @param renderer + * the current renderer + * @param shaderVariable + * variable to update + * @param useVBO + * if true, we'll use VBO for the attributes, if false we'll use arrays. + */ + public static void updateShaderAttribute(final Renderer renderer, final ShaderVariable shaderVariable, + final boolean useVBO) { + if (shaderVariable.variableID == -1) { + // attribute is not bound, or was not found in shader. + return; + } + + if (!shaderVariable.hasData()) { + throw new IllegalArgumentException("shaderVariable has no data: " + shaderVariable.name + " type: " + + shaderVariable.getClass().getName()); + } + + final RenderContext context = ContextManager.getCurrentContext(); + final ContextCapabilities caps = context.getCapabilities(); + if (caps.isVBOSupported() && !useVBO) { + renderer.unbindVBO(); + } + + final ShaderObjectsStateRecord record = (ShaderObjectsStateRecord) context.getStateRecord(StateType.GLSLShader); + + if (shaderVariable instanceof ShaderVariablePointerFloat) { + updateShaderAttribute((ShaderVariablePointerFloat) shaderVariable, record, useVBO); + } else if (shaderVariable instanceof ShaderVariablePointerFloatMatrix) { + updateShaderAttribute((ShaderVariablePointerFloatMatrix) shaderVariable, record, useVBO); + } else if (shaderVariable instanceof ShaderVariablePointerByte) { + updateShaderAttribute((ShaderVariablePointerByte) shaderVariable, record, useVBO); + } else if (shaderVariable instanceof ShaderVariablePointerInt) { + updateShaderAttribute((ShaderVariablePointerInt) shaderVariable, record, useVBO); + } else if (shaderVariable instanceof ShaderVariablePointerShort) { + updateShaderAttribute((ShaderVariablePointerShort) shaderVariable, record, useVBO); + } else { + logger.warning("updateShaderAttribute: Unknown shaderVariable type!"); + return; + } + } + + public static void useShaderProgram(final int id, final ShaderObjectsStateRecord record) { + if (record.shaderId != id) { + GLU.getCurrentGL().getGL2().glUseProgramObjectARB(id); + record.shaderId = id; + } + } + + private static void enableVertexAttribute(final ShaderVariable var, final ShaderObjectsStateRecord record) { + if (!record.enabledAttributes.contains(var)) { + if (var.getSize() == 1) { + GLU.getCurrentGL().getGL2GL3().glEnableVertexAttribArray(var.variableID); + } else { + final GL gl = GLU.getCurrentGL(); + for (int i = 0, max = var.getSize(); i < max; i++) { + gl.getGL2GL3().glEnableVertexAttribArray(var.variableID + i); + } + } + record.enabledAttributes.add(var); + } + } + + private static void updateShaderAttribute(final ShaderVariablePointerFloat variable, + final ShaderObjectsStateRecord record, final boolean useVBO) { + enableVertexAttribute(variable, record); + if (useVBO) { + final RenderContext context = ContextManager.getCurrentContext(); + final int vboId = JoglRenderer.setupVBO(variable.data, context); + JoglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); + GLU.getCurrentGL().getGL2GL3().glVertexAttribPointer(variable.variableID, variable.size, GL.GL_FLOAT, + variable.normalized, variable.stride, 0); + } else { + variable.data.getBuffer().rewind(); + GLU.getCurrentGL().getGL2GL3().glVertexAttribPointer(variable.variableID, variable.size, GL.GL_FLOAT, + variable.normalized, variable.stride, variable.data.getBuffer()); + } + } + + private static void updateShaderAttribute(final ShaderVariablePointerFloatMatrix variable, + final ShaderObjectsStateRecord record, final boolean useVBO) { + final GL gl = GLU.getCurrentGL(); + final int size = variable.size; + final int length = variable.data.getBuffer().capacity() / size; + final RenderContext context = ContextManager.getCurrentContext(); + int pos = 0; + enableVertexAttribute(variable, record); + for (int i = 0; i < size; i++) { + pos = (i * length); + if (useVBO) { + final int vboId = JoglRenderer.setupVBO(variable.data, context); + JoglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); + gl.getGL2GL3().glVertexAttribPointer(variable.variableID + i, size, GL.GL_FLOAT, variable.normalized, 0, pos); + } else { + variable.data.getBuffer().limit(pos + length - 1); + variable.data.getBuffer().position(pos); + gl.getGL2GL3().glVertexAttribPointer(variable.variableID + i, size, GL.GL_FLOAT, variable.normalized, 0, + variable.data.getBuffer()); + } + } + } + + private static void updateShaderAttribute(final ShaderVariablePointerByte variable, + final ShaderObjectsStateRecord record, final boolean useVBO) { + enableVertexAttribute(variable, record); + if (useVBO) { + final RenderContext context = ContextManager.getCurrentContext(); + final int vboId = JoglRenderer.setupVBO(variable.data, context); + JoglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); + GLU.getCurrentGL().getGL2GL3().glVertexAttribPointer(variable.variableID, variable.size, + variable.unsigned ? GL.GL_UNSIGNED_BYTE : GL.GL_BYTE, variable.normalized, variable.stride, 0); + } else { + variable.data.getBuffer().rewind(); + GLU.getCurrentGL().getGL2GL3().glVertexAttribPointer(variable.variableID, variable.size, + variable.unsigned ? GL.GL_UNSIGNED_BYTE : GL.GL_BYTE, variable.normalized, variable.stride, + variable.data.getBuffer()); + } + } + + private static void updateShaderAttribute(final ShaderVariablePointerInt variable, + final ShaderObjectsStateRecord record, final boolean useVBO) { + enableVertexAttribute(variable, record); + if (useVBO) { + final RenderContext context = ContextManager.getCurrentContext(); + final int vboId = JoglRenderer.setupVBO(variable.data, context); + JoglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); + GLU.getCurrentGL().getGL2GL3().glVertexAttribPointer(variable.variableID, variable.size, + variable.unsigned ? GL.GL_UNSIGNED_INT : GL2ES2.GL_INT, variable.normalized, variable.stride, 0); + } else { + variable.data.getBuffer().rewind(); + GLU.getCurrentGL().getGL2GL3().glVertexAttribPointer(variable.variableID, variable.size, + variable.unsigned ? GL.GL_UNSIGNED_INT : GL2ES2.GL_INT, variable.normalized, variable.stride, + variable.data.getBuffer()); + } + } + + private static void updateShaderAttribute(final ShaderVariablePointerShort variable, + final ShaderObjectsStateRecord record, final boolean useVBO) { + enableVertexAttribute(variable, record); + if (useVBO) { + final RenderContext context = ContextManager.getCurrentContext(); + final int vboId = JoglRenderer.setupVBO(variable.data, context); + JoglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); + GLU.getCurrentGL().getGL2GL3().glVertexAttribPointer(variable.variableID, variable.size, + variable.unsigned ? GL.GL_UNSIGNED_SHORT : GL.GL_SHORT, variable.normalized, variable.stride, 0); + } else { + variable.data.getBuffer().rewind(); + GLU.getCurrentGL().getGL2GL3().glVertexAttribPointer(variable.variableID, variable.size, + variable.unsigned ? GL.GL_UNSIGNED_SHORT : GL.GL_SHORT, variable.normalized, variable.stride, + variable.data.getBuffer()); + } + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/util/JoglRendererUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/util/JoglRendererUtil.java new file mode 100644 index 0000000..88f006e --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/util/JoglRendererUtil.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl.util; + +import java.util.Stack; + +import javax.media.opengl.GL; +import javax.media.opengl.glu.GLU; + +import com.ardor3d.math.Rectangle2; +import com.ardor3d.math.type.ReadOnlyRectangle2; +import com.ardor3d.renderer.state.record.RendererRecord; + +public abstract class JoglRendererUtil { + + public static void switchMode(final RendererRecord rendRecord, final int mode) { + final GL gl = GLU.getCurrentGL(); + + if (!rendRecord.isMatrixValid() || rendRecord.getMatrixMode() != mode) { + gl.getGL2().glMatrixMode(mode); + rendRecord.setMatrixMode(mode); + rendRecord.setMatrixValid(true); + } + } + + public static void setBoundVBO(final RendererRecord rendRecord, final int id) { + final GL gl = GLU.getCurrentGL(); + + if (!rendRecord.isVboValid() || rendRecord.getCurrentVboId() != id) { + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, id); + rendRecord.setCurrentVboId(id); + rendRecord.setVboValid(true); + } + } + + public static void setBoundElementVBO(final RendererRecord rendRecord, final int id) { + final GL gl = GLU.getCurrentGL(); + + if (!rendRecord.isElementVboValid() || rendRecord.getCurrentElementVboId() != id) { + gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, id); + rendRecord.setCurrentElementVboId(id); + rendRecord.setElementVboValid(true); + } + } + + public static void applyScissors(final RendererRecord rendRecord) { + final GL gl = GLU.getCurrentGL(); + final Stack<ReadOnlyRectangle2> clips = rendRecord.getScissorClips(); + + if (clips.size() > 0) { + final Rectangle2 init = Rectangle2.fetchTempInstance(); + init.set(-1, -1, -1, -1); + ReadOnlyRectangle2 r; + boolean first = true; + for (int i = clips.size(); --i >= 0;) { + r = clips.get(i); + + if (r == null) { + break; + } + if (first) { + init.set(r); + first = false; + } else { + init.intersect(r, init); + } + if (init.getWidth() <= 0 || init.getHeight() <= 0) { + init.setWidth(0); + init.setHeight(0); + break; + } + } + + if (init.getWidth() == -1) { + setClippingEnabled(rendRecord, false); + } else { + setClippingEnabled(rendRecord, true); + gl.glScissor(init.getX(), init.getY(), init.getWidth(), init.getHeight()); + } + Rectangle2.releaseTempInstance(init); + } else { + // no clips, so disable + setClippingEnabled(rendRecord, false); + } + } + + public static void setClippingEnabled(final RendererRecord rendRecord, final boolean enabled) { + final GL gl = GLU.getCurrentGL(); + + if (enabled && (!rendRecord.isClippingTestValid() || !rendRecord.isClippingTestEnabled())) { + gl.glEnable(GL.GL_SCISSOR_TEST); + rendRecord.setClippingTestEnabled(true); + } else if (!enabled && (!rendRecord.isClippingTestValid() || rendRecord.isClippingTestEnabled())) { + gl.glDisable(GL.GL_SCISSOR_TEST); + rendRecord.setClippingTestEnabled(false); + } + rendRecord.setClippingTestValid(true); + } +} diff --git a/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/util/JoglTextureUtil.java b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/util/JoglTextureUtil.java new file mode 100644 index 0000000..2e9ab9e --- /dev/null +++ b/ardor3d-jogl/src/main/java/com/ardor3d/scene/state/jogl/util/JoglTextureUtil.java @@ -0,0 +1,611 @@ +/** + * Copyright (c) 2008-2010 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.scene.state.jogl.util; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; + +import com.ardor3d.image.ImageDataFormat; +import com.ardor3d.image.PixelDataType; +import com.ardor3d.image.Texture.ApplyMode; +import com.ardor3d.image.Texture.CombinerFunctionAlpha; +import com.ardor3d.image.Texture.CombinerFunctionRGB; +import com.ardor3d.image.Texture.CombinerOperandAlpha; +import com.ardor3d.image.Texture.CombinerOperandRGB; +import com.ardor3d.image.Texture.CombinerSource; +import com.ardor3d.image.Texture.DepthTextureCompareFunc; +import com.ardor3d.image.Texture.DepthTextureCompareMode; +import com.ardor3d.image.Texture.DepthTextureMode; +import com.ardor3d.image.Texture.MagnificationFilter; +import com.ardor3d.image.Texture.MinificationFilter; +import com.ardor3d.image.TextureStoreFormat; +import com.ardor3d.renderer.state.TextureState.CorrectionType; + +public abstract class JoglTextureUtil { + + public static int getGLInternalFormat(final TextureStoreFormat format) { + switch (format) { + // first some frequently used formats + case RGBA8: + return GL.GL_RGBA8; + case RGB8: + return GL.GL_RGB8; + case Alpha8: + return GL2.GL_ALPHA8; + case CompressedRGBA: + return GL2GL3.GL_COMPRESSED_RGBA; + case CompressedRGB: + return GL2GL3.GL_COMPRESSED_RGB; + case CompressedRG: + return GL2GL3.GL_COMPRESSED_RG; + case CompressedRed: + return GL2GL3.GL_COMPRESSED_RED; + case CompressedLuminance: + return GL2.GL_COMPRESSED_LUMINANCE; + case CompressedLuminanceAlpha: + return GL2.GL_COMPRESSED_LUMINANCE_ALPHA; + case NativeDXT1: + return GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + case NativeDXT1A: + return GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case NativeDXT3: + return GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + case NativeDXT5: + return GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + case NativeLATC_L: + return GL2.GL_COMPRESSED_LUMINANCE_LATC1_EXT; + case NativeLATC_LA: + return GL2.GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT; + + // The rest... + case Alpha4: + return GL2.GL_ALPHA4; + case Alpha12: + return GL2.GL_ALPHA12; + case Alpha16: + return GL2.GL_ALPHA16; + case Luminance4: + return GL2.GL_LUMINANCE4; + case Luminance8: + return GL2.GL_LUMINANCE8; + case Luminance12: + return GL2.GL_LUMINANCE12; + case Luminance16: + return GL2.GL_LUMINANCE16; + case Intensity4: + return GL2.GL_INTENSITY4; + case Intensity8: + return GL2.GL_INTENSITY8; + case Intensity12: + return GL2.GL_INTENSITY12; + case Intensity16: + return GL2.GL_INTENSITY16; + case Luminance4Alpha4: + return GL2.GL_LUMINANCE4_ALPHA4; + case Luminance6Alpha2: + return GL2.GL_LUMINANCE6_ALPHA2; + case Luminance8Alpha8: + return GL2.GL_LUMINANCE8_ALPHA8; + case Luminance12Alpha4: + return GL2.GL_LUMINANCE12_ALPHA4; + case Luminance12Alpha12: + return GL2.GL_LUMINANCE12_ALPHA12; + case Luminance16Alpha16: + return GL2.GL_LUMINANCE16_ALPHA16; + case R3G3B2: + return GL2GL3.GL_R3_G3_B2; + case RGB4: + return GL2GL3.GL_RGB4; + case RGB5: + return GL2GL3.GL_RGB5; + case RGB10: + return GL.GL_RGB10; + case RGB12: + return GL2GL3.GL_RGB12; + case RGB16: + return GL2GL3.GL_RGB16; + case RGBA2: + return GL2GL3.GL_RGBA2; + case RGBA4: + return GL.GL_RGBA4; + case RGB5A1: + return GL.GL_RGB5_A1; + case RGB10A2: + return GL.GL_RGB10_A2; + case RGBA12: + return GL2GL3.GL_RGBA12; + case RGBA16: + return GL2GL3.GL_RGBA16; + case Depth: + return GL2ES2.GL_DEPTH_COMPONENT; + case Depth16: + return GL.GL_DEPTH_COMPONENT16; + case Depth24: + return GL.GL_DEPTH_COMPONENT24; + case Depth32: + return GL.GL_DEPTH_COMPONENT32; + case Depth32F: + return GL2GL3.GL_DEPTH_COMPONENT32F; + case RGB16F: + return GL2ES2.GL_RGB16F; + case RGB32F: + return GL.GL_RGB32F; + case RGBA16F: + return GL2ES2.GL_RGBA16F; + case RGBA32F: + return GL.GL_RGBA32F; + case Alpha16F: + return GL2.GL_ALPHA16F; + case Alpha32F: + return GL2.GL_ALPHA32F; + case Luminance16F: + return GL2.GL_LUMINANCE16F; + case Luminance32F: + return GL2.GL_LUMINANCE32F; + case LuminanceAlpha16F: + return GL2.GL_LUMINANCE_ALPHA16F; + case LuminanceAlpha32F: + return GL2.GL_LUMINANCE_ALPHA32F; + case Intensity16F: + return GL2.GL_INTENSITY16F; + case Intensity32F: + return GL2.GL_INTENSITY32F; + case R8: + return GL2ES2.GL_R8; + case R16: + return GL2GL3.GL_R16; + case RG8: + return GL2ES2.GL_RG8; + case RG16: + return GL2GL3.GL_RG16; + case R16F: + return GL2ES2.GL_R16F; + case R32F: + return GL2GL3.GL_R32F; + case RG16F: + return GL2ES2.GL_RG16F; + case RG32F: + return GL2GL3.GL_RG32F; + case R8I: + return GL2GL3.GL_R8I; + case R8UI: + return GL2GL3.GL_R8UI; + case R16I: + return GL2GL3.GL_R16I; + case R16UI: + return GL2GL3.GL_R16UI; + case R32I: + return GL2GL3.GL_R32I; + case R32UI: + return GL2GL3.GL_R32UI; + case RG8I: + return GL2GL3.GL_RG8I; + case RG8UI: + return GL2GL3.GL_RG8UI; + case RG16I: + return GL2GL3.GL_RG16I; + case RG16UI: + return GL2GL3.GL_RG16UI; + case RG32I: + return GL2GL3.GL_RG32I; + case RG32UI: + return GL2GL3.GL_RG32UI; + default: + break; + } + throw new IllegalArgumentException("Incorrect format set: " + format); + } + + public static int getGLPixelDataType(final PixelDataType type) { + switch (type) { + case Byte: + return GL.GL_BYTE; + case Float: + return GL.GL_FLOAT; + case HalfFloat: + return GL.GL_HALF_FLOAT; + case Short: + return GL.GL_SHORT; + case UnsignedShort: + return GL.GL_UNSIGNED_SHORT; + case Int: + return GL2ES2.GL_INT; + case UnsignedInt: + return GL.GL_UNSIGNED_INT; + case UnsignedByte: + return GL.GL_UNSIGNED_BYTE; + default: + throw new Error("Unhandled type: " + type); + } + } + + public static int getGLPixelFormat(final ImageDataFormat format) { + switch (format) { + case RGBA: + return GL.GL_RGBA; + case RGB: + return GL.GL_RGB; + case Alpha: + return GL.GL_ALPHA; + case Luminance: + return GL.GL_LUMINANCE; + case Intensity: + return GL2.GL_INTENSITY; + case LuminanceAlpha: + return GL.GL_LUMINANCE_ALPHA; + case Depth: + return GL2ES2.GL_DEPTH_COMPONENT; + case BGR: + return GL2GL3.GL_BGR; + case BGRA: + return GL.GL_BGRA; + case Red: + return GL2ES2.GL_RED; + case Blue: + return GL2GL3.GL_BLUE; + case Green: + return GL2GL3.GL_GREEN; + case ColorIndex: + return GL2.GL_COLOR_INDEX; + case StencilIndex: + return GL2ES2.GL_STENCIL_INDEX; + case PrecompressedDXT1: + break; + case PrecompressedDXT1A: + break; + case PrecompressedDXT3: + break; + case PrecompressedDXT5: + break; + case PrecompressedLATC_L: + break; + case PrecompressedLATC_LA: + break; + case RG: + break; + default: + break; + } + throw new IllegalArgumentException("Incorrect format set: " + format); + } + + public static int getGLPixelFormatFromStoreFormat(final TextureStoreFormat format) { + switch (format) { + case RGBA2: + case RGBA4: + case RGBA8: + case RGB5A1: + case RGB10A2: + case RGBA12: + case RGBA16: + case CompressedRGBA: + case NativeDXT1A: + case NativeDXT3: + case NativeDXT5: + case RGBA16F: + case RGBA32F: + return GL.GL_RGBA; + case R3G3B2: + case RGB4: + case RGB5: + case RGB8: + case RGB10: + case RGB12: + case RGB16: + case CompressedRGB: + case NativeDXT1: + case RGB16F: + case RGB32F: + return GL.GL_RGB; + case Alpha4: + case Alpha8: + case Alpha12: + case Alpha16: + case Alpha16F: + case Alpha32F: + return GL.GL_ALPHA; + case Luminance4: + case Luminance8: + case Luminance12: + case Luminance16: + case Luminance16F: + case Luminance32F: + case CompressedLuminance: + case NativeLATC_L: + return GL.GL_LUMINANCE; + case Intensity4: + case Intensity8: + case Intensity12: + case Intensity16: + case Intensity16F: + case Intensity32F: + return GL2.GL_INTENSITY; + case Luminance4Alpha4: + case Luminance6Alpha2: + case Luminance8Alpha8: + case Luminance12Alpha4: + case Luminance12Alpha12: + case Luminance16Alpha16: + case LuminanceAlpha16F: + case LuminanceAlpha32F: + case CompressedLuminanceAlpha: + case NativeLATC_LA: + return GL.GL_LUMINANCE_ALPHA; + case Depth: + case Depth16: + case Depth24: + case Depth32: + case Depth32F: + return GL2ES2.GL_DEPTH_COMPONENT; + case R8: + case R16: + case R16F: + case R32F: + case R8I: + case R8UI: + case R16I: + case R16UI: + case R32I: + case R32UI: + case CompressedRed: + return GL2ES2.GL_RED; + case RG8: + case RG16: + case RG16F: + case RG32F: + case RG8I: + case RG8UI: + case RG16I: + case RG16UI: + case RG32I: + case RG32UI: + case CompressedRG: + return GL2ES2.GL_RG; + default: + break; + } + throw new IllegalArgumentException("Incorrect format set: " + format); + } + + public static int getGLDepthTextureMode(final DepthTextureMode mode) { + switch (mode) { + case Alpha: + return GL.GL_ALPHA; + case Luminance: + return GL.GL_LUMINANCE; + case Intensity: + default: + return GL2.GL_INTENSITY; + } + } + + public static int getGLDepthTextureCompareMode(final DepthTextureCompareMode mode) { + switch (mode) { + case RtoTexture: + return GL2.GL_COMPARE_R_TO_TEXTURE; + case None: + default: + return GL.GL_NONE; + } + } + + public static int getGLDepthTextureCompareFunc(final DepthTextureCompareFunc func) { + switch (func) { + case GreaterThanEqual: + return GL.GL_GEQUAL; + case LessThanEqual: + default: + return GL.GL_LEQUAL; + } + } + + public static int getGLMagFilter(final MagnificationFilter magFilter) { + switch (magFilter) { + case Bilinear: + return GL.GL_LINEAR; + case NearestNeighbor: + default: + return GL.GL_NEAREST; + + } + } + + public static int getGLMinFilter(final MinificationFilter filter) { + switch (filter) { + case BilinearNoMipMaps: + return GL.GL_LINEAR; + case Trilinear: + return GL.GL_LINEAR_MIPMAP_LINEAR; + case BilinearNearestMipMap: + return GL.GL_LINEAR_MIPMAP_NEAREST; + case NearestNeighborNoMipMaps: + return GL.GL_NEAREST; + case NearestNeighborNearestMipMap: + return GL.GL_NEAREST_MIPMAP_NEAREST; + case NearestNeighborLinearMipMap: + return GL.GL_NEAREST_MIPMAP_LINEAR; + } + throw new IllegalArgumentException("invalid MinificationFilter type: " + filter); + } + + public static int getGLEnvMode(final ApplyMode apply) { + switch (apply) { + case Replace: + return GL.GL_REPLACE; + case Blend: + return GL.GL_BLEND; + case Combine: + return GL2ES1.GL_COMBINE; + case Decal: + return GL2ES1.GL_DECAL; + case Add: + return GL2ES1.GL_ADD; + case Modulate: + return GL2ES1.GL_MODULATE; + } + throw new IllegalArgumentException("invalid ApplyMode type: " + apply); + } + + public static int getPerspHint(final CorrectionType type) { + switch (type) { + case Perspective: + return GL.GL_NICEST; + case Affine: + return GL.GL_FASTEST; + } + throw new IllegalArgumentException("unknown correction type: " + type); + } + + public static int getGLCombineOpRGB(final CombinerOperandRGB operand) { + switch (operand) { + case SourceColor: + return GL.GL_SRC_COLOR; + case OneMinusSourceColor: + return GL.GL_ONE_MINUS_SRC_COLOR; + case SourceAlpha: + return GL.GL_SRC_ALPHA; + case OneMinusSourceAlpha: + return GL.GL_ONE_MINUS_SRC_ALPHA; + } + throw new IllegalArgumentException("invalid CombinerOperandRGB type: " + operand); + } + + public static int getGLCombineOpAlpha(final CombinerOperandAlpha operand) { + switch (operand) { + case SourceAlpha: + return GL.GL_SRC_ALPHA; + case OneMinusSourceAlpha: + return GL.GL_ONE_MINUS_SRC_ALPHA; + } + throw new IllegalArgumentException("invalid CombinerOperandAlpha type: " + operand); + } + + public static int getGLCombineSrc(final CombinerSource combineSrc) { + switch (combineSrc) { + case CurrentTexture: + return GL.GL_TEXTURE; + case PrimaryColor: + return GL2ES1.GL_PRIMARY_COLOR; + case Constant: + return GL2ES1.GL_CONSTANT; + case Previous: + return GL2ES1.GL_PREVIOUS; + case TextureUnit0: + return GL.GL_TEXTURE0; + case TextureUnit1: + return GL.GL_TEXTURE1; + case TextureUnit2: + return GL.GL_TEXTURE2; + case TextureUnit3: + return GL.GL_TEXTURE3; + case TextureUnit4: + return GL.GL_TEXTURE4; + case TextureUnit5: + return GL.GL_TEXTURE5; + case TextureUnit6: + return GL.GL_TEXTURE6; + case TextureUnit7: + return GL.GL_TEXTURE7; + case TextureUnit8: + return GL.GL_TEXTURE8; + case TextureUnit9: + return GL.GL_TEXTURE9; + case TextureUnit10: + return GL.GL_TEXTURE10; + case TextureUnit11: + return GL.GL_TEXTURE11; + case TextureUnit12: + return GL.GL_TEXTURE12; + case TextureUnit13: + return GL.GL_TEXTURE13; + case TextureUnit14: + return GL.GL_TEXTURE14; + case TextureUnit15: + return GL.GL_TEXTURE15; + case TextureUnit16: + return GL.GL_TEXTURE16; + case TextureUnit17: + return GL.GL_TEXTURE17; + case TextureUnit18: + return GL.GL_TEXTURE18; + case TextureUnit19: + return GL.GL_TEXTURE19; + case TextureUnit20: + return GL.GL_TEXTURE20; + case TextureUnit21: + return GL.GL_TEXTURE21; + case TextureUnit22: + return GL.GL_TEXTURE22; + case TextureUnit23: + return GL.GL_TEXTURE23; + case TextureUnit24: + return GL.GL_TEXTURE24; + case TextureUnit25: + return GL.GL_TEXTURE25; + case TextureUnit26: + return GL.GL_TEXTURE26; + case TextureUnit27: + return GL.GL_TEXTURE27; + case TextureUnit28: + return GL.GL_TEXTURE28; + case TextureUnit29: + return GL.GL_TEXTURE29; + case TextureUnit30: + return GL.GL_TEXTURE30; + case TextureUnit31: + return GL.GL_TEXTURE31; + } + throw new IllegalArgumentException("invalid CombinerSource type: " + combineSrc); + } + + public static int getGLCombineFuncAlpha(final CombinerFunctionAlpha combineFunc) { + switch (combineFunc) { + case Modulate: + return GL2ES1.GL_MODULATE; + case Replace: + return GL.GL_REPLACE; + case Add: + return GL2ES1.GL_ADD; + case AddSigned: + return GL2ES1.GL_ADD_SIGNED; + case Subtract: + return GL2ES1.GL_SUBTRACT; + case Interpolate: + return GL2ES1.GL_INTERPOLATE; + } + throw new IllegalArgumentException("invalid CombinerFunctionAlpha type: " + combineFunc); + } + + public static int getGLCombineFuncRGB(final CombinerFunctionRGB combineFunc) { + switch (combineFunc) { + case Modulate: + return GL2ES1.GL_MODULATE; + case Replace: + return GL.GL_REPLACE; + case Add: + return GL2ES1.GL_ADD; + case AddSigned: + return GL2ES1.GL_ADD_SIGNED; + case Subtract: + return GL2ES1.GL_SUBTRACT; + case Interpolate: + return GL2ES1.GL_INTERPOLATE; + case Dot3RGB: + return GL2ES1.GL_DOT3_RGB; + case Dot3RGBA: + return GL2ES1.GL_DOT3_RGBA; + } + throw new IllegalArgumentException("invalid CombinerFunctionRGB type: " + combineFunc); + } +} |