From 202008c4703f984cd4119310290bbaef97ef85be Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 2 Jan 2015 14:55:06 +0100 Subject: [PATCH 1/7] Support digraphs and alternate operator names in CPPParser --- dtool/src/cppparser/cppPreprocessor.cxx | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/dtool/src/cppparser/cppPreprocessor.cxx b/dtool/src/cppparser/cppPreprocessor.cxx index 474063e4a7..0911921510 100644 --- a/dtool/src/cppparser/cppPreprocessor.cxx +++ b/dtool/src/cppparser/cppPreprocessor.cxx @@ -824,6 +824,8 @@ internal_get_next_token() { } if (next_c == '<') return CPPToken(LSHIFT, first_line, first_col, first_file); if (next_c == '=') return CPPToken(LECOMPARE, first_line, first_col, first_file); + if (next_c == ':') return CPPToken('[', first_line, first_col, first_file); + if (next_c == '%') return CPPToken('{', first_line, first_col, first_file); break; case '>': @@ -867,6 +869,7 @@ internal_get_next_token() { case ':': if (next_c == ':') return CPPToken(SCOPE, first_line, first_col, first_file); + if (next_c == '>') return CPPToken(']', first_line, first_col, first_file); break; case '*': @@ -879,6 +882,7 @@ internal_get_next_token() { case '%': if (next_c == '=') return CPPToken(MODEQUAL, first_line, first_col, first_file); + if (next_c == '>') return CPPToken('}', first_line, first_col, first_file); break; } @@ -1411,7 +1415,7 @@ handle_include_directive(const string &args, int first_line, found_file = true; source = CPPFile::S_local; } - + // Search the same directory as the includer. if (!angle_quotes && !found_file) { Filename match(get_file()._filename.get_dirname(), filename); @@ -1439,7 +1443,7 @@ handle_include_directive(const string &args, int first_line, } } } - + if (!found_file) { warning("Cannot find " + filename.get_fullpath(), first_line, first_col, first_file); @@ -2058,6 +2062,19 @@ check_keyword(const string &name) { if (name == "volatile") return KW_VOLATILE; if (name == "while") return KW_WHILE; + // These are alternative ways to refer to built-in operators. + if (name == "and") return ANDAND; + if (name == "and_eq") return ANDEQUAL; + if (name == "bitand") return '&'; + if (name == "bitor") return '|'; + if (name == "compl") return '~'; + if (name == "not") return '!'; + if (name == "not_eq") return NECOMPARE; + if (name == "or") return OROR; + if (name == "or_eq") return OREQUAL; + if (name == "xor") return '^'; + if (name == "xor_eq") return XOREQUAL; + if (!cpp_longlong_keyword.empty() && name == cpp_longlong_keyword) { return KW_LONGLONG; } From 368e1ca644c999336975ada6d1ab3af40c13f757 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 2 Jan 2015 14:57:33 +0100 Subject: [PATCH 2/7] Support noexcept and rvalue references in C++ parser --- dtool/src/cppparser/cppBison.yxx | 111 +++++++++++------- dtool/src/cppparser/cppFunctionType.cxx | 3 + dtool/src/cppparser/cppFunctionType.h | 1 + dtool/src/cppparser/cppInstanceIdentifier.cxx | 10 +- dtool/src/cppparser/cppInstanceIdentifier.h | 1 + dtool/src/cppparser/cppPreprocessor.cxx | 1 + dtool/src/cppparser/cppReferenceType.cxx | 22 +++- dtool/src/cppparser/cppReferenceType.h | 13 +- 8 files changed, 110 insertions(+), 52 deletions(-) diff --git a/dtool/src/cppparser/cppBison.yxx b/dtool/src/cppparser/cppBison.yxx index 238c4f578b..80d78fe184 100644 --- a/dtool/src/cppparser/cppBison.yxx +++ b/dtool/src/cppparser/cppBison.yxx @@ -1,6 +1,6 @@ // Filename: cppBison.y // Created by: drose (16Jan99) -// +// //////////////////////////////////////////////////////////////////// %{ @@ -38,7 +38,7 @@ CPPScope *current_scope = NULL; CPPScope *global_scope = NULL; CPPPreprocessor *current_lexer = NULL; -static CPPStructType *current_struct = NULL; +static CPPStructType *current_struct = NULL; static CPPEnumType *current_enum = NULL; static int current_storage_class = 0; static CPPType *current_type = NULL; @@ -98,7 +98,7 @@ parse_cpp(CPPParser *cp) { current_scope = old_scope; global_scope = old_global_scope; current_lexer = old_lexer; - + } CPPExpression * @@ -140,7 +140,7 @@ parse_type(CPPPreprocessor *pp, CPPScope *new_current_scope, yyparse(); CPPType *result = current_type; - + current_scope = old_scope; global_scope = old_global_scope; current_lexer = old_lexer; @@ -223,8 +223,8 @@ pop_struct() { %token UNARY_REF %token POINTSAT %token SCOPE -%token PLUSPLUS -%token MINUSMINUS +%token PLUSPLUS +%token MINUSMINUS %token TIMESEQUAL %token DIVIDEEQUAL %token MODEQUAL @@ -242,14 +242,14 @@ pop_struct() { %token KW_CATCH %token KW_CHAR %token KW_WCHAR_T -%token KW_CLASS -%token KW_CONST +%token KW_CLASS +%token KW_CONST %token KW_DELETE %token KW_DOUBLE %token KW_DYNAMIC_CAST %token KW_ELSE -%token KW_END_PUBLISH -%token KW_ENUM +%token KW_END_PUBLISH +%token KW_ENUM %token KW_EXTENSION %token KW_EXTERN %token KW_EXPLICIT @@ -269,6 +269,7 @@ pop_struct() { %token KW_MUTABLE %token KW_NAMESPACE %token KW_NEW +%token KW_NOEXCEPT %token KW_OPERATOR %token KW_PRIVATE %token KW_PROTECTED @@ -280,14 +281,14 @@ pop_struct() { %token KW_SIZEOF %token KW_STATIC %token KW_STATIC_CAST -%token KW_STRUCT +%token KW_STRUCT %token KW_TEMPLATE %token KW_THROW %token KW_TRUE %token KW_TRY -%token KW_TYPEDEF +%token KW_TYPEDEF %token KW_TYPENAME -%token KW_UNION +%token KW_UNION %token KW_UNSIGNED %token KW_USING %token KW_VIRTUAL @@ -417,7 +418,7 @@ constructor_init: extern_c: storage_class '{' { - push_storage_class((current_storage_class & ~CPPInstance::SC_c_binding) | + push_storage_class((current_storage_class & ~CPPInstance::SC_c_binding) | ($1 & CPPInstance::SC_c_binding)); } cpp '}' @@ -434,7 +435,7 @@ declaration: | using_declaration | friend_declaration | KW_TYPEDEF typedef_declaration - | KW_BEGIN_PUBLISH + | KW_BEGIN_PUBLISH { if (publish_nest_level != 0) { yyerror("Unclosed __begin_publish", publish_loc); @@ -447,7 +448,7 @@ declaration: publish_nest_level++; current_scope->set_current_vis(V_published); } - | KW_END_PUBLISH + | KW_END_PUBLISH { if (publish_nest_level != 1) { yyerror("Unmatched __end_publish", @1); @@ -765,7 +766,7 @@ typedef_const_instance_identifiers: function_prototype: /* Functions with implicit return types, and constructors */ - IDENTIFIER '(' + IDENTIFIER '(' { push_scope($1->get_scope(current_scope, global_scope)); } @@ -821,13 +822,13 @@ function_prototype: if ($2->is_scoped()) { yyerror("Invalid destructor name: ~" + $2->get_fully_scoped_name(), @2); } else { - CPPIdentifier *ident = + CPPIdentifier *ident = new CPPIdentifier("~" + $2->get_simple_name(), @2.file); delete $2; CPPType *type; type = new CPPSimpleType(CPPSimpleType::T_void); - + CPPInstanceIdentifier *ii = new CPPInstanceIdentifier(ident); ii->add_func_modifier($5, $7); @@ -932,7 +933,7 @@ function_prototype: avoid shift/reduce conflicts. */ | IDENTIFIER { - CPPDeclaration *decl = + CPPDeclaration *decl = $1->find_symbol(current_scope, global_scope, current_lexer); if (decl != (CPPDeclaration *)NULL) { $$ = decl->as_instance(); @@ -950,6 +951,10 @@ function_post: | KW_CONST { $$ = (int)CPPFunctionType::F_const_method; +} + | function_post KW_NOEXCEPT +{ + $$ = (int)CPPFunctionType::F_noexcept; } | function_post KW_THROW '(' ')' { @@ -1239,6 +1244,11 @@ instance_identifier: { $$ = $2; $$->add_modifier(IIT_reference); +} + | ANDAND instance_identifier %prec UNARY +{ + $$ = $2; + $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' instance_identifier %prec UNARY { @@ -1436,6 +1446,11 @@ not_paren_formal_parameter_identifier: { $$ = $2; $$->add_modifier(IIT_reference); +} + | ANDAND not_paren_formal_parameter_identifier %prec UNARY +{ + $$ = $2; + $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' not_paren_formal_parameter_identifier %prec UNARY { @@ -1476,6 +1491,11 @@ formal_parameter_identifier: { $$ = $2; $$->add_modifier(IIT_reference); +} + | ANDAND formal_parameter_identifier %prec UNARY +{ + $$ = $2; + $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' formal_parameter_identifier %prec UNARY { @@ -1519,6 +1539,11 @@ empty_instance_identifier: { $$ = $2; $$->add_modifier(IIT_reference); +} + | ANDAND empty_instance_identifier %prec UNARY +{ + $$ = $2; + $$->add_modifier(IIT_rvalue_reference); } | SCOPING '*' empty_instance_identifier %prec UNARY { @@ -1574,7 +1599,7 @@ type: if (type != NULL) { $$ = type; } else { - CPPExtensionType *et = + CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); @@ -1590,7 +1615,7 @@ type: if (type != NULL) { $$ = type; } else { - CPPExtensionType *et = + CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); @@ -1638,7 +1663,7 @@ type_decl: if (type != NULL) { $$ = type; } else { - CPPExtensionType *et = + CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); @@ -1654,7 +1679,7 @@ type_decl: if (type != NULL) { $$ = type; } else { - CPPExtensionType *et = + CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); @@ -1686,7 +1711,7 @@ predefined_type: if (type != NULL) { $$ = type; } else { - CPPExtensionType *et = + CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); @@ -1702,7 +1727,7 @@ predefined_type: if (type != NULL) { $$ = type; } else { - CPPExtensionType *et = + CPPExtensionType *et = CPPType::new_type(new CPPExtensionType($1, $2, current_scope, @1.file)) ->as_extension_type(); CPPScope *scope = $2->get_scope(current_scope, global_scope); @@ -1733,9 +1758,9 @@ full_type: anonymous_struct: struct_keyword '{' { - CPPVisibility starting_vis = + CPPVisibility starting_vis = ($1 == CPPExtensionType::T_class) ? V_private : V_public; - + CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("anon"), starting_vis); CPPStructType *st = new CPPStructType($1, NULL, current_scope, @@ -1757,7 +1782,7 @@ anonymous_struct: named_struct: struct_keyword name { - CPPVisibility starting_vis = + CPPVisibility starting_vis = ($1 == CPPExtensionType::T_class) ? V_private : V_public; CPPScope *scope = $2->get_scope(current_scope, global_scope, current_lexer); @@ -1771,7 +1796,7 @@ named_struct: new_scope, @1.file); new_scope->set_struct_type(st); current_scope->define_extension_type(st); - + push_scope(new_scope); push_struct(st); } @@ -1916,7 +1941,7 @@ namespace_declaration: CPPScope *scope = $2->find_scope(current_scope, global_scope, current_lexer); if (scope == NULL) { // This must be a new namespace declaration. - CPPScope *parent_scope = + CPPScope *parent_scope = $2->get_scope(current_scope, global_scope, current_lexer); if (parent_scope == NULL) { parent_scope = current_scope; @@ -2104,13 +2129,13 @@ element: | ELLIPSIS | OROR | ANDAND | EQCOMPARE | NECOMPARE | LECOMPARE | GECOMPARE | LSHIFT | RSHIFT | POINTSAT_STAR | DOT_STAR | POINTSAT - | SCOPE | PLUSPLUS | MINUSMINUS + | SCOPE | PLUSPLUS | MINUSMINUS | TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL | OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL | KW_BOOL | KW_CATCH | KW_CHAR | KW_WCHAR_T | KW_CLASS | KW_CONST | KW_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST | KW_ELSE | KW_ENUM | KW_EXTERN | KW_EXPLICIT | KW_FALSE - | KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO + | KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO | KW_IF | KW_INLINE | KW_INT | KW_LONG | KW_MUTABLE | KW_NEW | KW_PRIVATE | KW_PROTECTED | KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_RETURN @@ -2329,65 +2354,65 @@ const_expr: } | KW_INT '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_CHAR '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_WCHAR_T '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_BOOL '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_bool)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_SHORT '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_short)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_LONG '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_long)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_UNSIGNED '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_unsigned)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_SIGNED '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, CPPSimpleType::F_signed)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_FLOAT '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_float)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } | KW_DOUBLE '(' optional_const_expr_comma ')' { - CPPType *type = + CPPType *type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); } diff --git a/dtool/src/cppparser/cppFunctionType.cxx b/dtool/src/cppparser/cppFunctionType.cxx index 8625f7e721..515729cf39 100644 --- a/dtool/src/cppparser/cppFunctionType.cxx +++ b/dtool/src/cppparser/cppFunctionType.cxx @@ -243,6 +243,9 @@ output_instance(ostream &out, int indent_level, CPPScope *scope, if (_flags & F_const_method) { out << " const"; } + if (_flags & F_noexcept) { + out << " noexcept"; + } } //////////////////////////////////////////////////////////////////// diff --git a/dtool/src/cppparser/cppFunctionType.h b/dtool/src/cppparser/cppFunctionType.h index 021aeba5ce..b728fa7b22 100644 --- a/dtool/src/cppparser/cppFunctionType.h +++ b/dtool/src/cppparser/cppFunctionType.h @@ -36,6 +36,7 @@ public: F_method_pointer = 0x10, F_unary_op = 0x20, F_operator = 0x40, + F_noexcept = 0x80, }; CPPFunctionType(CPPType *return_type, CPPParameterList *parameters, diff --git a/dtool/src/cppparser/cppInstanceIdentifier.cxx b/dtool/src/cppparser/cppInstanceIdentifier.cxx index 8db68d389d..7cd3c67283 100644 --- a/dtool/src/cppparser/cppInstanceIdentifier.cxx +++ b/dtool/src/cppparser/cppInstanceIdentifier.cxx @@ -133,7 +133,7 @@ add_func_modifier(CPPParameterList *params, int flags) { // function, check if the parameter list is empty. If it is, this // is really a unary operator, so set the unary_op flag. Operators // () and [] are never considered unary operators. - if (_ident != NULL && + if (_ident != NULL && _ident->get_simple_name().substr(0, 9) == "operator ") { if (_ident->get_simple_name() != string("operator ()") && @@ -245,7 +245,13 @@ r_unroll_type(CPPType *start_type, break; case IIT_reference: - result = new CPPReferenceType(r_unroll_type(start_type, mi)); + result = new CPPReferenceType(r_unroll_type(start_type, mi), + CPPReferenceType::VC_lvalue); + break; + + case IIT_rvalue_reference: + result = new CPPReferenceType(r_unroll_type(start_type, mi), + CPPReferenceType::VC_rvalue); break; case IIT_scoped_pointer: diff --git a/dtool/src/cppparser/cppInstanceIdentifier.h b/dtool/src/cppparser/cppInstanceIdentifier.h index 7662292c12..b906a4f386 100644 --- a/dtool/src/cppparser/cppInstanceIdentifier.h +++ b/dtool/src/cppparser/cppInstanceIdentifier.h @@ -32,6 +32,7 @@ class CPPPreprocessor; enum CPPInstanceIdentifierType { IIT_pointer, IIT_reference, + IIT_rvalue_reference, IIT_scoped_pointer, IIT_array, IIT_const, diff --git a/dtool/src/cppparser/cppPreprocessor.cxx b/dtool/src/cppparser/cppPreprocessor.cxx index 0911921510..591f856da6 100644 --- a/dtool/src/cppparser/cppPreprocessor.cxx +++ b/dtool/src/cppparser/cppPreprocessor.cxx @@ -2035,6 +2035,7 @@ check_keyword(const string &name) { if (name == "__make_seq") return KW_MAKE_SEQ; if (name == "mutable") return KW_MUTABLE; if (name == "namespace") return KW_NAMESPACE; + if (name == "noexcept") return KW_NOEXCEPT; if (name == "new") return KW_NEW; if (name == "operator") return KW_OPERATOR; if (name == "private") return KW_PRIVATE; diff --git a/dtool/src/cppparser/cppReferenceType.cxx b/dtool/src/cppparser/cppReferenceType.cxx index 7438dfe89f..40d6e987da 100644 --- a/dtool/src/cppparser/cppReferenceType.cxx +++ b/dtool/src/cppparser/cppReferenceType.cxx @@ -21,9 +21,10 @@ // Description: //////////////////////////////////////////////////////////////////// CPPReferenceType:: -CPPReferenceType(CPPType *pointing_at) : +CPPReferenceType(CPPType *pointing_at, ValueCategory vcat) : CPPType(CPPFile()), - _pointing_at(pointing_at) + _pointing_at(pointing_at), + _value_category(vcat) { } @@ -146,8 +147,14 @@ void CPPReferenceType:: output_instance(ostream &out, int indent_level, CPPScope *scope, bool complete, const string &prename, const string &name) const { - _pointing_at->output_instance(out, indent_level, scope, complete, - "&" + prename, name); + + if (_value_category == VC_rvalue) { + _pointing_at->output_instance(out, indent_level, scope, complete, + "&&" + prename, name); + } else { + _pointing_at->output_instance(out, indent_level, scope, complete, + "&" + prename, name); + } } //////////////////////////////////////////////////////////////////// @@ -182,7 +189,8 @@ is_equal(const CPPDeclaration *other) const { const CPPReferenceType *ot = ((CPPDeclaration *)other)->as_reference_type(); assert(ot != NULL); - return _pointing_at == ot->_pointing_at; + return (_pointing_at == ot->_pointing_at) && + (_value_category == ot->_value_category); } @@ -198,5 +206,9 @@ is_less(const CPPDeclaration *other) const { const CPPReferenceType *ot = ((CPPDeclaration *)other)->as_reference_type(); assert(ot != NULL); + if (_value_category != ot->_value_category) { + return (_value_category < ot->_value_category); + } + return _pointing_at < ot->_pointing_at; } diff --git a/dtool/src/cppparser/cppReferenceType.h b/dtool/src/cppparser/cppReferenceType.h index 300db0035c..3bf292841e 100644 --- a/dtool/src/cppparser/cppReferenceType.h +++ b/dtool/src/cppparser/cppReferenceType.h @@ -21,13 +21,22 @@ /////////////////////////////////////////////////////////////////// // Class : CPPReferenceType -// Description : +// Description : Either an lvalue- or rvalue-reference. //////////////////////////////////////////////////////////////////// class CPPReferenceType : public CPPType { public: - CPPReferenceType(CPPType *pointing_at); + enum ValueCategory { + VC_lvalue, + VC_rvalue + }; + + CPPReferenceType(CPPType *pointing_at, ValueCategory vcat=VC_lvalue); CPPType *_pointing_at; + ValueCategory _value_category; + + inline bool is_lvalue() const; + inline bool is_rvalue() const; virtual bool is_fully_specified() const; virtual CPPDeclaration *substitute_decl(SubstDecl &subst, From 8098460433ba5ae3ac38e9021ea0685f269fc2b7 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 2 Jan 2015 15:06:47 +0100 Subject: [PATCH 3/7] Use -fno-exceptions for more performance; disable RTTI in release builds --- makepanda/makepanda.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 04b1df78cd..8bb6a92280 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -1108,8 +1108,6 @@ def CompileCxx(obj,src,opts): cmd += ' -fno-inline-functions-called-once -fgcse-after-reload' cmd += ' -frerun-cse-after-loop -frename-registers' - if not src.endswith(".c"): - cmd += " -fno-exceptions -fno-rtti" cmd += " -Wa,--noexecstack" # Now add specific release/debug flags. @@ -1135,6 +1133,16 @@ def CompileCxx(obj,src,opts): else: cmd += " -pthread" + if not src.endswith(".c"): + # We don't use exceptions. + if 'EXCEPTIONS' not in opts: + cmd += " -fno-exceptions" + + if 'RTTI' not in opts: + # We always disable RTTI on Android for memory usage reasons. + if optlevel >= 4 or GetTarget() == "android": + cmd += " -fno-rtti" + if PkgSkip("SSE2") == 0 and not arch.startswith("arm"): cmd += " -msse2" @@ -2185,6 +2193,10 @@ def WriteConfigSettings(): if (GetOptimize() >= 4): dtool_config["PRC_SAVE_DESCRIPTIONS"] = 'UNDEF' + if (GetOptimize() >= 4): + # Disable RTTI on release builds. + dtool_config["HAVE_RTTI"] = 'UNDEF' + # Now that we have OS_SIMPLE_THREADS, we can support # SIMPLE_THREADS on exotic architectures like win64, so we no # longer need to disable it for this platform. @@ -3665,7 +3677,7 @@ if (PkgSkip("ROCKET") == 0) and (not RUNTIME): TargetAdd('libp3rocket.dll', input=COMMON_PANDA_LIBS) TargetAdd('libp3rocket.dll', opts=OPTS) - OPTS=['DIR:panda/src/rocket', 'ROCKET'] + OPTS=['DIR:panda/src/rocket', 'ROCKET', 'RTTI', 'EXCEPTIONS'] IGATEFILES=GetDirectoryContents('panda/src/rocket', ["rocketInputHandler.h", "rocketInputHandler.cxx", "rocketRegion.h", "rocketRegion.cxx", "rocketRegion_ext.h"]) TargetAdd('libp3rocket.in', opts=OPTS, input=IGATEFILES) From e8905b840cb13113f4d62c58f6730488628d694d Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 2 Jan 2015 15:25:58 +0100 Subject: [PATCH 4/7] Use C++11 move semantics to dramatically improve PointerTo performance --- dtool/src/dtoolbase/dtoolbase_cc.h | 41 +++++++++--------- panda/src/express/pointerTo.I | 68 ++++++++++++++++++++++++++++++ panda/src/express/pointerTo.h | 10 +++++ panda/src/express/pointerToBase.I | 14 ++++++ panda/src/express/pointerToBase.h | 4 ++ 5 files changed, 118 insertions(+), 19 deletions(-) diff --git a/dtool/src/dtoolbase/dtoolbase_cc.h b/dtool/src/dtoolbase/dtoolbase_cc.h index 94891de299..93d90efe48 100644 --- a/dtool/src/dtoolbase/dtoolbase_cc.h +++ b/dtool/src/dtoolbase/dtoolbase_cc.h @@ -34,6 +34,7 @@ using namespace std; #define INLINE inline #define TYPENAME typename #define CONSTEXPR +#define NOEXCEPT noexcept #define EXPORT_TEMPLATE_CLASS(expcl, exptp, classname) @@ -121,15 +122,28 @@ typedef ios::seekdir ios_seekdir; #endif #if defined(__has_extension) // Clang magic. -#if __has_extension(cxx_constexpr) -#define CONSTEXPR constexpr -#else -#define CONSTEXPR INLINE -#endif +# if __has_extension(cxx_constexpr) +# define CONSTEXPR constexpr +# else +# define CONSTEXPR INLINE +# endif +# if __has_extension(cxx_noexcept) +# define NOEXCEPT noexcept +# else +# define NOEXCEPT +# endif +# if __has_extension(cxx_rvalue_references) +# define USE_MOVE_SEMANTICS +# endif #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && (__cplusplus >= 201103L) -#define CONSTEXPR constexpr +// noexcept was introduced in GCC 4.6, constexpr in GCC 4.7, rvalue refs in +// GCC 4.3. However, GCC only started defining __cplusplus properly in 4.7. +# define CONSTEXPR constexpr +# define NOEXCEPT noexcept +# define USE_MOVE_SEMANTICS #else -#define CONSTEXPR INLINE +# define CONSTEXPR INLINE +# define NOEXCEPT #endif #if defined(WIN32_VC) && !defined(LINK_ALL_STATIC) && defined(EXPORT_TEMPLATES) @@ -209,7 +223,7 @@ public: TauProfile(void *&tautimer, char *name, char *type, int group, char *group_name) { Tau_profile_c_timer(&tautimer, name, type, group, group_name); _tautimer = tautimer; - TAU_PROFILE_START(_tautimer); + TAU_PROFILE_START(_tautimer); } ~TauProfile() { if (!__tau_shutdown) { @@ -233,16 +247,5 @@ private: #endif // USE_TAU -// Macros from hell. -#define EXT_METHOD(cl, m) Extension::m() -#define EXT_METHOD_ARGS(cl, m, ...) Extension::m(__VA_ARGS__) -#define EXT_CONST_METHOD(cl, m) Extension::m() const -#define EXT_CONST_METHOD_ARGS(cl, m, ...) Extension::m(__VA_ARGS__) const -#define EXT_NESTED_METHOD(cl1, cl2, m) Extension::m() -#define EXT_NESTED_METHOD_ARGS(cl1, cl2, m, ...) Extension::m(__VA_ARGS__) -#define EXT_NESTED_CONST_METHOD(cl1, cl2, m) Extension::m() const -#define EXT_NESTED_CONST_METHOD_ARGS(cl1, cl2, m, ...) Extension::m(__VA_ARGS__) const -#define CALL_EXT_METHOD(cl, m, obj, ...) invoke_extension(obj).m(__VA_ARGS__) - #endif // __cplusplus #endif diff --git a/panda/src/express/pointerTo.I b/panda/src/express/pointerTo.I index d17d6ed6e8..5b021f8e86 100644 --- a/panda/src/express/pointerTo.I +++ b/panda/src/express/pointerTo.I @@ -35,6 +35,40 @@ PointerTo(const PointerTo ©) : { } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: PointerTo::Move Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PointerTo:: +PointerTo(PointerTo &&move) NOEXCEPT : + PointerToBase((PointerToBase &&)move) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PointerTo::Move Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PointerTo &PointerTo:: +operator = (PointerTo &&move) NOEXCEPT { + To *old_ptr = (To *)this->_void_ptr; + + this->_void_ptr = move._void_ptr; + move._void_ptr = NULL; + + if (old_ptr != (To *)NULL) { + unref_delete(old_ptr); + } + + return *this; +} +#endif + //////////////////////////////////////////////////////////////////// // Function: PointerTo::Destructor // Access: Public @@ -166,6 +200,40 @@ ConstPointerTo(const ConstPointerTo ©) : { } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: ConstPointerTo::Move Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ConstPointerTo:: +ConstPointerTo(ConstPointerTo &&move) NOEXCEPT : + PointerToBase((PointerToBase &&)move) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ConstPointerTo::Move Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ConstPointerTo &ConstPointerTo:: +operator = (ConstPointerTo &&move) NOEXCEPT { + To *old_ptr = (To *)this->_void_ptr; + + this->_void_ptr = move._void_ptr; + move._void_ptr = NULL; + + if (old_ptr != (To *)NULL) { + unref_delete(old_ptr); + } + + return *this; +} +#endif + //////////////////////////////////////////////////////////////////// // Function: ConstPointerTo::Dereference operator // Access: Public diff --git a/panda/src/express/pointerTo.h b/panda/src/express/pointerTo.h index 144bc0eb87..e93ef68f80 100644 --- a/panda/src/express/pointerTo.h +++ b/panda/src/express/pointerTo.h @@ -85,6 +85,11 @@ PUBLISHED: INLINE ~PointerTo(); public: +#ifdef USE_MOVE_SEMANTICS + INLINE PointerTo(PointerTo &&move) NOEXCEPT; + INLINE PointerTo &operator = (PointerTo &&move) NOEXCEPT; +#endif + INLINE To &operator *() const; INLINE To *operator -> () const; // MSVC.NET 2005 insists that we use T *, and not To *, here. @@ -144,6 +149,11 @@ PUBLISHED: INLINE ~ConstPointerTo(); public: +#ifdef USE_MOVE_SEMANTICS + INLINE ConstPointerTo(ConstPointerTo &&move) NOEXCEPT; + INLINE ConstPointerTo &operator = (ConstPointerTo &&move) NOEXCEPT; +#endif + INLINE const To &operator *() const; INLINE const To *operator -> () const; INLINE operator const T *() const; diff --git a/panda/src/express/pointerToBase.I b/panda/src/express/pointerToBase.I index df0b635093..f6c5e192fd 100644 --- a/panda/src/express/pointerToBase.I +++ b/panda/src/express/pointerToBase.I @@ -35,6 +35,20 @@ PointerToBase(const PointerToBase ©) { reassign(copy); } +//////////////////////////////////////////////////////////////////// +// Function: PointerToBase::Move Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +#ifdef USE_MOVE_SEMANTICS +template +INLINE PointerToBase:: +PointerToBase(PointerToBase &&move) NOEXCEPT { + _void_ptr = move._void_ptr; + move._void_ptr = (void *)NULL; +} +#endif + //////////////////////////////////////////////////////////////////// // Function: PointerToBase::Destructor // Access: Protected diff --git a/panda/src/express/pointerToBase.h b/panda/src/express/pointerToBase.h index dd8a610188..495033ff71 100644 --- a/panda/src/express/pointerToBase.h +++ b/panda/src/express/pointerToBase.h @@ -38,6 +38,10 @@ protected: INLINE PointerToBase(const PointerToBase ©); INLINE ~PointerToBase(); +#ifdef USE_MOVE_SEMANTICS + INLINE PointerToBase(PointerToBase &&move) NOEXCEPT; +#endif + INLINE void reassign(To *ptr); INLINE void reassign(const PointerToBase ©); From 5e5a04031f68c5cb1737223d66bd84e37f29f354 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 2 Jan 2015 15:26:47 +0100 Subject: [PATCH 5/7] Remove old decal system to simplify cull/draw process a bit more --- panda/src/pgraph/config_pgraph.cxx | 8 +- panda/src/pgraph/cullBin.cxx | 57 +---- panda/src/pgraph/cullResult.cxx | 74 +----- panda/src/pgraph/cullResult.h | 7 +- panda/src/pgraph/cullTraverser.I | 8 +- panda/src/pgraph/cullTraverser.cxx | 370 +++++----------------------- panda/src/pgraph/cullTraverser.h | 9 +- panda/src/pgraph/cullableObject.I | 118 ++------- panda/src/pgraph/cullableObject.cxx | 120 +-------- panda/src/pgraph/cullableObject.h | 30 +-- 10 files changed, 132 insertions(+), 669 deletions(-) diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 840ce5ba4e..639f7f4a5a 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -257,12 +257,12 @@ ConfigVariableBool retransform_sprites "necessary in order for fog to work correctly on the sprites.")); ConfigVariableBool depth_offset_decals -("depth-offset-decals", false, +("depth-offset-decals", true, PRC_DESC("Set this true to allow decals to be implemented via the advanced " "depth offset feature, if supported, instead of via the traditional " - "(and slower) two-pass approach. This is false by default " - "because it appears that many graphics drivers have issues with " - "their depth offset implementation.")); + "(and slower) two-pass approach. This is currently the only method " + "by which decals are implemented in Panda3D, and as such, this " + "setting is ignored.")); ConfigVariableInt max_collect_vertices ("max-collect-vertices", 65534, diff --git a/panda/src/pgraph/cullBin.cxx b/panda/src/pgraph/cullBin.cxx index 3c16739197..ce1a97c402 100644 --- a/panda/src/pgraph/cullBin.cxx +++ b/panda/src/pgraph/cullBin.cxx @@ -27,7 +27,7 @@ TypeHandle CullBin::_type_handle; //////////////////////////////////////////////////////////////////// // Function: CullBin::Destructor // Access: Public, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// CullBin:: ~CullBin() { @@ -115,7 +115,7 @@ check_flash_color() { } else { _has_flash_color = false; pgraph_cat.warning() - << "Invalid value for flash-bin-" << _name << ": " + << "Invalid value for flash-bin-" << _name << ": " << flash_bin.get_string_value() << "\n"; } #endif // NDEBUG @@ -124,7 +124,7 @@ check_flash_color() { //////////////////////////////////////////////////////////////////// // Function: CullBin::ResultGraphBuilder::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// CullBin::ResultGraphBuilder:: ResultGraphBuilder(PandaNode *root_node) : @@ -142,9 +142,8 @@ ResultGraphBuilder(PandaNode *root_node) : //////////////////////////////////////////////////////////////////// void CullBin::ResultGraphBuilder:: add_object(CullableObject *object) { - if (_current_transform != object->_modelview_transform || - _current_state != object->_state || - object->is_fancy()) { + if (_current_transform != object->_modelview_transform || + _current_state != object->_state) { // Create a new GeomNode to hold the net transform and state. We // choose to create a new GeomNode for each new state, to make it // clearer to the observer when the state changes. @@ -157,57 +156,13 @@ add_object(CullableObject *object) { } record_one_object(_current_node, object); - - if (object->get_next() != (CullableObject *)NULL) { - // Collect the decal base pieces. - CullableObject *base = object->get_next(); - while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) { - record_one_object(_current_node, base); - base = base->get_next(); - } - - if (base != (CullableObject *)NULL) { - // Now, collect all the decals. - _current_node->set_effect(DecalEffect::make()); - int decal_index = 0; - - CPT(TransformState) transform; - CPT(RenderState) state; - PT(GeomNode) decal_node; - CullableObject *decal = base->get_next(); - while (decal != (CullableObject *)NULL) { - if (transform != decal->_modelview_transform || - state != decal->_state || - decal->get_next() != (CullableObject *)NULL) { - // Create a new GeomNode to hold the net transform. - transform = decal->_modelview_transform; - state = decal->_state; - decal_node = new GeomNode("decal_" + format_string(decal_index)); - _current_node->add_child(decal_node); - decal_node->set_transform(transform); - decal_node->set_state(state); - } - - record_one_object(decal_node, decal); - decal = decal->get_next(); - ++decal_index; - } - } - - // Reset the current node pointer for next time so the decal root - // will remain in its own node. - _current_node.clear(); - _current_transform.clear(); - _current_state.clear(); - } - ++_object_index; } //////////////////////////////////////////////////////////////////// // Function: CullBin::ResultGraphBuilder::record_one_object // Access: Private -// Description: Records a single object, without regard to decalling. +// Description: Records a single object. //////////////////////////////////////////////////////////////////// void CullBin::ResultGraphBuilder:: record_one_object(GeomNode *node, CullableObject *object) { diff --git a/panda/src/pgraph/cullResult.cxx b/panda/src/pgraph/cullResult.cxx index 4868d46529..cd795c489f 100644 --- a/panda/src/pgraph/cullResult.cxx +++ b/panda/src/pgraph/cullResult.cxx @@ -57,7 +57,7 @@ static const double bin_color_flash_rate = 1.0; // 1 state change per second //////////////////////////////////////////////////////////////////// // Function: CullResult::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// CullResult:: CullResult(GraphicsStateGuardianBase *gsg, @@ -87,7 +87,7 @@ make_next() const { for (size_t i = 0; i < _bins.size(); ++i) { CullBin *old_bin = _bins[i]; - if (old_bin == (CullBin *)NULL || + if (old_bin == (CullBin *)NULL || old_bin->get_bin_type() != bin_manager->get_bin_type(i)) { new_result->_bins.push_back((CullBin *)NULL); } else { @@ -166,21 +166,19 @@ add_object(CullableObject *object, const CullTraverser *traverser) { // later. This means we must copy the object and add it to // both bins. We can only do this if we do not have an // explicit bin already applied; otherwise, M_dual falls back - // to M_alpha. + // to M_alpha. { const CullBinAttrib *bin_attrib = DCAST(CullBinAttrib, state->get_attrib(CullBinAttrib::get_class_slot())); - if (bin_attrib == (CullBinAttrib *)NULL || + if (bin_attrib == (CullBinAttrib *)NULL || bin_attrib->get_bin_name().empty()) { - // We make a copy of the object to draw the transparent part - // without decals; this gets placed in the transparent bin. + // We make a copy of the object to draw the transparent part; + // this gets placed in the transparent bin. #ifndef NDEBUG - if (m_dual_transparent) + if (m_dual_transparent) #endif { CullableObject *transparent_part = new CullableObject(*object); - CPT(RenderState) transparent_state = object->has_decals() ? - get_dual_transparent_state_decals() : - get_dual_transparent_state(); + CPT(RenderState) transparent_state = get_dual_transparent_state(); transparent_part->_state = state->compose(transparent_state); if (transparent_part->munge_geom (_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread), @@ -195,9 +193,9 @@ add_object(CullableObject *object, const CullTraverser *traverser) { delete transparent_part; } } - - // Now we can draw the opaque part, with decals. This will - // end up in the opaque bin. + + // Now we can draw the opaque part. This will end up in + // the opaque bin. object->_state = state->compose(get_dual_opaque_state()); #ifndef NDEBUG if (!m_dual_opaque) { @@ -210,7 +208,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) { // M_alpha. } break; - + default: // Other kinds of transparency need no special handling. break; @@ -443,8 +441,6 @@ check_flash_transparency(CPT(RenderState) &state, const LColor &transparency) { // Access: Private // Description: Returns a RenderState that renders only the // transparent parts of an object, in support of M_dual. -// This state is suitable only for objects that do not -// contain decals. //////////////////////////////////////////////////////////////////// CPT(RenderState) CullResult:: get_dual_transparent_state() { @@ -454,10 +450,7 @@ get_dual_transparent_state() { // and hence filling up the depth buffer with large empty spaces // that may obscure other things. However, this does mean we draw // pixels twice where the alpha == 1.0 (since they were already - // drawn in the opaque pass). This is not normally a problem, - // except when we are using decals; in the case of decals, we - // don't want to draw the 1.0 pixels again, since these are the - // ones that may have been decaled onto. + // drawn in the opaque pass). This is not normally a problem. state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_greater, 0.0f), TransparencyAttrib::make(TransparencyAttrib::M_alpha), DepthWriteAttrib::make(DepthWriteAttrib::M_off), @@ -487,47 +480,6 @@ get_dual_transparent_state() { return state; } -//////////////////////////////////////////////////////////////////// -// Function: CullResult::get_dual_transparent_state_decals -// Access: Private -// Description: Returns a RenderState that renders only the -// transparent parts of an object, but suitable for -// objects that contain decals. -//////////////////////////////////////////////////////////////////// -CPT(RenderState) CullResult:: -get_dual_transparent_state_decals() { - static CPT(RenderState) state = NULL; - if (state == (const RenderState *)NULL) { - // This is exactly the same as above except here we make the alpha - // test of < 1.0 instead of > 0.0. This makes us draw big empty - // pixels where the alpha values are 0.0, but we don't overwrite - // the decals where the pixels are 1.0. - state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_less, dual_opaque_level), - TransparencyAttrib::make(TransparencyAttrib::M_alpha), - DepthWriteAttrib::make(DepthWriteAttrib::M_off), - RenderState::get_max_priority()); - } - -#ifndef NDEBUG - if (m_dual_flash) { - int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate); - if ((cycle & 1) == 0) { - static CPT(RenderState) flash_state = NULL; - if (flash_state == (const RenderState *)NULL) { - flash_state = state->add_attrib(ColorAttrib::make_flat(LColor(0.8f, 0.2, 0.2, 1.0f)), - RenderState::get_max_priority()); - flash_state = flash_state->add_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)), - RenderState::get_max_priority()); - - } - return flash_state; - } - } -#endif // NDEBUG - - return state; -} - //////////////////////////////////////////////////////////////////// // Function: CullResult::get_dual_opaque_state // Access: Private diff --git a/panda/src/pgraph/cullResult.h b/panda/src/pgraph/cullResult.h index 06b7c1a17b..93604fc558 100644 --- a/panda/src/pgraph/cullResult.h +++ b/panda/src/pgraph/cullResult.h @@ -72,12 +72,11 @@ private: static CPT(RenderState) get_alpha_state(); static CPT(RenderState) get_binary_state(); static CPT(RenderState) get_dual_transparent_state(); - static CPT(RenderState) get_dual_transparent_state_decals(); static CPT(RenderState) get_dual_opaque_state(); GraphicsStateGuardianBase *_gsg; PStatCollector _draw_region_pcollector; - + typedef pvector< PT(CullBin) > Bins; Bins _bins; @@ -90,7 +89,7 @@ public: register_type(_type_handle, "CullResult", ReferenceCount::get_class_type()); } - + private: static TypeHandle _type_handle; }; @@ -99,5 +98,3 @@ private: #endif - - diff --git a/panda/src/pgraph/cullTraverser.I b/panda/src/pgraph/cullTraverser.I index 7ee69834e2..291221b2de 100644 --- a/panda/src/pgraph/cullTraverser.I +++ b/panda/src/pgraph/cullTraverser.I @@ -110,12 +110,12 @@ get_initial_state() const { //////////////////////////////////////////////////////////////////// // Function: CullTraverser::get_depth_offset_decals // Access: Published -// Description: Returns the depth_offset_decals flag. See -// set_depth_offset_decals(). +// Description: Returns true, as depth offsets are the only way +// that we implement decals nowadays. //////////////////////////////////////////////////////////////////// INLINE bool CullTraverser:: get_depth_offset_decals() const { - return _depth_offset_decals; + return true; } //////////////////////////////////////////////////////////////////// @@ -199,7 +199,7 @@ get_cull_handler() const { //////////////////////////////////////////////////////////////////// // Function: CullTraverser::set_portal_clipper // Access: Published -// Description: Specifies _portal_clipper object pointer that +// Description: Specifies _portal_clipper object pointer that // subsequent traverse() or traverse_below may use. //////////////////////////////////////////////////////////////////// INLINE void CullTraverser:: diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index 308d52f3b7..292e81565e 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -47,7 +47,7 @@ TypeHandle CullTraverser::_type_handle; //////////////////////////////////////////////////////////////////// // Function: CullTraverser::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CullTraverser:: CullTraverser() : @@ -65,7 +65,7 @@ CullTraverser() : //////////////////////////////////////////////////////////////////// // Function: CullTraverser::Copy Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CullTraverser:: CullTraverser(const CullTraverser ©) : @@ -76,7 +76,6 @@ CullTraverser(const CullTraverser ©) : _has_tag_state_key(copy._has_tag_state_key), _tag_state_key(copy._tag_state_key), _initial_state(copy._initial_state), - _depth_offset_decals(copy._depth_offset_decals), _view_frustum(copy._view_frustum), _cull_handler(copy._cull_handler), _portal_clipper(copy._portal_clipper), @@ -98,7 +97,6 @@ set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg, _gsg = gsg; _initial_state = scene_setup->get_initial_state(); - _depth_offset_decals = _gsg->depth_offset_decals() && depth_offset_decals; _current_thread = Thread::get_current_thread(); @@ -129,43 +127,43 @@ traverse(const NodePath &root) { PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds(); if (bv != (BoundingVolume *)NULL && bv->is_of_type(GeometricBoundingVolume::get_class_type())) { - + local_frustum = DCAST(GeometricBoundingVolume, bv); } - + // This local_frustum is in camera space PortalClipper portal_viewer(local_frustum, _scene_setup); if (debug_portal_cull) { portal_viewer.draw_camera_frustum(); } - + // Store this pointer in this set_portal_clipper(&portal_viewer); CullTraverserData data(root, TransformState::make_identity(), - _initial_state, _view_frustum, + _initial_state, _view_frustum, _current_thread); - + traverse(data); - + // Finally add the lines to be drawn if (debug_portal_cull) { portal_viewer.draw_lines(); } - + // Render the frustum relative to the cull center. NodePath cull_center = _scene_setup->get_cull_center(); CPT(TransformState) transform = cull_center.get_transform(root); - + CullTraverserData my_data(data, portal_viewer._previous); my_data._net_transform = my_data._net_transform->compose(transform); traverse(my_data); } else { CullTraverserData data(root, TransformState::make_identity(), - _initial_state, _view_frustum, + _initial_state, _view_frustum, _current_thread); - + traverse(data); } } @@ -181,7 +179,7 @@ void CullTraverser:: traverse(CullTraverserData &data) { if (is_in_view(data)) { if (pgraph_cat.is_spam()) { - pgraph_cat.spam() + pgraph_cat.spam() << "\n" << data._node_path << " " << data._draw_mask << "\n"; } @@ -207,9 +205,9 @@ traverse(CullTraverserData &data) { // up now. show_bounds(data, node_effects->has_show_tight_bounds()); } - + data.apply_transform_and_state(this); - + const FogAttrib *fog = DCAST(FogAttrib, node_reader->get_state()->get_attrib(FogAttrib::get_class_slot())); if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) { // If we just introduced a FogAttrib here, call adjust_to_camera() @@ -218,7 +216,7 @@ traverse(CullTraverserData &data) { // need for it. fog->get_fog()->adjust_to_camera(get_camera_transform()); } - + if (fancy_bits & PandaNode::FB_cull_callback) { PandaNode *node = data.node(); if (!node->cull_callback(this, data)) { @@ -247,47 +245,41 @@ traverse_below(CullTraverserData &data) { const RenderEffects *node_effects = node_reader->get_effects(); bool has_decal = !this_node_hidden && node_effects->has_decal(); - if (has_decal && !_depth_offset_decals) { - // Start the three-pass decal rendering if we're not using - // DepthOffsetAttribs to implement decals. - start_decal(data); - - } else { - if (!this_node_hidden) { - node->add_for_draw(this, data); - } - if (has_decal) { - // If we *are* implementing decals with DepthOffsetAttribs, - // apply it now, so that each child of this node gets offset by - // a tiny amount. - data._state = data._state->compose(get_depth_offset_state()); + if (!this_node_hidden) { + node->add_for_draw(this, data); + } + + if (has_decal) { + // If we *are* implementing decals with DepthOffsetAttribs, + // apply it now, so that each child of this node gets offset by + // a tiny amount. + data._state = data._state->compose(get_depth_offset_state()); #ifndef NDEBUG - // This is just a sanity check message. - if (!node->is_geom_node()) { - pgraph_cat.error() - << "DecalEffect applied to " << *node << ", not a GeomNode.\n"; - } + // This is just a sanity check message. + if (!node->is_geom_node()) { + pgraph_cat.error() + << "DecalEffect applied to " << *node << ", not a GeomNode.\n"; + } #endif + } + + // Now visit all the node's children. + PandaNode::Children children = node_reader->get_children(); + node_reader->release(); + int num_children = children.get_num_children(); + if (node->has_selective_visibility()) { + int i = node->get_first_visible_child(); + while (i < num_children) { + CullTraverserData next_data(data, children.get_child(i)); + traverse(next_data); + i = node->get_next_visible_child(i); } - // Now visit all the node's children. - PandaNode::Children children = node_reader->get_children(); - node_reader->release(); - int num_children = children.get_num_children(); - if (node->has_selective_visibility()) { - int i = node->get_first_visible_child(); - while (i < num_children) { - CullTraverserData next_data(data, children.get_child(i)); - traverse(next_data); - i = node->get_next_visible_child(i); - } - - } else { - for (int i = 0; i < num_children; i++) { - CullTraverserData next_data(data, children.get_child(i)); - traverse(next_data); - } + } else { + for (int i = 0; i < num_children; i++) { + CullTraverserData next_data(data, children.get_child(i)); + traverse(next_data); } } } @@ -311,20 +303,20 @@ end_traverse() { // bounding volume. //////////////////////////////////////////////////////////////////// void CullTraverser:: -draw_bounding_volume(const BoundingVolume *vol, +draw_bounding_volume(const BoundingVolume *vol, const TransformState *net_transform, const TransformState *modelview_transform) const { PT(Geom) bounds_viz = make_bounds_viz(vol); - + if (bounds_viz != (Geom *)NULL) { _geoms_pcollector.add_level(2); - CullableObject *outer_viz = - new CullableObject(bounds_viz, get_bounds_outer_viz_state(), + CullableObject *outer_viz = + new CullableObject(bounds_viz, get_bounds_outer_viz_state(), net_transform, modelview_transform, get_scene()); _cull_handler->record_object(outer_viz, this); - - CullableObject *inner_viz = - new CullableObject(bounds_viz, get_bounds_inner_viz_state(), + + CullableObject *inner_viz = + new CullableObject(bounds_viz, get_bounds_inner_viz_state(), net_transform, modelview_transform, get_scene()); _cull_handler->record_object(inner_viz, this); } @@ -360,13 +352,13 @@ show_bounds(CullTraverserData &data, bool tight) { if (bounds_viz != (Geom *)NULL) { _geoms_pcollector.add_level(1); - CullableObject *outer_viz = - new CullableObject(bounds_viz, get_bounds_outer_viz_state(), + CullableObject *outer_viz = + new CullableObject(bounds_viz, get_bounds_outer_viz_state(), net_transform, modelview_transform, get_scene()); _cull_handler->record_object(outer_viz, this); } - + } else { draw_bounding_volume(node->get_bounds(), net_transform, modelview_transform); @@ -378,7 +370,7 @@ show_bounds(CullTraverserData &data, bool tight) { GeomNode *gnode = DCAST(GeomNode, node); int num_geoms = gnode->get_num_geoms(); for (int i = 0; i < num_geoms; ++i) { - draw_bounding_volume(gnode->get_geom(i)->get_bounds(), + draw_bounding_volume(gnode->get_geom(i)->get_bounds(), net_transform, modelview_transform); } } @@ -407,7 +399,7 @@ make_bounds_viz(const BoundingVolume *vol) { ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream); GeomVertexWriter vertex(vdata, InternalName::get_vertex()); - + PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream); for (int sl = 0; sl < num_slices; ++sl) { PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices; @@ -419,11 +411,11 @@ make_bounds_viz(const BoundingVolume *vol) { vertex.add_data3(compute_point(sphere, latitude, longitude1)); } vertex.add_data3(compute_point(sphere, 1.0, longitude0)); - + strip->add_next_vertices(num_stacks * 2); strip->close_primitive(); } - + geom = new Geom(vdata); geom->add_primitive(strip); @@ -438,7 +430,7 @@ make_bounds_viz(const BoundingVolume *vol) { for (int i = 0; i < 8; ++i ) { vertex.add_data3(fvol->get_point(i)); } - + PT(GeomLines) lines = new GeomLines(Geom::UH_stream); lines->add_vertices(0, 1); lines->close_primitive(); lines->add_vertices(1, 2); lines->close_primitive(); @@ -472,7 +464,7 @@ make_bounds_viz(const BoundingVolume *vol) { for (int i = 0; i < 8; ++i ) { vertex.add_data3(box.get_point(i)); } - + PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_stream); tris->add_vertices(0, 4, 5); tris->close_primitive(); @@ -533,7 +525,7 @@ make_tight_bounds_viz(PandaNode *node) const { Geom::UH_stream); GeomVertexWriter vertex(vdata, InternalName::get_vertex(), _current_thread); - + vertex.add_data3(n[0], n[1], n[2]); vertex.add_data3(n[0], n[1], x[2]); vertex.add_data3(n[0], x[1], n[2]); @@ -542,7 +534,7 @@ make_tight_bounds_viz(PandaNode *node) const { vertex.add_data3(x[0], n[1], x[2]); vertex.add_data3(x[0], x[1], n[2]); vertex.add_data3(x[0], x[1], x[2]); - + PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream); // We wind one long linestrip around the wireframe cube. This @@ -564,7 +556,7 @@ make_tight_bounds_viz(PandaNode *node) const { strip->add_vertex(5); strip->add_vertex(1); strip->close_primitive(); - + geom = new Geom(vdata); geom->add_primitive(strip); } @@ -576,10 +568,10 @@ make_tight_bounds_viz(PandaNode *node) const { // Function: CullTraverser::compute_point // Access: Private, Static // Description: Returns a point on the surface of the sphere. -// latitude and longitude range from 0.0 to 1.0. +// latitude and longitude range from 0.0 to 1.0. //////////////////////////////////////////////////////////////////// LVertex CullTraverser:: -compute_point(const BoundingSphere *sphere, +compute_point(const BoundingSphere *sphere, PN_stdfloat latitude, PN_stdfloat longitude) { PN_stdfloat s1, c1; csincos(latitude * MathNumbers::pi, &s1, &c1); @@ -648,231 +640,3 @@ get_depth_offset_state() { } return state; } - - -//////////////////////////////////////////////////////////////////// -// Function: CullTraverser::start_decal -// Access: Private -// Description: Collects a base node and all of the decals applied to -// it. This involves recursing below the base GeomNode -// to find all the decal geoms. -//////////////////////////////////////////////////////////////////// -void CullTraverser:: -start_decal(const CullTraverserData &data) { - PandaNode *node = data.node(); - if (!node->is_geom_node()) { - pgraph_cat.error() - << "DecalEffect applied to " << *node << ", not a GeomNode.\n"; - return; - } - - const PandaNodePipelineReader *node_reader = data.node_reader(); - - // Build a chain of CullableObjects. The head of the chain will be - // all of the base Geoms in order, followed by an empty - // CullableObject node, followed by all of the decal Geoms, in - // order. - - // Since the CullableObject is a linked list which gets built in - // LIFO order, we start with the decals. - CullableObject *decals = (CullableObject *)NULL; - PandaNode::Children cr = node_reader->get_children(); - int num_children = cr.get_num_children(); - if (node->has_selective_visibility()) { - int i = node->get_first_visible_child(); - while (i < num_children) { - CullTraverserData next_data(data, cr.get_child(i)); - decals = r_get_decals(next_data, decals); - i = node->get_next_visible_child(i); - } - - } else { - for (int i = num_children - 1; i >= 0; i--) { - CullTraverserData next_data(data, cr.get_child(i)); - decals = r_get_decals(next_data, decals); - } - } - - // Now create a new, empty CullableObject to separate the decals - // from the non-decals. - CullableObject *separator = new CullableObject; - separator->set_next(decals); - - // And now get the base Geoms, again in reverse order. - CullableObject *object = separator; - GeomNode *geom_node = DCAST(GeomNode, node); - GeomNode::Geoms geoms = geom_node->get_geoms(); - int num_geoms = geoms.get_num_geoms(); - _geoms_pcollector.add_level(num_geoms); - CPT(TransformState) net_transform = data.get_net_transform(this); - CPT(TransformState) modelview_transform = data.get_modelview_transform(this); - CPT(TransformState) internal_transform = _scene_setup->get_cs_transform()->compose(modelview_transform); - - for (int i = num_geoms - 1; i >= 0; i--) { - const Geom *geom = geoms.get_geom(i); - if (geom->is_empty()) { - continue; - } - - CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i)); - if (state->has_cull_callback() && !state->cull_callback(this, data)) { - // Cull. - continue; - } - - // Cull the Geom bounding volume against the view frustum - // and/or the cull planes. Don't bother unless we've got more - // than one Geom, since otherwise the bounding volume of the - // GeomNode is (probably) the same as that of the one Geom, - // and we've already culled against that. - if (num_geoms > 1) { - if (data._view_frustum != (GeometricBoundingVolume *)NULL) { - // Cull the individual Geom against the view frustum. - CPT(BoundingVolume) geom_volume = geom->get_bounds(); - const GeometricBoundingVolume *geom_gbv = - DCAST(GeometricBoundingVolume, geom_volume); - - int result = data._view_frustum->contains(geom_gbv); - if (result == BoundingVolume::IF_no_intersection) { - // Cull this Geom. - continue; - } - } - if (!data._cull_planes->is_empty()) { - // Also cull the Geom against the cull planes. - CPT(BoundingVolume) geom_volume = geom->get_bounds(); - const GeometricBoundingVolume *geom_gbv = - DCAST(GeometricBoundingVolume, geom_volume); - int result; - data._cull_planes->do_cull(result, state, geom_gbv); - if (result == BoundingVolume::IF_no_intersection) { - // Cull. - continue; - } - } - } - - CullableObject *next = object; - object = - new CullableObject(geom, state, net_transform, - modelview_transform, internal_transform); - object->set_next(next); - } - - if (object != separator) { - // Finally, send the whole list down to the CullHandler for - // processing. The first Geom in the node now represents the - // overall state. - _cull_handler->record_object(object, this); - } else { - // Never mind; there's nothing to render. - delete object; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: CullTraverser::r_get_decals -// Access: Private -// Description: Recursively gets all the decals applied to a -// particular GeomNode. These are built into a -// CullableObject list in LIFO order (so that the -// traversing the list will extract them in the order -// they were encountered in the scene graph). -//////////////////////////////////////////////////////////////////// -CullableObject *CullTraverser:: -r_get_decals(CullTraverserData &data, CullableObject *decals) { - if (is_in_view(data)) { - PandaNodePipelineReader *node_reader = data.node_reader(); - PandaNode *node = data.node(); - - const RenderEffects *node_effects = node_reader->get_effects(); - if (node_effects->has_show_bounds()) { - // If we should show the bounding volume for this node, make it - // up now. - show_bounds(data, node_effects->has_show_tight_bounds()); - } - - data.apply_transform_and_state(this); - - // First, visit all of the node's children. - int num_children = node_reader->get_num_children(); - if (node->has_selective_visibility()) { - int i = node->get_first_visible_child(); - while (i < num_children) { - CullTraverserData next_data(data, node_reader->get_child(i)); - decals = r_get_decals(next_data, decals); - i = node->get_next_visible_child(i); - } - - } else { - for (int i = num_children - 1; i >= 0; i--) { - CullTraverserData next_data(data, node_reader->get_child(i)); - decals = r_get_decals(next_data, decals); - } - } - - // Now, tack on any geoms within the node. - if (node->is_geom_node()) { - GeomNode *geom_node = DCAST(GeomNode, node); - GeomNode::Geoms geoms = geom_node->get_geoms(); - int num_geoms = geoms.get_num_geoms(); - _geoms_pcollector.add_level(num_geoms); - CPT(TransformState) net_transform = data.get_net_transform(this); - CPT(TransformState) modelview_transform = data.get_modelview_transform(this); - CPT(TransformState) internal_transform = _scene_setup->get_cs_transform()->compose(modelview_transform); - - for (int i = num_geoms - 1; i >= 0; i--) { - const Geom *geom = geoms.get_geom(i); - if (geom->is_empty()) { - continue; - } - - CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i)); - if (state->has_cull_callback() && !state->cull_callback(this, data)) { - // Cull. - continue; - } - - // Cull the Geom bounding volume against the view frustum - // and/or the cull planes. Don't bother unless we've got more - // than one Geom, since otherwise the bounding volume of the - // GeomNode is (probably) the same as that of the one Geom, - // and we've already culled against that. - if (num_geoms > 1) { - if (data._view_frustum != (GeometricBoundingVolume *)NULL) { - // Cull the individual Geom against the view frustum. - CPT(BoundingVolume) geom_volume = geom->get_bounds(); - const GeometricBoundingVolume *geom_gbv = - DCAST(GeometricBoundingVolume, geom_volume); - - int result = data._view_frustum->contains(geom_gbv); - if (result == BoundingVolume::IF_no_intersection) { - // Cull this Geom. - continue; - } - } - if (!data._cull_planes->is_empty()) { - // Also cull the Geom against the cull planes. - CPT(BoundingVolume) geom_volume = geom->get_bounds(); - const GeometricBoundingVolume *geom_gbv = - DCAST(GeometricBoundingVolume, geom_volume); - int result; - data._cull_planes->do_cull(result, state, geom_gbv); - if (result == BoundingVolume::IF_no_intersection) { - // Cull. - continue; - } - } - } - - CullableObject *next = decals; - decals = - new CullableObject(geom, state, net_transform, - modelview_transform, internal_transform); - decals->set_next(next); - } - } - } - - return decals; -} diff --git a/panda/src/pgraph/cullTraverser.h b/panda/src/pgraph/cullTraverser.h index 5100b0e7eb..4ec772076f 100644 --- a/panda/src/pgraph/cullTraverser.h +++ b/panda/src/pgraph/cullTraverser.h @@ -87,7 +87,7 @@ PUBLISHED: INLINE static void flush_level(); - void draw_bounding_volume(const BoundingVolume *vol, + void draw_bounding_volume(const BoundingVolume *vol, const TransformState *net_transform, const TransformState *modelview_transform) const; @@ -105,7 +105,7 @@ private: void show_bounds(CullTraverserData &data, bool tight); static PT(Geom) make_bounds_viz(const BoundingVolume *vol); PT(Geom) make_tight_bounds_viz(PandaNode *node) const; - static LVertex compute_point(const BoundingSphere *sphere, + static LVertex compute_point(const BoundingSphere *sphere, PN_stdfloat latitude, PN_stdfloat longitude); static CPT(RenderState) get_bounds_outer_viz_state(); static CPT(RenderState) get_bounds_inner_viz_state(); @@ -121,12 +121,11 @@ private: bool _has_tag_state_key; string _tag_state_key; CPT(RenderState) _initial_state; - bool _depth_offset_decals; PT(GeometricBoundingVolume) _view_frustum; CullHandler *_cull_handler; PortalClipper *_portal_clipper; bool _effective_incomplete_render; - + public: static TypeHandle get_class_type() { return _type_handle; @@ -150,4 +149,4 @@ private: #endif - + diff --git a/panda/src/pgraph/cullableObject.I b/panda/src/pgraph/cullableObject.I index a5d7901dce..f9b32825e5 100644 --- a/panda/src/pgraph/cullableObject.I +++ b/panda/src/pgraph/cullableObject.I @@ -12,6 +12,7 @@ // //////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// // Function: CullableObject::Constructor // Access: Public @@ -19,9 +20,7 @@ // filled in later. //////////////////////////////////////////////////////////////////// INLINE CullableObject:: -CullableObject() : - _fancy(false) -{ +CullableObject() { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); #endif @@ -42,8 +41,7 @@ CullableObject(const Geom *geom, const RenderState *state, _state(state), _net_transform(net_transform), _modelview_transform(modelview_transform), - _internal_transform(scene_setup->get_cs_transform()->compose(modelview_transform)), - _fancy(false) + _internal_transform(scene_setup->get_cs_transform()->compose(modelview_transform)) { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); @@ -65,20 +63,17 @@ CullableObject(const Geom *geom, const RenderState *state, _state(state), _net_transform(net_transform), _modelview_transform(modelview_transform), - _internal_transform(internal_transform), - _fancy(false) + _internal_transform(internal_transform) { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); #endif } - //////////////////////////////////////////////////////////////////// // Function: CullableObject::Copy Constructor // Access: Public -// Description: Copies the CullableObject, but does not copy its -// children (decals). +// Description: Copies the CullableObject. //////////////////////////////////////////////////////////////////// INLINE CullableObject:: CullableObject(const CullableObject ©) : @@ -88,8 +83,7 @@ CullableObject(const CullableObject ©) : _state(copy._state), _net_transform(copy._net_transform), _modelview_transform(copy._modelview_transform), - _internal_transform(copy._internal_transform), - _fancy(false) + _internal_transform(copy._internal_transform) { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); @@ -99,12 +93,10 @@ CullableObject(const CullableObject ©) : //////////////////////////////////////////////////////////////////// // Function: CullableObject::Copy Assignment Operator // Access: Public -// Description: Copies the CullableObject, but does not copy its -// children (decals). +// Description: Copies the CullableObject. //////////////////////////////////////////////////////////////////// INLINE void CullableObject:: operator = (const CullableObject ©) { - nassertv(!_fancy); _geom = copy._geom; _munger = copy._munger; _munged_data = copy._munged_data; @@ -112,29 +104,7 @@ operator = (const CullableObject ©) { _net_transform = copy._net_transform; _modelview_transform = copy._modelview_transform; _internal_transform = copy._internal_transform; -} - -//////////////////////////////////////////////////////////////////// -// Function: CullableObject::is_fancy -// Access: Public -// Description: Returns true if the object has something fancy to it: -// decals, maybe, or a draw_callback, that prevents it -// from being rendered inline. -//////////////////////////////////////////////////////////////////// -INLINE bool CullableObject:: -is_fancy() const { - return _fancy; -} - -//////////////////////////////////////////////////////////////////// -// Function: CullableObject::has_decals -// Access: Public -// Description: Returns true if the object has decals associated with -// it. -//////////////////////////////////////////////////////////////////// -INLINE bool CullableObject:: -has_decals() const { - return _fancy && (_next != (CullableObject *)NULL); + _draw_callback = copy._draw_callback; } //////////////////////////////////////////////////////////////////// @@ -146,8 +116,17 @@ has_decals() const { //////////////////////////////////////////////////////////////////// INLINE void CullableObject:: draw(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) { - if (_fancy) { - draw_fancy(gsg, force, current_thread); + if (_draw_callback != (CallbackObject *)NULL) { + // It has a callback associated. + gsg->clear_before_callback(); + gsg->set_state_and_transform(_state, _internal_transform); + GeomDrawCallbackData cbdata(this, gsg, force); + _draw_callback->do_callback(&cbdata); + if (cbdata.get_lost_state()) { + // Tell the GSG to forget its state. + gsg->clear_state_and_transform(); + } + // Now the callback has taken care of drawing. } else { nassertv(_geom != (Geom *)NULL); gsg->set_state_and_transform(_state, _internal_transform); @@ -184,43 +163,7 @@ request_resident() const { //////////////////////////////////////////////////////////////////// INLINE void CullableObject:: set_draw_callback(CallbackObject *draw_callback) { - make_fancy(); - if (draw_callback != _draw_callback) { - if (_draw_callback != (CallbackObject *)NULL) { - unref_delete(_draw_callback); - } - _draw_callback = draw_callback; - if (_draw_callback != (CallbackObject *)NULL) { - _draw_callback->ref(); - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: CullableObject::set_next -// Access: Public -// Description: Sets the next object in the decal chain. This next -// object will be destructed when this object destructs. -//////////////////////////////////////////////////////////////////// -INLINE void CullableObject:: -set_next(CullableObject *next) { - make_fancy(); - nassertv(_next == (CullableObject *)NULL); - _next = next; -} - -//////////////////////////////////////////////////////////////////// -// Function: CullableObject::get_next -// Access: Public -// Description: Returns the next object in the decal chain, or NULL -// for the end of the chain. -//////////////////////////////////////////////////////////////////// -INLINE CullableObject *CullableObject:: -get_next() const { - if (_fancy) { - return _next; - } - return NULL; + _draw_callback = draw_callback; } //////////////////////////////////////////////////////////////////// @@ -233,23 +176,6 @@ flush_level() { _sw_sprites_pcollector.flush_level(); } -//////////////////////////////////////////////////////////////////// -// Function: CullableObject::make_fancy -// Access: Private -// Description: Elevates this object to "fancy" status. This means -// that the additional pointers, like _next and -// _draw_callback, have meaningful values and should be -// examined. -//////////////////////////////////////////////////////////////////// -INLINE void CullableObject:: -make_fancy() { - if (!_fancy) { - _fancy = true; - _draw_callback = NULL; - _next = NULL; - } -} - //////////////////////////////////////////////////////////////////// // Function: CullableObject::draw_inline // Access: Private @@ -266,7 +192,7 @@ draw_inline(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) //////////////////////////////////////////////////////////////////// // Function: CullableObject::SortPoints::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE CullableObject::SortPoints:: SortPoints(const CullableObject::PointData *array) : @@ -288,7 +214,7 @@ operator () (unsigned short a, unsigned short b) const { //////////////////////////////////////////////////////////////////// // Function: CullableObject::SourceFormat::operator < // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool CullableObject::SourceFormat:: operator < (const CullableObject::SourceFormat &other) const { diff --git a/panda/src/pgraph/cullableObject.cxx b/panda/src/pgraph/cullableObject.cxx index b76fc6b445..6d5e2d2e27 100644 --- a/panda/src/pgraph/cullableObject.cxx +++ b/panda/src/pgraph/cullableObject.cxx @@ -30,7 +30,6 @@ #include "geomTriangles.h" #include "light.h" #include "lightMutexHolder.h" -#include "geomDrawCallbackData.h" CullableObject::FormatMap CullableObject::_format_map; LightMutex CullableObject::_format_lock; @@ -180,41 +179,13 @@ munge_geom(GraphicsStateGuardianBase *gsg, #endif } - if (_fancy) { - // Only check the _next pointer if the _fancy flag is set. - if (_next != (CullableObject *)NULL) { - if (_next->_state != (RenderState *)NULL) { - _next->munge_geom(gsg, gsg->get_geom_munger(_next->_state, current_thread), - traverser, force); - } else { - _next->munge_geom(gsg, munger, traverser, force); - } - } - } - return true; } -//////////////////////////////////////////////////////////////////// -// Function: CullableObject::Destructor -// Access: Public -// Description: Automatically deletes the whole chain of these things. -//////////////////////////////////////////////////////////////////// -CullableObject:: -~CullableObject() { - if (_fancy) { - // Only check the _next pointer if the _fancy flag is set. - if (_next != (CullableObject *)NULL) { - delete _next; - } - set_draw_callback(NULL); - } -} - //////////////////////////////////////////////////////////////////// // Function: CullableObject::output // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// void CullableObject:: output(ostream &out) const { @@ -225,7 +196,6 @@ output(ostream &out) const { } } - //////////////////////////////////////////////////////////////////// // Function: CullableObject::munge_points_to_quads // Access: Private @@ -642,7 +612,7 @@ munge_texcoord_light_vector(const CullTraverser *traverser, bool force) { return true; } - if (!_munged_data->has_column(InternalName::get_vertex()) || + if (!_munged_data->has_column(InternalName::get_vertex()) || !_munged_data->has_column(InternalName::get_normal())) { // No vertex or normal; can't compute light vector. return true; @@ -775,97 +745,15 @@ get_flash_hardware_state() { return flash_hardware_state; } -//////////////////////////////////////////////////////////////////// -// Function: CullableObject::draw_fancy -// Access: Private -// Description: Something fancy about this object. Draw it properly. -//////////////////////////////////////////////////////////////////// -void CullableObject:: -draw_fancy(GraphicsStateGuardianBase *gsg, bool force, - Thread *current_thread) { - nassertv(_fancy); - if (_draw_callback != (CallbackObject *)NULL) { - // It has a callback associated. - gsg->clear_before_callback(); - gsg->set_state_and_transform(_state, _internal_transform); - GeomDrawCallbackData cbdata(this, gsg, force); - _draw_callback->do_callback(&cbdata); - if (cbdata.get_lost_state()) { - // Tell the GSG to forget its state. - gsg->clear_state_and_transform(); - } - // Now the callback has taken care of drawing. - - } else if (_next != (CullableObject *)NULL) { - // It has decals. - draw_with_decals(gsg, force, current_thread); - - } else { - // Huh, nothing fancy after all. Somehow the _fancy flag got set - // incorrectly; that's a bug. - gsg->set_state_and_transform(_state, _internal_transform); - draw_inline(gsg, force, current_thread); - nassertv(false); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: CullableObject::draw_with_decals -// Access: Private -// Description: Draws the current CullableObject, assuming it has -// attached decals. -//////////////////////////////////////////////////////////////////// -void CullableObject:: -draw_with_decals(GraphicsStateGuardianBase *gsg, bool force, - Thread *current_thread) { - nassertv(_fancy && _next != (CullableObject *)NULL); - // We draw with a three-step process. - - // First, render all of the base geometry for the first pass. - CPT(RenderState) state = gsg->begin_decal_base_first(); - - CullableObject *base = this; - while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) { - gsg->set_state_and_transform(base->_state->compose(state), base->_internal_transform); - base->draw_inline(gsg, force, current_thread); - - base = base->_next; - } - - if (base != (CullableObject *)NULL) { - // Now, draw all the decals. - state = gsg->begin_decal_nested(); - - CullableObject *decal = base->_next; - while (decal != (CullableObject *)NULL) { - gsg->set_state_and_transform(decal->_state->compose(state), decal->_internal_transform); - decal->draw_inline(gsg, force, current_thread); - decal = decal->_next; - } - } - - // And now, re-draw the base geometry, if required. - state = gsg->begin_decal_base_second(); - if (state != (const RenderState *)NULL) { - base = this; - while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) { - gsg->set_state_and_transform(base->_state->compose(state), base->_internal_transform); - base->draw_inline(gsg, force, current_thread); - - base = base->_next; - } - } -} - //////////////////////////////////////////////////////////////////// // Function: CullableObject::SourceFormat::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// CullableObject::SourceFormat:: SourceFormat(const GeomVertexFormat *format, bool sprite_texcoord) : _format(format), - _sprite_texcoord(sprite_texcoord) + _sprite_texcoord(sprite_texcoord) { _retransform_sprites = retransform_sprites; } diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index 19a8731aca..7d4db8fd0d 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -32,17 +32,17 @@ #include "sceneSetup.h" #include "lightMutex.h" #include "callbackObject.h" +#include "geomDrawCallbackData.h" class CullTraverser; //////////////////////////////////////////////////////////////////// // Class : CullableObject // Description : The smallest atom of cull. This is normally just a -// Geom and its associated state, but it also represent -// a number of Geoms to be drawn together, with a number -// of Geoms decalled onto them. +// Geom and its associated state, but it also contain +// a draw callback. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_PGRAPH CullableObject +class EXPCL_PANDA_PGRAPH CullableObject #ifdef DO_MEMORY_USAGE : public ReferenceCount // We inherit from ReferenceCount just to get the memory type tracking that MemoryUsage provides. #endif // DO_MEMORY_USAGE @@ -57,13 +57,10 @@ public: const TransformState *net_transform, const TransformState *modelview_transform, const TransformState *internal_transform); - + INLINE CullableObject(const CullableObject ©); INLINE void operator = (const CullableObject ©); - INLINE bool is_fancy() const; - INLINE bool has_decals() const; - bool munge_geom(GraphicsStateGuardianBase *gsg, GeomMunger *munger, const CullTraverser *traverser, bool force); @@ -74,11 +71,8 @@ public: INLINE static void flush_level(); INLINE void set_draw_callback(CallbackObject *draw_callback); - INLINE void set_next(CullableObject *next); - INLINE CullableObject *get_next() const; public: - ~CullableObject(); ALLOC_DELETED_CHAIN(CullableObject); void output(ostream &out) const; @@ -91,17 +85,9 @@ public: CPT(TransformState) _net_transform; CPT(TransformState) _modelview_transform; CPT(TransformState) _internal_transform; + PT(CallbackObject) _draw_callback; private: - bool _fancy; - - // Fancy things below. These pointers are only meaningful if - // _fancy, above, is true. - CallbackObject *_draw_callback; - CullableObject *_next; // for decals - -private: - INLINE void make_fancy(); bool munge_points_to_quads(const CullTraverser *traverser, bool force); bool munge_texcoord_light_vector(const CullTraverser *traverser, bool force); @@ -110,10 +96,6 @@ private: INLINE void draw_inline(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread); - void draw_fancy(GraphicsStateGuardianBase *gsg, bool force, - Thread *current_thread); - void draw_with_decals(GraphicsStateGuardianBase *gsg, bool force, - Thread *current_thread); private: // This class is used internally by munge_points_to_quads(). From 3831d445761721f897c11bc993e78a932a622d7e Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 2 Jan 2015 22:38:02 +0100 Subject: [PATCH 6/7] Fix issue with resetting ScissorAttrib state https://www.panda3d.org/forums/viewtopic.php?f=1&t=17505 --- .../glstuff/glGraphicsStateGuardian_src.cxx | 61 ++++++++++++++++--- .../src/glstuff/glGraphicsStateGuardian_src.h | 2 + 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 86a0a3672a..222ae9d977 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -316,6 +316,7 @@ CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) : _force_flush = gl_force_flush; _scissor_enabled = false; + _scissor_attrib_active = false; #ifdef DO_PSTATS if (gl_finish) { @@ -2468,6 +2469,8 @@ prepare_display_region(DisplayRegionPipelineReader *dr) { _draw_buffer_type |= _current_properties->get_aux_mask(); set_draw_buffer(_draw_buffer_type); + int count = dr->get_num_regions(); + if (dr->get_scissor_enabled()) { if (GLCAT.is_spam()) { GLCAT.spam() @@ -2475,6 +2478,7 @@ prepare_display_region(DisplayRegionPipelineReader *dr) { } glEnable(GL_SCISSOR_TEST); _scissor_enabled = true; + _scissor_array.resize(count); } else { if (GLCAT.is_spam()) { GLCAT.spam() @@ -2482,27 +2486,35 @@ prepare_display_region(DisplayRegionPipelineReader *dr) { } glDisable(GL_SCISSOR_TEST); _scissor_enabled = false; + _scissor_array.clear(); } + _scissor_attrib_active = false; + #ifndef OPENGLES if (_supports_viewport_arrays) { - int count = dr->get_num_regions(); - GLfloat *viewports = (GLfloat *)alloca(sizeof(GLfloat) * 4 * count); - GLint *scissors = (GLint *)alloca(sizeof(GLint) * 4 * count); + GLfloat *viewports = (GLfloat *)alloca(sizeof(GLfloat) * 4 * count); + + // We store the scissor regions in a vector since we may need + // to switch back to it in do_issue_scissor. for (int i = 0; i < count; ++i) { - GLint *sr = scissors + i * 4; + LVecBase4i sr; dr->get_region_pixels(i, sr[0], sr[1], sr[2], sr[3]); GLfloat *vr = viewports + i * 4; vr[0] = (GLfloat) sr[0]; vr[1] = (GLfloat) sr[1]; vr[2] = (GLfloat) sr[2]; vr[3] = (GLfloat) sr[3]; + if (_scissor_enabled) { + _scissor_array[i] = sr; + } } _glViewportArrayv(0, count, viewports); - if (dr->get_scissor_enabled()) { - _glScissorArrayv(0, count, scissors); + if (_scissor_enabled) { + _glScissorArrayv(0, count, _scissor_array[0].get_data()); } + if (GLCAT.is_spam()) { GLCAT.spam() << "glViewportArrayv(0, " << count << ", [\n"; @@ -2511,12 +2523,12 @@ prepare_display_region(DisplayRegionPipelineReader *dr) { GLCAT.spam(false) << vr[0] << ", " << vr[1] << ", " << vr[2] << ", " << vr[3] << ",\n"; } GLCAT.spam(false) << "])\n"; - if (dr->get_scissor_enabled()) { + if (_scissor_enabled) { GLCAT.spam() << "glScissorArrayv(0, " << count << ", [\n"; for (int i = 0; i < count; ++i) { - GLint *sr = scissors + i * 4; - GLCAT.spam(false) << sr[0] << ", " << sr[1] << ", " << sr[2] << ", " << sr[3] << ",\n"; + const LVecBase4i &sr = _scissor_array[i]; + GLCAT.spam(false) << sr << ",\n"; } } GLCAT.spam(false) << "])\n"; @@ -2526,9 +2538,13 @@ prepare_display_region(DisplayRegionPipelineReader *dr) { #endif // OPENGLES { glViewport(x, y, width, height); - if (dr->get_scissor_enabled()) { + if (_scissor_enabled) { glScissor(x, y, width, height); + + _scissor_array.resize(1); + _scissor_array[0].set(x, y, width, height); } + if (GLCAT.is_spam()) { GLCAT.spam() << "glViewport(" << x << ", " << y << ", " << width << ", " << height << ")\n"; @@ -11984,5 +12000,30 @@ do_issue_scissor() { << "glScissor(" << x << ", " << y << ", " << width << ", " << height << ")\n"; } glScissor(x, y, width, height); + + _scissor_attrib_active = true; + + } else if (_scissor_attrib_active) { + _scissor_attrib_active = false; + + if (_scissor_array.size() > 0) { + // Scissoring is enabled on the display region. + // Revert to the scissor state specified in the DisplayRegion. + if (_supports_viewport_arrays) { + _glScissorArrayv(0, _scissor_array.size(), _scissor_array[0].get_data()); + } else { + const LVecBase4i sr = _scissor_array[0]; + glScissor(sr[0], sr[1], sr[2], sr[3]); + } + + } else if (_scissor_enabled) { + // The display region had no scissor enabled. Disable scissoring. + if (GLCAT.is_spam()) { + GLCAT.spam() + << "glDisable(GL_SCISSOR_TEST)\n"; + } + glDisable(GL_SCISSOR_TEST); + _scissor_enabled = false; + } } } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index f89a84600b..23786533e6 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -550,6 +550,8 @@ protected: bool _point_perspective; bool _vertex_blending_enabled; bool _scissor_enabled; + bool _scissor_attrib_active; + epvector _scissor_array; #ifndef OPENGLES_1 PT(Shader) _current_shader; From 33ef39b7dbb2ae069c7d4ee2f9fe70617fa8dd69 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 3 Jan 2015 16:33:19 +0100 Subject: [PATCH 7/7] Remove modules that seem obsolete from direct tree --- direct/src/autorestart/Sources.pp | 8 - direct/src/autorestart/autorestart.c | 901 --------------- direct/src/directscripts/Doxyfile.python | 3 +- direct/src/heapq/Sources.pp | 29 - direct/src/heapq/heapq.cxx | 240 ---- direct/src/http/LandingPage.py | 2 +- direct/src/http/LandingPageHTML.py | 2 +- direct/src/http/WebRequest.py | 2 +- direct/src/pyinst/Builder.py | 504 --------- direct/src/pyinst/Sources.pp | 0 direct/src/pyinst/__init__.py | 0 direct/src/pyinst/archive.py | 246 ---- direct/src/pyinst/archive_rt.py | 226 ---- direct/src/pyinst/archivebuilder.py | 81 -- direct/src/pyinst/bindepend.py | 169 --- direct/src/pyinst/carchive.py | 204 ---- direct/src/pyinst/carchive_rt.py | 157 --- direct/src/pyinst/finder.py | 178 --- direct/src/pyinst/icon.py | 138 --- direct/src/pyinst/imputil.py | 487 -------- direct/src/pyinst/installutils.py | 91 -- direct/src/pyinst/ltoc.py | 85 -- direct/src/pyinst/mkarchive.py | 42 - direct/src/pyinst/modulefinder.py | 436 ------- direct/src/pyinst/resource.py | 317 ------ direct/src/pyinst/tocfilter.py | 131 --- direct/src/showbase/ElementTree.py | 1251 --------------------- direct/src/showbase/HTMLTree.py | 2 +- direct/src/showbase/PythonUtil.py | 1 - direct/src/test/ModelScreenShot.py | 71 -- direct/src/test/ModelScreenShotGlobals.py | 6 - direct/src/test/Sources.pp | 0 direct/src/test/__init__.py | 0 33 files changed, 5 insertions(+), 6005 deletions(-) delete mode 100644 direct/src/autorestart/Sources.pp delete mode 100644 direct/src/autorestart/autorestart.c delete mode 100755 direct/src/heapq/Sources.pp delete mode 100755 direct/src/heapq/heapq.cxx delete mode 100644 direct/src/pyinst/Builder.py delete mode 100644 direct/src/pyinst/Sources.pp delete mode 100644 direct/src/pyinst/__init__.py delete mode 100644 direct/src/pyinst/archive.py delete mode 100644 direct/src/pyinst/archive_rt.py delete mode 100644 direct/src/pyinst/archivebuilder.py delete mode 100644 direct/src/pyinst/bindepend.py delete mode 100644 direct/src/pyinst/carchive.py delete mode 100644 direct/src/pyinst/carchive_rt.py delete mode 100644 direct/src/pyinst/finder.py delete mode 100644 direct/src/pyinst/icon.py delete mode 100644 direct/src/pyinst/imputil.py delete mode 100644 direct/src/pyinst/installutils.py delete mode 100644 direct/src/pyinst/ltoc.py delete mode 100644 direct/src/pyinst/mkarchive.py delete mode 100644 direct/src/pyinst/modulefinder.py delete mode 100644 direct/src/pyinst/resource.py delete mode 100644 direct/src/pyinst/tocfilter.py delete mode 100755 direct/src/showbase/ElementTree.py delete mode 100755 direct/src/test/ModelScreenShot.py delete mode 100644 direct/src/test/ModelScreenShotGlobals.py delete mode 100644 direct/src/test/Sources.pp delete mode 100644 direct/src/test/__init__.py diff --git a/direct/src/autorestart/Sources.pp b/direct/src/autorestart/Sources.pp deleted file mode 100644 index a85fc78a17..0000000000 --- a/direct/src/autorestart/Sources.pp +++ /dev/null @@ -1,8 +0,0 @@ -#begin bin_target - // This program only compiles on Unix. - #define BUILD_TARGET $[UNIX_PLATFORM] - #define C++FLAGS -DWITHIN_PANDA - - #define TARGET autorestart - #define SOURCES autorestart.c -#end bin_target diff --git a/direct/src/autorestart/autorestart.c b/direct/src/autorestart/autorestart.c deleted file mode 100644 index bfcad109de..0000000000 --- a/direct/src/autorestart/autorestart.c +++ /dev/null @@ -1,901 +0,0 @@ -/* Filename: autorestart.c - * Created by: drose (05Sep02) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifdef WITHIN_PANDA -#include "dtoolbase.h" -#endif - -#include -#include -#include -#include /* for strerror */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBCURL -#include -#endif - -/* The maximum number of seconds to wait for a process to go away - after issuing SIGTERM. This is only used in watchdog mode, when -W - is provided on the command line. */ -#define MAX_WAITTERM_SEC 10 - -char **params = NULL; -char *logfile_name = NULL; -char *pidfile_name = NULL; -int dont_fork = 0; -char *watchdog_url = NULL; -int watchdog_start_sec = 0; -int watchdog_cycle_sec = 0; -int watchdog_timeout_sec = 0; -char *startup_username = NULL; -char *startup_groupname = NULL; -char *startup_chdir = NULL; -int logfile_fd = -1; -int stop_on_terminate = 0; -int stop_always = 0; -char *respawn_script = NULL; -int respawn_count_time = 0; - -/* If requested, delay these many seconds between restart attempts */ -int respawn_delay_time = 5; - - -/* We shouldn't respawn more than (spam_respawn_count - 1) times over - spam_respawn_time seconds. */ -int spam_respawn_count = 5; -int spam_respawn_time = 60; -int spam_restart_delay_time = 600; /* Optionally, do not exit if we spam too much; simply sleep for this many seconds*/ - - - -pid_t child_pid = 0; -pid_t watchdog_pid = 0; - -#define TIME_BUFFER_SIZE 128 - -/* Keep track of the frequency with which we respawn, so we can report - this to our respawn script. */ -typedef struct respawn_record_struct { - time_t _time; - struct respawn_record_struct *_next; -} respawn_record; - -respawn_record *respawns = NULL; - -int -record_respawn(time_t now) { - /* Records the respawning event in the respawn_record, and returns - the number of respawns in the last respawn_count_time - interval. */ - respawn_record *rec; - respawn_record *next; - int count; - - if (respawn_count_time <= 0) { - /* We're not tracking respawns if respawn_count_time is 0. */ - return 0; - } - - rec = (respawn_record *)malloc(sizeof(respawn_record)); - rec->_time = now; - rec->_next = respawns; - respawns = rec; - - /* Now walk through the rest of the list and count up the number of - respawn events until we reach a record more than - respawn_count_time seconds old. */ - count = 0; - while (rec->_next != NULL && - (now - rec->_time) <= respawn_count_time) { - rec = rec->_next; - count++; - } - - /* The remaining respawn records get removed. */ - next = rec->_next; - rec->_next = NULL; - while (next != NULL) { - rec = next; - next = rec->_next; - free(rec); - } - - return count; -} - -void -invoke_respawn_script(time_t now) { - char buffer[32]; - char *new_command; - int new_command_length; - - /* The process is about to be respawned; run the script that we were - given on the command line. */ - if (respawn_count_time <= 0) { - /* We're not counting respawn times, so just run the script - directly. */ - system(respawn_script); - - } else { - /* We are counting respawn times, so append that information as a - parameter to the command. */ - sprintf(buffer, " %d", record_respawn(now)); - new_command_length = strlen(respawn_script) + strlen(buffer); - new_command = (char *)malloc(new_command_length + 1); - strcpy(new_command, respawn_script); - strcat(new_command, buffer); - assert(strlen(new_command) == new_command_length); - - system(new_command); - - free(new_command); - } -} - -/* A callback function passed to libcurl that simply discards the data - retrieved from the server. We only care about the HTTP status. */ -size_t -watchdog_bitbucket(void *ptr, size_t size, size_t nmemb, void *userdata) { - return size * nmemb; -} - -/* Waits up to timeout_ms for a particular child to terminate. - Returns 0 if the timeout expires. */ -pid_t -waitpid_timeout(pid_t child_pid, int *status_ptr, int timeout_ms) { - pid_t result; - struct timeval now, tv; - int now_ms, start_ms, elapsed_ms; - - gettimeofday(&now, NULL); - start_ms = now.tv_sec * 1000 + now.tv_usec / 1000; - - result = waitpid(child_pid, status_ptr, WNOHANG); - while (result == 0) { - gettimeofday(&now, NULL); - now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; - elapsed_ms = now_ms - start_ms; - - if (elapsed_ms > timeout_ms) { - /* Tired of waiting. */ - return 0; - } - - /* Yield the timeslice and wait some more. */ - tv.tv_sec = 0; - tv.tv_usec = 1; - select(0, NULL, NULL, NULL, &tv); - result = waitpid(child_pid, status_ptr, WNOHANG); - } - if (result == -1) { - perror("waitpid"); - } - - return result; -} - - -/* Poll the requested URL until a failure or timeout occurs, or until - the child terminates on its own. Returns 1 on HTTP failure or - timeout, 0 on self-termination. In either case, *status_ptr is - filled in with the status value returned by waitpid().*/ -int -do_watchdog(int *status_ptr) { -#ifndef HAVE_LIBCURL - fprintf(stderr, "Cannot watchdog; no libcurl available.\n"); - return 0; -#else /* HAVE_LIBCURL */ - - CURL *curl; - CURLcode res; - char error_buffer[CURL_ERROR_SIZE]; - pid_t wresult; - - // Before we start polling the URL, wait at least start milliseconds. - wresult = waitpid_timeout(child_pid, status_ptr, watchdog_start_sec * 1000); - if (wresult == child_pid) { - // The child terminated on its own before we got started. - return 0; - } - - curl = curl_easy_init(); - if (!curl) { - fprintf(stderr, "Cannot watchdog; curl failed to init.\n"); - return 0; - } - - curl_easy_setopt(curl, CURLOPT_URL, watchdog_url); - /*curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);*/ - curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, watchdog_timeout_sec * 1000); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, watchdog_bitbucket); - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "autorestart"); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); - curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1); - - res = curl_easy_perform(curl); - while (res == 0) { - /* 0: The HTTP request finished successfully (but might or might - not have returned an error code like a 404). */ - long http_response = 0; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response); - if ((http_response / 100) != 2) { - /* Anything in the 200 range is deemed success. Anything else - is deemed failure. */ - fprintf(stderr, "%s returned %ld\n", watchdog_url, http_response); - break; - } - - wresult = waitpid_timeout(child_pid, status_ptr, watchdog_cycle_sec * 1000); - if (wresult == child_pid) { - /* The process terminated on its own. Return 0 to indicate this. */ - return 0; - } - - res = curl_easy_perform(curl); - } - - curl_easy_cleanup(curl); - - /* Failed to retrieve the watchdog URL. */ - if (res != 0) { - fprintf(stderr, "Failed to contact %s: %s\n", watchdog_url, error_buffer); - } - - /* Kill the child process and wait for it to go away. */ - kill(child_pid, SIGTERM); - - pid_t result = waitpid_timeout(child_pid, status_ptr, MAX_WAITTERM_SEC * 1000); - if (result != child_pid) { - if (result == -1) { - perror("waitpid"); - } else { - /* SIGTERM didn't make the process die. Try SIGKILL. */ - fprintf(stderr, "Force-killing child process\n"); - kill(child_pid, SIGKILL); - result = waitpid_timeout(child_pid, status_ptr, MAX_WAITTERM_SEC * 1000); - if (result == -1) { - perror("waitpid"); - } - } - } - - /* Return 1 to indicate we killed the child due to an HTTP error. */ - return 1; -#endif /* HAVE_LIBCURL */ -} - -void -exec_process() { - /* First, output the command line to the log file. */ - char **p; - for (p = params; *p != NULL; ++p) { - fprintf(stderr, "%s ", *p); - } - fprintf(stderr, "\n"); - execvp(params[0], params); - fprintf(stderr, "Cannot exec %s: %s\n", params[0], strerror(errno)); - - /* Exit with a status of 0, to indicate to the parent process that - we should stop. */ - exit(0); -} - -int -spawn_process() { - /* Spawns the child process. Returns true if the process terminated - by itself and should be respawned, false if it was explicitly - killed (or some other error condition exists), and it should not - respawn any more. */ - pid_t wresult; - int status; - int error_exit; - - child_pid = fork(); - if (child_pid < 0) { - /* Fork error. */ - perror("fork"); - return 0; - } - - if (child_pid == 0) { - /* Child. Exec the process. */ - fprintf(stderr, "Child pid is %d.\n", getpid()); - exec_process(); - /* Shouldn't get here. */ - exit(1); - } - - /* Parent. */ - - error_exit = 0; - - if (watchdog_url != NULL) { - /* If we're watchdogging, then go check the URL. This function - won't return until the URL fails or the child exits. */ - error_exit = do_watchdog(&status); - - } else { - /* If we're not watchdogging, then just wait for the child to - terminate, and diagnose the reason. */ - wresult = waitpid(child_pid, &status, 0); - if (wresult < 0) { - perror("waitpid"); - return 0; - } - } - - /* Now that we've returned from waitpid, clear the child pid number - so our signal handler doesn't get too confused. */ - child_pid = 0; - - if (error_exit) { - /* An HTTP error exit is a reason to respawn. */ - return 1; - - } else if (WIFSIGNALED(status)) { - int signal = WTERMSIG(status); - fprintf(stderr, "\nprocess caught signal %d.\n\n", signal); - /* A signal exit is a reason to respawn unless the signal is TERM - or KILL. */ - return !stop_on_terminate || (signal != SIGTERM && signal != SIGKILL); - - } else { - int exit_status = WEXITSTATUS(status); - fprintf(stderr, "\nprocess exited with status %d.\n\n", WEXITSTATUS(status)); - /* Normal exit is a reason to respawn if the status indicates failure. */ - return !stop_on_terminate || (exit_status != 0); - } -} - -void -sigterm_handler() { - pid_t wresult; - int status; - time_t now; - char time_buffer[TIME_BUFFER_SIZE]; - - now = time(NULL); - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - - fprintf(stderr, "\nsigterm caught at %s; shutting down.\n", time_buffer); - if (child_pid == 0) { - fprintf(stderr, "no child process.\n\n"); - - } else { - kill(child_pid, SIGTERM); - - wresult = waitpid(child_pid, &status, 0); - if (wresult < 0) { - perror("waitpid"); - } else { - fprintf(stderr, "child process terminated.\n\n"); - } - } - exit(1); -} - -void -sighup_handler() { - time_t now; - char time_buffer[TIME_BUFFER_SIZE]; - - now = time(NULL); - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - - fprintf(stderr, "\nsighup caught at %s.\n", time_buffer); - if (child_pid == 0) { - fprintf(stderr, "no child process.\n\n"); - - } else { - kill(child_pid, SIGHUP); - } -} - -void -sigalarm_handler() { - fprintf(stderr, "sleep epoch was complete.\n"); -} - -void -do_autorestart() { - char time_buffer[TIME_BUFFER_SIZE]; - time_t now; - time_t *spam_respawn = NULL; - int sri, num_sri; - struct sigaction sa; - - if (spam_respawn_count > 1) { - spam_respawn = (time_t *)malloc(sizeof(time_t) * spam_respawn_count); - } - - /* Make our process its own process group. */ - setpgid(0, 0); - - /* Set up a signal handler to trap SIGTERM. */ - sa.sa_handler = sigterm_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - if (sigaction(SIGTERM, &sa, NULL) < 0) { - perror("sigaction"); - } - - /* Set up a signal handler to trap SIGHUP. We pass this into the - child. */ - sa.sa_handler = sighup_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - if (sigaction(SIGHUP, &sa, NULL) < 0) { - perror("sigaction"); - } - - if (logfile_fd >= 0) { - /* If we have a logfile, dup it onto stdout and stderr. */ - dup2(logfile_fd, STDOUT_FILENO); - dup2(logfile_fd, STDERR_FILENO); - close(logfile_fd); - } - - /* Make sure stdin is closed. */ - close(STDIN_FILENO); - - now = time(NULL); - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - fprintf(stderr, "autorestart begun at %s.\n", time_buffer); - - if (pidfile_name != NULL) { - unlink(pidfile_name); - FILE *pidfile = fopen(pidfile_name, "w"); - if (pidfile == NULL) { - fprintf(stderr, "Could not write pidfile %s\n", pidfile_name); - } else { - fprintf(pidfile, "%d\n", getpid()); - fclose(pidfile); - } - } - - sri = 1; - num_sri = 1; - if (spam_respawn_count > 1) { - spam_respawn[1] = now; - } - - while (spawn_process()) { - now = time(NULL); - - if (respawn_script != NULL) { - invoke_respawn_script(now); - } - - if (respawn_delay_time) { - sleep(respawn_delay_time); - } - - /* Make sure we're not respawning too fast. */ - if (spam_respawn_count > 1) { - sri = (sri + 1) % spam_respawn_count; - spam_respawn[sri] = now; - if (num_sri < spam_respawn_count) { - num_sri++; - } else { - time_t last = spam_respawn[(sri + 1) % spam_respawn_count]; - if (now - last < spam_respawn_time) - { - if(!spam_restart_delay_time) - { - fprintf(stderr, "respawning too fast, giving up.\n"); - break; - } - else - { - num_sri = 1; /* reset num_sri */ - fprintf(stderr, "respawning too fast, will sleep for %d seconds.\n", spam_restart_delay_time); - signal (SIGALRM, sigalarm_handler); - alarm(spam_restart_delay_time); - pause(); - signal (SIGALRM, SIG_IGN); - } - } - } - } - - if (stop_always) { - fprintf(stderr, "instructed to not autorestart, exiting.\n"); - break; - } - - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - fprintf(stderr, "respawning at %s.\n", time_buffer); - } - - now = time(NULL); - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - fprintf(stderr, "autorestart terminated at %s.\n", time_buffer); - exit(0); -} - -void -double_fork() { - pid_t child, grandchild, wresult; - int status; - - /* Fork once, then again, to disassociate the child from the command - shell process group. */ - child = fork(); - if (child < 0) { - /* Failure to fork. */ - perror("fork"); - exit(1); - } - - if (child == 0) { - /* Child. Fork again. */ - grandchild = fork(); - if (grandchild < 0) { - perror("fork"); - exit(1); - } - - if (grandchild == 0) { - /* Grandchild. Begin useful work. */ - do_autorestart(); - /* Shouldn't get here. */ - exit(1); - } - - /* Child. Report the new pid, then terminate gracefully. */ - fprintf(stderr, "Spawned, monitoring pid is %d.\n", grandchild); - exit(0); - } - - /* Parent. Wait for the child to terminate, then return. */ - wresult = waitpid(child, &status, 0); - if (wresult < 0) { - perror("waitpid"); - exit(1); - } - - if (!WIFEXITED(status)) { - if (WIFSIGNALED(status)) { - fprintf(stderr, "child caught signal %d unexpectedly.\n", WTERMSIG(status)); - } else { - fprintf(stderr, "child exited with status %d.\n", WEXITSTATUS(status)); - } - exit(1); - } -} - -void -usage() { - fprintf(stderr, - "\n" - "autorestart [opts] program [args . . . ]\n" - "autorestart -h\n\n"); -} - -void -help() { - usage(); - fprintf(stderr, - "This program is used to run a program as a background task and\n" - "automatically restart it should it terminate for any reason other\n" - "than normal exit or explicit user kill.\n\n" - - "If the program exits with a status of 0, indicating successful\n" - "completion, it is not restarted.\n\n" - - "If the program is terminated via a TERM or KILL signal (e.g. via\n" - "kill [pid] or kill -9 [pid]), it is assumed the user meant for the\n" - "process to stop, and it is not restarted.\n\n" - - "Options:\n\n" - - " -l logfilename\n" - " Route stdout and stderr from the child process into the indicated\n" - " log file.\n\n" - - " -p pidfilename\n" - " Write the pid of the monitoring process to the indicated pidfile.\n\n" - " -f\n" - " Don't fork autorestart itself; run it as a foreground process. \n" - " (Normally, autorestart forks itself to run as a background process.)\n" - " In this case, the file named by -p is not used.\n\n" - - " -n\n" - " Do not attempt to restart the process under any circumstance.\n" - " The program can still be used to execute a script on abnormal\n" - " process termination.\n\n" - - " -t\n" - " Stop on terminate: don't restart if the child process exits\n" - " normally or is killed with a SIGTERM. With this flag, the\n" - " child process will be restarted only if it exits with a\n" - " non-zero exit status, or if it is killed with a signal other\n" - " than SIGTERM. Without this flag, the default behavior is to\n" - " restart the child process if it exits for any reason.\n\n" - - " -r count,secs,sleep\n" - " Sleep 'sleep' seconds if the process respawns 'count' times\n" - " within 'secs' seconds. This is designed to prevent respawning\n" - " from using too many system resources if something is wrong with\n" - " the child process. The default value is %d,%d,%d. Use -r 0,0,0\n" - " to disable this feature.\n\n" - - " -s \"command\"\n" - " Run the indicated command or script each time the process is\n" - " respawned, using the system() call. This may be useful, for\n" - " instance, to notify an operator via email each time a respawn\n" - " occurs. If -c is also specified, an additional parameter will\n" - " be appended to the command, indicating the number of times the\n" - " respawn has occurred in the given time interval.\n\n" - - " -c secs\n" - " Specifies the number of seconds over which to count respawn events\n" - " for the purposes of passing an argument to the script named with\n" - " -s.\n\n" - - " -d secs\n" - " Specifies the number of seconds to delay for between restarts.\n" - " The default is %d.\n\n" - -#ifdef HAVE_LIBCURL - " -W watchdog_url,start,cycle,timeout\n" - " Specifies an optional URL to watch while waiting for the process\n" - " to terminate. If this is specified, autorestart will start the process,\n" - " wait start seconds, and then repeatedly poll the indicated URL\n" - " every cycle seconds. If a HTTP failure code is detected,\n" - " or no response is received within timeout seconds, then the\n" - " child is terminated and restarted. The start, cycle, and timeout\n" - " parameters are all required.\n\n" -#endif /* HAVE_LIBCURL */ - - " -U username\n" - " Change to the indicated user upon startup. The logfile is still\n" - " created as the initial user.\n\n" - - " -G groupname\n" - " Change to the indicated group upon startup.\n\n" - - " -D dirname\n" - " Change to the indicated working directory upon startup. The logfile\n" - " is still created relative to the initial startup directory.\n\n" - - " -h\n" - " Output this help information.\n\n", - spam_respawn_count, spam_respawn_time, spam_restart_delay_time, respawn_delay_time); -} - -void -parse_int_triplet(char *param, int *a, int *b, int *c) { - char *comma; - char *comma2; - - comma = strchr(param, ','); - if (comma == NULL) { - fprintf(stderr, "Comma required: %s\n", param); - exit(1); - } - - comma2 = strchr(comma+1, ','); - if (comma2 == NULL) { - fprintf(stderr, "Second comma required: %s\n", param); - exit(1); - } - - *comma = '\0'; - *comma2 = '\0'; - - *a = atoi(param); - *b = atoi(comma + 1); - *c = atoi(comma2 + 1); -} - -void -parse_watchdog(char *param) { - char *comma; - char *comma2; - char *comma3; - -#ifndef HAVE_LIBCURL - fprintf(stderr, "-W requires autorestart to have been compiled with libcurl support.\n"); - exit(1); -#endif /* HAVE_LIBCURL */ - - comma = strrchr(param, ','); - if (comma == NULL) { - fprintf(stderr, "Comma required: %s\n", param); - exit(1); - } - *comma = '\0'; - - comma2 = strrchr(param, ','); - if (comma2 == NULL) { - *comma = ','; - fprintf(stderr, "Second comma required: %s\n", param); - exit(1); - } - *comma2 = '\0'; - - comma3 = strrchr(param, ','); - if (comma3 == NULL) { - *comma = ','; - *comma2 = ','; - fprintf(stderr, "Third comma required: %s\n", param); - exit(1); - } - *comma3 = '\0'; - - watchdog_url = param; - watchdog_start_sec = atoi(comma3 + 1); - watchdog_cycle_sec = atoi(comma2 + 1); - watchdog_timeout_sec = atoi(comma + 1); -} - - -int -main(int argc, char *argv[]) { - extern char *optarg; - extern int optind; - /* The initial '+' instructs GNU getopt not to reorder switches. */ - static const char *optflags = "+l:p:fntr:s:c:d:W:U:G:D:h"; - int flag; - - flag = getopt(argc, argv, optflags); - while (flag != EOF) { - switch (flag) { - case 'l': - logfile_name = optarg; - break; - - case 'p': - pidfile_name = optarg; - break; - - case 'f': - dont_fork = 1; - break; - - case 'n': - stop_always = 1; - break; - - case 't': - stop_on_terminate = 1; - break; - - case 'r': - parse_int_triplet(optarg, &spam_respawn_count, &spam_respawn_time, &spam_restart_delay_time); - break; - - case 's': - respawn_script = optarg; - break; - - case 'c': - respawn_count_time = atoi(optarg); - break; - - case 'd': - respawn_delay_time = atoi(optarg); - break; - - case 'W': - parse_watchdog(optarg); - break; - - case 'U': - startup_username = optarg; - break; - - case 'G': - startup_groupname = optarg; - break; - - case 'D': - startup_chdir = optarg; - break; - - case 'h': - help(); - return 1; - - case '?': - case '+': - usage(); - return 1; - - default: - fprintf(stderr, "Unhandled switch: -%c\n", flag); - return 1; - } - flag = getopt(argc, argv, optflags); - } - - argc -= (optind - 1); - argv += (optind - 1); - - if (argc < 2) { - fprintf(stderr, "No program to execute given.\n"); - usage(); - return 1; - } - - params = &argv[1]; - - if (logfile_name != NULL) { - logfile_fd = open(logfile_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (logfile_fd < 0) { - fprintf(stderr, "Cannot write to logfile %s: %s\n", - logfile_name, strerror(errno)); - return 1; - } - fprintf(stderr, "Generating output to %s.\n", logfile_name); - } - - if (startup_chdir != NULL) { - if (chdir(startup_chdir) != 0) { - perror(startup_chdir); - return 1; - } - } - - if (startup_groupname != NULL) { - struct group *grp; - grp = getgrnam(startup_groupname); - if (grp == NULL) { - perror(startup_groupname); - return 1; - } - - if (setgid(grp->gr_gid) != 0) { - perror(startup_groupname); - return 1; - } - } - - if (startup_username != NULL) { - struct passwd *pwd; - pwd = getpwnam(startup_username); - if (pwd == NULL) { - perror(startup_username); - return 1; - } - - if (setuid(pwd->pw_uid) != 0) { - perror(startup_username); - return 1; - } - } - - if (dont_fork) { - do_autorestart(); - } else { - double_fork(); - } - - return 0; -} - diff --git a/direct/src/directscripts/Doxyfile.python b/direct/src/directscripts/Doxyfile.python index 32ba23481d..81b68dc6b2 100644 --- a/direct/src/directscripts/Doxyfile.python +++ b/direct/src/directscripts/Doxyfile.python @@ -643,8 +643,7 @@ RECURSIVE = YES # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -EXCLUDE = built/direct/test \ - built/direct/plugin \ +EXCLUDE = built/direct/plugin \ built/direct/plugin_npapi \ built/direct/plugin_activex \ built/direct/plugin_installer \ diff --git a/direct/src/heapq/Sources.pp b/direct/src/heapq/Sources.pp deleted file mode 100755 index e072ecf367..0000000000 --- a/direct/src/heapq/Sources.pp +++ /dev/null @@ -1,29 +0,0 @@ -// DIR_TYPE "metalib" indicates we are building a shared library that -// consists mostly of references to other shared libraries. Under -// Windows, this directly produces a DLL (as opposed to the regular -// src libraries, which don't produce anything but a pile of OBJ files -// under Windows). - -#define DIR_TYPE metalib - -// This directory strictly contains a Python utility; therefore, only -// build it if we actually have Python. -#define BUILD_DIRECTORY $[HAVE_PYTHON] - - -#define OTHER_LIBS \ - pandaexpress:m \ - p3dconfig:c p3dtoolconfig:m \ - p3dtoolutil:c p3dtoolbase:c p3prc:c p3dtool:m - -#begin metalib_target - #define TARGET p3heapq - - // Tell ppremake to treat this file as if it had been generated via - // interrogate. On OSX, this will move it into the .so, instead of - // the .dylib, so that it can be imported into Python. - #define PYTHON_MODULE_ONLY 1 - - #define SOURCES heapq.cxx -#end metalib_target - diff --git a/direct/src/heapq/heapq.cxx b/direct/src/heapq/heapq.cxx deleted file mode 100755 index dcfe34f4bd..0000000000 --- a/direct/src/heapq/heapq.cxx +++ /dev/null @@ -1,240 +0,0 @@ - -/* Note: This module can probably go away when we upgrade to Python 2.4. - Python 2.3 has a heapq implementation, but it is in Python. This is - reported to be about 20x faster. In 2.4 they reimplemented heapq in C so - it should be comparable to this. At this time though, Python 2.4 is - still in alpha. - - Note: This code has been bastardized to only work on Tasks temporarily. - -*/ - -#include - -/* Prototypes */ -static PyObject * heappush(PyObject *self, PyObject *args); -static PyObject * heappop(PyObject *self, PyObject *args); -static PyObject * heapreplace(PyObject *self, PyObject *args); -static PyObject * heapify(PyObject *self, PyObject *args); -static int _siftdown(PyObject *list, int startpos, int pos); -static int _siftup(PyObject *list, int pos); - -#ifdef _WIN32 -extern "C" __declspec(dllexport) void initlibheapq(void); -extern "C" __declspec(dllexport) void initlibp3heapq(void); -#else -extern "C" void initlibheapq(); -extern "C" void initlibp3heapq(); -#endif - -static PyObject * -heappush(PyObject *self, PyObject *args) { - int len; - PyObject *list = NULL; - PyObject *node = NULL; - - if (!PyArg_ParseTuple(args,"O!O",&PyList_Type,&list,&node)) - return NULL; - - len = PyList_Size(list); - if (PyList_Append(list,node)) - return NULL; - - if (_siftdown(list,0,len)) - return NULL; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -heappop(PyObject *self, PyObject *args) { - PyObject *list = NULL; - PyObject *node = NULL; - PyObject *returnNode = NULL; - int len; - - if (!PyArg_ParseTuple(args,"O!",&PyList_Type,&list)) - return NULL; - - len = PyList_Size(list); - if (len == 0) { - /* Special-case most common failure cause */ - PyErr_SetString(PyExc_IndexError, "pop from empty list"); - return NULL; - } - - node = PySequence_GetItem(list,-1); - PySequence_DelItem(list,-1); - - len -= 1; - if (len > 0) { - returnNode = PySequence_GetItem(list,0); - PyList_SetItem(list,0,node); - if (_siftup(list,0)) - return NULL; - } else { - returnNode = node; - } - - return returnNode; -} - -static PyObject * -heapreplace(PyObject *self, PyObject *args) { - PyObject *list = NULL; - PyObject *node = NULL; - PyObject *returnNode = NULL; - int len; - - if (!PyArg_ParseTuple(args,"O!O",&PyList_Type,&list,&node)) - return NULL; - - len = PyList_Size(list); - if (len == 0) { - /* Special-case most common failure cause */ - PyErr_SetString(PyExc_IndexError, "replace on an empty list"); - return NULL; - } - - returnNode = PySequence_GetItem(list,0); - PySequence_SetItem(list,0,node); - if (_siftup(list,0)) - return NULL; - - return returnNode; -} - -static PyObject * -heapify(PyObject *self, PyObject *args) { - int n, i; - PyObject *list; - - if (!PyArg_ParseTuple(args,"O!",&PyList_Type,&list)) - return NULL; - n = (PyList_Size(list)/2)-1; - - for (i=n;i>=0;i--) { - if (_siftup(list,i)) - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static int -_siftdown(PyObject *list, int startpos, int pos) { - PyObject *newitem, *parent; - int parentpos; - - newitem = PySequence_GetItem(list,pos); - - PyObject *newitem_wakeTime_obj = PyObject_GetAttrString(newitem, "wakeTime"); - double newitem_wakeTime = 0.0; - if (newitem_wakeTime_obj != NULL) { - newitem_wakeTime = PyFloat_AS_DOUBLE(newitem_wakeTime_obj); - Py_DECREF(newitem_wakeTime_obj); - } - - while (pos > startpos) { - parentpos = (pos - 1) >> 1; - parent = PyList_GetItem(list,parentpos); - - /* - cmp = PyObject_RichCompareBool(parent,newitem,Py_LE); - if (cmp > 0) - break; - else if (cmp < 0) - return -1; - */ - - PyObject *parent_wakeTime_obj = PyObject_GetAttrString(parent, "wakeTime"); - double parent_wakeTime = 0.0; - if (parent_wakeTime_obj != NULL) { - parent_wakeTime = PyFloat_AS_DOUBLE(parent_wakeTime_obj); - Py_DECREF(parent_wakeTime_obj); - } - - if (parent_wakeTime <= newitem_wakeTime) { - break; - } - - Py_INCREF(parent); - PyList_SetItem(list,pos,parent); - pos = parentpos; - } - PyList_SetItem(list,pos,newitem); - return 0; -} - -static int -_siftup(PyObject *list, int pos) { - PyObject *newitem, *right, *child; - int endpos, rightpos, childpos; - int startpos = pos; - - endpos = PyList_Size(list); - newitem = PySequence_GetItem(list,pos); - - childpos = (2*pos)+1; - while (childpos < endpos) { - rightpos = childpos + 1; - child = PySequence_Fast_GET_ITEM(list,childpos); - - PyObject *child_wakeTime_obj = PyObject_GetAttrString(child, "wakeTime"); - double child_wakeTime = 0.0; - if (child_wakeTime_obj != NULL) { - child_wakeTime = PyFloat_AS_DOUBLE(child_wakeTime_obj); - Py_DECREF(child_wakeTime_obj); - } - - - if (rightpos < endpos) { - right = PySequence_Fast_GET_ITEM(list,rightpos); - - PyObject *right_wakeTime_obj = PyObject_GetAttrString(right, "wakeTime"); - double right_wakeTime = 0.0; - if (right_wakeTime_obj != NULL) { - right_wakeTime = PyFloat_AS_DOUBLE(right_wakeTime_obj); - Py_DECREF(right_wakeTime_obj); - } - - /* - cmp = PyObject_RichCompareBool(right,child,Py_LE); - if (cmp > 0) - childpos = rightpos; - else if (cmp < 0) - return -1; - */ - - if (right_wakeTime <= child_wakeTime) { - childpos = rightpos; - } - } - child = PySequence_GetItem(list,childpos); - PyList_SetItem(list,pos,child); - pos = childpos; - childpos = (2*pos)+1; - } - PyList_SetItem(list,pos,newitem); - - return _siftdown(list,startpos,pos); -} - -static PyMethodDef heapqcMethods[] = { - {"heappush",heappush,METH_VARARGS}, - {"heappop",heappop,METH_VARARGS}, - {"heapreplace",heapreplace,METH_VARARGS}, - {"heapify",heapify,METH_VARARGS}, - {NULL, NULL} /* Sentinel */ -}; - -void initlibheapq(void) { - (void) Py_InitModule("libheapq", heapqcMethods); -}; - -void initlibp3heapq(void) { - (void) Py_InitModule("libp3heapq", heapqcMethods); -}; - diff --git a/direct/src/http/LandingPage.py b/direct/src/http/LandingPage.py index 927994d326..212e3a6e20 100755 --- a/direct/src/http/LandingPage.py +++ b/direct/src/http/LandingPage.py @@ -3,7 +3,7 @@ from direct.directnotify.DirectNotifyGlobal import directNotify from pandac.PandaModules import VirtualFileSystem from pandac.PandaModules import Filename from pandac.PandaModules import DSearchPath -from direct.showbase import ElementTree as ET +import xml.etree.ElementTree as ET import LandingPageHTML from StringIO import StringIO diff --git a/direct/src/http/LandingPageHTML.py b/direct/src/http/LandingPageHTML.py index b40eac6324..bc04caf80e 100755 --- a/direct/src/http/LandingPageHTML.py +++ b/direct/src/http/LandingPageHTML.py @@ -1,6 +1,6 @@ # -- Text content for the landing page. You should change these for yours! -- -from direct.showbase import ElementTree as ET +import xml.etree.ElementTree as ET title = "Landing Page" defaultTitle = title diff --git a/direct/src/http/WebRequest.py b/direct/src/http/WebRequest.py index 95b058ef5e..dc40be7e28 100755 --- a/direct/src/http/WebRequest.py +++ b/direct/src/http/WebRequest.py @@ -4,7 +4,7 @@ from direct.directnotify.DirectNotifyGlobal import directNotify from direct.task.TaskManagerGlobal import taskMgr from direct.task import Task from LandingPage import LandingPage -from direct.showbase import ElementTree as ET +import xml.etree.ElementTree as ET notify = directNotify.newCategory('WebRequestDispatcher') diff --git a/direct/src/pyinst/Builder.py b/direct/src/pyinst/Builder.py deleted file mode 100644 index b43f18172b..0000000000 --- a/direct/src/pyinst/Builder.py +++ /dev/null @@ -1,504 +0,0 @@ -import string -import pprint -import sys -import os -import ConfigParser -import pprint -import shutil -import tempfile -import ltoc -import tocfilter -import resource -import archive -import archivebuilder -import carchive - -logfile = None -autopath = [] -built = {} -copyFile = None - -class Target: - def __init__(self, cfg, sectnm, cnvrts): - self.children = [] - self._dependencies = ltoc.lTOC() # the stuff an outer package will need to use me - self.cfg = cfg - self.__name__ = 'joe' - for optnm in cfg.options(sectnm): - cnvrt = cnvrts.get(optnm, 'getstringlist') - if cnvrt: - f = getattr(self, cnvrt, None) - if f: - self.__dict__[optnm] = f(cfg.get(sectnm, optnm)) - if not hasattr(self, 'name'): - self.name = self.__name__ - print "Initializing", self.__name__ - self.pathprefix = autopath + self.pathprefix - self.pathprefix.append(os.path.join(pyinsthome, 'support')) - for z in self.zlib: - if z in self.cfg.sections(): - self.children.append(z) - else: - raise ValueError, "%s - zlib '%s' does not refer to a sections" \ - % (self.name, z) - for i in range(len(self.misc)): - x = self.misc[i] - if x in self.cfg.sections(): - if self.cfg.get(x, "type") == 'PYZ': - self.zlib.append(x) - self.misc[i] = None - self.children.append(x) - self.misc = filter(None, self.misc) - self.edit() - self.toc = ltoc.lTOC() - for thingie in self.excludes: - try: - fltr = tocfilter.makefilter(thingie, self.pathprefix) - except ValueError: - print "Warning: '%s' not found - no filter created" % thingie - else: - self.toc.addFilter(fltr) - if self.exstdlib: - self.toc.addFilter(tocfilter.StdLibFilter()) - if self.extypes: - self.toc.addFilter(tocfilter.ExtFilter(self.extypes)) - if self.expatterns: - self.toc.addFilter(tocfilter.PatternFilter(self.expatterns)) - - ##------utilities------## - def dump(self): - logfile.write("---- %s: %s -----\n" % (self.__class__.__name__, self.name)) - pprint.pprint(self.__dict__, logfile) - def getstringlist(self, opt): - tmp = string.split(opt, ',') - return filter(None, map(string.strip, tmp)) - def getstring(self, opt): - return opt - def getbool(self, opt): - if opt in ('0','f','F','n','N'): - return 0 - return 1 - ##-----framework-----## - def build(self): - print "Gathering components of %s" % self.name - self.gather() - logfile.write("Final Table of Contents for %s:\n" % self.name) - pprint.pprint(self.toc.toList(), logfile) - print "Creating %s" % self.name - self.assemble() - ##-----overrideables-----## - def edit(self): - pass - def gather(self): - pass - def assemble(self): - pass - -class PYZTarget(Target): - def __init__(self, cfg, sectnm, cnvrts): - Target.__init__(self, cfg, sectnm, cnvrts) - # to use a PYZTarget, you'll need imputil and archive - archivebuilder.GetCompiled([os.path.join(pyinsthome, 'imputil.py')]) - print "pyinsthome:", pyinsthome - imputil = resource.makeresource('imputil.py', [pyinsthome]) - self._dependencies.append(imputil) - archivebuilder.GetCompiled([os.path.join(pyinsthome, 'archive_rt.py')]) - archmodule = resource.makeresource('archive_rt.py', [pyinsthome]) - self._dependencies.merge(archmodule.dependencies()) - self._dependencies.append(archmodule) - self.toc.addFilter(archmodule) - self.toc.addFilter(imputil) - for mod in archmodule.modules: - self.toc.addFilter(mod) - def edit(self): - if self.extypes: - print "PYZ target %s ignoring extypes = %s" % (self.__name__, self.extypes) - - def gather(self): - for script in self.dependencies: - rsrc = resource.makeresource(script, self.pathprefix) - if not isinstance(rsrc, resource.scriptresource): - print "Bug alert - Made %s from %s!" % (rsrc, script) - self.toc.merge(rsrc.modules) - logfile.write("lTOC after expanding 'depends':\n") - pprint.pprint(self.toc.toList(), logfile) - for thingie in self.includes + self.directories + self.packages: - rsrc = resource.makeresource(thingie, self.pathprefix) -## if not isinstance(rsrc, resource.pythonresource): -## print "PYZ target %s ignoring include %s" % (self.name, thingie) -## else: - self.toc.merge(rsrc.contents()) - logfile.write("lTOC after includes, dir, pkgs:\n") - pprint.pprint(self.toc.toList(), logfile) - self.toc.addFilter(tocfilter.ExtFilter(['.py', '.pyc', '.pyo'], 1)) - logfile.write("Applying the following filters:\n") - pprint.pprint(self.toc.filters, logfile) - self.toc.filter() - - def assemble(self): - contents = self.toc.toList() - if contents: - lib = archive.ZlibArchive() - lib.build(self.name, archivebuilder.GetCompiled(self.toc.toList())) - -class CollectTarget(Target): - def __init__(self, cfg, sectnm, cnvrts): - Target.__init__(self, cfg, sectnm, cnvrts) - - _rsrcdict = {'COLLECT': resource.dirresource, 'PYZ': resource.zlibresource, 'CARCHIVE': resource.archiveresource} - - def gather(self): - if self.support: - # the bare minimum - self.toc.merge([resource.makeresource('python20.dll')]) - self.toc.merge([resource.makeresource('exceptions.pyc').asBinary()]) - # zlib, bindepends, misc, trees, destdir - for i in range(len(self.zlib)): - # z refers to the section name - z = self.zlib[i] - nm = self.cfg.get(z, 'name') - try: - self.toc.merge([resource.makeresource(nm, ['.'])]) - except ValueError: - # zlibs aren't written if they turn out to be empty - self.zlib[i] = None - self.zlib = filter(None, self.zlib) - if self.zlib: - target = built.get(self.zlib[0], None) - if target: - self.toc.merge(target._dependencies) - for script in self.bindepends: - rsrc = resource.makeresource(script, self.pathprefix) - self.toc.merge(rsrc.binaries) - logfile.write('ltoc after bindepends:\n') - pprint.pprint(self.toc.toList(), logfile) - for thingie in self.misc: - if thingie in self.cfg.sections(): - name = self.cfg.get(thingie, "name") - typ = self.cfg.get(thingie, "type") - klass = self._rsrcdict.get(typ, resource.dataresource) - rsrc = apply(klass, (name, name)) - #now make sure we have the stuff the resource requires - target = built.get(thingie, None) - if target: - self.toc.merge(target._dependencies) - else: - rsrc = resource.makeresource(thingie, self.pathprefix) - self.toc.merge(rsrc.contents()) - logfile.write('ltoc after misc:\n') - pprint.pprint(self.toc.toList(), logfile) - for script in self.script: - if string.find(script, '.') == -1: - script = script + '.py' - rsrc = resource.makeresource(script, self.pathprefix) - if rsrc.typ == 'm': - rsrc.typ = 's' - self.toc.merge([rsrc]) - logfile.write('ltoc after scripts:\n') - pprint.pprint(self.toc.toList(), logfile) - for tree in self.trees: - try: - rsrc = resource.treeresource('.', tree) - except ValueError: - print "tree %s not found" % tree - else: - self.toc.merge(rsrc.contents()) - logfile.write('ltoc after trees:\n') - pprint.pprint(self.toc.toList(), logfile) - self.toc.addFilter(tocfilter.TypeFilter(['d'])) - logfile.write("Applying the following filters:\n") - pprint.pprint(self.toc.filters, logfile) - self.toc.filter() - #don't dupe stuff in a zlib that's part of this target - if self.zlib: - ztoc = ltoc.lTOC() - for zlibnm in self.zlib: - target = built.get(zlibnm, None) - if target: - ztoc.merge(target.toc) - for i in range(len(self.toc)-1, -1, -1): - rsrc = self.toc[i] - if isinstance(rsrc, resource.moduleresource) and rsrc in ztoc: - del self.toc[i] - - def assemble(self): - if os.path.exists(self.name): - if os.path.isdir(self.name): - for fnm in os.listdir(self.name): - try: - os.remove(os.path.join(self.name, fnm)) - except: - print "Could not delete file %s" % os.path.join(self.name, fnm) - else: - os.makedirs(self.name) - mysite = [] - for nm, path, typ in self.toc.toList(): - shutil.copy2(path, self.name) - if typ == 'z': - mysite.append('imputil.FuncImporter(archive.ZlibArchive("%s", 0).get_code).install()' % nm) - if mysite: - mysite.insert(0, 'import archive, imputil') - open(os.path.join(self.name, 'site.py'),'w').write(string.join(mysite, '\n')) - - -class ArchiveTarget(CollectTarget): - usefullname = 1 - def __init__(self, cfg, sectnm, cnvrts): - CollectTarget.__init__(self, cfg, sectnm, cnvrts) - archivebuilder.GetCompiled([os.path.join(pyinsthome, 'carchive_rt.py')]) - carchmodule = resource.makeresource('carchive_rt.py', [pyinsthome]) - self._dependencies.merge(carchmodule.dependencies()) - self._dependencies.append(carchmodule) - - def edit(self): - if self.destdir: - print "Warning 'destdir = %s' ignored for %s" % (self.destdir, self.name) - - def gather(self): - CollectTarget.gather(self) - - _cdict = {'s':2,'m':1,'b':1,'x':1,'a':0,'z':0, 'p':1} - - def assemble(self, pkgnm=None): - if pkgnm is None: - pkgnm = self.name - arch = carchive.CArchive() - toc = [] - pytoc = [] - for nm, path, typ in self.toc.toList(): - compress = self._cdict[typ] - if typ == 'b' or (self.usefullname and typ in 'ms'): - nm = os.path.basename(path) - if typ == 'm': - pytoc.append((nm, path, compress, typ)) - else: - toc.append((nm, path, compress, typ)) - toc = toc + archivebuilder.GetCompiled(pytoc) - arch.build(pkgnm, toc) - return arch - -class FullExeTarget(ArchiveTarget): - usefullname = 0 - def __init__(self, cfg, sectnm, cnvrts): - ArchiveTarget.__init__(self, cfg, sectnm, cnvrts) - - def gather(self): - for script in self.script: - #print "FullExeTarget.gather: script is", repr(script) - rsrc = resource.makeresource(script, self.pathprefix) - rsrc = resource.scriptresource(rsrc.name, rsrc.path) - #print " resource is", repr(rsrc) - self.toc.merge(rsrc.binaries) - ArchiveTarget.gather(self) - if not self.zlib: - self.toc.merge(rsrc.modules) - self._dependencies = ltoc.lTOC() - - _cdict = {'s':2,'m':0,'b':1,'x':0,'a':0,'z':0} - _edict = { (1, 1):'Runw_d.exe', (1, 0):'Runw.exe', (0, 1):'Run_d.exe', (0, 0):'Run.exe'} - - def assemble(self): - pkgname = tempfile.mktemp() - arch = ArchiveTarget.assemble(self, pkgname) - exe = self._edict[(self.userunw, self.debug)] - exe = os.path.normpath(os.path.join(pyinsthome, 'support', exe)) -## copyFile([exe, pkgname], self.name) -## os.remove(pkgname) - # Thomas Heller's icon code - # my version - if self.icon: - myexe = tempfile.mktemp() - copyFile (exe, myexe) - try: - from icon import CopyIcons - CopyIcons(myexe, self.icon) - except ImportError: - print "win32api is required for updating icons" - print "You should have win32api.pyd and PyWinTypes20.dll" - print "in the installation directory." - print "Please copy them to Python's DLLS subdirectory" - print "(or install Mark Hammond's Win32 extensions)." -## iconfile = None -## for name in self.cfg.sections(): -## if self.cfg.get (name, "type") == "STANDALONE": -## try: -## iconfile = self.cfg.get (name, "iconfile") -## except: -## pass -## if iconfile: -## from icon import CopyIcons -## CopyIcons (myexe, iconfile) - copyFile ([myexe, pkgname], self.name) - os.remove(myexe) - else: - copyFile([exe, pkgname], self.name) - #os.remove(pkgname) - -class ExeTarget(FullExeTarget): - def __init__(self, cfg, sectnm, cnvrts): - FullExeTarget.__init__(self, cfg, sectnm, cnvrts) - - def edit(self): - if not self.script: - raise ValueError, "EXE target %s requires 'script=