diff --git a/.classpath b/.classpath index a7d40d52..61c34d64 100644 --- a/.classpath +++ b/.classpath @@ -2,12 +2,13 @@ - - - - + + + + + diff --git a/.gitignore b/.gitignore index 33e0312f..6e756686 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ zamples misc/windowsexecutablestub/Debug misc/windowsexecutablestub/Release *.sdf -*.suo \ No newline at end of file +*.suo +linux/ diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 8579988f..f6904a94 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -5,9 +5,10 @@ org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -92,8 +93,7 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disa org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.7 -org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.compiler.source=1.8 org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field=1585 org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field.count_dependent=1585|-1|1585 org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=1585 @@ -109,323 +109,44 @@ org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter.count_depe org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type=1585 org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type.count_dependent=1585|-1|1585 org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type_declaration=569 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression.count_dependent=16|5|80 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation.count_dependent=16|-1|16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant.count_dependent=16|-1|16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call.count_dependent=16|5|80 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation.count_dependent=16|5|80 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression.count_dependent=16|4|80 -org.eclipse.jdt.core.formatter.alignment_for_assignment=16 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 org.eclipse.jdt.core.formatter.alignment_for_binary_expression.count_dependent=16|-1|16 org.eclipse.jdt.core.formatter.alignment_for_cascading_method_invocation_with_arguments=16 org.eclipse.jdt.core.formatter.alignment_for_cascading_method_invocation_with_arguments.count_dependent=16|-1|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_enum_constants.count_dependent=16|5|48 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer.count_dependent=16|5|80 org.eclipse.jdt.core.formatter.alignment_for_field_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_for_statement=16 org.eclipse.jdt.core.formatter.alignment_for_generic_type_arguments=16 org.eclipse.jdt.core.formatter.alignment_for_generic_type_arguments.count_dependent=16|-1|16 org.eclipse.jdt.core.formatter.alignment_for_local_variable_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields.count_dependent=16|-1|16 org.eclipse.jdt.core.formatter.alignment_for_new_anonymous_class=20 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration.count_dependent=16|5|80 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration.count_dependent=16|5|80 -org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 -org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation.count_dependent=16|4|48 -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_enum_declaration.count_dependent=16|4|49 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration.count_dependent=16|4|48 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration.count_dependent=16|4|48 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration.count_dependent=16|4|48 -org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=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=0 -org.eclipse.jdt.core.formatter.blank_lines_before_member_type=0 -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=0 -org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 -org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=2 -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=false -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=false -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=false -org.eclipse.jdt.core.formatter.comment.indent_root_tags=true -org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert -org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert -org.eclipse.jdt.core.formatter.comment.line_length=100 -org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true -org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true -org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false org.eclipse.jdt.core.formatter.comment_new_line_at_start_of_html_paragraph=true -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.disabling_tag=@formatter\:off -org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on org.eclipse.jdt.core.formatter.force_if_else_statement_brace=true -org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true -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_field=insert -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_method=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=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_annotation_on_type=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_label=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=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=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=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=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=do not 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=do not 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_comment_prefix=do not 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=do not 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_try=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_semicolon_in_try_resources=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=do not 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_try=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_try=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_semicolon_in_try_resources=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.join_lines_in_comments=true -org.eclipse.jdt.core.formatter.join_wrapped_lines=true -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=100 -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=3 -org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false org.eclipse.jdt.core.formatter.sort_local_variable_annotations=false org.eclipse.jdt.core.formatter.sort_member_annotations=false org.eclipse.jdt.core.formatter.sort_package_annotations=false org.eclipse.jdt.core.formatter.sort_parameter_annotations=false org.eclipse.jdt.core.formatter.sort_type_annotations=false -org.eclipse.jdt.core.formatter.tabulation.char=space -org.eclipse.jdt.core.formatter.tabulation.size=2 -org.eclipse.jdt.core.formatter.use_on_off_tags=false -org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true -org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true org.eclipse.jdt.core.formatter.wrap_comment_inline_tags=false org.eclipse.jdt.core.formatter.wrap_non_simple_local_variable_annotation=true org.eclipse.jdt.core.formatter.wrap_non_simple_member_annotation=true org.eclipse.jdt.core.formatter.wrap_non_simple_package_annotation=true org.eclipse.jdt.core.formatter.wrap_non_simple_parameter_annotation=false org.eclipse.jdt.core.formatter.wrap_non_simple_type_annotation=true -org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true org.eclipse.jdt.core.formatter.wrap_prefer_two_fragments=false diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs index e142db0d..dd684219 100644 --- a/.settings/org.eclipse.jdt.ui.prefs +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -52,8 +52,7 @@ cleanup_profile=_processing.py cleanup cleanup_settings_version=2 eclipse.preferences.version=1 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true -formatter_profile=_processing.py -formatter_settings_version=13 +formatter_settings_version=12 sp_cleanup.add_default_serial_version_id=true sp_cleanup.add_generated_serial_version_id=false sp_cleanup.add_missing_annotations=true @@ -67,10 +66,12 @@ 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_functional_interfaces=false sp_cleanup.convert_to_enhanced_for_loop=true sp_cleanup.correct_indentation=false sp_cleanup.format_source_code=true -sp_cleanup.format_source_code_changes_only=false +sp_cleanup.format_source_code_changes_only=true +sp_cleanup.insert_inferred_type_arguments=false sp_cleanup.make_local_variable_final=true sp_cleanup.make_parameters_final=true sp_cleanup.make_private_fields_final=true @@ -78,14 +79,15 @@ 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.on_save_use_additional_actions=false +sp_cleanup.organize_imports=false 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=false sp_cleanup.qualify_static_method_accesses_with_declaring_class=false sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false sp_cleanup.remove_trailing_whitespaces=true sp_cleanup.remove_trailing_whitespaces_all=true sp_cleanup.remove_trailing_whitespaces_ignore_empty=false @@ -99,8 +101,10 @@ 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_anonymous_class_creation=false sp_cleanup.use_blocks=true sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false sp_cleanup.use_parentheses_in_expressions=false sp_cleanup.use_this_for_non_static_field_access=false sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true diff --git a/.travis.yml b/.travis.yml index 3438d7e0..b22a7fa4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,11 @@ env: DISPLAY=:99.0 sudo: false +addons: + apt: + packages: + - oracle-java8-installer + - ant-optional language: java diff --git a/Base - Launch Mode in Eclipse.launch b/Base - Launch Mode in Eclipse.launch index 167cd20a..e561a978 100644 --- a/Base - Launch Mode in Eclipse.launch +++ b/Base - Launch Mode in Eclipse.launch @@ -11,14 +11,38 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Base - Sketch Runner First.launch b/Base - Sketch Runner First.launch index 3a1e1d48..dc466d79 100644 --- a/Base - Sketch Runner First.launch +++ b/Base - Sketch Runner First.launch @@ -25,5 +25,5 @@ - + diff --git a/HOWTO-HACK.txt b/HOWTO-HACK.txt index 856cecad..54e9902c 100644 --- a/HOWTO-HACK.txt +++ b/HOWTO-HACK.txt @@ -2,45 +2,78 @@ Instructions for folks who want to contribute to processing.py itself. Prerequisites: - git - http://git-scm.com/downloads - Java 7 SDK - http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html - Apache ant - http://ant.apache.org/bindownload.cgi + git - http://git-scm.com/downloads + Latest JDK 8 - http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html + Apache ant - http://ant.apache.org/bindownload.cgi -Recommended: +The Processing and Python Mode developers use Eclipse for their development, +but it is not required. There are Eclipse project configs in our source trees. - Eclipse Standard - https://www.eclipse.org/downloads/ + Eclipse - https://www.eclipse.org/downloads/ -Steps: +Steps +----- + +Create a directory to organize your Processing-related source, say + + $ mkdir processing-source + $ cd processing-source + +These build steps assume your file structure will look like this: + + processing-source/ + |- processing.py/ + |- processing/ + |- processing-video/ If you think you're going to want to submit your own work to processing.py, -you should start by creating a fork of processing.py on github. Let's say +you should start by creating a fork of processing.py on GitHub. Let's say you've done so, and that your fork can be found at: - https://github.com/JRandomHacker/processing.py + https://github.com/JRandomHacker/processing.py + +I'll also assume you've uploaded your SSH public key to GitHub. + + $ git clone git@github.com:JRandomHacker/processing.py.git + +Otherwise, if you just want to build or examine Python Mode, you can clone +the original repo: + + $ git clone https://github.com/jdf/processing.py.git + + +You'll need source for processing and processing-video. + + $ git clone --depth=1 https://github.com/processing/processing.git + $ git clone --depth=1 https://github.com/processing/processing-video.git + +If you are a Linux user, you'll also have to create a directory named `linux` +inside your `processing.py` directory. -I'll also assume you've uploaded your SSH public key to Github. +Then, to sanity-check your environment and run all of Python Mode's +integration tests, do the following: - $ git clone git@github.com:JRandomHacker/processing.py.git + $ cd processing.py + $ ant test -You'll need my forks of processing and processing-video (at least until such time as -processing.py has been rewritten to be compatible with versions of Processing -> 3.0a5). +That will take 2-5 minutes. - $ git clone https://github.com/jdf/processing.git - $ git clone https://github.com/jdf/processing-video.git +Take a look at the script testmode.sh and modify it, if necessary, to +match your Processing install. This script will build Python Mode, +install it in your copy of Processing, and launch it. -Then: - $ cd processing.py - $ ant test +Configuring Eclipse +------------------- If you want to modify the code, and you're an Eclipse user, you can "Import -existing project into workspace" a couple of times, once for processing.py -itself (which lives in the processing.py top level directory), and once for -processing.core, which you'll find in the directory where you've cloned -jdf/processing. +existing project into workspace" a few of times, once for processing.py +itself (which lives in the processing.py top level directory), and once +each for processing.core, processing-java, processing-app, and +processing-video, which you'll find in the directories where you've +cloned processing and processing-video. -Once you've imported those two projects, you should be able to run +Once you've imported those projects, you should be able to run test.jycessing.JycessingTests as a JUnit test. There are several Eclipse Run Configurations included in the processing.py @@ -48,7 +81,7 @@ directory, which are essential for debugging the Python mode sketch runner, which is an independent application, and which communicates with the Mode stuff via sockets. -To run or debug the SketchRunner, launch the SketchRunner Run Configuration +To run or debug the SketchRunner, launch the "SketchRunner" Run Configuration from Eclipse's Java runner menu. Once it has started up, run the "Base - Sketch Runner First" configuration. This sequence runs things backwards; normally the Mode runs, and itself launches the SketchRunner. diff --git a/README.markdown b/README.markdown index c00d0581..9e977fc7 100644 --- a/README.markdown +++ b/README.markdown @@ -1,18 +1,31 @@ +# THIS PROJECT IS NOT MAINTAINED # + +It is not compatible with the latest major version of Processing, 4.0. + +There is no longer anyone fixing bugs or developing new features. + +If you are interested in taking ownership of this repository, please contact +Jonathan Feinberg. + # Python Mode for Processing # Write real [Processing](http://processing.org/) sketches in Python. - * Based on [Processing 2.0](http://processing.org/), and compatible with most [3rd party libraries](http://www.processing.org/reference/libraries/). - * Source compatible with [Python 2.7.3](http://python.org). +* Based on [Processing 3.0](http://processing.org/), and compatible with most [3rd party libraries](http://www.processing.org/reference/libraries/). +* Source compatible with [Python 2.7.3](http://python.org). -Tested on Mac OS 10.8 & 10.9, Windows XP, 7 & 8, and Ubuntu 12.10. +Tested on Mac OS 10.10 and Ubuntu 14. [![Build Status](https://travis-ci.org/jdf/processing.py.svg?branch=master)](https://travis-ci.org/jdf/processing.py) +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjdf%2Fprocessing.py.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjdf%2Fprocessing.py?ref=badge_shield) ## Quick Start ## -### Processing Development Environment ### +
+Processing Development Environment +
+ If you're looking to write Processing sketches in Python, your best bet is to use Python Mode. The project is still in its early days, and documentation is lacking, but there are many example sketches to get you started. In general, the Processing @@ -32,7 +45,6 @@ def setup(): colorMode(HSB) noStroke() - def draw(): fill(0x11000000) rect(0, 0, width, height) @@ -40,157 +52,172 @@ def draw(): ellipse(mouseX, mouseY, 20, 20) ``` -### Processing.py ### - -For command-line hackers and people who need much greater flexibility in how -they construct and integrate their programs, there's processing.py. - -- [Mac OS X (83M)](http://py.processing.org/processing.py-0202-macosx.tgz) -- [Windows x64 (74M)](http://py.processing.org/processing.py-0202-windows64.zip) -- [Windows x32 (72M)](http://py.processing.org/processing.py-0202-windows32.zip) -- [Linux x64 (68M)](http://py.processing.org/processing.py-0202-linux64.tgz) -- [Linux x32 (69M)](http://py.processing.org/processing.py-0202-linux32.tgz) - -Then, paste this code into a file, e.g., `mysketch.py`. - - def setup(): - size(600, 400) - - def draw(): - ellipse(mouseX, mouseY, 10, 10) - -Drag and drop your sketch onto one of these files, according to your platform: - - +If you are just getting started, it is a good idea to go through the [tutorials on our website](http://py.processing.org/tutorials/), and alternatively some [examples](mode/examples). + +
-You can also run the sketch from the command line, either with the included launcher script: +## Processing Basics ## - $ ./processing-py.sh path/to/mysketch.py +
-or using your own Java runtime environment: +What is Processing? +
+ +Processing is a graphics library utilized by artists, educators, students, and hobbyists to create sketches without the hassle of traditional graphics libraries. Processing provides a simplified API that allows for visual tasks that would take dozens of lines in other software to be completed in just a couple of lines. Processing is also a community with extensive support in developing, maintaining, as well as creating educational resources for this software. Please see https://processing.org/ for more information. + +
- $ java -jar processing-py.jar path/to/mysketch.py +Should I use Processing? +
+ +Processing is the perfect enviornment for programmers of all experience levels. It is a great starting point for programmers with no graphics programming experience. The [documentation](https://processing.org/environment/#overview) is a great place to start and learn the basics. Processing is also a vehicle for learning how to code, since you can see the changes you make in your code visually. [Here](http://learningprocessing.com/videos/) is a great video tutorial for getting started. For users with graphics programming experience, Processing is very effective for fun projects and quick prototypes. For extremely complex, performance heavy, and commerical applications - Processing may not be the best choice. + +
-## Documentation ## - -To learn Processing.py check out these resources: - - * Built-in [Processing 2.0 functions](http://processing.org/reference/) for rendering and interaction. - * The [Python 2.7 documentation](http://docs.python.org/2/index.html). - * And of course the [Java 7 API documentation](http://docs.oracle.com/javase/7/docs/api/). - -Processing.py comes with many [examples](https://github.com/jdf/processing.py/tree/master/examples.py), most of which are exactly like the -example sketches that come with Processing, but converted to Python. - - $ processing-py.sh examples.py/Basics/Math/noisefield.py - $ processing-py.sh examples.py/Library/OpenGL/SpaceJunk.py - $ processing-py.sh examples.py/3D/Typography/KineticType.py - $ processing-py.sh examples.py/3D/Textures/TextureCube.py - -## Using Processing Libraries ## - -Processing.py is implemented in Java, and is designed to be compatible with the existing ecosystem of [Processing libraries](http://processing.org/reference/libraries/). - -* Put processing extension libraries in the `libraries` subdirectory of your processing.py installation. Processing.py will search every jar file and directory beneath that special directory, so you don't need to be too fussy about where things go. Just unzip Processing libraries right there. - -* Import the library in one of the usual Python ways, as in these snippets: - - from peasy import PeasyCam - # or - import peasy.PeasyCam - # or - import peasy.PeasyCam as PeasyCam +Structure of a Processing Project +
+ + ```python +def setup(): + # This code is only run once + size(800, 800) - Unfortunately, `from foo import *` is not supported. +def draw(): + # This code is run on a loop + background(255, 0, 0) +``` + +A graphics library has three essential components: before the main loop; the code the consists of the main loop; and code that is executed after the main loop. In processing we write all of the code that will be executed before the main loop in a function that we define as `setup`. This function is only called once at the start of program execution. Typically we will define the size of the graphics window we want to generate using the called `size(w, h)`, where w is the width we desire (in pixels) and h is the height we desire (in pixels). If we want the window to take up the entire screen we can call `fullScreen()`. + +We write the code that we want to continously execute in the function defined as `draw`. This code is run on a loop and is only terminated if we tell it to (or the program exits in an error). Typically we will define a background using a call to the `bacground()` function. This function accepts a wide variety of values from [RGB](https://en.wikipedia.org/wiki/RGB_color_model), [RGBA](https://en.wikipedia.org/wiki/RGBA_color_model), [HSB](https://en.wikipedia.org/wiki/HSL_and_HSV), and [HEX](https://en.wikipedia.org/wiki/Web_colors#Hex_triplet). By placing `background` in draw the screen is 'refreshed' each execution, which mean what we drew to the screen last cycle is erased. We can also move `background` to setup if we wish to not have this behavior. + +
+ +Drawing Shapes +
+ + ```python +def setup(): + # This code is only run once + size(800, 800) -* Then, in your `setup()` method: +def draw(): + # This code is run on a loop + background(255, 0, 0) + fill(0, 0, 0) + rectMode(CENTER) + rect(width / 2, height / 2, 10, 20) +``` - cam = PeasyCam(this, 200) + One of the most basic things we can do in Processing is draw shapes. There are a [wide variety of shapes](https://processing.org/reference/#shape) that we can draw, but for this example we will be drawing a rectangle. Processing uses a [Caretsian Coordinate System](https://en.wikipedia.org/wiki/Cartesian_coordinate_system) where the origin (0,0) is in the top left corner, and the maximal (x,y) is in the bottom right corner. The function `rect(x,y,w,h)` allows us to draw a rectangle. The first and second parameters, x and y, defines the coordinates where we want to draw the rectangle. Processing also provides a variety of defined constants; `width` and `height` are the width and height of the current window. By setting `rectMode(CENTER)` and passing `width / 2` and `height / 2` as the arguments for x and y we draw a rectangle in the center of the window. + +The function `fill(r,g,b)` allows us to change the color of the rectangle we are drawing. Think of `fill` as changing the color of the paint brush you are using. Once you call `fill` every call after will use that color until `fill` is called again. This is why we call fill before drawing our rectangle. We pass the value `(0,0,0)` to 'fill` to set the color to black. + +
- Many libraries need a reference to "the current PApplet", and that's what - `this` is for. Of course, there's no such thing as `this` in Python; it's just something that processing.py provides for you for compatibility with such libraries. +## Advanced Usage ## -## Included Libraries ## +
+ +Using Processing Libraries +
-Some Processing libraries may not work with processing.py right out of the box. In particular, any library that uses Java reflection to call specially-named functions in your sketch will not work. However, we're happy to modify processing.py to work with any of the official Processing libraries. Here are the libraries that have required special handling in processing.py, and are included in the processing.py download: +Python Mode is implemented in Java, and is designed to be compatible with the existing ecosystem of [Processing libraries](http://processing.org/reference/libraries/). - * [Fisica](http://www.ricardmarxer.com/fisica/), by [Ricard Marxer](http://www.ricardmarxer.com/). Included under the terms of the LGPLv3, and with the kind cooperation of Mr. Marxer. See [examples.py/Fisica](https://github.com/jdf/processing.py/tree/master/examples.py/Fisica) for examples. +Many libraries need a reference to "the current PApplet", and that's what +`this` is for. Of course, there's no such thing as `this` in Python; it's just something that processing.py provides for you for compatibility with such libraries. If you find that some Processing library doesn't work as expected with processing.py, please let us know in the [bug tracker](http://github.com/jdf/processing.py/issues). + +
-## FAQ ## - - * __How do I report bugs or request new features?__ - - Please report any issue in the [bug tracker](http://github.com/jdf/processing.py/issues). - - * __How can I create a launcher for my sketch?__ - - Add these lines near the top of your script: - - import launcher - launcher.create() - - * __How should I load data?__ - - [Tentative] Along with the launcher, consider using `pwd()` for file paths. For a given argument it resolves the path for an object relative to the currently running script: - - data = load(pwd("data.txt")) +How do I report bugs or request new features? +
- In that case, processing.py will try to search `data.txt` always where your script resides. +Please report any issue in the [bug tracker](http://github.com/jdf/processing.py/issues). - * __How can I use Ani, or any other library that modifies fields?__ +### How can I create a launcher for my sketch? ### - Some libraries such as [Ani](http://www.looksgood.de/libraries/Ani/) require you to specify a variable name for animation. Unfortunately they cannot access Python variables directly (and Java's built in classes are immutable). +Add these lines near the top of your script: - To solve this problem we instead create a mutable `PrimitiveFloat` object. This object has a field `.value`, which you can use for these purposes. - - import jycessing.primitives.PrimitiveFloat as Float - x = Float(100.0) - Ani.to(x, 200, "value", 50); # "value" is the name of the Float's internal field - - In case you need other primitive values, please [let us know](http://github.com/jdf/processing.py/issues)! - - * __Why was this project created?__ - - I ([Jonathan](http://MrFeinberg.com/)) recently gave a talk about Processing to a group of rather bright 8th-graders, - as part of a computer-programming summer camp they were attending at my office. - Their curriculum up to that point had been in Python, which is an eminently - sensible choice, given the - [pedagogical roots](http://en.wikipedia.org/wiki/ABC_%28programming_language%29) - of the language. +```python +import launcher +launcher.create() +``` - The kids were really turned on by the demos--I showed them the - [white glove](http://whiteglovetracking.com/), and - [Golan Levin](http://flong.com/)'s - [New Year's cards](http://www.flong.com/storage/experience/newyear/newyear10/)--but - they were bogged down by Processing's C-like syntax, which really seems arcane - and unnecessarily complex when you're used to Python. +
+ +How can I use Ani, or any other library that modifies fields? +
- I shared my experience with Processing creators - [Ben Fry](http://benfry.com/) and [Casey Reas](http://reas.com/), and they - told me that, indeed, the original Processing was a fork of - ["Design By Numbers"](http://dbn.media.mit.edu/), with Python and Scheme - support hacked in. Support for a multi-lingual programming - environment was always part of the plan, so they were enthusiastic - about any new attempt at the problem. +Some libraries such as [Ani](http://www.looksgood.de/libraries/Ani/) require you to specify a variable name for animation. Unfortunately they cannot access Python variables directly (and Java's built in classes are immutable). - I was able to hack up a proof of concept in a couple of hours, and have - managed to create something worth sharing in a couple of weeks. I was only - able to do it at all thanks to the brilliant and beautiful - [Jython](http://www.jython.org/) project. +To solve this problem we instead create a mutable `PrimitiveFloat` object. This object has a field `.value`, which you can use for these purposes. - At the time of Processing's first public release, August of 2001, - Jython was too young a project to be used in this way. But now, having done - absolutely no work to profile and optimize, I can get hundreds of frames - per second of 3D graphics on my linux box. So, kudos to the Processing - project, and kudos to Jython! +```python +import jycessing.primitives.PrimitiveFloat as Float +x = Float(100.0) +Ani.to(x, 200, "value", 50); # "value" is the name of the Float's internal field +``` +In case you need other primitive values, please [let us know](http://github.com/jdf/processing.py/issues)! + +
+ +## Why was this project created? ## + +I ([Jonathan](http://MrFeinberg.com/)) recently gave a talk about Processing to a group of rather bright 8th-graders, +as part of a computer-programming summer camp they were attending at my office. +Their curriculum up to that point had been in Python, which is an eminently +sensible choice, given the +[pedagogical roots](http://en.wikipedia.org/wiki/ABC_%28programming_language%29) +of the language. + +The kids were really turned on by the demos--I showed them the +[white glove](http://whiteglovetracking.com/), and +[Golan Levin](http://flong.com/)'s +[New Year's cards](http://www.flong.com/storage/experience/newyear/newyear10/)--but +they were bogged down by Processing's C-like syntax, which really seems arcane +and unnecessarily complex when you're used to Python. + +I shared my experience with Processing creators +[Ben Fry](http://benfry.com/) and [Casey Reas](http://reas.com/), and they +told me that, indeed, the original Processing was a fork of +["Design By Numbers"](http://dbn.media.mit.edu/), with Python and Scheme +support hacked in. Support for a multi-lingual programming +environment was always part of the plan, so they were enthusiastic +about any new attempt at the problem. + +I was able to hack up a proof of concept in a couple of hours, and have +managed to create something worth sharing in a couple of weeks. I was only +able to do it at all thanks to the brilliant and beautiful +[Jython](http://www.jython.org/) project. + +At the time of Processing's first public release, August of 2001, +Jython was too young a project to be used in this way. But now, having done +absolutely no work to profile and optimize, I can get hundreds of frames +per second of 3D graphics on my linux box. So, kudos to the Processing +project, and kudos to Jython! ## Credits ## Written by [Jonathan Feinberg](http://mrfeinberg.com) <[jdf@pobox.com](mailto:jdf@pobox.com)> Launcher & many improvements by [Ralf Biedert](http://xr.io) <[rb@xr.io](mailto:rb@xr.io)> -Also, [YourKit, LLC](http://www.yourkit.com) was so kind to sponsor a license for their excellent [YourKit Java Profiler](http://www.yourkit.com/java/profiler/index.jsp). Thank you very much! +Much of the work in achieving compatibility with Processing 3.x was +was done by Luca Damasco +(Google Summer of Code student), under the supervision of Golan Levin, +with additional support from the Frank-Ratchye STUDIO for Creative Inquiry at Carnegie +Mellon University. Without Luca, the project might well have died. + +Also, [YourKit, LLC](http://www.yourkit.com) was so kind to sponsor a license for their excellent [YourKit Java Profiler](http://www.yourkit.com/java/profiler/index.jsp). Thank you very much! They've asked me to place this message here in return for their sponsorship: + + +YourKit supports open source projects with its full-featured Java Profiler. +YourKit, LLC is the creator of YourKit Java Profiler +and YourKit .NET Profiler, +innovative and intelligent tools for profiling Java and .NET applications. + +## License ## +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjdf%2Fprocessing.py.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjdf%2Fprocessing.py?ref=badge_large) diff --git a/SketchRunner.launch b/SketchRunner.launch index 02e8d3ff..e0c7b6f2 100644 --- a/SketchRunner.launch +++ b/SketchRunner.launch @@ -14,4 +14,6 @@ + + diff --git a/build.xml b/build.xml index 7a3de389..e162ee55 100644 --- a/build.xml +++ b/build.xml @@ -49,7 +49,7 @@ - + @@ -60,10 +60,10 @@ - - - - + + + + @@ -100,7 +100,11 @@ - + + + + + + replace="${jycessing.build.number}" /> @@ -125,10 +129,17 @@ - + + + + + + + + @@ -293,7 +304,7 @@ - + @@ -301,6 +312,13 @@ + + + + @@ -347,7 +365,7 @@ - + @@ -424,7 +442,7 @@ includes="*.txt,*.jar,${platform}/**,${platform}64/**"/> - + @@ -432,15 +450,21 @@ + + + - + + + diff --git a/buildtime/lib/jython/README b/buildtime/lib/jython/README new file mode 100644 index 00000000..c6d46c45 --- /dev/null +++ b/buildtime/lib/jython/README @@ -0,0 +1,10 @@ +export PROCESSING_PY=~/processing.py +cd /tmp +hg clone http://hg.python.org/jython +cd jython +hg update v2.7.1 +hg import --no-commit ~/processing.py/buildtime/lib/jython/jython-patch.diff +ant jar-standalone +cp dist/jython-standalone.jar $(PROCESSING_PY)/buildtime/lib/jython/jython.jar +cd $(PROCESSING_PY) +ant test diff --git a/buildtime/lib/jython/jython-src.jar b/buildtime/lib/jython/jython-src.jar new file mode 100644 index 00000000..c29f4cf4 Binary files /dev/null and b/buildtime/lib/jython/jython-src.jar differ diff --git a/buildtime/lib/jython/jython.jar b/buildtime/lib/jython/jython.jar index ff914c76..8e0670e7 100644 Binary files a/buildtime/lib/jython/jython.jar and b/buildtime/lib/jython/jython.jar differ diff --git a/buildtime/py/astpp.py b/buildtime/py/astpp.py new file mode 100644 index 00000000..67a87185 --- /dev/null +++ b/buildtime/py/astpp.py @@ -0,0 +1,56 @@ +""" +A pretty-printing dump function for the ast module. The code was copied from +the ast.dump function and modified slightly to pretty-print. + +Alex Leone (acleone ~AT~ gmail.com), 2010-01-30 +""" + +from ast import * + +def dump(node, annotate_fields=True, include_attributes=False, indent=' '): + """ + Return a formatted dump of the tree in *node*. This is mainly useful for + debugging purposes. The returned string will show the names and the values + for fields. This makes the code impossible to evaluate, so if evaluation is + wanted *annotate_fields* must be set to False. Attributes such as line + numbers and column offsets are not dumped by default. If this is wanted, + *include_attributes* can be set to True. + """ + def _format(node, level=0): + if isinstance(node, AST): + fields = [(a, _format(b, level)) for a, b in iter_fields(node)] + if include_attributes and node._attributes: + fields.extend([(a, _format(getattr(node, a), level)) + for a in node._attributes]) + return ''.join([ + node.__class__.__name__, + '(', + ', '.join(('%s=%s' % field for field in fields) + if annotate_fields else + (b for a, b in fields)), + ')']) + elif isinstance(node, list): + lines = ['['] + lines.extend((indent * (level + 2) + _format(x, level + 2) + ',' + for x in node)) + if len(lines) > 1: + lines.append(indent * (level + 1) + ']') + else: + lines[-1] += ']' + return '\n'.join(lines) + return repr(node) + if not isinstance(node, AST): + raise TypeError('expected AST, got %r' % node.__class__.__name__) + return _format(node) + +if __name__ == '__main__': + import sys + for filename in sys.argv[1:]: + print '=' * 50 + print 'AST tree for', filename + print '=' * 50 + f = open(filename, 'r') + fstr = f.read() + f.close() + print dump(parse(fstr, filename=filename), include_attributes=True) + print diff --git a/examples.py/3D/Camera/MoveEye.py b/examples.py/3D/Camera/MoveEye.py index b8bf393d..a942e028 100755 --- a/examples.py/3D/Camera/MoveEye.py +++ b/examples.py/3D/Camera/MoveEye.py @@ -1,22 +1,24 @@ """ - * Move Eye. - * by Simon Greenwold. - * - * The camera lifts up (controlled by mouseY) while looking at the same point. + Move Eye. + by Simon Greenwold. + + The camera lifts up (controlled by mouseY) while looking at the same point. """ -def setup(): + +def setup(): size(640, 360, P3D) fill(204) - -def draw(): + + +def draw(): lights() background(0) - + # Change height of the camera with mouseY - camera(30.0, mouseY, 220.0, # eyeX, eyeY, eyeZ - 0.0, 0.0, 0.0, # centerX, centerY, centerZ - 0.0, 1.0, 0.0) # upX, upY, upZ - + camera(30.0, mouseY, 220.0, # eyeX, eyeY, eyeZ + 0.0, 0.0, 0.0, # centerX, centerY, centerZ + 0.0, 1.0, 0.0) # upX, upY, upZ + noStroke() box(90) stroke(255) diff --git a/examples.py/3D/Camera/OrthoVSPerspective.py b/examples.py/3D/Camera/OrthoVSPerspective.py index cf497c6c..8c1a2004 100755 --- a/examples.py/3D/Camera/OrthoVSPerspective.py +++ b/examples.py/3D/Camera/OrthoVSPerspective.py @@ -1,36 +1,40 @@ """ - * Ortho vs Perspective. - * - * Click to see the difference between orthographic projection - * and perspective projection as applied to a simple box. - * The ortho() function sets an orthographic projection and - * defines a parallel clipping volume. All objects with the - * same dimension appear the same size, regardless of whether - * they are near or far from the camera. The parameters to this - * function specify the clipping volume where left and right - * are the minimum and maximum x values, top and bottom are the - * minimum and maximum y values, and near and far are the minimum - * and maximum z values. +Ortho vs Perspective. + +Click to see the difference between orthographic projection +and perspective projection as applied to a simple box. +The ortho() function sets an orthographic projection and +defines a parallel clipping volume. All objects with the +same dimension appear to be the same size, regardless of whether +they are near or far away from the camera. The parameters to this +function specify the clipping volume where left and right +are the minimum and maximum x values respectively, +top and bottom are the minimum and maximum y values respectively, +and lastly, the near and far are the minimum and maximum z values. """ +showPerspective = True def setup(): size(640, 360, P3D) - noStroke() fill(204) + noStroke() + def draw(): - background(0) lights() - - if mousePressed: - fov = PI / 3.0 - cameraZ = (height / 2.0) / tan(PI * fov / 360.0) - perspective(fov, float(width) / float(height), - cameraZ / 2.0, cameraZ * 2.0) + background(0) + far = map(mouseX, 0, width, 120, 400) + if showPerspective: + perspective(THIRD_PI, float(width) / height, 10, far) else: - ortho(-width / 2, width / 2, -height / 2, height / 2, -10, 10) - - + ortho(0, width, 0, height, 10, far) + translate(width / 2, height / 2, 0) - rotateX(-PI / 6) - rotateY(PI / 3) + rotateX(-0.5 * THIRD_PI) + rotateY(THIRD_PI) box(160) + + +def mousePressed(): + global showPerspective + showPerspective = not showPerspective + diff --git a/examples.py/3D/Camera/Perspective.py b/examples.py/3D/Camera/Perspective.py index 07ff8ff3..b9b81dea 100755 --- a/examples.py/3D/Camera/Perspective.py +++ b/examples.py/3D/Camera/Perspective.py @@ -1,22 +1,23 @@ """ - * Perspective. - * - * Move the mouse left and right to change the field of view (fov). - * Click to modify the aspect ratio. The perspective() function - * sets a perspective projection applying foreshortening, making - * distant objects appear smaller than closer ones. The parameters - * define a viewing volume with the shape of truncated pyramid. - * Objects near to the front of the volume appear their actual size, - * while farther objects appear smaller. This projection simulates - * the perspective of the world more accurately than orthographic projection. - * The version of perspective without parameters sets the default - * perspective and the version with four parameters allows the programmer - * to set the area precisely. - """ +Perspective. + +Move the mouse left or right to change the field of view (fov). +Click to modify the aspect ratio. The perspective() function +sets a perspective projection applying foreshortening, making +distant objects appear smaller than closer ones. The parameters +define a viewing volume with the shape of truncated pyramid. +Objects near to the front of the volume appears to be in their actual size, +while farther objects appears to be smaller than original. This projection simulates +the perspective of the world more accurately than orthographic projection. +The version of perspective without parameters sets the default +perspective and the version with four parameters allows the programmer +to set the area precisely. +""" def setup(): size(640, 360, P3D) noStroke() + def draw(): lights() background(204) @@ -28,10 +29,9 @@ def draw(): aspect = aspect / 2.0 perspective(fov, aspect, cameraZ / 10.0, cameraZ * 10.0) - translate(width / 2 + 30, height / 2, 0) rotateX(-PI / 6) - rotateY(PI / 3 + mouseY / float(height) * PI) + rotateY(THIRD_PI + PI * mouseY / height) box(45) translate(0, 0, -50) box(30) diff --git a/examples.py/3D/Form/Primitives3D.py b/examples.py/3D/Form/Primitives3D.py index 691f2d60..82d3052f 100644 --- a/examples.py/3D/Form/Primitives3D.py +++ b/examples.py/3D/Form/Primitives3D.py @@ -1,26 +1,28 @@ """ - * Primitives 3D. - * - * Placing mathematically 3D objects in synthetic space. - * The lights() method reveals their imagined dimension. - * The box() and sphere() functions each have one parameter - * which is used to specify their size. These shapes are - * positioned using the translate() function. - """ +Primitives 3D. -size(640, 360, P3D) -background(0) -lights() -noStroke() -pushMatrix() -translate(130, height/2, 0) -rotateY(1.25) -rotateX(-0.4) -box(100) -popMatrix() -noFill() -stroke(255) -pushMatrix() -translate(500, height*0.35, -200) -sphere(280) -popMatrix() + Placing mathematically 3D objects in synthetic space. + The lights() method reveals their imagined dimension. + The box() and sphere() functions each have one parameter + which is used to specify their size. These shapes are + positioned using the translate() function. +""" +def setup(): + size(640, 360, P3D) + background(0) + +def draw(): + lights() + fill(50) + pushMatrix() + translate(130, height / 2, 0) + rotateY(1.25) + rotateX(-0.4) + box(100) + popMatrix() + noFill() + stroke(255) + pushMatrix() + translate(500, height * 0.35, -200) + sphere(210) + popMatrix() diff --git a/examples.py/3D/Form/Toroid.py b/examples.py/3D/Form/Toroid.py index c223a4be..8f2d7257 100644 --- a/examples.py/3D/Form/Toroid.py +++ b/examples.py/3D/Form/Toroid.py @@ -1,22 +1,22 @@ """ - * Interactive Toroid - * PDE by Ira Greenberg, rewritten in Python by Jonathan Feinberg - * - * Illustrates the geometric relationship between Toroid, Sphere, and Helix - * 3D primitives, as well as lathing principal. - * - * Instructions: - * UP arrow key pts++ - * DOWN arrow key pts-- - * LEFT arrow key segments-- - * RIGHT arrow key segments++ - * 'a' key toroid radius-- - * 's' key toroid radius++ - * 'z' key initial polygon radius-- - * 'x' key initial polygon radius++ - * 'w' key toggle wireframe/solid shading - * 'h' key toggle sphere/helix - """ + Interactive Toroid + PDE by Ira Greenberg, rewritten in Python by Jonathan Feinberg + + Illustrates the geometric relationship between Toroid, Sphere, and Helix + 3D primitives, as well as lathing principal. + + Instructions: + UP arrow key pts++ + DOWN arrow key pts-- + LEFT arrow key segments-- + RIGHT arrow key segments++ + 'a' key toroid radius-- + 's' key toroid radius++ + 'z' key initial polygon radius-- + 'x' key initial polygon radius++ + 'w' key toggle wireframe/solid shading + 'h' key toggle sphere/helix +""" pts = 40 radius = 60.0 diff --git a/examples.py/3D/Form/bricktower.py b/examples.py/3D/Form/bricktower.py index 0623aab8..e2845ad1 100644 --- a/examples.py/3D/Form/bricktower.py +++ b/examples.py/3D/Form/bricktower.py @@ -1,12 +1,12 @@ -""" - * Brick Tower - * by Ira Greenberg. - * - * 3D castle tower constructed out of individual bricks. -""" +''' + Brick Tower + by Ira Greenberg. + + 3D castle tower constructed out of individual bricks. +''' bricksPerLayer = 16.0 -brickLayers = 18.0 +brickLayers = 18 brickWidth = 60 brickHeight = 25 brickDepth = 25 @@ -15,35 +15,36 @@ def setup(): size(640, 360, OPENGL) + def draw(): - background(0) - (tempX, tempY, tempZ) = (0, 0, 0) - fill(182, 62, 29) - noStroke() - # Add basic light setup - lights() - translate(width / 2, height * 1.2, -380) - # Tip tower to see inside - rotateX(radians(-45)) - # Slowly rotate tower - rotateY(frameCount * PI / 600) - for i in range(brickLayers): + background(0) + (tempX, tempY, tempZ) = (0, 0, 0) + fill(182, 62, 29) + noStroke() + # Add basic light setup + lights() + translate(width / 2, height * 1.2, -380) + # Tip tower to see inside + rotateX(radians(-45)) + # Slowly rotate tower + rotateY(frameCount * PI / 600) + for i in xrange(brickLayers): # Increment rows - tempY -= brickHeight - # Alternate brick seams - angle = 360.0 / bricksPerLayer * i / 2 - for j in range(bricksPerLayer): - tempZ = cos(radians(angle)) * radius - tempX = sin(radians(angle)) * radius - pushMatrix() - translate(tempX, tempY, tempZ) - rotateY(radians(angle)) - # Add crenelation - if (i == brickLayers - 1): - if (j % 2 == 0): - box(brickWidth, brickHeight, brickDepth) - else: - # Create main tower - box(brickWidth, brickHeight, brickDepth) - popMatrix() - angle += 360.0 / bricksPerLayer + tempY -= brickHeight + # Alternate brick seams + angle = 360.0 / bricksPerLayer * i / 2 + for j in xrange(bricksPerLayer): + tempZ = cos(radians(angle)) * radius + tempX = sin(radians(angle)) * radius + pushMatrix() + translate(tempX, tempY, tempZ) + rotateY(radians(angle)) + # Add crenelation + if (i == brickLayers - 1): + if (j % 2 == 0): + box(brickWidth, brickHeight, brickDepth) + else: + # Create main tower + box(brickWidth, brickHeight, brickDepth) + popMatrix() + angle += 360.0 / bricksPerLayer diff --git a/examples.py/3D/Image/Explode.py b/examples.py/3D/Image/Explode.py index 4e801947..ae4df5ac 100755 --- a/examples.py/3D/Image/Explode.py +++ b/examples.py/3D/Image/Explode.py @@ -1,21 +1,24 @@ """ Explode by Daniel Shiffman. - (Rewritten in Python by Jonathan Feinberg.) Mouse horizontal location controls breaking apart of image and Maps pixels from a 2D image into 3D space. Pixel brightness controls translation along z axis. """ - -cellsize = 2 # Dimensions of each cell in the grid -img = loadImage("eames.jpg") -columns = img.width / cellsize # Calculate # of columns -rows = img.height / cellsize # Calculate # of rows + +cellsize = 2 # Dimensions of each cell in the grid + + def setup(): - size(640, 360, P3D) + size(640, 360, P3D) + global img, columns, rows + img = loadImage("eames.jpg") + columns = img.width / cellsize # Calculate # of columns + rows = img.height / cellsize # Calculate # of rows + -def draw(): +def draw(): background(0) for row in range(rows): for col in range(columns): @@ -23,7 +26,8 @@ def draw(): y = cellsize * row + cellsize / 2 loc = x + y * img.width # Pixel array location c = img.pixels[loc] # Grab the color - # Calculate a z position as a function of mouseX and pixel brightness + # Calculate a z position as a function of mouseX and pixel + # brightness z = (mouseX / float(width)) * brightness(img.pixels[loc]) - 20.0 # Translate to the location, set fill and stroke, and draw the rect pushMatrix() diff --git a/examples.py/3D/Textures/TextureCube.py b/examples.py/3D/Textures/TextureCube.py index 8ea8d18c..e2c66845 100755 --- a/examples.py/3D/Textures/TextureCube.py +++ b/examples.py/3D/Textures/TextureCube.py @@ -1,75 +1,80 @@ -""" - * TexturedCube - * based on pde example by Dave Bollinger. - * - * Drag mouse to rotate cube. Demonstrates use of u/v coords in - * vertex() and effect on texture(). -""" -tex = loadImage("data/berlin-1.jpg") -rotx = PI / 4 -roty = PI / 4 -rate = 0.01 - -def setup(): - size(640, 360, OPENGL) - textureMode(NORMAL) - fill(255) - stroke(color(44, 48, 32)) - -def draw(): - background(0) - noStroke() - translate(width / 2.0, height / 2.0, -100) - rotateX(rotx) - rotateY(roty) - scale(90) - TexturedCube() - -def TexturedCube(): - beginShape(QUADS) - texture(tex) - # Given one texture and six faces, we can easily set up the uv coordinates - # such that four of the faces tile "perfectly" along either u or v, but the other - # two faces cannot be so aligned. This code tiles "along" u, "around" the X / Z faces - # and fudges the Y faces - the Y faces are arbitrarily aligned such that a - # rotation along the X axis will put the "top" of either texture at the "top" - # of the screen, but is not otherwised aligned with the X / Z faces. (This - # just affects what type of symmetry is required if you need seamless - # tiling all the way around the cube) - - # +Z "front" face - vertex(-1, -1, 1, 0, 0) - vertex(1, -1, 1, 1, 0) - vertex(1, 1, 1, 1, 1) - vertex(-1, 1, 1, 0, 1) - # -Z "back" face - vertex(1, -1, -1, 0, 0) - vertex(-1, -1, -1, 1, 0) - vertex(-1, 1, -1, 1, 1) - vertex(1, 1, -1, 0, 1) - # +Y "bottom" face - vertex(-1, 1, 1, 0, 0) - vertex(1, 1, 1, 1, 0) - vertex(1, 1, -1, 1, 1) - vertex(-1, 1, -1, 0, 1) - # -Y "top" face - vertex(-1, -1, -1, 0, 0) - vertex(1, -1, -1, 1, 0) - vertex(1, -1, 1, 1, 1) - vertex(-1, -1, 1, 0, 1) - # +X "right" face - vertex(1, -1, 1, 0, 0) - vertex(1, -1, -1, 1, 0) - vertex(1, 1, -1, 1, 1) - vertex(1, 1, 1, 0, 1) - # -X "left" face - vertex(-1, -1, -1, 0, 0) - vertex(-1, -1, 1, 1, 0) - vertex(-1, 1, 1, 1, 1) - vertex(-1, 1, -1, 0, 1) - endShape() - -def mouseDragged(): - global rotx, roty - rotx += (pmouseY - mouseY) * rate - roty += (mouseX - pmouseX) * rate +""" + * TexturedCube + * based on pde example by Dave Bollinger. + * + * Drag mouse to rotate cube. Demonstrates use of u/v coords in + * vertex() and effect on texture(). +""" +rotx = PI / 4 +roty = PI / 4 +rate = 0.01 + + +def setup(): + size(640, 360, OPENGL) + textureMode(NORMAL) + fill(255) + stroke(color(44, 48, 32)) + global tex + tex = loadImage("data/berlin-1.jpg") + + +def draw(): + background(0) + noStroke() + translate(width / 2.0, height / 2.0, -100) + rotateX(rotx) + rotateY(roty) + scale(90) + TexturedCube() + + +def TexturedCube(): + beginShape(QUADS) + texture(tex) + # Given one texture and six faces, we can easily set up the uv coordinates + # such that four of the faces tile "perfectly" along either u or v, but the other + # two faces cannot be so aligned. This code tiles "along" u, "around" the X / Z faces + # and fudges the Y faces - the Y faces are arbitrarily aligned such that a + # rotation along the X axis will put the "top" of either texture at the "top" + # of the screen, but is not otherwised aligned with the X / Z faces. (This + # just affects what type of symmetry is required if you need seamless + # tiling all the way around the cube) + + # +Z "front" face + vertex(-1, -1, 1, 0, 0) + vertex(1, -1, 1, 1, 0) + vertex(1, 1, 1, 1, 1) + vertex(-1, 1, 1, 0, 1) + # -Z "back" face + vertex(1, -1, -1, 0, 0) + vertex(-1, -1, -1, 1, 0) + vertex(-1, 1, -1, 1, 1) + vertex(1, 1, -1, 0, 1) + # +Y "bottom" face + vertex(-1, 1, 1, 0, 0) + vertex(1, 1, 1, 1, 0) + vertex(1, 1, -1, 1, 1) + vertex(-1, 1, -1, 0, 1) + # -Y "top" face + vertex(-1, -1, -1, 0, 0) + vertex(1, -1, -1, 1, 0) + vertex(1, -1, 1, 1, 1) + vertex(-1, -1, 1, 0, 1) + # +X "right" face + vertex(1, -1, 1, 0, 0) + vertex(1, -1, -1, 1, 0) + vertex(1, 1, -1, 1, 1) + vertex(1, 1, 1, 0, 1) + # -X "left" face + vertex(-1, -1, -1, 0, 0) + vertex(-1, -1, 1, 1, 0) + vertex(-1, 1, 1, 1, 1) + vertex(-1, 1, -1, 0, 1) + endShape() + + +def mouseDragged(): + global rotx, roty + rotx += (pmouseY - mouseY) * rate + roty += (mouseX - pmouseX) * rate diff --git a/examples.py/Basics/Color/WaveGradient.py b/examples.py/Basics/Color/WaveGradient.py index e4793cba..e624c342 100644 --- a/examples.py/Basics/Color/WaveGradient.py +++ b/examples.py/Basics/Color/WaveGradient.py @@ -5,6 +5,7 @@ Generate a gradient along a sin() wave. """ +import math amplitude = 30 fillGap = 2.5 @@ -28,7 +29,7 @@ def draw(): 255 - abs(py - i) * 255 / amplitude, j * (255.0 / (width + 50))) # Hack to fill gaps. Raise value of fillGap if you increase frequency - for filler in range(fillGap): + for filler in range(int(math.ceil(fillGap))): set(int(j - filler), int(py) - filler, c) set(int(j), int(py), c) set(int(j + filler), int(py) + filler, c) diff --git a/examples.py/Library/DXF Export/SimpleExport.pyde b/examples.py/Library/DXF Export/SimpleExport.pyde new file mode 100644 index 00000000..3afc4915 --- /dev/null +++ b/examples.py/Library/DXF Export/SimpleExport.pyde @@ -0,0 +1,39 @@ +""" +Simple DXF Export by Simon Greenwold. + +Press the 'R' key to export a DXF file. +""" + +add_library('dxf') # import processing.dxf.* +record = False + +def setup(): + size(400, 400, P3D) + noStroke() + sphereDetail(12) + +def draw(): + global record + if record: + beginRaw(DXF, "output.dxf") # Start recording to the file + lights() + background(0) + translate(width / 3, height / 3, -200) + rotateZ(map(mouseY, 0, height, 0, PI)) + rotateY(map(mouseX, 0, width, 0, HALF_PI)) + for y in range(-2, 2): + for x in range(-2, 2): + for z in range(-2, 2): + pushMatrix() + translate(120 * x, 120 * y, -120 * z) + sphere(30) + popMatrix() + if record: + endRaw() + record = False # Stop recording to the file + +def keyPressed(): + global record + if key == 'R' or key == 'r': + # Press R to save the file + record = True diff --git a/examples.py/Library/Network/ChatServer.pyde b/examples.py/Library/Network/ChatServer.pyde new file mode 100644 index 00000000..cc511805 --- /dev/null +++ b/examples.py/Library/Network/ChatServer.pyde @@ -0,0 +1,39 @@ +""" +Chat Server by Tom Igoe. + +Press the mouse to stop the server. +""" + +add_library('net') # import processing.net.* + +port = 10002 +myServerRunning = True +bgColor = 0 +direction = 1 +textLine = 60 + +def setup(): + global myServer + size(400, 400) + textFont(createFont("SanSerif", 16)) + myServer = Server(this, port) # Starts a myServer on port 10002 + background(0) + +def mousePressed(): + global myServerRunning + # If the mouse clicked the myServer stops + myServer.stop() + myServerRunning = False + +def draw(): + if myServerRunning: + text("server", 15, 45) + thisClient = myServer.available() + if thisClient: # not None + if thisClient.available(): # thisClient.available() > 0 + text("mesage from: " + thisClient.ip() + " : " + + thisClient.readString(), 15, textLine) + textLine = textLine + 35 + else: + text("server", 15, 45) + text("stopped", 15, 65) diff --git a/examples.py/Library/Network/HTTPClient.pyde b/examples.py/Library/Network/HTTPClient.pyde new file mode 100644 index 00000000..1e6c75db --- /dev/null +++ b/examples.py/Library/Network/HTTPClient.pyde @@ -0,0 +1,29 @@ +""" +HTTP Client. + +Starts a network client that connects to a server on port 80, +sends an HTTP 1.0 GET request, and prints the results. + +Note that this code is not necessary for simple HTTP GET request: +Simply calling loadStrings("http://www.processing.org") would do +the same thing as (and more efficiently than) this example. +This example is for people who might want to do something more +complicated later. +""" + +add_library('net') # import processing.net.* + +def setup(): + global c + size(200, 200) + background(50) + fill(200) + c = Client(this, "www.ucla.edu", 80) # Connect to server on port 80 + # Use the HTTP "GET" command to ask for a Web page + c.write("GET / HTTP/1.0\r\n") + c.write("\r\n") + +def draw(): + if c.available(): # If there's incoming data from the client... + data = c.readString() # ...then grab it and print it + println(data) diff --git a/examples.py/Library/Network/SharedCanvasClient.pyde b/examples.py/Library/Network/SharedCanvasClient.pyde new file mode 100644 index 00000000..52793e17 --- /dev/null +++ b/examples.py/Library/Network/SharedCanvasClient.pyde @@ -0,0 +1,40 @@ +""" +Shared Drawing Canvas (Client) by Alexander R. Galloway. + +The Processing Client class is instantiated by specifying a remote +address and port number to which the socket connection should be made. +Once the connection is made, client may read (or write) data to the server. +Before running this program, the Shared Drawing Canvas (Server) program. +""" + +add_library('net') # import processing.net.* + +def setup(): + global c + size(450, 255) + background(204) + stroke(0) + frameRate(5) # Slow it down a little + # Connect to the server's IP address and port + c = Client(this, "127.0.0.1", 12345) + # Replace with your server's IP and port + +def draw(): + if mousePressed == True: + # Draw our line + stroke(255) + line(pmouseX, pmouseY, mouseX, mouseY) + # Send mouse coords to other person + c.write(str(pmouseX) + " " + + str(pmouseY) + " " + + str(mouseX) + " " + + str(mouseY) + "\n") + # Receive data from server + if c.available(): # c.available > 0 + input = c.readString() + input = input[:input.find("\n")] # Only up to the newline + data = [int(coord) + for coord in input.split()] # Split values into list + # Draw line using received coords + stroke(0) + line(data[0], data[1], data[2], data[3]) diff --git a/examples.py/Library/Network/SharedCanvasServer.pyde b/examples.py/Library/Network/SharedCanvasServer.pyde new file mode 100644 index 00000000..fb089fdb --- /dev/null +++ b/examples.py/Library/Network/SharedCanvasServer.pyde @@ -0,0 +1,42 @@ +""" +Shared Drawing Canvas (Server) by Alexander R. Galloway. + +A server that shares a drawing canvas between two computers. +In order to open a socket connection, a server must select a +port on which to listen for incoming clients and through which +to communicate. Once the socket is established, a client may +connect to the server and send or receive commands and data. +Get this program running and then start the Shared Drawing +Canvas (Client) program so see how they interact. +""" + +add_library('net') # import processing.net.* + +def setup(): + global s + size(450, 255) + background(204) + stroke(0) + frameRate(5) # Slow it down a little + s = Server(this, 12345) # Start a simple server on a port + +def draw(): + if mousePressed == True: + # Draw our line + stroke(255) + line(pmouseX, pmouseY, mouseX, mouseY) + # Send mouse coords to other person + s.write(str(pmouseX) + " " + + str(pmouseY) + " " + + str(mouseX) + " " + + str(mouseY) + "\n") + # Receive data from client + c = s.available() + if c: # c not null/None + input = c.readString() + input = input[:input.find("\n")] # Only up to the newline + data = [int(coord) + for coord in input.split()] # Split values into list + # Draw line using received coords + stroke(0) + line(data[0], data[1], data[2], data[3]) diff --git a/examples.py/Library/PDF Export/Complex3D.pyde b/examples.py/Library/PDF Export/Complex3D.pyde new file mode 100644 index 00000000..a860d3d5 --- /dev/null +++ b/examples.py/Library/PDF Export/Complex3D.pyde @@ -0,0 +1,153 @@ +""" +PDF Complex by Marius Watz (workshop.evolutionzone.com). + +Example using PDF to output complex 3D geometry for print. +Press "s" to save a PDF. +""" + +add_library('pdf') # import processing.pdf.* + +# Trig lookup tables (sinLUT and cosLUT) borrowed from Toxi. +# Cryptic but effective. +SINCOS_PRECISION = 1.0 +SINCOS_LENGTH = int(360.0 / SINCOS_PRECISION) +# System data +do_save = False + +def setup(): + global sinLUT, cosLUT, num, pt, style + size(600, 600, OPENGL) + frameRate(24) + background(255) + # Fill the tables + sinLUT = [sin(i * DEG_TO_RAD * SINCOS_PRECISION) + for i in range(SINCOS_LENGTH)] + cosLUT = [cos(i * DEG_TO_RAD * SINCOS_PRECISION) + for i in range(SINCOS_LENGTH)] + num = 150 + pt = [0.0 for _ in range(6 * num)] # rotx, roty, deg, rad, w, speed + style = [0 for _ in range(2 * num)] # color, render style + # Set up arc shapes + index = 0 + for i in range(num): + pt[index + 0] = random(TWO_PI) # Random X axis rotation + pt[index + 1] = random(TWO_PI) # Random Y axis rotation + pt[index + 2] = random(60, 80) # Short to quarter-circle arcs + if random(100) > 90: + pt[index + 2] = int(random(8, 27) * 10.0) + # Radius. Space them out nicely + pt[index + 3] = int(random(2, 50) * 5.0) + pt[index + 4] = random(4, 32) # Width of band + if random(100) > 90: + pt[index + 4] = random(40, 60) # Width of band + pt[index + 5] = radians(random(5, 30)) / 5.0 # Speed of rotation + index += 6 + # get colors + prob = random(100) + if prob < 30: + style[i * 2] = rgb_blend(random(1), 255, 0, 100, 255, 0, 0, 210) + elif prob < 70: + style[i * 2] = rgb_blend(random(1), 0, 153, 255, 170, 225, 255, 210) + elif prob < 90: + style[i * 2] = rgb_blend(random(1), 200, 255, 0, 150, 255, 0, 210) + else: + style[i * 2] = color(255, 255, 255, 220) + if prob < 50: + style[i * 2] = rgb_blend(random(1), 200, 255, 0, 50, 120, 0, 210) + elif prob < 90: + style[i * 2] = rgb_blend(random(1), 255, 100, 0, 255, 255, 0, 210) + else: + style[i * 2] = color(255, 255, 255, 220) + style[i * 2 + 1] = int(random(100)) % 3 + +def draw(): + global do_save + if do_save: + # set up PGraphicsPDF for use with beginRaw() + pdf = beginRaw(PDF, "pdf_complex_out.pdf") + # set default Illustrator stroke styles and paint background rect. + pdf.strokeJoin(MITER) + pdf.strokeCap(SQUARE) + pdf.fill(0) + pdf.noStroke() + pdf.rect(0, 0, width, height) + background(0) + index = 0 + translate(width / 2, height / 2, 0) + rotateX(PI / 6.0) + rotateY(PI / 6.0) + for i in range(num): + with pushMatrix(): + rotateX(pt[index + 0]) + rotateY(pt[index + 1]) + if style[i * 2 + 1] == 0: + stroke(style[i * 2]) + noFill() + strokeWeight(1) + arc_line(0, 0, pt[index + 2], pt[index + 3], pt[index + 4]) + elif style[i * 2 + 1] == 1: + fill(style[i * 2]) + noStroke() + arc_line_bars(0, 0, pt[index + 2], pt[index + 3], pt[index + 4]) + else: + fill(style[i * 2]) + noStroke() + arc(0, 0, pt[index + 2], pt[index + 3], pt[index + 4]) + # increase rotation + pt[index + 0] += pt[index + 5] / 10.0 + pt[index + 1] += pt[index + 5] / 20.0 + index += 6 + if do_save: + endRaw() + do_save = False + +# Get blend of two colors +def rgb_blend(fract, r, g, b, r2, g2, b2, a): + r2, g2, b2 = (r2 - r), (g2 - g), (b2 - b) + return color(r + r2 * fract, g + g2 * fract, b + b2 * fract, a) + +# Draw arc line +def arc_line(x, y, deg, rad, w): + a = int(min(deg / SINCOS_PRECISION, SINCOS_LENGTH - 1.0)) + numlines = int(w / 2) + for j in range(numlines): + beginShape() + for i in range(a): + vertex(cosLUT[i] * rad + x, + sinLUT[i] * rad + y) + endShape() + rad += 2 + +# Draw arc line with bars +def arc_line_bars(x, y, deg, rad, w): + a = int((min(deg / SINCOS_PRECISION, SINCOS_LENGTH - 1.0))) + a /= 4 + beginShape(QUADS) + for i in range(0, a, 4): + vertex(cosLUT[i] * (rad) + x, + sinLUT[i] * (rad) + y) + vertex(cosLUT[i] * (rad + w) + x, + sinLUT[i] * (rad + w) + y) + vertex(cosLUT[i + 2] * (rad + w) + x, + sinLUT[i + 2] * (rad + w) + y) + vertex(cosLUT[i + 2] * (rad) + x, + sinLUT[i + 2] * (rad) + y) + endShape() + +# Draw solid arc +def arc(x, y, deg, rad, w): + a = int(min(deg / SINCOS_PRECISION, SINCOS_LENGTH - 1.0)) + beginShape(QUAD_STRIP) + for i in range(a): + vertex(cosLUT[i] * (rad) + x, + sinLUT[i] * (rad) + y) + vertex(cosLUT[i] * (rad + w) + x, + sinLUT[i] * (rad + w) + y) + endShape() + +def keyPressed(): + if (key == 's'): + do_save = True + +def mouseReleased(): + background(255) diff --git a/examples.py/Library/PDF Export/LargePage.pyde b/examples.py/Library/PDF Export/LargePage.pyde new file mode 100644 index 00000000..36bc2b96 --- /dev/null +++ b/examples.py/Library/PDF Export/LargePage.pyde @@ -0,0 +1,23 @@ +""" +Large Page. + +Saves one frame as a PDF with a size larger +than the screen. When PDF is used as the renderer +(the third parameter of size) the display window +does not open. The file is saved to the sketch folder. +You can open it by "Sketch->Show Sketch Folder." +""" + +add_library('pdf') + + +def setup(): + size(2000, 2000, PDF, "Line.pdf") + + +def draw(): + background(255) + stroke(0, 20) + strokeWeight(20.0) + line(200, 0, width / 2, height) + exit() diff --git a/examples.py/Library/PDF Export/ManyPDFs.pyde b/examples.py/Library/PDF Export/ManyPDFs.pyde new file mode 100644 index 00000000..6629bf85 --- /dev/null +++ b/examples.py/Library/PDF Export/ManyPDFs.pyde @@ -0,0 +1,39 @@ +""" +Many PDFs. + +Saves one PDF file each each frame while the mouse is pressed. +When the mouse is released, the PDF creation stops. +""" + + +add_library('pdf') + +savePDF = False + + +def setup(): + size(600, 600) + frameRate(24) + + +def draw(): + if savePDF: + beginRecord(PDF, "lines%d.pdf" % (frameCount)) + + background(255) + stroke(0, 20) + strokeWeight(20.0) + line(mouseX, 0, width - mouseY, height) + + if savePDF: + endRecord() + + +def mousePressed(): + global savePDF + savePDF = True + + +def mouseReleased(): + global savePDF + savePDF = False diff --git a/examples.py/Library/PDF Export/ManyPages.pyde b/examples.py/Library/PDF Export/ManyPages.pyde new file mode 100644 index 00000000..fdc0e9f9 --- /dev/null +++ b/examples.py/Library/PDF Export/ManyPages.pyde @@ -0,0 +1,29 @@ +""" +Many Pages. + +Saves a new page into a PDF file each loop through draw(). +Pressing the mouse finishes writing the file and exits the program. +""" + + +add_library('pdf') + + +def setup(): + global pdf + size(600, 600) + frameRate(4) + pdf = beginRecord(PDF, "Lines.pdf") + + +def draw(): + background(255) + stroke(0, 20) + strokeWeight(20.0) + line(mouseX, 0, width - mouseY, height) + pdf.nextPage() + + +def mousePressed(): + endRecord() + exit() diff --git a/examples.py/Library/PDF Export/MousePress.pyde b/examples.py/Library/PDF Export/MousePress.pyde new file mode 100644 index 00000000..74ea973e --- /dev/null +++ b/examples.py/Library/PDF Export/MousePress.pyde @@ -0,0 +1,36 @@ +""" +Mouse Press. + +Saves one PDF of the contents of the display window +each time the mouse is pressed. +""" + + +add_library('pdf') + +saveOneFrame = False + + +def setup(): + size(600, 600) + frameRate(24) + + +def draw(): + global saveOneFrame + if saveOneFrame: + beginRecord(PDF, "Line.pdf") + + background(255) + stroke(0, 20) + strokeWeight(20.0) + line(mouseX, 0, width - mouseY, height) + + if saveOneFrame: + endRecord() + saveOneFrame = False + + +def mousePressed(): + global saveOneFrame + saveOneFrame = True diff --git a/examples.py/Library/PDF Export/MultipleFrames.pyde b/examples.py/Library/PDF Export/MultipleFrames.pyde new file mode 100644 index 00000000..66bcf7dd --- /dev/null +++ b/examples.py/Library/PDF Export/MultipleFrames.pyde @@ -0,0 +1,27 @@ +""" +Multiple Frames. + +Saves one PDF document of many frames drawn to the screen. +Starts the file when the mouse is pressed and end the file +when the mouse is released. +""" + +add_library('pdf') # import processing.pdf.* + +def setup(): + size(600, 600) + frameRate(24) + background(255) + +def draw(): + stroke(0, 20) + strokeWeight(20.0) + line(mouseX, 0, width - mouseY, height) + +def mousePressed(): + beginRecord(PDF, "Lines.pdf") + background(255) + +def mouseReleased(): + endRecord() + background(255) diff --git a/examples.py/Library/PDF Export/OneFrame.py b/examples.py/Library/PDF Export/OneFrame.py index dc319c52..841607fe 100644 --- a/examples.py/Library/PDF Export/OneFrame.py +++ b/examples.py/Library/PDF Export/OneFrame.py @@ -1,16 +1,15 @@ -""" - * One Frame. - * - * Saves one PDF with the contents of the display window. - * Because this example uses beginRecord, the image is shown - * on the display window and is saved to the file. -""" +""" One Frame. + + Saves one PDF with the contents of the display window. + Because this example uses beginRecord, the image is shown + on the display window and is saved to the file. + """ -#from processing.pdf import * +add_library('pdf') # from processing.pdf import * size(600, 600) -beginRecord(PDF, "line.pdf") +beginRecord(PDF, "line.pdf") background(255) stroke(0, 20) @@ -18,5 +17,3 @@ line(200, 0, 400, height) endRecord() - - diff --git a/examples.py/Library/PDF Export/RandomBook.pyde b/examples.py/Library/PDF Export/RandomBook.pyde new file mode 100644 index 00000000..59b4bd42 --- /dev/null +++ b/examples.py/Library/PDF Export/RandomBook.pyde @@ -0,0 +1,38 @@ +""" +RandomBook + +Creates a 768 page book of random lines. +""" + +add_library('pdf') # import processing.pdf.* + +def setup(): + global pdf + size(594, 842) + # randomSeed(0) # Uncomment to make the same book each time + pdf = beginRecord(PDF, "RandomBook.pdf") + beginRecord(pdf) + +def draw(): + background(255) + + for i in range(100): + r = random(1.0) + if r < 0.2: + stroke(255) + else: + stroke(0) + + sw = pow(random(1.0), 12) + strokeWeight(sw * 260) + x1 = random(-200, -100) + x2 = random(width + 100, width + 200) + y1 = random(-100, height + 100) + y2 = random(-100, height + 100) + line(x1, y1, x2, y2) + + if frameCount == 768: + endRecord() + exit() # Quit + else: + pdf.nextPage() # Tell it to go to the next page diff --git a/examples.py/Python/colornames/colorsketch.py b/examples.py/Python/colornames/colorsketch.py index 62a3be42..a540a997 100644 --- a/examples.py/Python/colornames/colorsketch.py +++ b/examples.py/Python/colornames/colorsketch.py @@ -4,11 +4,12 @@ """ from namethatcolor import NameThatColor -flag = loadImage("flag.jpg") namer = NameThatColor() def setup(): size(200, 200) + global flag + flag = loadImage("flag.jpg") def draw(): background(0) diff --git a/libraries/README.txt b/libraries/README.txt index 9846d2f3..dc81b48f 100644 --- a/libraries/README.txt +++ b/libraries/README.txt @@ -1,2 +1,2 @@ -Extract any Processing 2.0 plug-in into this directory, or any subdirectory +Extract any Processing 3 plug-in into this directory, or any subdirectory of this directory. diff --git a/mode/examples/Basics/Camera/MoveEye/MoveEye.pyde b/mode/examples/Basics/Camera/MoveEye/MoveEye.pyde index 310c8efb..ab6d05ae 100644 --- a/mode/examples/Basics/Camera/MoveEye/MoveEye.pyde +++ b/mode/examples/Basics/Camera/MoveEye/MoveEye.pyde @@ -1,9 +1,9 @@ """ - * Move Eye. - * by Simon Greenwold. - * - * The camera lifts up (controlled by mouseY) while looking at the same point. - """ +Move Eye. +by Simon Greenwold. + +The camera lifts up (controlled by mouseY) while looking at the same point. +""" def setup(): @@ -26,4 +26,3 @@ def draw(): line(-100, 0, 0, 100, 0, 0) line(0, -100, 0, 0, 100, 0) line(0, 0, -100, 0, 0, 100) - diff --git a/mode/examples/Basics/Camera/Orthographic/Orthographic.pyde b/mode/examples/Basics/Camera/Orthographic/Orthographic.pyde index 2f54f13d..a17471ed 100644 --- a/mode/examples/Basics/Camera/Orthographic/Orthographic.pyde +++ b/mode/examples/Basics/Camera/Orthographic/Orthographic.pyde @@ -30,7 +30,7 @@ def draw(): if showPerspective: perspective(PI / 3.0, float(width) / float(height), 10, far) else: - ortho(0, width, 0, height, 10, far) + ortho(-width/2.0, width/2.0, -height/2.0, height/2.0, 10, far) translate(width / 2, height / 2, 0) rotateX(-PI / 6) rotateY(PI / 3) diff --git a/mode/examples/Basics/Color/WaveGradient/WaveGradient.pyde b/mode/examples/Basics/Color/WaveGradient/WaveGradient.pyde index 9e7d4876..7eb7c282 100644 --- a/mode/examples/Basics/Color/WaveGradient/WaveGradient.pyde +++ b/mode/examples/Basics/Color/WaveGradient/WaveGradient.pyde @@ -28,7 +28,7 @@ def draw(): * 255 / amplitude, j * (255.0 / (width + 50))) # Hack to fill gaps. Raise value of fillGap if you increase # frequency - for filler in range(0, fillGap): + for filler in range(0, int(fillGap)): set(int(j - filler), int(py) - filler, c) set(int(j), int(py), c) set(int(j + filler), int(py) + filler, c) diff --git a/mode/examples/Basics/Data/Strings/Strings.pyde b/mode/examples/Basics/Data/Strings/Strings.pyde index 60674b69..9f849454 100644 --- a/mode/examples/Basics/Data/Strings/Strings.pyde +++ b/mode/examples/Basics/Data/Strings/Strings.pyde @@ -3,14 +3,12 @@ Strings TODO: Add Python-specific description. -TODO: Make a more Pythonic example showing string manipulation - in Python (e.g. string multiplication)? ''' -letter = ' ' # Strings can be written in single quotes -words = "Begin..." # Or double quotes +letter = ' ' # Strings can be written in single quotes +words = "Begin..." # Or double quotes -#Or triple quotes for multi-line strings +# Or triple quotes for multi-line strings morewords = """ I am @@ -18,38 +16,45 @@ a multi-line string """ +# String Multiplication: Strings can be multiplied by an integer. +my_str = "Hi! " * 5 +# my_str is initialised as "Hi! Hi! Hi! Hi! Hi! " -def setup(): +# Reversing a string +string = "Hello World" +string = ''.join(reversed(string)) +# string becomes 'dlroW olleH' + +def setup(): size(640, 360) # Create the font textFont(createFont("Georgia", 36)) -def draw(): - background(0)# Set background to black +def draw(): + background(0) # Set background to black # Draw the letter to the center of the screen textSize(14) - # Concatenate (combine) strings by juxtaposition: + # Concatenate (combine) strings by juxtaposition: text("Click on the program, " - "then type to add to the String", 50, 50) + "then type to add to the String", 50, 50) text("Current key: " + letter, 50, 70) - text("The String is " + str(len(words)) + " letters long", 50, 90) + text("The String is " + str(len(words)) + " letters long", 50, 90) textSize(36) text(words, 50, 120) - -def keyPressed(): + +def keyPressed(): global letter, words - # The variable "key" always contains the value + # The variable "key" always contains the value # of the most recent key pressed. if ('A' <= key <= 'z') or key == ' ': letter = key words += key - - #Hack to bound text to window - #Remove when rectangular bounding is added for text() - if len(words) % 30 == 0: + + # Hack to bound text to window + # Remove when rectangular bounding is added for text() + if len(words) % 30 == 0: words += '\n' - + # Write the letter to the console println(key) - diff --git a/mode/examples/Basics/Form/PieChart/PieChart.pyde b/mode/examples/Basics/Form/PieChart/PieChart.pyde index 0a13fbf7..dd801e44 100644 --- a/mode/examples/Basics/Form/PieChart/PieChart.pyde +++ b/mode/examples/Basics/Form/PieChart/PieChart.pyde @@ -2,7 +2,7 @@ Pie Chart Uses the arc() function to generate a pie chart from the data -stored in an array. +stored in a tuple. """ angles = (30, 10, 45, 35, 60, 38, 75, 67) diff --git a/mode/examples/Basics/Form/TriangleStrip/TriangleStrip.pyde b/mode/examples/Basics/Form/TriangleStrip/TriangleStrip.pyde index b3c2c141..757750de 100644 --- a/mode/examples/Basics/Form/TriangleStrip/TriangleStrip.pyde +++ b/mode/examples/Basics/Form/TriangleStrip/TriangleStrip.pyde @@ -13,6 +13,7 @@ insideRadius = 100 def setup(): size(640, 360) background(204) + global x, y x = width / 2 y = height / 2 @@ -25,7 +26,7 @@ def draw(): angleStep = 180.0 / numPoints beginShape(TRIANGLE_STRIP) - for i in range(numPoints): + for i in range(numPoints + 1): px = x + cos(radians(angle)) * outsideRadius py = y + sin(radians(angle)) * outsideRadius angle += angleStep @@ -35,4 +36,3 @@ def draw(): vertex(px, py) angle += angleStep endShape() - diff --git a/mode/examples/Basics/Image/Alphamask/Alphamask.pyde b/mode/examples/Basics/Image/Alphamask/Alphamask.pyde index 153e60c5..012d6b99 100644 --- a/mode/examples/Basics/Image/Alphamask/Alphamask.pyde +++ b/mode/examples/Basics/Image/Alphamask/Alphamask.pyde @@ -1,10 +1,10 @@ """ - * Alpha Mask. - * - * Loads a "mask" for an image to specify the transparency - * in different parts of the image. The two images are blended - * together using the mask() method of PImage. - """ +Alpha Mask. + +Loads a "mask" for an image to specify the transparency +in different parts of the image. The two images are blended +together using the mask() method of PImage. +""" def setup(): @@ -20,4 +20,3 @@ def draw(): background(0, 102, 153) image(img, width / 2, height / 2) image(img, mouseX, mouseY) - diff --git a/mode/examples/Basics/Image/BackgroundImage/BackgroundImage.pyde b/mode/examples/Basics/Image/BackgroundImage/BackgroundImage.pyde index 1346ae6b..33b5c799 100644 --- a/mode/examples/Basics/Image/BackgroundImage/BackgroundImage.pyde +++ b/mode/examples/Basics/Image/BackgroundImage/BackgroundImage.pyde @@ -1,10 +1,10 @@ """ - * Background Image. - * - * This example presents the fastest way to load a background image - * into Processing. To load an image as the background, it must be - * the same width and height as the program. - """ +Background Image. + +This example presents the fastest way to load a background image +into Processing. To load an image as the background, it must be +the same width and height as the program. +""" y = 0 @@ -26,4 +26,3 @@ def draw(): y += 1 if y > height: y = 0 - diff --git a/mode/examples/Basics/Image/CreateImage/CreateImage.pyde b/mode/examples/Basics/Image/CreateImage/CreateImage.pyde index 7340c784..cf75f1fa 100644 --- a/mode/examples/Basics/Image/CreateImage/CreateImage.pyde +++ b/mode/examples/Basics/Image/CreateImage/CreateImage.pyde @@ -1,9 +1,9 @@ """ - * Create Image. - * - * The createImage() function provides a fresh buffer of pixels to play with. - * This example creates an image gradient. - """ +Create Image. + +The createImage() function provides a fresh buffer of pixels to play with. +This example creates an image gradient. +""" def setup(): @@ -20,4 +20,3 @@ def draw(): background(0) image(img, 90, 80) image(img, mouseX - img.width / 2, mouseY - img.height / 2) - diff --git a/mode/examples/Basics/Image/LoadDisplayImage/LoadDisplayImage.pyde b/mode/examples/Basics/Image/LoadDisplayImage/LoadDisplayImage.pyde index 3cadcea6..5a957200 100644 --- a/mode/examples/Basics/Image/LoadDisplayImage/LoadDisplayImage.pyde +++ b/mode/examples/Basics/Image/LoadDisplayImage/LoadDisplayImage.pyde @@ -1,9 +1,9 @@ """ - * Load and Display - * - * Images can be loaded and displayed to the screen at their actual size - * or any other size. - """ +Load and Display + +Images can be loaded and displayed to the screen at their actual size +or any other size. +""" def setup(): @@ -20,4 +20,3 @@ def draw(): image(img, 0, 0) # Displays the image at point (0, height/2) at half of its size image(img, 0, height / 2, img.width / 2, img.height / 2) - diff --git a/mode/examples/Basics/Image/Pointillism/Pointillism.pyde b/mode/examples/Basics/Image/Pointillism/Pointillism.pyde index 8db6ef24..7768311a 100644 --- a/mode/examples/Basics/Image/Pointillism/Pointillism.pyde +++ b/mode/examples/Basics/Image/Pointillism/Pointillism.pyde @@ -1,11 +1,11 @@ """ - * Pointillism - * by Daniel Shiffman. - * - * Mouse horizontal location controls size of dots. - * Creates a simple pointillist effect using ellipses colored - * according to pixels in an image. - """ +Pointillism +by Daniel Shiffman. + +Mouse horizontal location controls size of dots. +Creates a simple pointillist effect using ellipses colored +according to pixels in an image. +""" smallPoint = 4 largePoint = 40 @@ -26,4 +26,3 @@ def draw(): pix = img.get(x, y) fill(pix, 128) ellipse(x, y, pointillize, pointillize) - diff --git a/mode/examples/Basics/Image/RequestImage/RequestImage.pyde b/mode/examples/Basics/Image/RequestImage/RequestImage.pyde index c12660bd..75938857 100644 --- a/mode/examples/Basics/Image/RequestImage/RequestImage.pyde +++ b/mode/examples/Basics/Image/RequestImage/RequestImage.pyde @@ -1,15 +1,16 @@ """ - * Request Image - * by Ira Greenberg ( From Processing for Flash Developers). - * - * Shows how to use the requestImage() function with preloader animation. - * The requestImage() function loads images on a separate thread so that - * the sketch does not freeze while they load. It's very useful when you are - * loading large images. - * - * These images are small for a quick download, but try it with your own huge - * images to get the full effect. - """ +Request Image +by Ira Greenberg ( From Processing for Flash Developers). + +Shows how to use the requestImage() function with preloader animation. +The requestImage() function loads images on a separate thread so that +the sketch does not freeze while they load. It's very useful when you are +loading large images. + +These images are small for a quick download, but try it with your own huge +images to get the full effect. +""" + imgCount = 12 imgs = [] @@ -57,7 +58,7 @@ theta = 0 def runLoaderAni(): global loaderX, loaderY, theta - + # Only run when images are loading if not all(loadStates): ellipse(loaderX, loaderY, 10, 10) @@ -67,4 +68,3 @@ def runLoaderAni(): # Reposition ellipse if it goes off the screen if loaderX > width + 5: loaderX = -5 - diff --git a/mode/examples/Basics/Image/Transparency/Transparency.pyde b/mode/examples/Basics/Image/Transparency/Transparency.pyde index 6a66e778..72a3a525 100644 --- a/mode/examples/Basics/Image/Transparency/Transparency.pyde +++ b/mode/examples/Basics/Image/Transparency/Transparency.pyde @@ -1,10 +1,10 @@ """ - * Transparency. - * - * Move the pointer left and right across the image to change - * its position. This program overlays one image over another - * by modifying the alpha value of the image with the tint() function. - """ +Transparency. + +Move the pointer left and right across the image to change +its position. This program overlays one image over another +by modifying the alpha value of the image with the tint() function. +""" offset = 0 easing = 0.05 @@ -23,4 +23,3 @@ def draw(): offset += dx * easing tint(255, 127) # Display at half opacity image(img, offset, 0) - diff --git a/mode/examples/Basics/Input/KeyboardFunctions/KeyboardFunctions.pyde b/mode/examples/Basics/Input/KeyboardFunctions/KeyboardFunctions.pyde index 83b4134a..b761f629 100644 --- a/mode/examples/Basics/Input/KeyboardFunctions/KeyboardFunctions.pyde +++ b/mode/examples/Basics/Input/KeyboardFunctions/KeyboardFunctions.pyde @@ -55,10 +55,12 @@ def draw(): def keyPressed(): global newletter, x, y, letterHeight - + if key != CODED: + key_code = ord(key) + else: + key_code = keyCode # If the key is between 'A'(65) to 'Z' and 'a' to 'z'(122) - key_code = ord(key) - if (key_code >= A_code and key_code <= Z_code) or (key_code >= a_code and key_code <= z_code): + if A_code <= key_code <= Z_code or a_code <= key_code <= z_code: if key_code <= Z_code: keyIndex = key_code - A_code letterHeight = maxHeight diff --git a/mode/examples/Basics/Lists/List/List.pyde b/mode/examples/Basics/Lists/List/List.pyde index 0bbbac56..57db123a 100644 --- a/mode/examples/Basics/Lists/List/List.pyde +++ b/mode/examples/Basics/Lists/List/List.pyde @@ -1,14 +1,14 @@ """ - * List. - * - * A list is an ordered collection of data. Each piece of data in - * a list is identified by an index number representing its position in - * the list. Lists are zero based, which means that the first - * element in the list is [0], the second element is [1], and so on. - * In this example, an array named "coswav" is created and - * filled with the cosine values. This data is displayed three - * separate ways on the screen. - """ +List. + +A list is an ordered collection of data. Each piece of data in +a list is identified by an index number representing its position in +the list. Lists are zero based, which means that the first +element in the list is [0], the second element is [1], and so on. +In this example, an array named "coswav" is created and +filled with the cosine values. This data is displayed three +separate ways on the screen. +""" # You can create a new, empty list with a pair of square brackets: coswave = [] @@ -40,4 +40,3 @@ def draw(): for i in range(0, width, 2): stroke(255 - coswave[i] * 255) line(i, y1, i, y2) - diff --git a/mode/examples/Basics/Lists/List2D/List2D.pyde b/mode/examples/Basics/Lists/List2D/List2D.pyde index f18a2b6b..5b9eb6af 100644 --- a/mode/examples/Basics/Lists/List2D/List2D.pyde +++ b/mode/examples/Basics/Lists/List2D/List2D.pyde @@ -1,12 +1,12 @@ """ - * List 2D. - * - * Demonstrates the syntax for creating a two-dimensional (2D) list, - * which, in Python, is simply a list of lists. - * Values in a 2D list are accessed through two index values. - * 2D arrays are useful for storing images. In this example, each dot - * is colored in relation to its distance from the center of the image. - """ +List 2D. + +Demonstrates the syntax for creating a two-dimensional (2D) list, +which, in Python, is simply a list of lists. +Values in a 2D list are accessed through two index values. +2D arrays are useful for storing images. In this example, each dot +is colored in relation to its distance from the center of the image. +""" # By convention, Python constants have UPPERCASE_NAMES. SPACER = 10 @@ -38,4 +38,3 @@ def draw(): for y in range(0, height, SPACER): stroke(distances[x][y]) point(x + SPACER / 2, y + SPACER / 2) - diff --git a/mode/examples/Basics/Lists/ListObjects/ListObjects.pyde b/mode/examples/Basics/Lists/ListObjects/ListObjects.pyde index 23d72c03..d430484c 100644 --- a/mode/examples/Basics/Lists/ListObjects/ListObjects.pyde +++ b/mode/examples/Basics/Lists/ListObjects/ListObjects.pyde @@ -1,8 +1,8 @@ """ - * List Objects. - * - * Demonstrates the syntax for creating a list of custom objects. - """ +List Objects. + +Demonstrates the syntax for creating a list of custom objects. +""" from module import MovingBall @@ -24,4 +24,3 @@ def draw(): for b in balls: b.update() b.draw() - diff --git a/mode/examples/Basics/Math/Map/Map.pyde b/mode/examples/Basics/Math/Map/Map.pyde new file mode 100644 index 00000000..9f576be9 --- /dev/null +++ b/mode/examples/Basics/Math/Map/Map.pyde @@ -0,0 +1,28 @@ +''' + Map. + + Use the map() function to take any number and scale it to a new number + that is more useful for the project that you are working on. For example, use the + numbers from the mouse position to control the size or color of a shape. + In this example, the mouse’s x-coordinate (a number between 0 and 360) is scaled to a + new number to define the color and size of a circle. + + Example ReWritten in Python By: Prabhjot Singh (NITH) + example original in Java mode examples: Math->Maps +''' +def setup(): + size(640, 360) + noStroke() + + +def draw(): + background(0) + + # Scale the mouseX value from 0 to 640 to a range between 0 and 175 + c = map(mouseX, 0, width, 0, 175) + + # Scale the mouseX value from 0 to 640 to a range between 40 and 300 + d = map(mouseX, 0, width, 40, 300) + + fill(255, c, 0) + ellipse(width / 2, height / 2, d, d) diff --git a/mode/examples/Basics/Math/SineWave/SineWave.pyde b/mode/examples/Basics/Math/SineWave/SineWave.pyde index 599cb3ec..d9306e89 100644 --- a/mode/examples/Basics/Math/SineWave/SineWave.pyde +++ b/mode/examples/Basics/Math/SineWave/SineWave.pyde @@ -1,8 +1,8 @@ """ Sine Wave -by Daniel Shiffman. +by Daniel Shiffman. -Render a simple sine wave. +Render a simple sine wave. """ xspacing = 16 # How far apart should each horizontal location be spaced @@ -14,14 +14,13 @@ period = 500.0 # How many pixels before the wave repeats # Value for incrementing X, a function of period and xspacing dx = (TWO_PI / period) * xspacing -# Using a list to store height values for the wave. -yvalues = None - def setup(): size(640, 360) global w # Width of entire wave w = width + 16 + # Using a list to store height values for the wave. + global yvalues yvalues = [0.0] * (w / xspacing) @@ -48,4 +47,3 @@ def renderWave(): # A simple way to draw the wave with an ellipse at each location for x in range(len(yvalues)): ellipse(x * xspacing, height / 2 + yvalues[x], 16, 16) - diff --git a/mode/examples/Basics/Objects/MultipleConstructors/MultipleConstructors.pyde b/mode/examples/Basics/Objects/MultipleConstructors/MultipleConstructors.pyde new file mode 100644 index 00000000..ea04ef04 --- /dev/null +++ b/mode/examples/Basics/Objects/MultipleConstructors/MultipleConstructors.pyde @@ -0,0 +1,48 @@ +''' + Multiple Constructors + + A class can have multiple constructors that assign the fields in different ways. + Sometimes it's beneficial to specify every aspect of an object's data by assigning + parameters to the fields, but other times it might be appropriate to define only + one or a few. + +In Python, as there is no method overloading, one can provide different ways of creating +instances by setting default values for parameters in the __init__ method. +''' + +def setup(): + size(640, 360) + background(204) + noLoop() + + global spots + spots = (Spot(), + Spot(x=120, y=70), + Spot(width / 2, height / 2, 120), + Spot(radius=10), + ) + +def draw(): + for sp in spots: + sp.display() + + +class Spot: + + def __init__(self, x=None, y=None, radius=40): + if x is None: + self.x = width / 4 + else: + self.x = x + + if y is None: + self.y = height / 2 + else: + self.y = y + + self.radius = radius + self.diam = radius * 2 + + + def display(self): + ellipse(self.x, self.y, self.diam, self.diam) diff --git a/mode/examples/Basics/Objects/Objects/Objects.pyde b/mode/examples/Basics/Objects/Objects/Objects.pyde index e113880b..2b387435 100644 --- a/mode/examples/Basics/Objects/Objects/Objects.pyde +++ b/mode/examples/Basics/Objects/Objects/Objects.pyde @@ -1,6 +1,6 @@ """ Objects -by hbarragan. +by hbarragan. Move the cursor across the image to change the speed and positions of the geometry. The class MRect defines a group of lines. @@ -8,14 +8,15 @@ of the geometry. The class MRect defines a group of lines. rects = [] + def setup(): size(640, 360) fill(255, 204) noStroke() - rects.append(MRect(1, 134.0, 0.532, 0.1 * height, 10.0, 60.0)) - rects.append(MRect(2, 44.0, 0.166, 0.3 * height, 5.0, 50.0)) - rects.append(MRect(2, 58.0, 0.332, 0.4 * height, 10.0, 35.0)) - rects.append(MRect(1, 120.0, 0.0498, 0.9 * height, 15.0, 60.0)) + rects.append(MRect(1, 134.0, 0.532, 0.1 * height, 10.0, 60)) + rects.append(MRect(2, 44.0, 0.166, 0.3 * height, 5.0, 50)) + rects.append(MRect(2, 58.0, 0.332, 0.4 * height, 10.0, 35)) + rects.append(MRect(1, 120.0, 0.0498, 0.9 * height, 15.0, 60)) def draw(): diff --git a/mode/examples/Basics/Shape/ShapeVertices/ShapeVertices.pyde b/mode/examples/Basics/Shape/ShapeVertices/ShapeVertices.pyde new file mode 100644 index 00000000..37b97502 --- /dev/null +++ b/mode/examples/Basics/Shape/ShapeVertices/ShapeVertices.pyde @@ -0,0 +1,37 @@ +""" +Shape Vertices. + +How to iterate over the vertices of a shape. +When loading an obj or SVG, getVertexCount() +will typically return 0 since all the vertices +are in the child shapes. +You should iterate through the children and then +iterate through their vertices. +""" + + +def setup(): + size(640, 360) + # Load the shape + global uk + uk = loadShape("uk.svg") + + +def draw(): + background(51) + # Center where we will draw all the vertices + translate(width / 2 - uk.width / 2, height / 2 - uk.height / 2) + + # Iterate over the children + children = uk.getChildCount() + for i in xrange(children): + child = uk.getChild(i) + total = child.getVertexCount() + + # Now we can actually get the vertices from each child + for j in xrange(total): + v = child.getVertex(j) + # Cycling brightness for each vertex + stroke((frameCount + (i + 1) * j) % 255) + # Just a dot for each one + point(v.x, v.y) diff --git a/mode/examples/Basics/Shape/ShapeVertices/data/uk.svg b/mode/examples/Basics/Shape/ShapeVertices/data/uk.svg new file mode 100644 index 00000000..fb565514 --- /dev/null +++ b/mode/examples/Basics/Shape/ShapeVertices/data/uk.svg @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mode/examples/Basics/Structure/CreateGraphics/CreateGraphics.pyde b/mode/examples/Basics/Structure/CreateGraphics/CreateGraphics.pyde index 64e76c5f..a3c4f300 100644 --- a/mode/examples/Basics/Structure/CreateGraphics/CreateGraphics.pyde +++ b/mode/examples/Basics/Structure/CreateGraphics/CreateGraphics.pyde @@ -1,11 +1,11 @@ """ - * Create Graphics. - * - * The createGraphics() function creates an object from the PGraphics class - * PGraphics is the main graphics and rendering context for Processing. - * The beginDraw() method is necessary to prepare for drawing and endDraw() is - * necessary to finish. Use this class if you need to draw into an off-screen - * graphics buffer or to maintain two contexts with different properties. +Create Graphics. + +The createGraphics() function creates an object from the PGraphics class +PGraphics is the main graphics and rendering context for Processing. +The beginDraw() method is necessary to prepare for drawing and endDraw() is +necessary to finish. Use this class if you need to draw into an off-screen +graphics buffer or to maintain two contexts with different properties. """ @@ -31,4 +31,3 @@ def draw(): # Draw the offscreen buffer to the screen with image() image(pg, 120, 60) - diff --git a/mode/examples/Basics/Structure/Functions/Functions.pyde b/mode/examples/Basics/Structure/Functions/Functions.pyde index 8382f073..01b8254f 100644 --- a/mode/examples/Basics/Structure/Functions/Functions.pyde +++ b/mode/examples/Basics/Structure/Functions/Functions.pyde @@ -1,9 +1,9 @@ """ - * Functions. - * - * The drawTarget() function makes it easy to draw many distinct targets. - * Each call to drawTarget() specifies the position, size, and number of - * rings for each target. +Functions. + +The drawTarget() function makes it easy to draw many distinct targets. +Each call to drawTarget() specifies the position, size, and number of +rings for each target. """ @@ -26,4 +26,3 @@ def drawTarget(xloc, yloc, size, num): for i in range(num): fill(i * grayvalues) ellipse(xloc, yloc, size - i * steps, size - i * steps) - diff --git a/mode/examples/Basics/Structure/NoLoop/NoLoop.pyde b/mode/examples/Basics/Structure/NoLoop/NoLoop.pyde index c8e66db6..d7934247 100644 --- a/mode/examples/Basics/Structure/NoLoop/NoLoop.pyde +++ b/mode/examples/Basics/Structure/NoLoop/NoLoop.pyde @@ -1,16 +1,16 @@ """ - * No Loop. - * - * The noLoop() function causes draw() to only - * execute once. Without calling noLoop(), the - * code inside draw() is run continually. - """ +No Loop. + +The noLoop() function causes draw() to only +execute once. Without calling noLoop(), the +code inside draw() is run continually. +""" y = 180 def setup(): - """ - The statements in the setup() function + """ + The statements in the setup() function execute once when the program begins """ size(640, 360) # Size should be the first statement @@ -31,4 +31,3 @@ def draw(): if (y < 0): y = height line(0, y, width, y) - diff --git a/mode/examples/Basics/Structure/SetupDraw/SetupDraw.pyde b/mode/examples/Basics/Structure/SetupDraw/SetupDraw.pyde index abd44e58..0f8ee6ad 100644 --- a/mode/examples/Basics/Structure/SetupDraw/SetupDraw.pyde +++ b/mode/examples/Basics/Structure/SetupDraw/SetupDraw.pyde @@ -1,9 +1,9 @@ """ - * Setup and Draw. - * - * The code inside the draw() function runs continuously - * from top to bottom until the program is stopped. - """ +Setup and Draw. + +The code inside the draw() function runs continuously +from top to bottom until the program is stopped. +""" y = 100 @@ -31,4 +31,3 @@ def draw(): y = height line(0, y, width, y) - diff --git a/mode/examples/Basics/Transform/Arm/Arm.pyde b/mode/examples/Basics/Transform/Arm/Arm.pyde index 4b9fbfa2..28e75763 100644 --- a/mode/examples/Basics/Transform/Arm/Arm.pyde +++ b/mode/examples/Basics/Transform/Arm/Arm.pyde @@ -30,7 +30,7 @@ def draw(): segment(segLength, 0, angle2) -def segment(s, y, a): +def segment(x, y, a): translate(x, y) rotate(a) line(0, 0, segLength, 0) diff --git a/mode/examples/Basics/Typography/Letters/Letters.pyde b/mode/examples/Basics/Typography/Letters/Letters.pyde index efd39b15..98bf99ab 100644 --- a/mode/examples/Basics/Typography/Letters/Letters.pyde +++ b/mode/examples/Basics/Typography/Letters/Letters.pyde @@ -1,9 +1,9 @@ """ - * Letters. - * - * Draws letters to the screen. This requires loading a font, - * setting the font, and then drawing the letters. - """ +Letters. + +Draws letters to the screen. This requires loading a font, +setting the font, and then drawing the letters. +""" def setup(): @@ -35,4 +35,3 @@ def draw(): text(letter, x, y) # Increment the counter counter += 1 - diff --git a/mode/examples/Basics/Typography/Words/Words.pyde b/mode/examples/Basics/Typography/Words/Words.pyde index e23b8147..df30c38f 100644 --- a/mode/examples/Basics/Typography/Words/Words.pyde +++ b/mode/examples/Basics/Typography/Words/Words.pyde @@ -1,10 +1,10 @@ """ - * Words. - * - * The text() function is used for writing words to the screen. - * The letters can be aligned left, center, or right with the - * textAlign() function. - """ +Words. + +The text() function is used for writing words to the screen. +The letters can be aligned left, center, or right with the +textAlign() function. +""" def setup(): @@ -37,4 +37,3 @@ def drawType(x): text("san", x, 165) fill(255) text("shi", x, 210) - diff --git a/mode/examples/Basics/Web/EmbeddedLinks/EmbeddedLinks.pyde b/mode/examples/Basics/Web/EmbeddedLinks/EmbeddedLinks.pyde index bb955523..f8ab535a 100644 --- a/mode/examples/Basics/Web/EmbeddedLinks/EmbeddedLinks.pyde +++ b/mode/examples/Basics/Web/EmbeddedLinks/EmbeddedLinks.pyde @@ -1,12 +1,9 @@ """ Loading URLs. -Click on the left button to open a different URL in the same window (Only -works online). Click on the right button to open a URL in a browser window. +Click on the button to open a URL in a browser """ -overLeftButton = False -overRightButton = False - +overButton = False def setup(): size(640, 360) @@ -15,17 +12,7 @@ def setup(): def draw(): background(204) - # Left button - if overLeftButton: - fill(255) - else: - noFill() - - rect(20, 60, 75, 75) - rect(50, 90, 15, 15) - - # Right button - if overRightButton: + if overButton: fill(255) else: noFill() @@ -37,10 +24,8 @@ def draw(): def mousePressed(): - if overLeftButton: + if overButton: link("http://www.processing.org") - elif overRightButton: - link("http://www.processing.org", "_new") def mouseMoved(): @@ -52,7 +37,5 @@ def mouseDragged(): def checkButtons(): - global overLeftButton, overRightButton - overLeftButton = 20 < mouseX < 95 and 60 < mouseY < 135; - overRightButton = 105 < mouseX < 180 and 60 < mouseY < 135; - + global overButton + overButton = 105 < mouseX < 180 and 60 < mouseY < 135; diff --git a/mode/examples/Contributed Libraries in Python/Arduino-Firmata/arduino_input/arduino_input.pyde b/mode/examples/Contributed Libraries in Python/Arduino-Firmata/arduino_input/arduino_input.pyde new file mode 100644 index 00000000..d378c8a5 --- /dev/null +++ b/mode/examples/Contributed Libraries in Python/Arduino-Firmata/arduino_input/arduino_input.pyde @@ -0,0 +1,72 @@ +""" +arduino_input + +Demonstrates the reading of digital and analog pins of an Arduino board +running the StandardFirmata firmware. + +To use: +* Using the Arduino software, upload the StandardFirmata example (located + in Examples > Firmata > StandardFirmata) to your Arduino board. +* Run this sketch and look at the list of serial ports printed in the + message area below. Note the index of the port corresponding to your + Arduino board (the numbering starts at 0). (Unless your Arduino board + happens to be at index 0 in the list, the sketch probably won't work. + Stop it and proceed with the instructions.) +* Modify the "arduino = Arduino(...)" line below, changing the number + in Arduino.list()[0] to the number corresponding to the serial port of + your Arduino board. Alternatively, you can replace Arduino.list()[0] + with the name of the serial port, in double quotes, e.g. "COM5" on Windows + or "/dev/tty.usbmodem621" on Mac. +* Run this sketch. The squares show the values of the digital inputs (HIGH + pins are filled, LOW pins are not). The circles show the values of the + analog inputs (the bigger the circle, the higher the reading on the + corresponding analog input pin). The pins are laid out as if the Arduino + were held with the logo upright (i.e. pin 13 is at the upper left). Note + that the readings from unconnected pins will fluctuate randomly. + +For more information, see: http:#playground.arduino.cc/Interfacing/Processing +""" + +add_library('serial') # replaces import processing.serial.*; +add_library('arduino') # replaces import cc.arduino.*; + +off = color(4, 79, 111) +on = color(84, 145, 158) + +def setup(): + global arduino + size(470, 280) + + # Prints out the available serial ports. + println(Arduino.list()) + + # Modify this line, by changing the "0" to the index of the serial + # port corresponding to your Arduino board (as it appears in the list + # printed by the line above). + arduino = Arduino(this, Arduino.list()[0], 57600) + + # Alternatively, use the name of the serial port corresponding to your + # Arduino (in double-quotes), as in the following line. + # arduino = Arduino(this, "/dev/tty.usbmodem621", 57600) + + # Set the Arduino digital pins as inputs. + for i in range(14): # for pins 0 to 13 + arduino.pinMode(i, Arduino.INPUT) + +def draw(): + background(off) + stroke(on) + + # Draw a filled box for each digital pin that's HIGH (5 volts). + for i in range(14): # from 0 to 13 + if arduino.digitalRead(i) == Arduino.HIGH: + fill(on) + else: + fill(off) + rect(420 - i * 30, 30, 20, 20) + + # Draw a circle whose size corresponds to the value of an analog input. + noFill() + for i in range(6): # for analog pins from A0 to A5 + ellipse(280 + i * 30, 240, arduino.analogRead(i) / 16, + arduino.analogRead(i) / 16) diff --git a/mode/examples/Contributed Libraries in Python/OpenCV/LiveCamTest/LiveCamTest.pyde b/mode/examples/Contributed Libraries in Python/OpenCV/LiveCamTest/LiveCamTest.pyde index d5439415..99d0ca87 100644 --- a/mode/examples/Contributed Libraries in Python/OpenCV/LiveCamTest/LiveCamTest.pyde +++ b/mode/examples/Contributed Libraries in Python/OpenCV/LiveCamTest/LiveCamTest.pyde @@ -34,4 +34,5 @@ def captureEvent(c): c.read() def mousePressed(): + global show_fps show_fps = not show_fps diff --git a/mode/examples/Contributed Libraries in Python/PeasyCam/HelloPeasy/HelloPeasy.pyde b/mode/examples/Contributed Libraries in Python/PeasyCam/HelloPeasy/HelloPeasy.pyde new file mode 100644 index 00000000..b44decd2 --- /dev/null +++ b/mode/examples/Contributed Libraries in Python/PeasyCam/HelloPeasy/HelloPeasy.pyde @@ -0,0 +1,19 @@ +add_library('peasycam') + +def setup(): + global cam + size(200, 200, P3D) + cam = PeasyCam(this, 100) + cam.setMinimumDistance(50) + cam.setMaximumDistance(500) + +def draw(): + rotateX(-.5) + rotateY(-.5) + background(0) + fill(255, 0, 0) + box(30) + with pushMatrix(): + translate(0,0,20) + fill(0,0,255) + box(5) diff --git a/mode/examples/Contributed Libraries in Python/PeasyCam/cameraHUD/cameraHUD.pyde b/mode/examples/Contributed Libraries in Python/PeasyCam/cameraHUD/cameraHUD.pyde new file mode 100644 index 00000000..ab9dc978 --- /dev/null +++ b/mode/examples/Contributed Libraries in Python/PeasyCam/cameraHUD/cameraHUD.pyde @@ -0,0 +1,29 @@ +""" PeasyCam provides a dead-simple mouse-driven camera for Processing. + full documentation at http://mrfeinberg.com/peasycam/ +""" + +add_library('peasycam') + +def setup(): + global camera + size(200, 200, P3D) + camera = PeasyCam(this, 100) + camera.setMinimumDistance(50) + camera.setMaximumDistance(500) + +def draw(): + rotateX(-.5) + rotateY(-.5) + background(0) + fill(255, 0, 0) + box(30) + with pushMatrix(): + translate(0, 0, 20) + fill(0, 0, 255) + box(5) + camera.beginHUD() # start drawing relative to the camera view + fill(255) + rect(20, 10, 120, 30) + fill(0) + text(str(frameRate), 30, 30) + camera.endHUD() # and don't forget to stop/close with this! diff --git a/mode/examples/Demos/Graphics/LowLevelGL/LowLevelGL.pyde b/mode/examples/Demos/Graphics/LowLevelGL/LowLevelGL.pyde deleted file mode 100644 index bcdc5814..00000000 --- a/mode/examples/Demos/Graphics/LowLevelGL/LowLevelGL.pyde +++ /dev/null @@ -1,89 +0,0 @@ -# Draws a triangle using low-level OpenGL calls. - -import array - -from java.nio import ByteBuffer, ByteOrder -from java.lang import Float - - -def allocateDirectFloatBuffer(n): - return (ByteBuffer.allocateDirect(n * Float.SIZE / 8). - order(ByteOrder.nativeOrder()).asFloatBuffer()) - -vertices = array.array('f', (0,) * 12) -vertData = allocateDirectFloatBuffer(12) -colors = array.array('f', (0,) * 12) -colorData = allocateDirectFloatBuffer(12) - - -def setup(): - size(640, 360, P3D) - global sh - # Loads a shader to render geometry w/out textures and lights. - sh = loadShader("frag.glsl", "vert.glsl") - - -def draw(): - background(0) - - # The geometric transformations will be automatically passed - # to the shader. - rotate(frameCount * 0.01, width, height, 0) - - updateGeometry() - - pgl = g.beginPGL() - sh.bind() - - vertLoc = pgl.getAttribLocation(sh.glProgram, "vertex") - colorLoc = pgl.getAttribLocation(sh.glProgram, "color") - - pgl.enableVertexAttribArray(vertLoc) - pgl.enableVertexAttribArray(colorLoc) - - pgl.vertexAttribPointer(vertLoc, 4, PGL.FLOAT, False, 0, vertData) - pgl.vertexAttribPointer(colorLoc, 4, PGL.FLOAT, False, 0, colorData) - pgl.drawArrays(PGL.TRIANGLES, 0, 3) - pgl.disableVertexAttribArray(vertLoc) - pgl.disableVertexAttribArray(colorLoc) - - sh.unbind() - g.endPGL() - - -def updateGeometry(): - # Vertex 1 - vertices[0] = 0 - vertices[1] = 0 - vertices[2] = 0 - vertices[3] = 1 - colors[0] = 1 - colors[1] = 0 - colors[2] = 0 - colors[3] = 1 - # Corner 2 - vertices[4] = width / 2 - vertices[5] = height - vertices[6] = 0 - vertices[7] = 1 - colors[4] = 0 - colors[5] = 1 - colors[6] = 0 - colors[7] = 1 - # Corner 3 - vertices[8] = width - vertices[9] = 0 - vertices[10] = 0 - vertices[11] = 1 - colors[8] = 0 - colors[9] = 0 - colors[10] = 1 - colors[11] = 1 - - vertData.rewind() - vertData.put(vertices) - vertData.position(0) - - colorData.rewind() - colorData.put(colors) - colorData.position(0) diff --git a/mode/examples/Demos/Graphics/LowLevelGLVboInterleaved/LowLevelGLVboInterleaved.pyde b/mode/examples/Demos/Graphics/LowLevelGLVboInterleaved/LowLevelGLVboInterleaved.pyde new file mode 100644 index 00000000..2925f0fc --- /dev/null +++ b/mode/examples/Demos/Graphics/LowLevelGLVboInterleaved/LowLevelGLVboInterleaved.pyde @@ -0,0 +1,138 @@ +# Draws a triangle using low-level OpenGL calls. + +import array + +from java.nio import ByteBuffer, ByteOrder, IntBuffer +from java.lang import Float + +VERT_CMP_COUNT = 4 # vertex component count (x, y, z, w) -> 4 +CLR_CMP_COUNT = 4 # color component count (r, g, b, a) -> 4 + +def allocateDirectFloatBuffer(n): + return (ByteBuffer.allocateDirect(n * Float.SIZE / 8). + order(ByteOrder.nativeOrder()).asFloatBuffer()) + +attribs = array.array('f', (0,) * 24) +attribBuffer = allocateDirectFloatBuffer(24) + +def setup(): + size(640, 360, P3D) + + # Loads a shader to render geometry w/out textures and lights. + global sh + sh = loadShader("frag.glsl", "vert.glsl") + + with beginPGL() as pgl: + intBuffer = IntBuffer.allocate(1) + pgl.genBuffers(1, intBuffer) + global attribVboId + attribVboId = intBuffer.get(0) + +def draw(): + with g.beginPGL() as pgl: + + background(0) + + # The geometric transformations will be automatically passed + # to the shader. + rotate(frameCount * 0.01, width, height, 0) + + updateGeometry() + + sh.bind() + + # get "vertex" attribute location in the shader + vertLoc = pgl.getAttribLocation(sh.glProgram, "vertex") + # enable array for "vertex" attribute + pgl.enableVertexAttribArray(vertLoc) + + # get "color" attribute location in the shader + colorLoc = pgl.getAttribLocation(sh.glProgram, "color") + # enable array for "color" attribute + pgl.enableVertexAttribArray(colorLoc) + + # BUFFER LAYOUT from updateGeometry() + + # xyzwrgbaxyzwrgbaxyzwrgba... + # + # |v1 |v2 |v3 |... + # |0 |4 |8 |12 |16 |20 |... + # |xyzw|rgba|xyzw|rgba|xyzw|rgba|... + # + # stride (values per vertex) is 8 floats + # vertex offset is 0 floats (starts at the beginning of each line) + # color offset is 4 floats (starts after vertex coords) + # + # |0 |4 |8 + # v1 |xyzw|rgba| + # v2 |xyzw|rgba| + # v3 |xyzw|rgba| + # |... + + stride = (VERT_CMP_COUNT + CLR_CMP_COUNT) * Float.BYTES + vertexOffset = 0 * Float.BYTES + colorOffset = VERT_CMP_COUNT * Float.BYTES + + # bind VBO + pgl.bindBuffer(PGL.ARRAY_BUFFER, attribVboId) + # fill VBO with data + pgl.bufferData( + PGL.ARRAY_BUFFER, Float.BYTES * len(attribs), attribBuffer, PGL.DYNAMIC_DRAW) + # associate currently bound VBO with "vertex" shader attribute + pgl.vertexAttribPointer( + vertLoc, VERT_CMP_COUNT, PGL.FLOAT, False, stride, vertexOffset) + # associate currently bound VBO with "color" shader attribute + pgl.vertexAttribPointer( + colorLoc, CLR_CMP_COUNT, PGL.FLOAT, False, stride, colorOffset) + # unbind VBO + pgl.bindBuffer(PGL.ARRAY_BUFFER, 0) + + pgl.drawArrays(PGL.TRIANGLES, 0, 3) + + # disable arrays for attributes before unbinding the shader + pgl.disableVertexAttribArray(vertLoc) + pgl.disableVertexAttribArray(colorLoc) + + sh.unbind() + +def updateGeometry(): + # Vertex 1 + attribs[0] = 0 + attribs[1] = 0 + attribs[2] = 0 + attribs[3] = 1 + + # Color 1 + attribs[4] = 1 + attribs[5] = 0 + attribs[6] = 0 + attribs[7] = 1 + + # Vertex 2 + attribs[8] = width/2 + attribs[9] = height + attribs[10] = 0 + attribs[11] = 1 + + # Color 2 + attribs[12] = 0 + attribs[13] = 1 + attribs[14] = 0 + attribs[15] = 1 + + # Vertex 3 + attribs[16] = width + attribs[17] = 0 + attribs[18] = 0 + attribs[19] = 1 + + # Color 3 + attribs[20] = 0 + attribs[21] = 0 + attribs[22] = 1 + attribs[23] = 1 + + attribBuffer.rewind() + attribBuffer.put(attribs) + attribBuffer.rewind() + \ No newline at end of file diff --git a/mode/examples/Demos/Graphics/LowLevelGL/data/frag.glsl b/mode/examples/Demos/Graphics/LowLevelGLVboInterleaved/data/frag.glsl similarity index 100% rename from mode/examples/Demos/Graphics/LowLevelGL/data/frag.glsl rename to mode/examples/Demos/Graphics/LowLevelGLVboInterleaved/data/frag.glsl diff --git a/mode/examples/Demos/Graphics/LowLevelGL/data/vert.glsl b/mode/examples/Demos/Graphics/LowLevelGLVboInterleaved/data/vert.glsl similarity index 100% rename from mode/examples/Demos/Graphics/LowLevelGL/data/vert.glsl rename to mode/examples/Demos/Graphics/LowLevelGLVboInterleaved/data/vert.glsl diff --git a/mode/examples/Demos/Graphics/LowLevelGLVboSeparate/LowLevelGLVboSeparate.pyde b/mode/examples/Demos/Graphics/LowLevelGLVboSeparate/LowLevelGLVboSeparate.pyde new file mode 100644 index 00000000..dd5c868a --- /dev/null +++ b/mode/examples/Demos/Graphics/LowLevelGLVboSeparate/LowLevelGLVboSeparate.pyde @@ -0,0 +1,164 @@ +# Draws a triangle using low-level OpenGL calls. + +import array + +from java.nio import ByteBuffer, ByteOrder, IntBuffer +from java.lang import Float + +VERT_CMP_COUNT = 4 # vertex component count (x, y, z, w) -> 4 +CLR_CMP_COUNT = 4 # color component count (r, g, b, a) -> 4 + +def allocateDirectFloatBuffer(n): + return (ByteBuffer.allocateDirect(n * Float.SIZE / 8). + order(ByteOrder.nativeOrder()).asFloatBuffer()) + +vertices = array.array('f', (0,) * 12) +colors = array.array('f', (0,) * 12) + +vertexBuffer = allocateDirectFloatBuffer(12) +colorBuffer = allocateDirectFloatBuffer(12) + +def setup(): + size(640, 360, P3D) + + # Loads a shader to render geometry w/out textures and lights. + global sh + sh = loadShader("frag.glsl", "vert.glsl") + + with beginPGL() as pgl: + # allocate buffer big enough to get all VBO ids back + intBuffer = IntBuffer.allocate(2) + pgl.genBuffers(2, intBuffer) + global vertexVboId + vertexVboId = intBuffer.get(0) + + global colorVboId + colorVboId = intBuffer.get(1) + +def draw(): + with g.beginPGL() as pgl: + + background(0) + + # The geometric transformations will be automatically passed + # to the shader. + rotate(frameCount * 0.01, width, height, 0) + + updateGeometry() + + sh.bind() + + # get "vertex" attribute location in the shader + vertLoc = pgl.getAttribLocation(sh.glProgram, "vertex") + # enable array for "vertex" attribute + pgl.enableVertexAttribArray(vertLoc) + + # get "color" attribute location in the shader + colorLoc = pgl.getAttribLocation(sh.glProgram, "color") + # enable array for "color" attribute + pgl.enableVertexAttribArray(colorLoc) + + # BUFFER LAYOUT from updateGeometry() + # + # Vertex buffer: + # + # xyzwxyzwxyzw... + # + # |v1 |v2 |v3 |... + # |0 |4 |8 |... + # |xyzw|xyzw|xyzw|... + # + # + # Color buffer: + # + # rgbargbargba... + # + # |v1 |v2 |v3 |... + # |0 |4 |8 |... + # |rgba|rgba|rgba|... + # + # stride (values per vertex) is 4 floats in both cases + # vertex offset is 0 floats in both cases + + vertexStride = VERT_CMP_COUNT * Float.BYTES + colorStride = CLR_CMP_COUNT * Float.BYTES + vertexOffset = 0 * Float.BYTES + colorOffset = 0 * Float.BYTES + + # VERTEX + # bind VBO + pgl.bindBuffer(PGL.ARRAY_BUFFER, vertexVboId) + # fill VBO with data + pgl.bufferData( + PGL.ARRAY_BUFFER, Float.BYTES * len(vertices), vertexBuffer, PGL.DYNAMIC_DRAW) + # associate currently bound VBO with "vertex" shader attribute + pgl.vertexAttribPointer( + vertLoc, VERT_CMP_COUNT, PGL.FLOAT, False, vertexStride, vertexOffset) + + # COLOR + # bind VBO + pgl.bindBuffer(PGL.ARRAY_BUFFER, colorVboId) + # fill VBO with data + pgl.bufferData( + PGL.ARRAY_BUFFER, Float.BYTES * len(colors), colorBuffer, PGL.DYNAMIC_DRAW) + # associate currently bound VBO with "color" shader attribute + pgl.vertexAttribPointer( + colorLoc, CLR_CMP_COUNT, PGL.FLOAT, False, colorStride, colorOffset) + + # unbind VBOs + pgl.bindBuffer(PGL.ARRAY_BUFFER, 0) + + pgl.drawArrays(PGL.TRIANGLES, 0, 3) + + # disable arrays for attributes before unbinding the shader + pgl.disableVertexAttribArray(vertLoc) + pgl.disableVertexAttribArray(colorLoc) + + sh.unbind() + + +def updateGeometry(): + # Vertex 1 + vertices[0] = 0 + vertices[1] = 0 + vertices[2] = 0 + vertices[3] = 1 + + # Color 1 + colors[0] = 1 + colors[1] = 0 + colors[2] = 0 + colors[3] = 1 + + # Vertex 2 + vertices[4] = width / 2 + vertices[5] = height + vertices[6] = 0 + vertices[7] = 1 + + # Color 2 + colors[4] = 0 + colors[5] = 1 + colors[6] = 0 + colors[7] = 1 + + # Vertex 3 + vertices[8] = width + vertices[9] = 0 + vertices[10] = 0 + vertices[11] = 1 + + # Color 3 + colors[8] = 0 + colors[9] = 0 + colors[10] = 1 + colors[11] = 1 + + vertexBuffer.rewind() + vertexBuffer.put(vertices) + vertexBuffer.rewind() + + colorBuffer.rewind() + colorBuffer.put(colors) + colorBuffer.rewind() + \ No newline at end of file diff --git a/mode/examples/Demos/Graphics/LowLevelGLVboSeparate/data/frag.glsl b/mode/examples/Demos/Graphics/LowLevelGLVboSeparate/data/frag.glsl new file mode 100644 index 00000000..16742d2b --- /dev/null +++ b/mode/examples/Demos/Graphics/LowLevelGLVboSeparate/data/frag.glsl @@ -0,0 +1,30 @@ +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2011-12 Ben Fry and Casey Reas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + */ + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +varying vec4 vertColor; + +void main() { + gl_FragColor = vertColor; +} \ No newline at end of file diff --git a/mode/examples/Demos/Graphics/LowLevelGLVboSeparate/data/vert.glsl b/mode/examples/Demos/Graphics/LowLevelGLVboSeparate/data/vert.glsl new file mode 100644 index 00000000..27c255ee --- /dev/null +++ b/mode/examples/Demos/Graphics/LowLevelGLVboSeparate/data/vert.glsl @@ -0,0 +1,31 @@ +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2011-12 Ben Fry and Casey Reas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + */ + +uniform mat4 transform; + +attribute vec4 vertex; +attribute vec4 color; + +varying vec4 vertColor; + +void main() { + gl_Position = transform * vertex; + vertColor = color; +} \ No newline at end of file diff --git a/mode/examples/Demos/Graphics/Trefoil/Surface.py b/mode/examples/Demos/Graphics/Trefoil/Surface.py new file mode 100644 index 00000000..abb8a1ca --- /dev/null +++ b/mode/examples/Demos/Graphics/Trefoil/Surface.py @@ -0,0 +1,103 @@ +""" +Code to draw a trefoil knot surface, normals and texture coordinates. +Adapted from the parametric equations example by Philip Rideout: +http://iphone-3d-programming.labs.oreilly.com/ch03.html +""" + +def createTrefoil(s, ny, nx, tex): + """ + This function draws a trefoil knot surface as a triangle mesh derived + from its parametric equation. + """ + + obj = createShape() + obj.beginShape(TRIANGLES) + obj.texture(tex) + + for j in range(nx): + u0 = float(j) / nx + u1 = float(j + 1) / nx + for i in range(ny): + v0 = float(i) / ny + v1 = float(i + 1) / ny + + p0 = evalPoint(u0, v0) + n0 = evalNormal(u0, v0) + + p1 = evalPoint(u0, v1) + n1 = evalNormal(u0, v1) + + p2 = evalPoint(u1, v1) + n2 = evalNormal(u1, v1) + + # Triangle p0-p1-p2 + obj.normal(n0.x, n0.y, n0.z) + obj.vertex(s * p0.x, s * p0.y, s * p0.z, u0, v0) + obj.normal(n1.x, n1.y, n1.z) + obj.vertex(s * p1.x, s * p1.y, s * p1.z, u0, v1) + obj.normal(n2.x, n2.y, n2.z) + obj.vertex(s * p2.x, s * p2.y, s * p2.z, u1, v1) + + p1 = evalPoint(u1, v0) + n1 = evalNormal(u1, v0) + + # Triangle p0-p2-p1 + obj.normal(n0.x, n0.y, n0.z) + obj.vertex(s * p0.x, s * p0.y, s * p0.z, u0, v0) + obj.normal(n2.x, n2.y, n2.z) + obj.vertex(s * p2.x, s * p2.y, s * p2.z, u1, v1) + obj.normal(n1.x, n1.y, n1.z) + obj.vertex(s * p1.x, s * p1.y, s * p1.z, u1, v0) + + obj.endShape() + return obj + +def evalNormal(u, v): + """ + Evaluates the surface normal corresponding to normalized parameters (u, v) + """ + + # Compute the tangents and their cross product. + p = evalPoint(u, v) + tangU = evalPoint(u + 0.01, v) + tangV = evalPoint(u, v + 0.01) + tangU.sub(p) + tangV.sub(p) + + normUV = tangV.cross(tangU) + normUV.normalize() + return normUV + + +def evalPoint(u, v): + """ + Evaluates the surface point corresponding to normalized parameters (u, v) + """ + + a, b, c, d = 0.5, 0.3, 0.5, 0.1 + s = TWO_PI * u + t = (TWO_PI * (1 - v)) * 2 + + r = a + b * cos(1.5 * t) + x = r * cos(t) + y = r * sin(t) + z = c * sin(1.5 * t) + + dv = PVector() + dv.x = (-1.5 * b * sin(1.5 * t) * cos(t) - + (a + b * cos(1.5 * t)) * sin(t)) + dv.y = (-1.5 * b * sin(1.5 * t) * sin(t) + + (a + b * cos(1.5 * t)) * cos(t)) + dv.z = 1.5 * c * cos(1.5 * t) + + q = dv + q.normalize() + qvn = PVector(q.y, -q.x, 0) + qvn.normalize() + ww = q.cross(qvn) + + pt = PVector() + pt.x = x + d * (qvn.x * cos(s) + ww.x * sin(s)) + pt.y = y + d * (qvn.y * cos(s) + ww.y * sin(s)) + pt.z = z + d * ww.z * sin(s) + return pt diff --git a/mode/examples/Demos/Graphics/Trefoil/Trefoil.pyde b/mode/examples/Demos/Graphics/Trefoil/Trefoil.pyde new file mode 100644 index 00000000..9200ae28 --- /dev/null +++ b/mode/examples/Demos/Graphics/Trefoil/Trefoil.pyde @@ -0,0 +1,42 @@ +""" +Trefoil, Andres Colubri +A parametric surface is textured procedurally +by drawing on an offscreen PGraphics surface. +""" +from Surface import * + + +def setup(): + global pg, trefoil # PGraphics, PShape + size(1024, 768, P3D) + + textureMode(NORMAL) + noStroke() + + # Creating offscreen surface for 3D rendering. + pg = createGraphics(32, 512, P3D) + pg.beginDraw() + pg.background(0, 0) + pg.noStroke() + pg.fill(255, 0, 0, 200) + pg.endDraw() + + # Saving trefoil surface into a PShape3D object + trefoil = createTrefoil(350, 60, 15, pg) + + +def draw(): + background(0) + + pg.beginDraw() + pg.ellipse(random(pg.width), random(pg.height), 4, 4) + pg.endDraw() + + ambient(250, 250, 250) + pointLight(255, 255, 255, 0, 0, 200) + + with pushMatrix(): + translate(width / 2, height / 2, -200) + rotateX(frameCount * PI / 500) + rotateY(frameCount * PI / 500) + shape(trefoil) diff --git a/mode/examples/Demos/Graphics/Wiggling/Wiggling.pyde b/mode/examples/Demos/Graphics/Wiggling/Wiggling.pyde new file mode 100644 index 00000000..e6f468eb --- /dev/null +++ b/mode/examples/Demos/Graphics/Wiggling/Wiggling.pyde @@ -0,0 +1,121 @@ +""" +Press 'w' to start/stop wiggling, space to restore original positions. +""" + +cubeSize = 320 +circleRad = 100 +circleRes = 40 +noiseMag = 1 + +wiggling = False + + +def setup(): + size(1024, 768, P3D) + createCube() + + +def draw(): + background(0) + translate(width / 2, height / 2) + rotateX(frameCount * 0.01) + rotateY(frameCount * 0.01) + shape(cube) + + if wiggling: + pos = None + for i in range(cube.getChildCount()): + face = cube.getChild(i) + for j in range(face.getVertexCount()): + pos = face.getVertex(j, pos) + pos.x += random(-noiseMag / 2.0, +noiseMag / 2.0) + pos.y += random(-noiseMag / 2.0, +noiseMag / 2.0) + pos.z += random(-noiseMag / 2.0, +noiseMag / 2.0) + face.setVertex(j, pos.x, pos.y, pos.z) + + if frameCount % 60 == 0: + println(frameRate) + + +def keyPressed(): + global wiggling + if key == 'w': + wiggling = not wiggling + elif key == ' ': + restoreCube() + elif key == '1': + cube.setStrokeWeight(1) + elif key == '2': + cube.setStrokeWeight(5) + elif key == '3': + cube.setStrokeWeight(10) + + +def createCube(): + global cube + cube = createShape(GROUP) + # Create all faces at front position + for _ in range(6): + face = createShape() + createFaceWithHole(face) + cube.addChild(face) + # Rotate all the faces to their positions + # Front face - already correct + face = cube.getChild(0) + # Back face + face = cube.getChild(1) + face.rotateY(radians(180)) + # Right face + face = cube.getChild(2) + face.rotateY(radians(90)) + # Left face + face = cube.getChild(3) + face.rotateY(radians(-90)) + # Top face + face = cube.getChild(4) + face.rotateX(radians(90)) + # Bottom face + face = cube.getChild(5) + face.rotateX(radians(-90)) + + +def createFaceWithHole(face): + face.beginShape(POLYGON) + face.stroke(255, 0, 0) + face.fill(255) + # Draw main shape Clockwise + face.vertex(-cubeSize / 2, -cubeSize / 2, +cubeSize / 2) + face.vertex(+cubeSize / 2, -cubeSize / 2, +cubeSize / 2) + face.vertex(+cubeSize / 2, +cubeSize / 2, +cubeSize / 2) + face.vertex(-cubeSize / 2, +cubeSize / 2, +cubeSize / 2) + # Draw contour (hole) Counter-Clockwise + face.beginContour() + for i in range(circleRes): + angle = TWO_PI * i / circleRes + x = circleRad * sin(angle) + y = circleRad * cos(angle) + z = +cubeSize / 2 + face.vertex(x, y, z) + face.endContour() + face.endShape(CLOSE) + + +def restoreCube(): + # Rotation of faces is preserved, we just reset them the same way + # as the "front" face and they will stay rotated correctly. + for i in range(6): + face = cube.getChild(i) + restoreFaceWithHole(face) + + +def restoreFaceWithHole(face): + face.setVertex(0, -cubeSize / 2, -cubeSize / 2, +cubeSize / 2) + face.setVertex(1, +cubeSize / 2, -cubeSize / 2, +cubeSize / 2) + face.setVertex(2, +cubeSize / 2, +cubeSize / 2, +cubeSize / 2) + face.setVertex(3, -cubeSize / 2, +cubeSize / 2, +cubeSize / 2) + for i in range(circleRes): + angle = TWO_PI * i / circleRes + x = circleRad * sin(angle) + y = circleRad * cos(angle) + z = +cubeSize / 2 + face.setVertex(4 + i, x, y, z) diff --git a/mode/examples/Demos/Graphics/Yellowtail/Yellowtail.pyde b/mode/examples/Demos/Graphics/Yellowtail/Yellowtail.pyde index af99bed6..e5273f65 100644 --- a/mode/examples/Demos/Graphics/Yellowtail/Yellowtail.pyde +++ b/mode/examples/Demos/Graphics/Yellowtail/Yellowtail.pyde @@ -1,17 +1,17 @@ """ - * Yellowtail - * by Golan Levin (www.flong.com). - * Translated to Python by Jonathan Feinberg. - * - * Click, drag, and release to create a kinetic gesture. - * - * Yellowtail (1998-2000) is an interactive software system for the gestural - * creation and performance of real-time abstract animation. Yellowtail repeats - * a user's strokes end-over-end, enabling simultaneous specification of a - * line's shape and quality of movement. Each line repeats according to its - * own period, producing an ever-changing and responsive display of lively, - * worm-like textures. - """ +Yellowtail +by Golan Levin (www.flong.com). +Translated to Python by Jonathan Feinberg. + +Click, drag, and release to create a kinetic gesture. + +Yellowtail (1998-2000) is an interactive software system for the gestural +creation and performance of real-time abstract animation. Yellowtail repeats +a user's strokes end-over-end, enabling simultaneous specification of a +line's shape and quality of movement. Each line repeats according to its +own period, producing an ever-changing and responsive display of lively, +worm-like textures. +""" from gesture import Gesture @@ -137,4 +137,3 @@ def advanceGesture(gesture): def clearGestures(): for g in gestureArray: g.clear() - diff --git a/mode/examples/Demos/Performance/Esfera/Esfera.pyde b/mode/examples/Demos/Performance/Esfera/Esfera.pyde new file mode 100644 index 00000000..3192806a --- /dev/null +++ b/mode/examples/Demos/Performance/Esfera/Esfera.pyde @@ -0,0 +1,82 @@ +""" +Esfera by David Pena. + +ES - Distribucion aleatoria uniforme sobre la superficie de una esfera. +EN - Uniform random distribution on the surface of a sphere. +""" + +CUANTOS = 16000 # how many +LISTA = [] # list +RADIO = 200 # radius +rx = 0 +ry = 0 + + +def setup(): + global RADIO, LISTA + size(1024, 768, P3D) + RADIO = height / 3.5 + + for _ in range(CUANTOS): + LISTA.append(Pelo()) + + noiseDetail(3) + + +def draw(): + global rx, ry + + background(0) + + rxp = (mouseX - (width / 2)) * 0.005 + ryp = (mouseY - (height / 2)) * 0.005 + rx = rx * 0.9 + rxp * 0.1 + ry = ry * 0.9 + ryp * 0.1 + + translate(width / 2, height / 2) + rotateY(rx) + rotateX(ry) + fill(0) + noStroke() + sphere(RADIO) + + for pelo in LISTA: + pelo.dibujar() + + +class Pelo(): + + """A hair""" + + def __init__(self): + self.z = random(-RADIO, RADIO) + self.phi = random(TWO_PI) + self.largo = random(1.15, 1.2) + self.theta = asin(self.z / RADIO) + + def dibujar(self): + """Draw""" + off = (noise(millis() * 0.0005, sin(self.phi)) - 0.5) * 0.3 + offb = (noise(millis() * 0.0007, sin(self.z) * 0.01) - 0.5) * 0.3 + + thetaff = self.theta + off + phff = self.phi + offb + x = RADIO * cos(self.theta) * cos(self.phi) + y = RADIO * cos(self.theta) * sin(self.phi) + z = RADIO * sin(self.theta) + + xo = RADIO * cos(thetaff) * cos(phff) + yo = RADIO * cos(thetaff) * sin(phff) + zo = RADIO * sin(thetaff) + + xb = xo * self.largo + yb = yo * self.largo + zb = zo * self.largo + + strokeWeight(1) + beginShape(LINES) + stroke(0) + vertex(x, y, z) + stroke(200, 150) + vertex(xb, yb, zb) + endShape() diff --git a/mode/examples/Demos/Performance/LineRendering/LineRendering.pyde b/mode/examples/Demos/Performance/LineRendering/LineRendering.pyde new file mode 100644 index 00000000..7c821f24 --- /dev/null +++ b/mode/examples/Demos/Performance/LineRendering/LineRendering.pyde @@ -0,0 +1,27 @@ +""" +Performance demo with line rendering +""" + +def setup(): + size(800, 600, P2D) + + +def draw(): + background(255) + stroke(0, 10) + for i in xrange(50000): + x0 = random(width) + y0 = random(height) + z0 = random(-100, 100) + x1 = random(width) + y1 = random(height) + z1 = random(-100, 100) + + # purely 2D lines will trigger the GLU + # tessellator to add accurate line caps, + # but performance will be substantially + # lower. + line(x0, y0, z0, x1, y1, z1) + + if frameCount % 10 == 0: + print frameRate \ No newline at end of file diff --git a/mode/examples/Demos/Performance/QuadRendering/QuadRendering.pyde b/mode/examples/Demos/Performance/QuadRendering/QuadRendering.pyde new file mode 100644 index 00000000..6140fd9a --- /dev/null +++ b/mode/examples/Demos/Performance/QuadRendering/QuadRendering.pyde @@ -0,0 +1,20 @@ +""" +Performance demo using quad rendering +""" + + +def setup(): + size(800, 600, P2D) + noStroke() + fill(0, 1) + + +def draw(): + background(255) + for i in xrange(50000): + x = random(width) + y = random(height) + rect(x, y, 30, 30) + + if frameCount % 10 == 0: + print frameRate diff --git a/mode/examples/Demos/Performance/TextRendering/TextRendering.pyde b/mode/examples/Demos/Performance/TextRendering/TextRendering.pyde new file mode 100644 index 00000000..2dd53c76 --- /dev/null +++ b/mode/examples/Demos/Performance/TextRendering/TextRendering.pyde @@ -0,0 +1,19 @@ +""" +Performance demo using text rendering +""" + + +def setup(): + size(800, 600, P2D) + fill(0) + + +def draw(): + background(255) + for i in xrange(10000): + x = random(width) + y = random(height) + text("HELLO", x, y) + + if frameCount % 10 == 0: + print frameRate diff --git a/mode/examples/Demos/Tests/NoBackgroundTest/NoBackgroundTest.pyde b/mode/examples/Demos/Tests/NoBackgroundTest/NoBackgroundTest.pyde new file mode 100644 index 00000000..961739d8 --- /dev/null +++ b/mode/examples/Demos/Tests/NoBackgroundTest/NoBackgroundTest.pyde @@ -0,0 +1,8 @@ +def setup(): + size(400, 400, P2D) + background(255, 0, 0) + fill(255, 150) + + +def draw(): + ellipse(mouseX, mouseY, 100, 100) diff --git a/mode/examples/Demos/Tests/RedrawTest/RedrawTest.pyde b/mode/examples/Demos/Tests/RedrawTest/RedrawTest.pyde new file mode 100644 index 00000000..92dc4164 --- /dev/null +++ b/mode/examples/Demos/Tests/RedrawTest/RedrawTest.pyde @@ -0,0 +1,13 @@ +def setup(): + size(400, 400, P3D) + noLoop() + + +def draw(): + background(255, 0, 0) + ellipse(mouseX, mouseY, 100, 50) + print "draw" + + +def keyPressed(): + redraw() diff --git a/mode/examples/Demos/Tests/ResizeTest/ResizeTest.pyde b/mode/examples/Demos/Tests/ResizeTest/ResizeTest.pyde new file mode 100644 index 00000000..b01a2ddd --- /dev/null +++ b/mode/examples/Demos/Tests/ResizeTest/ResizeTest.pyde @@ -0,0 +1,8 @@ +def setup(): + size(400, 400, P3D) + this.surface.setResizable(True) + + +def draw(): + background(255, 0, 0) + ellipse(width / 2, height / 2, 100, 50) diff --git a/mode/examples/Topics/AdvancedData/A_List/A_List.pyde b/mode/examples/Topics/AdvancedData/A_List/A_List.pyde new file mode 100644 index 00000000..e09c1619 --- /dev/null +++ b/mode/examples/Topics/AdvancedData/A_List/A_List.pyde @@ -0,0 +1,37 @@ +""" +Based on the ArrayList of objects Java Mode example by Daniel Shiffman, +this demonstrates, to the same effect, how to use a simple Python list +to store a variable number of objects. +Items can be added and removed from the list. + +Click the mouse to add bouncing balls. +""" +from Ball import Ball + +balls = [] +ballWidth = 48 + +def setup(): + size(640, 360) + noStroke() + + # Start by adding one element + balls.append(Ball(width / 2, 0, ballWidth)) + + +def draw(): + background(255) + + # With a list, we could use `for i in range(len(list)):` but + # we will let the Python `for obj in list:` loop iterate it. + for ball in balls: + ball.move() + ball.display() + if ball.finished(): + # Items can be deleted with remove() + balls.remove(ball) + + +def mousePressed(): + # A new ball object is added to the list (by default to the end) + balls.append(Ball(mouseX, mouseY, ballWidth)) diff --git a/mode/examples/Topics/AdvancedData/A_List/Ball.py b/mode/examples/Topics/AdvancedData/A_List/Ball.py new file mode 100644 index 00000000..6dd822e0 --- /dev/null +++ b/mode/examples/Topics/AdvancedData/A_List/Ball.py @@ -0,0 +1,31 @@ +class Ball(): + + def __init__(self, tempX, tempY, tempW): + self.x = tempX + self.y = tempY + self.w = tempW + self.speed = 0 + self.gravity = 0.1 + self.life = 255 + + def move(self): + # Add gravity to speed + self.speed = self.speed + self.gravity + # Add speed to y location + self.y = self.y + self.speed + # If it reaches the bottom, reverse speed + if self.y > height: + # Dampening + self.speed = self.speed * -0.8 + self.y = height + + def finished(self): + # Balls fade out + self.life -= 1 + return self.life < 0 + + def display(self): + # Dispaly the circle + fill(0, self.life) + # stroke(0, self.life) + ellipse(self.x, self.y, self.w, self.w) diff --git a/mode/examples/Topics/AdvancedData/LoadSaveTable/Bubble.py b/mode/examples/Topics/AdvancedData/LoadSaveTable/Bubble.py new file mode 100644 index 00000000..c9e11d30 --- /dev/null +++ b/mode/examples/Topics/AdvancedData/LoadSaveTable/Bubble.py @@ -0,0 +1,28 @@ +# A Bubble class + + +class Bubble(object): + # Create the Bubble + + def __init__(self, x, y, diameter, name): + self.x = x + self.y = y + self.diameter = diameter + self.name = name + self.over = False + + # Checking if mouse is over the Bubble + def rollover(self, px, py): + d = dist(px, py, self.x, self.y) + self.over = d < self.diameter / 2 + + # Display the Bubble + def display(self): + stroke(0) + strokeWeight(2) + noFill() + ellipse(self.x, self.y, self.diameter, self.diameter) + if self.over: + fill(0) + textAlign(CENTER) + text(self.name, self.x, self.y + self.diameter / 2 + 20) diff --git a/mode/examples/Topics/AdvancedData/LoadSaveTable/LoadSaveTable.pyde b/mode/examples/Topics/AdvancedData/LoadSaveTable/LoadSaveTable.pyde new file mode 100644 index 00000000..ed8072d7 --- /dev/null +++ b/mode/examples/Topics/AdvancedData/LoadSaveTable/LoadSaveTable.pyde @@ -0,0 +1,75 @@ +""" +Loading Tabular Data +by Daniel Shiffman. + +This example demonstrates how to use loadTable() +to retrieve data from a CSV file and make objects +from that data. +Here is what the CSV looks like: + +x,y,diameter,name +160,103,43.19838,Happy +372,137,52.42526,Sad +273,235,61.14072,Joyous +121,179,44.758068,Melancholy +""" +from Bubble import Bubble + +# A list of Bubble objects +bubbles = [] + + +def setup(): + size(640, 360) + loadData() + + +def draw(): + background(255) + # Display all bubbles + for b in bubbles: + b.display() + b.rollover(mouseX, mouseY) + + textAlign(LEFT) + fill(0) + text("Click to add bubbles.", 10, height - 10) + + +def loadData(): + # Load CSV file into a Table object + global table + global bubbles + # "header" option indicates the file has a header row + table = loadTable("data.csv", "header") + bubbles = [] + + for row in table.rows(): + # You can access the fields via their column name (or index) + x = row.getFloat("x") + y = row.getFloat("y") + d = row.getFloat("diameter") + n = row.getString("name") + # Make a Bubble object out of the data read + bubbles.append(Bubble(x, y, d, n)) + + +def mousePressed(): + global table + # Create a new row + row = table.addRow() + # Set the values of that row + row.setFloat("x", mouseX) + row.setFloat("y", mouseY) + row.setFloat("diameter", random(40, 80)) + row.setString("name", "Blah") + + # If the table has more than 10 rows + if table.getRowCount() > 10: + # Delete the oldest row + table.removeRow(0) + + # Writing the CSV back to the same file + saveTable(table, "data/data.csv") + # And reloading it + loadData() diff --git a/mode/examples/Topics/AdvancedData/LoadSaveTable/data/data.csv b/mode/examples/Topics/AdvancedData/LoadSaveTable/data/data.csv new file mode 100644 index 00000000..d9e1efd6 --- /dev/null +++ b/mode/examples/Topics/AdvancedData/LoadSaveTable/data/data.csv @@ -0,0 +1,5 @@ +x,y,diameter,name +160,103,43.19838,Happy +372,137,52.42526,Sad +273,235,61.14072,Joyous +121,179,44.758068,Melancholy \ No newline at end of file diff --git a/mode/examples/Topics/Cellular Automata/GameOfLife/GameOfLife.pyde b/mode/examples/Topics/Cellular Automata/GameOfLife/GameOfLife.pyde new file mode 100644 index 00000000..73d1f88c --- /dev/null +++ b/mode/examples/Topics/Cellular Automata/GameOfLife/GameOfLife.pyde @@ -0,0 +1,131 @@ +""" +A Processing implementation of Game of Life By Joan Soler-Adillon + +Press SPACE BAR to pause and change the cell's values with the mouse +On pause, click to activate/deactivate cells +Press R to randomly reset the cells' grid +Press C to clear the cells' grid + +The original Game of Life was created by John Conway in 1970. +""" + +cellSize = 5 # Size of cells + +# How likely for a cell to be alive at start (in percentage) +probabilityOfAliveAtStart = 15 + +# Variables for timer +interval = 100 +lastRecordedTime = 0 + +# Colors for active/inactive cells +alive = color(0, 200, 0) +dead = color(0) + +pause = False # Pause + +def setup(): + global grid_w, grid_h + global cells # Array of cells + global cellsBuffer # Buffer while changing the others in the interations + size(360, 360) + # Instantiate arrays + grid_w, grid_h = int(width / cellSize), int(height / cellSize) + cells = [[None] * grid_w for _ in range(grid_h)] + cellsBuffer = [[None] * grid_w for _ in range(grid_h)] + # This stroke will draw the background grid + stroke(48) + noSmooth() + # Initialization of cells + for x in range(grid_w): + for y in range(grid_h): + state = random(100) + if state > probabilityOfAliveAtStart: + state = 0 + else: + state = 1 + cells[x][y] = state # Save state of each cell + background(0) # Fill in black in case cells don't cover all the windows + +def draw(): + global lastRecordedTime + # Draw grid + for x in range(grid_w): + for y in range(grid_h): + if cells[x][y] == 1: + fill(alive) # If alive + else: + fill(dead) # If dead + rect(x * cellSize, y * cellSize, cellSize, cellSize) + # Iterate if timer ticks + if millis() - lastRecordedTime > interval: + if not pause: + iteration() + lastRecordedTime = millis() + # Create new cells manually on pause + if pause and mousePressed: + # Map and adef out of bound errors + xCellOver = int(map(mouseX, 0, width, 0, width / cellSize)) + xCellOver = constrain(xCellOver, 0, width / cellSize - 1) + yCellOver = int(map(mouseY, 0, height, 0, height / cellSize)) + yCellOver = constrain(yCellOver, 0, height / cellSize - 1) + # Check against cells in buffer + if cellsBuffer[xCellOver][yCellOver] == 1: # Cell is alive + cells[xCellOver][yCellOver] = 0 # Kill + fill(dead) # Fill with kill color + else: # Cell is dead + cells[xCellOver][yCellOver] = 1 # Make alive + fill(alive) # Fill alive color + # And then save to buffer once mouse goes up + elif pause and not mousePressed: + # Save cells to buffer + # (so we opeate with one array keeping the other intact) + for x in range(grid_w): + for y in range(grid_h): + cellsBuffer[x][y] = cells[x][y] + +def iteration(): # When the clock ticks + # Save cells to buffer + # (so we opeate with one array keeping the other intact) + for x in range(grid_w): + for y in range(grid_h): + cellsBuffer[x][y] = cells[x][y] + # Visit each cell: + for x in range(grid_w): + for y in range(grid_h): + # And visit all the neighbours of each cell + neighbours = 0 # We'll count the neighbours + for xx in range(x - 1, x + 2): + for yy in range(y - 1, y + 2): + # Make sure you are not out of bounds + if 0 <= xx < grid_w and 0 <= yy < grid_w: + # Make sure to check against self + if not (xx == x and yy == y): + if cellsBuffer[xx][yy] == 1: + # Check alive neighbours and count them + neighbours = neighbours + 1 + if cellsBuffer[x][y] == 1: + if neighbours < 2 or neighbours > 3: + cells[x][y] = 0 # Die unless it has 2 or 3 neighbours + else: # The cell is dead: make it live if necessary + if neighbours == 3: + cells[x][y] = 1 # Only if it has 3 neighbours + +def keyPressed(): + global pause + if key == 'r' or key == 'R': + # Restart: reinitialization of cells + for x in range(grid_w): + for y in range(grid_h): + state = random(100) + if state > probabilityOfAliveAtStart: + state = 0 + else: + state = 1 + cells[x][y] = state # Save state of each cell + if key == ' ': # On/off of pause + pause = not pause + if (key == 'c' or key == 'C'): # Clear all + for x in range(grid_w): + for y in range(grid_h): + cells[x][y] = 0 # Save all to zero diff --git a/mode/examples/Topics/Cellular Automata/Wolfram/CA.py b/mode/examples/Topics/Cellular Automata/Wolfram/CA.py new file mode 100644 index 00000000..9be2a723 --- /dev/null +++ b/mode/examples/Topics/Cellular Automata/Wolfram/CA.py @@ -0,0 +1,87 @@ +class CA: + + def __init__(self, r): + self.rules = r # List that stores the ruleset, i.e. 0,1,1,0,1,1,0,1 + self.scl = 1 # How many pixels wide/high is each cell? + self.cells = [0] * int(width / self.scl) + self.restart() # Sets self.generation to 0, only middle cell to 1 + + # Set the rules of the CA + def setRules(self, r): + self.rules = r + + # Make a random ruleset + def randomize(self): + for i in range(8): + self.rules[i] = int(random(2)) + + # Reset to generation 0 + def restart(self): + for i in range(len(self.cells)): + self.cells[i] = 0 + + # We arbitrarily start with just the middle cell having a state of "1" + self.cells[len(self.cells) / 2] = 1 + self.generation = 0 + + # The process of creating the new generation + def generate(self): + # First we create an empty array for the new values + nextgen = [0] * len(self.cells) + # For every spot, determine new state by examing current state, + # and neighbor states + # Ignore edges that only have one neighbor + for i in range(1, len(self.cells) - 1): + left = self.cells[i - 1] # Left neighbor state + me = self.cells[i] # Current state + right = self.cells[i + 1] # Right neighbor state + # Compute next generation state based on ruleset + nextgen[i] = self.executeRules(left, me, right) + + # Copy the array into current value + for i in range(1, len(self.cells) - 1): + self.cells[i] = nextgen[i] + + self.generation += 1 + + # This is the easy part, just draw the cells, + # fill 255 for '1', fill 0 for'0' + def render(self): + scl = self.scl + for i in range(len(self.cells)): + if (self.cells[i] == 1): + fill(255) + else: + fill(0) + + noStroke() + rect(i * scl, self.generation * scl, scl, scl) + + # Implementing the Wolfram rules + # Could be improved and made more concise, but here we can + # explicitly see what is going on for each case + def executeRules(self, a, b, c): + if a == 1 and b == 1 and c == 1: + return self.rules[0] + if a == 1 and b == 1 and c == 0: + return self.rules[1] + if a == 1 and b == 0 and c == 1: + return self.rules[2] + if a == 1 and b == 0 and c == 0: + return self.rules[3] + if a == 0 and b == 1 and c == 1: + return self.rules[4] + if a == 0 and b == 1 and c == 0: + return self.rules[5] + if a == 0 and b == 0 and c == 1: + return self.rules[6] + if a == 0 and b == 0 and c == 0: + return self.rules[7] + return 0 + + # The CA is done if it reaches the bottom of the screen + def finished(self): + if self.generation > height / self.scl: + return True + else: + return False diff --git a/mode/examples/Topics/Cellular Automata/Wolfram/Wolfram.pyde b/mode/examples/Topics/Cellular Automata/Wolfram/Wolfram.pyde new file mode 100644 index 00000000..6dc002f3 --- /dev/null +++ b/mode/examples/Topics/Cellular Automata/Wolfram/Wolfram.pyde @@ -0,0 +1,32 @@ +""" +Wolfram Cellular Automata by Daniel Shiffman. + +Simple demonstration of a Wolfram 1-dimensional cellular automata +When the system reaches bottom of the window, it restarts with a new ruleset +Mouse click restarts as well. +""" + +from CA import CA # Object to describe the Wolfram basic Cellular Automata + +def setup(): + global ca + size(640, 360) + ruleset = [0, 1, 0, 1, 1, 0, 1, 0] # An initial rule system + ca = CA(ruleset) # Initialize CA + background(0) + + +def draw(): + ca.render() # Draw the CA + ca.generate() # Generate the next level + + # If we're done, clear the screen, pick a new ruleset and restart + if ca.finished(): + background(0) + ca.randomize() + ca.restart() + +def mousePressed(): + background(0) + ca.randomize() + ca.restart() diff --git a/mode/examples/Topics/Create Shapes/BeginEndContour/BeginEndContour.pyde b/mode/examples/Topics/Create Shapes/BeginEndContour/BeginEndContour.pyde index e81a7bff..2a24635a 100644 --- a/mode/examples/Topics/Create Shapes/BeginEndContour/BeginEndContour.pyde +++ b/mode/examples/Topics/Create Shapes/BeginEndContour/BeginEndContour.pyde @@ -14,17 +14,17 @@ def setup(): s.fill(0) s.stroke(255) s.strokeWeight(2) - # Exterior part of shape + # Exterior part of shape, clockwise winding s.vertex(-100, -100) s.vertex(100, -100) s.vertex(100, 100) s.vertex(-100, 100) - # Interior part of shape + # Interior part of shape, counter-clockwise winding s.beginContour() s.vertex(-10, -10) - s.vertex(10, -10) - s.vertex(10, 10) s.vertex(-10, 10) + s.vertex(10, 10) + s.vertex(10, -10) s.endContour() # Finishing off shape s.endShape(CLOSE) diff --git a/mode/examples/Topics/Create Shapes/GroupPShape/GroupPShape.pyde b/mode/examples/Topics/Create Shapes/GroupPShape/GroupPShape.pyde index 577442b2..94cb5a84 100644 --- a/mode/examples/Topics/Create Shapes/GroupPShape/GroupPShape.pyde +++ b/mode/examples/Topics/Create Shapes/GroupPShape/GroupPShape.pyde @@ -4,6 +4,7 @@ GroupPShape This example shows how to group multiple PShapes into one PShape. """ + def setup(): size(640, 360, P2D) smooth() @@ -32,8 +33,8 @@ def setup(): path.noFill() path.stroke(255) # Note: range() only operates on integers. - # The next two lines show a way to increment by a float value. - for t in range(-PI * 10, 0, 1): + # Use a scaled temp value to increment a float. + for t in range(int(round(-PI * 10)), 0, 1): ttemp = t * 0.1 r = random(60, 70) path.vertex(r * cos(ttemp), r * sin(ttemp)) @@ -57,4 +58,3 @@ def draw(): # Display the group PShape. translate(mouseX, mouseY) shape(group) - diff --git a/mode/examples/Topics/Create Shapes/ParticleSystemPShape/particle.py b/mode/examples/Topics/Create Shapes/ParticleSystemPShape/particle.py index a55f8d8f..122e16d7 100644 --- a/mode/examples/Topics/Create Shapes/ParticleSystemPShape/particle.py +++ b/mode/examples/Topics/Create Shapes/ParticleSystemPShape/particle.py @@ -1,5 +1,3 @@ -import globals - # An individual Particle @@ -61,4 +59,3 @@ def update(self): self.part.translate(self.velocity.x, self.velocity.y) # and also update the center self.center.add(self.velocity) - diff --git a/mode/examples/Topics/Create Shapes/PathPShape/PathPShape.pyde b/mode/examples/Topics/Create Shapes/PathPShape/PathPShape.pyde index f6a798a5..342eb65c 100644 --- a/mode/examples/Topics/Create Shapes/PathPShape/PathPShape.pyde +++ b/mode/examples/Topics/Create Shapes/PathPShape/PathPShape.pyde @@ -17,7 +17,7 @@ def setup(): path.strokeWeight(2) x = 0 # Calculate the path as a sine wave. - for i in range(0, TWO_PI * 10, 1): + for i in range(0, int(round(TWO_PI * 10)), 1): itemp = i * .1 path.vertex(x, sin(itemp) * 100) x += 5 @@ -30,4 +30,3 @@ def draw(): # Draw the path at the mouse location. translate(mouseX, mouseY) shape(path) - diff --git a/mode/examples/Topics/Create Shapes/WigglePShape/wiggler.py b/mode/examples/Topics/Create Shapes/WigglePShape/wiggler.py index d28db790..86e7f772 100644 --- a/mode/examples/Topics/Create Shapes/WigglePShape/wiggler.py +++ b/mode/examples/Topics/Create Shapes/WigglePShape/wiggler.py @@ -11,7 +11,7 @@ def __init__(self): # We are using a list to keep a duplicate copy # of vertices original locations. self.original = [] - for a in range(0, TWO_PI * 10, 2): + for a in range(0, int(TWO_PI * 10), 2): ascaled = a * .1 v = PVector.fromAngle(ascaled) v.mult(100) @@ -49,4 +49,3 @@ def display(self): with pushMatrix(): translate(self.x, self.y) shape(self.s) - diff --git a/mode/examples/Topics/File IO/LoadFile1/LoadFile1.pyde b/mode/examples/Topics/File IO/LoadFile1/LoadFile1.pyde new file mode 100644 index 00000000..08e15eac --- /dev/null +++ b/mode/examples/Topics/File IO/LoadFile1/LoadFile1.pyde @@ -0,0 +1,26 @@ +""" +LoadFile 1 + +Loads a text file that contains two numbers separated by a tab ('\t'). +A new pair of numbers is loaded each frame and used to draw a point on the screen. +""" + +index = 0 + +def setup(): + global lines + size(200, 200) + background(0) + stroke(255) + frameRate(12) + lines = loadStrings("positions.txt") + +def draw(): + global index + if index < len(lines): + pieces = lines[index].split('\t') + if len(pieces) == 2: + x, y = int(pieces[0]) * 2, int(pieces[1]) * 2 + point(x, y) + # Go to the next line for the next run through draw() + index = index + 1 diff --git a/mode/examples/Topics/File IO/LoadFile1/data/positions.txt b/mode/examples/Topics/File IO/LoadFile1/data/positions.txt new file mode 100644 index 00000000..3b8ff2e2 --- /dev/null +++ b/mode/examples/Topics/File IO/LoadFile1/data/positions.txt @@ -0,0 +1,206 @@ +70 35 +69 35 +68 39 +67 42 +66 47 +64 51 +64 54 +63 57 +60 60 +58 64 +51 69 +48 72 +44 73 +39 75 +35 75 +30 75 +25 75 +21 75 +17 73 +13 69 +12 66 +11 61 +11 57 +10 49 +10 45 +10 38 +12 32 +13 29 +16 23 +20 19 +24 16 +27 15 +31 13 +33 13 +37 13 +40 15 +42 16 +45 19 +46 21 +47 24 +48 26 +48 29 +48 33 +47 39 +43 45 +42 47 +38 50 +35 51 +32 51 +30 51 +27 50 +27 50 +26 46 +26 41 +29 36 +30 34 +31 33 +31 33 +32 33 +33 33 +34 33 +34 33 +35 33 +37 33 +39 33 +42 32 +44 31 +46 29 +48 29 +49 27 +52 24 +53 23 +57 19 +61 16 +63 14 +67 13 +69 12 +69 12 +77 11 +77 11 +80 11 +86 16 +90 21 +93 25 +95 29 +95 32 +95 33 +95 37 +94 41 +93 44 +92 46 +91 49 +89 51 +87 55 +85 59 +82 62 +80 64 +79 67 +77 69 +74 71 +68 72 +65 73 +63 73 +62 73 +60 72 +58 69 +57 67 +57 66 +56 60 +56 56 +56 54 +58 49 +60 47 +62 47 +63 47 +67 48 +70 52 +73 55 +74 57 +74 58 +74 60 +74 62 +73 65 +70 68 +67 69 +65 70 +63 70 +62 70 +60 68 +57 65 +55 64 +50 62 +46 61 +40 60 +38 60 +36 60 +32 61 +30 62 +27 64 +26 68 +25 71 +25 77 +25 81 +26 84 +28 86 +31 87 +33 88 +36 88 +39 86 +41 85 +43 83 +44 81 +45 76 +45 74 +45 71 +40 67 +37 65 +34 63 +33 61 +33 61 +32 60 +33 49 +37 45 +41 41 +45 39 +47 38 +51 37 +54 37 +58 38 +61 41 +63 44 +65 46 +66 49 +66 51 +67 55 +67 58 +67 60 +66 62 +64 65 +63 66 +61 67 +60 68 +58 68 +55 69 +54 69 +51 69 +48 69 +46 68 +45 66 +44 65 +44 63 +44 61 +44 59 +44 56 +44 55 +45 53 +47 52 +49 50 +50 48 +51 47 +52 46 +54 46 +55 45 +55 45 +56 44 +57 44 diff --git a/mode/examples/Topics/File IO/LoadFile2/LoadFile2.pyde b/mode/examples/Topics/File IO/LoadFile2/LoadFile2.pyde new file mode 100644 index 00000000..dd3bc9f3 --- /dev/null +++ b/mode/examples/Topics/File IO/LoadFile2/LoadFile2.pyde @@ -0,0 +1,55 @@ +""" +LoadFile 2 + +This example loads a data file about cars. Each element is separated +with a tab and corresponds to a different aspect of each car. The file stores +the miles per gallon, cylinders, displacement, etc., for more than 400 different +makes and models. Press a mouse button to advance to the next group of entries. +""" + +from collections import namedtuple + +Record = namedtuple('Record', ["name", + "mpg", + "cylinders", + "displacement", + "horsepower", + "weight", + "acceleration", + "year", + "origin"]) +records = [] +NUM = 9 # Display this many entries on each screen. +starting_entry = 0 # Display from this entry number + +def setup(): + size(200, 200) + fill(255) + noLoop() + + body_font = loadFont("TheSans-Plain-12.vlw") + textFont(body_font) + + lines = loadStrings("cars2.tsv") + for l in lines: + pieces = l.split(TAB) # Load data into array + if len(pieces) == 9: + println(pieces) + records.append(Record(*pieces)) + + +def draw(): + background(0) + for i in range(NUM): + this_entry = starting_entry + i + if this_entry < len(records): + entry_text = "{} > {}".format(this_entry, records[this_entry].name) + text(entry_text, 20, 20 + i * 20) + + +def mousePressed(): + global starting_entry + starting_entry += NUM + if starting_entry > len(records): + starting_entry = 0 # go back to the beginning + redraw() diff --git a/mode/examples/Topics/File IO/LoadFile2/data/TheSans-Plain-12.vlw b/mode/examples/Topics/File IO/LoadFile2/data/TheSans-Plain-12.vlw new file mode 100644 index 00000000..4fcefba6 Binary files /dev/null and b/mode/examples/Topics/File IO/LoadFile2/data/TheSans-Plain-12.vlw differ diff --git a/mode/examples/Topics/File IO/LoadFile2/data/cars2.tsv b/mode/examples/Topics/File IO/LoadFile2/data/cars2.tsv new file mode 100644 index 00000000..7f658bf2 --- /dev/null +++ b/mode/examples/Topics/File IO/LoadFile2/data/cars2.tsv @@ -0,0 +1,406 @@ +chevrolet chevelle malibu 18 8 307 130 3504 12 70 1 +buick skylark 320 15 8 350 165 3693 11.5 70 1 +plymouth satellite 18 8 318 150 3436 11 70 1 +amc rebel sst 16 8 304 150 3433 12 70 1 +ford torino 17 8 302 140 3449 10.5 70 1 +ford galaxie 500 15 8 429 198 4341 10 70 1 +chevrolet impala 14 8 454 220 4354 9 70 1 +plymouth fury iii 14 8 440 215 4312 8.5 70 1 +pontiac catalina 14 8 455 225 4425 10 70 1 +amc ambassador dpl 15 8 390 190 3850 8.5 70 1 +citroen ds-21 pallas NA 4 133 115 3090 17.5 70 2 +chevrolet chevelle concours (sw) NA 8 350 165 4142 11.5 70 1 +ford torino (sw) NA 8 351 153 4034 11 70 1 +plymouth satellite (sw) NA 8 383 175 4166 10.5 70 1 +amc rebel sst (sw) NA 8 360 175 3850 11 70 1 +dodge challenger se 15 8 383 170 3563 10 70 1 +plymouth 'cuda 340 14 8 340 160 3609 8 70 1 +ford mustang boss 302 NA 8 302 140 3353 8 70 1 +chevrolet monte carlo 15 8 400 150 3761 9.5 70 1 +buick estate wagon (sw) 14 8 455 225 3086 10 70 1 +toyota corona mark ii 24 4 113 95 2372 15 70 3 +plymouth duster 22 6 198 95 2833 15.5 70 1 +amc hornet 18 6 199 97 2774 15.5 70 1 +ford maverick 21 6 200 85 2587 16 70 1 +datsun pl510 27 4 97 88 2130 14.5 70 3 +volkswagen 1131 deluxe sedan 26 4 97 46 1835 20.5 70 2 +peugeot 504 25 4 110 87 2672 17.5 70 2 +audi 100 ls 24 4 107 90 2430 14.5 70 2 +saab 99e 25 4 104 95 2375 17.5 70 2 +bmw 2002 26 4 121 113 2234 12.5 70 2 +amc gremlin 21 6 199 90 2648 15 70 1 +ford f250 10 8 360 215 4615 14 70 1 +chevy c20 10 8 307 200 4376 15 70 1 +dodge d200 11 8 318 210 4382 13.5 70 1 +hi 1200d 9 8 304 193 4732 18.5 70 1 +datsun pl510 27 4 97 88 2130 14.5 71 3 +chevrolet vega 2300 28 4 140 90 2264 15.5 71 1 +toyota corona 25 4 113 95 2228 14 71 3 +ford pinto 25 4 98 NA 2046 19 71 1 +volkswagen super beetle 117 NA 4 97 48 1978 20 71 2 +amc gremlin 19 6 232 100 2634 13 71 1 +plymouth satellite custom 16 6 225 105 3439 15.5 71 1 +chevrolet chevelle malibu 17 6 250 100 3329 15.5 71 1 +ford torino 500 19 6 250 88 3302 15.5 71 1 +amc matador 18 6 232 100 3288 15.5 71 1 +chevrolet impala 14 8 350 165 4209 12 71 1 +pontiac catalina brougham 14 8 400 175 4464 11.5 71 1 +ford galaxie 500 14 8 351 153 4154 13.5 71 1 +plymouth fury iii 14 8 318 150 4096 13 71 1 +dodge monaco (sw) 12 8 383 180 4955 11.5 71 1 +ford country squire (sw) 13 8 400 170 4746 12 71 1 +pontiac safari (sw) 13 8 400 175 5140 12 71 1 +amc hornet sportabout (sw) 18 6 258 110 2962 13.5 71 1 +chevrolet vega (sw) 22 4 140 72 2408 19 71 1 +pontiac firebird 19 6 250 100 3282 15 71 1 +ford mustang 18 6 250 88 3139 14.5 71 1 +mercury capri 2000 23 4 122 86 2220 14 71 1 +opel 1900 28 4 116 90 2123 14 71 2 +peugeot 304 30 4 79 70 2074 19.5 71 2 +fiat 124b 30 4 88 76 2065 14.5 71 2 +toyota corolla 1200 31 4 71 65 1773 19 71 3 +datsun 1200 35 4 72 69 1613 18 71 3 +volkswagen model 111 27 4 97 60 1834 19 71 2 +plymouth cricket 26 4 91 70 1955 20.5 71 1 +toyota corona hardtop 24 4 113 95 2278 15.5 72 3 +dodge colt hardtop 25 4 97.5 80 2126 17 72 1 +volkswagen type 3 23 4 97 54 2254 23.5 72 2 +chevrolet vega 20 4 140 90 2408 19.5 72 1 +ford pinto runabout 21 4 122 86 2226 16.5 72 1 +chevrolet impala 13 8 350 165 4274 12 72 1 +pontiac catalina 14 8 400 175 4385 12 72 1 +plymouth fury iii 15 8 318 150 4135 13.5 72 1 +ford galaxie 500 14 8 351 153 4129 13 72 1 +amc ambassador sst 17 8 304 150 3672 11.5 72 1 +mercury marquis 11 8 429 208 4633 11 72 1 +buick lesabre custom 13 8 350 155 4502 13.5 72 1 +oldsmobile delta 88 royale 12 8 350 160 4456 13.5 72 1 +chrysler newport royal 13 8 400 190 4422 12.5 72 1 +mazda rx2 coupe 19 3 70 97 2330 13.5 72 3 +amc matador (sw) 15 8 304 150 3892 12.5 72 1 +chevrolet chevelle concours (sw) 13 8 307 130 4098 14 72 1 +ford gran torino (sw) 13 8 302 140 4294 16 72 1 +plymouth satellite custom (sw) 14 8 318 150 4077 14 72 1 +volvo 145e (sw) 18 4 121 112 2933 14.5 72 2 +volkswagen 411 (sw) 22 4 121 76 2511 18 72 2 +peugeot 504 (sw) 21 4 120 87 2979 19.5 72 2 +renault 12 (sw) 26 4 96 69 2189 18 72 2 +ford pinto (sw) 22 4 122 86 2395 16 72 1 +datsun 510 (sw) 28 4 97 92 2288 17 72 3 +toyouta corona mark ii (sw) 23 4 120 97 2506 14.5 72 3 +dodge colt (sw) 28 4 98 80 2164 15 72 1 +toyota corolla 1600 (sw) 27 4 97 88 2100 16.5 72 3 +buick century 350 13 8 350 175 4100 13 73 1 +amc matador 14 8 304 150 3672 11.5 73 1 +chevrolet malibu 13 8 350 145 3988 13 73 1 +ford gran torino 14 8 302 137 4042 14.5 73 1 +dodge coronet custom 15 8 318 150 3777 12.5 73 1 +mercury marquis brougham 12 8 429 198 4952 11.5 73 1 +chevrolet caprice classic 13 8 400 150 4464 12 73 1 +ford ltd 13 8 351 158 4363 13 73 1 +plymouth fury gran sedan 14 8 318 150 4237 14.5 73 1 +chrysler new yorker brougham 13 8 440 215 4735 11 73 1 +buick electra 225 custom 12 8 455 225 4951 11 73 1 +amc ambassador brougham 13 8 360 175 3821 11 73 1 +plymouth valiant 18 6 225 105 3121 16.5 73 1 +chevrolet nova custom 16 6 250 100 3278 18 73 1 +amc hornet 18 6 232 100 2945 16 73 1 +ford maverick 18 6 250 88 3021 16.5 73 1 +plymouth duster 23 6 198 95 2904 16 73 1 +volkswagen super beetle 26 4 97 46 1950 21 73 2 +chevrolet impala 11 8 400 150 4997 14 73 1 +ford country 12 8 400 167 4906 12.5 73 1 +plymouth custom suburb 13 8 360 170 4654 13 73 1 +oldsmobile vista cruiser 12 8 350 180 4499 12.5 73 1 +amc gremlin 18 6 232 100 2789 15 73 1 +toyota carina 20 4 97 88 2279 19 73 3 +chevrolet vega 21 4 140 72 2401 19.5 73 1 +datsun 610 22 4 108 94 2379 16.5 73 3 +maxda rx3 18 3 70 90 2124 13.5 73 3 +ford pinto 19 4 122 85 2310 18.5 73 1 +mercury capri v6 21 6 155 107 2472 14 73 1 +fiat 124 sport coupe 26 4 98 90 2265 15.5 73 2 +chevrolet monte carlo s 15 8 350 145 4082 13 73 1 +pontiac grand prix 16 8 400 230 4278 9.5 73 1 +fiat 128 29 4 68 49 1867 19.5 73 2 +opel manta 24 4 116 75 2158 15.5 73 2 +audi 100ls 20 4 114 91 2582 14 73 2 +volvo 144ea 19 4 121 112 2868 15.5 73 2 +dodge dart custom 15 8 318 150 3399 11 73 1 +saab 99le 24 4 121 110 2660 14 73 2 +toyota mark ii 20 6 156 122 2807 13.5 73 3 +oldsmobile omega 11 8 350 180 3664 11 73 1 +plymouth duster 20 6 198 95 3102 16.5 74 1 +ford maverick 21 6 200 NA 2875 17 74 1 +amc hornet 19 6 232 100 2901 16 74 1 +chevrolet nova 15 6 250 100 3336 17 74 1 +datsun b210 31 4 79 67 1950 19 74 3 +ford pinto 26 4 122 80 2451 16.5 74 1 +toyota corolla 1200 32 4 71 65 1836 21 74 3 +chevrolet vega 25 4 140 75 2542 17 74 1 +chevrolet chevelle malibu classic 16 6 250 100 3781 17 74 1 +amc matador 16 6 258 110 3632 18 74 1 +plymouth satellite sebring 18 6 225 105 3613 16.5 74 1 +ford gran torino 16 8 302 140 4141 14 74 1 +buick century luxus (sw) 13 8 350 150 4699 14.5 74 1 +dodge coronet custom (sw) 14 8 318 150 4457 13.5 74 1 +ford gran torino (sw) 14 8 302 140 4638 16 74 1 +amc matador (sw) 14 8 304 150 4257 15.5 74 1 +audi fox 29 4 98 83 2219 16.5 74 2 +volkswagen dasher 26 4 79 67 1963 15.5 74 2 +opel manta 26 4 97 78 2300 14.5 74 2 +toyota corona 31 4 76 52 1649 16.5 74 3 +datsun 710 32 4 83 61 2003 19 74 3 +dodge colt 28 4 90 75 2125 14.5 74 1 +fiat 128 24 4 90 75 2108 15.5 74 2 +fiat 124 tc 26 4 116 75 2246 14 74 2 +honda civic 24 4 120 97 2489 15 74 3 +subaru 26 4 108 93 2391 15.5 74 3 +fiat x1.9 31 4 79 67 2000 16 74 2 +plymouth valiant custom 19 6 225 95 3264 16 75 1 +chevrolet nova 18 6 250 105 3459 16 75 1 +mercury monarch 15 6 250 72 3432 21 75 1 +ford maverick 15 6 250 72 3158 19.5 75 1 +pontiac catalina 16 8 400 170 4668 11.5 75 1 +chevrolet bel air 15 8 350 145 4440 14 75 1 +plymouth grand fury 16 8 318 150 4498 14.5 75 1 +ford ltd 14 8 351 148 4657 13.5 75 1 +buick century 17 6 231 110 3907 21 75 1 +chevroelt chevelle malibu 16 6 250 105 3897 18.5 75 1 +amc matador 15 6 258 110 3730 19 75 1 +plymouth fury 18 6 225 95 3785 19 75 1 +buick skyhawk 21 6 231 110 3039 15 75 1 +chevrolet monza 2+2 20 8 262 110 3221 13.5 75 1 +ford mustang ii 13 8 302 129 3169 12 75 1 +toyota corolla 29 4 97 75 2171 16 75 3 +ford pinto 23 4 140 83 2639 17 75 1 +amc gremlin 20 6 232 100 2914 16 75 1 +pontiac astro 23 4 140 78 2592 18.5 75 1 +toyota corona 24 4 134 96 2702 13.5 75 3 +volkswagen dasher 25 4 90 71 2223 16.5 75 2 +datsun 710 24 4 119 97 2545 17 75 3 +ford pinto 18 6 171 97 2984 14.5 75 1 +volkswagen rabbit 29 4 90 70 1937 14 75 2 +amc pacer 19 6 232 90 3211 17 75 1 +audi 100ls 23 4 115 95 2694 15 75 2 +peugeot 504 23 4 120 88 2957 17 75 2 +volvo 244dl 22 4 121 98 2945 14.5 75 2 +saab 99le 25 4 121 115 2671 13.5 75 2 +honda civic cvcc 33 4 91 53 1795 17.5 75 3 +fiat 131 28 4 107 86 2464 15.5 76 2 +opel 1900 25 4 116 81 2220 16.9 76 2 +capri ii 25 4 140 92 2572 14.9 76 1 +dodge colt 26 4 98 79 2255 17.7 76 1 +renault 12tl 27 4 101 83 2202 15.3 76 2 +chevrolet chevelle malibu classic 17.5 8 305 140 4215 13 76 1 +dodge coronet brougham 16 8 318 150 4190 13 76 1 +amc matador 15.5 8 304 120 3962 13.9 76 1 +ford gran torino 14.5 8 351 152 4215 12.8 76 1 +plymouth valiant 22 6 225 100 3233 15.4 76 1 +chevrolet nova 22 6 250 105 3353 14.5 76 1 +ford maverick 24 6 200 81 3012 17.6 76 1 +amc hornet 22.5 6 232 90 3085 17.6 76 1 +chevrolet chevette 29 4 85 52 2035 22.2 76 1 +chevrolet woody 24.5 4 98 60 2164 22.1 76 1 +vw rabbit 29 4 90 70 1937 14.2 76 2 +honda civic 33 4 91 53 1795 17.4 76 3 +dodge aspen se 20 6 225 100 3651 17.7 76 1 +ford granada ghia 18 6 250 78 3574 21 76 1 +pontiac ventura sj 18.5 6 250 110 3645 16.2 76 1 +amc pacer d/l 17.5 6 258 95 3193 17.8 76 1 +volkswagen rabbit 29.5 4 97 71 1825 12.2 76 2 +datsun b-210 32 4 85 70 1990 17 76 3 +toyota corolla 28 4 97 75 2155 16.4 76 3 +ford pinto 26.5 4 140 72 2565 13.6 76 1 +volvo 245 20 4 130 102 3150 15.7 76 2 +plymouth volare premier v8 13 8 318 150 3940 13.2 76 1 +peugeot 504 19 4 120 88 3270 21.9 76 2 +toyota mark ii 19 6 156 108 2930 15.5 76 3 +mercedes-benz 280s 16.5 6 168 120 3820 16.7 76 2 +cadillac seville 16.5 8 350 180 4380 12.1 76 1 +chevy c10 13 8 350 145 4055 12 76 1 +ford f108 13 8 302 130 3870 15 76 1 +dodge d100 13 8 318 150 3755 14 76 1 +honda accord cvcc 31.5 4 98 68 2045 18.5 77 3 +buick opel isuzu deluxe 30 4 111 80 2155 14.8 77 1 +renault 5 gtl 36 4 79 58 1825 18.6 77 2 +plymouth arrow gs 25.5 4 122 96 2300 15.5 77 1 +datsun f-10 hatchback 33.5 4 85 70 1945 16.8 77 3 +chevrolet caprice classic 17.5 8 305 145 3880 12.5 77 1 +oldsmobile cutlass supreme 17 8 260 110 4060 19 77 1 +dodge monaco brougham 15.5 8 318 145 4140 13.7 77 1 +mercury cougar brougham 15 8 302 130 4295 14.9 77 1 +chevrolet concours 17.5 6 250 110 3520 16.4 77 1 +buick skylark 20.5 6 231 105 3425 16.9 77 1 +plymouth volare custom 19 6 225 100 3630 17.7 77 1 +ford granada 18.5 6 250 98 3525 19 77 1 +pontiac grand prix lj 16 8 400 180 4220 11.1 77 1 +chevrolet monte carlo landau 15.5 8 350 170 4165 11.4 77 1 +chrysler cordoba 15.5 8 400 190 4325 12.2 77 1 +ford thunderbird 16 8 351 149 4335 14.5 77 1 +volkswagen rabbit custom 29 4 97 78 1940 14.5 77 2 +pontiac sunbird coupe 24.5 4 151 88 2740 16 77 1 +toyota corolla liftback 26 4 97 75 2265 18.2 77 3 +ford mustang ii 2+2 25.5 4 140 89 2755 15.8 77 1 +chevrolet chevette 30.5 4 98 63 2051 17 77 1 +dodge colt m/m 33.5 4 98 83 2075 15.9 77 1 +subaru dl 30 4 97 67 1985 16.4 77 3 +volkswagen dasher 30.5 4 97 78 2190 14.1 77 2 +datsun 810 22 6 146 97 2815 14.5 77 3 +bmw 320i 21.5 4 121 110 2600 12.8 77 2 +mazda rx-4 21.5 3 80 110 2720 13.5 77 3 +volkswagen rabbit custom diesel 43.1 4 90 48 1985 21.5 78 2 +ford fiesta 36.1 4 98 66 1800 14.4 78 1 +mazda glc deluxe 32.8 4 78 52 1985 19.4 78 3 +datsun b210 gx 39.4 4 85 70 2070 18.6 78 3 +honda civic cvcc 36.1 4 91 60 1800 16.4 78 3 +oldsmobile cutlass salon brougham 19.9 8 260 110 3365 15.5 78 1 +dodge diplomat 19.4 8 318 140 3735 13.2 78 1 +mercury monarch ghia 20.2 8 302 139 3570 12.8 78 1 +pontiac phoenix lj 19.2 6 231 105 3535 19.2 78 1 +chevrolet malibu 20.5 6 200 95 3155 18.2 78 1 +ford fairmont (auto) 20.2 6 200 85 2965 15.8 78 1 +ford fairmont (man) 25.1 4 140 88 2720 15.4 78 1 +plymouth volare 20.5 6 225 100 3430 17.2 78 1 +amc concord 19.4 6 232 90 3210 17.2 78 1 +buick century special 20.6 6 231 105 3380 15.8 78 1 +mercury zephyr 20.8 6 200 85 3070 16.7 78 1 +dodge aspen 18.6 6 225 110 3620 18.7 78 1 +amc concord d/l 18.1 6 258 120 3410 15.1 78 1 +chevrolet monte carlo landau 19.2 8 305 145 3425 13.2 78 1 +buick regal sport coupe (turbo) 17.7 6 231 165 3445 13.4 78 1 +ford futura 18.1 8 302 139 3205 11.2 78 1 +dodge magnum xe 17.5 8 318 140 4080 13.7 78 1 +chevrolet chevette 30 4 98 68 2155 16.5 78 1 +toyota corona 27.5 4 134 95 2560 14.2 78 3 +datsun 510 27.2 4 119 97 2300 14.7 78 3 +dodge omni 30.9 4 105 75 2230 14.5 78 1 +toyota celica gt liftback 21.1 4 134 95 2515 14.8 78 3 +plymouth sapporo 23.2 4 156 105 2745 16.7 78 1 +oldsmobile starfire sx 23.8 4 151 85 2855 17.6 78 1 +datsun 200-sx 23.9 4 119 97 2405 14.9 78 3 +audi 5000 20.3 5 131 103 2830 15.9 78 2 +volvo 264gl 17 6 163 125 3140 13.6 78 2 +saab 99gle 21.6 4 121 115 2795 15.7 78 2 +peugeot 604sl 16.2 6 163 133 3410 15.8 78 2 +volkswagen scirocco 31.5 4 89 71 1990 14.9 78 2 +honda accord lx 29.5 4 98 68 2135 16.6 78 3 +pontiac lemans v6 21.5 6 231 115 3245 15.4 79 1 +mercury zephyr 6 19.8 6 200 85 2990 18.2 79 1 +ford fairmont 4 22.3 4 140 88 2890 17.3 79 1 +amc concord dl 6 20.2 6 232 90 3265 18.2 79 1 +dodge aspen 6 20.6 6 225 110 3360 16.6 79 1 +chevrolet caprice classic 17 8 305 130 3840 15.4 79 1 +ford ltd landau 17.6 8 302 129 3725 13.4 79 1 +mercury grand marquis 16.5 8 351 138 3955 13.2 79 1 +dodge st. regis 18.2 8 318 135 3830 15.2 79 1 +buick estate wagon (sw) 16.9 8 350 155 4360 14.9 79 1 +ford country squire (sw) 15.5 8 351 142 4054 14.3 79 1 +chevrolet malibu classic (sw) 19.2 8 267 125 3605 15 79 1 +chrysler lebaron town @ country (sw) 18.5 8 360 150 3940 13 79 1 +vw rabbit custom 31.9 4 89 71 1925 14 79 2 +maxda glc deluxe 34.1 4 86 65 1975 15.2 79 3 +dodge colt hatchback custom 35.7 4 98 80 1915 14.4 79 1 +amc spirit dl 27.4 4 121 80 2670 15 79 1 +mercedes benz 300d 25.4 5 183 77 3530 20.1 79 2 +cadillac eldorado 23 8 350 125 3900 17.4 79 1 +peugeot 504 27.2 4 141 71 3190 24.8 79 2 +oldsmobile cutlass salon brougham 23.9 8 260 90 3420 22.2 79 1 +plymouth horizon 34.2 4 105 70 2200 13.2 79 1 +plymouth horizon tc3 34.5 4 105 70 2150 14.9 79 1 +datsun 210 31.8 4 85 65 2020 19.2 79 3 +fiat strada custom 37.3 4 91 69 2130 14.7 79 2 +buick skylark limited 28.4 4 151 90 2670 16 79 1 +chevrolet citation 28.8 6 173 115 2595 11.3 79 1 +oldsmobile omega brougham 26.8 6 173 115 2700 12.9 79 1 +pontiac phoenix 33.5 4 151 90 2556 13.2 79 1 +vw rabbit 41.5 4 98 76 2144 14.7 80 2 +toyota corolla tercel 38.1 4 89 60 1968 18.8 80 3 +chevrolet chevette 32.1 4 98 70 2120 15.5 80 1 +datsun 310 37.2 4 86 65 2019 16.4 80 3 +chevrolet citation 28 4 151 90 2678 16.5 80 1 +ford fairmont 26.4 4 140 88 2870 18.1 80 1 +amc concord 24.3 4 151 90 3003 20.1 80 1 +dodge aspen 19.1 6 225 90 3381 18.7 80 1 +audi 4000 34.3 4 97 78 2188 15.8 80 2 +toyota corona liftback 29.8 4 134 90 2711 15.5 80 3 +mazda 626 31.3 4 120 75 2542 17.5 80 3 +datsun 510 hatchback 37 4 119 92 2434 15 80 3 +toyota corolla 32.2 4 108 75 2265 15.2 80 3 +mazda glc 46.6 4 86 65 2110 17.9 80 3 +dodge colt 27.9 4 156 105 2800 14.4 80 1 +datsun 210 40.8 4 85 65 2110 19.2 80 3 +vw rabbit c (diesel) 44.3 4 90 48 2085 21.7 80 2 +vw dasher (diesel) 43.4 4 90 48 2335 23.7 80 2 +audi 5000s (diesel) 36.4 5 121 67 2950 19.9 80 2 +mercedes-benz 240d 30 4 146 67 3250 21.8 80 2 +honda civic 1500 gl 44.6 4 91 67 1850 13.8 80 3 +renault lecar deluxe 40.9 4 85 NA 1835 17.3 80 2 +subaru dl 33.8 4 97 67 2145 18 80 3 +vokswagen rabbit 29.8 4 89 62 1845 15.3 80 2 +datsun 280-zx 32.7 6 168 132 2910 11.4 80 3 +mazda rx-7 gs 23.7 3 70 100 2420 12.5 80 3 +triumph tr7 coupe 35 4 122 88 2500 15.1 80 2 +ford mustang cobra 23.6 4 140 NA 2905 14.3 80 1 +honda accord 32.4 4 107 72 2290 17 80 3 +plymouth reliant 27.2 4 135 84 2490 15.7 81 1 +buick skylark 26.6 4 151 84 2635 16.4 81 1 +dodge aries wagon (sw) 25.8 4 156 92 2620 14.4 81 1 +chevrolet citation 23.5 6 173 110 2725 12.6 81 1 +plymouth reliant 30 4 135 84 2385 12.9 81 1 +toyota starlet 39.1 4 79 58 1755 16.9 81 3 +plymouth champ 39 4 86 64 1875 16.4 81 1 +honda civic 1300 35.1 4 81 60 1760 16.1 81 3 +subaru 32.3 4 97 67 2065 17.8 81 3 +datsun 210 mpg 37 4 85 65 1975 19.4 81 3 +toyota tercel 37.7 4 89 62 2050 17.3 81 3 +mazda glc 4 34.1 4 91 68 1985 16 81 3 +plymouth horizon 4 34.7 4 105 63 2215 14.9 81 1 +ford escort 4w 34.4 4 98 65 2045 16.2 81 1 +ford escort 2h 29.9 4 98 65 2380 20.7 81 1 +volkswagen jetta 33 4 105 74 2190 14.2 81 2 +renault 18i 34.5 4 100 NA 2320 15.8 81 2 +honda prelude 33.7 4 107 75 2210 14.4 81 3 +toyota corolla 32.4 4 108 75 2350 16.8 81 3 +datsun 200sx 32.9 4 119 100 2615 14.8 81 3 +mazda 626 31.6 4 120 74 2635 18.3 81 3 +peugeot 505s turbo diesel 28.1 4 141 80 3230 20.4 81 2 +saab 900s NA 4 121 110 2800 15.4 81 2 +volvo diesel 30.7 6 145 76 3160 19.6 81 2 +toyota cressida 25.4 6 168 116 2900 12.6 81 3 +datsun 810 maxima 24.2 6 146 120 2930 13.8 81 3 +buick century 22.4 6 231 110 3415 15.8 81 1 +oldsmobile cutlass ls 26.6 8 350 105 3725 19 81 1 +ford granada gl 20.2 6 200 88 3060 17.1 81 1 +chrysler lebaron salon 17.6 6 225 85 3465 16.6 81 1 +chevrolet cavalier 28 4 112 88 2605 19.6 82 1 +chevrolet cavalier wagon 27 4 112 88 2640 18.6 82 1 +chevrolet cavalier 2-door 34 4 112 88 2395 18 82 1 +pontiac j2000 se hatchback 31 4 112 85 2575 16.2 82 1 +dodge aries se 29 4 135 84 2525 16 82 1 +pontiac phoenix 27 4 151 90 2735 18 82 1 +ford fairmont futura 24 4 140 92 2865 16.4 82 1 +amc concord dl 23 4 151 NA 3035 20.5 82 1 +volkswagen rabbit l 36 4 105 74 1980 15.3 82 2 +mazda glc custom l 37 4 91 68 2025 18.2 82 3 +mazda glc custom 31 4 91 68 1970 17.6 82 3 +plymouth horizon miser 38 4 105 63 2125 14.7 82 1 +mercury lynx l 36 4 98 70 2125 17.3 82 1 +nissan stanza xe 36 4 120 88 2160 14.5 82 3 +honda accord 36 4 107 75 2205 14.5 82 3 +toyota corolla 34 4 108 70 2245 16.9 82 3 +honda civic 38 4 91 67 1965 15 82 3 +honda civic (auto) 32 4 91 67 1965 15.7 82 3 +datsun 310 gx 38 4 91 67 1995 16.2 82 3 +buick century limited 25 6 181 110 2945 16.4 82 1 +oldsmobile cutlass ciera (diesel) 38 6 262 85 3015 17 82 1 +chrysler lebaron medallion 26 4 156 92 2585 14.5 82 1 +ford granada l 22 6 232 112 2835 14.7 82 1 +toyota celica gt 32 4 144 96 2665 13.9 82 3 +dodge charger 2.2 36 4 135 84 2370 13 82 1 +chevrolet camaro 27 4 151 90 2950 17.3 82 1 +ford mustang gl 27 4 140 86 2790 15.6 82 1 +vw pickup 44 4 97 52 2130 24.6 82 2 +dodge rampage 32 4 135 84 2295 11.6 82 1 +ford ranger 28 4 120 79 2625 18.6 82 1 +chevy s-10 31 4 119 82 2720 19.4 82 1 \ No newline at end of file diff --git a/mode/examples/Topics/File IO/SaveOneImage/SaveOneImage.pyde b/mode/examples/Topics/File IO/SaveOneImage/SaveOneImage.pyde new file mode 100644 index 00000000..acb85303 --- /dev/null +++ b/mode/examples/Topics/File IO/SaveOneImage/SaveOneImage.pyde @@ -0,0 +1,21 @@ +""" +Save One Image + +The save() function allows you to save an image from the +display window. In this example, save() is run when a mouse +button is pressed. The image "line.tif" is saved to the +same folder as the sketch's program file. +""" + +def setup(): + size(200, 200) + + +def draw(): + background(204) + line(0, 0, mouseX, height) + line(width, 0, 0, mouseY) + + +def mousePressed(): + save("line.tif") diff --git a/mode/examples/Topics/Image Processing/Blending/Blending.pyde b/mode/examples/Topics/Image Processing/Blending/Blending.pyde index b3692360..4b15443f 100644 --- a/mode/examples/Topics/Image Processing/Blending/Blending.pyde +++ b/mode/examples/Topics/Image Processing/Blending/Blending.pyde @@ -1,7 +1,6 @@ """ Blending by Andres Colubri. - Images can be blended using one of the 10 blending modes (currently available only in P2D and P3). Click to go to cycle through the modes. @@ -18,13 +17,15 @@ modes = ((REPLACE, "REPLACE"), (MULTIPLY, "MULTIPLY"), (SCREEN, "SCREEN"), (REPLACE, "REPLACE")) -img1 = loadImage("layer1.jpg") -img2 = loadImage("layer2.jpg") + currentMode = 0 def setup(): size(640, 360, P3D) noStroke() + global img1, img2 + img1 = loadImage("layer1.jpg") + img2 = loadImage("layer2.jpg") def draw(): diff --git a/mode/examples/Topics/Image Processing/Blur/Blur.pyde b/mode/examples/Topics/Image Processing/Blur/Blur.pyde index 331a032f..a4cc52b7 100644 --- a/mode/examples/Topics/Image Processing/Blur/Blur.pyde +++ b/mode/examples/Topics/Image Processing/Blur/Blur.pyde @@ -9,11 +9,12 @@ v = 1.0 / 9.0 kernel = [[v, v, v], [v, v, v], [v, v, v]] -img = loadImage("moon.jpg") # Load the original image def setup(): size(640, 360) + global img + img = loadImage("moon.jpg") noLoop() diff --git a/mode/examples/Topics/Image Processing/Brightness/Brightness.pyde b/mode/examples/Topics/Image Processing/Brightness/Brightness.pyde index f4edca83..c735ad83 100644 --- a/mode/examples/Topics/Image Processing/Brightness/Brightness.pyde +++ b/mode/examples/Topics/Image Processing/Brightness/Brightness.pyde @@ -11,6 +11,8 @@ total = 0 runningavg = 0 def setup(): + global img + img = loadImage("moon-wide.jpg") size(640, 360) frameRate(30) img.loadPixels() diff --git a/mode/examples/Topics/Image Processing/Convolution/Convolution.pyde b/mode/examples/Topics/Image Processing/Convolution/Convolution.pyde index 7975b5e0..bd83558c 100644 --- a/mode/examples/Topics/Image Processing/Convolution/Convolution.pyde +++ b/mode/examples/Topics/Image Processing/Convolution/Convolution.pyde @@ -6,7 +6,6 @@ Applies a convolution matrix to a portion of an image. Move mouse to apply filter to different parts of the image. """ -img = loadImage("moon-wide.jpg") w = 120 # It's possible to convolve the image with many different # matrices to produce different effects. This is a high-pass @@ -18,6 +17,8 @@ matrix = [[-1, -1, -1], def setup(): size(640, 360) + global img + img = loadImage("moon-wide.jpg") def draw(): diff --git a/mode/examples/Topics/Image Processing/EdgeDetection/EdgeDetection.pyde b/mode/examples/Topics/Image Processing/EdgeDetection/EdgeDetection.pyde index 20502ab6..c3ea01c5 100644 --- a/mode/examples/Topics/Image Processing/EdgeDetection/EdgeDetection.pyde +++ b/mode/examples/Topics/Image Processing/EdgeDetection/EdgeDetection.pyde @@ -9,11 +9,12 @@ the image. kernel = [[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]] -img = loadImage("moon.jpg") # Load the original image def setup(): size(640, 360) + global img + img = loadImage("moon.jpg") # Load the original image noLoop() @@ -36,7 +37,8 @@ def draw(): kernelSum += kernel[ky + 1][kx + 1] * val # For this pixel in the image, set the gray value # based on the sum from the kernel - edgeImg.pixels[y * img.width + x] = color(kernelSum, kernelSum, kernelSum) + edgeImg.pixels[ + y * img.width + x] = color(kernelSum, kernelSum, kernelSum) # State that there are changes to edgeImg.pixels edgeImg.updatePixels() image(edgeImg, width / 2, 0) # Draw the image diff --git a/mode/examples/Topics/Image Processing/Explode/Explode.pyde b/mode/examples/Topics/Image Processing/Explode/Explode.pyde index fc79bbe3..a220d4c3 100644 --- a/mode/examples/Topics/Image Processing/Explode/Explode.pyde +++ b/mode/examples/Topics/Image Processing/Explode/Explode.pyde @@ -7,16 +7,14 @@ maps pixels from a 2D image into 3D space. Pixel brightness controls translation along z axis. """ -img = loadImage("eames.jpg") # Load the image -cellsize = 2 # Dimensions of each cell in the grid -# Number of columns and rows in our system -columns = img.width / cellsize # Calculate # of columns -rows = img.height / cellsize # Calculate # of rows - - def setup(): size(640, 360, P3D) - + # Number of columns and rows in our system + global columns, rows, cellsize, img + img = loadImage("eames.jpg") # Load the image + cellsize = 2 # Dimensions of each cell in the grid + columns = img.width / cellsize # Calculate # of columns + rows = img.height / cellsize # Calculate # of rows def draw(): background(0) diff --git a/mode/examples/Topics/Image Processing/Extrusion/Extrusion.pyde b/mode/examples/Topics/Image Processing/Extrusion/Extrusion.pyde index eacd9ae1..046e273a 100644 --- a/mode/examples/Topics/Image Processing/Extrusion/Extrusion.pyde +++ b/mode/examples/Topics/Image Processing/Extrusion/Extrusion.pyde @@ -4,14 +4,14 @@ Extrusion. Converts a flat image into spatial data points and rotates the points around the center. """ -img = loadImage("ystone08.jpg") angle = 0 def setup(): + global img + img = loadImage("ystone08.jpg") size(640, 360, P3D) global values - imgPixels = [[0] * width for i in range(height)] values = [[0] * width for i in range(height)] noFill() # Load the image into a array @@ -19,8 +19,7 @@ def setup(): img.loadPixels() for i in range(img.height): for j in range(img.width): - imgPixels[j][i] = img.pixels[i * img.width + j] - values[j][i] = int(blue(imgPixels[j][i])) + values[j][i] = int(blue(img.pixels[i * img.width + j])) def draw(): diff --git a/mode/examples/Topics/Image Processing/LinearImage/LinearImage.pyde b/mode/examples/Topics/Image Processing/LinearImage/LinearImage.pyde index dc76569b..e0695338 100644 --- a/mode/examples/Topics/Image Processing/LinearImage/LinearImage.pyde +++ b/mode/examples/Topics/Image Processing/LinearImage/LinearImage.pyde @@ -10,6 +10,8 @@ signal = 0.0 def setup(): + global img + img = loadImage("sea.jpg") size(640, 360) stroke(255) img.loadPixels() diff --git a/mode/examples/Topics/Image Processing/PixelArray/PixelArray.pyde b/mode/examples/Topics/Image Processing/PixelArray/PixelArray.pyde index ebec741b..661c7e50 100644 --- a/mode/examples/Topics/Image Processing/PixelArray/PixelArray.pyde +++ b/mode/examples/Topics/Image Processing/PixelArray/PixelArray.pyde @@ -6,7 +6,7 @@ press and hold any key to see the current pixel being read. This program sequentially reads the color of every pixel of an image and displays this color to fill the window. """ -img = loadImage("sea.jpg") + direction = 1 signal = 0.0 @@ -16,6 +16,8 @@ def setup(): noFill() stroke(255) frameRate(30) + global img + img = loadImage("sea.jpg") def draw(): diff --git a/mode/examples/Topics/Image Processing/Zoom/Zoom.pyde b/mode/examples/Topics/Image Processing/Zoom/Zoom.pyde index 79f91d54..6e759ec6 100644 --- a/mode/examples/Topics/Image Processing/Zoom/Zoom.pyde +++ b/mode/examples/Topics/Image Processing/Zoom/Zoom.pyde @@ -5,8 +5,7 @@ Move the cursor over the image to alter its position. Click and press the mouse to zoom. This program displays a series of lines with their heights corresponding to a color value read from an image. """ -img = loadImage("ystone08.jpg") -imgPixels = [[0] * img.width for _ in range(img.height)] + scaleVal = 1.0 nmx = 0 nmy = 0 @@ -17,6 +16,9 @@ def setup(): size(640, 360, P3D) noFill() stroke(255) + global img, imgPixels + img = loadImage("ystone08.jpg") + imgPixels = [[0] * img.width for _ in range(img.height)] for i in range(img.height): for j in range(img.width): imgPixels[j][i] = img.get(j, i) @@ -32,7 +34,8 @@ def draw(): else: scaleVal -= 0.01 scaleVal = constrain(scaleVal, 1.0, 2.0) - translate(width / 2 + nmx * scaleVal - 100, height / 2 + nmy * scaleVal - 100, -50) + translate(width / 2 + nmx * scaleVal - 100, + height / 2 + nmy * scaleVal - 100, -50) scale(scaleVal) rotateZ(PI / 9 - scaleVal + 1.0) rotateX(PI / scaleVal / 8 - 0.125) diff --git a/mode/examples/Topics/Interaction/Follow1/Follow1.pyde b/mode/examples/Topics/Interaction/Follow1/Follow1.pyde index 55aa579e..27a397a6 100644 --- a/mode/examples/Topics/Interaction/Follow1/Follow1.pyde +++ b/mode/examples/Topics/Interaction/Follow1/Follow1.pyde @@ -17,6 +17,7 @@ def setup(): def draw(): + global x, y background(0) dx = mouseX - x dy = mouseY - y @@ -32,4 +33,3 @@ def segment(x, y, a): translate(x, y) rotate(a) line(0, 0, segLength, 0) - diff --git a/mode/examples/Topics/Interaction/Reach1/Reach1.pyde b/mode/examples/Topics/Interaction/Reach1/Reach1.pyde index 1c524ffb..7362b9a0 100644 --- a/mode/examples/Topics/Interaction/Reach1/Reach1.pyde +++ b/mode/examples/Topics/Interaction/Reach1/Reach1.pyde @@ -24,6 +24,7 @@ def setup(): def draw(): + global x, y background(0) dx = mouseX - x dy = mouseY - y @@ -44,4 +45,3 @@ def segment(x, y, a): translate(x, y) rotate(a) line(0, 0, segLength, 0) - diff --git a/mode/examples/Topics/Interaction/Reach2/Reach2.pyde b/mode/examples/Topics/Interaction/Reach2/Reach2.pyde index 38667cf3..52c67a7d 100644 --- a/mode/examples/Topics/Interaction/Reach2/Reach2.pyde +++ b/mode/examples/Topics/Interaction/Reach2/Reach2.pyde @@ -41,6 +41,7 @@ def reachSegment(i, xin, yin): dx = xin - x[i] dy = yin - y[i] angle[i] = atan2(dy, dx) + global targetX, targetY targetX = xin - cos(angle[i]) * segLength targetY = yin - sin(angle[i]) * segLength @@ -51,4 +52,3 @@ def segment(x, y, a, sw): translate(x, y) rotate(a) line(0, 0, segLength, 0) - diff --git a/mode/examples/Topics/Interaction/Reach3/Reach3.pyde b/mode/examples/Topics/Interaction/Reach3/Reach3.pyde index e225b942..4382e6ca 100644 --- a/mode/examples/Topics/Interaction/Reach3/Reach3.pyde +++ b/mode/examples/Topics/Interaction/Reach3/Reach3.pyde @@ -14,8 +14,8 @@ targetX = 0 targetY = 0 ballX = 50 ballY = 50 -ballXDirection = 1 -ballYDirection = -1 +ballXDirection = 2.5 +ballYDirection = -2 def setup(): @@ -28,13 +28,15 @@ def setup(): def draw(): + global ballX, ballY + global ballXDirection, ballYDirection background(0) strokeWeight(20) ballX = ballX + 1.0 * ballXDirection ballY = ballY + 0.8 * ballYDirection - if width - 25 < ballX < 25: + if ballX > width - 25 or ballX < 25: ballXDirection *= -1 - if height - 25 < ballY < 25: + if ballY > height - 25 or ballY < 25: ballYDirection *= -1 ellipse(ballX, ballY, 30, 30) reachSegment(0, ballX, ballY) @@ -52,6 +54,7 @@ def positionSegment(a, b): def reachSegment(i, xin, yin): + global targetX, targetY dx = xin - x[i] dy = yin - y[i] angle[i] = atan2(dy, dx) @@ -65,4 +68,3 @@ def segment(x, y, a, sw): translate(x, y) rotate(a) line(0, 0, segLength, 0) - diff --git a/mode/examples/Topics/Interaction/Tickle/Tickle.pyde b/mode/examples/Topics/Interaction/Tickle/Tickle.pyde index 3ab31891..f16b36ec 100644 --- a/mode/examples/Topics/Interaction/Tickle/Tickle.pyde +++ b/mode/examples/Topics/Interaction/Tickle/Tickle.pyde @@ -15,6 +15,7 @@ vr = 0 def setup(): + global x, y, hr, vr size(640, 360) # Create the font textFont(createFont("Georgia", 36)) @@ -27,6 +28,7 @@ def setup(): def draw(): + global x, y # Instead of clearing the background, fade it by drawing # a semi-transparent rectangle on top fill(204, 120) @@ -37,4 +39,3 @@ def draw(): y += random(-5, 5) fill(0) text("tickle", x, y) - diff --git a/mode/examples/Topics/Shaders/BlurFilter/BlurFilter.pyde b/mode/examples/Topics/Shaders/BlurFilter/BlurFilter.pyde index 206d009a..1181300a 100644 --- a/mode/examples/Topics/Shaders/BlurFilter/BlurFilter.pyde +++ b/mode/examples/Topics/Shaders/BlurFilter/BlurFilter.pyde @@ -9,6 +9,7 @@ blur = None def setup(): + global blur size(640, 360, P2D) blur = loadShader("blur.glsl") stroke(255, 0, 0) @@ -19,4 +20,3 @@ def draw(): filter(blur) rect(mouseX, mouseY, 150, 150) ellipse(mouseX, mouseY, 100, 100) - diff --git a/mode/examples/Topics/Shaders/Conway/Conway.pyde b/mode/examples/Topics/Shaders/Conway/Conway.pyde index d4b29bda..a999982c 100644 --- a/mode/examples/Topics/Shaders/Conway/Conway.pyde +++ b/mode/examples/Topics/Shaders/Conway/Conway.pyde @@ -7,6 +7,7 @@ conway = None pg = None def setup(): + global conway, pg size(400, 400, P3D) conway = loadShader("conway.glsl") pg = createGraphics(400, 400, P2D) @@ -25,4 +26,3 @@ def draw(): pg.rect(0, 0, pg.width, pg.height) pg.endDraw() image(pg, 0, 0, width, height) - diff --git a/mode/examples/Topics/Shaders/CustomBlend/CustomBlend.pyde b/mode/examples/Topics/Shaders/CustomBlend/CustomBlend.pyde index 2bced4b2..98936c55 100644 --- a/mode/examples/Topics/Shaders/CustomBlend/CustomBlend.pyde +++ b/mode/examples/Topics/Shaders/CustomBlend/CustomBlend.pyde @@ -29,6 +29,7 @@ difference = None def setup(): + global destImage, srcImage size(640, 360, P2D) destImage = loadImage("leaves.jpg") srcImage = loadImage("moonwalk.jpg") @@ -49,6 +50,7 @@ def draw(): def initShaders(): + global dodge, burn, overlay, difference dodge = loadShader("dodge.glsl") burn = loadShader("burn.glsl") overlay = loadShader("overlay.glsl") @@ -99,4 +101,3 @@ def drawOutput(x, y, w, h): vertex(w, 0, 1, 0) vertex(w, h, 1, 1) vertex(0, h, 0, 1) - diff --git a/mode/examples/Topics/Shaders/Deform/Deform.pyde b/mode/examples/Topics/Shaders/Deform/Deform.pyde index a7888b5f..a58f44ad 100644 --- a/mode/examples/Topics/Shaders/Deform/Deform.pyde +++ b/mode/examples/Topics/Shaders/Deform/Deform.pyde @@ -13,6 +13,7 @@ deform = None def setup(): + global tex, deform size(640, 360, P2D) textureWrap(REPEAT) tex = loadImage("tex1.jpg") @@ -25,4 +26,3 @@ def draw(): deform.set("mouse", float(mouseX), float(mouseY)) shader(deform) image(tex, 0, 0, width, height) - diff --git a/mode/examples/Topics/Shaders/EdgeDetect/EdgeDetect.pyde b/mode/examples/Topics/Shaders/EdgeDetect/EdgeDetect.pyde index 8e41d734..dc9435d6 100644 --- a/mode/examples/Topics/Shaders/EdgeDetect/EdgeDetect.pyde +++ b/mode/examples/Topics/Shaders/EdgeDetect/EdgeDetect.pyde @@ -11,6 +11,7 @@ enabled = True def setup(): + global img, edges, enabled size(640, 360, P2D) img = loadImage("leaves.jpg") edges = loadShader("edges.glsl") @@ -23,7 +24,7 @@ def draw(): def mousePressed(): + global enabled enabled = not enabled if not enabled: resetShader() - diff --git a/mode/examples/Topics/Shaders/EdgeFilter/EdgeFilter.pyde b/mode/examples/Topics/Shaders/EdgeFilter/EdgeFilter.pyde index ff2bd1fe..7231c65f 100644 --- a/mode/examples/Topics/Shaders/EdgeFilter/EdgeFilter.pyde +++ b/mode/examples/Topics/Shaders/EdgeFilter/EdgeFilter.pyde @@ -11,6 +11,7 @@ applyFilter = True def setup(): + global edges size(640, 360, P3D) edges = loadShader("edges.glsl") noStroke() @@ -34,5 +35,5 @@ def draw(): def mousePressed(): + global applyFilter applyFilter = not applyFilter - diff --git a/mode/examples/Topics/Shaders/GlossyFishEye/GlossyFishEye.pyde b/mode/examples/Topics/Shaders/GlossyFishEye/GlossyFishEye.pyde index c2172d76..0edfc0b2 100644 --- a/mode/examples/Topics/Shaders/GlossyFishEye/GlossyFishEye.pyde +++ b/mode/examples/Topics/Shaders/GlossyFishEye/GlossyFishEye.pyde @@ -14,6 +14,7 @@ useFishEye = True def setup(): + global fisheye, glossy, canvas, img, ball size(640, 640, P3D) canvas = createGraphics(width, height, P3D) fisheye = loadShader("FishEye.glsl") @@ -54,6 +55,7 @@ def draw(): def mousePressed(): + global useFishEye useFishEye = not useFishEye if not useFishEye: resetShader() diff --git a/mode/examples/Topics/Shaders/ImageMask/ImageMask.pyde b/mode/examples/Topics/Shaders/ImageMask/ImageMask.pyde index ac3a520e..659cce71 100644 --- a/mode/examples/Topics/Shaders/ImageMask/ImageMask.pyde +++ b/mode/examples/Topics/Shaders/ImageMask/ImageMask.pyde @@ -10,6 +10,7 @@ maskImage = None def setup(): + global maskShader, srcImage, maskImage size(640, 360, P2D) srcImage = loadImage("leaves.jpg") maskImage = createGraphics(srcImage.width, srcImage.height, P2D) @@ -29,4 +30,3 @@ def draw(): maskImage.endDraw() shader(maskShader) image(srcImage, 0, 0, width, height) - diff --git a/mode/examples/Topics/Shaders/Landscape/Landscape.pyde b/mode/examples/Topics/Shaders/Landscape/Landscape.pyde index da4231cf..dd5419f7 100644 --- a/mode/examples/Topics/Shaders/Landscape/Landscape.pyde +++ b/mode/examples/Topics/Shaders/Landscape/Landscape.pyde @@ -10,6 +10,7 @@ elevatedshader = None def setup(): + global elevatedshader size(640, 360, P2D) noStroke() # The code of this shader shows how to integrate shaders from shadertoy diff --git a/mode/examples/Topics/Shaders/Monjori/Monjori.pyde b/mode/examples/Topics/Shaders/Monjori/Monjori.pyde index 975c4b2d..6baa4cf2 100644 --- a/mode/examples/Topics/Shaders/Monjori/Monjori.pyde +++ b/mode/examples/Topics/Shaders/Monjori/Monjori.pyde @@ -12,6 +12,7 @@ monjori = None def setup(): + global monjori size(640, 360, P2D) noStroke() monjori = loadShader("monjori.glsl") @@ -26,4 +27,3 @@ def draw(): # entire view area so every pixel is pushed through the # shader. rect(0, 0, width, height) - diff --git a/mode/examples/Topics/Shaders/Nebula/Nebula.pyde b/mode/examples/Topics/Shaders/Nebula/Nebula.pyde index e31a9f1a..2e0db494 100644 --- a/mode/examples/Topics/Shaders/Nebula/Nebula.pyde +++ b/mode/examples/Topics/Shaders/Nebula/Nebula.pyde @@ -10,6 +10,7 @@ nebula = None def setup(): + global nebula size(640, 360, P2D) noStroke() nebula = loadShader("nebula.glsl") @@ -23,4 +24,3 @@ def draw(): # fragment shader, they only need a quad covering the entire view # area so every pixel is pushed through the shader. rect(0, 0, width, height) - diff --git a/mode/examples/Topics/Shaders/SepBlur/SepBlur.pyde b/mode/examples/Topics/Shaders/SepBlur/SepBlur.pyde index ae679b1c..c4d00bcb 100644 --- a/mode/examples/Topics/Shaders/SepBlur/SepBlur.pyde +++ b/mode/examples/Topics/Shaders/SepBlur/SepBlur.pyde @@ -13,6 +13,7 @@ pass2 = None def setup(): + global blur, src, pass1, pass2 size(640, 360, P2D) blur = loadShader("blur.glsl") @@ -53,6 +54,7 @@ def draw(): def keyPressed(): + global blur if key == '9': blur.set("blurSize", 9) blur.set("sigma", 5.0) @@ -65,4 +67,3 @@ def keyPressed(): elif key == '3': blur.set("blurSize", 3) blur.set("sigma", 1.0) - diff --git a/mode/examples/Topics/Shaders/ToonShading/ToonShading.pyde b/mode/examples/Topics/Shaders/ToonShading/ToonShading.pyde index 4851e0c6..5c623c0f 100644 --- a/mode/examples/Topics/Shaders/ToonShading/ToonShading.pyde +++ b/mode/examples/Topics/Shaders/ToonShading/ToonShading.pyde @@ -12,6 +12,7 @@ shaderEnabled = True def setup(): + global toon size(640, 360, P3D) noStroke() fill(204) @@ -31,6 +32,7 @@ def draw(): def mousePressed(): + global shaderEnabled shaderEnabled = not shaderEnabled if not shaderEnabled: resetShader() diff --git a/mode/examples/Topics/Simulate/Chain/Chain.pyde b/mode/examples/Topics/Simulate/Chain/Chain.pyde index f905ffbf..6dcd85a2 100644 --- a/mode/examples/Topics/Simulate/Chain/Chain.pyde +++ b/mode/examples/Topics/Simulate/Chain/Chain.pyde @@ -5,21 +5,16 @@ One mass is attached to the mouse position and the other is attached the position of the other mass. The gravity in the environment pulls down on both. """ - -s1 = None -s2 = None gravity = 9.0 mass = 2.0 - def setup(): + global s1, s2 size(640, 360) fill(255, 126) - # Inputs: x, y, mass, gravity s1 = Spring2D(0.0, width / 2, mass, gravity) s2 = Spring2D(0.0, width / 2, mass, gravity) - def draw(): background(0) s1.update(mouseX, mouseY) @@ -32,8 +27,8 @@ class Spring2D(object): def __init__(self, xpos, ypos, m, g): # The x- and y-axis velocities - self.vx = 0 - self.vy = 0 + self.vx = 0.0 + self.vy = 0.0 # The x- and y-coordinates self.x = xpos self.y = ypos @@ -59,4 +54,3 @@ class Spring2D(object): ellipse(self.x, self.y, self.radius * 2, self.radius * 2) stroke(255) line(self.x, self.y, nx, ny) - diff --git a/mode/examples/Topics/Simulate/ForcesWithVectors/ForcesWithVectors.pyde b/mode/examples/Topics/Simulate/ForcesWithVectors/ForcesWithVectors.pyde index d2ef4e5f..458459f0 100644 --- a/mode/examples/Topics/Simulate/ForcesWithVectors/ForcesWithVectors.pyde +++ b/mode/examples/Topics/Simulate/ForcesWithVectors/ForcesWithVectors.pyde @@ -15,14 +15,12 @@ from liquid import Liquid from mover import Mover movers = [None] * 10 -# Liquid -liquid = None - def setup(): size(640, 360) reset() # Create liquid object. + global liquid liquid = Liquid(0, height / 2, width, height / 2, 0.1) diff --git a/mode/examples/Topics/Simulate/GravitationalAttraction3D/GravitationalAttraction3D.pyde b/mode/examples/Topics/Simulate/GravitationalAttraction3D/GravitationalAttraction3D.pyde index f9489b24..2971a3c8 100644 --- a/mode/examples/Topics/Simulate/GravitationalAttraction3D/GravitationalAttraction3D.pyde +++ b/mode/examples/Topics/Simulate/GravitationalAttraction3D/GravitationalAttraction3D.pyde @@ -27,6 +27,7 @@ angle = 0 def setup(): + global planets, s size(640, 360, P3D) smooth() # Some random planets. @@ -38,6 +39,7 @@ def setup(): def draw(): + global angle background(0) # Setup the scene. sphereDetail(8) @@ -56,4 +58,3 @@ def draw(): planet.display() # Rotate around the scene. angle += 0.003 - diff --git a/mode/examples/Topics/Simulate/MultipleParticleSystems/MultipleParticleSystems.pyde b/mode/examples/Topics/Simulate/MultipleParticleSystems/MultipleParticleSystems.pyde index 2f2ae01c..48497ced 100644 --- a/mode/examples/Topics/Simulate/MultipleParticleSystems/MultipleParticleSystems.pyde +++ b/mode/examples/Topics/Simulate/MultipleParticleSystems/MultipleParticleSystems.pyde @@ -17,6 +17,7 @@ from particle_system import ParticleSystem systems = None def setup(): + global systems size(640, 360) systems = [] @@ -35,4 +36,3 @@ def draw(): def mousePressed(): systems.append(ParticleSystem(1, PVector(mouseX, mouseY))) - diff --git a/mode/examples/Topics/Simulate/SimpleParticleSystem/SimpleParticleSystem.pyde b/mode/examples/Topics/Simulate/SimpleParticleSystem/SimpleParticleSystem.pyde index 443d5288..7c8c9f0f 100644 --- a/mode/examples/Topics/Simulate/SimpleParticleSystem/SimpleParticleSystem.pyde +++ b/mode/examples/Topics/Simulate/SimpleParticleSystem/SimpleParticleSystem.pyde @@ -13,6 +13,7 @@ from particle_system import ParticleSystem ps = None def setup(): + global ps size(640, 360) ps = ParticleSystem(PVector(width / 2, 50)) @@ -20,4 +21,3 @@ def draw(): background(0) ps.addParticle() ps.run() - diff --git a/mode/examples/Topics/Simulate/SmokeParticleSystem/SmokeParticleSystem.pyde b/mode/examples/Topics/Simulate/SmokeParticleSystem/SmokeParticleSystem.pyde index 58c14c83..72af5bf4 100644 --- a/mode/examples/Topics/Simulate/SmokeParticleSystem/SmokeParticleSystem.pyde +++ b/mode/examples/Topics/Simulate/SmokeParticleSystem/SmokeParticleSystem.pyde @@ -12,6 +12,7 @@ from particle_system import ParticleSystem ps = None def setup(): + global ps size(640, 360) img = loadImage("texture.png") ps = ParticleSystem(0, PVector(width / 2, height - 60), img) @@ -48,4 +49,3 @@ def drawVector(v, loc, scayl): line(0, 0, len, 0) line(len, 0, len - arrowsize, +arrowsize / 2) line(len, 0, len - arrowsize, -arrowsize / 2) - diff --git a/mode/examples/Topics/Simulate/SoftBody/SoftBody.pyde b/mode/examples/Topics/Simulate/SoftBody/SoftBody.pyde index 03f00d54..4c259eee 100644 --- a/mode/examples/Topics/Simulate/SoftBody/SoftBody.pyde +++ b/mode/examples/Topics/Simulate/SoftBody/SoftBody.pyde @@ -12,7 +12,7 @@ radius = 45 rotAngle = -90 accelX = 0 accelY = 0 -springing = .0009 +springing = .0009 damping = .98 # Corner nodes nodes = 5 @@ -47,6 +47,7 @@ def draw(): def drawShape(): + global rotAngle # Calculate node starting locations. for i in range(nodes): nodeStartX[i] = centerX + cos(radians(rotAngle)) * radius @@ -63,6 +64,7 @@ def drawShape(): def moveShape(): + global centerX, centerY, deltaX, deltaY, accelX, accelY # Move center point. deltaX = mouseX - centerX deltaY = mouseY - centerY @@ -84,4 +86,3 @@ def moveShape(): nodeX[i] = nodeStartX[i] + sin(radians(angle[i])) * (accelX * 2) nodeY[i] = nodeStartY[i] + sin(radians(angle[i])) * (accelY * 2) angle[i] += frequency[i] - diff --git a/mode/examples/Topics/Simulate/Spring/Spring.pyde b/mode/examples/Topics/Simulate/Spring/Spring.pyde index 75235861..9dca37b7 100644 --- a/mode/examples/Topics/Simulate/Spring/Spring.pyde +++ b/mode/examples/Topics/Simulate/Spring/Spring.pyde @@ -8,8 +8,8 @@ Click, drag, and release the horizontal bar to start the spring. springHeight = 32 # Height left = 0 # Left position right = 0 # Right position -max = 200 # Maximum Y value -min = 100 # Minimum Y value +maxHeight = 200 # Maximum Y value +minHeight = 100 # Minimum Y value over = False # If mouse over move = False # If mouse down and over # Spring simulation constants @@ -25,6 +25,7 @@ f = 0 # Force def setup(): + global left, right size(640, 360) rectMode(CORNERS) noStroke() @@ -53,6 +54,7 @@ def drawSpring(): def updateSpring(): + global over, f, ps, a, v # Update the spring position. if not move: f = -K * (ps - R) # f=-ky @@ -62,18 +64,22 @@ def updateSpring(): if abs(v) < 0.1: v = 0.0 # Test if mouse is over the top bar - over = left < mouseX < right and ps < mouseY < ps + springHeight + over = (left < mouseX < right) and (ps < mouseY < ps + springHeight) # Set and constrain the position of top bar. if move: ps = mouseY - springHeight / 2 - ps = constrain(ps, min, max) - - + if ps > maxHeight: + ps = maxHeight + elif ps < minHeight: + ps = minHeight + + def mousePressed(): + global move if over: move = True def mouseReleased(): + global move move = False - diff --git a/mode/examples/Topics/Simulate/Springs/Springs.pyde b/mode/examples/Topics/Simulate/Springs/Springs.pyde index 113bff04..fdb7e3a0 100644 --- a/mode/examples/Topics/Simulate/Springs/Springs.pyde +++ b/mode/examples/Topics/Simulate/Springs/Springs.pyde @@ -38,6 +38,7 @@ def mouseReleased(): class Spring(object): # Constructor + def __init__(self, x, y, s, d, m, k_in, others): self.over = False self.move = False @@ -83,7 +84,7 @@ class Spring(object): # Make sure no other springs are active def otherOver(self): for friend in self.friends: - if friend != self and friend.over + if friend != self and friend.over: return True return False @@ -101,4 +102,3 @@ class Spring(object): self.move = False self.rest_posx = self.xpos self.rest_posy = self.ypos - diff --git a/mode/examples/Topics/Textures/TextureCube/TextureCube.pyde b/mode/examples/Topics/Textures/TextureCube/TextureCube.pyde index a58d1b01..8deaf815 100644 --- a/mode/examples/Topics/Textures/TextureCube/TextureCube.pyde +++ b/mode/examples/Topics/Textures/TextureCube/TextureCube.pyde @@ -16,6 +16,7 @@ roty = PI / 4 def setup(): size(640, 360, P3D) + global halfWidth, halfHeight, tex halfWidth = width / 2.0 halfHeight = height / 2.0 tex = loadImage("berlin-1.jpg") @@ -39,7 +40,7 @@ def draw(): def texturedCube(tex): with beginShape(QUADS): texture(tex) - + # Given one texture and six faces, we can easily set up the uv coordinates # such that four of the faces tile "perfectly" along either u or v, but # the other two faces cannot be so aligned. This code tiles "along" u, @@ -49,46 +50,46 @@ def texturedCube(tex): # otherwised aligned with the X / Z faces. (This just affects what type of # symmetry is required if you need seamless tiling all the way around the # cube) - + # +Z "front" face. vertex(-1, -1, 1, 0, 0) vertex(1, -1, 1, 1, 0) vertex(1, 1, 1, 1, 1) vertex(-1, 1, 1, 0, 1) - + # -Z "back" face. vertex(1, -1, -1, 0, 0) vertex(-1, -1, -1, 1, 0) vertex(-1, 1, -1, 1, 1) vertex(1, 1, -1, 0, 1) - + # +Y "bottom" face. vertex(-1, 1, 1, 0, 0) vertex(1, 1, 1, 1, 0) vertex(1, 1, -1, 1, 1) vertex(-1, 1, -1, 0, 1) - + # -Y "top" face. vertex(-1, -1, -1, 0, 0) vertex(1, -1, -1, 1, 0) vertex(1, -1, 1, 1, 1) vertex(-1, -1, 1, 0, 1) - + # +X "right" face. vertex(1, -1, 1, 0, 0) vertex(1, -1, -1, 1, 0) vertex(1, 1, -1, 1, 1) vertex(1, 1, 1, 0, 1) - + # -X "left" face. vertex(-1, -1, -1, 0, 0) vertex(-1, -1, 1, 1, 0) vertex(-1, 1, 1, 1, 1) vertex(-1, 1, -1, 0, 1) - def mouseDragged(): + global rotx, roty rate = 0.01 rotx += (pmouseY - mouseY) * rate roty += (mouseX - pmouseX) * rate diff --git a/mode/examples/Topics/Textures/TextureCylinder/TextureCylinder.pyde b/mode/examples/Topics/Textures/TextureCylinder/TextureCylinder.pyde index 2b433a4f..f3a8685e 100644 --- a/mode/examples/Topics/Textures/TextureCylinder/TextureCylinder.pyde +++ b/mode/examples/Topics/Textures/TextureCylinder/TextureCylinder.pyde @@ -14,6 +14,7 @@ img = None def setup(): size(640, 360, P3D) + global halfWidth, halfHeight, img halfWidth = width / 2.0 halfHeight = height / 2.0 img = loadImage("berlin-1.jpg") diff --git a/mode/examples/Topics/Textures/TextureSphere/TextureSphere.pyde b/mode/examples/Topics/Textures/TextureSphere/TextureSphere.pyde index ad3bf502..6ce93738 100644 --- a/mode/examples/Topics/Textures/TextureSphere/TextureSphere.pyde +++ b/mode/examples/Topics/Textures/TextureSphere/TextureSphere.pyde @@ -1,6 +1,6 @@ """ Texture Sphere -by Mike 'Flux' Chang (cleaned up by Aaron Koblin). +by Mike 'Flux' Chang. Based on code by Toxi. A 3D textured sphere with simple rotation control. @@ -31,11 +31,12 @@ sinLUT = [] cosLUT = [] SinCosPrecision = 0.5 -SinCosLength = 360.0 / SinCosPrecision +SinCosLength = int(360.0 / SinCosPrecision) def setup(): size(640, 360, P3D) + global thirdWidth, halfHeight, texmap thirdWidth = width * 0.33 halfHeight = height * 0.5 texmap = loadImage("world32k.jpg") @@ -48,17 +49,18 @@ def draw(): def renderGlobe(): + global rotationX, rotationY, velocityX, velocityY with pushMatrix(): translate(thirdWidth, halfHeight, pushBack) - + with pushMatrix(): noFill() stroke(255, 200) strokeWeight(2) smooth() - + lights() - + with pushMatrix(): rotateX(radians(-rotationX)) rotateY(radians(270 - rotationY)) @@ -66,7 +68,6 @@ def renderGlobe(): noStroke() textureMode(IMAGE) texturedSphere(globeRadius, texmap) - rotationX += velocityX rotationY += velocityY @@ -81,7 +82,7 @@ def renderGlobe(): def initializeSphere(res): - + global sphereRes for i in range(SinCosLength): sinLUT.append(sin(radians(i * SinCosPrecision))) cosLUT.append(cos(radians(i * SinCosPrecision))) diff --git a/mode/keywords.txt b/mode/keywords.txt index 1e5a9365..117461e0 100644 --- a/mode/keywords.txt +++ b/mode/keywords.txt @@ -80,6 +80,7 @@ ERODE LITERAL2 filter_ ESC LITERAL2 keyCode EXCLUSION LITERAL2 blend_ EXIT LITERAL2 +FX2D LITERAL2 size_ GIF LITERAL2 GRAY LITERAL2 filter_ GREEN_MASK LITERAL2 @@ -192,6 +193,8 @@ assert KEYWORD1 class KEYWORD1 def KEYWORD1 del KEYWORD1 +dict FUNCTION1 +enumerate FUNCTION1 exec KEYWORD1 from KEYWORD1 global KEYWORD1 @@ -201,7 +204,13 @@ is KEYWORD1 not KEYWORD1 or KEYWORD1 print KEYWORD1 - +range KEYWORD1 +reversed FUNCTION1 +sorted FUNCTION1 +tuple FUNCTION1 +xrange KEYWORD1 +zip FUNCTION1 +items FUNCTION2 // Datatypes @@ -255,8 +264,8 @@ boolean FUNCTION1 booleanconvert_ byte FUNCTION1 byteconvert_ cache FUNCTION2 char FUNCTION1 charconvert_ -start FUNCTION1 -stop FUNCTION1 +//start FUNCTION1 +//stop FUNCTION1 breakShape FUNCTION1 createPath FUNCTION1 float FUNCTION1 floatconvert_ @@ -406,6 +415,7 @@ dist FUNCTION1 dist_ draw FUNCTION4 draw ellipse FUNCTION1 ellipse_ ellipseMode FUNCTION1 ellipseMode_ +circle FUNCTION1 circle_ emissive FUNCTION1 emissive_ endCamera FUNCTION1 endCamera_ endContour FUNCTION1 endContour_ @@ -635,6 +645,7 @@ point FUNCTION1 point_ pointLight FUNCTION1 pointLight_ popMatrix FUNCTION1 popMatrix_ popStyle FUNCTION1 popStyle_ +pop FUNCTION1 pop_ pow FUNCTION1 pow_ print FUNCTION1 print_ printCamera FUNCTION1 printCamera_ @@ -667,6 +678,7 @@ setVisible FUNCTION2 PShape_setVisible_ translate FUNCTION2 PShape_translate_ pushMatrix FUNCTION1 pushMatrix_ pushStyle FUNCTION1 pushStyle_ +push FUNCTION1 push_ PVector KEYWORD5 PVector add FUNCTION2 PVector_add_ angleBetween FUNCTION2 PVector_angleBetween_ @@ -700,6 +712,7 @@ randomGaussian FUNCTION1 randomGaussian_ randomSeed FUNCTION1 randomSeed_ rect FUNCTION1 rect_ rectMode FUNCTION1 rectMode_ +square FUNCTION1 square_ red FUNCTION1 red_ redraw FUNCTION1 redraw_ requestImage FUNCTION1 requestImage_ @@ -804,7 +817,7 @@ matchRows FUNCTION2 Table_matchRows_ removeColumn FUNCTION2 Table_removeColumn_ removeRow FUNCTION2 Table_removeRow_ removeTokens FUNCTION2 Table_removeTokens_ -rows FUNCTION2 Table_rows_ +//rows FUNCTION2 Table_rows_ setFloat FUNCTION2 Table_setFloat_ setInt FUNCTION2 Table_setInt_ setString FUNCTION2 Table_setString_ diff --git a/mode/mode.properties b/mode/mode.properties index bd13a399..87e5ee02 100644 --- a/mode/mode.properties +++ b/mode/mode.properties @@ -1,11 +1,11 @@ -name = Python +name = Python Mode for Processing 3 authorList = [Jonathan Feinberg](http://MrFeinberg.com/) url = https://github.com/jdf/processing.py sentence = Write Processing sketches in Python. paragraph = version = @@version@@ prettyVersion = @@pretty-version@@ -# 2.2.1 -minRevision = 227 -# 3.0a5 -maxRevision = 232 +# 3.0 +minRevision = 246 +# <3.2 +maxRevision = 0 diff --git a/native/libjniosx.dylib b/native/libjniosx.dylib new file mode 100644 index 00000000..8b7599c1 Binary files /dev/null and b/native/libjniosx.dylib differ diff --git a/processing-py-test-suite.launch b/processing-py-test-suite.launch index 0fd0b4aa..7d5ac6b7 100644 --- a/processing-py-test-suite.launch +++ b/processing-py-test-suite.launch @@ -39,5 +39,6 @@ + diff --git a/processing-py.app/Contents/Resources/script b/processing-py.app/Contents/Resources/script index cbab0ea8..851d838b 100755 --- a/processing-py.app/Contents/Resources/script +++ b/processing-py.app/Contents/Resources/script @@ -19,7 +19,8 @@ JVM_ARGS="-Xmx1024m" # #### JAVA=`which java` -BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +THIS_FILE="$( readlink "$( which ${BASH_SOURCE[0]} )" || echo ${BASH_SOURCE[0]} )" +BASEDIR="$( cd "$( dirname $THIS_FILE )" && pwd )" PLATFORM='unknown' SPLASH="-splash:$BASEDIR/libraries/runtime/splash.png" REDIRECT="--noredirect" diff --git a/pushbuild.sh b/pushbuild.sh deleted file mode 100755 index dc7e39ed..00000000 --- a/pushbuild.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -cd /Users/feinberg/processing/build && \ - ant -Dversion=feinberg macosx-dist && \ - scp -i ~/.ssh/id_rsa-processing.org macosx/processing-feinberg-macosx.zip jdf@processing.org:/var/www/py && \ - cd ../../processing.py && \ - ant upload-mode diff --git a/runtime/src/jycessing/DevNullPrinter.java b/runtime/src/jycessing/DevNullPrinter.java index 723946bd..af80ef2f 100644 --- a/runtime/src/jycessing/DevNullPrinter.java +++ b/runtime/src/jycessing/DevNullPrinter.java @@ -8,4 +8,9 @@ public DevNullPrinter() {} public void print(final Object o) { // no-op } + + @Override + public void flush() { + // no-op + } } diff --git a/runtime/src/jycessing/DisplayType.java b/runtime/src/jycessing/DisplayType.java index 493b90eb..85a2dce2 100644 --- a/runtime/src/jycessing/DisplayType.java +++ b/runtime/src/jycessing/DisplayType.java @@ -1,5 +1,6 @@ package jycessing; public enum DisplayType { - WINDOWED, PRESENTATION; + WINDOWED, + PRESENTATION; } diff --git a/runtime/src/jycessing/IOUtil.java b/runtime/src/jycessing/IOUtil.java index 623e6553..96dcabbc 100644 --- a/runtime/src/jycessing/IOUtil.java +++ b/runtime/src/jycessing/IOUtil.java @@ -48,28 +48,31 @@ public static String readText(final Path path) throws IOException { /** * Recursively deletes the given directory or file. + * * @param target Path of file to be deleted. * @throws IOException */ public static void rm(final Path target) throws IOException { - Files.walkFileTree(target, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) - throws IOException { - Files.delete(file); - return CONTINUE; - } + Files.walkFileTree( + target, + new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) + throws IOException { + Files.delete(file); + return CONTINUE; + } - @Override - public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) - throws IOException { - if (exc != null) { - throw exc; - } - Files.delete(dir); - return CONTINUE; - } - }); + @Override + public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) + throws IOException { + if (exc != null) { + throw exc; + } + Files.delete(dir); + return CONTINUE; + } + }); } public static void copy(final Path src, final Path target) throws IOException { diff --git a/runtime/src/jycessing/LibraryImporter.java b/runtime/src/jycessing/LibraryImporter.java index 9c4e91e0..50f432e6 100644 --- a/runtime/src/jycessing/LibraryImporter.java +++ b/runtime/src/jycessing/LibraryImporter.java @@ -1,7 +1,6 @@ package jycessing; import java.io.File; -import java.io.FileFilter; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Field; @@ -15,6 +14,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; @@ -34,16 +34,16 @@ /** * {@link LibraryImporter} contributes the add_library function to processing.py. - * - *

add_library causes the given Processing library (all of its jar files and - * library subdirectories potentially containing native code) to be added to the - * system {@link ClassLoader}, the native code search path, and the Jython sys.path. - * It then generates import statements bringing all top-level classes available - * in the main library jar file into the sketch's namespace. - * - *

Note: Once jar files and directories have been added in this fashion to the - * classloader and native lib search path, they're good and stuck there. In practice, - * this hasn't presented any difficulty. But it's good to keep in mind. + * + *

add_library causes the given Processing library (all of its jar files and library + * subdirectories potentially containing native code) to be added to the system {@link ClassLoader}, + * the native code search path, and the Jython sys.path. It then generates import statements + * bringing all top-level classes available in the main library jar file into the sketch's + * namespace. + * + *

Note: Once jar files and directories have been added in this fashion to the classloader and + * native lib search path, they're good and stuck there. In practice, this hasn't presented any + * difficulty. But it's good to keep in mind. */ class LibraryImporter { private static void log(final String msg) { @@ -87,14 +87,13 @@ public PyObject __call__(final PyObject[] args, final String[] kws) { } /** - * Locate the library in the library folder "libName", find what - * it exports for the current platform, and add exports to the - * system classpath, the system native library path, and jython's + * Locate the library in the library folder "libName", find what it exports for the current + * platform, and add exports to the system classpath, the system native library path, and jython's * sys.path. - * - * Then, go through the main jar file of the library and import - * all of its publicly exposed classes. - * + * + *

Then, go through the main jar file of the library and import all of its publicly exposed + * classes. + * * @param libName The name of the library to import */ protected void addLibrary(final String libName) { @@ -130,12 +129,33 @@ protected void addLibrary(final String libName) { if (libDir == null) { interp.exec("raise Exception('This sketch requires the \"" + libName + "\" library.')"); } + final File contentsDir = new File(libDir, "library"); if (!contentsDir.exists()) { interp.exec("raise Exception('The library " + libName + " is malformed and won't import.')"); } final File mainJar = new File(contentsDir, libName + ".jar"); + log("mainJar: " + mainJar); + log("Adding dir: " + contentsDir); + recursivelyAddJarsToClasspath(contentsDir); + log("Platform: " + PLATFORM + " Bits: " + BITS); + if (PLATFORM.indexOf("windows") != -1) { + File nativeDir; + nativeDir = new File(libDir, "library/windows" + BITS); + if (!nativeDir.isDirectory()) { + nativeDir = contentsDir; + } + recursivelyLoadNativeLibraries(nativeDir); + } + + if (mainJar.exists()) { + log("adding mainJar"); + importPublicClassesFromJar(mainJar); + } + } + + private void recursivelyAddJarsToClasspath(final File contentsDir) { final List resources = findResources(contentsDir); final PySystemState sys = Py.getSystemState(); for (final File resource : resources) { @@ -145,26 +165,74 @@ protected void addLibrary(final String libName) { addJarToClassLoader(resource.getAbsoluteFile()); log("Appending " + resource.getAbsolutePath() + " to sys.path."); - sys.path.append(Py.newString(resource.getAbsolutePath())); + sys.path.append(Py.newStringUTF8(resource.getAbsolutePath())); + } else if (resource.isDirectory()) { + recursivelyAddToClasspath(resource); + } + } + } - // Are we missing any extensions? - } else if (name.matches("^.*\\.(so|dll|dylib|jnilib)$")) { + private void recursivelyLoadNativeLibraries(final File contentsDir) { + final List resources = findResources(contentsDir); + final PySystemState sys = Py.getSystemState(); + LinkedList stack = new LinkedList(resources); + log("Dependency stack length: " + stack.size()); + // Terrible, horrible, no good, very bad, hack to load dependencies + // There are n! permutations here, which is unrealistic. + // 4096 seems like a realistic number to give up on + int timeToDie = 4096; + while (!stack.isEmpty() && timeToDie > 0) { + File resource = stack.poll(); + final String name = resource.getName(); + log("Resource name: " + name); + if (name.matches("^.*\\.(so|dll|dylib|jnilib)$")) { // Add *containing directory* to native search path + log("addDirectoryToNativeSearchPath: " + resource.getAbsoluteFile().getParentFile().getAbsolutePath()); addDirectoryToNativeSearchPath(resource.getAbsoluteFile().getParentFile()); + log("Loading library: " + resource.getAbsoluteFile().getName()); + try { + System.load(resource.getAbsolutePath()); + } catch (UnsatisfiedLinkError e) { + stack.add(resource); + } + } else if (resource.isDirectory()) { + recursivelyAddToClasspath(resource); + } + timeToDie--; + if (timeToDie == 0) { + throw new UnsatisfiedLinkError("Unable to satisfy dependencies for " + name + " after 4096 tries."); } } + } - importPublicClassesFromJar(mainJar); + private void recursivelyAddToClasspath(final File contentsDir) { + final List resources = findResources(contentsDir); + final PySystemState sys = Py.getSystemState(); + for (final File resource : resources) { + final String name = resource.getName(); + if (name.endsWith(".jar") || name.endsWith(".zip")) { + // Contains stuff we want + addJarToClassLoader(resource.getAbsoluteFile()); + + log("Appending " + resource.getAbsolutePath() + " to sys.path."); + sys.path.append(Py.newStringUTF8(resource.getAbsolutePath())); + } else if (name.matches("^.*\\.(so|dll|dylib|jnilib)$")) { + // Add *containing directory* to native search path + log("addDirectoryToNativeSearchPath: " + resource.getAbsoluteFile().getParentFile().getName()); + addDirectoryToNativeSearchPath(resource.getAbsoluteFile().getParentFile()); + } else if (resource.isDirectory()) { + recursivelyAddToClasspath(resource); + } + } } /** - * Find all of the resources a library requires on this platform. - * See https://github.com/processing/processing/wiki/Library-Basics. - * - * First, finds the library. - * Second, tries to parse export.txt, and follow its instructions. + * Find all of the resources a library requires on this platform. See + * https://github.com/processing/processing/wiki/Library-Basics. + * + *

First, finds the library. Second, tries to parse export.txt, and follow its instructions. * Third, tries to understand folder structure, and export according to that. - * + * * @param libName The name of the library to add. * @return The list of files we need to import. */ @@ -174,7 +242,9 @@ protected List findResources(final File contentsDir) { resources = findResourcesFromExportTxt(contentsDir); if (resources == null) { log("Falling back to directory structure."); - resources = findResourcesFromDirectoryStructure(contentsDir); + resources = Arrays.asList(contentsDir.listFiles((final File dir, final String s) -> { + return !s.startsWith("."); + })); } return resources; } @@ -211,7 +281,7 @@ private List findResourcesFromExportTxt(final File contentsDir) { } final List resources = new ArrayList<>(); for (final String resourceName : resourceNames) { - final File resource = new File(contentsDir, resourceName); + final File resource = new File(contentsDir, resourceName).getAbsoluteFile(); if (resource.exists()) { resources.add(resource); } else { @@ -223,49 +293,11 @@ private List findResourcesFromExportTxt(final File contentsDir) { return resources; } - private List findResourcesFromDirectoryStructure(final File contentsDir) { - final List childNames = Arrays.asList(contentsDir.list()); - final List resources = new ArrayList(); - - // Find platform-specific stuff - File platformDir = null; - if (childNames.contains(PLATFORM + BITS)) { - final File potentialPlatformDir = new File(contentsDir, PLATFORM + BITS); - if (potentialPlatformDir.isDirectory()) { - platformDir = potentialPlatformDir; - } - } - if (platformDir == null && childNames.contains(PLATFORM)) { - final File potentialPlatformDir = new File(contentsDir, PLATFORM); - if (potentialPlatformDir.isDirectory()) { - platformDir = potentialPlatformDir; - } - } - if (platformDir != null) { - log("Found platform-specific directory " + platformDir.getAbsolutePath()); - for (final File resource : platformDir.listFiles()) { - resources.add(resource); - } - } - - // Find multi-platform stuff; always do this - final File[] commonResources = contentsDir.listFiles(new FileFilter() { - @Override - public boolean accept(final File file) { - return !file.isDirectory(); - } - }); - for (final File resource : commonResources) { - resources.add(resource); - } - return resources; - } - /** - * Parse an export.txt file to figure out what we need to load for this platform. - * This is all duplicated from processing.app.Library / processing.app.Base, - * but we don't have the PDE around at runtime so we can't use them. - * + * Parse an export.txt file to figure out what we need to load for this platform. This is all + * duplicated from processing.app.Library / processing.app.Base, but we don't have the PDE around + * at runtime so we can't use them. + * * @param exportTxt The export.txt file; must exist. */ private Map parseExportTxt(final File exportTxt) throws Exception { @@ -290,8 +322,8 @@ private Map parseExportTxt(final File exportTxt) throws Except } /** - * Use a brittle and egregious hack to forcibly add the given jar file to the - * system classloader. + * Use a brittle and egregious hack to forcibly add the given jar file to the system classloader. + * * @param jar The jar to add to the system classloader. */ private void addJarToClassLoader(final File jar) { @@ -315,14 +347,11 @@ private void addJarToClassLoader(final File jar) { } /** - * Add the given path to the list of paths searched for DLLs (as in those - * loaded by loadLibrary). A hack, which depends on the presence of a - * particular field in ClassLoader. Known to work on all recent Sun JVMs and - * OS X. + * Add the given path to the list of paths searched for DLLs (as in those loaded by loadLibrary). + * A hack, which depends on the presence of a particular field in ClassLoader. Known to work on + * all recent Sun JVMs and OS X. * - *

- * See this - * thread. + *

See this thread. */ private void addDirectoryToNativeSearchPath(final File dllDir) { final String newPath = dllDir.getAbsolutePath(); @@ -340,13 +369,12 @@ private void addDirectoryToNativeSearchPath(final File dllDir) { field.set(null, tmp); log("Added " + newPath + " to java.library.path."); } catch (final Exception e) { - System.err.println("While attempting to add " + newPath - + " to the processing.py library search path: " + e.getClass().getSimpleName() + "--" - + e.getMessage()); + System.err.println( + "While attempting to add " + newPath + " to the processing.py library search path: " + + e.getClass().getSimpleName() + "--" + e.getMessage()); } } - private static final Pattern validPythonIdentifier = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*"); /* @@ -357,9 +385,9 @@ private void addDirectoryToNativeSearchPath(final File dllDir) { com.foo.Banana$1.class com.foo.Banana$2.class com.bar.Kiwi.class - + then we'll generate these import statements: - + from com.foo import Banana from com.bar import Kiwi */ @@ -396,6 +424,18 @@ private void importPublicClassesFromJar(final File jarPath) { continue; } + /** + * A class in a library jar may refer to other classes not present in this runtime. + * Proactively draw out such an error now, so we can catch it (rather than way inside the + * Jython interpreter, where it unceremoniously throws and terminates). The particular + * example that led to this hack is proscene's reference to Android classes. + */ + try { + Class.forName(String.format("%s.%s", packageName, className)).getMethods(); + } catch (final ClassNotFoundException | NoClassDefFoundError e) { + log("Rejecting " + name); + continue; + } final String importStatement = String.format("from %s import %s", packageName, className); log(importStatement); interp.exec(importStatement); diff --git a/runtime/src/jycessing/MixedModeError.java b/runtime/src/jycessing/MixedModeError.java index 1bb84329..e9676b06 100644 --- a/runtime/src/jycessing/MixedModeError.java +++ b/runtime/src/jycessing/MixedModeError.java @@ -8,5 +8,4 @@ public MixedModeError() { public MixedModeError(final String message, final String fileName, final int line) { super(message, fileName, line); } - } diff --git a/runtime/src/jycessing/MixedSmoothError.java b/runtime/src/jycessing/MixedSmoothError.java new file mode 100644 index 00000000..32940ca8 --- /dev/null +++ b/runtime/src/jycessing/MixedSmoothError.java @@ -0,0 +1,11 @@ +package jycessing; + +public class MixedSmoothError extends PythonSketchError { + public MixedSmoothError() { + super("smooth() and noSmooth() cannot be used in the same sketch."); + } + + public MixedSmoothError(final String message, final String fileName, final int line) { + super(message, fileName, line); + } +} diff --git a/runtime/src/jycessing/PAppletJythonDriver.java b/runtime/src/jycessing/PAppletJythonDriver.java old mode 100644 new mode 100755 index 0238e01d..b310a352 --- a/runtime/src/jycessing/PAppletJythonDriver.java +++ b/runtime/src/jycessing/PAppletJythonDriver.java @@ -1,21 +1,20 @@ /* * Copyright 2010 Jonathan Feinberg * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package jycessing; import java.awt.Component; +import java.awt.Frame; import java.awt.Point; import java.awt.Window; import java.awt.event.ComponentAdapter; @@ -31,17 +30,18 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.regex.Matcher; import java.util.regex.Pattern; -import jycessing.IOUtil.ResourceReader; -import jycessing.mode.run.WrappedPrintStream; -import jycessing.mode.run.WrappedPrintStream.PushedOut; +import javax.sound.midi.MidiMessage; import org.python.core.CompileMode; import org.python.core.CompilerFlags; +import org.python.core.JyAttribute; import org.python.core.Py; import org.python.core.PyBaseCode; import org.python.core.PyBoolean; @@ -53,6 +53,7 @@ import org.python.core.PyInteger; import org.python.core.PyJavaType; import org.python.core.PyObject; +import org.python.core.PyObjectDerived; import org.python.core.PySet; import org.python.core.PyString; import org.python.core.PyStringMap; @@ -62,6 +63,14 @@ import org.python.core.PyUnicode; import org.python.util.InteractiveConsole; +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import com.jogamp.newt.opengl.GLWindow; + +import jycessing.IOUtil.ResourceReader; +import jycessing.jni.OSX; +import jycessing.mode.run.WrappedPrintStream; +import jycessing.mode.run.WrappedPrintStream.PushedOut; import processing.awt.PSurfaceAWT; import processing.core.PApplet; import processing.core.PConstants; @@ -69,18 +78,11 @@ import processing.core.PSurface; import processing.event.KeyEvent; import processing.event.MouseEvent; +import processing.javafx.PSurfaceFX; +import processing.opengl.PGraphicsOpenGL; import processing.opengl.PShader; import processing.opengl.PSurfaceJOGL; -import com.google.common.base.Charsets; -import com.google.common.io.Files; -import com.jogamp.newt.opengl.GLWindow; - -/** - * - * @author Jonathan Feinberg <jdf@pobox.com> - * - */ @SuppressWarnings("serial") public class PAppletJythonDriver extends PApplet { @@ -92,8 +94,8 @@ public class PAppletJythonDriver extends PApplet { private static final ResourceReader resourceReader = new ResourceReader(PAppletJythonDriver.class); + private static final String GET_SETTINGS_SCRIPT = resourceReader.readText("get_settings.py"); private static final String DETECT_MODE_SCRIPT = resourceReader.readText("detect_sketch_mode.py"); - private static final String PREPROCESS_SCRIPT = resourceReader.readText("pyde_preprocessor.py"); static { @@ -102,6 +104,8 @@ public class PAppletJythonDriver extends PApplet { useNativeSelect = false; } + private Field frameField; + private PythonSketchError terminalException = null; protected final PyStringMap builtins; @@ -113,7 +117,9 @@ public class PAppletJythonDriver extends PApplet { private final CountDownLatch finishedLatch = new CountDownLatch(1); private enum Mode { - STATIC, ACTIVE, MIXED + STATIC, + ACTIVE, + MIXED } // A static-mode sketch must be interpreted from within the setup() method. @@ -121,12 +127,24 @@ private enum Mode { // definitions, which we then invoke during the run loop. private final Mode mode; + private int detectedWidth, detectedHeight, detectedPixelDensity; + private String detectedRenderer; + private boolean detectedSmooth, detectedNoSmooth, detectedFullScreen; + private PyObject processedStaticSketch; + + private static int argCount(final PyObject func) { + if (!(func instanceof PyFunction)) { + return -1; + } + return ((PyBaseCode) ((PyFunction) func).__code__).co_argcount; + } + /** - * The Processing event handling functions can take 0 or 1 argument. - * This class represents such a function. - *

If the user did not implement the variant that takes an event, - * then we have to pass through to the super implementation, or else - * the zero-arg version won't get called. + * The Processing event handling functions can take 0 or 1 argument. This class represents such a + * function. + * + *

If the user did not implement the variant that takes an event, then we have to pass through + * to the super implementation, or else the zero-arg version won't get called. */ private abstract class EventFunction { private final PyFunction func; @@ -135,8 +153,8 @@ private abstract class EventFunction { protected abstract void callSuper(T event); public EventFunction(final String funcName) { - func = (PyFunction)interp.get(funcName); - argCount = func == null ? -1 : ((PyBaseCode)(func).__code__).co_argcount; + func = (PyFunction) interp.get(funcName); + argCount = argCount(func); } public void invoke() { @@ -154,27 +172,66 @@ public void invoke(final T event) { } } + /** + * We maintain a map from function name to function in order to implement {@link + * PApplet#method(String)}. + */ + private final Map allFunctionsByName = new HashMap<>(); + // These are all of the methods that PApplet might call in your sketch. If // you have implemented a method, we save it and call it. - private PyObject setupMeth, settingsMeth, drawMeth, initMeth, pauseMeth, resumeMeth, stopMeth, - sketchFullScreenMeth, sketchWidthMeth, sketchHeightMeth, sketchRendererMeth; + private PyObject setupMeth, settingsMeth, drawMeth, pauseMeth, resumeMeth; + + // For compatibility, we look for definitions of both stop() and dispose() + // in the user's sketch, and call whatever's defined of those two when the sketch + // is dispose()d. If you define both, they'll both be called. + private PyObject stopMeth, disposeMeth; private EventFunction keyPressedFunc, keyReleasedFunc, keyTypedFunc; - private EventFunction mousePressedFunc, mouseClickedFunc, mouseMovedFunc, - mouseReleasedFunc, mouseDraggedFunc; + private EventFunction mousePressedFunc, + mouseClickedFunc, + mouseMovedFunc, + mouseReleasedFunc, + mouseDraggedFunc; private PyObject mouseWheelMeth; // Can only be called with a MouseEvent; no need for shenanigans - // Implement the Video library's callback. + // Implement the Video library's callbacks. private PyObject captureEventMeth, movieEventMeth; + // Implement the Serial library's callback. + private PyObject serialEventMeth; + + // Implement the net library's callbacks. + private PyObject clientEventMeth, disconnectEventMeth, serverEventMeth; + + // Implement the oscP5 library's callback. + private PyObject oscEventMeth; + + // Implement themidibus callbacks. + private PyObject noteOn3Meth, + noteOff3Meth, + controllerChange3Meth, + rawMidi1Meth, + midiMessage1Meth, + noteOn5Meth, + noteOff5Meth, + controllerChange5Meth, + rawMidi3Meth, + midiMessage3Meth; + + // Implement processing_websockets callbacks. + private PyObject webSocketEventMeth, webSocketServerEventMeth; + private SketchPositionListener sketchPositionListener; private void processSketch(final String scriptSource) throws PythonSketchError { try { interp.set("__processing_source__", programText); final PyCode code = - Py.compile_flags(scriptSource, pySketchPath.toString(), CompileMode.exec, - new CompilerFlags()); - interp.exec(code); + Py.compile_flags( + scriptSource, pySketchPath.toString(), CompileMode.exec, new CompilerFlags()); + try (PushedOut out = wrappedStdout.pushStdout()) { + interp.exec(code); + } Py.flushLine(); } catch (Throwable t) { while (t.getCause() != null) { @@ -186,6 +243,7 @@ private void processSketch(final String scriptSource) throws PythonSketchError { /** * Handy method for raising a Python exception in the current interpreter frame. + * * @param msg TypeError message. */ private PyObject raiseTypeError(final String msg) { @@ -198,18 +256,18 @@ private static PythonSketchError toSketchException(Throwable t) { t = t.getCause(); } if (t instanceof PythonSketchError) { - return (PythonSketchError)t; + return (PythonSketchError) t; } if (t instanceof PySyntaxError) { - final PySyntaxError e = (PySyntaxError)t; - return extractSketchErrorFromPyExceptionValue((PyTuple)e.value); + final PySyntaxError e = (PySyntaxError) t; + return extractSketchErrorFromPyExceptionValue((PyTuple) e.value); } if (t instanceof PyIndentationError) { - final PyIndentationError e = (PyIndentationError)t; - return extractSketchErrorFromPyExceptionValue((PyTuple)e.value); + final PyIndentationError e = (PyIndentationError) t; + return extractSketchErrorFromPyExceptionValue((PyTuple) e.value); } if (t instanceof PyException) { - final PyException e = (PyException)t; + final PyException e = (PyException) t; final Pattern tbParse = Pattern.compile("^\\s*File \"([^\"]+)\", line (\\d+)", Pattern.MULTILINE); final Matcher m = tbParse.matcher(e.toString()); @@ -228,7 +286,7 @@ private static PythonSketchError toSketchException(Throwable t) { } line = Integer.parseInt(m.group(2)) - 1; } - if (((PyType)e.type).getName().equals("ImportError")) { + if (((PyType) e.type).getName().equals("ImportError")) { final Pattern importStar = Pattern.compile("import\\s+\\*"); if (importStar.matcher(e.toString()).find()) { return new PythonSketchError("import * does not work in this environment.", file, line); @@ -242,13 +300,13 @@ private static PythonSketchError toSketchException(Throwable t) { } private static PythonSketchError extractSketchErrorFromPyExceptionValue(final PyTuple tup) { - final String pyMessage = (String)tup.get(0); + final String pyMessage = (String) tup.get(0); final String message = maybeMakeFriendlyMessage(pyMessage); - final PyTuple context = (PyTuple)tup.get(1); - final File file = new File((String)context.get(0)); + final PyTuple context = (PyTuple) tup.get(1); + final File file = new File((String) context.get(0)); final String fileName = file.getName(); - final int lineNumber = ((Integer)context.get(1)).intValue() - 1; - final int column = ((Integer)context.get(2)).intValue(); + final int lineNumber = ((Integer) context.get(1)).intValue() - 1; + final int column = ((Integer) context.get(2)).intValue(); if (pyMessage.startsWith("no viable alternative")) { return noViableAlternative(file, lineNumber, column, pyMessage); } @@ -259,21 +317,24 @@ private static PythonSketchError extractSketchErrorFromPyExceptionValue(final Py private static final Pattern NAKED_COLOR = Pattern.compile("[(,]\\s*#([0-9a-fA-F]{6})\\b"); /** - * The message "no vialble alternative" is a strong indication that there's an unclosed - * paren somewhere before the triggering line. Maybe the user tried to specify a color - * as in Java Processing, like fill(#FFAA55), which Python sees as an open - * paren followed by a comment. - *

This function takes a stab at finding such a thing, and reporting it. Otherwise, - * it throws a slightly less cryptic error message. + * The message "no viable alternative" is a strong indication that there's an unclosed paren + * somewhere before the triggering line. Maybe the user tried to specify a color as in Java + * Processing, like fill(#FFAA55), which Python sees as an open paren followed by a + * comment. + * + *

This function takes a stab at finding such a thing, and reporting it. Otherwise, it throws a + * slightly less cryptic error message. + * * @param file * @param line * @param column * @return */ - private static PythonSketchError noViableAlternative(final File file, final int lineNo, - final int column, final String message) { + private static PythonSketchError noViableAlternative( + final File file, final int lineNo, final int column, final String message) { if (message.equals("no viable alternative at input '&'")) { - return new PythonSketchError(C_LIKE_LOGICAL_AND_ERROR_MESSAGE, file.getName(), lineNo, column); + return new PythonSketchError( + C_LIKE_LOGICAL_AND_ERROR_MESSAGE, file.getName(), lineNo, column); } if (message.equals("no viable alternative at input '|'")) { return new PythonSketchError(C_LIKE_LOGICAL_OR_ERROR_MESSAGE, file.getName(), lineNo, column); @@ -281,17 +342,26 @@ private static PythonSketchError noViableAlternative(final File file, final int final PythonSketchError defaultException = new PythonSketchError( "Maybe there's an unclosed paren or quote mark somewhere before this line?", - file.getName(), lineNo, column); + file.getName(), + lineNo, + column); try { int lineIndex = 0; for (final String line : Files.readLines(file, Charsets.UTF_8)) { final Matcher m = NAKED_COLOR.matcher(line); if (m.find()) { final String color = m.group(1); - return new PythonSketchError("Did you try to name a color here? " - + "Colors in Python mode are either strings, like '#" + color + "', or " - + "large hex integers, like 0xFF" + color.toUpperCase() + ".", file.getName(), - lineIndex, m.start(1)); + return new PythonSketchError( + "Did you try to name a color here? " + + "Colors in Python mode are either strings, like '#" + + color + + "', or " + + "large hex integers, like 0xFF" + + color.toUpperCase() + + ".", + file.getName(), + lineIndex, + m.start(1)); } lineIndex++; } @@ -320,26 +390,60 @@ public void frameMoved(final int x, final int y) { } } - public PAppletJythonDriver(final InteractiveConsole interp, final String pySketchPath, - final String programText, final Printer stdout) throws PythonSketchError { - this.wrappedStdout = new WrappedPrintStream(System.out) { - @Override - public void doPrint(final String s) { - stdout.print(s); - } - }; + public PAppletJythonDriver( + final InteractiveConsole interp, + final String pySketchPath, + final String programText, + final Printer stdout) + throws PythonSketchError { + this.wrappedStdout = + new WrappedPrintStream(System.out) { + @Override + public void doPrint(final String s) { + stdout.print(s); + } + }; this.programText = programText; this.pySketchPath = Paths.get(pySketchPath); this.interp = interp; - this.builtins = (PyStringMap)interp.getSystemState().getBuiltins(); + this.builtins = (PyStringMap) interp.getSystemState().getBuiltins(); - interp.set("__file__", new File(pySketchPath).getName()); + interp.set("__file__", Py.newStringUTF8(new File(pySketchPath).getName())); processSketch(DETECT_MODE_SCRIPT); this.mode = Mode.valueOf(interp.get("__mode__").asString()); Runner.log("Mode: ", mode.name()); if (mode == Mode.MIXED) { throw interp.get("__error__", MixedModeError.class); } + if (mode == Mode.STATIC) { + processSketch(GET_SETTINGS_SCRIPT); + detectedWidth = interp.get("__width__").asInt(); + detectedHeight = interp.get("__height__").asInt(); + detectedPixelDensity = interp.get("__pixelDensity__").asInt(); + detectedSmooth = interp.get("__smooth__").asInt() != 0; + detectedNoSmooth = interp.get("__noSmooth__").asInt() != 0; + final String r = interp.get("__renderer__").asString(); + if (r.equals("JAVA2D")) { + detectedRenderer = JAVA2D; + } else if (r.equals("P2D")) { + detectedRenderer = P2D; + } else if (r.equals("P3D")) { + detectedRenderer = P3D; + } else if (r.equals("OPENGL")) { + detectedRenderer = P3D; + } else if (r.equals("FX2D")) { + detectedRenderer = FX2D; + } else if (r.equals("PDF")) { + detectedRenderer = PDF; + } else if (r.equals("SVG")) { + detectedRenderer = SVG; + } else if (r.equals("DXF")) { + detectedRenderer = DXF; + } else { + detectedRenderer = r; + } + processedStaticSketch = interp.get("__cleaned_sketch__"); + } initializeStatics(builtins); setFilter(); @@ -347,35 +451,122 @@ public void doPrint(final String s) { setSet(); setColorMethods(); setText(); - builtins.__setitem__("g", Py.java2py(g)); // Make sure key and keyCode are defined. - builtins.__setitem__("key", Py.newUnicode((char)0)); + builtins.__setitem__("key", Py.newUnicode((char) 0)); builtins.__setitem__("keyCode", pyint(0)); } + // method to find the frame field, rather than relying on an Exception + private Field getFrameField() { + for (Field field : getClass().getFields()) { + if (field.getName().equals("frame")) { + return field; + } + } + return null; + } + @Override protected PSurface initSurface() { final PSurface s = super.initSurface(); + + frameField = getFrameField(); + if (frameField != null) { + try { + // eliminate a memory leak from 2.x compat hack + frameField.set(this, null); + } catch (Exception e) { + // safe enough to ignore; this was a workaround + } + } + + s.setTitle(pySketchPath.getFileName().toString().replaceAll("\\..*$", "")); if (s instanceof PSurfaceAWT) { - final PSurfaceAWT surf = (PSurfaceAWT)s; - final Component c = (Component)surf.getNative(); - c.addComponentListener(new ComponentAdapter() { - @Override - public void componentHidden(final ComponentEvent e) { - finishedLatch.countDown(); - } - }); + final PSurfaceAWT surf = (PSurfaceAWT) s; + final Component c = (Component) surf.getNative(); + c.addComponentListener( + new ComponentAdapter() { + @Override + public void componentHidden(final ComponentEvent e) { + finishedLatch.countDown(); + } + }); } else if (s instanceof PSurfaceJOGL) { - final PSurfaceJOGL surf = (PSurfaceJOGL)s; - final GLWindow win = (GLWindow)surf.getNative(); - win.addWindowListener(new com.jogamp.newt.event.WindowAdapter() { - @Override - public void windowDestroyed(final com.jogamp.newt.event.WindowEvent arg0) { - finishedLatch.countDown(); - } - }); + final PSurfaceJOGL surf = (PSurfaceJOGL) s; + final GLWindow win = (GLWindow) surf.getNative(); + win.addWindowListener( + new com.jogamp.newt.event.WindowAdapter() { + @Override + public void windowDestroyed(final com.jogamp.newt.event.WindowEvent arg0) { + finishedLatch.countDown(); + } + }); + } else if (s instanceof PSurfaceFX) { + System.err.println("I don't know how to watch FX2D windows for close."); } + + final PyObject pyG; + if (g instanceof PGraphicsOpenGL) { + /* + * The name "camera" in PGraphicsOpenGL can refer to either a PMatrix3D field + * or a couple of functions of that name. Unfortunately, Python only has one namespace, + * not separate namespaces for functions and fields. So here we create new attributes + * on the "g" object that are aliases to the matrix fields. It's only necessary to + * do this for "camera" itself, but, for the sake of consistency, we do it for + * all of them. + * + * So, in Python Mode: + * + * def setup(): + * size(300, 300, P3D) + * + * def mousePressed(): + * # do something silly to the PGraphics camera + * g.camera(1, 2, 3, 4, 5, 6, 7, 8, 9) + * + * # read back what we did + * print g.cameraMatrix.m02 + */ + final PGraphicsOpenGL glGraphics = (PGraphicsOpenGL) g; + final PyObject cameraMatrix = Py.java2py(glGraphics.camera); + final PyObject cameraInvMatrix = Py.java2py(glGraphics.cameraInv); + final PyObject modelviewMatrix = Py.java2py(glGraphics.modelview); + final PyObject modelviewInvMatrix = Py.java2py(glGraphics.modelviewInv); + final PyObject projmodelviewMatrix = Py.java2py(glGraphics.projmodelview); + pyG = + new PyObjectDerived(PyType.fromClass(g.getClass(), false)) { + @Override + public PyObject __findattr_ex__(final String name) { + if (name == "cameraMatrix") { // name is interned + return cameraMatrix; + } + if (name == "cameraInvMatrix") { + return cameraInvMatrix; + } + if (name == "modelviewMatrix") { + return modelviewMatrix; + } + if (name == "modelviewInvMatrix") { + return modelviewInvMatrix; + } + if (name == "projmodelviewMatrix") { + return projmodelviewMatrix; + } + return super.__findattr_ex__(name); + } + }; + JyAttribute.setAttr(pyG, JyAttribute.JAVA_PROXY_ATTR, g); + } else { + pyG = Py.java2py(g); + } + // We want the builtin "g" object to behave just like PGraphics instances + // created with createGraphics(), so that its beginPGL can be used in a with + // statement, etc. + interp.set("__original_g__", pyG); + final PyObject wrappedG = interp.eval("PGraphicsPythonModeWrapper(__original_g__)"); + builtins.__setitem__("g", wrappedG); + return s; } @@ -384,6 +575,36 @@ public void exitActual() { finishedLatch.countDown(); } + /** Call the user-defined Python function with the given name. */ + @Override + public void method(final String name) { + final PyFunction f = allFunctionsByName.get(name); + if (f != null) { + f.__call__(); + } else { + super.method(name); + } + } + + /** + * Python Mode's {@link PApplet#thread(String)} can take a {@link String} (like Java mode) or a + * function object. + * + * @param obj either a {@link PyString} or a {@link PyFunction} to run in a thread. + */ + public void thread(final Object obj) { + if (obj instanceof String) { + super.thread((String) obj); + } else if (obj instanceof PyFunction) { + new Thread() { + @Override + public void run() { + ((PyFunction) obj).__call__(); + } + }.start(); + } + } + public void findSketchMethods() throws PythonSketchError { if (mode == Mode.ACTIVE) { // Executing the sketch will bind method names ("draw") to PyCode @@ -392,89 +613,185 @@ public void findSketchMethods() throws PythonSketchError { processSketch(PREPROCESS_SCRIPT); } + for (final Object local : ((PyStringMap) interp.getLocals()).items()) { + final PyTuple t = (PyTuple) local; + final String k = t.get(0).toString(); + final Object v = t.get(1); + if (v instanceof PyFunction) { + allFunctionsByName.put(k, (PyFunction) v); + } + } + // Find and cache any PApplet callbacks defined in the Python sketch drawMeth = interp.get("draw"); setupMeth = interp.get("setup"); - mousePressedFunc = new EventFunction("mousePressed") { - @Override - protected void callSuper(final MouseEvent event) { - PAppletJythonDriver.super.mousePressed(event); - } - }; - mouseClickedFunc = new EventFunction("mouseClicked") { - @Override - protected void callSuper(final MouseEvent event) { - PAppletJythonDriver.super.mouseClicked(event); - } - }; - mouseMovedFunc = new EventFunction("mouseMoved") { - @Override - protected void callSuper(final MouseEvent event) { - PAppletJythonDriver.super.mouseMoved(event); - } - }; - mouseReleasedFunc = new EventFunction("mouseReleased") { - @Override - protected void callSuper(final MouseEvent event) { - PAppletJythonDriver.super.mouseReleased(event); - } - }; - mouseDraggedFunc = new EventFunction("mouseDragged") { - @Override - protected void callSuper(final MouseEvent event) { - PAppletJythonDriver.super.mouseDragged(event); - } - }; - - keyPressedFunc = new EventFunction("keyPressed") { - @Override - protected void callSuper(final KeyEvent event) { - PAppletJythonDriver.super.keyPressed(event); - } - }; - keyReleasedFunc = new EventFunction("keyReleased") { - @Override - protected void callSuper(final KeyEvent event) { - PAppletJythonDriver.super.keyReleased(event); - } - }; - keyTypedFunc = new EventFunction("keyTyped") { - @Override - protected void callSuper(final KeyEvent event) { - PAppletJythonDriver.super.keyTyped(event); - } - }; + mousePressedFunc = + new EventFunction("mousePressed") { + @Override + protected void callSuper(final MouseEvent event) { + PAppletJythonDriver.super.mousePressed(event); + } + }; + mouseClickedFunc = + new EventFunction("mouseClicked") { + @Override + protected void callSuper(final MouseEvent event) { + PAppletJythonDriver.super.mouseClicked(event); + } + }; + mouseMovedFunc = + new EventFunction("mouseMoved") { + @Override + protected void callSuper(final MouseEvent event) { + PAppletJythonDriver.super.mouseMoved(event); + } + }; + mouseReleasedFunc = + new EventFunction("mouseReleased") { + @Override + protected void callSuper(final MouseEvent event) { + PAppletJythonDriver.super.mouseReleased(event); + } + }; + mouseDraggedFunc = + new EventFunction("mouseDragged") { + @Override + protected void callSuper(final MouseEvent event) { + PAppletJythonDriver.super.mouseDragged(event); + } + }; + + // keyPressed is renamed to __keyPressed__ by the preprocessor. + keyPressedFunc = + new EventFunction("__keyPressed__") { + @Override + protected void callSuper(final KeyEvent event) { + PAppletJythonDriver.super.keyPressed(event); + } + }; + keyReleasedFunc = + new EventFunction("keyReleased") { + @Override + protected void callSuper(final KeyEvent event) { + PAppletJythonDriver.super.keyReleased(event); + } + }; + keyTypedFunc = + new EventFunction("keyTyped") { + @Override + protected void callSuper(final KeyEvent event) { + PAppletJythonDriver.super.keyTyped(event); + } + }; - sketchFullScreenMeth = interp.get("sketchFullScreen"); - sketchWidthMeth = interp.get("sketchWidth"); - sketchHeightMeth = interp.get("sketchHeight"); - sketchRendererMeth = interp.get("sketchRenderer"); settingsMeth = interp.get("settings"); - initMeth = interp.get("init"); stopMeth = interp.get("stop"); + disposeMeth = interp.get("dispose"); pauseMeth = interp.get("pause"); resumeMeth = interp.get("resume"); mouseWheelMeth = interp.get("mouseWheel"); if (mousePressedFunc.func != null) { // The user defined a mousePressed() method, which will hide the magical // Processing variable boolean mousePressed. We have to do some magic. - interp.getLocals().__setitem__("mousePressed", new PyBoolean(false) { - @Override - public boolean getBooleanValue() { - return mousePressed; - } - - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - return mousePressedFunc.func.__call__(args, kws); - } - }); + interp + .getLocals() + .__setitem__( + "mousePressed", + new PyBoolean(false) { + @Override + public boolean getBooleanValue() { + return mousePressed; + } + + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + return mousePressedFunc.func.__call__(args, kws); + } + }); } // Video library callbacks. captureEventMeth = interp.get("captureEvent"); movieEventMeth = interp.get("movieEvent"); + + // Serial library callback. + serialEventMeth = interp.get("serialEvent"); + + // Net library callbacks. + clientEventMeth = interp.get("clientEvent"); + disconnectEventMeth = interp.get("disconnectEvent"); + serverEventMeth = interp.get("serverEvent"); + + // oscP5 library callback. + oscEventMeth = interp.get("oscEvent"); + + // themidibus callbacks + PyObject meth; + if ((meth = interp.get("noteOn")) != null) { + switch (argCount(meth)) { + default: + throw new RuntimeException( + "only noteOn(channel, pitch, velocity) or " + + "noteOn(channel, pitch, velocity, timestamp, bus_name) " + + "are supported by Python Mode"); + case 3: + noteOn3Meth = meth; + break; + case 5: + noteOn5Meth = meth; + } + } + if ((meth = interp.get("noteOff")) != null) { + switch (argCount(meth)) { + case 1: + throw new RuntimeException( + "only noteOff(channel, pitch, velocity) or " + + "noteOff(channel, pitch, velocity, timestamp, bus_name) " + + "are supported by Python Mode"); + case 3: + noteOff3Meth = meth; + break; + case 5: + noteOff5Meth = meth; + } + } + if ((meth = interp.get("controllerChange")) != null) { + switch (argCount(meth)) { + case 1: + throw new RuntimeException( + "only controllerChange(channel, pitch, velocity) or " + + "controllerChange(channel, pitch, velocity, timestamp, bus_name) " + + "are supported by Python Mode"); + case 3: + controllerChange3Meth = meth; + break; + case 5: + controllerChange5Meth = meth; + } + } + if ((meth = interp.get("rawMidi")) != null) { + switch (argCount(meth)) { + case 1: + rawMidi1Meth = meth; + break; + case 3: + rawMidi3Meth = meth; + } + } + if ((meth = interp.get("midiMessage")) != null) { + switch (argCount(meth)) { + case 1: + midiMessage1Meth = meth; + break; + case 3: + midiMessage3Meth = meth; + } + } + + // processing_websockets callbacks. + webSocketEventMeth = interp.get("webSocketEvent"); + webSocketServerEventMeth = interp.get("webSocketServerEvent"); } /* @@ -483,6 +800,7 @@ public PyObject __call__(final PyObject[] args, final String[] kws) { * them to avoid garbage collection. */ private static final PyInteger[] CHEAP_INTS = new PyInteger[20000]; + static { for (int i = 0; i < CHEAP_INTS.length; i++) { CHEAP_INTS[i] = Py.newInteger(i); @@ -515,18 +833,21 @@ protected void wrapProcessingVariables() { builtins.__setitem__("focused", Py.newBoolean(focused)); builtins.__setitem__("keyPressed", Py.newBoolean(keyPressed)); builtins.__setitem__("frameCount", pyint(frameCount)); - builtins.__setitem__("frameRate", new PyFloat(frameRate) { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - switch (args.length) { - default: - return raiseTypeError("Can't call \"frameRate\" with " + args.length + " parameters."); - case 1: - frameRate((float)args[0].asDouble()); - return Py.None; - } - } - }); + builtins.__setitem__( + "frameRate", + new PyFloat(frameRate) { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + switch (args.length) { + default: + return raiseTypeError( + "Can't call \"frameRate\" with " + args.length + " parameters."); + case 1: + frameRate((float) args[0].asDouble()); + return Py.None; + } + } + }); } // We only change the "key" variable as necessary to avoid generating @@ -562,23 +883,32 @@ private void wrapMouseVariables() { public void start() { // I want to quit on runtime exceptions. // Processing just sits there by default. - Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { - @Override - public void uncaughtException(final Thread t, final Throwable e) { - terminalException = toSketchException(e); - try { - handleMethods("dispose"); - } catch (final Exception noop) { - // give up - } - finishedLatch.countDown(); - } - }); + Thread.setDefaultUncaughtExceptionHandler( + new UncaughtExceptionHandler() { + @Override + public void uncaughtException(final Thread t, final Throwable e) { + terminalException = toSketchException(e); + try { + handleMethods("dispose"); + } catch (final Exception noop) { + // give up + } + finishedLatch.countDown(); + } + }); super.start(); } + private void bringToFront() { + if (PApplet.platform == PConstants.MACOSX) { + OSX.bringToFront(); + } + } + public void runAndBlock(final String[] args) throws PythonSketchError { PApplet.runSketch(args, this); + bringToFront(); + try { finishedLatch.await(); } catch (final InterruptedException interrupted) { @@ -590,14 +920,47 @@ public void runAndBlock(final String[] args) throws PythonSketchError { // fallthrough } } finally { + try { + if (stopMeth != null) { + stopMeth.__call__(); + } + if (disposeMeth != null) { + disposeMeth.__call__(); + } + } catch (Throwable t) { + System.err.println("while disposing: " + t); + } + + maybeShutdownSoundEngine(); + + Thread.setDefaultUncaughtExceptionHandler(null); if (PApplet.platform == PConstants.MACOSX && Arrays.asList(args).contains("fullScreen")) { // Frame should be OS-X fullscreen, and it won't stop being that unless the jvm // exits or we explicitly tell it to minimize. // (If it's disposed, it'll leave a gray blank window behind it.) Runner.log("Disabling fullscreen."); - macosxFullScreenToggle(frame); + + if (frameField != null) { + try { + Frame frameObj = (Frame) frameField.get(this); + macosxFullScreenToggle(frameObj); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + if (surface instanceof PSurfaceFX) { + // Sadly, JavaFX is an abomination, and there's no way to run an FX sketch more than once, + // so we must actually exit. + Runner.log("JavaFX requires SketchRunner to terminate. Farewell!"); + System.exit(0); + } + final Object nativeWindow = surface.getNative(); + if (nativeWindow instanceof com.jogamp.newt.Window) { + ((com.jogamp.newt.Window) nativeWindow).destroy(); + } else { + surface.setVisible(false); } - surface.setVisible(false); } if (terminalException != null) { throw terminalException; @@ -605,10 +968,30 @@ public void runAndBlock(final String[] args) throws PythonSketchError { } /** - * Use reflection to call - * com.apple.eawt.Application.getApplication().requestToggleFullScreen(window); + * The sound library is designed to depend on exiting the VM when the sketch + * exits, or rather, it's not designed to work if startup up with one + * PApplet, but then attempted to be used with another. This hack nukes + * the Engine singleton so that it has to be re-instantiated on the next + * run. + */ + private void maybeShutdownSoundEngine() { + try { + final Class appClass = Class.forName("processing.sound.Engine"); + final Field singleton = appClass.getDeclaredField("singleton"); + singleton.setAccessible(true); + singleton.set(null, null); + } catch (final ClassNotFoundException cnfe) { + // ignored + } catch (final Exception e) { + e.printStackTrace(); + } + } + + /** + * Use reflection to call + * com.apple.eawt.Application.getApplication().requestToggleFullScreen(window); */ - static private void macosxFullScreenToggle(final Window window) { + private static void macosxFullScreenToggle(final Window window) { try { final Class appClass = Class.forName("com.apple.eawt.Application"); final Method getAppMethod = appClass.getMethod("getApplication"); @@ -623,104 +1006,117 @@ static private void macosxFullScreenToggle(final Window window) { } /** - * Permit the punning use of set() by mucking with the builtin "set" Type. - * If you call it with 3 arguments, it acts like the Processing set(x, y, - * whatever) method. If you call it with 0 or 1 args, it constructs a Python - * set. + * Permit the punning use of set() by mucking with the builtin "set" Type. If you call it with 3 + * arguments, it acts like the Processing set(x, y, whatever) method. If you call it with 0 or 1 + * args, it constructs a Python set. */ private void setSet() { - final PyType originalSet = (PyType)builtins.__getitem__("set"); - builtins.__setitem__("set", new PyType(PyType.TYPE) { - { - builtin = true; - init(PySet.class, new HashSet()); - invalidateMethodCache(); - } + final PyType originalSet = (PyType) builtins.__getitem__("set"); + builtins.__setitem__( + "set", + new PyType(PyType.TYPE) { + { + builtin = true; + init(PySet.class, new HashSet()); + invalidateMethodCache(); + } - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - switch (args.length) { - default: - return originalSet.__call__(args, kws); - case 3: - final int x = args[0].asInt(); - final int y = args[1].asInt(); - final PyObject c = args[2]; - final PyType tc = c.getType(); - if (tc.getProxyType() != null && PImage.class.isAssignableFrom(tc.getProxyType())) { - set(x, y, (processing.core.PImage)c.__tojava__(processing.core.PImage.class)); - return Py.None; - } else { - set(x, y, interpretColorArg(c)); - return Py.None; + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + switch (args.length) { + default: + return originalSet.__call__(args, kws); + case 3: + final int x = args[0].asInt(); + final int y = args[1].asInt(); + final PyObject c = args[2]; + final PyType tc = c.getType(); + if (tc.getProxyType() != null && PImage.class.isAssignableFrom(tc.getProxyType())) { + set(x, y, (processing.core.PImage) c.__tojava__(processing.core.PImage.class)); + return Py.None; + } else { + set(x, y, interpretColorArg(c)); + return Py.None; + } } - } - } - }); + } + }); } /** - * Permit both the Processing map() (which is a linear interpolation function) and - * the Python map() (which is a list transformation). + * Permit both the Processing map() (which is a linear interpolation function) and the Python + * map() (which is a list transformation). */ private void setMap() { final PyObject builtinMap = builtins.__getitem__("map"); - builtins.__setitem__("map", new PyObject() { - - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - switch (args.length) { - default: - return builtinMap.__call__(args, kws); - case 5: - final PyObject value = args[0]; - final PyObject start1 = args[1]; - final PyObject stop1 = args[2]; - final PyObject start2 = args[3]; - final PyObject stop2 = args[4]; - if (value.isNumberType() && start1.isNumberType() && stop1.isNumberType() - && start2.isNumberType() && stop2.isNumberType()) { - return Py.newFloat(map((float)value.asDouble(), (float)start1.asDouble(), - (float)stop1.asDouble(), (float)start2.asDouble(), (float)stop2.asDouble())); - } else { - return builtinMap.__call__(args, kws); + builtins.__setitem__( + "map", + new PyObject() { + + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + switch (args.length) { + default: + return builtinMap.__call__(args, kws); + case 5: + final PyObject value = args[0]; + final PyObject start1 = args[1]; + final PyObject stop1 = args[2]; + final PyObject start2 = args[3]; + final PyObject stop2 = args[4]; + if (value.isNumberType() + && start1.isNumberType() + && stop1.isNumberType() + && start2.isNumberType() + && stop2.isNumberType()) { + return Py.newFloat( + map( + (float) value.asDouble(), + (float) start1.asDouble(), + (float) stop1.asDouble(), + (float) start2.asDouble(), + (float) stop2.asDouble())); + } else { + return builtinMap.__call__(args, kws); + } } - } - } - }); + } + }); } /** - * Permit both the Processing filter() (which does image processing) and the - * Python filter() (which does list comprehensions). + * Permit both the Processing filter() (which does image processing) and the Python filter() + * (which does list comprehensions). */ private void setFilter() { final PyObject builtinFilter = builtins.__getitem__("filter"); - builtins.__setitem__("filter", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - switch (args.length) { - case 1: - final PyObject value = args[0]; - if (value.isNumberType()) { - filter(value.asInt()); - } else { - filter(Py.tojava(value, PShader.class)); + builtins.__setitem__( + "filter", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + switch (args.length) { + case 1: + final PyObject value = args[0]; + if (value.isNumberType()) { + filter(value.asInt()); + } else { + filter(Py.tojava(value, PShader.class)); + } + return Py.None; + case 2: + final PyObject a = args[0]; + final PyObject b = args[1]; + if (a.isNumberType()) { + filter(a.asInt(), (float) b.asDouble()); + return Py.None; + } + //$FALL-THROUGH$ + default: + return builtinFilter.__call__(args, kws); } - return Py.None; - case 2: - final PyObject a = args[0]; - final PyObject b = args[1]; - if (a.isNumberType()) { - filter(a.asInt(), (float)b.asDouble()); - return Py.None; - } - //$FALL-THROUGH$ - default: - return builtinFilter.__call__(args, kws); - } - } - }); + } + }); } // If you call lerpColor in an active-mode sketch before setup() has run, @@ -740,15 +1136,15 @@ public int lerpColor(final int c1, final int c2, final float amt) { * version to catch it. */ public void fill(final long argb) { - fill((int)(argb & 0xFFFFFFFF)); + fill((int) (argb & 0xFFFFFFFF)); } public void stroke(final long argb) { - stroke((int)(argb & 0xFFFFFFFF)); + stroke((int) (argb & 0xFFFFFFFF)); } public void background(final long argb) { - background((int)(argb & 0xFFFFFFFF)); + background((int) (argb & 0xFFFFFFFF)); } /* @@ -780,8 +1176,8 @@ private boolean isString(final PyObject o) { } /** - * The positional arguments to lerpColor may be long integers or CSS-style - * string specs. + * The positional arguments to lerpColor may be long integers or CSS-style string specs. + * * @param arg A color argument. * @return the integer correspnding to the intended color. */ @@ -790,115 +1186,130 @@ private int interpretColorArg(final PyObject arg) { } /** - * Permit both the instance method lerpColor and the static method lerpColor. - * Also permit 0xAARRGGBB, '#RRGGBB', and 0-255. + * Permit both the instance method lerpColor and the static method lerpColor. Also permit + * 0xAARRGGBB, '#RRGGBB', and 0-255. */ private void setColorMethods() { - builtins.__setitem__("lerpColor", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - final int c1 = interpretColorArg(args[0]); - final int c2 = interpretColorArg(args[1]); - final float amt = (float)args[2].asDouble(); - switch (args.length) { - case 3: - return pyint(lerpColor(c1, c2, amt)); - case 4: - final int colorMode = (int)(args[3].asLong() & 0xFFFFFFFF); - return pyint(lerpColor(c1, c2, amt, colorMode)); - //$FALL-THROUGH$ - default: - return raiseTypeError("lerpColor takes either 3 or 4 arguments, but I got " - + args.length + "."); - } - } - }); - builtins.__setitem__("alpha", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - return Py.newFloat(alpha(interpretColorArg(args[0]))); - } - }); - builtins.__setitem__("red", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - return Py.newFloat(red(interpretColorArg(args[0]))); - } - }); - builtins.__setitem__("green", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - return Py.newFloat(green(interpretColorArg(args[0]))); - } - }); - builtins.__setitem__("blue", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - return Py.newFloat(blue(interpretColorArg(args[0]))); - } - }); - builtins.__setitem__("hue", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - return Py.newFloat(hue(interpretColorArg(args[0]))); - } - }); - builtins.__setitem__("saturation", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - return Py.newFloat(saturation(interpretColorArg(args[0]))); - } - }); - builtins.__setitem__("brightness", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - return Py.newFloat(brightness(interpretColorArg(args[0]))); - } - }); + builtins.__setitem__( + "lerpColor", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + final int c1 = interpretColorArg(args[0]); + final int c2 = interpretColorArg(args[1]); + final float amt = (float) args[2].asDouble(); + switch (args.length) { + case 3: + return pyint(lerpColor(c1, c2, amt)); + case 4: + final int colorMode = (int) (args[3].asLong() & 0xFFFFFFFF); + return pyint(lerpColor(c1, c2, amt, colorMode)); + default: + return raiseTypeError( + "lerpColor takes either 3 or 4 arguments, but I got " + args.length + "."); + } + } + }); + builtins.__setitem__( + "alpha", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + return Py.newFloat(alpha(interpretColorArg(args[0]))); + } + }); + builtins.__setitem__( + "red", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + return Py.newFloat(red(interpretColorArg(args[0]))); + } + }); + builtins.__setitem__( + "green", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + return Py.newFloat(green(interpretColorArg(args[0]))); + } + }); + builtins.__setitem__( + "blue", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + return Py.newFloat(blue(interpretColorArg(args[0]))); + } + }); + builtins.__setitem__( + "hue", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + return Py.newFloat(hue(interpretColorArg(args[0]))); + } + }); + builtins.__setitem__( + "saturation", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + return Py.newFloat(saturation(interpretColorArg(args[0]))); + } + }); + builtins.__setitem__( + "brightness", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + return Py.newFloat(brightness(interpretColorArg(args[0]))); + } + }); } /** - * Hide the variants of text() that take char/char[] and array indices, since that's - * not necessary in Python, and since they mask the text()s that take take strings. + * Hide the variants of text() that take char/char[] and array indices, since that's not necessary + * in Python, and since they mask the text()s that take take strings. */ private void setText() { - builtins.__setitem__("text", new PyObject() { - @Override - public PyObject __call__(final PyObject[] args, final String[] kws) { - if (args.length < 3 || args.length > 5) { - raiseTypeError("text() takes 3-5 arguments, but I got " + args.length + "."); - } - final PyObject a = args[0]; - final float x1 = (float)args[1].asDouble(); - final float y1 = (float)args[2].asDouble(); - if (args.length == 3) { - if (isString(a)) { - text(a.asString(), x1, y1); - } else if (a.getType() == PyInteger.TYPE) { - text(a.asInt(), x1, y1); - } else { - text((float)a.asDouble(), x1, y1); - } - } else if (args.length == 4) { - final float z1 = (float)args[3].asDouble(); - if (isString(a)) { - text(a.asString(), x1, y1, z1); - } else if (a.getType() == PyInteger.TYPE) { - text(a.asInt(), x1, y1, z1); - } else { - text((float)a.asDouble(), x1, y1, z1); + builtins.__setitem__( + "text", + new PyObject() { + @Override + public PyObject __call__(final PyObject[] args, final String[] kws) { + if (args.length < 3 || args.length > 5) { + raiseTypeError("text() takes 3-5 arguments, but I got " + args.length + "."); + } + final PyObject a = args[0]; + final float x1 = (float) args[1].asDouble(); + final float y1 = (float) args[2].asDouble(); + if (args.length == 3) { + if (isString(a)) { + text(a.asString(), x1, y1); + } else if (a.getType() == PyInteger.TYPE) { + text(a.asInt(), x1, y1); + } else { + text((float) a.asDouble(), x1, y1); + } + } else if (args.length == 4) { + final float z1 = (float) args[3].asDouble(); + if (isString(a)) { + text(a.asString(), x1, y1, z1); + } else if (a.getType() == PyInteger.TYPE) { + text(a.asInt(), x1, y1, z1); + } else { + text((float) a.asDouble(), x1, y1, z1); + } + } else /* 5 */ { + text(a.asString(), x1, y1, (float) args[3].asDouble(), (float) args[4].asDouble()); + } + return Py.None; } - } else /* 5 */{ - text(a.asString(), x1, y1, (float)args[3].asDouble(), (float)args[4].asDouble()); - } - return Py.None; - } - }); + }); } - /** - * Populate the Python builtins namespace with PConstants. - */ + /** Populate the Python builtins namespace with PConstants. */ public static void initializeStatics(final PyStringMap builtins) { for (final Field f : PConstants.class.getDeclaredFields()) { final int mods = f.getModifiers(); @@ -913,15 +1324,23 @@ public static void initializeStatics(final PyStringMap builtins) { } /** - * We have to override PApplet's size method in order to reset the Python - * context's knowledge of the magic variables that reflect the state of the - * sketch's world, particularly width and height. + * We have to override PApplet's size method in order to reset the Python context's knowledge of + * the magic variables that reflect the state of the sketch's world, particularly width and + * height. */ @Override - public void size(final int iwidth, final int iheight, final String irenderer, final String ipath) { + public void size( + final int iwidth, final int iheight, final String irenderer, final String ipath) { super.size(iwidth, iheight, irenderer, ipath); - builtins.__setitem__("g", Py.java2py(g)); - builtins.__setitem__("frame", Py.java2py(frame)); + if (frameField != null) { + // should surface be added instead? [fry 210616] + try { + Frame frameObj = (Frame) frameField.get(this); + builtins.__setitem__("frame", Py.java2py(frameObj)); + } catch (IllegalAccessException ignored) { + // log this? + } + } builtins.__setitem__("width", pyint(width)); builtins.__setitem__("height", pyint(height)); } @@ -931,33 +1350,60 @@ public void settings() { try { if (settingsMeth != null) { settingsMeth.__call__(); - } else { - super.settings(); + } else if (mode == Mode.STATIC) { + if (detectedFullScreen) { + fullScreen(); + } else { + if (detectedRenderer != null) { + size(detectedWidth, detectedHeight, detectedRenderer); + } else { + size(detectedWidth, detectedHeight); + } + } + pixelDensity(detectedPixelDensity); + if (detectedSmooth && detectedNoSmooth) { + throw new MixedSmoothError(); + } + if (detectedSmooth) { + smooth(); + } else if (detectedNoSmooth) { + noSmooth(); + } } } catch (final Exception e) { terminalException = toSketchException(e); - exit(); + exitActual(); } } @Override public void setup() { - builtins.__setitem__("frame", Py.java2py(frame)); + if (frameField != null) { + // should surface be added instead? [fry 210616] + try { + Frame frameObj = (Frame) frameField.get(this); + builtins.__setitem__("frame", Py.java2py(frameObj)); + } catch (IllegalAccessException ignored) { + // log this? + } + } wrapProcessingVariables(); - try { - if (mode == Mode.STATIC) { - // A static sketch gets called once, from this spot. - Runner.log("Interpreting static-mode sketch."); - processSketch(PREPROCESS_SCRIPT); - } else if (setupMeth != null) { - // Call the Python sketch's setup() + if (mode == Mode.STATIC) { + // A static sketch gets called once, from this spot. + Runner.log("Interpreting static-mode sketch."); + try { + try (PushedOut out = wrappedStdout.pushStdout()) { + interp.exec(processedStaticSketch); + } + } catch (final Exception e) { + terminalException = toSketchException(e); + exitActual(); + } + } else if (setupMeth != null) { + // Call the Python sketch's setup() + try (PushedOut out = wrappedStdout.pushStdout()) { setupMeth.__call__(); } - } catch (final Exception e) { - // No longer necessary in 3.0a7 - // checkForRendererChangeException(e); - terminalException = toSketchException(e); - exit(); } } @@ -967,7 +1413,12 @@ public void draw() { if (drawMeth == null) { super.draw(); } else if (!finished) { - drawMeth.__call__(); + try (PushedOut out = wrappedStdout.pushStdout()) { + drawMeth.__call__(); + } + } + if (exitCalled()) { + exitActual(); } } @@ -1025,7 +1476,6 @@ public void mouseReleased(final MouseEvent e) { mouseReleasedFunc.invoke(e); } - @Override public void mouseDragged() { wrapMouseVariables(); @@ -1070,7 +1520,6 @@ public void keyReleased(final KeyEvent e) { keyReleasedFunc.invoke(e); } - @Override public void keyTyped() { wrapKeyVariables(); @@ -1083,17 +1532,6 @@ public void keyTyped(final KeyEvent e) { keyTypedFunc.invoke(e); } - @Override - public void stop() { - try { - if (stopMeth != null) { - stopMeth.__call__(); - } - } finally { - super.stop(); - } - } - @Override public void pause() { try { @@ -1117,8 +1555,8 @@ public void resume() { } /** - * Processing uses reflection to call file selection callbacks by name. - * We fake out that stuff with one of these babies. + * Processing uses reflection to call file selection callbacks by name. We fake out that stuff + * with one of these babies. */ public class FileSelectCallbackProxy { private final PyObject callback; @@ -1190,6 +1628,133 @@ public void movieEvent(final Object movie) { } } + // Serial library callback. + public void serialEvent(final Object whichPort) { + if (serialEventMeth != null) { + serialEventMeth.__call__(Py.java2py(whichPort)); + } + } + + // Net library callbacks. + public void clientEvent(final Object someClient) { + if (clientEventMeth != null) { + clientEventMeth.__call__(Py.java2py(someClient)); + } + } + + public void disconnectEvent(final Object someClient) { + if (disconnectEventMeth != null) { + disconnectEventMeth.__call__(Py.java2py(someClient)); + } + } + + public void serverEvent(final Object someServer, final Object someClient) { + if (serverEventMeth != null) { + serverEventMeth.__call__(Py.java2py(someServer), Py.java2py(someClient)); + } + } + + // oscP5 callback. + public void oscEvent(final Object oscMessage) { + if (oscEventMeth != null) { + oscEventMeth.__call__(Py.java2py(oscMessage)); + } + } + + // themidibus callbacks + public void noteOn(final int channel, final int pitch, final int velocity) { + if (noteOn3Meth != null) { + noteOn3Meth.__call__(pyint(channel), pyint(pitch), pyint(velocity)); + } + } + + public void noteOn( + final int channel, + final int pitch, + final int velocity, + final long time, + final String busName) { + if (noteOn5Meth != null) { + noteOn5Meth.__call__( + new PyObject[] { + pyint(channel), pyint(pitch), pyint(velocity), Py.newLong(time), Py.newString(busName) + }); + } + } + + public void noteOff(final int channel, final int pitch, final int velocity) { + if (noteOff3Meth != null) { + noteOff3Meth.__call__(pyint(channel), pyint(pitch), pyint(velocity)); + } + } + + public void noteOff( + final int channel, + final int pitch, + final int velocity, + final long time, + final String busName) { + if (noteOff5Meth != null) { + noteOff5Meth.__call__( + new PyObject[] { + pyint(channel), pyint(pitch), pyint(velocity), Py.newLong(time), Py.newString(busName) + }); + } + } + + public void controllerChange(final int channel, final int number, final int value) { + if (controllerChange3Meth != null) { + controllerChange3Meth.__call__(pyint(channel), pyint(number), pyint(value)); + } + } + + public void controllerChange( + final int channel, final int number, final int value, final long time, final String busName) { + if (controllerChange5Meth != null) { + controllerChange5Meth.__call__( + new PyObject[] { + pyint(channel), pyint(number), pyint(value), Py.newLong(time), Py.newString(busName) + }); + } + } + + public void rawMidi(final byte[] data) { + if (rawMidi1Meth != null) { + rawMidi1Meth.__call__(Py.java2py(data)); + } + } + + public void rawMidi(final byte[] data, final long time, final String busName) { + if (rawMidi3Meth != null) { + rawMidi3Meth.__call__(Py.java2py(data), Py.newLong(time), Py.newString(busName)); + } + } + + public void midiMessage(final MidiMessage msg) { + if (midiMessage1Meth != null) { + midiMessage1Meth.__call__(Py.java2py(msg)); + } + } + + public void midiMessage(final MidiMessage msg, final long time, final String busName) { + if (midiMessage3Meth != null) { + midiMessage3Meth.__call__(Py.java2py(msg), Py.newLong(time), Py.newString(busName)); + } + } + + // processing_websockets callbacks. + public void webSocketEvent(final String msg) { + if (webSocketEventMeth != null) { + webSocketEventMeth.__call__(Py.java2py(msg)); + } + } + + public void webSocketServerEvent(final String msg) { + if (webSocketServerEventMeth != null) { + webSocketServerEventMeth.__call__(Py.java2py(msg)); + } + } + public void setSketchPositionListener(final SketchPositionListener sketchPositionListener) { this.sketchPositionListener = sketchPositionListener; } diff --git a/runtime/src/jycessing/Printer.java b/runtime/src/jycessing/Printer.java index c2b517b1..2001557e 100644 --- a/runtime/src/jycessing/Printer.java +++ b/runtime/src/jycessing/Printer.java @@ -2,4 +2,6 @@ public interface Printer { void print(Object o); + + void flush(); } diff --git a/runtime/src/jycessing/PythonSketchError.java b/runtime/src/jycessing/PythonSketchError.java index cf23ad92..cb62de3a 100644 --- a/runtime/src/jycessing/PythonSketchError.java +++ b/runtime/src/jycessing/PythonSketchError.java @@ -17,8 +17,8 @@ public PythonSketchError(final String message, final String fileName, final int this(message, fileName, line, 0); } - public PythonSketchError(final String message, final String fileName, final int line, - final int column) { + public PythonSketchError( + final String message, final String fileName, final int line, final int column) { super(message); this.fileName = fileName; diff --git a/runtime/src/jycessing/ReflectionUtil.java b/runtime/src/jycessing/ReflectionUtil.java index 466ae3a9..513b4668 100644 --- a/runtime/src/jycessing/ReflectionUtil.java +++ b/runtime/src/jycessing/ReflectionUtil.java @@ -13,8 +13,8 @@ public static Field accessibleField(final Class c, final String fieldName) { } } - public static void setObjectStatic(final Class klass, final String fieldName, - final Object value) { + public static void setObjectStatic( + final Class klass, final String fieldName, final Object value) { try { accessibleField(klass, fieldName).set(null, value); } catch (final Exception e) { @@ -22,8 +22,8 @@ public static void setObjectStatic(final Class klass, final String fieldN } } - public static void setBooleanStatic(final Class klass, final String fieldName, - final boolean value) { + public static void setBooleanStatic( + final Class klass, final String fieldName, final boolean value) { try { accessibleField(klass, fieldName).set(null, value); } catch (final Exception e) { diff --git a/runtime/src/jycessing/RunnableSketch.java b/runtime/src/jycessing/RunnableSketch.java index 4e2bbd13..28a0a3b2 100644 --- a/runtime/src/jycessing/RunnableSketch.java +++ b/runtime/src/jycessing/RunnableSketch.java @@ -5,49 +5,32 @@ import jycessing.Runner.LibraryPolicy; -/** - * - * Everything Runner.runSketchBlocking needs to know to be able to run a sketch. - * - */ +/** Everything Runner.runSketchBlocking needs to know to be able to run a sketch. */ public interface RunnableSketch { - /** - * @return The main file of the sketch - */ + /** @return The main file of the sketch */ public abstract File getMainFile(); - /** - * @return The primary code to run - */ + /** @return The primary code to run */ public abstract String getMainCode(); - /** - * @return The main directory of the sketch - */ + /** @return The main directory of the sketch */ public abstract File getHomeDirectory(); - /** - * @return Files to append to sys.path - */ + /** @return Files to append to sys.path */ public abstract List getPathEntries(); - /** - * @return Arguments to pass to PApplet - */ + /** @return Arguments to pass to PApplet */ public abstract String[] getPAppletArguments(); - /** - * @return Directories to search for Processing libraries - */ + /** @return Directories to search for Processing libraries */ public abstract List getLibraryDirectories(); - /** - * @return How eagerly we should look for libraries - */ + /** @return How eagerly we should look for libraries */ public abstract LibraryPolicy getLibraryPolicy(); /** * Should probably be true, unless you're a warmup sketch + * * @return Whether the sketch should run or not */ public abstract boolean shouldRun(); diff --git a/runtime/src/jycessing/Runner.java b/runtime/src/jycessing/Runner.java old mode 100644 new mode 100755 index d4a5ec1d..29d3b712 --- a/runtime/src/jycessing/Runner.java +++ b/runtime/src/jycessing/Runner.java @@ -29,10 +29,7 @@ import java.util.List; import java.util.Properties; import java.util.Set; - -import jycessing.launcher.LaunchHelper; -import jycessing.launcher.StandaloneSketch; -import jycessing.mode.export.ExportedSketch; +import java.util.TreeSet; import org.python.core.Py; import org.python.core.PyList; @@ -42,6 +39,9 @@ import org.python.util.InteractiveConsole; import org.python.util.PythonInterpreter; +import jycessing.launcher.LaunchHelper; +import jycessing.launcher.StandaloneSketch; +import jycessing.mode.export.ExportedSketch; import processing.core.PApplet; import processing.core.PConstants; @@ -50,6 +50,7 @@ public class Runner { private static final String BUILD_PROPERTIES = "build.properties"; private static final String ARCH; + static { final int archBits = Integer.parseInt(System.getProperty("sun.arch.data.model")); if (PApplet.platform == PConstants.MACOSX) { @@ -76,12 +77,12 @@ private static String loadBuildNumber() { } } - private static final String LAUNCHER_TEXT = IOUtil.readResourceAsText(LaunchHelper.class, - "launcher.py"); + private static final String LAUNCHER_TEXT = + IOUtil.readResourceAsText(LaunchHelper.class, "launcher.py"); private static final String CORE_TEXT = IOUtil.readResourceAsText(Runner.class, "core.py"); // -Dverbose=true for some logging - static public boolean VERBOSE = Boolean.getBoolean("verbose"); + public static boolean VERBOSE = Boolean.getBoolean("verbose"); static void log(final Object... objs) { if (!VERBOSE) { @@ -94,9 +95,8 @@ static void log(final Object... objs) { } /** - * Recursively search the given directory for jar files and directories - * containing dynamic libraries, adding them to the classpath and the - * library path respectively. + * Recursively search the given directory for jar files and directories containing dynamic + * libraries, adding them to the classpath and the library path respectively. */ private static void searchForExtraStuff(final File dir, final Set entries) { if (dir == null) { @@ -111,24 +111,28 @@ private static void searchForExtraStuff(final File dir, final Set entrie log("Searching: ", dir); - final File[] dlls = dir.listFiles(new FilenameFilter() { - @Override - public boolean accept(final File dir, final String name) { - return name.matches("^.+\\.(so|dll|jnilib|dylib)$"); - } - }); + final File[] dlls = + dir.listFiles( + new FilenameFilter() { + @Override + public boolean accept(final File dir, final String name) { + return name.matches("^.+\\.(so|dll|jnilib|dylib)$"); + } + }); if (dlls != null && dlls.length > 0) { entries.add(dir.getAbsolutePath()); } else { log("No DLLs in ", dir); } - final File[] jars = dir.listFiles(new FilenameFilter() { - @Override - public boolean accept(final File dir, final String name) { - return name.matches("^.+\\.jar$"); - } - }); + final File[] jars = + dir.listFiles( + new FilenameFilter() { + @Override + public boolean accept(final File dir, final String name) { + return name.matches("^.+\\.jar$"); + } + }); if (!(jars == null || jars.length == 0)) { for (final File jar : jars) { entries.add(jar.getAbsolutePath()); @@ -137,12 +141,14 @@ public boolean accept(final File dir, final String name) { log("No JARs in ", dir); } - final File[] dirs = dir.listFiles(new FileFilter() { - @Override - public boolean accept(final File f) { - return f.isDirectory() && f.getName().charAt(0) != '.'; - } - }); + final File[] dirs = + dir.listFiles( + new FileFilter() { + @Override + public boolean accept(final File f) { + return f.isDirectory() && f.getName().charAt(0) != '.'; + } + }); if (!(dirs == null || dirs.length == 0)) { for (final File d : dirs) { searchForExtraStuff(d, entries); @@ -155,11 +161,8 @@ public boolean accept(final File f) { public static RunnableSketch sketch; /** - * - * Entrypoint for non-PDE sketches. If we find ARGS_EXPORTED in the argument list, - * Launch as an exported sketch. - * Otherwise, launch as a standalone processing.py sketch. - * + * Entrypoint for non-PDE sketches. If we find ARGS_EXPORTED in the argument list, Launch as an + * exported sketch. Otherwise, launch as a standalone processing.py sketch. */ public static void main(final String[] args) throws Exception { if (args.length < 1) { @@ -187,18 +190,12 @@ public static void main(final String[] args) throws Exception { System.exit(0); } - /** - * Specifies how to deal with the libraries directory. - */ + /** Specifies how to deal with the libraries directory. */ public enum LibraryPolicy { - /** - * Preemptively put every jar file and directory under the library path on sys.path. - */ + /** Preemptively put every jar file and directory under the library path on sys.path. */ PROMISCUOUS, - /** - * Only put jar files and directories onto sys.path as called for by add_library. - */ + /** Only put jar files and directories onto sys.path as called for by add_library. */ SELECTIVE } @@ -266,8 +263,8 @@ public List getPathEntries() { } /** - * warmup() front-loads a huge amount of slow IO so that when the user gets around - * to running a sketch, most of the slow work is already done. + * warmup() front-loads a huge amount of slow IO so that when the user gets around to running a + * sketch, most of the slow work is already done. */ public static void warmup() { try (final WarmupSketch warmup = new WarmupSketch()) { @@ -277,40 +274,60 @@ public static void warmup() { } } - public synchronized static void runSketchBlocking(final RunnableSketch sketch, - final Printer stdout, final Printer stderr) throws PythonSketchError { + public static synchronized void runSketchBlocking( + final RunnableSketch sketch, final Printer stdout, final Printer stderr) + throws PythonSketchError { runSketchBlocking(sketch, stdout, stderr, null); } - public synchronized static void runSketchBlocking(final RunnableSketch sketch, - final Printer stdout, final Printer stderr, - final SketchPositionListener sketchPositionListener) throws PythonSketchError { + public static synchronized void runSketchBlocking( + final RunnableSketch sketch, + final Printer stdout, + final Printer stderr, + final SketchPositionListener sketchPositionListener) + throws PythonSketchError { final Properties props = new Properties(); // Suppress sys-package-manager output. props.setProperty("python.verbose", "error"); + // Attempt to prevent "Failed to install '': java.nio.charset.UnsupportedCharsetException: cp0." + props.put("python.console.encoding", "utf-8"); + props.put("python.io.encoding", "utf-8"); + props.put("python.io.errors", "utf-8"); + + props.put("python.import.site", "false"); + + props.put("python.cachedir.skip", "false"); + props.put("python.cachedir", + new File(System.getProperty("java.io.tmpdir"), "PythonModeCache").getAbsolutePath()); + + // Permit python subclasses to access protect fields, as in Beads. + props.put("python.security.respectJavaAccessibility", "false"); + // Can be handy for class loading issues and the like. // props.setProperty("python.verbose", "debug"); final StringBuilder pythonPath = new StringBuilder(); - final List libDirs = sketch.getLibraryDirectories(); + // The code may be located in a temp dir, if the sketch is unsaved. + final String actualCodeLocation = sketch.getMainFile().getParentFile().getAbsolutePath(); + pythonPath.append(File.pathSeparator).append(actualCodeLocation); final String sketchDirPath = sketch.getHomeDirectory().getAbsolutePath(); pythonPath.append(File.pathSeparator).append(sketchDirPath); - props.setProperty("python.path", pythonPath.toString()); props.setProperty("python.main", sketch.getMainFile().getAbsolutePath()); props.setProperty("python.main.root", sketchDirPath); final String[] args = sketch.getPAppletArguments(); + log("PythonInterpreter.initialize args: " + String.join(" ", args)); PythonInterpreter.initialize(null, props, args); final PySystemState sys = Py.getSystemState(); - final PyStringMap originalModules = ((PyStringMap)sys.modules).copy(); - final PyList originalPath = new PyList((PyObject)sys.path); - final PyStringMap builtins = (PyStringMap)sys.getBuiltins(); + final PyStringMap originalModules = ((PyStringMap) sys.modules).copy(); + final PyList originalPath = new PyList((PyObject) sys.path); + final PyStringMap builtins = (PyStringMap) sys.getBuiltins(); final PyStringMap originalBuiltins = builtins.copy(); try { final InteractiveConsole interp = new InteractiveConsole(); @@ -322,15 +339,16 @@ public synchronized static void runSketchBlocking(final RunnableSketch sketch, // Add all of the sketch's requested sys.path entries, and add all jar // files found there, recursively. - final Set userLibs = new HashSet<>(); + final Set userLibs = new TreeSet<>(); for (final File entry : sketch.getPathEntries()) { - sys.path.insert(0, Py.newString(entry.getAbsolutePath())); + userLibs.add(entry.getAbsolutePath()); searchForExtraStuff(entry, userLibs); } // Add the add_library function to the sketch namespace. + final List libDirs = sketch.getLibraryDirectories(); if (libDirs != null) { - new LibraryImporter(sketch.getLibraryDirectories(), interp); + new LibraryImporter(libDirs, interp); if (sketch.getLibraryPolicy() == LibraryPolicy.PROMISCUOUS) { log("Promiscusouly adding all libraries in " + libDirs); @@ -341,16 +359,15 @@ public synchronized static void runSketchBlocking(final RunnableSketch sketch, searchForExtraStuff(dir, libs); } for (final String lib : libs) { - sys.path.insert(0, Py.newString(lib)); + userLibs.add(lib); } } } for (final String lib : userLibs) { - sys.path.insert(0, Py.newString(lib)); + sys.path.insert(0, Py.newStringUTF8(lib)); } - // Make fake "launcher" module available to sketches - will only work with standalone sketches interp.exec(LAUNCHER_TEXT); @@ -362,13 +379,13 @@ public synchronized static void runSketchBlocking(final RunnableSketch sketch, * bound methods (such as loadImage(), noSmooth(), noise(), etc.) in the builtins * namespace. */ - interp.set("__cwd__", sketch.getHomeDirectory().getAbsolutePath()); + interp.set("__cwd__", Py.newStringUTF8(sketch.getHomeDirectory().getAbsolutePath())); interp.set("__python_mode_build__", BUILD_NUMBER); interp.set("__stdout__", stdout); interp.set("__stderr__", stderr); final PAppletJythonDriver applet = - new PAppletJythonDriver(interp, sketch.getMainFile().toString(), sketch.getMainCode(), - stdout); + new PAppletJythonDriver( + interp, sketch.getMainFile().toString(), sketch.getMainCode(), stdout); interp.set("__papplet__", applet); interp.exec(CORE_TEXT); @@ -407,9 +424,8 @@ public synchronized static void runSketchBlocking(final RunnableSketch sketch, } /** - * The urllib module unit tests exposed a bug in how the codecs module - * is mangled when the world is reset around it. This hack forces it to - * reinitialize. + * The urllib module unit tests exposed a bug in how the codecs module is mangled when the world + * is reset around it. This hack forces it to reinitialize. */ private static void resetCodecsModule() { ReflectionUtil.setObject(Py.getSystemState(), "codecState", null); diff --git a/runtime/src/jycessing/StreamPrinter.java b/runtime/src/jycessing/StreamPrinter.java index 0bed005b..63c8d351 100644 --- a/runtime/src/jycessing/StreamPrinter.java +++ b/runtime/src/jycessing/StreamPrinter.java @@ -15,4 +15,9 @@ public void print(final Object o) { stream.print(String.valueOf(o)); stream.flush(); } + + @Override + public void flush() { + stream.flush(); + } } diff --git a/runtime/src/jycessing/TreeCopier.java b/runtime/src/jycessing/TreeCopier.java index 95025896..ac6eb9ee 100644 --- a/runtime/src/jycessing/TreeCopier.java +++ b/runtime/src/jycessing/TreeCopier.java @@ -48,9 +48,7 @@ class TreeCopier implements FileVisitor { - /** - * Copy source file to target location. - */ + /** Copy source file to target location. */ static void copyFile(final Path source, final Path target) { try { Files.copy(source, target, COPY_ATTRIBUTES, REPLACE_EXISTING); diff --git a/runtime/src/jycessing/annotations/PythonUsage.java b/runtime/src/jycessing/annotations/PythonUsage.java index 329dc0d3..4f642ebb 100644 --- a/runtime/src/jycessing/annotations/PythonUsage.java +++ b/runtime/src/jycessing/annotations/PythonUsage.java @@ -1,6 +1,4 @@ -/** - * - */ +/** */ package jycessing.annotations; import java.lang.annotation.ElementType; @@ -9,17 +7,17 @@ import java.lang.annotation.Target; /** - * Reminds you that this method is used from Python. Unless you know what - * you're doing, do not change its name. - * + * Reminds you that this method is used from Python. Unless you know what you're doing, do not + * change its name. + * * @author Ralf Biedert */ @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) public @interface PythonUsage { /** - * The original method name. Must match with the actual method name. - * + * The original method name. Must match with the actual method name. + * * @return The original method name. */ public String methodName(); diff --git a/runtime/src/jycessing/build.properties b/runtime/src/jycessing/build.properties index ddc46b28..1a22f6ed 100644 --- a/runtime/src/jycessing/build.properties +++ b/runtime/src/jycessing/build.properties @@ -1,5 +1,5 @@ #Python mode build number -#Wed, 08 Jul 2015 14:03:43 -0400 +#Tue, 19 May 2020 13:23:09 -0400 -build.date=2015/07/08 14\:03 -build.number=0412 +build.date=2020/05/19 13\:23 +build.number=3063 diff --git a/runtime/src/jycessing/core.py b/runtime/src/jycessing/core.py index ca449fcf..30d068d4 100644 --- a/runtime/src/jycessing/core.py +++ b/runtime/src/jycessing/core.py @@ -5,45 +5,21 @@ from numbers import Number -# Bring all of the core Processing classes by name into the builtin namespace. -from processing.core import PApplet -__builtin__.PApplet = PApplet - -from processing.core import PConstants -__builtin__.PConstants = PConstants - -from processing.core import PFont -__builtin__.PFont = PFont - -from processing.core import PGraphics -__builtin__.PGraphics = PGraphics - -from processing.core import PImage -__builtin__.PImage = PImage - -from processing.core import PMatrix -__builtin__.PMatrix = PMatrix -from processing.core import PMatrix2D -__builtin__.PMatrix2D = PMatrix2D - -from processing.core import PMatrix3D -__builtin__.PMatrix3D = PMatrix3D - -from processing.core import PShape -__builtin__.PShape = PShape - -from processing.core import PShapeOBJ -__builtin__.PShapeOBJ = PShapeOBJ - -from processing.core import PShapeSVG -__builtin__.PShapeSVG = PShapeSVG +# Bring all of the core Processing classes by name into the builtin namespace. +import importlib +for klass in """ + PApplet PConstants PFont PGraphics PImage PMatrix PMatrix2D PMatrix3D + PShape PShapeOBJ PShapeSVG PStyle PSurface +""".split(): + module = importlib.import_module("processing.core.%s" % klass) + assert module + setattr(__builtin__, klass, module) -from processing.core import PStyle -__builtin__.PStyle = PStyle -from processing.core import PSurface -__builtin__.PSurface = PSurface +module = importlib.import_module("processing.opengl.PGL") +assert module +setattr(__builtin__, "PGL", module) # PVector requires special handling, because it exposes the same method names # as static methods and instance methods. @@ -52,30 +28,28 @@ class PVector(__pvector__): def __instance_add__(self, *args): if len(args) == 1: v = args[0] - self.x += v.x - self.y += v.y - self.z += v.z else: - self.x += args[0] - self.y += args[1] - self.z += args[2] + v = args + self.x += v[0] + self.y += v[1] + self.z += v[2] + return self def __instance_sub__(self, *args): if len(args) == 1: v = args[0] - self.x -= v.x - self.y -= v.y - self.z -= v.z else: - self.x -= args[0] - self.y -= args[1] - self.z -= args[2] + v = args + self.x -= v[0] + self.y -= v[1] + self.z -= v[2] + return self def __instance_mult__(self, o): - PVector.mult(self, o, self) + return PVector.mult(self, o, self) def __instance_div__(self, f): - PVector.div(self, f, self) + return PVector.div(self, f, self) def __instance_cross__(self, o): return PVector.cross(self, o, self) @@ -86,8 +60,9 @@ def __instance_dist__(self, o): def __instance_dot__(self, *args): if len(args) == 1: v = args[0] - return self.x * v.x + self.y * v.y + self.z * v.z - return self.x * args[0] + self.y * args[1] + self.z * args[2] + else: + v = args + return self.x * v[0] + self.y * v[1] + self.z * v[2] def __instance_lerp__(self, *args): if len(args) == 4: @@ -97,13 +72,14 @@ def __instance_lerp__(self, *args): t = args[3] elif len(args) == 2: v = args[0] - x = v.x - y = v.y - z = v.z + x = v[0] + y = v[1] + z = v[2] t = args[1] else: raise Exception('lerp takes either (x, y, z, t) or (v, t)') __pvector__.lerp(self, x, y, z, t) + return self def __init__(self, x=0, y=0, z=0): __pvector__.__init__(self, x, y, z) @@ -122,6 +98,12 @@ def get(self): def copy(self): return PVector(self.x, self.y, self.z) + def __getitem__(self, k): + return getattr(self, ('x','y','z')[k]) + + def __setitem__(self, k, v): + setattr(self, ('x','y','z')[k], v) + def __copy__(self): return PVector(self.x, self.y, self.z) @@ -131,15 +113,15 @@ def __deepcopy__(self, memo): @classmethod def add(cls, a, b, dest=None): if dest is None: - return PVector(a.x + b.x, a.y + b.y, a.z + b.z) - dest.set(a.x + b.x, a.y + b.y, a.z + b.z) + return PVector(a.x + b[0], a.y + b[1], a.z + b[2]) + dest.set(a.x + b[0], a.y + b[1], a.z + b[2]) return dest @classmethod def sub(cls, a, b, dest=None): if dest is None: - return PVector(a.x - b.x, a.y - b.y, a.z - b.z) - dest.set(a.x - b.x, a.y - b.y, a.z - b.z) + return PVector(a.x - b[0], a.y - b[1], a.z - b[2]) + dest.set(a.x - b[0], a.y - b[1], a.z - b[2]) return dest @classmethod @@ -172,14 +154,29 @@ def lerp(cls, a, b, f): @classmethod def cross(cls, a, b, dest=None): - x = a.y * b.z - b.y * a.z - y = a.z * b.x - b.z * a.x - z = a.x * b.y - b.x * a.y + x = a.y * b[2] - b[1] * a.z + y = a.z * b[0] - b[2] * a.x + z = a.x * b[1] - b[0] * a.y if dest is None: return PVector(x, y, z) dest.set(x, y, z) return dest + @classmethod + def fromAngle(cls, *args): + jpv = __pvector__.fromAngle(*args) + return PVector(jpv.x, jpv.y, jpv.z) + + @classmethod + def random2D(cls, *args): + jpv = __pvector__.random2D(*args) + return PVector(jpv.x, jpv.y, jpv.z) + + @classmethod + def random3D(cls, *args): + jpv = __pvector__.random3D(*args) + return PVector(jpv.x, jpv.y, jpv.z) + def __add__(a, b): return PVector.add(a, b, None) @@ -222,7 +219,7 @@ def __idiv__(a, b): return a def __eq__(a, b): - return a.x == b.x and a.y == b.y and a.z == b.z + return a.x == b[0] and a.y == b[1] and a.z == b[2] def __lt__(a, b): return a.magSq() < b.magSq() @@ -239,8 +236,8 @@ def __ge__(a, b): # Now expose the funky PVector class as a builtin. __builtin__.PVector = PVector -# Make it available to sketches by the name "this", to better match existing -# Java-based documentation for third-party libraries, and such. +# Make the PApplet available to sketches by the name "this", to better match +# existing Java-based documentation for third-party libraries, and such. __builtin__.this = __papplet__ @@ -248,184 +245,45 @@ def __ge__(a, b): # https://github.com/kazimuth/python-mode-processing for the # technique of exploiting Jython's bound methods, which is tidy # and simple. -__builtin__.ambient = __papplet__.ambient -__builtin__.ambientLight = __papplet__.ambientLight -__builtin__.applyMatrix = __papplet__.applyMatrix -__builtin__.arc = __papplet__.arc -__builtin__.background = __papplet__.background -__builtin__.beginCamera = __papplet__.beginCamera -__builtin__.beginContour = __papplet__.beginContour -__builtin__.beginPGL = __papplet__.beginPGL -__builtin__.beginRaw = __papplet__.beginRaw -__builtin__.beginRecord = __papplet__.beginRecord -__builtin__.beginShape = __papplet__.beginShape -__builtin__.bezier = __papplet__.bezier -__builtin__.bezierDetail = __papplet__.bezierDetail -__builtin__.bezierPoint = __papplet__.bezierPoint -__builtin__.bezierTangent = __papplet__.bezierTangent -__builtin__.bezierVertex = __papplet__.bezierVertex -__builtin__.blend = __papplet__.blend -__builtin__.blendMode = __papplet__.blendMode -__builtin__.box = __papplet__.box -__builtin__.camera = __papplet__.camera -__builtin__.clear = __papplet__.clear -__builtin__.clip = __papplet__.clip -__builtin__.color = __papplet__.color -__builtin__.colorMode = __papplet__.colorMode -__builtin__.copy = __papplet__.copy -__builtin__.createFont = __papplet__.createFont -__builtin__.createGraphics = __papplet__.createGraphics -__builtin__.createImage = __papplet__.createImage -__builtin__.createInput = __papplet__.createInput -__builtin__.createOutput = __papplet__.createOutput -__builtin__.createReader = __papplet__.createReader -__builtin__.createShape = __papplet__.createShape -__builtin__.cursor = __papplet__.cursor -__builtin__.curve = __papplet__.curve -__builtin__.curveDetail = __papplet__.curveDetail -__builtin__.curvePoint = __papplet__.curvePoint -__builtin__.curveTangent = __papplet__.curveTangent -__builtin__.curveTightness = __papplet__.curveTightness -__builtin__.curveVertex = __papplet__.curveVertex -__builtin__.delay = __papplet__.delay -__builtin__.directionalLight = __papplet__.directionalLight -__builtin__.ellipse = __papplet__.ellipse -__builtin__.ellipseMode = __papplet__.ellipseMode -__builtin__.emissive = __papplet__.emissive -__builtin__.endCamera = __papplet__.endCamera -__builtin__.endContour = __papplet__.endContour -__builtin__.endPGL = __papplet__.endPGL -__builtin__.endRaw = __papplet__.endRaw -__builtin__.endRecord = __papplet__.endRecord -__builtin__.endShape = __papplet__.endShape -__builtin__.exit = __papplet__.exit -__builtin__.fill = __papplet__.fill # We handle filter() by hand to permit both P5's filter() and Python's filter(). # __builtin__.filter = __papplet__.filter -__builtin__.frameRate = __papplet__.frameRate -__builtin__.frustum = __papplet__.frustum - -__builtin__.hint = __papplet__.hint -__builtin__.image = __papplet__.image -__builtin__.imageMode = __papplet__.imageMode - -__builtin__.lightFalloff = __papplet__.lightFalloff -__builtin__.lightSpecular = __papplet__.lightSpecular -__builtin__.lights = __papplet__.lights -__builtin__.line = __papplet__.line -__builtin__.link = __papplet__.link -__builtin__.loadBytes = __papplet__.loadBytes -__builtin__.loadFont = __papplet__.loadFont -__builtin__.loadImage = __papplet__.loadImage -__builtin__.loadJSONArray = __papplet__.loadJSONArray -__builtin__.loadJSONObject = __papplet__.loadJSONObject -__builtin__.loadPixels = __papplet__.loadPixels -__builtin__.loadShader = __papplet__.loadShader -__builtin__.loadShape = __papplet__.loadShape -__builtin__.loadTable = __papplet__.loadTable -__builtin__.loadXML = __papplet__.loadXML -__builtin__.loop = __papplet__.loop -__builtin__.millis = __papplet__.millis -__builtin__.modelX = __papplet__.modelX -__builtin__.modelY = __papplet__.modelY -__builtin__.modelZ = __papplet__.modelZ -__builtin__.noClip = __papplet__.noClip -__builtin__.noCursor = __papplet__.noCursor -__builtin__.noFill = __papplet__.noFill -__builtin__.noLights = __papplet__.noLights -__builtin__.noLoop = __papplet__.noLoop -__builtin__.noSmooth = __papplet__.noSmooth -__builtin__.noStroke = __papplet__.noStroke -__builtin__.noTint = __papplet__.noTint -__builtin__.noise = __papplet__.noise -__builtin__.noiseDetail = __papplet__.noiseDetail -__builtin__.noiseSeed = __papplet__.noiseSeed -__builtin__.normal = __papplet__.normal -__builtin__.ortho = __papplet__.ortho -__builtin__.parseXML = __papplet__.parseXML -__builtin__.perspective = __papplet__.perspective -__builtin__.point = __papplet__.point -__builtin__.pointLight = __papplet__.pointLight -__builtin__.popMatrix = __papplet__.popMatrix -__builtin__.popStyle = __papplet__.popStyle -__builtin__.printArray = __papplet__.printArray -__builtin__.printCamera = __papplet__.printCamera -__builtin__.printMatrix = __papplet__.printMatrix -__builtin__.printProjection = __papplet__.printProjection -__builtin__.quad = __papplet__.quad -__builtin__.quadraticVertex = __papplet__.quadraticVertex - # Processing's "random" function works as documented, but is blown # away if the user does a python 'import random'. This seems # reasonable to me. __builtin__.random = __papplet__.random -__builtin__.randomGaussian = __papplet__.randomGaussian -__builtin__.randomSeed = __papplet__.randomSeed -__builtin__.rect = __papplet__.rect -__builtin__.rectMode = __papplet__.rectMode -__builtin__.redraw = __papplet__.redraw -__builtin__.requestImage = __papplet__.requestImage -__builtin__.resetMatrix = __papplet__.resetMatrix -__builtin__.resetShader = __papplet__.resetShader -__builtin__.rotate = __papplet__.rotate -__builtin__.rotateX = __papplet__.rotateX -__builtin__.rotateY = __papplet__.rotateY -__builtin__.rotateZ = __papplet__.rotateZ -__builtin__.save = __papplet__.save -__builtin__.saveBytes = __papplet__.saveBytes -__builtin__.saveFrame = __papplet__.saveFrame -__builtin__.saveJSONArray = __papplet__.saveJSONArray -__builtin__.saveJSONObject = __papplet__.saveJSONObject -__builtin__.saveStream = __papplet__.saveStream -__builtin__.saveStrings = __papplet__.saveStrings -__builtin__.saveTable = __papplet__.saveTable -__builtin__.saveXML = __papplet__.saveXML -__builtin__.scale = __papplet__.scale -__builtin__.screenX = __papplet__.screenX -__builtin__.screenY = __papplet__.screenY -__builtin__.screenZ = __papplet__.screenZ -__builtin__.selectFolder = __papplet__.selectFolder -__builtin__.selectInput = __papplet__.selectInput -__builtin__.selectOutput = __papplet__.selectOutput -__builtin__.shader = __papplet__.shader -__builtin__.shape = __papplet__.shape -__builtin__.shapeMode = __papplet__.shapeMode -__builtin__.shearX = __papplet__.shearX -__builtin__.shearY = __papplet__.shearY -__builtin__.shininess = __papplet__.shininess -__builtin__.size = __papplet__.size -__builtin__.smooth = __papplet__.smooth -__builtin__.specular = __papplet__.specular -__builtin__.sphere = __papplet__.sphere -__builtin__.sphereDetail = __papplet__.sphereDetail -__builtin__.spotLight = __papplet__.spotLight -__builtin__.stroke = __papplet__.stroke -__builtin__.strokeCap = __papplet__.strokeCap -__builtin__.strokeJoin = __papplet__.strokeJoin -__builtin__.strokeWeight = __papplet__.strokeWeight - # Because of two 5-arg text() methods, we have to do this in Java. # __builtin__.text = __papplet__.text -__builtin__.textAlign = __papplet__.textAlign -__builtin__.textAscent = __papplet__.textAscent -__builtin__.textDescent = __papplet__.textDescent -__builtin__.textFont = __papplet__.textFont -__builtin__.textLeading = __papplet__.textLeading -__builtin__.textMode = __papplet__.textMode -__builtin__.textSize = __papplet__.textSize -__builtin__.textWidth = __papplet__.textWidth -__builtin__.texture = __papplet__.texture -__builtin__.textureMode = __papplet__.textureMode -__builtin__.textureWrap = __papplet__.textureWrap -__builtin__.tint = __papplet__.tint -__builtin__.translate = __papplet__.translate -__builtin__.triangle = __papplet__.triangle -__builtin__.updatePixels = __papplet__.updatePixels -__builtin__.vertex = __papplet__.vertex +for f in """ + ambient ambientLight applyMatrix arc beginCamera beginContour beginPGL + beginRaw beginRecord beginShape bezier bezierDetail bezierPoint bezierTangent + bezierVertex blendMode box camera clear clip color colorMode createFont + createImage createInput createOutput createReader createShape curve curveDetail + curvePoint curveTangent curveTightness curveVertex delay directionalLight + displayDensity ellipse ellipseMode emissive endCamera endContour endPGL endRaw + endRecord endShape exit fill frameRate frustum fullScreen hint imageMode + launch lightFalloff lightSpecular lights line link loadBytes loadFont loadImage + loadJSONArray loadJSONObject loadPixels loadShader loadShape loadTable loadXML + loop millis modelX modelY modelZ noClip noCursor noFill noLights noLoop + noSmooth noStroke noTint noise noiseDetail noiseSeed normal ortho parseXML + perspective pixelDensity point pointLight popMatrix popStyle printArray + printCamera printMatrix printProjection quad quadraticVertex randomGaussian + randomSeed rect rectMode redraw requestImage resetMatrix resetShader rotate + rotateX rotateY rotateZ save saveBytes saveFrame saveJSONArray saveJSONObject + saveStream saveTable saveXML scale screenX screenY screenZ selectFolder + selectInput selectOutput shader shape shapeMode shearX shearY shininess + size sketchPath smooth specular sphere sphereDetail spotLight stroke strokeCap + strokeJoin strokeWeight textAlign textAscent textDescent textFont textLeading + textMode textSize textWidth textureMode textureWrap thread tint translate + triangle updatePixels vertex + image background mask blend copy cursor texture + circle square push pop +""".split(): + assert getattr(__papplet__, f) + setattr(__builtin__, f, getattr(__papplet__, f)) ''' In order to get colors to behave reasonably, they have to be cast to positive @@ -453,78 +311,44 @@ def __ge__(a, b): # And these are PApplet static methods. Some are commented out to indicate # that we prefer or require Jython's implementation. #__builtin__.abs = PApplet.abs -__builtin__.acos = PApplet.acos -__builtin__.append = PApplet.append -__builtin__.arrayCopy = PApplet.arrayCopy -__builtin__.asin = PApplet.asin -__builtin__.atan = PApplet.atan -__builtin__.atan2 = PApplet.atan2 -__builtin__.binary = PApplet.binary -__builtin__.blendColor = PApplet.blendColor -__builtin__.ceil = PApplet.ceil -__builtin__.concat = PApplet.concat -__builtin__.constrain = lambda x, a, b: max(min(x, b), a) -__builtin__.cos = PApplet.cos -__builtin__.createInput = PApplet.createInput -__builtin__.createOutput = PApplet.createOutput -__builtin__.createReader = PApplet.createReader -__builtin__.day = PApplet.day -__builtin__.debug = PApplet.debug -__builtin__.degrees = PApplet.degrees -__builtin__.dist = PApplet.dist # __builtin__.exec = PApplet.exec -__builtin__.exp = PApplet.exp -__builtin__.expand = PApplet.expand -__builtin__.floor = PApplet.floor -__builtin__.hex = PApplet.hex -__builtin__.hour = PApplet.hour -__builtin__.join = PApplet.join -__builtin__.lerp = PApplet.lerp -__builtin__.loadBytes = PApplet.loadBytes -__builtin__.log = PApplet.log -__builtin__.mag = PApplet.mag # We permit both Python and P5's map()s. # __builtin__.map = PApplet.map -__builtin__.match = PApplet.match -__builtin__.matchAll = PApplet.matchAll # __builtin__.max = PApplet.max # __builtin__.min = PApplet.min -__builtin__.minute = PApplet.minute -__builtin__.month = PApplet.month -__builtin__.nf = PApplet.nf -__builtin__.nfc = PApplet.nfc -__builtin__.nfp = PApplet.nfp -__builtin__.nfs = PApplet.nfs -__builtin__.norm = PApplet.norm -__builtin__.pow = PApplet.pow # __builtin__.print = PApplet.print -#__builtin__.println = PApplet.println -__builtin__.radians = PApplet.radians -__builtin__.reverse = PApplet.reverse +# __builtin__.println = PApplet.println # __builtin__.round = PApplet.round -__builtin__.saveBytes = PApplet.saveBytes -__builtin__.saveStream = PApplet.saveStream -__builtin__.saveStrings = PApplet.saveStrings -__builtin__.second = PApplet.second -__builtin__.shorten = PApplet.shorten -__builtin__.sin = PApplet.sin -__builtin__.sort = PApplet.sort -__builtin__.splice = PApplet.splice -__builtin__.split = PApplet.split -__builtin__.splitTokens = PApplet.splitTokens -__builtin__.sq = PApplet.sq -__builtin__.sqrt = PApplet.sqrt -__builtin__.subset = PApplet.subset -__builtin__.tan = PApplet.tan -__builtin__.trim = PApplet.trim -__builtin__.unbinary = PApplet.unbinary -__builtin__.unhex = PApplet.unhex -__builtin__.year = PApplet.year + +__builtin__.constrain = lambda x, a, b: max(min(x, b), a) + +for f in """ +acos append arrayCopy asin atan atan2 binary blendColor ceil +concat cos createInput createOutput createReader day debug degrees dist +exp expand floor hex hour join lerp loadBytes log mag match matchAll +minute month nf nfc nfp nfs norm pow radians reverse saveBytes saveStream +saveStrings second shorten sin sort splice split splitTokens sq sqrt +subset tan trim unbinary unhex year +""".split(): + assert getattr(PApplet, f) + setattr(__builtin__, f, getattr(PApplet, f)) # Here are some names that resolve to static *and* instance methods. # Dispatch them to the appropriate methods based on the type of their # arguments. +def __createInput__(o): + if isinstance(o, basestring): + return __papplet__.createInput(o) + return PApplet.createInput(o) +__builtin__.createInput = __createInput__ + +def __createOutput__(o): + if isinstance(o, basestring): + return __papplet__.createOutput(o) + return PApplet.createOutput(o) +__builtin__.createOutput = __createOutput__ + def __createReader__(o): if isinstance(o, basestring): return __papplet__.createReader(o) @@ -601,11 +425,15 @@ def __open__(filename, *args, **kwargs): class FakeStdOut(): def write(self, s): __stdout__.print(s) + def flush(self): + __stdout__.flush() sys.stdout = FakeStdOut() class FakeStdErr(): def write(self, s): __stderr__.print(s) + def flush(self): + __stderr__.flush() sys.stderr = FakeStdErr() del FakeStdOut, FakeStdErr @@ -615,6 +443,74 @@ def __println__(o): __builtin__.println = __println__ +from org.python.core import Py +class PGraphicsPythonModeWrapper(object): + class popper(object): + def __init__(self, enter_func, exit_func, *args): + self.exit_func = exit_func + self.as_result = enter_func(*args) + def __enter__(self): + return self.as_result + def __exit__(self, *args): + self.exit_func() + + def __init__(self, g): + self.__dict__['g'] = g + + def _get_wrapped_image_(self): + return self.__dict__['g'] + + # Coerce this object into the wrapped PGraphics. + def __tojava__(self, klass): + if isinstance(self.g, klass): + return self.g + return Py.NoConversion + + def beginDraw(self): + return PGraphicsPythonModeWrapper.popper( + self.g.beginDraw, self.g.endDraw) + + def pushMatrix(self): + return PGraphicsPythonModeWrapper.popper( + self.g.pushMatrix, self.g.popMatrix) + + def beginShape(self, *args): + return PGraphicsPythonModeWrapper.popper( + self.g.beginShape, self.g.endShape, *args) + + def beginRaw(self, *args): + return PGraphicsPythonModeWrapper.popper( + self.g.beginRaw, self.g.endRaw, *args) + + def beginPGL(self): + return PGraphicsPythonModeWrapper.popper( + self.g.beginPGL, self.g.endPGL) + + # The PGraphicsJava2D shadows its ellipse, rect, arc, and line functions + # with field declarations, so we must bypass them here. + def ellipse(self, *args): + PGraphics.ellipse(self, *args) + + def rect(self, *args): + PGraphics.rect(self, *args) + + def line(self, *args): + PGraphics.line(self, *args) + + def arc(self, *args): + PGraphics.arc(self, *args) + + def __getattr__(self, attr): + return getattr(self.g, attr) + + def __setattr__(self, attr, value): + return setattr(self.g, attr, value) + +def FakeCreateGraphics(*args): + return PGraphicsPythonModeWrapper(__papplet__.createGraphics(*args)) +__builtin__.createGraphics = FakeCreateGraphics +del FakeCreateGraphics + # Implement # # with pushFoo(): @@ -666,6 +562,7 @@ def shim(*args): makePopper('beginShape', 'endShape', close_args=[CLOSE], exposed_name='beginClosedShape') makePopper('beginCamera', 'endCamera') +makePopper('push', 'pop') import os os.chdir(__cwd__) diff --git a/runtime/src/jycessing/detect_sketch_mode.py b/runtime/src/jycessing/detect_sketch_mode.py index b19910b5..bc01c764 100644 --- a/runtime/src/jycessing/detect_sketch_mode.py +++ b/runtime/src/jycessing/detect_sketch_mode.py @@ -16,6 +16,8 @@ ^( draw | + settings + | setup | key(Pressed|Released|Typed) @@ -58,6 +60,8 @@ (load|update)Pixels | background|clear|(no)?(Fill|Stroke) + | + createFont )$ """, re.X) @@ -78,7 +82,7 @@ def detect_mode(code, filename): if not isinstance(e, ast.Call): continue f = e.func - if illegalActiveModeCall.match(f.id): + if hasattr(f, 'id') and illegalActiveModeCall.match(f.id): return 'MIXED', MixedModeError( "You can't call %s() outside a function in \"active mode\"." % f.id, __file__, node.lineno - 1) diff --git a/runtime/src/jycessing/get_settings.py b/runtime/src/jycessing/get_settings.py new file mode 100644 index 00000000..b099bdda --- /dev/null +++ b/runtime/src/jycessing/get_settings.py @@ -0,0 +1,49 @@ +import ast + +__width__ = 100 +__height__ = 100 +__renderer__ = "JAVA2D" +__fullScreen__ = False +__smooth__ = False +__noSmooth__ = False +__pixelDensity__ = 1 + +def extract_settings(module): + global __width__, __height__, __renderer__, __fullScreen__, __smooth__, __noSmooth__ + global __pixelDensity__ + toremove = [] + for node in module.body: + if isinstance(node, ast.Expr) and isinstance(node.value, ast.Call): + func = node.value.func + if not hasattr(func, 'id'): continue + if func.id in ('size', 'smooth', 'noSmooth', 'fullScreen', 'pixelDensity'): + toremove.append(node) + if func.id == 'size': + args = node.value.args + if len(args) > 0 and isinstance(args[0], ast.Num): + __width__ = args[0].n + if len(args) > 1 and isinstance(args[1], ast.Num): + __height__ = args[1].n + if len(args) > 2: + if isinstance(args[2], ast.Str): + __renderer__ = args[2].s + elif isinstance(args[2], ast.Name): + __renderer__ = args[2].id + elif func.id == 'fullScreen': + __fullScreen__ = True + elif func.id == 'smooth': + __smooth__ = True + elif func.id == 'noSmooth': + __noSmooth__ = True + elif func.id == 'pixelDensity': + args = node.value.args + if len(args) > 0 and isinstance(args[0], ast.Num): + __pixelDensity__ = args[0].n + + for node in toremove: + module.body.remove(node) + +module = ast.parse(__processing_source__ + "\n\n", filename=__file__) +extract_settings(module) + +__cleaned_sketch__ = compile(module, __file__, mode='exec') diff --git a/runtime/src/jycessing/jni/OSX.java b/runtime/src/jycessing/jni/OSX.java new file mode 100644 index 00000000..aeb2ebfb --- /dev/null +++ b/runtime/src/jycessing/jni/OSX.java @@ -0,0 +1,39 @@ +package jycessing.jni; + +import jycessing.mode.PythonMode; +import processing.core.PApplet; +import processing.core.PConstants; + +public class OSX { + private static volatile boolean didLoad = false; + + public static void bringToFront() { + if (!didLoad && (PApplet.platform == PConstants.MACOSX)) { + try { + System.loadLibrary("jniosx"); + didLoad = true; + } catch (final UnsatisfiedLinkError err) { + System.err.println("Hmm. Can't load native code to bring window to front."); + } + } + if (didLoad) { + activateIgnoringOtherApps(); + } + } + + public static void bringToFront(PythonMode mode) { + if (!didLoad && (PApplet.platform == PConstants.MACOSX)) { + String path = null; + try { + path = mode.getContentFile("mode").getAbsolutePath() + "/libjniosx.dylib"; + System.load(path); + didLoad = true; + } catch (final UnsatisfiedLinkError err) { + System.err.println("Hmm. Can't load native code to bring window to front using the absolute path: " + path + "."); + } + } + bringToFront(); + } + + private static native void activateIgnoringOtherApps(); +} diff --git a/runtime/src/jycessing/jni/jniosx/jniosx/jniosx.m b/runtime/src/jycessing/jni/jniosx/jniosx/jniosx.m new file mode 100644 index 00000000..dd58aae4 --- /dev/null +++ b/runtime/src/jycessing/jni/jniosx/jniosx/jniosx.m @@ -0,0 +1,8 @@ +#include "jycessing_jni_OSX.h" + +#import "AppKit/AppKit.h" + +JNIEXPORT void JNICALL Java_jycessing_jni_OSX_activateIgnoringOtherApps +(JNIEnv *env, jclass klass) { + [NSApp activateIgnoringOtherApps:true]; +} diff --git a/runtime/src/jycessing/jni/jycessing_jni_OSX.h b/runtime/src/jycessing/jni/jycessing_jni_OSX.h new file mode 100644 index 00000000..79fa36f5 --- /dev/null +++ b/runtime/src/jycessing/jni/jycessing_jni_OSX.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class jycessing_jni_OSX */ + +#ifndef _Included_jycessing_jni_OSX +#define _Included_jycessing_jni_OSX +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: jycessing_jni_OSX + * Method: activateIgnoringOtherApps + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_jycessing_jni_OSX_activateIgnoringOtherApps + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/runtime/src/jycessing/launcher/LaunchHelper.java b/runtime/src/jycessing/launcher/LaunchHelper.java index ffdca55e..d3ca4a3c 100644 --- a/runtime/src/jycessing/launcher/LaunchHelper.java +++ b/runtime/src/jycessing/launcher/LaunchHelper.java @@ -9,14 +9,14 @@ /** * Launch and deployment service for various platforms. - * + * * @author Ralf Biedert */ public class LaunchHelper { /** * Copies one of our resources to a given file. - * + * * @param name * @param path * @throws IOException diff --git a/runtime/src/jycessing/launcher/StandaloneSketch.java b/runtime/src/jycessing/launcher/StandaloneSketch.java index f2790c03..38d9a4f8 100644 --- a/runtime/src/jycessing/launcher/StandaloneSketch.java +++ b/runtime/src/jycessing/launcher/StandaloneSketch.java @@ -19,11 +19,7 @@ import jycessing.annotations.PythonUsage; import processing.core.PApplet; -/** - * - * An old-school processing.py script. - * - */ +/** An old-school processing.py script. */ public class StandaloneSketch implements RunnableSketch { static void log(final Object... objs) { @@ -42,9 +38,9 @@ static void log(final Object... objs) { /** * Returns the path of the main processing-py.jar file. - * - * Used from launcher.py - * + * + *

Used from launcher.py + * * @return the path of processing-py.jar. */ @PythonUsage(methodName = "getMainJarFile") @@ -59,9 +55,8 @@ public File getMainJarFile() { } /** - * Returns the 'root' folder of this instance. Used when running with a - * wrapper. - * + * Returns the 'root' folder of this instance. Used when running with a wrapper. + * * @return the distribution root directory. */ public File getRuntimeRoot() { @@ -76,8 +71,6 @@ public File getRuntimeRoot() { return jar.getParentFile(); } - - public StandaloneSketch(final String[] args) throws Exception { final List argsList = Arrays.asList(args); @@ -116,8 +109,8 @@ public StandaloneSketch(final String[] args) throws Exception { } final Pattern JAR_RESOURCE = - Pattern.compile("jar:file:(.+?)/processing-py\\.jar!/jycessing/" - + Pattern.quote(BUILD_PROPERTIES)); + Pattern.compile( + "jar:file:(.+?)/processing-py\\.jar!/jycessing/" + Pattern.quote(BUILD_PROPERTIES)); final Pattern FILE_RESOURCE = Pattern.compile("file:(.+?)/bin/jycessing/" + Pattern.quote(BUILD_PROPERTIES)); @@ -149,8 +142,8 @@ public File getHomeDirectory() { @Override public String[] getPAppletArguments() { return new String[] { - PApplet.ARGS_SKETCH_FOLDER + "=" + sketchPath.getParentFile().getAbsolutePath(), - sketchPath.getName() // must be last argument + PApplet.ARGS_SKETCH_FOLDER + "=" + sketchPath.getParentFile().getAbsolutePath(), + sketchPath.getName() // must be last argument }; } @@ -188,5 +181,4 @@ public List getPathEntries() { return entries; } - } diff --git a/runtime/src/jycessing/mode/FormatServer.java b/runtime/src/jycessing/mode/FormatServer.java index 8401cfbb..e508de57 100644 --- a/runtime/src/jycessing/mode/FormatServer.java +++ b/runtime/src/jycessing/mode/FormatServer.java @@ -11,9 +11,9 @@ import processing.app.exec.StreamPump; /** - * This class manages running and communicating with a server that knows how to pretty-print - * Python source code. The server is written in python. If a CPython interpreter is available, - * we'll use it; otherwise we start up a Java processes using Jython to run the server. + * This class manages running and communicating with a server that knows how to pretty-print Python + * source code. The server is written in python. If a CPython interpreter is available, we'll use + * it; otherwise we start up a Java processes using Jython to run the server. */ public class FormatServer implements Formatter { @@ -41,8 +41,9 @@ private static boolean nativePythonAvailable() { /** * If a python exectuable is available on this machine, use it to run the formatting server. - * Otherwise, use the same Java that ran the PDE to interpret the formatting server with - * Jython, which takes a very long time to start up. + * Otherwise, use the same Java that ran the PDE to interpret the formatting server with Jython, + * which takes a very long time to start up. + * * @param formatServerPath Path to the format server script source. * @return a ProcessBuilder that, when started, will run the formatting server. */ @@ -56,43 +57,40 @@ private ProcessBuilder getPythonProcess(final String formatServerPath) { return new ProcessBuilder(Platform.getJavaPath(), "-jar", jython, formatServerPath); } - /** - * Starts the formatting server. - */ + /** Starts the formatting server. */ public void start() { started = true; final String serverpy = new File(modeHome, "formatter/format_server.py").getAbsolutePath(); final ProcessBuilder pb = getPythonProcess(serverpy); pb.redirectErrorStream(true); - new Thread(new Runnable() { - @Override - public void run() { - try { - log("Starting up the format server."); - server = pb.start(); - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - @Override - public void run() { - started = false; - shutdown(); - } - })); - new StreamPump(server.getInputStream(), "Format Server Output").addTarget(System.err) - .start(); - } catch (final Exception e) { - throw new RuntimeException(pb.toString(), e); - } - } - }, "FormatServerStarter").start(); + new Thread( + () -> { + try { + log("Starting up the format server."); + server = pb.start(); + Runtime.getRuntime() + .addShutdownHook( + new Thread( + () -> { + started = false; + shutdown(); + })); + new StreamPump(server.getInputStream(), "Format Server Output") + .addTarget(System.err) + .start(); + } catch (final Exception e) { + throw new RuntimeException(pb.toString(), e); + } + }, + "FormatServerStarter") + .start(); } public boolean isStarted() { return started; } - /** - * Called as a ShutdownHook. Stops the formatting server. - */ + /** Called as a ShutdownHook. Stops the formatting server. */ public void shutdown() { sendShutdown(); server.destroy(); @@ -104,7 +102,7 @@ public String format(final String text) { // Connect to format server. try (final Socket sock = new Socket("localhost", 10011); final DataOutputStream out = new DataOutputStream(sock.getOutputStream()); - final DataInputStream in = new DataInputStream(sock.getInputStream());) { + final DataInputStream in = new DataInputStream(sock.getInputStream()); ) { final byte[] encoded = text.getBytes("utf-8"); // Send big-endian encoded integer representing length of utf-8 encoded source code. out.writeInt(encoded.length); @@ -124,13 +122,11 @@ public String format(final String text) { } } - /** - * Tells the formatting server to shut down gracefully. - */ + /** Tells the formatting server to shut down gracefully. */ private void sendShutdown() { log("Sending shutdown message to format server."); try (final Socket sock = new Socket("localhost", 10011); - final DataOutputStream out = new DataOutputStream(sock.getOutputStream());) { + final DataOutputStream out = new DataOutputStream(sock.getOutputStream()); ) { // -1 is a sentinel value meaning "die". out.writeInt(-1); out.flush(); diff --git a/runtime/src/jycessing/mode/PyEditor.java b/runtime/src/jycessing/mode/PyEditor.java index 18d466ae..7bd824b8 100644 --- a/runtime/src/jycessing/mode/PyEditor.java +++ b/runtime/src/jycessing/mode/PyEditor.java @@ -21,6 +21,7 @@ import jycessing.DisplayType; import jycessing.IOUtil; +import jycessing.jni.OSX; import jycessing.mode.export.ExportDialog; import jycessing.mode.run.PdeSketch; import jycessing.mode.run.PdeSketch.LocationType; @@ -30,16 +31,23 @@ import processing.app.Base; import processing.app.Formatter; import processing.app.Language; +import processing.app.Library; import processing.app.Messages; import processing.app.Mode; import processing.app.Platform; +import processing.app.Preferences; import processing.app.SketchCode; import processing.app.SketchException; +import processing.app.syntax.JEditTextArea; +import processing.app.syntax.PdeTextArea; +import processing.app.syntax.PdeTextAreaDefaults; import processing.app.ui.Editor; import processing.app.ui.EditorException; import processing.app.ui.EditorState; import processing.app.ui.EditorToolbar; import processing.app.ui.Toolkit; +import processing.core.PApplet; +import processing.core.PConstants; @SuppressWarnings("serial") public class PyEditor extends Editor { @@ -52,8 +60,8 @@ private static void log(final String msg) { } /** - * Every PyEditor has a UUID that the {@link SketchServiceManager} uses to - * route events from the {@link SketchService} to its owning editor. + * Every PyEditor has a UUID that the {@link SketchServiceManager} uses to route events from the + * {@link SketchService} to its owning editor. */ private final String id; @@ -62,20 +70,19 @@ private static void log(final String msg) { private final SketchServiceProcess sketchService; /** - * If the user runs a dirty sketch, we create a temp dir containing the - * modified state of the sketch and run it from there. We keep track - * of it in this variable in order to delete it when done running. + * If the user runs a dirty sketch, we create a temp dir containing the modified state of the + * sketch and run it from there. We keep track of it in this variable in order to delete it when + * done running. */ private Path tempSketch; - protected PyEditor(final Base base, final String path, final EditorState state, final Mode mode) throws EditorException { super(base, path, state, mode); id = UUID.randomUUID().toString(); inputHandler = new PyInputHandler(this); - pyMode = (PythonMode)mode; + pyMode = (PythonMode) mode; // Provide horizontal scrolling. textarea.addMouseWheelListener(createHorizontalScrollListener()); @@ -86,20 +93,22 @@ protected PyEditor(final Base base, final String path, final EditorState state, // Ensure that the sketch service gets properly destroyed when either the // JVM terminates or this editor closes, whichever comes first. - final Thread cleanup = new Thread(new Runnable() { - @Override - public void run() { - sketchServiceManager.destroySketchService(PyEditor.this); - } - }); + final Thread cleanup = + new Thread(() -> sketchServiceManager.destroySketchService(PyEditor.this)); Runtime.getRuntime().addShutdownHook(cleanup); - addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(final WindowEvent e) { - cleanup.run(); - Runtime.getRuntime().removeShutdownHook(cleanup); - } - }); + addWindowListener( + new WindowAdapter() { + @Override + public void windowClosing(final WindowEvent e) { + cleanup.run(); + Runtime.getRuntime().removeShutdownHook(cleanup); + } + }); + } + + @Override + protected JEditTextArea createTextArea() { + return new PdeTextArea(new PdeTextAreaDefaults(mode), new PyInputHandler(this), this); } public String getId() { @@ -151,65 +160,98 @@ private void cleanupTempSketch() { } } - /** - * Build menus. - */ + /** Build menus. */ @Override public JMenu buildFileMenu() { - final String appTitle = Language.text("toolbar.export_application"); + final String appTitle = Language.text("Export Application"); final JMenuItem exportApplication = Toolkit.newJMenuItem(appTitle, 'E'); - exportApplication.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - handleExportApplication(); - } - }); + exportApplication.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + handleExportApplication(); + } + }); return buildFileMenu(new JMenuItem[] {exportApplication}); } @Override public JMenu buildHelpMenu() { - final JMenu menu = new JMenu("Help"); - menu.add(new JMenuItem(new AbstractAction("Report a bug in Python Mode") { - @Override - public void actionPerformed(final ActionEvent e) { - Platform.openURL("http://github.com/jdf/processing.py-bugs/issues"); - } - })); - menu.add(new JMenuItem(new AbstractAction("Contribute to Python Mode") { - @Override - public void actionPerformed(final ActionEvent e) { - Platform.openURL("http://github.com/jdf/processing.py"); - } - })); + // I add a zero-width space to the end of the word "Help" in order to + // prevent OS X from auto-disabling everything in the menu when running + // a sketch. + final JMenu menu = new JMenu("Help\u200B"); + menu.add( + new JMenuItem( + new AbstractAction("References") { + @Override + public void actionPerformed(final ActionEvent e) { + Platform.openURL("http://py.processing.org/reference/"); + } + })); + menu.add( + new JMenuItem( + new AbstractAction("Tutorials") { + @Override + public void actionPerformed(final ActionEvent e) { + Platform.openURL("http://py.processing.org/tutorials/"); + } + })); + menu.add( + new JMenuItem( + new AbstractAction("Examples") { + @Override + public void actionPerformed(final ActionEvent e) { + Platform.openURL("http://py.processing.org/examples/"); + } + })); + menu.add( + new JMenuItem( + new AbstractAction("Report a bug in Python Mode") { + @Override + public void actionPerformed(final ActionEvent e) { + Platform.openURL("http://github.com/jdf/processing.py-bugs/issues"); + } + })); + menu.add( + new JMenuItem( + new AbstractAction("Contribute to Python Mode") { + @Override + public void actionPerformed(final ActionEvent e) { + Platform.openURL("http://github.com/jdf/processing.py"); + } + })); return menu; } @Override public JMenu buildSketchMenu() { final JMenuItem runItem = Toolkit.newJMenuItem(Language.text("toolbar.run"), 'R'); - runItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - handleRun(); - } - }); + runItem.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + handleRun(); + } + }); final JMenuItem presentItem = Toolkit.newJMenuItemShift(Language.text("toolbar.present"), 'R'); - presentItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - handlePresent(); - } - }); + presentItem.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + handlePresent(); + } + }); final JMenuItem stopItem = new JMenuItem(Language.text("toolbar.stop")); - stopItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - handleStop(); - } - }); + stopItem.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + handleStop(); + } + }); return buildSketchMenu(new JMenuItem[] {runItem, presentItem, stopItem}); } @@ -224,19 +266,21 @@ public EditorToolbar createToolbar() { return new PyToolbar(this); } - /** - * TODO(James Gilles): Create this! - * Create export GUI and hand off results to performExport() - */ + /** TODO(James Gilles): Create this! Create export GUI and hand off results to performExport() */ public void handleExportApplication() { // Leaving this here because it seems like it's more the editor's responsibility if (sketch.isModified()) { final Object[] options = {"OK", "Cancel"}; final int result = - JOptionPane - .showOptionDialog(this, "Save changes before export?", "Save", - JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, - options[0]); + JOptionPane.showOptionDialog( + this, + "Save changes before export?", + "Save", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[0]); if (result == JOptionPane.OK_OPTION) { handleSave(true); } else { @@ -256,10 +300,10 @@ public File getSplashFile() { } /** - * Save the current state of the sketch code into a temp dir, and return - * the created directory. - * @return a new directory containing a saved version of the current - * (presumably modified) sketch code. + * Save the current state of the sketch code into a temp dir, and return the created directory. + * + * @return a new directory containing a saved version of the current (presumably modified) sketch + * code. * @throws IOException */ private Path createTempSketch() throws IOException { @@ -281,8 +325,8 @@ private void runSketch(final DisplayType displayType) { tempSketch = createTempSketch(); sketchPath = tempSketch.resolve(sketchMainFileName).toFile(); } catch (final IOException e) { - Messages.showError("Sketchy Behavior", "I can't copy your unsaved work\n" - + "to a temp directory.", e); + Messages.showError( + "Sketchy Behavior", "I can't copy your unsaved work\n" + "to a temp directory.", e); return; } } else { @@ -300,17 +344,25 @@ private void runSketch(final DisplayType displayType) { } try { - sketchService - .runSketch(new PdeSketch(sketch, sketchPath, displayType, location, locationType)); + sketchService.runSketch( + new PdeSketch(sketch, sketchPath, displayType, location, locationType, + Preferences.get("run.present.bgcolor"), Preferences.get("run.present.stop.color"))); } catch (final SketchException e) { statusError(e); } } + private void bringToFront() { + if (PApplet.platform == PConstants.MACOSX) { + OSX.bringToFront(pyMode); + } + } + @Override public void deactivateRun() { restoreToolbar(); cleanupTempSketch(); + bringToFront(); } public void handleRun() { @@ -329,25 +381,15 @@ public void handleStop() { } private void restoreToolbar() { - // toolbar.deactivate(PyToolbar.SAVE); toolbar.deactivateStop(); toolbar.deactivateRun(); toFront(); } - public void handleSave() { - // toolbar.activate(PyToolbar.SAVE); - super.handleSave(true); - restoreToolbar(); - recolor(); - } - @Override - public boolean handleSaveAs() { - // toolbar.activate(PyToolbar.SAVE); - final boolean result = super.handleSaveAs(); - restoreToolbar(); - return result; + public void handleSaveImpl() { + super.handleSaveImpl(); + recolor(); } @Override @@ -357,11 +399,19 @@ public void statusError(final String what) { // sketch died for some reason } @Override - public void handleImportLibrary(final String jarPath) { + public void handleImportLibrary(final String libraryName) { sketch.ensureExistence(); - final String name = new File(jarPath).getParentFile().getParentFile().getName(); + + final Library lib = mode.findLibraryByName(libraryName); + if (lib == null) { + statusError("Unable to locate library: " + libraryName); + return; + } + + final String name = new File(lib.getJarPath()).getParentFile().getParentFile().getName(); if (Pattern.compile("^add_library\\(\\s*'" + name + "'\\s*\\)\\s*$", Pattern.MULTILINE) - .matcher(getText()).find()) { + .matcher(getText()) + .find()) { return; } setSelection(0, 0); // scroll to start @@ -410,4 +460,10 @@ public void printOut(final String msg) { public void printErr(final String msg) { console.message(msg, true); } + + @Override + public void showReference(final String filename) { + Platform.openURL( + String.format("http://py.processing.org/reference/%s", filename.replace("_.", "."))); + } } diff --git a/runtime/src/jycessing/mode/PyInputHandler.java b/runtime/src/jycessing/mode/PyInputHandler.java index 948b73ff..da5c6f9f 100644 --- a/runtime/src/jycessing/mode/PyInputHandler.java +++ b/runtime/src/jycessing/mode/PyInputHandler.java @@ -2,7 +2,6 @@ import java.awt.Toolkit; import java.awt.event.ActionEvent; -import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.Stack; import java.util.regex.Matcher; @@ -13,44 +12,36 @@ import processing.app.syntax.PdeInputHandler; import processing.app.ui.Editor; -/** - * This class provides Pythonic handling of TAB, BACKSPACE, and ENTER keys. - */ +/** This class provides Pythonic handling of keystrokes. */ public class PyInputHandler extends PdeInputHandler { final PyEditor pyEditor; - JEditTextArea textArea; // assigned on first key press - // ctrl-alt on windows & linux, cmd-alt on os x - private static int CTRL_ALT = ActionEvent.ALT_MASK - | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); + private static int CTRL_ALT = + ActionEvent.ALT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); // 4 spaces per pep8 private static final String TAB = " "; private static final int TAB_SIZE = TAB.length(); public PyInputHandler(final Editor editor) { + super(editor); pyEditor = (PyEditor)editor; - textArea = pyEditor.getTextArea(); - - // This is a somewhat gross "shim" keyListener. - // The HandlePressed() Method was not properly overriding the - // handlePressed() within pdeInputHandler.java so I circumvent the need for - // the pde call by adding an additional keyListener here. It's in no way ideal, - // but is a quick fix to the "No Returns or Tabs" bug in the new - // python mode PDEX. You can find the pdeInputHandler.java at the url below. - // https://github.com/processing/processing/blob/master/ - // app/src/processing/app/syntax/PdeInputHandler.java#L243 - - textArea.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(final KeyEvent e) { - if (handlePressed(e)) { - e.consume(); - } - } - }); + } + + private static boolean isPrintableChar(final char c) { + if (c >= 32 && c <= 127) { + return true; + } + if (c == KeyEvent.CHAR_UNDEFINED || Character.isISOControl(c)) { + return false; + } + final Character.UnicodeBlock block = Character.UnicodeBlock.of(c); + return block != null && block != Character.UnicodeBlock.SPECIALS; + } + JEditTextArea getTextArea() { + return pyEditor.getTextArea(); } @Override @@ -59,14 +50,12 @@ public boolean handlePressed(final KeyEvent event) { final int code = event.getKeyCode(); final int mods = event.getModifiers(); + final JEditTextArea textArea = getTextArea(); final Sketch sketch = pyEditor.getSketch(); - if (textArea == null) { - textArea = pyEditor.getTextArea(); - } // things that change the content of the text area - if ((code == KeyEvent.VK_BACK_SPACE) || (code == KeyEvent.VK_TAB) - || (code == KeyEvent.VK_ENTER) || (mods == 0 && c >= 32 && c < 128)) { + if (!event.isMetaDown() && (code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_TAB + || code == KeyEvent.VK_ENTER || isPrintableChar(c))) { sketch.setModified(true); } @@ -104,7 +93,8 @@ public boolean handlePressed(final KeyEvent event) { } final LineInfo currentLine = new LineInfo(thisLine); if (currentLine.caretInText) { - // The caret is in the text; let the text editor handle this backspace. + // The caret is in the text; let the text editor handle this + // backspace. break; } // The caret is not in the text; treat it as a request to unindent. @@ -129,14 +119,10 @@ public boolean handlePressed(final KeyEvent event) { return false; } - /** - * A line is some whitespace followed by a bunch of whatever. - */ + /** A line is some whitespace followed by a bunch of whatever. */ private static final Pattern LINE = Pattern.compile("^(\\s*)(.*)$"); - /** - * Everything we need to know about a line in the text editor. - */ + /** Everything we need to know about a line in the text editor. */ private class LineInfo { public final int lineNumber; @@ -146,12 +132,14 @@ private class LineInfo { // The text content after whatever indent. public final String text; - // Whether or not the caret happens to be positioned in the text portion of the line. + // Whether or not the caret happens to be positioned in the text portion + // of the line. public final boolean caretInText; LineInfo(final int lineNumber) { this.lineNumber = lineNumber; + final JEditTextArea textArea = getTextArea(); final Matcher m = LINE.matcher(textArea.getLineText(lineNumber)); if (!m.matches()) { throw new AssertionError("How can a line have less than nothing in it?"); @@ -161,12 +149,14 @@ private class LineInfo { final int caretLinePos = textArea.getCaretPosition() - textArea.getLineStartOffset(lineNumber); caretInText = caretLinePos > space.length(); - // Calculate the current indent measured in tab stops of TAB_SIZE spaces. + // Calculate the current indent measured in tab stops of TAB_SIZE + // spaces. int currentIndent = 0; int spaceCounter = 0; for (int i = 0; i < space.length(); i++) { spaceCounter++; - // A literal tab character advances to the next tab stop, as does the TAB_SIZEth space + // A literal tab character advances to the next tab stop, as + // does the TAB_SIZEth space // character in a row. if (spaceCounter % TAB_SIZE == 0 || space.charAt(i) == '\t') { currentIndent++; @@ -183,15 +173,24 @@ public String toString() { } /** - * Maybe change the indent of the current selection. If sign is positive, then increase the - * indent; otherwise, decrease it. - *

If the last non-comment, non-blank line ends with ":", then the maximum indent for the - * current line is one greater than the indent of that ":"-bearing line. Otherwise, the maximum - * indent is equal to the indent of the last non-comment line. - *

The minimum indent is 0. - * @param sign The direction in which to modify the indent of the current line. + * Maybe change the indent of the current selection. If sign is positive, + * then increase the indent; otherwise, decrease it. + * + *

+ * If the last non-comment, non-blank line ends with ":", then the maximum + * indent for the current line is one greater than the indent of that + * ":"-bearing line. Otherwise, the maximum indent is equal to the indent of + * the last non-comment line. + * + *

+ * The minimum indent is 0. + * + * @param sign The direction in which to modify the indent of the current + * line. */ public void indent(final int sign) { + final JEditTextArea textArea = getTextArea(); + final int startLine = textArea.getSelectionStartLine(); final int stopLine = textArea.getSelectionStopLine(); final int selectionStart = textArea.getSelectionStart(); @@ -231,19 +230,23 @@ public void indent(final int sign) { for (int i = startLine; i <= stopLine; i++) { indentLineBy(i, deltaIndent); } - textArea.setSelectionStart(getAbsoluteCaretPositionRelativeToLineEnd(startLine, - startLineEndRelativePos)); - textArea.setSelectionEnd(getAbsoluteCaretPositionRelativeToLineEnd(stopLine, - stopLineEndRelativePos)); + textArea.setSelectionStart( + getAbsoluteCaretPositionRelativeToLineEnd(startLine, startLineEndRelativePos)); + textArea.setSelectionEnd( + getAbsoluteCaretPositionRelativeToLineEnd(stopLine, stopLineEndRelativePos)); } private int getAbsoluteCaretPositionRelativeToLineEnd(final int line, final int lineEndRelativePosition) { + final JEditTextArea textArea = getTextArea(); + return Math.max(textArea.getLineStopOffset(line) - lineEndRelativePosition, textArea.getLineStartOffset(line)); } private void indentLineBy(final int line, final int deltaIndent) { + final JEditTextArea textArea = getTextArea(); + final LineInfo currentLine = new LineInfo(line); final int newIndent = Math.max(0, currentLine.indent + deltaIndent); @@ -253,24 +256,14 @@ private void indentLineBy(final int line, final int deltaIndent) { } sb.append(currentLine.text); - // Adjust for off by one error when de indenting allowing easier traversal through text area. - if (deltaIndent < 0) { - textArea.select(textArea.getLineStartOffset(line) + 1, textArea.getLineStopOffset(line) - 1); - } else { - textArea.select(textArea.getLineStartOffset(line), textArea.getLineStopOffset(line) - 1); - } - - - final String newLine = sb.toString(); - textArea.setSelectedText(newLine); - + textArea.select(textArea.getLineStartOffset(line), textArea.getLineStopOffset(line) - 1); + textArea.setSelectedText(sb.toString()); textArea.selectNone(); } private static final Pattern INITIAL_WHITESPACE = Pattern.compile("^(\\s*)"); /* - * This can be fooled by a line like - * print "He said: #LOLHASHTAG!" + * This can be fooled by a line like print "He said: #LOLHASHTAG!" */ private static final Pattern TERMINAL_COLON = Pattern.compile(":\\s*(#.*)?$"); private static final Pattern POP_CONTEXT = Pattern.compile("^\\s*(return|break|continue)\\b"); @@ -284,15 +277,22 @@ private boolean isClose(final char c) { } /** - * Search for an unterminated paren or bracket. If found, return - * its index in the given text. Otherwise return -1. - *

Ignores syntax errors, treating (foo] as a valid construct. - *

Assumes that the text contains no surrogate characters. + * Search for an unterminated paren or bracket. If found, return its index + * in the given text. Otherwise return -1. + * + *

+ * Ignores syntax errors, treating (foo] as a valid construct. + * + *

+ * Assumes that the text contains no surrogate characters. + * * @param cursor The current cursor position in the given text. * @param text The text to search for an unterminated paren or bracket. * @return The index of the unterminated paren, or -1. */ private int indexOfUnclosedParen() { + final JEditTextArea textArea = getTextArea(); + final int cursor = textArea.getCaretPosition(); final String text = textArea.getText(); final Stack stack = new Stack(); @@ -327,6 +327,7 @@ private String indentOf(final String line) { } private String getInitialWhitespace() { + final JEditTextArea textArea = getTextArea(); final String text = textArea.getText(); final int cursor = textArea.getCaretPosition(); final int lineNumber = textArea.getLineOfOffset(cursor); @@ -372,6 +373,8 @@ private String getInitialWhitespace() { } private String newline() { + final JEditTextArea textArea = getTextArea(); + final int cursor = textArea.getCaretPosition(); if (cursor <= 1) { return "\n"; @@ -390,7 +393,8 @@ private String newline() { if (TERMINAL_COLON.matcher(line).find()) { return "\n" + initialWhitespace + TAB; } - // TODO: popping context on return should return to the indent of the last def. + // TODO: popping context on return should return to the indent of the + // last def. if (POP_CONTEXT.matcher(line).find()) { final int currentIndentLength = initialWhitespace.length(); final int spaceCount = Math.max(0, currentIndentLength - 4); diff --git a/runtime/src/jycessing/mode/PyKeywordMap.java b/runtime/src/jycessing/mode/PyKeywordMap.java index 685d2ea2..4875520e 100644 --- a/runtime/src/jycessing/mode/PyKeywordMap.java +++ b/runtime/src/jycessing/mode/PyKeywordMap.java @@ -7,17 +7,16 @@ public class PyKeywordMap { private final Keyword[] map; - /** - * Creates a new KeywordMap. - */ + /** Creates a new KeywordMap. */ public PyKeywordMap() { this(52); } /** * Creates a new KeywordMap. - * @param mapLength The number of `buckets' to create. - * A value of 52 will give good performance for most maps. + * + * @param mapLength The number of `buckets' to create. A value of 52 will give good performance + * for most maps. */ public PyKeywordMap(final int mapLength) { this.mapLength = mapLength; @@ -26,6 +25,7 @@ public PyKeywordMap(final int mapLength) { /** * Looks up a key. + * * @param text The text segment * @param offset The offset of the substring within the text segment * @param length The length of the substring @@ -50,8 +50,8 @@ public byte lookup(final Segment text, final int offset, final int length) { /** * Adds a key-value mapping. - * @param keyword The key - * @Param id The value + * + * @param keyword The key @Param id The value */ public void add(final String keyword, final byte id) { final int key = getStringMapKey(keyword); @@ -83,5 +83,4 @@ public Keyword(final char[] keyword, final byte id, final Keyword next) { public byte id; public Keyword next; } - } diff --git a/runtime/src/jycessing/mode/PyToolbar.java b/runtime/src/jycessing/mode/PyToolbar.java index d4d53f3c..dac5eeba 100644 --- a/runtime/src/jycessing/mode/PyToolbar.java +++ b/runtime/src/jycessing/mode/PyToolbar.java @@ -14,7 +14,7 @@ public PyToolbar(final Editor editor) { @Override public void handleRun(final int modifiers) { - final PyEditor peditor = (PyEditor)editor; + final PyEditor peditor = (PyEditor) editor; final boolean shift = (modifiers & InputEvent.SHIFT_MASK) != 0; if (shift) { peditor.handlePresent(); @@ -25,7 +25,7 @@ public void handleRun(final int modifiers) { @Override public void handleStop() { - final PyEditor peditor = (PyEditor)editor; + final PyEditor peditor = (PyEditor) editor; peditor.handleStop(); } } diff --git a/runtime/src/jycessing/mode/PythonMode.java b/runtime/src/jycessing/mode/PythonMode.java index 4715a795..c994983a 100644 --- a/runtime/src/jycessing/mode/PythonMode.java +++ b/runtime/src/jycessing/mode/PythonMode.java @@ -19,29 +19,31 @@ public class PythonMode extends Mode { /** - * If the environment variable VERBOSE_PYTHON_MODE is equal to the string "true", then - * many Python Mode operations will be logged to standard error. + * If the environment variable VERBOSE_PYTHON_MODE is equal to the string "true", then many Python + * Mode operations will be logged to standard error. */ public static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("VERBOSE_PYTHON_MODE")); /** - * If the environment variable SKETCH_RUNNER_FIRST is equal to the string "true", then - * {@link PythonMode} expects that the {@link SketchRunner} is already running and waiting - * to be communicated with (as when you're debugging it in Eclipse, for example). + * If the environment variable SKETCH_RUNNER_FIRST is equal to the string "true", then {@link + * PythonMode} expects that the {@link SketchRunner} is already running and waiting to be + * communicated with (as when you're debugging it in Eclipse, for example). */ - public static final boolean SKETCH_RUNNER_FIRST = Boolean.parseBoolean(System - .getenv("SKETCH_RUNNER_FIRST")); + public static final boolean SKETCH_RUNNER_FIRST = + Boolean.parseBoolean(System.getenv("SKETCH_RUNNER_FIRST")); + + public static final String SITE_PACKAGES = "site-packages"; /** - * Python auto-formatting is handled by a server. {@link FormatServer} handles - * the lifecycle of, and communication with, that server. + * Python auto-formatting is handled by a server. {@link FormatServer} handles the lifecycle of, + * and communication with, that server. */ private final FormatServer formatServer; /** - * Sketches are run in external JVM processes. The {@link SketchServiceManager} handles - * the creation and destruction of those processes, and routes communication between - * {@link PyEditor}s and their affiliated {@link SketchService}s. + * Sketches are run in external JVM processes. The {@link SketchServiceManager} handles the + * creation and destruction of those processes, and routes communication between {@link PyEditor}s + * and their affiliated {@link SketchService}s. */ private final SketchServiceManager sketchServiceManager; @@ -56,6 +58,20 @@ public PythonMode(final Base base, final File folder) { * and not on any API. May break in the future. */ librariesFolder = Platform.getContentFile("modes/java/libraries"); + final File pythonLibs = getSitePackages(); + if (pythonLibs.exists()) { + if (!pythonLibs.isDirectory()) { + System.err.println(pythonLibs + " exists but is not directory"); + } + } else { + if (!pythonLibs.mkdirs()) { + System.err.println("cannot create " + pythonLibs); + } + } + } + + public static File getSitePackages() { + return new File(Base.getSketchbookLibrariesFolder(), SITE_PACKAGES); } @Override @@ -74,10 +90,10 @@ public Editor createEditor(final Base base, final String path, final EditorState sketchServiceManager.start(); } - try { + try { return new PyEditor(base, path, state, this); - } catch(EditorException e) { - Messages.showError("Editor Exception", "Issue Creating Editor", e); + } catch (final EditorException e) { + Messages.showError("Editor Exception", "Issue Creating Editor", e); return null; } } @@ -119,5 +135,4 @@ public TokenMarker createTokenMarker() { public SketchServiceManager getSketchServiceManager() { return sketchServiceManager; } - } diff --git a/runtime/src/jycessing/mode/PythonTokenMarker.java b/runtime/src/jycessing/mode/PythonTokenMarker.java index 91eae7af..39c3fa94 100644 --- a/runtime/src/jycessing/mode/PythonTokenMarker.java +++ b/runtime/src/jycessing/mode/PythonTokenMarker.java @@ -37,7 +37,7 @@ public void addColoring(final String keyword, final String coloring) { paren = true; break; } - keywords.add(keyword, (byte)id); + keywords.add(keyword, (byte) id); } @Override @@ -49,7 +49,8 @@ public byte markTokensImpl(byte token, final Segment line, final int lineIndex) final int length = line.count + offset; boolean backslash = false; - loop: for (int i = offset; i < length; i++) { + loop: + for (int i = offset; i < length; i++) { final int i1 = (i + 1); final char c = array[i]; @@ -165,43 +166,73 @@ public byte markTokensImpl(byte token, final Segment line, final int lineIndex) return token; } + /** Constants (QUARTER_PI, CORNERS, etc.) */ + private static final byte CONSTANT = Token.LITERAL2; + + /** Keywords (void, int, boolean, etc.) */ + private static final byte KEYWORD = Token.KEYWORD1; + + /** Fields [variables within a class] */ + private static final byte FIELD = Token.KEYWORD2; + + /** Loop/function-like blocks (for, while, etc.) */ + private static final byte LOOP_KEYWORD = Token.KEYWORD3; + + /** Functions */ + private static final byte FUNCTION = Token.FUNCTION1; + + /** Methods (functions inside a class) */ + private static final byte METHOD = Token.FUNCTION2; + + /** Built-in Processing functions (setup, draw, mouseDragged). */ + private static final byte BUILTIN_FUNCTION = Token.FUNCTION4; + + /** Built-in Processing functions (setup, draw, mouseDragged). */ + private static final byte OPERATOR = Token.OPERATOR; + public static PyKeywordMap getKeywords() { if (pyKeywords == null) { pyKeywords = new PyKeywordMap(); - pyKeywords.add("__init__", Token.FUNCTION2); - pyKeywords.add("and", Token.KEYWORD3); - pyKeywords.add("as", Token.KEYWORD3); - pyKeywords.add("assert", Token.KEYWORD1); - pyKeywords.add("break", Token.KEYWORD1); - pyKeywords.add("chr", Token.FUNCTION1); - pyKeywords.add("class", Token.KEYWORD2); - pyKeywords.add("continue", Token.KEYWORD1); - pyKeywords.add("def", Token.KEYWORD2); - pyKeywords.add("del", Token.KEYWORD2); - pyKeywords.add("elif", Token.KEYWORD1); - pyKeywords.add("else", Token.KEYWORD1); - pyKeywords.add("except", Token.KEYWORD1); - pyKeywords.add("exec", Token.KEYWORD1); - pyKeywords.add("finally", Token.KEYWORD1); - pyKeywords.add("for", Token.KEYWORD3); - pyKeywords.add("from", Token.KEYWORD2); - pyKeywords.add("global", Token.KEYWORD2); - pyKeywords.add("if", Token.KEYWORD1); - pyKeywords.add("import", Token.KEYWORD2); - pyKeywords.add("in", Token.KEYWORD2); - pyKeywords.add("is", Token.KEYWORD2); - pyKeywords.add("lambda", Token.KEYWORD2); - pyKeywords.add("not", Token.KEYWORD3); - pyKeywords.add("or", Token.KEYWORD3); - pyKeywords.add("pass", Token.KEYWORD2); - pyKeywords.add("print", Token.KEYWORD2); - pyKeywords.add("raise", Token.KEYWORD1); - pyKeywords.add("range", Token.KEYWORD3); - pyKeywords.add("return", Token.KEYWORD1); - pyKeywords.add("self", Token.KEYWORD2); - pyKeywords.add("try", Token.KEYWORD1); - pyKeywords.add("with", Token.KEYWORD3); - pyKeywords.add("while", Token.KEYWORD3); + pyKeywords.add("__init__", METHOD); + pyKeywords.add("and", OPERATOR); + pyKeywords.add("as", LOOP_KEYWORD); + pyKeywords.add("assert", KEYWORD); + pyKeywords.add("break", KEYWORD); + pyKeywords.add("chr", FUNCTION); + pyKeywords.add("class", FIELD); + pyKeywords.add("continue", LOOP_KEYWORD); + pyKeywords.add("def", KEYWORD); + pyKeywords.add("del", KEYWORD); + pyKeywords.add("elif", LOOP_KEYWORD); + pyKeywords.add("else", LOOP_KEYWORD); + pyKeywords.add("except", KEYWORD); + pyKeywords.add("exec", FUNCTION); + pyKeywords.add("finally", LOOP_KEYWORD); + pyKeywords.add("for", LOOP_KEYWORD); + pyKeywords.add("from", FIELD); + pyKeywords.add("global", KEYWORD); + pyKeywords.add("if", LOOP_KEYWORD); + pyKeywords.add("import", KEYWORD); + pyKeywords.add("in", LOOP_KEYWORD); + pyKeywords.add("is", OPERATOR); + pyKeywords.add("lambda", OPERATOR); + pyKeywords.add("len", FUNCTION); + pyKeywords.add("not", OPERATOR); + pyKeywords.add("or", OPERATOR); + pyKeywords.add("pass", LOOP_KEYWORD); + pyKeywords.add("print", FUNCTION); + pyKeywords.add("raise", KEYWORD); + pyKeywords.add("range", LOOP_KEYWORD); + pyKeywords.add("return", KEYWORD); + pyKeywords.add("self", FIELD); + pyKeywords.add("try", LOOP_KEYWORD); + pyKeywords.add("with", LOOP_KEYWORD); + pyKeywords.add("while", LOOP_KEYWORD); + + // These seem to be missing from Processing's token list? + pyKeywords.add("fullScreen", BUILTIN_FUNCTION); + pyKeywords.add("settings", BUILTIN_FUNCTION); + pyKeywords.add("SPAN", CONSTANT); } return pyKeywords; } diff --git a/runtime/src/jycessing/mode/SyntaxUtilities.java b/runtime/src/jycessing/mode/SyntaxUtilities.java index 3bb0597f..7e90364d 100644 --- a/runtime/src/jycessing/mode/SyntaxUtilities.java +++ b/runtime/src/jycessing/mode/SyntaxUtilities.java @@ -5,8 +5,8 @@ public class SyntaxUtilities { /** - * Checks if a subregion of a Segment is equal to a - * string. + * Checks if a subregion of a Segment is equal to a string. + * * @param text The segment * @param offset The offset into the segment * @param match The string to match @@ -26,8 +26,8 @@ public static boolean regionMatches(final Segment text, final int offset, final } /** - * Checks if a subregion of a Segment is equal to a - * character array. + * Checks if a subregion of a Segment is equal to a character array. + * * @param text The segment * @param offset The offset into the segment * @param match The character array to match @@ -45,5 +45,4 @@ public static boolean regionMatches(final Segment text, final int offset, final } return true; } - } diff --git a/runtime/src/jycessing/mode/export/Arch.java b/runtime/src/jycessing/mode/export/Arch.java index 1839a77d..122cf781 100644 --- a/runtime/src/jycessing/mode/export/Arch.java +++ b/runtime/src/jycessing/mode/export/Arch.java @@ -1,13 +1,12 @@ package jycessing.mode.export; /** - * - * The architecture of the platform we're exporting to. - * (The "bits" field is necessary because the processing Library API uses magic integers for architecture.) - * + * The architecture of the platform we're exporting to. (The "bits" field is necessary because the + * processing Library API uses magic integers for architecture.) */ public enum Arch { - X86(32), AMD64(64); + X86(32), + AMD64(64); public final int bits; diff --git a/runtime/src/jycessing/mode/export/ExportDialog.java b/runtime/src/jycessing/mode/export/ExportDialog.java index f8c07342..c92ec1aa 100644 --- a/runtime/src/jycessing/mode/export/ExportDialog.java +++ b/runtime/src/jycessing/mode/export/ExportDialog.java @@ -36,12 +36,10 @@ import processing.app.ui.ColorChooser; /** - * - * This is the export window that pops up when the user clicks [=>]. - * It tries to look as much as possible like java mode's exporter. - * Rather than passing the options they select directly to Exporter, it sets them in their user preferences, which Exporter and the various - * Export classes reference later. - * + * This is the export window that pops up when the user clicks [=>]. It tries to look as much as + * possible like java mode's exporter. Rather than passing the options they select directly to + * Exporter, it sets them in their user preferences, which Exporter and the various Export classes + * reference later. */ @SuppressWarnings("serial") public class ExportDialog extends JDialog { @@ -84,29 +82,35 @@ public ExportDialog(final PyEditor editor, final Sketch sketch) { final String[] options = {"Export", "Cancel"}; optionPane = - new JOptionPane(center, JOptionPane.PLAIN_MESSAGE, JOptionPane.YES_NO_OPTION, null, - options, options[0]); + new JOptionPane( + center, + JOptionPane.PLAIN_MESSAGE, + JOptionPane.YES_NO_OPTION, + null, + options, + options[0]); this.setContentPane(optionPane); - optionPane.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(final PropertyChangeEvent e) { - final String prop = e.getPropertyName(); - - if (isVisible() && (e.getSource() == optionPane) - && (prop.equals(JOptionPane.VALUE_PROPERTY))) { - setVisible(false); - } - } - }); + optionPane.addPropertyChangeListener( + new PropertyChangeListener() { + @Override + public void propertyChange(final PropertyChangeEvent e) { + final String prop = e.getPropertyName(); + + if (isVisible() + && (e.getSource() == optionPane) + && (prop.equals(JOptionPane.VALUE_PROPERTY))) { + setVisible(false); + } + } + }); this.pack(); this.setResizable(false); final Rectangle bounds = editor.getBounds(); final Dimension size = this.getSize(); - this.setLocation(bounds.x + (bounds.width - size.width) / 2, bounds.y - + (bounds.height - size.height) / 2); - + this.setLocation( + bounds.x + (bounds.width - size.width) / 2, bounds.y + (bounds.height - size.height) / 2); } public void go() { @@ -143,30 +147,34 @@ private JPanel createCenterPanel() { private JPanel createPlatformsPanel() { final JCheckBox windowsButton = new JCheckBox("Windows"); windowsButton.setSelected(Preferences.getBoolean("export.application.platform.windows")); - windowsButton.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(final ItemEvent e) { - Preferences.setBoolean("export.application.platform.windows", windowsButton.isSelected()); - } - }); + windowsButton.addItemListener( + new ItemListener() { + @Override + public void itemStateChanged(final ItemEvent e) { + Preferences.setBoolean( + "export.application.platform.windows", windowsButton.isSelected()); + } + }); final JCheckBox macosxButton = new JCheckBox("Mac OS X"); macosxButton.setSelected(Preferences.getBoolean("export.application.platform.macosx")); - macosxButton.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(final ItemEvent e) { - Preferences.setBoolean("export.application.platform.macosx", macosxButton.isSelected()); - } - }); + macosxButton.addItemListener( + new ItemListener() { + @Override + public void itemStateChanged(final ItemEvent e) { + Preferences.setBoolean("export.application.platform.macosx", macosxButton.isSelected()); + } + }); final JCheckBox linuxButton = new JCheckBox("Linux"); linuxButton.setSelected(Preferences.getBoolean("export.application.platform.linux")); - linuxButton.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(final ItemEvent e) { - Preferences.setBoolean("export.application.platform.linux", linuxButton.isSelected()); - } - }); + linuxButton.addItemListener( + new ItemListener() { + @Override + public void itemStateChanged(final ItemEvent e) { + Preferences.setBoolean("export.application.platform.linux", linuxButton.isSelected()); + } + }); final JPanel platformPanel = new JPanel(); platformPanel.add(windowsButton); @@ -185,25 +193,27 @@ private JPanel createPresentPanel() { final JCheckBox showStopButton = new JCheckBox("Show a Stop button"); showStopButton.setSelected(Preferences.getBoolean("export.application.stop")); - showStopButton.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(final ItemEvent e) { - Preferences.setBoolean("export.application.stop", showStopButton.isSelected()); - } - }); + showStopButton.addItemListener( + new ItemListener() { + @Override + public void itemStateChanged(final ItemEvent e) { + Preferences.setBoolean("export.application.stop", showStopButton.isSelected()); + } + }); showStopButton.setEnabled(Preferences.getBoolean("export.application.fullscreen")); showStopButton.setBorder(new EmptyBorder(3, 13, 6, 13)); final JCheckBox fullScreenButton = new JCheckBox("Full Screen (Present mode)"); fullScreenButton.setSelected(Preferences.getBoolean("export.application.fullscreen")); - fullScreenButton.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(final ItemEvent e) { - final boolean selected = fullScreenButton.isSelected(); - Preferences.setBoolean("export.application.fullscreen", selected); - showStopButton.setEnabled(selected); - } - }); + fullScreenButton.addItemListener( + new ItemListener() { + @Override + public void itemStateChanged(final ItemEvent e) { + final boolean selected = fullScreenButton.isSelected(); + Preferences.setBoolean("export.application.fullscreen", selected); + showStopButton.setEnabled(selected); + } + }); fullScreenButton.setBorder(new EmptyBorder(3, 13, 3, 13)); final Box fullScreenBox = Box.createHorizontalBox(); @@ -241,37 +251,47 @@ private JPanel createEmbedJavaPanel(final int divWidth) { final boolean embed = Preferences.getBoolean("export.application.embed_java"); final String embedWarning = - "

" + "Embedding Java will make the " - + platformName + " application " + "larger, but it will be far more likely to work. " + "
" + + "Embedding Java will make the " + + platformName + + " application " + + "larger, but it will be far more likely to work. " + "Users on other platforms will need to install Java 7."; final String nopeWarning = - "
" + "
" + "Users on all platforms will have to install the latest " - + "version of Java 7 from http://java.com/download. " + "
 "; + + "version of Java 7 from http://java.com/download. " + + "
 "; // "from java.com/download."; final JLabel warningLabel = new JLabel(embed ? embedWarning : nopeWarning); - warningLabel.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(final MouseEvent event) { - Platform.openURL("http://java.com/download"); - } - }); + warningLabel.addMouseListener( + new MouseAdapter() { + @Override + public void mousePressed(final MouseEvent event) { + Platform.openURL("http://java.com/download"); + } + }); warningLabel.setBorder(new EmptyBorder(3, 13, 3, 13)); final JCheckBox embedJavaButton = new JCheckBox("Embed Java for " + platformName); embedJavaButton.setSelected(embed); - embedJavaButton.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(final ItemEvent e) { - final boolean selected = embedJavaButton.isSelected(); - Preferences.setBoolean("export.application.embed_java", selected); - if (selected) { - warningLabel.setText(embedWarning); - } else { - warningLabel.setText(nopeWarning); - } - } - }); + embedJavaButton.addItemListener( + new ItemListener() { + @Override + public void itemStateChanged(final ItemEvent e) { + final boolean selected = embedJavaButton.isSelected(); + Preferences.setBoolean("export.application.embed_java", selected); + if (selected) { + warningLabel.setText(embedWarning); + } else { + warningLabel.setText(nopeWarning); + } + } + }); embedJavaButton.setBorder(new EmptyBorder(3, 13, 3, 13)); embedPanel.add(embedJavaButton); @@ -292,34 +312,40 @@ private JPanel createMacSigningWarning(final int divWidth) { + "which makes it more difficult to run applications like those exported from Processing. "); if (new File("/usr/bin/codesign_allocate").exists()) { - thePain - .append("This application will be \u201Cself-signed\u201D which means that Finder may report that the " + thePain.append( + "This application will be \u201Cself-signed\u201D which means that Finder may report that the " + "application is from an \u201Cunidentified developer\u201D. If the application will not " + "run, try right-clicking the app and selecting Open from the pop-up menu. Or you can visit " + "System Preferences \u2192 Security & Privacy and select Allow apps downloaded from: anywhere. "); } else { - thePain - .append("Gatekeeper requires applications to be \u201Csigned\u201D, or they will be reported as damaged. " + thePain.append( + "Gatekeeper requires applications to be \u201Csigned\u201D, or they will be reported as damaged. " + "To prevent this message, install Xcode (and the Command Line Tools) from the App Store, or visit " + "System Preferences \u2192 Security & Privacy and select Allow apps downloaded from: anywhere. "); } - thePain.append("To avoid the messages entirely, manually code sign your app. " - + "For more information: https://developer.apple.com/developer-id/"); + thePain.append( + "To avoid the messages entirely, manually code sign your app. " + + "For more information: https://developer.apple.com/developer-id/"); final JLabel area = - new JLabel("
" + thePain.toString() - + "
"); + new JLabel( + "
" + + thePain.toString() + + "
"); area.setBorder(new EmptyBorder(3, 13, 3, 13)); signPanel.add(area); signPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - area.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(final MouseEvent event) { - Platform.openURL("https://developer.apple.com/developer-id/"); - } - }); + area.addMouseListener( + new MouseAdapter() { + @Override + public void mousePressed(final MouseEvent event) { + Platform.openURL("https://developer.apple.com/developer-id/"); + } + }); return signPanel; } @@ -334,14 +360,15 @@ public ColorPreference(final String pref, final PyEditor editor) { setPreferredSize(new Dimension(30, 20)); setMaximumSize(new Dimension(30, 20)); - addMouseListener(new MouseAdapter() { - @Override - public void mouseReleased(final MouseEvent e) { - final Color color = Preferences.getColor(prefName); - chooser = new ColorChooser(editor, true, color, "Select", ColorPreference.this); - chooser.show(); - } - }); + addMouseListener( + new MouseAdapter() { + @Override + public void mouseReleased(final MouseEvent e) { + final Color color = Preferences.getColor(prefName); + chooser = new ColorChooser(editor, true, color, "Select", ColorPreference.this); + chooser.show(); + } + }); } @Override diff --git a/runtime/src/jycessing/mode/export/ExportedSketch.java b/runtime/src/jycessing/mode/export/ExportedSketch.java index c3eea0e2..5b3fc216 100644 --- a/runtime/src/jycessing/mode/export/ExportedSketch.java +++ b/runtime/src/jycessing/mode/export/ExportedSketch.java @@ -14,11 +14,11 @@ import processing.core.PApplet; /** - * A sketch that's been exported from the PDE. - * Runner.main() will create one of these if ARGS_EXPORTED is in argv. - * - * This class tries to make sure that the exported sketch is in the right configuration - if it isn't, - * it will warn the user and fail. + * A sketch that's been exported from the PDE. Runner.main() will create one of these if + * ARGS_EXPORTED is in argv. + * + *

This class tries to make sure that the exported sketch is in the right configuration - if it + * isn't, it will warn the user and fail. */ public class ExportedSketch implements RunnableSketch { @@ -55,7 +55,7 @@ public ExportedSketch(final String[] args) throws Exception { } this.code = code.toString(); - if (Arrays.asList(args).contains("fullScreen")) { + if (Arrays.asList(args).contains(PApplet.ARGS_PRESENT)) { this.displayType = DisplayType.PRESENTATION; } else { this.displayType = DisplayType.WINDOWED; @@ -64,7 +64,7 @@ public ExportedSketch(final String[] args) throws Exception { String backgroundColor = null; String stopColor = null; for (final String arg : args) { - if (arg.contains("BGCOLOR")) { + if (arg.contains(PApplet.ARGS_WINDOW_COLOR)) { backgroundColor = arg.substring(arg.indexOf("=") + 1); } else if (arg.contains(PApplet.ARGS_STOP_COLOR)) { stopColor = arg.substring(arg.indexOf("=") + 1); @@ -106,8 +106,8 @@ public String[] getPAppletArguments() { final List args = new ArrayList<>(); if (displayType == DisplayType.PRESENTATION) { - args.add("fullScreen"); - args.add("BGCOLOR" + "=" + backgroundColor); + args.add(PApplet.ARGS_PRESENT); + args.add(PApplet.ARGS_WINDOW_COLOR + "=" + backgroundColor); if (stopColor != null) { args.add(PApplet.ARGS_STOP_COLOR + "=" + stopColor); @@ -148,5 +148,4 @@ public List getPathEntries() { return entries; } - } diff --git a/runtime/src/jycessing/mode/export/Exporter.java b/runtime/src/jycessing/mode/export/Exporter.java index ba3cf4e0..b4386b36 100644 --- a/runtime/src/jycessing/mode/export/Exporter.java +++ b/runtime/src/jycessing/mode/export/Exporter.java @@ -10,12 +10,9 @@ import processing.app.Preferences; import processing.app.Sketch; - /** - * - * Class that handles doing the actual exporting. - * All this currently does is figure out libraries and then hand off to each platform export. - * + * Class that handles doing the actual exporting. All this currently does is figure out libraries + * and then hand off to each platform export. */ public class Exporter { @@ -29,6 +26,7 @@ private static void log(final String msg) { // Architecture of the currently running Processing JRE. // Used to determine what platform we can embed java in. public static final Arch processingArch; + static { if (Platform.getNativeBits() == Arch.X86.bits) { processingArch = Arch.X86; @@ -39,7 +37,7 @@ private static void log(final String msg) { private final Sketch sketch; private final PyEditor editor; // I don't really want to pass this around but there's some - // functionality + // functionality // I need diff --git a/runtime/src/jycessing/mode/export/ImportExtractor.java b/runtime/src/jycessing/mode/export/ImportExtractor.java index e2702281..0f3281ff 100644 --- a/runtime/src/jycessing/mode/export/ImportExtractor.java +++ b/runtime/src/jycessing/mode/export/ImportExtractor.java @@ -5,14 +5,13 @@ import java.util.HashSet; import java.util.Set; -import jycessing.mode.PythonMode; - import org.python.antlr.ast.Call; import org.python.antlr.ast.Str; import org.python.antlr.base.mod; import org.python.core.CompilerFlags; import org.python.core.ParserFacade; +import jycessing.mode.PythonMode; import processing.app.Base; import processing.app.Library; import processing.app.Messages; @@ -21,13 +20,12 @@ import processing.app.SketchCode; /** - * Parses pyde source files using jython's ANTLR parser, goes through all - * function calls with a Visitor, finds all calls to add_library, and finds - * the libraries that are being imported. This WON'T WORK if add_library - * is reassigned or passed not-a-string. We currently only warn the user + * Parses pyde source files using jython's ANTLR parser, goes through all function calls with a + * Visitor, finds all calls to add_library, and finds the libraries that are being imported. This + * WON'T WORK if add_library is reassigned or passed not-a-string. We currently only warn the user * if they don't pass a string. - * - * TODO More stringent warnings. + * + *

TODO More stringent warnings. */ public class ImportExtractor { @SuppressWarnings("unused") @@ -37,8 +35,10 @@ private static void log(final String msg) { } } - private final static File[] libLocations = new File[] { - Platform.getContentFile("modes/java/libraries"), Base.getSketchbookLibrariesFolder()}; + private static final File[] libLocations = + new File[] { + Platform.getContentFile("modes/java/libraries"), Base.getSketchbookLibrariesFolder() + }; private final Sketch sketch; private final Set libraries; @@ -60,8 +60,8 @@ private void extract() { final mod ast; try { ast = - ParserFacade.parseExpressionOrModule(new StringReader(code.getProgram()), - code.getFileName(), new CompilerFlags()); + ParserFacade.parseExpressionOrModule( + new StringReader(code.getProgram()), code.getFileName(), new CompilerFlags()); } catch (final Exception e) { System.err.println("Couldn't parse " + code.getFileName()); // I don't like this but I'm not sure what else to do @@ -77,7 +77,8 @@ private void extract() { } } if (visitor.failure) { - Messages.showWarning("Library Problems", + Messages.showWarning( + "Library Problems", "I can't figure out all of the java libraries you're using. " + "Your exported sketch might not work."); } @@ -104,7 +105,6 @@ private void extract() { } } - private static class ImportVisitor extends org.python.antlr.Visitor { public final Set importNames; public boolean failure; @@ -123,8 +123,8 @@ public Object visitCall(final Call funcall) throws Exception { importNames.add(lib); log("Found library: " + lib); } else { - System.err - .println("I can't figure out what libraries you're using if you don't pass a string to add_library.\n" + System.err.println( + "I can't figure out what libraries you're using if you don't pass a string to add_library.\n" + "Please replace " + funcall.getInternalArgs().get(0).getToken().getText() + " with the name of the library you're importing."); @@ -134,5 +134,4 @@ public Object visitCall(final Call funcall) throws Exception { return super.visitCall(funcall); } } - } diff --git a/runtime/src/jycessing/mode/export/LinuxExport.java b/runtime/src/jycessing/mode/export/LinuxExport.java index 18195ca5..0450f273 100644 --- a/runtime/src/jycessing/mode/export/LinuxExport.java +++ b/runtime/src/jycessing/mode/export/LinuxExport.java @@ -20,26 +20,15 @@ import processing.core.PApplet; import processing.core.PConstants; - - /** - * - * Performs an export to Linux (32/64). - * The linux export folder layout is as follows: - * - * $appdir/ (e.g. $sketchname/application.linux32) - * /$sketchname (executable shell script to run the application) - * /source/ (the source code of the sketch; used to run it) - * /lib/ (where java imports are stored) - * /jycessing/ (where stuff necessary to jycessing is stored; - * everything in here is added to the classpath.) - * /$libname/library/ (where resources for $libname - imported with - * add_library - are stored. Not added to classpath.) - * /code/ (any other code resources the user wanted to add; - * copied verbatim.) - * /data/ (all non-code resources; copied verbatim.) - * + * Performs an export to Linux (32/64). The linux export folder layout is as follows: * + *

$appdir/ (e.g. $sketchname/application.linux32) /$sketchname (executable shell script to run + * the application) /source/ (the source code of the sketch; used to run it) /lib/ (where java + * imports are stored) /jycessing/ (where stuff necessary to jycessing is stored; everything in here + * is added to the classpath.) /$libname/library/ (where resources for $libname - imported with + * add_library - are stored. Not added to classpath.) /code/ (any other code resources the user + * wanted to add; copied verbatim.) /data/ (all non-code resources; copied verbatim.) */ public class LinuxExport extends PlatformExport { @@ -52,8 +41,8 @@ protected void log(final String msg) { } } - public LinuxExport(final Arch arch, final Sketch sketch, final PyEditor editor, - final Set libraries) { + public LinuxExport( + final Arch arch, final Sketch sketch, final PyEditor editor, final Set libraries) { this.id = PConstants.LINUX; this.arch = arch; this.name = PConstants.platformNames[id] + arch.bits; @@ -66,7 +55,8 @@ public LinuxExport(final Arch arch, final Sketch sketch, final PyEditor editor, public void export() throws IOException { // Work out user preferences and other possibilities we care about final boolean embedJava = - (id == PApplet.platform) && Preferences.getBoolean("export.application.embed_java") + (id == PApplet.platform) + && Preferences.getBoolean("export.application.embed_java") && arch == Exporter.processingArch; // Work out the folders we'll be (maybe) using @@ -90,7 +80,6 @@ public void export() throws IOException { private void buildShellScript(final File destFolder, final boolean embedJava) throws IOException { log("Creating shell script."); - final boolean setMemory = Preferences.getBoolean("run.options.memory"); final boolean presentMode = Preferences.getBoolean("export.application.fullscreen"); final boolean stopButton = Preferences.getBoolean("export.application.stop") && presentMode; @@ -131,7 +120,8 @@ private void buildShellScript(final File destFolder, final boolean embedJava) th // Work out classpath - only add core stuff, the rest will be found by add_library final StringWriter classpath = new StringWriter(); for (final File f : jycessingFolder.listFiles()) { - if (f.getName().toLowerCase().endsWith(".jar") || f.getName().toLowerCase().endsWith(".zip")) { + if (f.getName().toLowerCase().endsWith(".jar") + || f.getName().toLowerCase().endsWith(".zip")) { classpath.append("$APPDIR/lib/jycessing/" + f.getName() + ":"); } } @@ -153,9 +143,9 @@ private void buildShellScript(final File destFolder, final boolean embedJava) th options.add("--exported"); if (presentMode) { - options.add("fullScreen"); + options.add(PApplet.ARGS_PRESENT); - options.add("BGCOLOR" + "=" + Preferences.get("run.present.bgcolor")); + options.add(PApplet.ARGS_WINDOW_COLOR + "=" + Preferences.get("run.present.bgcolor")); } if (stopButton) { @@ -175,8 +165,8 @@ private void buildShellScript(final File destFolder, final boolean embedJava) th log("Setting script executable."); try { - Files.setPosixFilePermissions(scriptFile.toPath(), - PosixFilePermissions.fromString("rwxrwxrwx")); + Files.setPosixFilePermissions( + scriptFile.toPath(), PosixFilePermissions.fromString("rwxrwxrwx")); } catch (final UnsupportedOperationException e) { // Windows, probably log("Couldn't set script executable... we'll assume whoever gets it can handle it"); diff --git a/runtime/src/jycessing/mode/export/MacExport.java b/runtime/src/jycessing/mode/export/MacExport.java index 437969ed..948370e0 100644 --- a/runtime/src/jycessing/mode/export/MacExport.java +++ b/runtime/src/jycessing/mode/export/MacExport.java @@ -25,36 +25,21 @@ import processing.core.PApplet; import processing.core.PConstants; - /** - * * A Mac export. - * - * If we embed java, we embed Processing's java, since we know it's been properly appbundled - * and all symlinks work and stuff. - * - * N.B. We use bash for the executable, so that we can easily include a pile of command line arguments, - * as well as being able to prompt the user to install Java. * - * Inspired by: https://github.com/tofi86/universalJavaApplicationStub - * - * Layout: - * $appdir/ - * /$sketch.app/Contents/ - * /MacOS/ - * /$sketch (shell script that cd's to ../Processing and runs the sketch) - * /Info.plist - * /Resources/ - * /sketch.icns (pretty icon) - * /dialogs.applescript (used by main script to show native prompts) - * /Processing/ - * /source/ - * /lib/ - * /code/ - * /data/ - * /PlugIns/jdk$version.jdk/ (copied from core processing) - * + *

If we embed java, we embed Processing's java, since we know it's been properly appbundled and + * all symlinks work and stuff. + * + *

N.B. We use bash for the executable, so that we can easily include a pile of command line + * arguments, as well as being able to prompt the user to install Java. + * + *

Inspired by: https://github.com/tofi86/universalJavaApplicationStub * + *

Layout: $appdir/ /$sketch.app/Contents/ /MacOS/ /$sketch (shell script that cd's to + * ../Processing and runs the sketch) /Info.plist /Resources/ /sketch.icns (pretty icon) + * /dialogs.applescript (used by main script to show native prompts) /Processing/ /source/ /lib/ + * /code/ /data/ /PlugIns/jdk$version.jdk/ (copied from core processing) */ public class MacExport extends PlatformExport { @@ -105,17 +90,21 @@ public void export() throws IOException { /** * Copy Processing's builtin JDK to the export. - * - * (This only makes sense when we're on a Mac, running Processing from a .app bundle.) + * + *

(This only makes sense when we're on a Mac, running Processing from a .app bundle.) */ private void copyJDKPlugin(final File targetPluginsFolder) throws IOException { // This is how Java Mode finds it... basically - final File sourceJDKFolder = Platform.getContentFile("../PlugIns").listFiles(new FilenameFilter() { - @Override - public boolean accept(final File dir, final String name) { - return name.endsWith(".jdk") && !name.startsWith("."); - } - })[0].getAbsoluteFile(); + final File sourceJDKFolder = + Platform.getContentFile("../PlugIns") + .listFiles( + new FilenameFilter() { + @Override + public boolean accept(final File dir, final String name) { + return name.endsWith(".jdk") && !name.startsWith("."); + } + })[0] + .getAbsoluteFile(); log("Copying JDK from " + sourceJDKFolder); @@ -124,12 +113,9 @@ public boolean accept(final File dir, final String name) { Util.copyDirNative(sourceJDKFolder, targetJDKFolder); } + private static final Pattern sketchPattern = Pattern.compile("@@sketch@@"); - private final static Pattern sketchPattern = Pattern.compile("@@sketch@@"); - - /** - * Read in Info.plist.tmpl, modify fields, package away in .app - */ + /** Read in Info.plist.tmpl, modify fields, package away in .app */ private void setUpInfoPlist(final File targetInfoPlist, final String sketchName) throws IOException { log("Setting up Info.plist."); @@ -139,29 +125,36 @@ private void setUpInfoPlist(final File targetInfoPlist, final String sketchName) editor.getModeContentFile("application/macosx/Info.plist.tmpl").toPath(); final String infoPlistTemplateText = new String(Files.readAllBytes(infoPlistTemplate), "UTF-8"); final Matcher sketchNameMatcher = sketchPattern.matcher(infoPlistTemplateText); - Files.write(targetInfoPlist.toPath(), sketchNameMatcher.replaceAll(sketchName).getBytes(), - StandardOpenOption.WRITE, StandardOpenOption.CREATE); + Files.write( + targetInfoPlist.toPath(), + sketchNameMatcher.replaceAll(sketchName).getBytes(), + StandardOpenOption.WRITE, + StandardOpenOption.CREATE); } - /** - * Copy things that don't change between runs. - */ + /** Copy things that don't change between runs. */ private void copyStaticResources(final File resourcesFolder) throws IOException { log("Moving static macosx resources."); final File osxFolder = editor.getModeContentFile("application/macosx"); resourcesFolder.mkdirs(); Util.copyFile(new File(osxFolder, "sketch.icns"), new File(resourcesFolder, "sketch.icns")); - Util.copyFile(new File(osxFolder, "dialogs.applescript"), new File(resourcesFolder, - "dialogs.applescript")); + Util.copyFile( + new File(osxFolder, "dialogs.applescript"), + new File(resourcesFolder, "dialogs.applescript")); } /** * Create the shell script that will run the sketch. - * - * Some duplicated code here from LinuxExport, but there's enough differences that I want to keep them separate + * + *

Some duplicated code here from LinuxExport, but there's enough differences that I want to + * keep them separate */ - private void setUpExecutable(final File binFolder, final File processingFolder, - final String sketchName, final boolean embedJava) throws IOException { + private void setUpExecutable( + final File binFolder, + final File processingFolder, + final String sketchName, + final boolean embedJava) + throws IOException { log("Creating shell script."); @@ -174,7 +167,6 @@ private void setUpExecutable(final File binFolder, final File processingFolder, final File scriptFile = new File(binFolder, sketch.getName()); final PrintWriter script = new PrintWriter(scriptFile); - // We explicitly use "\n" because PrintWriter.println() uses the system line ending, // which will confuse Macs if we're running from Windows. script.print("#!/bin/bash\n"); @@ -188,8 +180,8 @@ private void setUpExecutable(final File binFolder, final File processingFolder, new String(Files.readAllBytes(findJavaScript), "UTF-8").replaceAll("\\r\\n?", "\n"); script.print(findJava + "\n"); } else { - script - .print("JAVA=\"$(find $CONTENTS/PlugIns -maxdepth 1 -type d -name '*jdk')/Contents/Home/jre/bin/java\"" + script.print( + "JAVA=\"$(find $CONTENTS/PlugIns -maxdepth 1 -type d -name '*jdk')/Contents/Home/jre/bin/java\"" + "\n"); } @@ -215,7 +207,8 @@ private void setUpExecutable(final File binFolder, final File processingFolder, // Work out classpath - only add core stuff, the rest will be found by add_library final StringWriter classpath = new StringWriter(); for (final File f : new File(processingFolder, "lib/jycessing").listFiles()) { - if (f.getName().toLowerCase().endsWith(".jar") || f.getName().toLowerCase().endsWith(".zip")) { + if (f.getName().toLowerCase().endsWith(".jar") + || f.getName().toLowerCase().endsWith(".zip")) { classpath.append("$APPDIR/lib/jycessing/" + f.getName() + ":"); } } @@ -248,9 +241,9 @@ private void setUpExecutable(final File binFolder, final File processingFolder, options.add("--exported"); if (presentMode) { - options.add("fullScreen"); + options.add(PApplet.ARGS_PRESENT); - options.add("BGCOLOR" + "=" + Preferences.get("run.present.bgcolor")); + options.add(PApplet.ARGS_WINDOW_COLOR + "=" + Preferences.get("run.present.bgcolor")); } if (stopButton) { @@ -270,8 +263,8 @@ private void setUpExecutable(final File binFolder, final File processingFolder, log("Setting script executable."); try { - Files.setPosixFilePermissions(scriptFile.toPath(), - PosixFilePermissions.fromString("rwxrwxrwx")); + Files.setPosixFilePermissions( + scriptFile.toPath(), PosixFilePermissions.fromString("rwxrwxrwx")); } catch (final UnsupportedOperationException e) { // Windows, probably log("Couldn't set script executable... .app should work anyway, though"); diff --git a/runtime/src/jycessing/mode/export/PlatformExport.java b/runtime/src/jycessing/mode/export/PlatformExport.java index 8440197d..036dd17b 100644 --- a/runtime/src/jycessing/mode/export/PlatformExport.java +++ b/runtime/src/jycessing/mode/export/PlatformExport.java @@ -12,11 +12,7 @@ import processing.app.SketchCode; import processing.app.Util; -/** - * - * Subclass this to add more platforms, if we ever want to add freebsd or haiku or something - * - */ +/** Subclass this to add more platforms, if we ever want to add freebsd or haiku or something */ public abstract class PlatformExport { protected int id; protected String name; @@ -25,17 +21,12 @@ public abstract class PlatformExport { protected Set libraries; protected Arch arch; - /** - * Instance so that subclasses can override it. - */ + /** Instance so that subclasses can override it. */ protected abstract void log(final String msg); public abstract void export() throws IOException; - /** - * This is the same between platforms. - * - */ + /** This is the same between platforms. */ public void copyBasicStructure(final File destFolder) throws IOException { final boolean hasData = sketch.hasDataFolder(); final boolean hasCode = sketch.hasCodeFolder(); @@ -85,12 +76,17 @@ public void copyBasicStructure(final File destFolder) throws IOException { final File libraryExportFolder = new File(libFolder, library.getFolder().getName() + "/library/"); libraryExportFolder.mkdirs(); - for (final File exportFile : library.getApplicationExports(id, Integer.toString(arch.bits))) { + for (final File exportFile : + library.getApplicationExports(id, Integer.toString(arch.bits))) { log("Exporting: " + exportFile); final String exportName = exportFile.getName(); if (!exportFile.exists()) { - System.err.println("The file " + exportName + " is mentioned in the export.txt from " - + library + " but does not actually exist. Moving on."); + System.err.println( + "The file " + + exportName + + " is mentioned in the export.txt from " + + library + + " but does not actually exist. Moving on."); continue; } if (exportFile.isDirectory()) { @@ -106,8 +102,9 @@ public void copyBasicStructure(final File destFolder) throws IOException { { jycessingFolder.mkdirs(); log("Copying core processing stuff to export"); - for (final File exportFile : new Library(Platform.getContentFile("core")).getApplicationExports( - id, Integer.toString(arch.bits))) { + for (final File exportFile : + new Library(Platform.getContentFile("core")) + .getApplicationExports(id, Integer.toString(arch.bits))) { if (exportFile.isDirectory()) { Util.copyDir(exportFile, new File(jycessingFolder, exportFile.getName())); } else { diff --git a/runtime/src/jycessing/mode/export/WindowsExport.java b/runtime/src/jycessing/mode/export/WindowsExport.java index 684c9ea0..5aa2fd96 100644 --- a/runtime/src/jycessing/mode/export/WindowsExport.java +++ b/runtime/src/jycessing/mode/export/WindowsExport.java @@ -21,30 +21,22 @@ import processing.data.XML; /** - * * Perform an export to Windows, using launch4j to generate the Windows executable. - * - * N.B. We use relative paths for everything. This is not laziness, this solves problems: - * - It allows us to specify the location of the sketch consistently - * - It prevents parent directories with special characters from confusing java / JOGL (which loads libs dynamically) - * - It is guaranteed to work, since we specify working directory with - * - * N.B. We don't use launch4j's splash screen functionality because it apparently only works with a very specific breed of 24-bit BMPs. - * Java's works just as well. - * - * Structure: - * $appdir/ (e.g. $sketchname/application.windows32) - * /$sketchname.exe (executable shell script to run the application) - * /source/ (the source code of the sketch; used to run it) - * /lib/ (where java imports are stored) - * /jycessing/ (where stuff necessary to jycessing is stored; - * everything in here is added to the classpath.) - * /$libname/library/ (where resources for $libname - imported with - * add_library - are stored. Not added to classpath.) - * /code/ (any other code resources the user wanted to add; - * copied verbatim.) - * /data/ (all non-code resources; copied verbatim.) * + *

N.B. We use relative paths for everything. This is not laziness, this solves problems: - It + * allows us to specify the location of the sketch consistently - It prevents parent directories + * with special characters from confusing java / JOGL (which loads libs dynamically) - It is + * guaranteed to work, since we specify working directory with + * + *

N.B. We don't use launch4j's splash screen functionality because it apparently only works with + * a very specific breed of 24-bit BMPs. Java's works just as well. + * + *

Structure: $appdir/ (e.g. $sketchname/application.windows32) /$sketchname.exe (executable + * shell script to run the application) /source/ (the source code of the sketch; used to run it) + * /lib/ (where java imports are stored) /jycessing/ (where stuff necessary to jycessing is stored; + * everything in here is added to the classpath.) /$libname/library/ (where resources for $libname - + * imported with add_library - are stored. Not added to classpath.) /code/ (any other code resources + * the user wanted to add; copied verbatim.) /data/ (all non-code resources; copied verbatim.) */ public class WindowsExport extends PlatformExport { @@ -55,8 +47,8 @@ protected void log(final String msg) { } } - public WindowsExport(final Arch arch, final Sketch sketch, final PyEditor editor, - final Set libraries) { + public WindowsExport( + final Arch arch, final Sketch sketch, final PyEditor editor, final Set libraries) { this.id = PConstants.WINDOWS; this.arch = arch; this.name = PConstants.platformNames[id] + arch.bits; @@ -68,7 +60,8 @@ public WindowsExport(final Arch arch, final Sketch sketch, final PyEditor editor @Override public void export() throws IOException { final boolean embedJava = - (id == PApplet.platform) && Preferences.getBoolean("export.application.embed_java") + (id == PApplet.platform) + && Preferences.getBoolean("export.application.embed_java") && arch == Exporter.processingArch; final File destFolder = new File(sketch.getFolder(), "application." + name); @@ -94,8 +87,8 @@ public void export() throws IOException { } /** - * Construct a Processing XML object containing the configuration for launch4j. - * Config file docs: http://launch4j.sourceforge.net/docs.html + * Construct a Processing XML object containing the configuration for launch4j. Config file docs: + * http://launch4j.sourceforge.net/docs.html */ private XML buildLaunch4jConfig(final File destFolder, final boolean embedJava) { log("Building launch4j configuration."); @@ -109,8 +102,9 @@ private XML buildLaunch4jConfig(final File destFolder, final boolean embedJava) final XML config = new XML("launch4jConfig"); config.addChild("headerType").setContent("gui"); // Not a console application - config.addChild("outfile").setContent( - new File(destFolder, sketchName + ".exe").getAbsolutePath()); + config + .addChild("outfile") + .setContent(new File(destFolder, sketchName + ".exe").getAbsolutePath()); config.addChild("dontWrapJar").setContent("true"); // We just want a launcher config.addChild("errTitle").setContent("Sketchy Behavior"); config.addChild("icon").setContent(iconFile.getAbsolutePath()); @@ -123,9 +117,7 @@ private XML buildLaunch4jConfig(final File destFolder, final boolean embedJava) return config; } - /** - * Run launch4j on a given configuration file - */ + /** Run launch4j on a given configuration file */ private void runLaunch4j(final File configFile) throws IOException { log("Running launch4j."); @@ -150,9 +142,14 @@ private void runLaunch4j(final File configFile) throws IOException { final File xstreamJar = new File(launch4jFolder, "lib/xstream.jar"); final ProcessBuilder pb = - new ProcessBuilder(javaExecutable.getAbsolutePath(), "-cp", launch4jJar.getAbsolutePath() - + System.getProperty("path.separator") + xstreamJar.getAbsolutePath(), - "net.sf.launch4j.Main", configFile.getAbsolutePath()); + new ProcessBuilder( + javaExecutable.getAbsolutePath(), + "-cp", + launch4jJar.getAbsolutePath() + + System.getProperty("path.separator") + + xstreamJar.getAbsolutePath(), + "net.sf.launch4j.Main", + configFile.getAbsolutePath()); if (PythonMode.VERBOSE) { log("Launch4j command:"); @@ -164,20 +161,20 @@ private void runLaunch4j(final File configFile) throws IOException { final Process launch4jProcess = pb.start(); if (PythonMode.VERBOSE) { - final Thread captureOutput = new Thread(new Runnable() { - @Override - public void run() { - final BufferedReader stderr = - new BufferedReader(new InputStreamReader(launch4jProcess.getInputStream())); - String line; - try { - while ((line = stderr.readLine()) != null) { - log(line); - } - } catch (final Exception e) { - } - } - }); + final Thread captureOutput = + new Thread( + () -> { + final BufferedReader stderr = + new BufferedReader(new InputStreamReader(launch4jProcess.getInputStream())); + String line; + try { + while ((line = stderr.readLine()) != null) { + log(line); + } + stderr.close(); + } catch (final Exception e) { + } + }); captureOutput.start(); } @@ -197,7 +194,7 @@ private XML buildJREOptions(final boolean embedJava, final boolean setMemory, fi if (embedJava) { // note that "Path" is relative to the output executable at runtime jre.addChild("path").setContent("\"%EXEDIR%\\java\""); // "java" folder is next to the - // executable? + // executable? // TODO check } // We always add the minVersion tag, which means that the sketch will always try to look for @@ -240,8 +237,8 @@ private XML buildRunnerOptions(final boolean presentMode, final boolean stopButt // Options to pass to Runner final List runnerOptions = new ArrayList<>(); if (presentMode) { - runnerOptions.add("fullScreen"); - runnerOptions.add("BGCOLOR" + "=" + Preferences.get("run.present.bgcolor")); + runnerOptions.add(PApplet.ARGS_PRESENT); + runnerOptions.add(PApplet.ARGS_WINDOW_COLOR + "=" + Preferences.get("run.present.bgcolor")); } if (stopButton) { runnerOptions.add(PApplet.ARGS_STOP_COLOR + "=" + Preferences.get("run.present.stop.color")); @@ -268,7 +265,8 @@ private XML buildClassPathOptions(final File jycessingFolder) { final XML classPathOptions = new XML("classPath"); classPathOptions.addChild("mainClass").setContent("jycessing.Runner"); for (final File f : jycessingFolder.listFiles()) { - if (f.getName().toLowerCase().endsWith(".jar") || f.getName().toLowerCase().endsWith(".zip")) { + if (f.getName().toLowerCase().endsWith(".jar") + || f.getName().toLowerCase().endsWith(".zip")) { // Don't need to quote classpath entries, launch4j at least handles that for us classPathOptions.addChild("cp").setContent("./lib/jycessing/" + f.getName()); } diff --git a/runtime/src/jycessing/mode/run/OSXAdapter.java b/runtime/src/jycessing/mode/run/OSXAdapter.java index 90ba3679..fd84d349 100644 --- a/runtime/src/jycessing/mode/run/OSXAdapter.java +++ b/runtime/src/jycessing/mode/run/OSXAdapter.java @@ -6,16 +6,16 @@ Abstract: Hooks existing preferences/about/quit functionality from an existing Java app into handlers for the Mac OS X application menu. - Uses a Proxy object to dynamically implement the + Uses a Proxy object to dynamically implement the com.apple.eawt.ApplicationListener interface and register it with the com.apple.eawt.Application object. This allows the complete project - to be both built and run on any platform without any stubs or - placeholders. Useful for developers looking to implement Mac OS X + to be both built and run on any platform without any stubs or + placeholders. Useful for developers looking to implement Mac OS X features while supporting multiple platforms with minimal impact. - + Version: 2.0 -Disclaimer: IMPORTANT: This Apple software is supplied to you by +Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these @@ -29,8 +29,8 @@ Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following -text and disclaimers in all such redistributions of the Apple Software. -Neither the name, trademarks, service marks or logos of Apple Inc. +text and disclaimers in all such redistributions of the Apple Software. +Neither the name, trademarks, service marks or logos of Apple Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express @@ -62,7 +62,6 @@ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), import java.lang.reflect.Method; import java.lang.reflect.Proxy; - public class OSXAdapter implements InvocationHandler { protected Object targetObject; @@ -88,8 +87,9 @@ public static void setAboutHandler(final Object target, final Method aboutHandle // com.apple.eawt.Application reflectively try { final Method enableAboutMethod = - macOSXApplication.getClass().getDeclaredMethod("setEnabledAboutMenu", - new Class[] {boolean.class}); + macOSXApplication + .getClass() + .getDeclaredMethod("setEnabledAboutMenu", new Class[] {boolean.class}); enableAboutMethod.invoke(macOSXApplication, new Object[] {Boolean.valueOf(enableAboutMenu)}); } catch (final Exception ex) { System.err.println("OSXAdapter could not access the About Menu"); @@ -108,8 +108,9 @@ public static void setPreferencesHandler(final Object target, final Method prefs // com.apple.eawt.Application reflectively try { final Method enablePrefsMethod = - macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", - new Class[] {boolean.class}); + macOSXApplication + .getClass() + .getDeclaredMethod("setEnabledPreferencesMenu", new Class[] {boolean.class}); enablePrefsMethod.invoke(macOSXApplication, new Object[] {Boolean.valueOf(enablePrefsMenu)}); } catch (final Exception ex) { System.err.println("OSXAdapter could not access the About Menu: " + ex); @@ -120,24 +121,26 @@ public static void setPreferencesHandler(final Object target, final Method prefs // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the // application bundle's Info.plist public static void setFileHandler(final Object target, final Method fileHandler) { - setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) { - // Override OSXAdapter.callTarget to send information on the - // file to be opened - @Override - public boolean callTarget(final Object appleEvent) { - if (appleEvent != null) { - try { - final Method getFilenameMethod = - appleEvent.getClass().getDeclaredMethod("getFilename", (Class[])null); - final String filename = (String)getFilenameMethod.invoke(appleEvent, (Object[])null); - this.targetMethod.invoke(this.targetObject, new Object[] {filename}); - } catch (final Exception ex) { - + setHandler( + new OSXAdapter("handleOpenFile", target, fileHandler) { + // Override OSXAdapter.callTarget to send information on the + // file to be opened + @Override + public boolean callTarget(final Object appleEvent) { + if (appleEvent != null) { + try { + final Method getFilenameMethod = + appleEvent.getClass().getDeclaredMethod("getFilename", (Class[]) null); + final String filename = + (String) getFilenameMethod.invoke(appleEvent, (Object[]) null); + this.targetMethod.invoke(this.targetObject, new Object[] {filename}); + } catch (final Exception ex) { + + } + } + return true; } - } - return true; - } - }); + }); } // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an @@ -147,22 +150,23 @@ public static void setHandler(final OSXAdapter adapter) { final Class applicationClass = Class.forName("com.apple.eawt.Application"); if (macOSXApplication == null) { macOSXApplication = - applicationClass.getConstructor((Class[])null).newInstance((Object[])null); + applicationClass.getConstructor((Class[]) null).newInstance((Object[]) null); } final Class applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener"); final Method addListenerMethod = - applicationClass.getDeclaredMethod("addApplicationListener", - new Class[] {applicationListenerClass}); + applicationClass.getDeclaredMethod( + "addApplicationListener", new Class[] {applicationListenerClass}); // Create a proxy object around this handler that can be reflectively added as an Apple // ApplicationListener final Object osxAdapterProxy = - Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(), - new Class[] {applicationListenerClass}, adapter); + Proxy.newProxyInstance( + OSXAdapter.class.getClassLoader(), new Class[] {applicationListenerClass}, adapter); addListenerMethod.invoke(macOSXApplication, new Object[] {osxAdapterProxy}); } catch (final ClassNotFoundException cnfe) { - System.err - .println("This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled (" - + cnfe + ")"); + System.err.println( + "This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled (" + + cnfe + + ")"); } catch (final Exception ex) { // Likely a NoSuchMethodException or an IllegalAccessException // loading/invoking eawt.Application methods System.err.println("Mac OS X Adapter could not talk to EAWT:" + ex); @@ -181,9 +185,9 @@ protected OSXAdapter(final String proxySignature, final Object target, final Met // Override this method to perform any operations on the event // that comes with the various callbacks // See setFileHandler above for an example - public boolean callTarget(final Object appleEvent) throws InvocationTargetException, - IllegalAccessException { - final Object result = targetMethod.invoke(targetObject, (Object[])null); + public boolean callTarget(final Object appleEvent) + throws InvocationTargetException, IllegalAccessException { + final Object result = targetMethod.invoke(targetObject, (Object[]) null); if (result == null) { return true; } diff --git a/runtime/src/jycessing/mode/run/PdeSketch.java b/runtime/src/jycessing/mode/run/PdeSketch.java index 7e2da531..7bfd808f 100644 --- a/runtime/src/jycessing/mode/run/PdeSketch.java +++ b/runtime/src/jycessing/mode/run/PdeSketch.java @@ -4,11 +4,13 @@ import java.io.File; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import jycessing.DisplayType; import jycessing.RunnableSketch; import jycessing.Runner.LibraryPolicy; +import jycessing.mode.PythonMode; import processing.app.Base; import processing.app.Platform; import processing.app.Sketch; @@ -17,37 +19,47 @@ /** * A sketch run from the PDE. * - * This is created in the PDE process, serialized, and then used in the sketch process. + *

This is created in the PDE process, serialized, and then used in the sketch process. */ - @SuppressWarnings("serial") public class PdeSketch implements RunnableSketch, Serializable { private final List libraryDirs; + private final List pythonLibraryDirs; private final File mainFile; private final String mainCode; private final File sketchHome; + private final File realSketchPath; private final Point location; private final LocationType locationType; private final DisplayType displayType; + private final String bgColor; + private final String stopColor; public final String[] codeFileNames; // unique to PdeSketch - leave as public field? - public PdeSketch(final Sketch sketch, final File sketchPath, final DisplayType displayType, - final Point location, final LocationType locationType) { + public PdeSketch( + final Sketch sketch, + final File sketchPath, + final DisplayType displayType, + final Point location, + final LocationType locationType, final String bgColor, final String stopColor) { this.displayType = displayType; this.location = location; this.locationType = locationType; + this.bgColor = bgColor; + this.stopColor = stopColor; this.mainFile = sketchPath.getAbsoluteFile(); this.mainCode = sketch.getMainProgram(); this.sketchHome = sketch.getFolder().getAbsoluteFile(); + this.realSketchPath = sketchPath; final List libraryDirs = new ArrayList<>(); libraryDirs.add(Platform.getContentFile("modes/java/libraries")); libraryDirs.add(Base.getSketchbookLibrariesFolder()); - libraryDirs.add(sketch.getCodeFolder()); + libraryDirs.add(sketchPath); this.libraryDirs = libraryDirs; final String[] codeFileNames = new String[sketch.getCodeCount()]; @@ -55,10 +67,13 @@ public PdeSketch(final Sketch sketch, final File sketchPath, final DisplayType d codeFileNames[i] = sketch.getCode(i).getFile().getName(); } this.codeFileNames = codeFileNames; + this.pythonLibraryDirs = + Arrays.asList(PythonMode.getSitePackages().getAbsoluteFile()); } public static enum LocationType { - EDITOR_LOCATION, SKETCH_LOCATION; + EDITOR_LOCATION, + SKETCH_LOCATION; } @Override @@ -92,7 +107,9 @@ public String[] getPAppletArguments() { } break; case PRESENTATION: - args.add("fullScreen"); + args.add(PApplet.ARGS_PRESENT); + args.add(String.join("=", PApplet.ARGS_WINDOW_COLOR, bgColor)); + args.add(String.join("=", PApplet.ARGS_STOP_COLOR, stopColor)); break; } @@ -106,9 +123,6 @@ public List getLibraryDirectories() { return libraryDirs; } - /** - * PDE sketches should be selective - no need to rush, we can just load as we go. - */ @Override public LibraryPolicy getLibraryPolicy() { return LibraryPolicy.SELECTIVE; @@ -122,12 +136,14 @@ public boolean shouldRun() { @Override public List getPathEntries() { final List entries = new ArrayList<>(); + entries.add(realSketchPath.getParentFile()); entries.add(sketchHome); entries.add(new File(sketchHome, "source")); final File code = new File(sketchHome, "code"); if (code.exists()) { entries.add(code); } + entries.addAll(pythonLibraryDirs); return entries; } } diff --git a/runtime/src/jycessing/mode/run/RMIUtils.java b/runtime/src/jycessing/mode/run/RMIUtils.java index a01ccaf1..a096b6bf 100644 --- a/runtime/src/jycessing/mode/run/RMIUtils.java +++ b/runtime/src/jycessing/mode/run/RMIUtils.java @@ -1,18 +1,38 @@ package jycessing.mode.run; +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; import jycessing.mode.PythonMode; public class RMIUtils { - private static final boolean EXTREMELY_VERSBOSE = false; + private static final boolean EXTREMELY_VERBOSE = false; static final int RMI_PORT = 8220; + private static final RMIClientSocketFactory clientFactory = new RMIClientSocketFactory() { + @Override + public Socket createSocket(final String host, final int port) throws IOException { + return new Socket(host, port); + } + }; + + private static final RMIServerSocketFactory serverFactory = new RMIServerSocketFactory() { + @Override + public ServerSocket createServerSocket(final int port) throws IOException { + return new ServerSocket(port, 50, InetAddress.getLoopbackAddress()); + } + }; + static { System.setProperty("sun.rmi.transport.tcp.localHostNameTimeOut", "1000"); System.setProperty("java.rmi.server.hostname", "127.0.0.1"); @@ -20,7 +40,7 @@ public class RMIUtils { // Timeout RMI calls after 1.5 seconds. Good for detecting a hanging sketch runner. System.setProperty("sun.rmi.transport.tcp.responseTimeout", "1500"); - if (EXTREMELY_VERSBOSE) { + if (EXTREMELY_VERBOSE) { System.setProperty("java.rmi.server.logCalls", "true"); System.setProperty("sun.rmi.server.logLevel", "VERBOSE"); System.setProperty("sun.rmi.client.logCalls", "true"); @@ -42,31 +62,35 @@ public static class RMIProblem extends Exception { private RMIUtils() {} + private static Registry registry; + public static Registry registry() throws RemoteException { - try { - return LocateRegistry.createRegistry(RMI_PORT); - } catch (final RemoteException e) { + if (registry == null) { + try { + registry = LocateRegistry.createRegistry(RMI_PORT, clientFactory, serverFactory); + System.err.println("created registry at port " + RMI_PORT); + } catch (final RemoteException e) { + System.err.println("could not create registry; assume it's already created"); + registry = LocateRegistry.getRegistry("127.0.0.1", RMI_PORT, clientFactory); + } } - return LocateRegistry.getRegistry(RMI_PORT); + return registry; } public static void bind(final Remote remote, final Class remoteInterface) throws RMIProblem { final String registryKey = remoteInterface.getSimpleName(); try { - final Remote stub = export(remote); + export(remote); log("Attempting to bind instance of " + remote.getClass().getName() + " to registry as " + registryKey); - registry().bind(registryKey, stub); + registry().bind(registryKey, remote); log("Bound."); - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - @Override - public void run() { - try { - log("Unbinding " + registryKey + " from registry."); - registry().unbind(registryKey); - } catch (final Exception e) { - } + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + log("Unbinding " + registryKey + " from registry."); + registry().unbind(registryKey); + } catch (final Exception e) { } })); } catch (final Exception e) { @@ -74,9 +98,9 @@ public void run() { } } - public static Remote export(final Remote remote) throws RMIProblem { + public static void export(final Remote remote) throws RMIProblem { try { - return UnicastRemoteObject.exportObject(remote, 0); + UnicastRemoteObject.exportObject(remote, 0); } catch (final RemoteException e) { throw new RMIProblem(e); } diff --git a/runtime/src/jycessing/mode/run/SketchRunner.java b/runtime/src/jycessing/mode/run/SketchRunner.java index 373f2335..cb79df20 100644 --- a/runtime/src/jycessing/mode/run/SketchRunner.java +++ b/runtime/src/jycessing/mode/run/SketchRunner.java @@ -1,6 +1,5 @@ package jycessing.mode.run; -import java.awt.Point; import java.rmi.RemoteException; import jycessing.Printer; @@ -36,24 +35,20 @@ public SketchRunner(final String id, final ModeService modeService) { System.err.println(e.getMessage()); } } - new Thread(new Runnable() { - @Override - public void run() { - Runner.warmup(); - } - }, "SketchRunner Warmup Thread").start(); + new Thread(() -> Runner.warmup(), "SketchRunner Warmup Thread").start(); } /** - * On Mac, even though this app has no menu, there's still a - * built-in cmd-Q handler that, by default, quits the app. - * Because starting up the {@link SketchRunner} is expensive, - * we'd prefer to leave the app running. - *

This function responds to a user cmd-Q by stopping the - * currently running sketch, and rejecting the attempt to quit. - *

But if we've received a shutdown request from the - * {@link SketchServiceProcess} on the PDE VM, then we permit - * the quit to proceed. + * On Mac, even though this app has no menu, there's still a built-in cmd-Q handler that, by + * default, quits the app. Because starting up the {@link SketchRunner} is expensive, we'd prefer + * to leave the app running. + * + *

This function responds to a user cmd-Q by stopping the currently running sketch, and + * rejecting the attempt to quit. + * + *

But if we've received a shutdown request from the {@link SketchServiceProcess} on the PDE + * VM, then we permit the quit to proceed. + * * @return true iff the SketchRunner should quit. */ public boolean preventUserQuit() { @@ -62,12 +57,7 @@ public boolean preventUserQuit() { return true; } log("Cancelling quit, but stopping sketch."); - new Thread(new Runnable() { - @Override - public void run() { - stopSketch(); - } - }).start(); + new Thread(() -> stopSketch()).start(); return false; } @@ -78,64 +68,72 @@ public void shutdown() { System.exit(0); } + private abstract class RemotePrinter implements Printer { + abstract protected void doPrint(String s) throws RemoteException; + + public void print(final Object o) { + try { + doPrint(String.valueOf(o)); + } catch (final RemoteException e) { + System.err.println(e); + } + } + + @Override + public void flush() { + // no-op + } + } + @Override public void startSketch(final PdeSketch sketch) { - runner = new Thread(new Runnable() { - @Override - public void run() { + runner = new Thread(() -> { + try { try { - try { - final Printer stdout = new Printer() { - @Override - public void print(final Object o) { - try { - modeService.printStdOut(id, String.valueOf(o)); - } catch (final RemoteException e) { - System.err.println(e); - } - } - }; - final Printer stderr = new Printer() { - @Override - public void print(final Object o) { - try { - modeService.printStdErr(id, String.valueOf(o)); - } catch (final RemoteException e) { - System.err.println(e); - } - } - }; - final SketchPositionListener sketchPositionListener = new SketchPositionListener() { - @Override - public void sketchMoved(final Point leftTop) { - try { - modeService.handleSketchMoved(id, leftTop); - } catch (final RemoteException e) { - System.err.println(e); - } - } - }; - Runner.runSketchBlocking(sketch, stdout, stderr, sketchPositionListener); - } catch (final PythonSketchError e) { - log("Sketch runner caught " + e); - modeService.handleSketchException(id, convertPythonSketchError(e, sketch.codeFileNames)); - } catch (final Exception e) { - if (e.getCause() != null && e.getCause() instanceof PythonSketchError) { - modeService.handleSketchException(id, - convertPythonSketchError((PythonSketchError)e.getCause(), sketch.codeFileNames)); - } else { - modeService.handleSketchException(id, e); + final Printer stdout = new RemotePrinter() { + @Override + protected void doPrint(final String s) throws RemoteException { + modeService.printStdOut(id, s); } - } finally { - log("Handling sketch stoppage..."); - modeService.handleSketchStopped(id); + }; + final Printer stderr = new RemotePrinter() { + @Override + protected void doPrint(final String s) throws RemoteException { + modeService.printStdErr(id, s); + } + }; + final SketchPositionListener sketchPositionListener = leftTop -> { + try { + modeService.handleSketchMoved(id, leftTop); + } catch (final RemoteException e) { + System.err.println(e); + } + }; + Runner.runSketchBlocking(sketch, stdout, stderr, sketchPositionListener); + } catch (final PythonSketchError e1) { + log("Sketch runner caught " + e1); + if (e1.getMessage().startsWith("SystemExit")) { + // Someone called sys.exit(). No-op. + } else { + modeService.handleSketchException(id, + convertPythonSketchError(e1, sketch.codeFileNames)); + } + } catch (final Exception e2) { + if (e2.getCause() != null && e2.getCause() instanceof PythonSketchError) { + modeService.handleSketchException(id, + convertPythonSketchError((PythonSketchError)e2.getCause(), sketch.codeFileNames)); + } else { + modeService.handleSketchException(id, e2); } - } catch (final RemoteException e) { - log(e.toString()); + } finally { + log("Handling sketch stoppage..."); + modeService.handleSketchStopped(id); } - // Exiting; no need to interrupt and join it later. - runner = null; + } catch (final RemoteException e3) { + log(e3.toString()); } + // Exiting; no need to interrupt and join it later. + runner = null; }, "processing.py mode runner"); runner.start(); } @@ -162,8 +160,10 @@ public static void main(final String[] args) { // If env var SKETCH_RUNNER_FIRST=true then SketchRunner will wait for a ping from the Mode // before registering itself as the sketch runner. if (PythonMode.SKETCH_RUNNER_FIRST) { + log("Waiting for mode with id " + id); waitForMode(id); } else { + log("Starting sketch runner immediately with id " + id); startSketchRunner(id); } } @@ -171,12 +171,10 @@ public static void main(final String[] args) { private static class ModeWaiterImpl implements ModeWaiter { final String id; - public ModeWaiterImpl(final String id) { this.id = id; } - @Override public void modeReady(final ModeService modeService) { try { @@ -204,21 +202,18 @@ private static void startSketchRunner(final String id) { } } - private static void launch(final String id, final ModeService modeService) throws RMIProblem, - RemoteException { + private static void launch(final String id, final ModeService modeService) + throws RMIProblem, RemoteException { final SketchRunner sketchRunner = new SketchRunner(id, modeService); - final SketchService stub = (SketchService)RMIUtils.export(sketchRunner); + RMIUtils.export(sketchRunner); log("Calling mode's handleReady()."); - modeService.handleReady(id, stub); - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - @Override - public void run() { - log("Exiting; telling modeService."); - try { - modeService.handleSketchStopped(id); - } catch (final RemoteException e) { - // nothing we can do about it now. - } + modeService.handleReady(id, sketchRunner); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + log("Exiting; telling modeService."); + try { + modeService.handleSketchStopped(id); + } catch (final RemoteException e) { + // nothing we can do about it now. } })); } @@ -246,5 +241,4 @@ private SketchException convertPythonSketchError(final PythonSketchError e, } return new SketchException(e.getMessage(), fileIndex, e.line, e.column); } - } diff --git a/runtime/src/jycessing/mode/run/SketchServiceManager.java b/runtime/src/jycessing/mode/run/SketchServiceManager.java index 7d3ad554..7ed4e975 100644 --- a/runtime/src/jycessing/mode/run/SketchServiceManager.java +++ b/runtime/src/jycessing/mode/run/SketchServiceManager.java @@ -26,8 +26,8 @@ private static void log(final String msg) { private volatile boolean isStarted = false; /** - * This is used when {@link PythonMode#SKETCH_RUNNER_FIRST} is true. This lets - * use run the SketchRunner in a debugger, for example. + * This is used when {@link PythonMode#SKETCH_RUNNER_FIRST} is true. This lets use run the + * SketchRunner in a debugger, for example. */ private SketchService debugSketchRunner; @@ -63,9 +63,8 @@ public void start() { isStarted = true; try { if (PythonMode.SKETCH_RUNNER_FIRST) { - final ModeService stub = (ModeService)RMIUtils.export(this); - final ModeWaiter modeWaiter = RMIUtils.lookup(ModeWaiter.class); - modeWaiter.modeReady(stub); + RMIUtils.export(this); + RMIUtils.lookup(ModeWaiter.class).modeReady(this); } else { RMIUtils.bind(this, ModeService.class); } @@ -75,7 +74,6 @@ public void start() { } } - private SketchServiceProcess processFor(final String editorId) { if (PythonMode.SKETCH_RUNNER_FIRST) { return sketchServices.get(DEBUG_SKETCH_RUNNER_KEY); @@ -83,8 +81,10 @@ private SketchServiceProcess processFor(final String editorId) { final SketchServiceProcess p = sketchServices.get(editorId); if (p == null) { - throw new RuntimeException("I somehow got a message from the sketch runner for " + editorId - + " but don't have an active service process for it!"); + throw new RuntimeException( + "I somehow got a message from the sketch runner for " + + editorId + + " but don't have an active service process for it!"); } return p; } diff --git a/runtime/src/jycessing/mode/run/SketchServiceProcess.java b/runtime/src/jycessing/mode/run/SketchServiceProcess.java index 91f37b5f..b2e018fa 100644 --- a/runtime/src/jycessing/mode/run/SketchServiceProcess.java +++ b/runtime/src/jycessing/mode/run/SketchServiceProcess.java @@ -17,6 +17,8 @@ import java.util.List; import java.util.regex.Pattern; +import com.google.common.base.Joiner; + import jycessing.mode.PyEditor; import jycessing.mode.PythonMode; import processing.app.Messages; @@ -24,8 +26,6 @@ import processing.app.Preferences; import processing.app.SketchException; -import com.google.common.base.Joiner; - public class SketchServiceProcess { private static void log(final String msg) { if (PythonMode.VERBOSE) { @@ -56,9 +56,8 @@ public SketchServiceProcess(final PythonMode mode, final PyEditor editor) { } /** - * This constructor should only be used while instrumenting or debugging the - * {@link SketchRunner}, in which case it has already been started in the - * debugger or such like. + * This constructor should only be used while instrumenting or debugging the {@link SketchRunner}, + * in which case it has already been started in the debugger or such like. */ SketchServiceProcess(final PythonMode mode, final PyEditor editor, final SketchService runningService) { @@ -121,18 +120,23 @@ private ProcessBuilder createServerCommand() { command.add("-Xdock:name=Processing"); } + // Attempt to address https://github.com/jdf/Processing.py-Bugs/issues/158 + command.add("-Dpython.console.encoding=UTF-8"); + if (PythonMode.VERBOSE) { command.add("-Dverbose=true"); } - command.add("-Djava.library.path=" + System.getProperty("java.library.path")); + command.add("-Djava.library.path=" + System.getProperty("java.library.path") + + File.pathSeparator + mode.getContentFile("mode").getAbsolutePath()); final List cp = new ArrayList<>(); cp.addAll(filter( - Arrays.asList(System.getProperty("java.class.path") - .split(Pattern.quote(File.pathSeparator))), + Arrays + .asList(System.getProperty("java.class.path").split(Pattern.quote(File.pathSeparator))), not(or( - containsPattern("(ant|ant-launcher|antlr|netbeans.*|osgi.*|jdi.*|ibm\\.icu.*|jna)\\.jar$"), + containsPattern( + "(ant|ant-launcher|antlr|netbeans.*|osgi.*|jdi.*|ibm\\.icu.*|jna)\\.jar$"), containsPattern("/processing/app/(test|lib)/"))))); for (final File jar : new File(Platform.getContentFile("core"), "library").listFiles(JARS)) { cp.add(jar.getAbsolutePath()); @@ -193,7 +197,6 @@ public void run() { } } - public void stopSketch() throws SketchException { if (sketchService == null) { log("Sketch runner apparently not running; can't stop sketch."); @@ -208,7 +211,6 @@ public void stopSketch() throws SketchException { } } - public void shutdown() { if (sketchService != null) { log("Telling sketch runner to shutdown."); @@ -246,5 +248,4 @@ public void handleSketchException(final Exception e) { public void handleSketchMoved(final Point leftTop) { editor.setSketchLocation(leftTop); } - } diff --git a/runtime/src/jycessing/mode/run/WrappedPrintStream.java b/runtime/src/jycessing/mode/run/WrappedPrintStream.java index a403bb18..6a5c0e1e 100644 --- a/runtime/src/jycessing/mode/run/WrappedPrintStream.java +++ b/runtime/src/jycessing/mode/run/WrappedPrintStream.java @@ -13,6 +13,10 @@ private PushedOut() { System.setOut(WrappedPrintStream.this); } + public void open() { + System.setOut(WrappedPrintStream.this); + } + @Override public void close() { System.setOut(saved); @@ -23,13 +27,20 @@ public WrappedPrintStream(final OutputStream out) { super(out); } + private PushedOut cachedOut = null; + /** - * {@link #pushStdout()} swaps this {@link WrappedPrintStream} in for System.out, - * and then puts the original stream back when the {@link PushedOut} is closed. + * {@link #pushStdout()} swaps this {@link WrappedPrintStream} in for System.out, and then puts + * the original stream back when the {@link PushedOut} is closed. + * * @return an AutoCloseable context that restores System.out. */ public PushedOut pushStdout() { - return new PushedOut(); + if (cachedOut == null) { + cachedOut = new PushedOut(); + } + cachedOut.open(); + return cachedOut; } public abstract void doPrint(String s); @@ -133,5 +144,4 @@ public void println(final long x) { public void println(final Object x) { println(String.valueOf(x)); } - } diff --git a/runtime/src/jycessing/primitives/PrimitiveFloat.java b/runtime/src/jycessing/primitives/PrimitiveFloat.java index 0cca5d72..ca8c3549 100755 --- a/runtime/src/jycessing/primitives/PrimitiveFloat.java +++ b/runtime/src/jycessing/primitives/PrimitiveFloat.java @@ -4,7 +4,7 @@ /** * Primitive float class. Serves as a container for libraries such as Ani. - * + * * @author Ralf Biedert */ @PythonUsage(methodName = "PrimitiveFloat") diff --git a/runtime/src/jycessing/pyde_preprocessor.py b/runtime/src/jycessing/pyde_preprocessor.py index a2c6e3c3..b512576c 100644 --- a/runtime/src/jycessing/pyde_preprocessor.py +++ b/runtime/src/jycessing/pyde_preprocessor.py @@ -18,6 +18,9 @@ # # def draw(): # +# +# This also renames a "keyPressed" function to "__keyPressed__", to avoid hiding +# the boolean variable with the same name. import ast @@ -29,74 +32,65 @@ def __init__(self): self.fullScreen = False self.noSmooth = False self.smooth = False + self.pixelDensity = False + def insert(self, body): + for attr in ('size', 'fullScreen', 'noSmooth', 'smooth', 'pixelDensity'): + if getattr(self, attr): + body.insert(0, getattr(self, attr)) + def pyde_preprocessor(module): - __program_info__ = Program_info() + info = Program_info() # Walk throught the abstract syntax tree for the original sketch. for node in module.body: if isinstance(node, ast.FunctionDef): + if (node.name == 'keyPressed'): + # rename keyPressed to not clash with the builtin boolean variable + node.name = '__keyPressed__' + continue if (node.name == 'setup'): + toremove = [] # The user has defined a setup() function. Look through setup() for calls # to size(), fullScreen(), noSmooth() and smooth(). - __program_info__.found_setup = True + info.found_setup = True for subNode in node.body: - if isinstance(subNode, ast.Expr): - if isinstance(subNode.value, ast.Call): - calledFunc = subNode.value.func.id - if (calledFunc == "size"): - __program_info__.size = subNode - node.body.remove(subNode) - elif (calledFunc == "fullScreen"): - __program_info__.fullScreen = subNode - node.body.remove(subNode) - elif (calledFunc == "noSmooth"): - __program_info__.noSmooth = subNode - node.body.remove(subNode) - elif (calledFunc == "smooth"): - __program_info__.smooth = subNode - node.body.remove(subNode) + if not isinstance(subNode, ast.Expr): + continue + if not isinstance(subNode.value, ast.Call): + continue + func = subNode.value.func + if hasattr(func, 'id') and func.id in ( + 'size', 'fullScreen', 'noSmooth', 'smooth', 'pixelDensity'): + toremove.append(subNode) + setattr(info, func.id, subNode) + for n in toremove: + node.body.remove(n) elif (node.name == 'settings'): # The user has defined a settings() function. - __program_info__.found_settings = True + info.found_settings = True - if (__program_info__.size or __program_info__.fullScreen or __program_info__.noSmooth or __program_info__.smooth): + if (info.size or info.fullScreen or info.noSmooth or info.smooth): # The user called one of the settings() subfunctions inside setup. - if (__program_info__.found_settings): + if (info.found_settings): # If a settings function was already defined, go through the tree to find it. # Place all of the special function calls inside settings function body. for node in module.body: if (isinstance(node, ast.FunctionDef)): if (node.name == 'settings'): - if (__program_info__.smooth): - node.body.insert(0, __program_info__.smooth) - if (__program_info__.noSmooth): - node.body.insert(0, __program_info__.noSmooth) - if (__program_info__.size): - node.body.insert(0, __program_info__.size) - if (__program_info__.fullScreen): - node.body.insert(0, __program_info__.fullScreen) - # Don't look through the rest of the tree. + info.insert(node.body) break else: # If a settings function is not defined, we define one and place all of # the special function calls within it. - settingsArgs = ast.arguments(args = [], vararg = None, kwarg = None, defaults = []) - settingsFunc = ast.FunctionDef("settings",settingsArgs,[],[]) - if (__program_info__.noSmooth): - settingsFunc.body.insert(0, __program_info__.noSmooth) - if (__program_info__.smooth): - settingsFunc.body.insert(0, __program_info__.smooth) - if (__program_info__.size): - settingsFunc.body.insert(0, __program_info__.size) - if (__program_info__.fullScreen): - settingsFunc.body.insert(0, __program_info__.fullScreen) - - # Place the newly defined settings() function within the module body. + settingsArgs = ast.arguments(args=[], vararg=None, kwarg=None, defaults=[]) + settingsFunc = ast.FunctionDef("settings", settingsArgs, [], []) + info.insert(settingsFunc.body) + # Place the newly defined settings() function at the end of the module body. # It's like it's been there the whole time... - module.body.insert(0, settingsFunc) + module.body.insert(len(module.body), settingsFunc) module = ast.parse(__processing_source__ + "\n\n", filename=__file__) pyde_preprocessor(module) -codeobj = compile(module, __file__, mode='exec') +codeobj = compile(module, __file__, mode='exec') exec(codeobj) diff --git a/testing/resources/data/foo.py b/testing/resources/data/foo.py new file mode 100755 index 00000000..8f062c16 --- /dev/null +++ b/testing/resources/data/foo.py @@ -0,0 +1 @@ +victory = 'yes' diff --git a/testing/resources/test_from_future_with_settings.py b/testing/resources/test_from_future_with_settings.py new file mode 100644 index 00000000..64339bba --- /dev/null +++ b/testing/resources/test_from_future_with_settings.py @@ -0,0 +1,8 @@ +from __future__ import division + +def setup(): + size(20, 20) + +def draw(): + print 'OK' + exit() \ No newline at end of file diff --git a/testing/resources/test_g.py b/testing/resources/test_g.py new file mode 100644 index 00000000..0b303016 --- /dev/null +++ b/testing/resources/test_g.py @@ -0,0 +1,12 @@ +import processing.opengl.PGraphics3D + +def setup(): + size(100, 100, P3D) + +def draw(): + # check that the alias cameraMatrix->camera is working as expected + g.camera(0, 0, -10, 0, 0, 0, 0, 1, 0) + assert(g.cameraMatrix.m03 == 0) + assert(g.cameraMatrix.m23 == -10) + print 'OK' + exit() diff --git a/testing/resources/test_keyPressed_redefined.py b/testing/resources/test_keyPressed_redefined.py new file mode 100644 index 00000000..5e7ad921 --- /dev/null +++ b/testing/resources/test_keyPressed_redefined.py @@ -0,0 +1,12 @@ +def settings(): + size(48, 48, P2D) + +def draw(): + if frameCount > 1: + raise Exception("Expected to exit.") + assert(keyPressed == False) + __keyPressed__() + +def keyPressed(): + print "OK" + exit() \ No newline at end of file diff --git a/testing/resources/test_loadthings.py b/testing/resources/test_loadthings.py index af3597c2..00643685 100755 --- a/testing/resources/test_loadthings.py +++ b/testing/resources/test_loadthings.py @@ -28,5 +28,14 @@ assert a.getString(0) == 'hello' assert a.getString(1) == 'world' +expected = ['hello', 'world'] +helloworld = loadStrings(createInput("strings.txt")) +assert helloworld[0] == 'hello' +assert helloworld[1] == 'world' + +helloworld = loadStrings(createInput(File("testing/resources/data/strings.txt"))) +assert helloworld[0] == 'hello' +assert helloworld[1] == 'world' + print 'OK' -exit() \ No newline at end of file +exit() diff --git a/testing/resources/test_mixed_smooth_error.py b/testing/resources/test_mixed_smooth_error.py new file mode 100644 index 00000000..27add5e6 --- /dev/null +++ b/testing/resources/test_mixed_smooth_error.py @@ -0,0 +1,8 @@ +# should throw a mixed smooth exception + +background(0) +noStroke() +smooth() +ellipse(30, 48, 36, 36) +noSmooth() +ellipse(70, 48, 36, 36) \ No newline at end of file diff --git a/testing/resources/test_pgraphics_calls.py b/testing/resources/test_pgraphics_calls.py new file mode 100644 index 00000000..0df4ad06 --- /dev/null +++ b/testing/resources/test_pgraphics_calls.py @@ -0,0 +1,16 @@ +# make sure that ellipse, arc, line, and rect all work as functions + +size(100, 100) +pg = createGraphics(40, 40) + +pg.beginDraw() + +pg.ellipse(20, 20, 10, 10) +pg.line(30, 30, 40, 40) +pg.rect(0, 0, 10, 10) +pg.arc(30, 35, 30, 30, 0, HALF_PI) +pg.endDraw() +image(pg, 9, 30) + +print 'OK' +exit() diff --git a/testing/resources/test_pixels.py b/testing/resources/test_pixels.py index 1d9a556f..92fc03db 100755 --- a/testing/resources/test_pixels.py +++ b/testing/resources/test_pixels.py @@ -5,6 +5,12 @@ rect(10, 10, 10, 10) assert get(15, 15) == 0xFF0000FF +square(10, 30, 10) +assert get(15, 35) == 0xFF0000FF + +circle(100, 100, 10) +assert get(99, 99) == 0xFF0000FF + fill(255) rect(20, 10, 10, 10) assert get(25, 15) == 0xFFFFFFFF @@ -36,5 +42,20 @@ set(x, y, '#EEEE00') assert get(75, 15) == 0xFFEEEE00 +background(100) +fill('#0000FF') +rect(0, 0, 10, 10) +assert get(5, 5) == 0xFF0000FF + +with push(): + translate(20, 0) + fill(255) + rect(0, 0, 10, 10) + +assert get(25, 5) == 0xFFFFFFFF + +rect(40, 0, 10, 10) +assert get(45, 5) == 0xFF0000FF # pop also restores previous style confs + print 'OK' -exit() \ No newline at end of file +exit() diff --git a/testing/resources/test_pmatrixprint.py b/testing/resources/test_pmatrixprint.py new file mode 100755 index 00000000..c6fb8520 --- /dev/null +++ b/testing/resources/test_pmatrixprint.py @@ -0,0 +1,3 @@ +a = PMatrix3D() +a.print() +exit() diff --git a/testing/resources/test_pvector.py b/testing/resources/test_pvector.py index f2b2d34d..dcf6f06f 100755 --- a/testing/resources/test_pvector.py +++ b/testing/resources/test_pvector.py @@ -130,6 +130,35 @@ end.lerp(200, 200, 0, .5) assert end == PVector(150.0, 150.0) +# test that instance op returns self +a = PVector(3, 5, 7) +b = a * 10 +assert a.mult(10) == b + +# test that a vector can do arithmetic with a tuple +assert PVector(1, 2, 3) == (1, 2, 3) +assert (PVector(1, 2, 3) + (3, 3, 3)) == (4, 5, 6) +assert (PVector(5, 5, 5) - (1, 2, 3)) == (4, 3, 2) + +# Regression test for https://github.com/jdf/processing.py/issues/317 +r = PVector.random2D() * 10 +assert -10 <= r.x <= 10 +assert -10 <= r.y <= 10 +assert r.z == 0 + +PVector.random3D(r) +r += (1, 1, 1) +assert 0 <= r.x <= 2 +assert 0 <= r.y <= 2 +assert 0 <= r.z <= 2 + +# Regression test for https://github.com/jdf/processing.py/issues/334 +r = PVector.fromAngle(0) * 10 +assert r.x == 10 +assert r.y == 0 +assert r.z == 0 + + print 'OK' exit() diff --git a/testing/resources/test_static_size.py b/testing/resources/test_static_size.py index 497f0032..6e130ba1 100755 --- a/testing/resources/test_static_size.py +++ b/testing/resources/test_static_size.py @@ -1,5 +1,5 @@ -def settings(): - size(10, 10) - +size(11, 13) +assert(width == 11) +assert(height == 13) print 'OK' exit() diff --git a/testing/resources/test_syspathappend.py b/testing/resources/test_syspathappend.py new file mode 100755 index 00000000..8db98132 --- /dev/null +++ b/testing/resources/test_syspathappend.py @@ -0,0 +1,11 @@ +import sys +sys.path.append('data') +from foo import victory + +def setup(): + pass + +def draw(): + assert victory == 'yes' + print 'OK' + exit() diff --git a/testing/resources/test_thread.py b/testing/resources/test_thread.py new file mode 100755 index 00000000..6afaf620 --- /dev/null +++ b/testing/resources/test_thread.py @@ -0,0 +1,25 @@ +import time + +def setup(): + size(10, 10) + +n = 0 + +def func1(): + global n + n += 1 + +def func2(): + global n + n += 4 + +def draw(): + noLoop() + thread("func1") + while n < 1: + time.sleep(0.02) + thread(func2) + while n < 5: + time.sleep(0.02) + print('OK') + exit() diff --git a/testing/resources/test_unittest.py b/testing/resources/test_unittest.py new file mode 100755 index 00000000..3a6bcd4f --- /dev/null +++ b/testing/resources/test_unittest.py @@ -0,0 +1,13 @@ +import unittest + +def return_twelve(): + return 12 + +class TestTwelveness(unittest.TestCase): + def test_base(self): + self.assertEqual(12, return_twelve()) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestTwelveness) +unittest.TextTestRunner(verbosity=0).run(suite) +print 'OK' +exit() \ No newline at end of file diff --git a/testing/resources/test_writethings.py b/testing/resources/test_writethings.py new file mode 100644 index 00000000..611c6420 --- /dev/null +++ b/testing/resources/test_writethings.py @@ -0,0 +1,27 @@ +import tempfile +from java.io import File + +content = "hello" + +# guaranteed to be deleted on close and/or garbage collection +with tempfile.NamedTemporaryFile() as tmpfile: + + w = createOutput(tmpfile.name) + saveBytes(w, content) + w.close() + r = createInput(tmpfile.name) + data = loadBytes(r) + r.close() + assert ''.join([chr(c) for c in data]) == content + + w = createOutput(tmpfile.name) + saveBytes(w, content) + w.close() + r = createInput(tmpfile.name) + data = loadBytes(r) + r.close() + assert ''.join([chr(c) for c in data]) == content + +print 'OK' +exit() + diff --git a/testing/src/test/jycessing/JycessingTests.java b/testing/src/test/jycessing/JycessingTests.java index fdc47b74..7753e109 100755 --- a/testing/src/test/jycessing/JycessingTests.java +++ b/testing/src/test/jycessing/JycessingTests.java @@ -12,16 +12,18 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import org.junit.Test; + import jycessing.MixedModeError; +import jycessing.MixedSmoothError; import jycessing.PAppletJythonDriver; import jycessing.Printer; import jycessing.PythonSketchError; import jycessing.Runner; import jycessing.StreamPrinter; -import org.junit.Test; - public class JycessingTests { + private static class CapturingPrinter implements Printer { private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); private final PrintStream out = new PrintStream(baos, true); @@ -31,17 +33,22 @@ public void print(final Object o) { out.print(String.valueOf(o)); } + @Override + public void flush() { + out.flush(); + } + public String getText() { try { - return new String(baos.toByteArray(), "utf-8").replaceAll("\r\n", "\n").replaceAll("\r", - "\n"); + return new String(baos.toByteArray(), "utf-8") + .replaceAll("\r\n", "\n") + .replaceAll("\r", "\n"); } catch (final UnsupportedEncodingException e) { throw new RuntimeException(e); } } } - private static String run(final String testResource) throws Exception { System.err.println("Running " + testResource + " test."); final Path source = Paths.get("testing/resources/test_" + testResource + ".py"); @@ -61,7 +68,9 @@ private static void testImport(final String module) throws Exception { final Path src = Paths.get(tmp.toString(), "test_import_" + module + ".pyde"); try { final String testText = "import " + module + "\nprint 'OK'\nexit()"; - Files.copy(new ByteArrayInputStream(testText.getBytes("utf-8")), src, + Files.copy( + new ByteArrayInputStream(testText.getBytes("utf-8")), + src, StandardCopyOption.REPLACE_EXISTING); final CapturingPrinter out = new CapturingPrinter(); System.err.println("Running import " + module + " test."); @@ -78,7 +87,6 @@ private static void expectOK(final String testName) throws Exception { assertEquals("OK\n", run(testName)); } - @Test public void inherit_str() throws Exception { assertEquals("cosmic\n12\n[12, 13]\n", run("inherit_str")); @@ -210,6 +218,11 @@ public void loadThings() throws Exception { expectOK("loadthings"); } + @Test + public void writeThings() throws Exception { + expectOK("writethings"); + } + @Test public void constrain() throws Exception { expectOK("constrain"); @@ -264,4 +277,68 @@ public void keyDefinedBeforeKeyEvent() throws Exception { public void randintDomainRegression() throws Exception { expectOK("randint_domain_regression"); } + + // https://github.com/jdf/processing.py/issues/167 + @Test + public void syspathappend() throws Exception { + expectOK("syspathappend"); + } + + // https://github.com/jdf/Processing.py-Bugs/issues/148 + @Test + public void from_future_with_settings() throws Exception { + expectOK("from_future_with_settings"); + } + + // https://github.com/jdf/processing.py/issues/199 + @Test + public void matrix3d_print() throws Exception { + final String actual = run("pmatrixprint"); + final String expected = + " 1.0000 0.0000 0.0000 0.0000\n" + + " 0.0000 1.0000 0.0000 0.0000\n" + + " 0.0000 0.0000 1.0000 0.0000\n" + + " 0.0000 0.0000 0.0000 1.0000\n\n"; + assertEquals(expected, actual); + } + + // https://github.com/jdf/processing.py/issues/264 + @Test + public void unittest() throws Exception { + expectOK("unittest"); + } + + // https://github.com/jdf/processing.py/issues/251 + @Test + public void detectMixedSmooth() throws Exception { + try { + run("mixed_smooth_error"); + fail("Expected mixed smooth error."); + } catch (final MixedSmoothError expected) { + // noop + } + } + + // https://github.com/jdf/processing.py/issues/280 + @Test + public void g() throws Exception { + expectOK("g"); + } + + @Test + public void keyPressed_redefined() throws Exception { + expectOK("keyPressed_redefined"); + } + + // https://github.com/jdf/processing.py/issues/281 + @Test + public void thread() throws Exception { + expectOK("thread"); + } + + // https://github.com/jdf/processing.py/issues/326 + @Test + public void pGraphicsJava2d() throws Exception { + expectOK("pgraphics_calls"); + } } diff --git a/testing/src/test/jycessing/TestSketch.java b/testing/src/test/jycessing/TestSketch.java index 0d89c9a3..a8d08af5 100644 --- a/testing/src/test/jycessing/TestSketch.java +++ b/testing/src/test/jycessing/TestSketch.java @@ -6,27 +6,23 @@ import java.util.ArrayList; import java.util.List; -import processing.core.PApplet; import jycessing.RunnableSketch; import jycessing.Runner.LibraryPolicy; +import processing.core.PApplet; -/** - * - * Encapsulates a unit test so that it can be run by Runner. - * - */ +/** Encapsulates a unit test so that it can be run by Runner. */ public class TestSketch implements RunnableSketch { private final Path sourcePath; private final String sourceText; private final String name; - + public TestSketch(final Path sourcePath, final String sourceText, final String name) { this.sourcePath = sourcePath; this.sourceText = sourceText; this.name = name; } - + @Override public File getMainFile() { return sourcePath.toFile(); @@ -68,5 +64,4 @@ public List getPathEntries() { entries.add(getHomeDirectory()); return entries; } - } diff --git a/testmode.bat b/testmode.bat new file mode 100644 index 00000000..4199e560 --- /dev/null +++ b/testmode.bat @@ -0,0 +1,26 @@ +set VERBOSE_PYTHON_MODE=true + +set PROCESSINGPY=%CD% +set PROCESSING=..\processing + +for /f "tokens=1,2*" %%A in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" /v "Personal" 2^>nul') do set MY_DOCS_ROOT=%%C + +set MODES=%MY_DOCS_ROOT%\Processing\modes +set RUNPROCESSINGDIR=%PROCESSING%\build\windows\work + +cd /d %PROCESSINGPY% +ant mode.zip + +cd /d %MODES% +del /s /f /q PythonMode +for /f %%f in ('dir /ad /b PythonMode') do rd /s /q PythonMode\%%f + +cd /d %PROCESSINGPY%\work +powershell Expand-Archive PythonMode.zip -DestinationPath %MODES% + +cd /d %PROCESSINGPY% + +cd /d %RUNPROCESSINGDIR% +.\java\bin\java -cp lib\pde.jar;core\library\core.jar;lib\jna.jar;lib\jna-platform.jar;lib\antlr.jar;lib\ant.jar;lib\ant-launcher.jar processing.app.Base + +cd %PROCESSINGPY% \ No newline at end of file diff --git a/testmode.sh b/testmode.sh index 434d5f0c..f7356c29 100755 --- a/testmode.sh +++ b/testmode.sh @@ -1,23 +1,23 @@ #!/bin/bash export VERBOSE_PYTHON_MODE=true -PROCESSING=~/processing -PROCESSINGPY=~/processing.py +PROCESSINGPY=$(pwd) +PROCESSING=../processing +MODES=~/Documents/Processing/modes; if [[ $(uname) == 'Darwin' ]]; then RUNPROCESSING=$PROCESSING/build/macosx/work/Processing.app/Contents/MacOS/Processing - MODES=~/Documents/Processing/modes; else - RUNPROCESSING=$PROCESSING/build/linux/work/processing + RUNPROCESSING="$PROCESSING/build/linux/work/processing" MODES=~/sketchbook/modes; fi -cd $PROCESSING/build && \ +cd "$PROCESSING/build" && \ #ant && \ - cd $PROCESSINGPY && \ + cd "$PROCESSINGPY" && \ ant mode.zip && \ - cd $MODES && \ + cd "$MODES" && \ rm -rf PythonMode && \ - unzip $PROCESSINGPY/work/PythonMode.zip && \ - cd /tmp && \ - $RUNPROCESSING + unzip "$PROCESSINGPY/work/PythonMode.zip" && \ + cd "$PROCESSINGPY" && \ + "$RUNPROCESSING"