Merge remote-tracking branch 'origin/master' into deploy-ng
This commit is contained in:
commit
fba41dafae
|
|
@ -1,10 +0,0 @@
|
|||
/**
|
||||
* @file direct.cxx
|
||||
* @author drose
|
||||
* @date 2000-05-18
|
||||
*/
|
||||
|
||||
// This is a dummy file whose sole purpose is to give the compiler something
|
||||
// to compile when making libdirect.so in NO_DEFER mode, which generates an
|
||||
// empty library that itself links with all the other shared libraries that
|
||||
// make up libdirect.
|
||||
|
|
@ -708,7 +708,7 @@ pack_object(PyObject *object) {
|
|||
pack_int64(PyLong_AsLongLong(object));
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
} else if (PyUnicode_Check(object)) {
|
||||
char *buffer;
|
||||
const char *buffer;
|
||||
Py_ssize_t length;
|
||||
buffer = PyUnicode_AsUTF8AndSize(object, &length);
|
||||
if (buffer) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -397,6 +397,7 @@ pop_struct() {
|
|||
%type <u.type> class_derivation_name
|
||||
%type <u.type> enum_element_type
|
||||
%type <u.type> maybe_trailing_return_type
|
||||
%type <u.identifier> maybe_comma_identifier
|
||||
/*%type <u.type> typedefname*/
|
||||
%type <u.identifier> name
|
||||
%type <u.identifier> name_no_final
|
||||
|
|
@ -548,202 +549,264 @@ declaration:
|
|||
{
|
||||
current_scope->set_current_vis(V_private);
|
||||
}
|
||||
| KW_MAKE_PROPERTY '(' name ',' IDENTIFIER ')' ';'
|
||||
{
|
||||
|
||||
CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @5);
|
||||
}
|
||||
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), NULL, current_scope, @1.file);
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
| KW_MAKE_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';'
|
||||
| KW_MAKE_PROPERTY '(' name ',' IDENTIFIER maybe_comma_identifier ')' ';'
|
||||
{
|
||||
CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @5);
|
||||
|
||||
} else {
|
||||
CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
CPPFunctionGroup *setter_func = NULL;
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_normal, current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
|
||||
if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @7);
|
||||
} else {
|
||||
setter_func = setter->as_function_group();
|
||||
if ($6 != nullptr) {
|
||||
CPPDeclaration *setter = $6->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid setter: " + $6->get_fully_scoped_name(), @6);
|
||||
} else {
|
||||
make_property->_set_function = setter->as_function_group();
|
||||
}
|
||||
}
|
||||
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(),
|
||||
setter_func, current_scope, @1.file);
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
| KW_MAKE_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';'
|
||||
{
|
||||
CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @5);
|
||||
|
||||
} else {
|
||||
CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
CPPFunctionGroup *setter_func = NULL;
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_normal, current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
|
||||
if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @7);
|
||||
} else {
|
||||
setter_func = setter->as_function_group();
|
||||
make_property->_set_function = setter->as_function_group();
|
||||
}
|
||||
|
||||
CPPDeclaration *deleter = $9->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (deleter == (CPPDeclaration *)NULL || deleter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid delete method: " + $9->get_fully_scoped_name(), @9);
|
||||
deleter = NULL;
|
||||
}
|
||||
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(),
|
||||
setter_func, current_scope, @1.file);
|
||||
if (deleter) {
|
||||
} else {
|
||||
make_property->_del_function = deleter->as_function_group();
|
||||
}
|
||||
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
| KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';'
|
||||
{
|
||||
CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5);
|
||||
length_getter = NULL;
|
||||
length_getter = nullptr;
|
||||
}
|
||||
|
||||
CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7);
|
||||
getter = nullptr;
|
||||
}
|
||||
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), NULL, current_scope, @1.file);
|
||||
make_property->_length_function = length_getter->as_function_group();
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
if (getter != nullptr && length_getter != nullptr) {
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_sequence, current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
make_property->_length_function = length_getter->as_function_group();
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
| KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';'
|
||||
{
|
||||
CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5);
|
||||
length_getter = NULL;
|
||||
length_getter = nullptr;
|
||||
}
|
||||
|
||||
CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7);
|
||||
getter = nullptr;
|
||||
}
|
||||
|
||||
if (getter != nullptr && length_getter != nullptr) {
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_sequence, current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
make_property->_length_function = length_getter->as_function_group();
|
||||
|
||||
} else {
|
||||
CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer);
|
||||
CPPFunctionGroup *setter_func = NULL;
|
||||
|
||||
if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9);
|
||||
} else {
|
||||
setter_func = setter->as_function_group();
|
||||
make_property->_set_function = setter->as_function_group();
|
||||
}
|
||||
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(),
|
||||
setter_func, current_scope, @1.file);
|
||||
make_property->_length_function = length_getter->as_function_group();
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
| KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';'
|
||||
{
|
||||
CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5);
|
||||
length_getter = NULL;
|
||||
}
|
||||
|
||||
CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7);
|
||||
getter = nullptr;
|
||||
}
|
||||
|
||||
if (getter != nullptr && length_getter != nullptr) {
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_sequence, current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
make_property->_length_function = length_getter->as_function_group();
|
||||
|
||||
} else {
|
||||
CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer);
|
||||
CPPFunctionGroup *setter_func = NULL;
|
||||
|
||||
if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9);
|
||||
} else {
|
||||
setter_func = setter->as_function_group();
|
||||
make_property->_set_function = setter->as_function_group();
|
||||
}
|
||||
|
||||
CPPDeclaration *deleter = $11->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (deleter == (CPPDeclaration *)NULL || deleter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid delete method: " + $11->get_fully_scoped_name(), @11);
|
||||
deleter = NULL;
|
||||
}
|
||||
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(),
|
||||
setter_func, current_scope, @1.file);
|
||||
make_property->_length_function = length_getter->as_function_group();
|
||||
if (deleter) {
|
||||
} else {
|
||||
make_property->_del_function = deleter->as_function_group();
|
||||
}
|
||||
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
| KW_MAKE_MAP_PROPERTY '(' name ',' IDENTIFIER ')' ';'
|
||||
{
|
||||
CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid item getter method: " + $5->get_fully_scoped_name(), @5);
|
||||
|
||||
} else {
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_mapping, current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
| KW_MAKE_MAP_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';'
|
||||
{
|
||||
CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7);
|
||||
|
||||
} else {
|
||||
CPPMakeProperty *make_property;
|
||||
make_property = new CPPMakeProperty($3, CPPMakeProperty::T_mapping, current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
|
||||
CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid has/find method: " + $5->get_fully_scoped_name(), @5);
|
||||
} else {
|
||||
make_property->_has_function = hasser->as_function_group();
|
||||
}
|
||||
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
| KW_MAKE_MAP_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER maybe_comma_identifier ')' ';'
|
||||
{
|
||||
CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7);
|
||||
|
||||
} else {
|
||||
CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_mapping, current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
|
||||
CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid has/find method: " + $5->get_fully_scoped_name(), @5);
|
||||
} else {
|
||||
make_property->_has_function = hasser->as_function_group();
|
||||
}
|
||||
|
||||
CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9);
|
||||
} else {
|
||||
make_property->_set_function = setter->as_function_group();
|
||||
}
|
||||
|
||||
if ($10 != nullptr) {
|
||||
CPPDeclaration *deleter = $10->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid delete method: " + $10->get_fully_scoped_name(), @10);
|
||||
} else {
|
||||
make_property->_del_function = deleter->as_function_group();
|
||||
}
|
||||
}
|
||||
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
| KW_MAKE_PROPERTY2 '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';'
|
||||
{
|
||||
CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (hasser == (CPPDeclaration *)NULL || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid has-function: " + $5->get_fully_scoped_name(), @5);
|
||||
}
|
||||
|
||||
CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7);
|
||||
}
|
||||
|
||||
if (hasser && getter) {
|
||||
} else {
|
||||
CPPMakeProperty *make_property;
|
||||
make_property = new CPPMakeProperty($3,
|
||||
hasser->as_function_group(),
|
||||
getter->as_function_group(),
|
||||
NULL, NULL,
|
||||
make_property = new CPPMakeProperty($3, CPPMakeProperty::T_normal,
|
||||
current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
|
||||
CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid has/find method: " + $5->get_fully_scoped_name(), @5);
|
||||
} else {
|
||||
make_property->_has_function = hasser->as_function_group();
|
||||
}
|
||||
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
| KW_MAKE_PROPERTY2 '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';'
|
||||
{
|
||||
CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (hasser == (CPPDeclaration *)NULL || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid has-function: " + $5->get_fully_scoped_name(), @5);
|
||||
}
|
||||
|
||||
CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7);
|
||||
}
|
||||
|
||||
CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9);
|
||||
}
|
||||
|
||||
CPPDeclaration *clearer = $11->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (clearer == (CPPDeclaration *)NULL || clearer->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("Reference to non-existent or invalid clear-function: " + $11->get_fully_scoped_name(), @11);
|
||||
}
|
||||
|
||||
if (hasser && getter && setter && clearer) {
|
||||
} else {
|
||||
CPPMakeProperty *make_property;
|
||||
make_property = new CPPMakeProperty($3,
|
||||
hasser->as_function_group(),
|
||||
getter->as_function_group(),
|
||||
setter->as_function_group(),
|
||||
clearer->as_function_group(),
|
||||
make_property = new CPPMakeProperty($3, CPPMakeProperty::T_normal,
|
||||
current_scope, @1.file);
|
||||
make_property->_get_function = getter->as_function_group();
|
||||
|
||||
CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid has/find method: " + $5->get_fully_scoped_name(), @5);
|
||||
} else {
|
||||
make_property->_has_function = hasser->as_function_group();
|
||||
}
|
||||
|
||||
CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9);
|
||||
} else {
|
||||
make_property->_set_function = setter->as_function_group();
|
||||
}
|
||||
|
||||
CPPDeclaration *clearer = $11->find_symbol(current_scope, global_scope, current_lexer);
|
||||
if (clearer == nullptr || clearer->get_subtype() != CPPDeclaration::ST_function_group) {
|
||||
yyerror("reference to non-existent or invalid clear method: " + $11->get_fully_scoped_name(), @11);
|
||||
} else {
|
||||
make_property->_clear_function = clearer->as_function_group();
|
||||
}
|
||||
|
||||
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
|
||||
}
|
||||
}
|
||||
|
|
@ -1723,6 +1786,18 @@ maybe_trailing_return_type:
|
|||
;
|
||||
|
||||
|
||||
maybe_comma_identifier:
|
||||
empty
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
| ',' IDENTIFIER
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
function_parameter_list:
|
||||
empty
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,37 +18,17 @@
|
|||
*
|
||||
*/
|
||||
CPPMakeProperty::
|
||||
CPPMakeProperty(CPPIdentifier *ident,
|
||||
CPPFunctionGroup *getter, CPPFunctionGroup *setter,
|
||||
CPPMakeProperty(CPPIdentifier *ident, Type type,
|
||||
CPPScope *current_scope, const CPPFile &file) :
|
||||
CPPDeclaration(file),
|
||||
_ident(ident),
|
||||
_length_function(NULL),
|
||||
_has_function(NULL),
|
||||
_get_function(getter),
|
||||
_set_function(setter),
|
||||
_clear_function(NULL),
|
||||
_del_function(NULL)
|
||||
{
|
||||
_ident->_native_scope = current_scope;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
CPPMakeProperty::
|
||||
CPPMakeProperty(CPPIdentifier *ident,
|
||||
CPPFunctionGroup *hasser, CPPFunctionGroup *getter,
|
||||
CPPFunctionGroup *setter, CPPFunctionGroup *clearer,
|
||||
CPPScope *current_scope, const CPPFile &file) :
|
||||
CPPDeclaration(file),
|
||||
_ident(ident),
|
||||
_length_function(NULL),
|
||||
_has_function(hasser),
|
||||
_get_function(getter),
|
||||
_set_function(setter),
|
||||
_clear_function(clearer),
|
||||
_del_function(NULL)
|
||||
_type(type),
|
||||
_length_function(nullptr),
|
||||
_has_function(nullptr),
|
||||
_get_function(nullptr),
|
||||
_set_function(nullptr),
|
||||
_clear_function(nullptr),
|
||||
_del_function(nullptr)
|
||||
{
|
||||
_ident->_native_scope = current_scope;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,16 +23,72 @@
|
|||
* This is a MAKE_PROPERTY() declaration appearing within a class body. It
|
||||
* means to generate a property within Python, replacing (for instance)
|
||||
* get_something()/set_something() with a synthetic 'something' attribute.
|
||||
*
|
||||
* This is an example of a simple property (MAKE_PROPERTY is defined as
|
||||
* the built-in __make_property):
|
||||
* @@code
|
||||
* Thing get_thing() const;
|
||||
* void set_thing(const Thing &);
|
||||
*
|
||||
* MAKE_PROPERTY(thing, get_thing, set_thing);
|
||||
* @@endcode
|
||||
* The setter may be omitted to make the property read-only.
|
||||
*
|
||||
* There is also a secondary macro that allows the property to be set to a
|
||||
* cleared state using separate clear functions. In the scripting language,
|
||||
* this would be represented by a "null" value, or an "optional" construct in
|
||||
* languages that have no notion of a null value.
|
||||
*
|
||||
* @@code
|
||||
* bool has_thing() const;
|
||||
* Thing get_thing() const;
|
||||
* void set_thing(const Thing &);
|
||||
* void clear_thing();
|
||||
* MAKE_PROPERTY2(thing, has_thing, get_thing, set_thing, clear_thing);
|
||||
* @@endcode
|
||||
* As with MAKE_PROPERTY, both the setter and clearer can be omitted to create
|
||||
* a read-only property.
|
||||
*
|
||||
* Thirdly, there is a variant called MAKE_SEQ_PROPERTY. It takes a length
|
||||
* function as argument and the getter and setter take an index as first
|
||||
* argument:
|
||||
* @@code
|
||||
* size_t get_num_things() const;
|
||||
* Thing &get_thing(size_t i) const;
|
||||
* void set_thing(size_t i, Thing value) const;
|
||||
* void remove_thing(size_t i) const;
|
||||
*
|
||||
* MAKE_SEQ_PROPERTY(get_num_things, get_thing, set_thing, remove_thing);
|
||||
* @@endcode
|
||||
*
|
||||
* Lastly, there is the possibility to have properties with key/value
|
||||
* associations, often called a "map" or "dictionary" in scripting languages:
|
||||
* @@code
|
||||
* bool has_thing(string key) const;
|
||||
* Thing &get_thing(string key) const;
|
||||
* void set_thing(string key, Thing value) const;
|
||||
* void clear_thing(string key) const;
|
||||
*
|
||||
* MAKE_MAP_PROPERTY(things, has_thing, get_thing, set_thing, clear_thing);
|
||||
* @@endcode
|
||||
* You may also replace the "has" function with a "find" function that returns
|
||||
* an index. If the returned index is negative (or in the case of an unsigned
|
||||
* integer, the maximum value), the item is assumed not to be present in the
|
||||
* mapping.
|
||||
*
|
||||
* It is also possible to use both MAKE_SEQ_PROPERTY and MAKE_MAP_PROPERTY on
|
||||
* the same property name. This implies that this property has both a
|
||||
* sequence and mapping interface.
|
||||
*/
|
||||
class CPPMakeProperty : public CPPDeclaration {
|
||||
public:
|
||||
CPPMakeProperty(CPPIdentifier *ident,
|
||||
CPPFunctionGroup *getter, CPPFunctionGroup *setter,
|
||||
CPPScope *current_scope, const CPPFile &file);
|
||||
enum Type {
|
||||
T_normal = 0x0,
|
||||
T_sequence = 0x1,
|
||||
T_mapping = 0x2,
|
||||
};
|
||||
|
||||
CPPMakeProperty(CPPIdentifier *ident,
|
||||
CPPFunctionGroup *hasser, CPPFunctionGroup *getter,
|
||||
CPPFunctionGroup *setter, CPPFunctionGroup *clearer,
|
||||
CPPMakeProperty(CPPIdentifier *ident, Type type,
|
||||
CPPScope *current_scope, const CPPFile &file);
|
||||
|
||||
virtual string get_simple_name() const;
|
||||
|
|
@ -46,8 +102,7 @@ public:
|
|||
virtual CPPMakeProperty *as_make_property();
|
||||
|
||||
CPPIdentifier *_ident;
|
||||
// If length_function is not NULL, this is actually a sequence property,
|
||||
// and the other functions take an additional index argument.
|
||||
Type _type;
|
||||
CPPFunctionGroup *_length_function;
|
||||
CPPFunctionGroup *_has_function;
|
||||
CPPFunctionGroup *_get_function;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,14 @@
|
|||
#define RETURNS_ALIGNED(x)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define LIKELY(x) (x)
|
||||
#define UNLIKELY(x) (x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
include win32 defns for everything up to WinServer2003, and assume
|
||||
I'm smart enough to use GetProcAddress for backward compat on
|
||||
|
|
@ -456,6 +464,7 @@ typedef struct _object PyObject;
|
|||
#define MAKE_PROPERTY2(property_name, ...) __make_property2(property_name, __VA_ARGS__)
|
||||
#define MAKE_SEQ(seq_name, num_name, element_name) __make_seq(seq_name, num_name, element_name)
|
||||
#define MAKE_SEQ_PROPERTY(property_name, ...) __make_seq_property(property_name, __VA_ARGS__)
|
||||
#define MAKE_MAP_PROPERTY(property_name, ...) __make_map_property(property_name, __VA_ARGS__)
|
||||
#define EXTENSION(x) __extension x
|
||||
#define EXTEND __extension
|
||||
#else
|
||||
|
|
@ -466,6 +475,7 @@ typedef struct _object PyObject;
|
|||
#define MAKE_PROPERTY2(property_name, ...)
|
||||
#define MAKE_SEQ(seq_name, num_name, element_name)
|
||||
#define MAKE_SEQ_PROPERTY(property_name, ...)
|
||||
#define MAKE_MAP_PROPERTY(property_name, ...)
|
||||
#define EXTENSION(x)
|
||||
#define EXTEND
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ PUBLISHED:
|
|||
|
||||
static Filename get_cwd();
|
||||
|
||||
PUBLISHED:
|
||||
MAKE_MAP_PROPERTY(environment_variables, has_environment_variable,
|
||||
get_environment_variable, set_environment_variable);
|
||||
|
||||
MAKE_SEQ_PROPERTY(args, get_num_args, get_arg);
|
||||
MAKE_PROPERTY(binary_name, get_binary_name, set_binary_name);
|
||||
MAKE_PROPERTY(dtool_name, get_dtool_name, set_dtool_name);
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ InterfaceMaker::MakeSeq::
|
|||
MakeSeq(const string &name, const InterrogateMakeSeq &imake_seq) :
|
||||
_name(name),
|
||||
_imake_seq(imake_seq),
|
||||
_length_getter(NULL),
|
||||
_element_getter(NULL)
|
||||
_length_getter(nullptr),
|
||||
_element_getter(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -86,12 +86,10 @@ MakeSeq(const string &name, const InterrogateMakeSeq &imake_seq) :
|
|||
InterfaceMaker::Property::
|
||||
Property(const InterrogateElement &ielement) :
|
||||
_ielement(ielement),
|
||||
_length_function(NULL),
|
||||
_getter(NULL),
|
||||
_setter(NULL),
|
||||
_has_function(NULL),
|
||||
_clear_function(NULL),
|
||||
_deleter(NULL),
|
||||
_length_function(nullptr),
|
||||
_has_function(nullptr),
|
||||
_clear_function(nullptr),
|
||||
_deleter(nullptr),
|
||||
_has_this(false)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,9 +126,9 @@ public:
|
|||
Property(const InterrogateElement &ielement);
|
||||
|
||||
const InterrogateElement &_ielement;
|
||||
vector<FunctionRemap *> _getter_remaps;
|
||||
vector<FunctionRemap *> _setter_remaps;
|
||||
Function *_length_function;
|
||||
Function *_getter;
|
||||
Function *_setter;
|
||||
Function *_has_function;
|
||||
Function *_clear_function;
|
||||
Function *_deleter;
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ test_assert(ostream &out, int indent_level) const {
|
|||
indent(out, indent_level)
|
||||
<< "Notify *notify = Notify::ptr();\n";
|
||||
indent(out, indent_level)
|
||||
<< "if (notify->has_assert_failed()) {\n";
|
||||
<< "if (UNLIKELY(notify->has_assert_failed())) {\n";
|
||||
indent(out, indent_level + 2)
|
||||
<< "PyErr_SetString(PyExc_AssertionError, notify->get_assert_error_message().c_str());\n";
|
||||
indent(out, indent_level + 2)
|
||||
|
|
|
|||
|
|
@ -2640,8 +2640,7 @@ write_module_class(ostream &out, Object *obj) {
|
|||
for (pit = obj->_properties.begin(); pit != obj->_properties.end(); ++pit) {
|
||||
Property *property = (*pit);
|
||||
const InterrogateElement &ielem = property->_ielement;
|
||||
if (!property->_has_this ||
|
||||
property->_getter == NULL || !is_function_legal(property->_getter)) {
|
||||
if (!property->_has_this || property->_getter_remaps.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2652,8 +2651,7 @@ write_module_class(ostream &out, Object *obj) {
|
|||
|
||||
string getter = "&Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter";
|
||||
string setter = "NULL";
|
||||
if (property->_length_function == NULL &&
|
||||
property->_setter != NULL && is_function_legal(property->_setter)) {
|
||||
if (!ielem.is_sequence() && !ielem.is_mapping() && !property->_setter_remaps.empty()) {
|
||||
setter = "&Dtool_" + ClassName + "_" + ielem.get_name() + "_Setter";
|
||||
}
|
||||
|
||||
|
|
@ -3190,8 +3188,7 @@ write_module_class(ostream &out, Object *obj) {
|
|||
for (pit = obj->_properties.begin(); pit != obj->_properties.end(); ++pit) {
|
||||
Property *property = (*pit);
|
||||
const InterrogateElement &ielem = property->_ielement;
|
||||
if (property->_has_this ||
|
||||
property->_getter == NULL || !is_function_legal(property->_getter)) {
|
||||
if (property->_has_this || property->_getter_remaps.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -3200,8 +3197,7 @@ write_module_class(ostream &out, Object *obj) {
|
|||
|
||||
string getter = "&Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter";
|
||||
string setter = "NULL";
|
||||
if (property->_length_function == NULL &&
|
||||
property->_setter != NULL && is_function_legal(property->_setter)) {
|
||||
if (!ielem.is_sequence() && !ielem.is_mapping() && !property->_setter_remaps.empty()) {
|
||||
setter = "&Dtool_" + ClassName + "_" + ielem.get_name() + "_Setter";
|
||||
}
|
||||
|
||||
|
|
@ -4389,57 +4385,6 @@ write_function_forset(ostream &out,
|
|||
std::sort(remaps.begin(), remaps.end(), RemapCompareLess);
|
||||
std::vector<FunctionRemap *>::const_iterator sii;
|
||||
|
||||
// Check if all of them have an InternalName pointer as first parameter.
|
||||
// This is a dirty hack, of course, to work around an awkward overload
|
||||
// resolution problem in NodePath::set_shader_input() (while perhaps also
|
||||
// improving its performance). If I had more time I'd create a better
|
||||
// solution.
|
||||
bool first_internalname = false;
|
||||
string first_pexpr2(first_pexpr);
|
||||
if (first_pexpr.empty() && args_type != AT_no_args) {
|
||||
first_internalname = true;
|
||||
|
||||
for (sii = remaps.begin(); sii != remaps.end(); ++sii) {
|
||||
remap = (*sii);
|
||||
if (remap->_parameters.size() > (size_t)remap->_has_this) {
|
||||
ParameterRemap *param = remap->_parameters[(size_t)remap->_has_this]._remap;
|
||||
string param_name = param->get_orig_type()->get_local_name(&parser);
|
||||
|
||||
if (param_name != "CPT_InternalName" &&
|
||||
param_name != "InternalName const *" &&
|
||||
param_name != "InternalName *") {
|
||||
// Aw.
|
||||
first_internalname = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
first_internalname = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first_internalname) {
|
||||
// Yeah, all remaps have a first InternalName parameter, so process
|
||||
// that and remove it from the args tuple.
|
||||
if (args_type == AT_single_arg) {
|
||||
// Bit of a weird case, but whatever.
|
||||
indent(out, indent_level) << "PyObject *name_obj = arg;\n";
|
||||
args_type = AT_no_args;
|
||||
} else if (min_num_args == 2 && max_num_args == 2) {
|
||||
indent(out, indent_level) << "PyObject *name_obj = PyTuple_GET_ITEM(args, 0);\n";
|
||||
indent(out, indent_level) << "PyObject *arg = PyTuple_GET_ITEM(args, 1);\n";
|
||||
args_type = AT_single_arg;
|
||||
} else {
|
||||
indent(out, indent_level) << "PyObject *name_obj = PyTuple_GET_ITEM(args, 0);\n";
|
||||
indent(out, indent_level) << "args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));\n";
|
||||
return_flags |= RF_decref_args;
|
||||
}
|
||||
indent(out, indent_level) << "PT(InternalName) name;\n";
|
||||
indent(out, indent_level) << "if (Dtool_Coerce_InternalName(name_obj, name)) {\n";
|
||||
indent_level += 2;
|
||||
first_pexpr2 = "name";
|
||||
}
|
||||
}
|
||||
|
||||
int num_coercion_possible = 0;
|
||||
sii = remaps.begin();
|
||||
while (sii != remaps.end()) {
|
||||
|
|
@ -4474,7 +4419,7 @@ write_function_forset(ostream &out,
|
|||
write_function_instance(out, remap, min_num_args, max_num_args,
|
||||
expected_params, indent_level + 2,
|
||||
false, false, args_type, return_flags,
|
||||
check_exceptions, first_pexpr2);
|
||||
check_exceptions, first_pexpr);
|
||||
|
||||
indent(out, indent_level) << "}\n\n";
|
||||
}
|
||||
|
|
@ -4507,28 +4452,11 @@ write_function_forset(ostream &out,
|
|||
write_function_instance(out, remap, min_num_args, max_num_args,
|
||||
ignore_expected_params, indent_level + 2,
|
||||
true, false, args_type, return_flags,
|
||||
check_exceptions, first_pexpr2);
|
||||
check_exceptions, first_pexpr);
|
||||
|
||||
indent(out, indent_level) << "}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (first_internalname) {
|
||||
indent_level -= 2;
|
||||
if (report_errors) {
|
||||
indent(out, indent_level) << "} else {\n";
|
||||
|
||||
string class_name = remap->_cpptype->get_simple_name();
|
||||
ostringstream msg;
|
||||
msg << classNameFromCppName(class_name, false) << "."
|
||||
<< methodNameFromCppName(remap, class_name, false)
|
||||
<< "() first argument must be str or InternalName";
|
||||
|
||||
error_raise_return(out, indent_level + 2, return_flags,
|
||||
"TypeError", msg.str());
|
||||
}
|
||||
indent(out, indent_level) << "}\n";
|
||||
}
|
||||
} else {
|
||||
// There is only one possible overload with this number of parameters.
|
||||
// Just call it.
|
||||
|
|
@ -4891,7 +4819,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
|||
<< default_value->_str.size() << ";\n";
|
||||
}
|
||||
} else {
|
||||
indent(out, indent_level) << "char *" << param_name << "_str = NULL;\n";
|
||||
indent(out, indent_level) << "const char *" << param_name << "_str = NULL;\n";
|
||||
indent(out, indent_level) << "Py_ssize_t " << param_name << "_len;\n";
|
||||
}
|
||||
|
||||
|
|
@ -4900,7 +4828,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
|||
// As a special hack to fix pickling in Python 3, if the method name
|
||||
// starts with py_decode_, we take a bytes object instead of a str.
|
||||
if (remap->_cppfunc->get_local_name().substr(0, 10) == "py_decode_") {
|
||||
indent(out, indent_level) << "if (PyBytes_AsStringAndSize(arg, &"
|
||||
indent(out, indent_level) << "if (PyBytes_AsStringAndSize(arg, (char **)&"
|
||||
<< param_name << "_str, &" << param_name << "_len) == -1) {\n";
|
||||
indent(out, indent_level + 2) << param_name << "_str = NULL;\n";
|
||||
indent(out, indent_level) << "}\n";
|
||||
|
|
@ -4910,7 +4838,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
|||
<< param_name << "_len);\n";
|
||||
}
|
||||
out << "#else\n"; // NB. PyString_AsStringAndSize also accepts a PyUnicode.
|
||||
indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, &"
|
||||
indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, (char **)&"
|
||||
<< param_name << "_str, &" << param_name << "_len) == -1) {\n";
|
||||
indent(out, indent_level + 2) << param_name << "_str = NULL;\n";
|
||||
indent(out, indent_level) << "}\n";
|
||||
|
|
@ -6065,14 +5993,14 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
|||
// this for coercion constructors since they are called by other wrapper
|
||||
// functions which already check this on their own. Generated getters
|
||||
// obviously can't raise asserts.
|
||||
if (watch_asserts && (return_flags & RF_coerced) == 0 &&
|
||||
if (watch_asserts && (return_flags & (RF_coerced | RF_raise_keyerror)) == 0 &&
|
||||
remap->_type != FunctionRemap::T_getter &&
|
||||
remap->_type != FunctionRemap::T_setter) {
|
||||
out << "#ifndef NDEBUG\n";
|
||||
indent(out, indent_level)
|
||||
<< "Notify *notify = Notify::ptr();\n";
|
||||
indent(out, indent_level)
|
||||
<< "if (notify->has_assert_failed()) {\n";
|
||||
<< "if (UNLIKELY(notify->has_assert_failed())) {\n";
|
||||
|
||||
if (manage_return) {
|
||||
// Output code to delete any temporary object we may have allocated.
|
||||
|
|
@ -6194,6 +6122,27 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
|||
indent(out, indent_level) << "manage = true;\n";
|
||||
indent(out, indent_level) << "return true;\n";
|
||||
}
|
||||
|
||||
} else if (return_flags & RF_raise_keyerror) {
|
||||
CPPType *orig_type = remap->_return_type->get_orig_type();
|
||||
|
||||
if (TypeManager::is_bool(orig_type) || TypeManager::is_pointer(orig_type)) {
|
||||
indent(out, indent_level) << "if (!" << return_expr << ") {\n";
|
||||
} else if (TypeManager::is_unsigned_integer(orig_type)) {
|
||||
indent(out, indent_level) << "if ((int)" << return_expr << " == -1) {\n";
|
||||
} else if (TypeManager::is_integer(orig_type)) {
|
||||
indent(out, indent_level) << "if (" << return_expr << " < 0) {\n";
|
||||
} else {
|
||||
indent(out, indent_level) << "if (false) {\n";
|
||||
}
|
||||
|
||||
if (args_type == AT_single_arg) {
|
||||
indent(out, indent_level) << " PyErr_SetObject(PyExc_KeyError, arg);\n";
|
||||
} else {
|
||||
indent(out, indent_level) << " PyErr_SetObject(PyExc_KeyError, key);\n";
|
||||
}
|
||||
error_return(out, indent_level + 2, return_flags);
|
||||
indent(out, indent_level) << "}\n";
|
||||
}
|
||||
|
||||
// Close the extra braces opened earlier.
|
||||
|
|
@ -6466,19 +6415,21 @@ write_make_seq(ostream &out, Object *obj, const std::string &ClassName,
|
|||
*/
|
||||
void InterfaceMakerPythonNative::
|
||||
write_getset(ostream &out, Object *obj, Property *property) {
|
||||
// We keep around this empty vector for passing to get_call_str.
|
||||
const vector_string pexprs;
|
||||
|
||||
string ClassName = make_safe_name(obj->_itype.get_scoped_name());
|
||||
std::string cClassName = obj->_itype.get_true_name();
|
||||
|
||||
const InterrogateElement &ielem = property->_ielement;
|
||||
|
||||
if (property->_length_function != NULL) {
|
||||
FunctionRemap *len_remap = nullptr;
|
||||
if (property->_length_function != nullptr) {
|
||||
// This is actually a sequence. Wrap this with a special class.
|
||||
FunctionRemap *len_remap = property->_length_function->_remaps.front();
|
||||
vector_string pexprs;
|
||||
len_remap = property->_length_function->_remaps.front();
|
||||
|
||||
out << "/**\n"
|
||||
" * sequence length function for property " << cClassName << "::" << ielem.get_name() << "\n"
|
||||
" * sequence length function for property " << ielem.get_scoped_name() << "\n"
|
||||
" */\n"
|
||||
"static Py_ssize_t Dtool_" + ClassName + "_" + ielem.get_name() + "_Len(PyObject *self) {\n";
|
||||
if (property->_length_function->_has_this) {
|
||||
|
|
@ -6492,72 +6443,72 @@ write_getset(ostream &out, Object *obj, Property *property) {
|
|||
out << " return (Py_ssize_t)" << len_remap->get_call_str("", pexprs) << ";\n";
|
||||
}
|
||||
out << "}\n\n";
|
||||
}
|
||||
|
||||
// Now write out the getitem helper function.
|
||||
if (property->_getter != NULL) {
|
||||
if (property->_getter_remaps.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ielem.is_sequence()) {
|
||||
out <<
|
||||
"/**\n"
|
||||
" * sequence getter for property " << ielem.get_scoped_name() << "\n"
|
||||
" */\n"
|
||||
"static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Sequence_Getitem(PyObject *self, Py_ssize_t index) {\n";
|
||||
|
||||
if (property->_has_this) {
|
||||
out <<
|
||||
"/**\n"
|
||||
" * sequence getter for property " << cClassName << "::" << ielem.get_name() << "\n"
|
||||
" */\n"
|
||||
"static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getitem(PyObject *self, Py_ssize_t index) {\n";
|
||||
if (property->_getter->_has_this ||
|
||||
(property->_has_function && property->_has_function->_has_this)) {
|
||||
out <<
|
||||
" " << cClassName << " *local_this = NULL;\n"
|
||||
" if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"
|
||||
" return NULL;\n"
|
||||
" }\n";
|
||||
}
|
||||
|
||||
// This is a getitem of a sequence type. This means we *need* to raise
|
||||
// IndexError if we're out of bounds.
|
||||
out << " if (index < 0 || index >= (Py_ssize_t)"
|
||||
<< len_remap->get_call_str("local_this", pexprs) << ") {\n";
|
||||
out << " PyErr_SetString(PyExc_IndexError, \"" << ClassName << "." << ielem.get_name() << "[] index out of range\");\n";
|
||||
out << " return NULL;\n";
|
||||
out << " }\n";
|
||||
|
||||
if (property->_has_function != NULL) {
|
||||
if (property->_has_function->_has_this) {
|
||||
out << " if (!local_this->" << property->_has_function->_ifunc.get_name() << "(index)) {\n";
|
||||
} else {
|
||||
out << " if (!" << cClassName << "::" << property->_has_function->_ifunc.get_name() << "(index)) {\n";
|
||||
}
|
||||
out << " Py_INCREF(Py_None);\n"
|
||||
<< " return Py_None;\n"
|
||||
<< " }\n";
|
||||
}
|
||||
|
||||
std::set<FunctionRemap*> remaps;
|
||||
|
||||
// Extract only the getters that take one argument.
|
||||
Function::Remaps::iterator it;
|
||||
for (it = property->_getter->_remaps.begin();
|
||||
it != property->_getter->_remaps.end();
|
||||
++it) {
|
||||
FunctionRemap *remap = *it;
|
||||
int min_num_args = remap->get_min_num_args();
|
||||
int max_num_args = remap->get_max_num_args();
|
||||
if (min_num_args <= 1 && max_num_args >= 1) {
|
||||
remaps.insert(remap);
|
||||
}
|
||||
}
|
||||
|
||||
string expected_params;
|
||||
write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
|
||||
AT_no_args, RF_pyobject | RF_err_null, false, true, "index");
|
||||
|
||||
out << " if (!_PyErr_OCCURRED()) {\n";
|
||||
out << " return Dtool_Raise_BadArgumentsError(\n";
|
||||
output_quoted(out, 6, expected_params);
|
||||
out << ");\n"
|
||||
" }\n"
|
||||
"}\n\n";
|
||||
" " << cClassName << " *local_this = NULL;\n"
|
||||
" if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"
|
||||
" return NULL;\n"
|
||||
" }\n";
|
||||
}
|
||||
|
||||
// This is a getitem of a sequence type. This means we *need* to raise
|
||||
// IndexError if we're out of bounds.
|
||||
out << " if (index < 0 || index >= (Py_ssize_t)"
|
||||
<< len_remap->get_call_str("local_this", pexprs) << ") {\n";
|
||||
out << " PyErr_SetString(PyExc_IndexError, \"" << ClassName << "." << ielem.get_name() << "[] index out of range\");\n";
|
||||
out << " return NULL;\n";
|
||||
out << " }\n";
|
||||
|
||||
/*if (property->_has_function != NULL) {
|
||||
out << " if (!local_this->" << property->_has_function->_ifunc.get_name() << "(index)) {\n"
|
||||
<< " Py_INCREF(Py_None);\n"
|
||||
<< " return Py_None;\n"
|
||||
<< " }\n";
|
||||
}*/
|
||||
|
||||
std::set<FunctionRemap*> remaps;
|
||||
|
||||
// Extract only the getters that take one integral argument.
|
||||
Function::Remaps::iterator it;
|
||||
for (it = property->_getter_remaps.begin();
|
||||
it != property->_getter_remaps.end();
|
||||
++it) {
|
||||
FunctionRemap *remap = *it;
|
||||
int min_num_args = remap->get_min_num_args();
|
||||
int max_num_args = remap->get_max_num_args();
|
||||
if (min_num_args <= 1 && max_num_args >= 1 &&
|
||||
TypeManager::is_integer(remap->_parameters[(size_t)remap->_has_this]._remap->get_new_type())) {
|
||||
remaps.insert(remap);
|
||||
}
|
||||
}
|
||||
|
||||
string expected_params;
|
||||
write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
|
||||
AT_no_args, RF_pyobject | RF_err_null, false, true, "index");
|
||||
|
||||
out << " if (!_PyErr_OCCURRED()) {\n";
|
||||
out << " return Dtool_Raise_BadArgumentsError(\n";
|
||||
output_quoted(out, 6, expected_params);
|
||||
out << ");\n"
|
||||
" }\n"
|
||||
"}\n\n";
|
||||
|
||||
// Write out a setitem if this is not a read-only property.
|
||||
if (property->_setter != NULL) {
|
||||
out << "static int Dtool_" + ClassName + "_" + ielem.get_name() + "_Setitem(PyObject *self, Py_ssize_t index, PyObject *arg) {\n";
|
||||
if (!property->_setter_remaps.empty()) {
|
||||
out << "static int Dtool_" + ClassName + "_" + ielem.get_name() + "_Sequence_Setitem(PyObject *self, Py_ssize_t index, PyObject *arg) {\n";
|
||||
if (property->_has_this) {
|
||||
out << " " << cClassName << " *local_this = NULL;\n";
|
||||
out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this, \""
|
||||
|
|
@ -6595,13 +6546,14 @@ write_getset(ostream &out, Object *obj, Property *property) {
|
|||
|
||||
// Extract only the setters that take two arguments.
|
||||
Function::Remaps::iterator it;
|
||||
for (it = property->_setter->_remaps.begin();
|
||||
it != property->_setter->_remaps.end();
|
||||
for (it = property->_setter_remaps.begin();
|
||||
it != property->_setter_remaps.end();
|
||||
++it) {
|
||||
FunctionRemap *remap = *it;
|
||||
int min_num_args = remap->get_min_num_args();
|
||||
int max_num_args = remap->get_max_num_args();
|
||||
if (min_num_args <= 2 && max_num_args >= 2) {
|
||||
if (min_num_args <= 2 && max_num_args >= 2 &&
|
||||
TypeManager::is_integer(remap->_parameters[1]._remap->get_new_type())) {
|
||||
remaps.insert(remap);
|
||||
}
|
||||
}
|
||||
|
|
@ -6619,8 +6571,192 @@ write_getset(ostream &out, Object *obj, Property *property) {
|
|||
out << " return -1;\n";
|
||||
out << "}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Now write the getter, which returns a special wrapper object.
|
||||
|
||||
// Write the getitem functions.
|
||||
if (ielem.is_mapping()) {
|
||||
out <<
|
||||
"/**\n"
|
||||
" * mapping getitem for property " << ielem.get_scoped_name() << "\n"
|
||||
" */\n"
|
||||
"static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Mapping_Getitem(PyObject *self, PyObject *arg) {\n";
|
||||
|
||||
// Before we do the has_function: if this is also a sequence, then we have
|
||||
// to also handle the case here that we were passed an index.
|
||||
if (ielem.is_sequence()) {
|
||||
out <<
|
||||
"#if PY_MAJOR_VERSION >= 3\n"
|
||||
" if (PyLong_CheckExact(arg)) {\n"
|
||||
"#else\n"
|
||||
" if (PyLong_CheckExact(arg) || PyInt_CheckExact(arg)) {\n"
|
||||
"#endif\n"
|
||||
" return Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem(self, PyLongOrInt_AsSize_t(arg));\n"
|
||||
" }\n\n";
|
||||
}
|
||||
|
||||
if (property->_has_this) {
|
||||
out <<
|
||||
" " << cClassName << " *local_this = NULL;\n"
|
||||
" if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"
|
||||
" return NULL;\n"
|
||||
" }\n";
|
||||
}
|
||||
|
||||
if (property->_has_function != NULL) {
|
||||
std::set<FunctionRemap*> remaps;
|
||||
remaps.insert(property->_has_function->_remaps.begin(),
|
||||
property->_has_function->_remaps.end());
|
||||
|
||||
out << " {\n";
|
||||
string expected_params;
|
||||
write_function_forset(out, remaps, 1, 1, expected_params, 4, true, true,
|
||||
AT_single_arg, RF_raise_keyerror | RF_err_null, false, true);
|
||||
out << " }\n";
|
||||
}
|
||||
|
||||
std::set<FunctionRemap*> remaps;
|
||||
// Extract only the getters that take one argument. Fish out the ones
|
||||
// already taken by the sequence getter.
|
||||
Function::Remaps::iterator it;
|
||||
for (it = property->_getter_remaps.begin();
|
||||
it != property->_getter_remaps.end();
|
||||
++it) {
|
||||
FunctionRemap *remap = *it;
|
||||
int min_num_args = remap->get_min_num_args();
|
||||
int max_num_args = remap->get_max_num_args();
|
||||
if (min_num_args <= 1 && max_num_args >= 1 &&
|
||||
(!ielem.is_sequence() || !TypeManager::is_integer(remap->_parameters[(size_t)remap->_has_this]._remap->get_new_type()))) {
|
||||
remaps.insert(remap);
|
||||
}
|
||||
}
|
||||
|
||||
string expected_params;
|
||||
write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
|
||||
AT_single_arg, RF_pyobject | RF_err_null, false, true);
|
||||
|
||||
out << " if (!_PyErr_OCCURRED()) {\n";
|
||||
out << " return Dtool_Raise_BadArgumentsError(\n";
|
||||
output_quoted(out, 6, expected_params);
|
||||
out << ");\n"
|
||||
" }\n"
|
||||
" return NULL;\n"
|
||||
"}\n\n";
|
||||
|
||||
// Write out a setitem if this is not a read-only property.
|
||||
if (!property->_setter_remaps.empty()) {
|
||||
out <<
|
||||
"/**\n"
|
||||
" * mapping setitem for property " << ielem.get_scoped_name() << "\n"
|
||||
" */\n"
|
||||
"static int Dtool_" + ClassName + "_" + ielem.get_name() + "_Mapping_Setitem(PyObject *self, PyObject *key, PyObject *value) {\n";
|
||||
|
||||
if (property->_has_this) {
|
||||
out <<
|
||||
" " << cClassName << " *local_this = NULL;\n"
|
||||
" if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this, \""
|
||||
<< classNameFromCppName(cClassName, false) << "." << ielem.get_name() << "\")) {\n"
|
||||
" return -1;\n"
|
||||
" }\n\n";
|
||||
}
|
||||
|
||||
out << " if (value == (PyObject *)NULL) {\n";
|
||||
if (property->_deleter != NULL) {
|
||||
out << " PyObject *arg = key;\n";
|
||||
std::set<FunctionRemap*> remaps;
|
||||
remaps.insert(property->_deleter->_remaps.begin(),
|
||||
property->_deleter->_remaps.end());
|
||||
|
||||
string expected_params;
|
||||
write_function_forset(out, remaps, 1, 1,
|
||||
expected_params, 4, true, true, AT_single_arg,
|
||||
RF_int, false, false);
|
||||
out << " return -1;\n";
|
||||
} else {
|
||||
out << " Dtool_Raise_TypeError(\"can't delete " << ielem.get_name() << "[] attribute\");\n"
|
||||
" return -1;\n";
|
||||
}
|
||||
out << " }\n";
|
||||
|
||||
if (property->_clear_function != NULL) {
|
||||
out << " if (value == Py_None) {\n"
|
||||
<< " local_this->" << property->_clear_function->_ifunc.get_name() << "(key);\n"
|
||||
<< " return 0;\n"
|
||||
<< " }\n";
|
||||
}
|
||||
|
||||
std::set<FunctionRemap*> remaps;
|
||||
remaps.insert(property->_setter_remaps.begin(),
|
||||
property->_setter_remaps.end());
|
||||
|
||||
// We have to create an args tuple only to unpack it alter, ugh.
|
||||
out << " PyObject *args = PyTuple_New(2);\n"
|
||||
<< " PyTuple_SET_ITEM(args, 0, key);\n"
|
||||
<< " PyTuple_SET_ITEM(args, 1, value);\n"
|
||||
<< " Py_INCREF(key);\n"
|
||||
<< " Py_INCREF(value);\n";
|
||||
|
||||
string expected_params;
|
||||
write_function_forset(out, remaps, 2, 2,
|
||||
expected_params, 2, true, true, AT_varargs,
|
||||
RF_int | RF_decref_args, false, false);
|
||||
|
||||
out << " if (!_PyErr_OCCURRED()) {\n";
|
||||
out << " Dtool_Raise_BadArgumentsError(\n";
|
||||
output_quoted(out, 6, expected_params);
|
||||
out << ");\n";
|
||||
out << " }\n";
|
||||
out << " Py_DECREF(args);\n";
|
||||
out << " return -1;\n";
|
||||
out << "}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Now write the actual getter wrapper. It will be a different wrapper
|
||||
// depending on whether it's a mapping, sequence, or both.
|
||||
if (ielem.is_mapping() && ielem.is_sequence()) {
|
||||
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
|
||||
if (property->_has_this) {
|
||||
out << " nassertr(self != NULL, NULL);\n"
|
||||
" Py_INCREF(self);\n";
|
||||
} else {
|
||||
out << " Py_XINCREF(self);\n";
|
||||
}
|
||||
out << " Dtool_SeqMapWrapper *wrap = PyObject_New(Dtool_SeqMapWrapper, &Dtool_SeqMapWrapper_Type);\n"
|
||||
" wrap->_seq._base._self = self;\n"
|
||||
" wrap->_seq._len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n"
|
||||
" wrap->_seq._getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem;\n"
|
||||
" wrap->_map_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Getitem;\n";
|
||||
if (!property->_setter_remaps.empty()) {
|
||||
out << " wrap->_seq._setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Setitem;\n";
|
||||
out << " wrap->_map_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Setitem;\n";
|
||||
} else {
|
||||
out << " wrap->_seq._setitem_func = NULL;\n";
|
||||
out << " wrap->_map_setitem_func = NULL;\n";
|
||||
}
|
||||
out << " return (PyObject *)wrap;\n"
|
||||
"}\n\n";
|
||||
|
||||
} else if (ielem.is_mapping()) {
|
||||
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
|
||||
if (property->_has_this) {
|
||||
out << " nassertr(self != NULL, NULL);\n"
|
||||
" Py_INCREF(self);\n";
|
||||
} else {
|
||||
out << " Py_XINCREF(self);\n";
|
||||
}
|
||||
out << " Dtool_MappingWrapper *wrap = PyObject_New(Dtool_MappingWrapper, &Dtool_MappingWrapper_Type);\n"
|
||||
" wrap->_base._self = self;\n"
|
||||
" wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Getitem;\n";
|
||||
if (!property->_setter_remaps.empty()) {
|
||||
out << " wrap->_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Setitem;\n";
|
||||
} else {
|
||||
out << " wrap->_setitem_func = NULL;\n";
|
||||
}
|
||||
out << " return (PyObject *)wrap;\n"
|
||||
"}\n\n";
|
||||
|
||||
} else if (ielem.is_sequence()) {
|
||||
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
|
||||
if (property->_has_this) {
|
||||
out << " nassertr(self != NULL, NULL);\n"
|
||||
|
|
@ -6629,21 +6765,21 @@ write_getset(ostream &out, Object *obj, Property *property) {
|
|||
out << " Py_XINCREF(self);\n";
|
||||
}
|
||||
out << " Dtool_SequenceWrapper *wrap = PyObject_New(Dtool_SequenceWrapper, &Dtool_SequenceWrapper_Type);\n"
|
||||
" wrap->_base = self;\n"
|
||||
" wrap->_base._self = self;\n"
|
||||
" wrap->_len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n"
|
||||
" wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Getitem;\n";
|
||||
if (property->_setter != NULL) {
|
||||
out << " wrap->_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Setitem;\n";
|
||||
" wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem;\n";
|
||||
if (!property->_setter_remaps.empty()) {
|
||||
out << " wrap->_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Setitem;\n";
|
||||
} else {
|
||||
out << " wrap->_setitem_func = NULL;\n";
|
||||
}
|
||||
out << " return (PyObject *)wrap;\n"
|
||||
"}\n\n";
|
||||
"}\n\n";
|
||||
|
||||
} else if (property->_getter != NULL) {
|
||||
} else {
|
||||
// Write out a regular, unwrapped getter.
|
||||
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
|
||||
FunctionRemap *remap = property->_getter->_remaps.front();
|
||||
FunctionRemap *remap = property->_getter_remaps.front();
|
||||
|
||||
if (remap->_has_this) {
|
||||
if (remap->_const_method) {
|
||||
|
|
@ -6679,7 +6815,7 @@ write_getset(ostream &out, Object *obj, Property *property) {
|
|||
out << "}\n\n";
|
||||
|
||||
// Write out a setter if this is not a read-only property.
|
||||
if (property->_setter != NULL) {
|
||||
if (!property->_setter_remaps.empty()) {
|
||||
out << "static int Dtool_" + ClassName + "_" + ielem.get_name() + "_Setter(PyObject *self, PyObject *arg, void *) {\n";
|
||||
if (remap->_has_this) {
|
||||
out << " " << cClassName << " *local_this = NULL;\n";
|
||||
|
|
@ -6698,7 +6834,7 @@ write_getset(ostream &out, Object *obj, Property *property) {
|
|||
<< " return 0;\n";
|
||||
} else {
|
||||
out << " Dtool_Raise_TypeError(\"can't delete " << ielem.get_name() << " attribute\");\n"
|
||||
" return -1;\n";
|
||||
" return -1;\n";
|
||||
}
|
||||
out << " }\n";
|
||||
|
||||
|
|
@ -6717,9 +6853,9 @@ write_getset(ostream &out, Object *obj, Property *property) {
|
|||
|
||||
// Extract only the setters that take one argument.
|
||||
Function::Remaps::iterator it;
|
||||
for (it = property->_setter->_remaps.begin();
|
||||
it != property->_setter->_remaps.end();
|
||||
++it) {
|
||||
for (it = property->_setter_remaps.begin();
|
||||
it != property->_setter_remaps.end();
|
||||
++it) {
|
||||
FunctionRemap *remap = *it;
|
||||
int min_num_args = remap->get_min_num_args();
|
||||
int max_num_args = remap->get_max_num_args();
|
||||
|
|
@ -6831,62 +6967,8 @@ record_object(TypeIndex type_index) {
|
|||
ElementIndex element_index = itype.get_element(ei);
|
||||
const InterrogateElement &ielement = idb->get_element(element_index);
|
||||
|
||||
Property *property = new Property(ielement);
|
||||
|
||||
if (ielement.has_setter()) {
|
||||
FunctionIndex func_index = ielement.get_setter();
|
||||
Function *setter = record_function(itype, func_index);
|
||||
if (is_function_legal(setter)) {
|
||||
property->_setter = setter;
|
||||
property->_has_this |= setter->_has_this;
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.has_getter()) {
|
||||
FunctionIndex func_index = ielement.get_getter();
|
||||
Function *getter = record_function(itype, func_index);
|
||||
if (is_function_legal(getter)) {
|
||||
property->_getter = getter;
|
||||
property->_has_this |= getter->_has_this;
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.has_has_function()) {
|
||||
FunctionIndex func_index = ielement.get_has_function();
|
||||
Function *has_function = record_function(itype, func_index);
|
||||
if (is_function_legal(has_function)) {
|
||||
property->_has_function = has_function;
|
||||
property->_has_this |= has_function->_has_this;
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.has_clear_function()) {
|
||||
FunctionIndex func_index = ielement.get_clear_function();
|
||||
Function *clear_function = record_function(itype, func_index);
|
||||
if (is_function_legal(clear_function)) {
|
||||
property->_clear_function = clear_function;
|
||||
property->_has_this |= clear_function->_has_this;
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.has_del_function()) {
|
||||
FunctionIndex func_index = ielement.get_del_function();
|
||||
Function *del_function = record_function(itype, func_index);
|
||||
if (is_function_legal(del_function)) {
|
||||
property->_deleter = del_function;
|
||||
property->_has_this |= del_function->_has_this;
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.is_sequence()) {
|
||||
FunctionIndex func_index = ielement.get_length_function();
|
||||
property->_length_function = record_function(itype, func_index);
|
||||
if (property->_length_function != nullptr) {
|
||||
property->_has_this |= property->_length_function->_has_this;
|
||||
}
|
||||
}
|
||||
|
||||
if (property->_getter != NULL) {
|
||||
Property *property = record_property(itype, itype.get_element(ei));
|
||||
if (property != nullptr) {
|
||||
object->_properties.push_back(property);
|
||||
} else {
|
||||
// No use exporting a property without a getter.
|
||||
|
|
@ -6918,6 +7000,96 @@ record_object(TypeIndex type_index) {
|
|||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
InterfaceMaker::Property *InterfaceMakerPythonNative::
|
||||
record_property(const InterrogateType &itype, ElementIndex element_index) {
|
||||
InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
|
||||
const InterrogateElement &ielement = idb->get_element(element_index);
|
||||
if (!ielement.has_getter()) {
|
||||
// A property needs at the very least a getter.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Property *property;
|
||||
{
|
||||
FunctionIndex func_index = ielement.get_getter();
|
||||
if (func_index != 0) {
|
||||
const InterrogateFunction &ifunc = idb->get_function(func_index);
|
||||
property = new Property(ielement);
|
||||
|
||||
InterrogateFunction::Instances::const_iterator ii;
|
||||
for (ii = ifunc._instances->begin(); ii != ifunc._instances->end(); ++ii) {
|
||||
CPPInstance *cppfunc = (*ii).second;
|
||||
FunctionRemap *remap =
|
||||
make_function_remap(itype, ifunc, cppfunc, 0);
|
||||
|
||||
if (remap != nullptr && is_remap_legal(remap)) {
|
||||
property->_getter_remaps.push_back(remap);
|
||||
property->_has_this |= remap->_has_this;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.has_setter()) {
|
||||
FunctionIndex func_index = ielement.get_setter();
|
||||
if (func_index != 0) {
|
||||
const InterrogateFunction &ifunc = idb->get_function(func_index);
|
||||
|
||||
InterrogateFunction::Instances::const_iterator ii;
|
||||
for (ii = ifunc._instances->begin(); ii != ifunc._instances->end(); ++ii) {
|
||||
CPPInstance *cppfunc = (*ii).second;
|
||||
FunctionRemap *remap =
|
||||
make_function_remap(itype, ifunc, cppfunc, 0);
|
||||
|
||||
if (remap != nullptr && is_remap_legal(remap)) {
|
||||
property->_setter_remaps.push_back(remap);
|
||||
property->_has_this |= remap->_has_this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.has_has_function()) {
|
||||
FunctionIndex func_index = ielement.get_has_function();
|
||||
Function *has_function = record_function(itype, func_index);
|
||||
if (is_function_legal(has_function)) {
|
||||
property->_has_function = has_function;
|
||||
property->_has_this |= has_function->_has_this;
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.has_clear_function()) {
|
||||
FunctionIndex func_index = ielement.get_clear_function();
|
||||
Function *clear_function = record_function(itype, func_index);
|
||||
if (is_function_legal(clear_function)) {
|
||||
property->_clear_function = clear_function;
|
||||
property->_has_this |= clear_function->_has_this;
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.has_del_function()) {
|
||||
FunctionIndex func_index = ielement.get_del_function();
|
||||
Function *del_function = record_function(itype, func_index);
|
||||
if (is_function_legal(del_function)) {
|
||||
property->_deleter = del_function;
|
||||
property->_has_this |= del_function->_has_this;
|
||||
}
|
||||
}
|
||||
|
||||
if (ielement.is_sequence()) {
|
||||
FunctionIndex func_index = ielement.get_length_function();
|
||||
property->_length_function = record_function(itype, func_index);
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks through the set of functions in the database and generates wrappers
|
||||
* for each function, storing these in the database. No actual code should be
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public:
|
|||
virtual bool separate_overloading();
|
||||
|
||||
virtual Object *record_object(TypeIndex type_index);
|
||||
Property *record_property(const InterrogateType &itype, ElementIndex element_index);
|
||||
|
||||
protected:
|
||||
virtual string get_wrapper_prefix();
|
||||
|
|
@ -111,6 +112,9 @@ private:
|
|||
|
||||
// Decref temporary args object before returning.
|
||||
RF_decref_args = 0x1000,
|
||||
|
||||
// This raises a KeyError on falsey (or -1) return value.
|
||||
RF_raise_keyerror = 0x4000,
|
||||
};
|
||||
|
||||
class SlottedFunctionDef {
|
||||
|
|
|
|||
|
|
@ -1798,34 +1798,46 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
|
|||
}
|
||||
|
||||
string property_name = make_property->get_local_name(&parser);
|
||||
InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
|
||||
|
||||
// First, check to see if it's already there.
|
||||
ElementIndex index = 0;
|
||||
PropertiesByName::const_iterator tni =
|
||||
_properties_by_name.find(property_name);
|
||||
if (tni != _properties_by_name.end()) {
|
||||
ElementIndex index = (*tni).second;
|
||||
return index;
|
||||
index = (*tni).second;
|
||||
const InterrogateElement &ielem = idb->get_element(index);
|
||||
if (ielem._make_property == make_property) {
|
||||
// This is the same property.
|
||||
return index;
|
||||
}
|
||||
|
||||
// It is possible to have property definitions with the same name, but
|
||||
// they cannot define conflicting interfaces.
|
||||
if ((ielem.is_sequence() || ielem.is_mapping()) !=
|
||||
(make_property->_type != CPPMakeProperty::T_normal)) {
|
||||
cerr << "Conflicting property definitions for " << property_name << "!\n";
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a length function (ie. this is a sequence property), we should
|
||||
// find the function that will give us the length.
|
||||
FunctionIndex length_function = 0;
|
||||
bool is_seq = false;
|
||||
|
||||
CPPFunctionGroup::Instances::const_iterator fi;
|
||||
CPPFunctionGroup *fgroup = make_property->_length_function;
|
||||
if (fgroup != NULL) {
|
||||
is_seq = true;
|
||||
|
||||
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
|
||||
CPPInstance *function = (*fi);
|
||||
CPPFunctionType *ftype =
|
||||
function->_type->as_function_type();
|
||||
if (ftype != NULL) {
|
||||
length_function = get_function(function, "", struct_type,
|
||||
struct_type->get_scope(), 0);
|
||||
if (length_function != 0) {
|
||||
break;
|
||||
if (make_property->_type & CPPMakeProperty::T_sequence) {
|
||||
CPPFunctionGroup::Instances::const_iterator fi;
|
||||
CPPFunctionGroup *fgroup = make_property->_length_function;
|
||||
if (fgroup != NULL) {
|
||||
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
|
||||
CPPInstance *function = (*fi);
|
||||
CPPFunctionType *ftype =
|
||||
function->_type->as_function_type();
|
||||
if (ftype != NULL) {
|
||||
length_function = get_function(function, "", struct_type,
|
||||
struct_type->get_scope(), 0);
|
||||
if (length_function != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1840,7 +1852,10 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
|
|||
CPPInstance *getter = NULL;
|
||||
CPPType *return_type = NULL;
|
||||
|
||||
fgroup = make_property->_get_function;
|
||||
// How many arguments we expect the getter to have.
|
||||
size_t num_args = (size_t)(make_property->_type != CPPMakeProperty::T_normal);
|
||||
|
||||
CPPFunctionGroup *fgroup = make_property->_get_function;
|
||||
if (fgroup != NULL) {
|
||||
CPPFunctionGroup::Instances::const_iterator fi;
|
||||
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
|
||||
|
|
@ -1852,9 +1867,13 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
|
|||
|
||||
const CPPParameterList::Parameters ¶ms = ftype->_parameters->_parameters;
|
||||
|
||||
size_t expected_num_args = (size_t)is_seq;
|
||||
size_t expected_num_args = 0;
|
||||
size_t index_arg = 0;
|
||||
|
||||
if (make_property->_type != CPPMakeProperty::T_normal) {
|
||||
++expected_num_args;
|
||||
}
|
||||
|
||||
if (!params.empty() && params[0]->get_simple_name() == "self" &&
|
||||
TypeManager::is_pointer_to_PyObject(params[0]->_type)) {
|
||||
// Taking a PyObject *self argument.
|
||||
|
|
@ -1867,7 +1886,8 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
|
|||
(params.size() > expected_num_args &&
|
||||
params[expected_num_args]->_initializer != NULL)) {
|
||||
// If this is a sequence getter, it must take an index argument.
|
||||
if (is_seq && !TypeManager::is_integer(params[index_arg]->_type)) {
|
||||
if (make_property->_type == CPPMakeProperty::T_sequence &&
|
||||
!TypeManager::is_integer(params[index_arg]->_type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1899,13 +1919,14 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
|
|||
CPPInstance *function = (*fi);
|
||||
CPPFunctionType *ftype =
|
||||
function->_type->as_function_type();
|
||||
if (ftype != NULL && TypeManager::is_bool(ftype->_return_type)) {
|
||||
if (ftype != nullptr && (TypeManager::is_integer(ftype->_return_type) ||
|
||||
TypeManager::is_pointer(ftype->_return_type))) {
|
||||
hasser = function;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasser == NULL || return_type == NULL) {
|
||||
if (hasser == nullptr) {
|
||||
cerr << "No instance of has-function '"
|
||||
<< fgroup->_name << "' is suitable!\n";
|
||||
return 0;
|
||||
|
|
@ -1921,44 +1942,77 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
|
|||
for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
|
||||
CPPInstance *function = (*fi);
|
||||
CPPFunctionType *ftype = function->_type->as_function_type();
|
||||
if (ftype != NULL && ftype->_parameters->_parameters.size() == (size_t)is_seq) {
|
||||
if (ftype != NULL && ftype->_parameters->_parameters.size() == num_args) {
|
||||
deleter = function;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (deleter == NULL || return_type == NULL) {
|
||||
if (deleter == nullptr) {
|
||||
cerr << "No instance of delete-function '"
|
||||
<< fgroup->_name << "' is suitable!\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
|
||||
// It isn't here, so we'll have to define it.
|
||||
ElementIndex index = idb->get_next_index();
|
||||
_properties_by_name[property_name] = index;
|
||||
if (index == 0) {
|
||||
// It isn't here, so we'll have to define it.
|
||||
index = idb->get_next_index();
|
||||
_properties_by_name[property_name] = index;
|
||||
|
||||
InterrogateElement iproperty;
|
||||
iproperty._name = make_property->get_simple_name();
|
||||
iproperty._scoped_name = descope(make_property->get_local_name(&parser));
|
||||
InterrogateElement iproperty;
|
||||
iproperty._name = make_property->get_simple_name();
|
||||
iproperty._scoped_name = descope(make_property->get_local_name(&parser));
|
||||
idb->add_element(index, iproperty);
|
||||
}
|
||||
|
||||
InterrogateElement &iproperty = idb->update_element(index);
|
||||
|
||||
if (return_type != NULL) {
|
||||
iproperty._type = get_type(TypeManager::unwrap_reference(return_type), false);
|
||||
TypeIndex return_index = get_type(TypeManager::unwrap_reference(return_type), false);
|
||||
if (iproperty._type != 0 && iproperty._type != return_index) {
|
||||
cerr << "Property " << property_name << " has inconsistent element type!\n";
|
||||
}
|
||||
} else {
|
||||
iproperty._type = 0;
|
||||
}
|
||||
|
||||
if (length_function != 0) {
|
||||
if (make_property->_type & CPPMakeProperty::T_sequence) {
|
||||
iproperty._flags |= InterrogateElement::F_sequence;
|
||||
iproperty._length_function = length_function;
|
||||
}
|
||||
|
||||
if (getter != NULL) {
|
||||
iproperty._flags |= InterrogateElement::F_has_getter;
|
||||
iproperty._getter = get_function(getter, "", struct_type,
|
||||
struct_type->get_scope(), 0);
|
||||
nassertr(iproperty._getter, 0);
|
||||
if (make_property->_type & CPPMakeProperty::T_mapping) {
|
||||
iproperty._flags |= InterrogateElement::F_mapping;
|
||||
}
|
||||
|
||||
if (make_property->_type == CPPMakeProperty::T_normal) {
|
||||
if (getter != NULL) {
|
||||
iproperty._flags |= InterrogateElement::F_has_getter;
|
||||
iproperty._getter = get_function(getter, "", struct_type,
|
||||
struct_type->get_scope(), 0);
|
||||
nassertr(iproperty._getter, 0);
|
||||
}
|
||||
} else {
|
||||
// We could have a mixed sequence/mapping property, so synthesize a
|
||||
// getitem function. We don't really care what's in here; we just use
|
||||
// this to store the remaps.
|
||||
if (!iproperty.has_getter()) {
|
||||
iproperty._flags |= InterrogateElement::F_has_getter;
|
||||
iproperty._getter = InterrogateDatabase::get_ptr()->get_next_index();
|
||||
InterrogateFunction *ifunction = new InterrogateFunction;
|
||||
ifunction->_instances = new InterrogateFunction::Instances;
|
||||
InterrogateDatabase::get_ptr()->add_function(iproperty._getter, ifunction);
|
||||
}
|
||||
|
||||
// Add our getter to the generated getitem function.
|
||||
string signature = TypeManager::get_function_signature(getter);
|
||||
InterrogateFunction &ifunction =
|
||||
InterrogateDatabase::get_ptr()->update_function(iproperty._getter);
|
||||
if (ifunction._instances == nullptr) {
|
||||
ifunction._instances = new InterrogateFunction::Instances;
|
||||
}
|
||||
ifunction._instances->insert(InterrogateFunction::Instances::value_type(signature, getter));
|
||||
}
|
||||
|
||||
if (hasser != NULL) {
|
||||
|
|
@ -2011,7 +2065,6 @@ get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CP
|
|||
}
|
||||
}
|
||||
|
||||
idb->add_element(index, iproperty);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
|
@ -2621,7 +2674,9 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
|
|||
|
||||
} else if ((*di)->get_subtype() == CPPDeclaration::ST_make_property) {
|
||||
ElementIndex element_index = get_make_property((*di)->as_make_property(), cpptype, scope);
|
||||
itype._elements.push_back(element_index);
|
||||
if (find(itype._elements.begin(), itype._elements.end(), element_index) == itype._elements.end()) {
|
||||
itype._elements.push_back(element_index);
|
||||
}
|
||||
|
||||
} else if ((*di)->get_subtype() == CPPDeclaration::ST_make_seq) {
|
||||
MakeSeqIndex make_seq_index = get_make_seq((*di)->as_make_seq(), cpptype);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ InterrogateElement(InterrogateModuleDef *def) :
|
|||
_clear_function = 0;
|
||||
_del_function = 0;
|
||||
_length_function = 0;
|
||||
_make_property = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -52,6 +53,7 @@ operator = (const InterrogateElement ©) {
|
|||
_clear_function = copy._clear_function;
|
||||
_del_function = copy._del_function;
|
||||
_length_function = copy._length_function;
|
||||
_make_property = copy._make_property;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -199,6 +201,14 @@ get_length_function() const {
|
|||
return _length_function;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE bool InterrogateElement::
|
||||
is_mapping() const {
|
||||
return (_flags & F_mapping) != 0;
|
||||
}
|
||||
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const InterrogateElement &element) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "interrogateComponent.h"
|
||||
|
||||
class IndexRemapper;
|
||||
class CPPMakeProperty;
|
||||
|
||||
/**
|
||||
* An internal representation of a data element, like a data member or a
|
||||
|
|
@ -51,6 +52,7 @@ public:
|
|||
INLINE FunctionIndex get_del_function() const;
|
||||
INLINE bool is_sequence() const;
|
||||
INLINE FunctionIndex get_length_function() const;
|
||||
INLINE bool is_mapping() const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
void input(istream &in);
|
||||
|
|
@ -80,6 +82,8 @@ private:
|
|||
FunctionIndex _clear_function;
|
||||
FunctionIndex _del_function;
|
||||
|
||||
CPPMakeProperty *_make_property;
|
||||
|
||||
friend class InterrogateBuilder;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -322,11 +322,11 @@ PyObject *_Dtool_Raise_BadArgumentsError() {
|
|||
* NULL, otherwise Py_None.
|
||||
*/
|
||||
PyObject *_Dtool_Return_None() {
|
||||
if (_PyErr_OCCURRED()) {
|
||||
if (UNLIKELY(_PyErr_OCCURRED())) {
|
||||
return NULL;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
if (Notify::ptr()->has_assert_failed()) {
|
||||
if (UNLIKELY(Notify::ptr()->has_assert_failed())) {
|
||||
return Dtool_Raise_AssertionError();
|
||||
}
|
||||
#endif
|
||||
|
|
@ -339,11 +339,11 @@ PyObject *_Dtool_Return_None() {
|
|||
* NULL, otherwise the given boolean value as a PyObject *.
|
||||
*/
|
||||
PyObject *Dtool_Return_Bool(bool value) {
|
||||
if (_PyErr_OCCURRED()) {
|
||||
if (UNLIKELY(_PyErr_OCCURRED())) {
|
||||
return NULL;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
if (Notify::ptr()->has_assert_failed()) {
|
||||
if (UNLIKELY(Notify::ptr()->has_assert_failed())) {
|
||||
return Dtool_Raise_AssertionError();
|
||||
}
|
||||
#endif
|
||||
|
|
@ -358,11 +358,11 @@ PyObject *Dtool_Return_Bool(bool value) {
|
|||
* increased.
|
||||
*/
|
||||
PyObject *_Dtool_Return(PyObject *value) {
|
||||
if (_PyErr_OCCURRED()) {
|
||||
if (UNLIKELY(_PyErr_OCCURRED())) {
|
||||
return NULL;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
if (Notify::ptr()->has_assert_failed()) {
|
||||
if (UNLIKELY(Notify::ptr()->has_assert_failed())) {
|
||||
return Dtool_Raise_AssertionError();
|
||||
}
|
||||
#endif
|
||||
|
|
@ -614,6 +614,14 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
|
|||
return Dtool_Raise_TypeError("PyType_Ready(Dtool_SequenceWrapper)");
|
||||
}
|
||||
|
||||
if (PyType_Ready(&Dtool_MappingWrapper_Type) < 0) {
|
||||
return Dtool_Raise_TypeError("PyType_Ready(Dtool_MappingWrapper)");
|
||||
}
|
||||
|
||||
if (PyType_Ready(&Dtool_SeqMapWrapper_Type) < 0) {
|
||||
return Dtool_Raise_TypeError("PyType_Ready(Dtool_SeqMapWrapper)");
|
||||
}
|
||||
|
||||
if (PyType_Ready(&Dtool_StaticProperty_Type) < 0) {
|
||||
return Dtool_Raise_TypeError("PyType_Ready(Dtool_StaticProperty_Type)");
|
||||
}
|
||||
|
|
@ -1028,34 +1036,79 @@ bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args, PyObject *kwds)
|
|||
}
|
||||
|
||||
/**
|
||||
* This class is returned from properties that require a settable interface,
|
||||
* ie. something.children[i] = 3.
|
||||
* These classes are returned from properties that require a subscript
|
||||
* interface, ie. something.children[i] = 3.
|
||||
*/
|
||||
static void Dtool_SequenceWrapper_dealloc(PyObject *self) {
|
||||
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
|
||||
static void Dtool_WrapperBase_dealloc(PyObject *self) {
|
||||
Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self;
|
||||
nassertv(wrap);
|
||||
Py_XDECREF(wrap->_base);
|
||||
Py_XDECREF(wrap->_self);
|
||||
}
|
||||
|
||||
static Py_ssize_t Dtool_SequenceWrapper_length(PyObject *self) {
|
||||
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
|
||||
nassertr(wrap, -1);
|
||||
nassertr(wrap->_len_func, -1);
|
||||
return wrap->_len_func(wrap->_base);
|
||||
if (wrap->_len_func != nullptr) {
|
||||
nassertr(wrap->_len_func, -1);
|
||||
return wrap->_len_func(wrap->_base._self);
|
||||
} else {
|
||||
Dtool_Raise_TypeError("property does not support len()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *Dtool_SequenceWrapper_getitem(PyObject *self, Py_ssize_t index) {
|
||||
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
|
||||
nassertr(wrap, NULL);
|
||||
nassertr(wrap->_getitem_func, NULL);
|
||||
return wrap->_getitem_func(wrap->_base, index);
|
||||
nassertr(wrap, nullptr);
|
||||
nassertr(wrap->_getitem_func, nullptr);
|
||||
return wrap->_getitem_func(wrap->_base._self, index);
|
||||
}
|
||||
|
||||
static int Dtool_SequenceWrapper_setitem(PyObject *self, Py_ssize_t index, PyObject *value) {
|
||||
Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
|
||||
nassertr(wrap, -1);
|
||||
nassertr(wrap->_setitem_func, -1);
|
||||
return wrap->_setitem_func(wrap->_base, index, value);
|
||||
if (wrap->_setitem_func != nullptr) {
|
||||
return wrap->_setitem_func(wrap->_base._self, index, value);
|
||||
} else {
|
||||
Dtool_Raise_TypeError("property does not support item assignment");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *Dtool_MappingWrapper_getitem(PyObject *self, PyObject *key) {
|
||||
Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
|
||||
nassertr(wrap, nullptr);
|
||||
nassertr(wrap->_getitem_func, nullptr);
|
||||
return wrap->_getitem_func(wrap->_base._self, key);
|
||||
}
|
||||
|
||||
static int Dtool_MappingWrapper_setitem(PyObject *self, PyObject *key, PyObject *value) {
|
||||
Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
|
||||
nassertr(wrap, -1);
|
||||
if (wrap->_setitem_func != nullptr) {
|
||||
return wrap->_setitem_func(wrap->_base._self, key, value);
|
||||
} else {
|
||||
Dtool_Raise_TypeError("property does not support item assignment");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *Dtool_SeqMapWrapper_getitem(PyObject *self, PyObject *key) {
|
||||
Dtool_SeqMapWrapper *wrap = (Dtool_SeqMapWrapper *)self;
|
||||
nassertr(wrap, nullptr);
|
||||
nassertr(wrap->_map_getitem_func, nullptr);
|
||||
return wrap->_map_getitem_func(wrap->_seq._base._self, key);
|
||||
}
|
||||
|
||||
static int Dtool_SeqMapWrapper_setitem(PyObject *self, PyObject *key, PyObject *value) {
|
||||
Dtool_SeqMapWrapper *wrap = (Dtool_SeqMapWrapper *)self;
|
||||
nassertr(wrap, -1);
|
||||
if (wrap->_map_setitem_func != nullptr) {
|
||||
return wrap->_map_setitem_func(wrap->_seq._base._self, key, value);
|
||||
} else {
|
||||
Dtool_Raise_TypeError("property does not support item assignment");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PySequenceMethods Dtool_SequenceWrapper_SequenceMethods = {
|
||||
|
|
@ -1071,12 +1124,27 @@ static PySequenceMethods Dtool_SequenceWrapper_SequenceMethods = {
|
|||
0, // sq_inplace_repeat
|
||||
};
|
||||
|
||||
static PyMappingMethods Dtool_MappingWrapper_MappingMethods = {
|
||||
0, // mp_length
|
||||
Dtool_MappingWrapper_getitem,
|
||||
Dtool_MappingWrapper_setitem,
|
||||
};
|
||||
|
||||
static PyMappingMethods Dtool_SeqMapWrapper_MappingMethods = {
|
||||
Dtool_SequenceWrapper_length,
|
||||
Dtool_SeqMapWrapper_getitem,
|
||||
Dtool_SeqMapWrapper_setitem,
|
||||
};
|
||||
|
||||
/**
|
||||
* This variant defines only a sequence interface.
|
||||
*/
|
||||
PyTypeObject Dtool_SequenceWrapper_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"sequence wrapper",
|
||||
sizeof(Dtool_SequenceWrapper),
|
||||
0, // tp_itemsize
|
||||
Dtool_SequenceWrapper_dealloc,
|
||||
Dtool_WrapperBase_dealloc,
|
||||
0, // tp_print
|
||||
0, // tp_getattr
|
||||
0, // tp_setattr
|
||||
|
|
@ -1262,4 +1330,128 @@ PyTypeObject Dtool_StaticProperty_Type = {
|
|||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* This variant defines only a mapping interface.
|
||||
*/
|
||||
PyTypeObject Dtool_MappingWrapper_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"mapping wrapper",
|
||||
sizeof(Dtool_MappingWrapper),
|
||||
0, // tp_itemsize
|
||||
Dtool_WrapperBase_dealloc,
|
||||
0, // tp_print
|
||||
0, // tp_getattr
|
||||
0, // tp_setattr
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
0, // tp_reserved
|
||||
#else
|
||||
0, // tp_compare
|
||||
#endif
|
||||
0, // tp_repr
|
||||
0, // tp_as_number
|
||||
0, // tp_as_sequence
|
||||
&Dtool_MappingWrapper_MappingMethods,
|
||||
0, // tp_hash
|
||||
0, // tp_call
|
||||
0, // tp_str
|
||||
PyObject_GenericGetAttr,
|
||||
PyObject_GenericSetAttr,
|
||||
0, // tp_as_buffer
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
|
||||
0, // tp_doc
|
||||
0, // tp_traverse
|
||||
0, // tp_clear
|
||||
0, // tp_richcompare
|
||||
0, // tp_weaklistoffset
|
||||
0, // tp_iter
|
||||
0, // tp_iternext
|
||||
0, // tp_methods
|
||||
0, // tp_members
|
||||
0, // tp_getset
|
||||
0, // tp_base
|
||||
0, // tp_dict
|
||||
0, // tp_descr_get
|
||||
0, // tp_descr_set
|
||||
0, // tp_dictoffset
|
||||
0, // tp_init
|
||||
PyType_GenericAlloc,
|
||||
0, // tp_new
|
||||
PyObject_Del,
|
||||
0, // tp_is_gc
|
||||
0, // tp_bases
|
||||
0, // tp_mro
|
||||
0, // tp_cache
|
||||
0, // tp_subclasses
|
||||
0, // tp_weaklist
|
||||
0, // tp_del
|
||||
#if PY_VERSION_HEX >= 0x02060000
|
||||
0, // tp_version_tag
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x03040000
|
||||
0, // tp_finalize
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* This variant defines both a sequence and mapping interface.
|
||||
*/
|
||||
PyTypeObject Dtool_SeqMapWrapper_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"sequence/mapping wrapper",
|
||||
sizeof(Dtool_SeqMapWrapper),
|
||||
0, // tp_itemsize
|
||||
Dtool_WrapperBase_dealloc,
|
||||
0, // tp_print
|
||||
0, // tp_getattr
|
||||
0, // tp_setattr
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
0, // tp_reserved
|
||||
#else
|
||||
0, // tp_compare
|
||||
#endif
|
||||
0, // tp_repr
|
||||
0, // tp_as_number
|
||||
&Dtool_SequenceWrapper_SequenceMethods,
|
||||
&Dtool_SeqMapWrapper_MappingMethods,
|
||||
0, // tp_hash
|
||||
0, // tp_call
|
||||
0, // tp_str
|
||||
PyObject_GenericGetAttr,
|
||||
PyObject_GenericSetAttr,
|
||||
0, // tp_as_buffer
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
|
||||
0, // tp_doc
|
||||
0, // tp_traverse
|
||||
0, // tp_clear
|
||||
0, // tp_richcompare
|
||||
0, // tp_weaklistoffset
|
||||
0, // tp_iter
|
||||
0, // tp_iternext
|
||||
0, // tp_methods
|
||||
0, // tp_members
|
||||
0, // tp_getset
|
||||
0, // tp_base
|
||||
0, // tp_dict
|
||||
0, // tp_descr_get
|
||||
0, // tp_descr_set
|
||||
0, // tp_dictoffset
|
||||
0, // tp_init
|
||||
PyType_GenericAlloc,
|
||||
0, // tp_new
|
||||
PyObject_Del,
|
||||
0, // tp_is_gc
|
||||
0, // tp_bases
|
||||
0, // tp_mro
|
||||
0, // tp_cache
|
||||
0, // tp_subclasses
|
||||
0, // tp_weaklist
|
||||
0, // tp_del
|
||||
#if PY_VERSION_HEX >= 0x02060000
|
||||
0, // tp_version_tag
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x03040000
|
||||
0, // tp_finalize
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
|
|
|||
|
|
@ -320,9 +320,9 @@ EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred();
|
|||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define Dtool_CheckErrorOccurred() (_PyErr_OCCURRED() != NULL)
|
||||
#define Dtool_CheckErrorOccurred() (UNLIKELY(_PyErr_OCCURRED() != NULL))
|
||||
#else
|
||||
#define Dtool_CheckErrorOccurred() _Dtool_CheckErrorOccurred()
|
||||
#define Dtool_CheckErrorOccurred() (UNLIKELY(_Dtool_CheckErrorOccurred()))
|
||||
#endif
|
||||
|
||||
EXPCL_INTERROGATEDB PyObject *Dtool_Raise_AssertionError();
|
||||
|
|
@ -339,6 +339,9 @@ EXPCL_INTERROGATEDB PyObject *_Dtool_Raise_BadArgumentsError();
|
|||
#define Dtool_Raise_BadArgumentsError(x) Dtool_Raise_TypeError("Arguments must match:\n" x)
|
||||
#endif
|
||||
|
||||
// These functions are similar to Dtool_WrapValue, except that they also
|
||||
// contain code for checking assertions and exceptions when compiling with
|
||||
// NDEBUG mode on.
|
||||
EXPCL_INTERROGATEDB PyObject *_Dtool_Return_None();
|
||||
EXPCL_INTERROGATEDB PyObject *Dtool_Return_Bool(bool value);
|
||||
EXPCL_INTERROGATEDB PyObject *_Dtool_Return(PyObject *value);
|
||||
|
|
@ -465,18 +468,36 @@ EXPCL_INTERROGATEDB PyObject *
|
|||
map_deepcopy_to_copy(PyObject *self, PyObject *args);
|
||||
|
||||
/**
|
||||
* This class is returned from properties that require a settable interface,
|
||||
* ie. something.children[i] = 3.
|
||||
* These classes are returned from properties that require a subscript
|
||||
* interface, ie. something.children[i] = 3.
|
||||
*/
|
||||
struct Dtool_WrapperBase {
|
||||
PyObject_HEAD;
|
||||
PyObject *_self;
|
||||
};
|
||||
|
||||
struct Dtool_SequenceWrapper {
|
||||
PyObject_HEAD
|
||||
PyObject *_base;
|
||||
Dtool_WrapperBase _base;
|
||||
lenfunc _len_func;
|
||||
ssizeargfunc _getitem_func;
|
||||
ssizeobjargproc _setitem_func;
|
||||
};
|
||||
|
||||
struct Dtool_MappingWrapper {
|
||||
Dtool_WrapperBase _base;
|
||||
binaryfunc _getitem_func;
|
||||
objobjargproc _setitem_func;
|
||||
};
|
||||
|
||||
struct Dtool_SeqMapWrapper {
|
||||
Dtool_SequenceWrapper _seq;
|
||||
binaryfunc _map_getitem_func;
|
||||
objobjargproc _map_setitem_func;
|
||||
};
|
||||
|
||||
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_SequenceWrapper_Type;
|
||||
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_MappingWrapper_Type;
|
||||
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_SeqMapWrapper_Type;
|
||||
EXPCL_INTERROGATEDB extern PyTypeObject Dtool_StaticProperty_Type;
|
||||
|
||||
EXPCL_INTERROGATEDB PyObject *Dtool_NewStaticProperty(PyTypeObject *obj, const PyGetSetDef *getset);
|
||||
|
|
|
|||
|
|
@ -71,11 +71,7 @@ is_on(NotifySeverity severity) const {
|
|||
INLINE bool NotifyCategory::
|
||||
is_spam() const {
|
||||
// Instruct the compiler to optimize for the usual case.
|
||||
#ifdef __GNUC__
|
||||
return __builtin_expect(is_on(NS_spam), 0);
|
||||
#else
|
||||
return is_on(NS_spam);
|
||||
#endif
|
||||
return UNLIKELY(is_on(NS_spam));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -84,11 +80,7 @@ is_spam() const {
|
|||
INLINE bool NotifyCategory::
|
||||
is_debug() const {
|
||||
// Instruct the compiler to optimize for the usual case.
|
||||
#ifdef __GNUC__
|
||||
return __builtin_expect(is_on(NS_debug), 0);
|
||||
#else
|
||||
return is_on(NS_debug);
|
||||
#endif
|
||||
return UNLIKELY(is_on(NS_debug));
|
||||
}
|
||||
#else
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -70,11 +70,7 @@ template<class GetCategory>
|
|||
INLINE bool NotifyCategoryProxy<GetCategory>::
|
||||
is_spam() {
|
||||
// Instruct the compiler to optimize for the usual case.
|
||||
#ifdef __GNUC__
|
||||
return __builtin_expect(get_unsafe_ptr()->is_spam(), 0);
|
||||
#else
|
||||
return get_unsafe_ptr()->is_spam();
|
||||
#endif
|
||||
return UNLIKELY(get_unsafe_ptr()->is_spam());
|
||||
}
|
||||
#else
|
||||
template<class GetCategory>
|
||||
|
|
@ -92,11 +88,7 @@ template<class GetCategory>
|
|||
INLINE bool NotifyCategoryProxy<GetCategory>::
|
||||
is_debug() {
|
||||
// Instruct the compiler to optimize for the usual case.
|
||||
#ifdef __GNUC__
|
||||
return __builtin_expect(get_unsafe_ptr()->is_debug(), 0);
|
||||
#else
|
||||
return get_unsafe_ptr()->is_debug();
|
||||
#endif
|
||||
return UNLIKELY(get_unsafe_ptr()->is_debug());
|
||||
}
|
||||
#else
|
||||
template<class GetCategory>
|
||||
|
|
|
|||
|
|
@ -3179,7 +3179,6 @@ if (PkgSkip("DIRECT")==0):
|
|||
CopyAllHeaders('direct/src/distributed')
|
||||
CopyAllHeaders('direct/src/interval')
|
||||
CopyAllHeaders('direct/src/showbase')
|
||||
CopyAllHeaders('direct/metalibs/direct')
|
||||
CopyAllHeaders('direct/src/dcparse')
|
||||
|
||||
if (RUNTIME or RTDIST):
|
||||
|
|
@ -5244,10 +5243,6 @@ if (PkgSkip("DIRECT")==0):
|
|||
#
|
||||
|
||||
if (PkgSkip("DIRECT")==0):
|
||||
OPTS=['DIR:direct/metalibs/direct', 'BUILDING:DIRECT']
|
||||
TargetAdd('p3direct_direct.obj', opts=OPTS, input='direct.cxx')
|
||||
|
||||
TargetAdd('libp3direct.dll', input='p3direct_direct.obj')
|
||||
TargetAdd('libp3direct.dll', input='p3directbase_directbase.obj')
|
||||
TargetAdd('libp3direct.dll', input='p3showbase_showBase.obj')
|
||||
if GetTarget() == 'darwin':
|
||||
|
|
@ -5259,7 +5254,7 @@ if (PkgSkip("DIRECT")==0):
|
|||
TargetAdd('libp3direct.dll', input=COMMON_PANDA_LIBS)
|
||||
TargetAdd('libp3direct.dll', opts=['ADVAPI', 'OPENSSL', 'WINUSER', 'WINGDI'])
|
||||
|
||||
OPTS=['DIR:direct/metalibs/direct', 'PYTHON']
|
||||
OPTS=['PYTHON']
|
||||
TargetAdd('direct_module.obj', input='libp3dcparser.in')
|
||||
TargetAdd('direct_module.obj', input='libp3showbase.in')
|
||||
TargetAdd('direct_module.obj', input='libp3deadrec.in')
|
||||
|
|
|
|||
|
|
@ -2620,6 +2620,8 @@ def SetupBuildEnvironment(compiler):
|
|||
if os.path.isdir(pcbsd_inc):
|
||||
SYS_INC_DIRS.append(pcbsd_inc)
|
||||
|
||||
null.close()
|
||||
|
||||
# Print out the search paths
|
||||
if GetVerbose():
|
||||
print("System library search path:")
|
||||
|
|
|
|||
|
|
@ -19,6 +19,34 @@ ptr() const {
|
|||
return (btStridingMeshInterface *)&_mesh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of vertices in this triangle mesh.
|
||||
*/
|
||||
INLINE size_t BulletTriangleMesh::
|
||||
get_num_vertices() const {
|
||||
return _vertices.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex at the given vertex index.
|
||||
*/
|
||||
INLINE LPoint3 BulletTriangleMesh::
|
||||
get_vertex(size_t index) const {
|
||||
nassertr(index < _vertices.size(), LPoint3::zero());
|
||||
const btVector3 &vertex = _vertices[index];
|
||||
return LPoint3(vertex[0], vertex[1], vertex[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex indices making up the given triangle index.
|
||||
*/
|
||||
INLINE LVecBase3i BulletTriangleMesh::
|
||||
get_triangle(size_t index) const {
|
||||
index *= 3;
|
||||
nassertr(index + 2 < _indices.size(), LVecBase3i::zero());
|
||||
return LVecBase3i(_indices[index], _indices[index + 1], _indices[index + 2]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ BulletTriangleMesh()
|
|||
/**
|
||||
* Returns the number of triangles in this triangle mesh.
|
||||
*/
|
||||
int BulletTriangleMesh::
|
||||
size_t BulletTriangleMesh::
|
||||
get_num_triangles() const {
|
||||
return _indices.size() / 3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,15 +48,24 @@ PUBLISHED:
|
|||
void set_welding_distance(PN_stdfloat distance);
|
||||
void preallocate(int num_verts, int num_indices);
|
||||
|
||||
int get_num_triangles() const;
|
||||
size_t get_num_triangles() const;
|
||||
PN_stdfloat get_welding_distance() const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
||||
MAKE_PROPERTY(num_triangles, get_num_triangles);
|
||||
public:
|
||||
INLINE size_t get_num_vertices() const;
|
||||
INLINE LPoint3 get_vertex(size_t index) const;
|
||||
|
||||
INLINE LVecBase3i get_triangle(size_t index) const;
|
||||
|
||||
PUBLISHED:
|
||||
MAKE_PROPERTY(welding_distance, get_welding_distance, set_welding_distance);
|
||||
|
||||
MAKE_SEQ_PROPERTY(vertices, get_num_vertices, get_vertex);
|
||||
MAKE_SEQ_PROPERTY(triangles, get_num_triangles, get_triangle);
|
||||
|
||||
public:
|
||||
INLINE btStridingMeshInterface *ptr() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,12 +44,13 @@ PUBLISHED:
|
|||
AnimGroup *get_child(int n) const;
|
||||
MAKE_SEQ(get_children, get_num_children, get_child);
|
||||
|
||||
MAKE_SEQ_PROPERTY(children, get_num_children, get_child);
|
||||
|
||||
AnimGroup *get_child_named(const string &name) const;
|
||||
AnimGroup *find_child(const string &name) const;
|
||||
void sort_descendants();
|
||||
|
||||
MAKE_SEQ_PROPERTY(children, get_num_children, get_child);
|
||||
MAKE_MAP_PROPERTY(children, get_child_named, get_child_named);
|
||||
|
||||
public:
|
||||
virtual TypeHandle get_value_type() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -70,12 +70,14 @@ PUBLISHED:
|
|||
int get_num_children() const;
|
||||
PartGroup *get_child(int n) const;
|
||||
MAKE_SEQ(get_children, get_num_children, get_child);
|
||||
MAKE_SEQ_PROPERTY(children, get_num_children, get_child);
|
||||
|
||||
PartGroup *get_child_named(const string &name) const;
|
||||
PartGroup *find_child(const string &name) const;
|
||||
void sort_descendants();
|
||||
|
||||
MAKE_SEQ_PROPERTY(children, get_num_children, get_child);
|
||||
MAKE_MAP_PROPERTY(children, get_child_named, get_child_named);
|
||||
|
||||
bool apply_freeze(const TransformState *transform);
|
||||
virtual bool apply_freeze_matrix(const LVecBase3 &pos, const LVecBase3 &hpr, const LVecBase3 &scale);
|
||||
virtual bool apply_freeze_scalar(PN_stdfloat value);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Create the Box by giving a Center and distances of of each of the sides of
|
||||
* Create the Box by giving a Center and distances of each of the sides of
|
||||
* box from the Center.
|
||||
*/
|
||||
INLINE CollisionBox::
|
||||
|
|
|
|||
|
|
@ -1271,7 +1271,7 @@ set_window_sort(GraphicsOutput *window, int sort) {
|
|||
* model begins with the "-" character.
|
||||
*/
|
||||
void GraphicsEngine::
|
||||
cull_and_draw_together(const GraphicsEngine::Windows &wlist,
|
||||
cull_and_draw_together(GraphicsEngine::Windows wlist,
|
||||
Thread *current_thread) {
|
||||
PStatTimer timer(_cull_pcollector, current_thread);
|
||||
|
||||
|
|
@ -1380,7 +1380,7 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
|
|||
* drawing.
|
||||
*/
|
||||
void GraphicsEngine::
|
||||
cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
|
||||
cull_to_bins(GraphicsEngine::Windows wlist, Thread *current_thread) {
|
||||
PStatTimer timer(_cull_pcollector, current_thread);
|
||||
|
||||
_singular_warning_last_frame = _singular_warning_this_frame;
|
||||
|
|
|
|||
|
|
@ -142,11 +142,11 @@ private:
|
|||
|
||||
void set_window_sort(GraphicsOutput *window, int sort);
|
||||
|
||||
void cull_and_draw_together(const Windows &wlist, Thread *current_thread);
|
||||
void cull_and_draw_together(Windows wlist, Thread *current_thread);
|
||||
void cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
|
||||
Thread *current_thread);
|
||||
|
||||
void cull_to_bins(const Windows &wlist, Thread *current_thread);
|
||||
void cull_to_bins(Windows wlist, Thread *current_thread);
|
||||
void cull_to_bins(GraphicsOutput *win, GraphicsStateGuardian *gsg,
|
||||
DisplayRegion *dr, SceneSetup *scene_setup,
|
||||
CullResult *cull_result, Thread *current_thread);
|
||||
|
|
|
|||
|
|
@ -227,14 +227,20 @@ clear_render_textures() {
|
|||
* You can specify a bitplane to attach the texture to. the legal choices
|
||||
* are:
|
||||
*
|
||||
* * RTP_depth * RTP_depth_stencil * RTP_color * RTP_aux_rgba_0 *
|
||||
* RTP_aux_rgba_1 * RTP_aux_rgba_2 * RTP_aux_rgba_3
|
||||
* - RTP_depth
|
||||
* - RTP_depth_stencil
|
||||
* - RTP_color
|
||||
* - RTP_aux_rgba_0
|
||||
* - RTP_aux_rgba_1
|
||||
* - RTP_aux_rgba_2
|
||||
* - RTP_aux_rgba_3
|
||||
*
|
||||
* If you do not specify a bitplane to attach the texture to, this routine
|
||||
* will use a default based on the texture's format:
|
||||
*
|
||||
* * F_depth_component attaches to RTP_depth * F_depth_stencil attaches to
|
||||
* RTP_depth_stencil * all other formats attach to RTP_color.
|
||||
* - F_depth_component attaches to RTP_depth
|
||||
* - F_depth_stencil attaches to RTP_depth_stencil
|
||||
* - all other formats attach to RTP_color.
|
||||
*
|
||||
* The texture's format will be changed to match the format of the bitplane to
|
||||
* which it is attached. For example, if you pass in an F_rgba texture and
|
||||
|
|
@ -283,32 +289,41 @@ add_render_texture(Texture *tex, RenderTextureMode mode,
|
|||
// bitplane, while we're at it).
|
||||
|
||||
if (plane == RTP_depth) {
|
||||
tex->set_format(Texture::F_depth_component);
|
||||
_fb_properties.setup_depth_texture(tex);
|
||||
tex->set_match_framebuffer_format(true);
|
||||
|
||||
} else if (plane == RTP_depth_stencil) {
|
||||
tex->set_format(Texture::F_depth_stencil);
|
||||
tex->set_component_type(Texture::T_unsigned_int_24_8);
|
||||
if (_fb_properties.get_float_depth()) {
|
||||
tex->set_component_type(Texture::T_float);
|
||||
} else {
|
||||
tex->set_component_type(Texture::T_unsigned_int_24_8);
|
||||
}
|
||||
tex->set_match_framebuffer_format(true);
|
||||
} else if ((plane == RTP_color)||
|
||||
(plane == RTP_aux_rgba_0)||
|
||||
(plane == RTP_aux_rgba_1)||
|
||||
(plane == RTP_aux_rgba_2)||
|
||||
(plane == RTP_aux_rgba_3)) {
|
||||
tex->set_format(Texture::F_rgba);
|
||||
|
||||
} else if (plane == RTP_color ||
|
||||
plane == RTP_aux_rgba_0 ||
|
||||
plane == RTP_aux_rgba_1 ||
|
||||
plane == RTP_aux_rgba_2 ||
|
||||
plane == RTP_aux_rgba_3) {
|
||||
_fb_properties.setup_color_texture(tex);
|
||||
tex->set_match_framebuffer_format(true);
|
||||
} else if ((plane == RTP_aux_hrgba_0)||
|
||||
(plane == RTP_aux_hrgba_1)||
|
||||
(plane == RTP_aux_hrgba_2)||
|
||||
(plane == RTP_aux_hrgba_3)) {
|
||||
|
||||
} else if (plane == RTP_aux_hrgba_0 ||
|
||||
plane == RTP_aux_hrgba_1 ||
|
||||
plane == RTP_aux_hrgba_2 ||
|
||||
plane == RTP_aux_hrgba_3) {
|
||||
tex->set_format(Texture::F_rgba16);
|
||||
tex->set_match_framebuffer_format(true);
|
||||
} else if ((plane == RTP_aux_float_0)||
|
||||
(plane == RTP_aux_float_1)||
|
||||
(plane == RTP_aux_float_2)||
|
||||
(plane == RTP_aux_float_3)) {
|
||||
|
||||
} else if (plane == RTP_aux_float_0 ||
|
||||
plane == RTP_aux_float_1 ||
|
||||
plane == RTP_aux_float_2 ||
|
||||
plane == RTP_aux_float_3) {
|
||||
tex->set_format(Texture::F_rgba32);
|
||||
tex->set_component_type(Texture::T_float);
|
||||
tex->set_match_framebuffer_format(true);
|
||||
|
||||
} else {
|
||||
display_cat.error() <<
|
||||
"add_render_texture: invalid bitplane specified.\n";
|
||||
|
|
|
|||
|
|
@ -281,6 +281,11 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
|
|||
|
||||
_gamma = 1.0f;
|
||||
_texture_quality_override = Texture::QL_default;
|
||||
|
||||
// Give it a unique identifier. Unlike a pointer, we can guarantee that
|
||||
// this value will never be reused.
|
||||
static size_t next_index = 0;
|
||||
_id = next_index++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -290,6 +295,19 @@ GraphicsStateGuardian::
|
|||
~GraphicsStateGuardian() {
|
||||
remove_gsg(this);
|
||||
GeomMunger::unregister_mungers_for_gsg(this);
|
||||
|
||||
// Remove the munged states for this GSG. This requires going through all
|
||||
// states, although destructing a GSG should be rare enough for this not to
|
||||
// matter too much.
|
||||
// Note that if uniquify-states is false, we can't iterate over all the
|
||||
// states, and some GSGs will linger. Let's hope this isn't a problem.
|
||||
LightReMutexHolder holder(*RenderState::_states_lock);
|
||||
size_t size = RenderState::_states->get_num_entries();
|
||||
for (size_t si = 0; si < size; ++si) {
|
||||
const RenderState *state = RenderState::_states->get_key(si);
|
||||
state->_mungers.remove(_id);
|
||||
state->_munged_states.remove(_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -743,7 +761,7 @@ get_geom_munger(const RenderState *state, Thread *current_thread) {
|
|||
// multiple times during a frame. Also, this might well be the only GSG
|
||||
// in the world anyway.
|
||||
int mi = state->_last_mi;
|
||||
if (mi >= 0 && mungers.has_element(mi) && mungers.get_key(mi) == this) {
|
||||
if (mi >= 0 && mi < mungers.get_num_entries() && mungers.get_key(mi) == _id) {
|
||||
PT(GeomMunger) munger = mungers.get_data(mi);
|
||||
if (munger->is_registered()) {
|
||||
return munger;
|
||||
|
|
@ -751,7 +769,7 @@ get_geom_munger(const RenderState *state, Thread *current_thread) {
|
|||
}
|
||||
|
||||
// Nope, we have to look it up in the map.
|
||||
mi = mungers.find(this);
|
||||
mi = mungers.find(_id);
|
||||
if (mi >= 0) {
|
||||
PT(GeomMunger) munger = mungers.get_data(mi);
|
||||
if (munger->is_registered()) {
|
||||
|
|
@ -769,7 +787,7 @@ get_geom_munger(const RenderState *state, Thread *current_thread) {
|
|||
nassertr(munger != (GeomMunger *)NULL && munger->is_registered(), munger);
|
||||
nassertr(munger->is_of_type(StateMunger::get_class_type()), munger);
|
||||
|
||||
state->_last_mi = mungers.store(this, munger);
|
||||
state->_last_mi = mungers.store(_id, munger);
|
||||
return munger;
|
||||
}
|
||||
|
||||
|
|
@ -3021,6 +3039,19 @@ determine_target_texture() {
|
|||
nassertv(_target_texture->get_num_on_stages() <= max_texture_stages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns _target_shader based on the _target_rs.
|
||||
*/
|
||||
void GraphicsStateGuardian::
|
||||
determine_target_shader() {
|
||||
if (_target_rs->_generated_shader != nullptr) {
|
||||
_target_shader = (const ShaderAttrib *)_target_rs->_generated_shader.p();
|
||||
} else {
|
||||
_target_shader = (const ShaderAttrib *)
|
||||
_target_rs->get_attrib_def(ShaderAttrib::get_class_slot());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees some memory that was explicitly allocated within the glgsg.
|
||||
*/
|
||||
|
|
@ -3364,6 +3395,43 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) {
|
|||
return tex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that an appropriate shader has been generated for the given state.
|
||||
* This is stored in the _generated_shader field on the RenderState.
|
||||
*/
|
||||
void GraphicsStateGuardian::
|
||||
ensure_generated_shader(const RenderState *state) {
|
||||
#ifdef HAVE_CG
|
||||
const ShaderAttrib *shader_attrib;
|
||||
state->get_attrib_def(shader_attrib);
|
||||
|
||||
if (shader_attrib->auto_shader()) {
|
||||
if (_shader_generator == nullptr) {
|
||||
if (!_supports_basic_shaders) {
|
||||
return;
|
||||
}
|
||||
_shader_generator = new ShaderGenerator(this);
|
||||
}
|
||||
if (state->_generated_shader == nullptr ||
|
||||
state->_generated_shader_seq != _generated_shader_seq) {
|
||||
GeomVertexAnimationSpec spec;
|
||||
|
||||
// Currently we overload this flag to request vertex animation for the
|
||||
// shader generator.
|
||||
const ShaderAttrib *sattr;
|
||||
state->get_attrib_def(sattr);
|
||||
if (sattr->get_flag(ShaderAttrib::F_hardware_skinning)) {
|
||||
spec.set_hardware(4, true);
|
||||
}
|
||||
|
||||
// Cache the generated ShaderAttrib on the shader state.
|
||||
state->_generated_shader = _shader_generator->synthesize_shader(state, spec);
|
||||
state->_generated_shader_seq = _generated_shader_seq;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the GSG implements the extension identified by the given
|
||||
* string. This currently is only implemented by the OpenGL back-end.
|
||||
|
|
|
|||
|
|
@ -426,6 +426,8 @@ public:
|
|||
PT(Texture) get_dummy_shadow_map(Texture::TextureType texture_type) const;
|
||||
PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host);
|
||||
|
||||
virtual void ensure_generated_shader(const RenderState *state);
|
||||
|
||||
#ifdef DO_PSTATS
|
||||
static void init_frame_pstats();
|
||||
#endif
|
||||
|
|
@ -446,6 +448,7 @@ protected:
|
|||
virtual void end_bind_clip_planes();
|
||||
|
||||
void determine_target_texture();
|
||||
void determine_target_shader();
|
||||
|
||||
virtual void free_pointers();
|
||||
virtual void close_gsg();
|
||||
|
|
|
|||
|
|
@ -38,7 +38,17 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
|
|||
_auto_shader(false),
|
||||
_shader_skinning(false)
|
||||
{
|
||||
if (!get_gsg()->get_runtime_color_scale()) {
|
||||
const ShaderAttrib *shader_attrib;
|
||||
state->get_attrib_def(shader_attrib);
|
||||
#ifdef HAVE_CG
|
||||
_auto_shader = shader_attrib->auto_shader();
|
||||
#endif
|
||||
if (shader_attrib->get_flag(ShaderAttrib::F_hardware_skinning)) {
|
||||
_shader_skinning = true;
|
||||
}
|
||||
|
||||
if (!get_gsg()->get_runtime_color_scale() && !_auto_shader &&
|
||||
shader_attrib->get_shader() == nullptr) {
|
||||
// We might need to munge the colors.
|
||||
const ColorAttrib *color_attrib;
|
||||
const ColorScaleAttrib *color_scale_attrib;
|
||||
|
|
@ -60,6 +70,7 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
|
|||
_color[3] * cs[3]);
|
||||
}
|
||||
_munge_color = true;
|
||||
_should_munge_state = true;
|
||||
}
|
||||
|
||||
} else if (state->get_attrib(color_scale_attrib) &&
|
||||
|
|
@ -74,6 +85,7 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
|
|||
if ((color_scale_attrib->has_rgb_scale() && !get_gsg()->get_color_scale_via_lighting()) ||
|
||||
(color_scale_attrib->has_alpha_scale() && !get_gsg()->get_alpha_scale_via_texture(tex_attrib))) {
|
||||
_munge_color_scale = true;
|
||||
_should_munge_state = true;
|
||||
}
|
||||
|
||||
// Known bug: if there is a material on an object that would obscure the
|
||||
|
|
@ -82,15 +94,6 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
|
|||
// effort to detect this contrived situation and handle it correctly.
|
||||
}
|
||||
}
|
||||
|
||||
const ShaderAttrib *shader_attrib = (const ShaderAttrib *)
|
||||
state->get_attrib_def(ShaderAttrib::get_class_slot());
|
||||
if (shader_attrib->auto_shader()) {
|
||||
_auto_shader = true;
|
||||
}
|
||||
if (shader_attrib->get_flag(ShaderAttrib::F_hardware_skinning)) {
|
||||
_shader_skinning = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -341,33 +344,5 @@ munge_state_impl(const RenderState *state) {
|
|||
munged_state = munged_state->remove_attrib(ColorScaleAttrib::get_class_slot());
|
||||
}
|
||||
|
||||
#ifdef HAVE_CG
|
||||
if (_auto_shader) {
|
||||
GraphicsStateGuardian *gsg = get_gsg();
|
||||
ShaderGenerator *shader_generator = gsg->get_shader_generator();
|
||||
if (shader_generator == nullptr) {
|
||||
shader_generator = new ShaderGenerator(gsg);
|
||||
gsg->set_shader_generator(shader_generator);
|
||||
}
|
||||
if (munged_state->_generated_shader == nullptr) {
|
||||
// Cache the generated ShaderAttrib on the shader state.
|
||||
GeomVertexAnimationSpec spec;
|
||||
|
||||
// Currently we overload this flag to request vertex animation for the
|
||||
// shader generator.
|
||||
const ShaderAttrib *sattr;
|
||||
munged_state->get_attrib_def(sattr);
|
||||
if (sattr->get_flag(ShaderAttrib::F_hardware_skinning)) {
|
||||
spec.set_hardware(4, true);
|
||||
}
|
||||
|
||||
munged_state->_generated_shader = shader_generator->synthesize_shader(munged_state, spec);
|
||||
}
|
||||
if (munged_state->_generated_shader != nullptr) {
|
||||
munged_state = munged_state->set_attrib(munged_state->_generated_shader);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return munged_state;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3074,7 +3074,7 @@ set_state_and_transform(const RenderState *target,
|
|||
}
|
||||
_target_rs = target;
|
||||
|
||||
_target_shader = DCAST(ShaderAttrib, _target_rs->get_attrib_def(ShaderAttrib::get_class_slot()));
|
||||
determine_target_shader();
|
||||
|
||||
int alpha_test_slot = AlphaTestAttrib::get_class_slot();
|
||||
if (_target_rs->get_attrib(alpha_test_slot) != _state_rs->get_attrib(alpha_test_slot) ||
|
||||
|
|
@ -4438,7 +4438,7 @@ set_texture_blend_mode(int i, const TextureStage *stage) {
|
|||
set_texture_stage_state(i, D3DTSS_RESULTARG, D3DTA_CURRENT);
|
||||
}
|
||||
|
||||
if (stage->uses_color()) {
|
||||
if (stage->uses_color() || stage->involves_color_scale()) {
|
||||
// Set up the constant color for this stage.
|
||||
|
||||
D3DCOLOR constant_color;
|
||||
|
|
|
|||
|
|
@ -182,6 +182,46 @@ has_hook(const string &event_name) const {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if there is the hook added on the indicated event name and
|
||||
* function pointer, false otherwise.
|
||||
*/
|
||||
bool EventHandler::
|
||||
has_hook(const string &event_name, EventFunction *function) const {
|
||||
assert(!event_name.empty());
|
||||
Hooks::const_iterator hi;
|
||||
hi = _hooks.find(event_name);
|
||||
if (hi != _hooks.end()) {
|
||||
const Functions& functions = (*hi).second;
|
||||
if (functions.find(function) != functions.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if there is the hook added on the indicated event name,
|
||||
* function pointer and callback data, false otherwise.
|
||||
*/
|
||||
bool EventHandler::
|
||||
has_hook(const string &event_name, EventCallbackFunction *function, void *data) const {
|
||||
assert(!event_name.empty());
|
||||
CallbackHooks::const_iterator chi;
|
||||
chi = _cbhooks.find(event_name);
|
||||
if (chi != _cbhooks.end()) {
|
||||
const CallbackFunctions& cbfunctions = (*chi).second;
|
||||
if (cbfunctions.find(CallbackFunction(function, data)) != cbfunctions.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the indicated function from the named event hook. Returns true if
|
||||
* the hook was removed, false if it wasn't there in the first place.
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ public:
|
|||
bool add_hook(const string &event_name, EventCallbackFunction *function,
|
||||
void *data);
|
||||
bool has_hook(const string &event_name) const;
|
||||
bool has_hook(const string &event_name, EventFunction *function) const;
|
||||
bool has_hook(const string &event_name, EventCallbackFunction *function,
|
||||
void *data) const;
|
||||
bool remove_hook(const string &event_name, EventFunction *function);
|
||||
bool remove_hook(const string &event_name, EventCallbackFunction *function,
|
||||
void *data);
|
||||
|
|
|
|||
|
|
@ -105,9 +105,9 @@ PUBLISHED:
|
|||
INLINE void set_element(size_type n, const Element &value);
|
||||
EXTENSION(const Element &__getitem__(size_type n) const);
|
||||
EXTENSION(void __setitem__(size_type n, const Element &value));
|
||||
INLINE string get_data() const;
|
||||
INLINE void set_data(const string &data);
|
||||
INLINE string get_subdata(size_type n, size_type count) const;
|
||||
EXTENSION(PyObject *get_data() const);
|
||||
EXTENSION(void set_data(PyObject *data));
|
||||
EXTENSION(PyObject *get_subdata(size_type n, size_type count) const);
|
||||
INLINE void set_subdata(size_type n, size_type count, const string &data);
|
||||
INLINE int get_ref_count() const;
|
||||
INLINE int get_node_ref_count() const;
|
||||
|
|
@ -255,14 +255,12 @@ PUBLISHED:
|
|||
INLINE ConstPointerToArray(const PointerToArray<Element> ©);
|
||||
INLINE ConstPointerToArray(const ConstPointerToArray<Element> ©);
|
||||
|
||||
EXTENSION(ConstPointerToArray(PyObject *self, PyObject *source));
|
||||
|
||||
typedef TYPENAME pvector<Element>::size_type size_type;
|
||||
INLINE size_type size() const;
|
||||
INLINE const Element &get_element(size_type n) const;
|
||||
EXTENSION(const Element &__getitem__(size_type n) const);
|
||||
INLINE string get_data() const;
|
||||
INLINE string get_subdata(size_type n, size_type count) const;
|
||||
EXTENSION(PyObject *get_data() const);
|
||||
EXTENSION(PyObject *get_subdata(size_type n, size_type count) const);
|
||||
INLINE int get_ref_count() const;
|
||||
INLINE int get_node_ref_count() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,93 +79,26 @@ INLINE void Extension<PointerToArray<Element> >::
|
|||
__init__(PyObject *self, PyObject *source) {
|
||||
#if PY_VERSION_HEX >= 0x02060000
|
||||
if (PyObject_CheckBuffer(source)) {
|
||||
// User passed a buffer object.
|
||||
Py_buffer view;
|
||||
if (PyObject_GetBuffer(source, &view, PyBUF_CONTIG_RO) == -1) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"PointerToArray constructor requires a contiguous buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.itemsize != 1 && view.itemsize != sizeof(Element)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"buffer.itemsize does not match PointerToArray element size");
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.len % sizeof(Element) != 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"byte buffer is not a multiple of %zu bytes",
|
||||
sizeof(Element));
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.len > 0) {
|
||||
this->_this->resize(view.len / sizeof(Element));
|
||||
memcpy(this->_this->p(), view.buf, view.len);
|
||||
}
|
||||
|
||||
PyBuffer_Release(&view);
|
||||
#else
|
||||
if (PyString_CheckExact(source)) {
|
||||
#endif
|
||||
// It's a byte sequence, or any object that exports the buffer protocol.
|
||||
this->set_data(source);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!PySequence_Check(source)) {
|
||||
// Don't allow a unicode object even though it's a sequence.
|
||||
if (!PySequence_Check(source) || PyUnicode_CheckExact(source)) {
|
||||
// If passed with a non-sequence, this isn't the right constructor.
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"PointerToArray constructor requires a sequence or buffer object");
|
||||
return;
|
||||
}
|
||||
|
||||
// If we were passed a Python string, then instead of storing it character-
|
||||
// at-a-time, just load the whole string as a data buffer. Not sure if this
|
||||
// case is still necessary - don't Python strbytes objects export the buffer
|
||||
// protocol, as above?
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
if (PyBytes_Check(source)) {
|
||||
int size = PyBytes_Size(source);
|
||||
if (size % sizeof(Element) != 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"bytes object is not a multiple of %zu bytes",
|
||||
sizeof(Element));
|
||||
return;
|
||||
}
|
||||
|
||||
int num_elements = size / sizeof(Element);
|
||||
this->_this->insert(this->_this->begin(), num_elements, Element());
|
||||
|
||||
// Hope there aren't any constructors or destructors involved here.
|
||||
if (size != 0) {
|
||||
const char *data = PyBytes_AsString(source);
|
||||
memcpy(this->_this->p(), data, size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (PyString_CheckExact(source)) {
|
||||
int size = PyString_Size(source);
|
||||
if (size % sizeof(Element) != 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"str object is not a multiple of %zu bytes",
|
||||
sizeof(Element));
|
||||
return;
|
||||
}
|
||||
|
||||
int num_elements = size / sizeof(Element);
|
||||
this->_this->insert(this->_this->begin(), num_elements, Element());
|
||||
|
||||
// Hope there aren't any constructors or destructors involved here.
|
||||
if (size != 0) {
|
||||
const char *data = PyString_AsString(source);
|
||||
memcpy(this->_this->p(), data, size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Now construct the internal list by copying the elements one-at-a-time
|
||||
// from Python.
|
||||
PyObject *push_back = PyObject_GetAttrString(self, "push_back");
|
||||
PyObject *dict = ((Dtool_PyInstDef *)self)->_My_Type->_PyType.tp_dict;
|
||||
PyObject *push_back = PyDict_GetItemString(dict, "push_back");
|
||||
if (push_back == NULL) {
|
||||
PyErr_BadArgument();
|
||||
return;
|
||||
|
|
@ -174,19 +107,20 @@ __init__(PyObject *self, PyObject *source) {
|
|||
// We need to initialize the this pointer before we can call push_back.
|
||||
((Dtool_PyInstDef *)self)->_ptr_to_object = (void *)this->_this;
|
||||
|
||||
int size = PySequence_Size(source);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
Py_ssize_t size = PySequence_Size(source);
|
||||
this->_this->reserve(size);
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
PyObject *item = PySequence_GetItem(source, i);
|
||||
if (item == NULL) {
|
||||
return;
|
||||
}
|
||||
PyObject *result = PyObject_CallFunctionObjArgs(push_back, item, NULL);
|
||||
PyObject *result = PyObject_CallFunctionObjArgs(push_back, self, item, NULL);
|
||||
Py_DECREF(item);
|
||||
if (result == NULL) {
|
||||
// Unable to add item--probably it wasn't of the appropriate type.
|
||||
PyErr_Print();
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Element %d in sequence passed to PointerToArray "
|
||||
"Element %zd in sequence passed to PointerToArray "
|
||||
"constructor could not be added", i);
|
||||
return;
|
||||
}
|
||||
|
|
@ -213,15 +147,110 @@ __setitem__(size_t n, const Element &value) {
|
|||
}
|
||||
|
||||
/**
|
||||
* This special constructor accepts a Python list of elements, or a Python
|
||||
* string (or a bytes object, in Python 3).
|
||||
* This returns the entire contents of the vector as a block of raw data in a
|
||||
* string (or bytes object, in Python 3).
|
||||
*
|
||||
* @deprecated use memoryview(pta) or bytearray(pta) instead.
|
||||
*/
|
||||
template<class Element>
|
||||
INLINE void Extension<ConstPointerToArray<Element> >::
|
||||
__init__(PyObject *self, PyObject *source) {
|
||||
PointerToArray<Element> array;
|
||||
invoke_extension(&array).__init__(self, source);
|
||||
*(this->_this) = MOVE(array);
|
||||
INLINE PyObject *Extension<PointerToArray<Element> >::
|
||||
get_data() const {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return PyBytes_FromStringAndSize((char *)this->_this->p(), sizeof(Element) * this->_this->size());
|
||||
#else
|
||||
return PyString_FromStringAndSize((char *)this->_this->p(), sizeof(Element) * this->_this->size());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This method exists mainly to access the data of the array easily from a
|
||||
* high-level language such as Python.
|
||||
*
|
||||
* This replaces the entire contents of the vector from a block of raw data
|
||||
* in a string (or bytes object, in Python 3).
|
||||
*/
|
||||
template<class Element>
|
||||
INLINE void Extension<PointerToArray<Element> >::
|
||||
set_data(PyObject *data) {
|
||||
#if PY_VERSION_HEX >= 0x02060000
|
||||
if (PyObject_CheckBuffer(data)) {
|
||||
// User passed a buffer object.
|
||||
Py_buffer view;
|
||||
if (PyObject_GetBuffer(data, &view, PyBUF_CONTIG_RO) == -1) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"PointerToArray.set_data() requires a contiguous buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.itemsize != 1 && view.itemsize != sizeof(Element)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"buffer.itemsize does not match PointerToArray element size");
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.len % sizeof(Element) != 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"byte buffer is not a multiple of %zu bytes",
|
||||
sizeof(Element));
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.len > 0) {
|
||||
this->_this->resize(view.len / sizeof(Element));
|
||||
memcpy(this->_this->p(), view.buf, view.len);
|
||||
} else {
|
||||
this->_this->clear();
|
||||
}
|
||||
|
||||
PyBuffer_Release(&view);
|
||||
} else {
|
||||
Dtool_Raise_TypeError("PointerToArray.set_data() requires a buffer object");
|
||||
}
|
||||
#else
|
||||
// In Python 2.5 we didn't have the new buffer protocol, only str.
|
||||
if (PyString_CheckExact(data)) {
|
||||
int size = PyString_Size(data);
|
||||
if (size % sizeof(Element) != 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"str object is not a multiple of %zu bytes",
|
||||
sizeof(Element));
|
||||
return;
|
||||
}
|
||||
|
||||
int num_elements = size / sizeof(Element);
|
||||
this->_this->insert(this->_this->begin(), num_elements, Element());
|
||||
|
||||
// Hope there aren't any constructors or destructors involved here.
|
||||
if (size != 0) {
|
||||
const char *ptr = PyString_AsString(data);
|
||||
memcpy(this->_this->p(), ptr, size);
|
||||
} else {
|
||||
this->_this->clear();
|
||||
}
|
||||
} else {
|
||||
Dtool_Raise_TypeError("PointerToArray.set_data() requires a str");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the contents of a portion of the vector--from element (n)
|
||||
* through element (n + count - 1)--as a block of raw data in a string (or
|
||||
* bytes object, in Python 3).
|
||||
*
|
||||
* @deprecated use memoryview(pta) or bytearray(pta) instead.
|
||||
*/
|
||||
template<class Element>
|
||||
INLINE PyObject *Extension<PointerToArray<Element> >::
|
||||
get_subdata(size_t n, size_t count) const {
|
||||
n = min(n, this->_this->size());
|
||||
count = max(count, n);
|
||||
count = min(count, this->_this->size() - n);
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return PyBytes_FromStringAndSize((char *)(this->_this->p() + n), sizeof(Element) * count);
|
||||
#else
|
||||
return PyString_FromStringAndSize((char *)(this->_this->p() + n), sizeof(Element) * count);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -233,6 +262,42 @@ __getitem__(size_t n) const {
|
|||
return (*this->_this)[n];
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the entire contents of the vector as a block of raw data in a
|
||||
* string (or bytes object, in Python 3).
|
||||
*
|
||||
* @deprecated use memoryview(pta) or bytearray(pta) instead.
|
||||
*/
|
||||
template<class Element>
|
||||
INLINE PyObject *Extension<ConstPointerToArray<Element> >::
|
||||
get_data() const {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return PyBytes_FromStringAndSize((char *)this->_this->p(), sizeof(Element) * this->_this->size());
|
||||
#else
|
||||
return PyString_FromStringAndSize((char *)this->_this->p(), sizeof(Element) * this->_this->size());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the contents of a portion of the vector--from element (n)
|
||||
* through element (n + count - 1)--as a block of raw data in a string (or
|
||||
* bytes object, in Python 3).
|
||||
*
|
||||
* @deprecated use memoryview(pta) or bytearray(pta) instead.
|
||||
*/
|
||||
template<class Element>
|
||||
INLINE PyObject *Extension<ConstPointerToArray<Element> >::
|
||||
get_subdata(size_t n, size_t count) const {
|
||||
n = min(n, this->_this->size());
|
||||
count = max(count, n);
|
||||
count = min(count, this->_this->size() - n);
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return PyBytes_FromStringAndSize((char *)(this->_this->p() + n), sizeof(Element) * count);
|
||||
#else
|
||||
return PyString_FromStringAndSize((char *)(this->_this->p() + n), sizeof(Element) * count);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to implement the buffer protocol, in order to allow efficient
|
||||
* access to the array data through a Python multiview object.
|
||||
|
|
@ -461,6 +526,9 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization on __getbuffer__ for LMatrix3f.
|
||||
*/
|
||||
template<>
|
||||
INLINE int Extension<ConstPointerToArray<LMatrix3f> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
|
||||
|
|
@ -488,6 +556,9 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization on __getbuffer__ for LMatrix3d.
|
||||
*/
|
||||
template<>
|
||||
INLINE int Extension<ConstPointerToArray<LMatrix3d> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
|
||||
|
|
@ -515,6 +586,9 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization on __getbuffer__ for UnalignedLMatrix4f.
|
||||
*/
|
||||
template<>
|
||||
INLINE int Extension<ConstPointerToArray<UnalignedLMatrix4f> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
|
||||
|
|
@ -542,6 +616,9 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization on __getbuffer__ for UnalignedLMatrix4d.
|
||||
*/
|
||||
template<>
|
||||
INLINE int Extension<ConstPointerToArray<UnalignedLMatrix4d> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags) const {
|
||||
|
|
|
|||
|
|
@ -36,18 +36,29 @@ public:
|
|||
INLINE const Element &__getitem__(size_t n) const;
|
||||
INLINE void __setitem__(size_t n, const Element &value);
|
||||
|
||||
INLINE PyObject *get_data() const;
|
||||
INLINE void set_data(PyObject *data);
|
||||
INLINE PyObject *get_subdata(size_t n, size_t count) const;
|
||||
|
||||
INLINE int __getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||
INLINE void __releasebuffer__(PyObject *self, Py_buffer *view) const;
|
||||
};
|
||||
|
||||
template<>
|
||||
INLINE int Extension<PointerToArray<LMatrix3f> >::__getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||
INLINE int Extension<PointerToArray<LMatrix3f> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||
|
||||
template<>
|
||||
INLINE int Extension<PointerToArray<LMatrix3d> >::__getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||
INLINE int Extension<PointerToArray<LMatrix3d> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||
|
||||
template<>
|
||||
INLINE int Extension<PointerToArray<UnalignedLMatrix4f> >::__getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||
INLINE int Extension<PointerToArray<UnalignedLMatrix4f> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||
|
||||
template<>
|
||||
INLINE int Extension<PointerToArray<UnalignedLMatrix4d> >::__getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||
INLINE int Extension<PointerToArray<UnalignedLMatrix4d> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags);
|
||||
|
||||
/**
|
||||
* This class defines the extension methods for ConstPointerToArray, which are
|
||||
|
|
@ -59,22 +70,30 @@ template<>
|
|||
template<class Element>
|
||||
class Extension<ConstPointerToArray<Element> > : public ExtensionBase<ConstPointerToArray<Element> > {
|
||||
public:
|
||||
INLINE void __init__(PyObject *self, PyObject *source);
|
||||
|
||||
INLINE const Element &__getitem__(size_t n) const;
|
||||
|
||||
INLINE PyObject *get_data() const;
|
||||
INLINE PyObject *get_subdata(size_t n, size_t count) const;
|
||||
|
||||
INLINE int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||
INLINE void __releasebuffer__(PyObject *self, Py_buffer *view) const;
|
||||
};
|
||||
|
||||
template<>
|
||||
INLINE int Extension<ConstPointerToArray<LMatrix3f> >::__getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||
INLINE int Extension<ConstPointerToArray<LMatrix3f> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||
|
||||
template<>
|
||||
INLINE int Extension<ConstPointerToArray<LMatrix3d> >::__getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||
INLINE int Extension<ConstPointerToArray<LMatrix3d> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||
|
||||
template<>
|
||||
INLINE int Extension<ConstPointerToArray<UnalignedLMatrix4f> >::__getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||
INLINE int Extension<ConstPointerToArray<UnalignedLMatrix4f> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||
|
||||
template<>
|
||||
INLINE int Extension<ConstPointerToArray<UnalignedLMatrix4d> >::__getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||
INLINE int Extension<ConstPointerToArray<UnalignedLMatrix4d> >::
|
||||
__getbuffer__(PyObject *self, Py_buffer *view, int flags) const;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Ugh... MSVC needs this because they still don't have a decent linker.
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ static const string default_vshader =
|
|||
"void main(void) {\n"
|
||||
" gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\n"
|
||||
" texcoord = p3d_MultiTexCoord0;\n"
|
||||
" color = p3d_Color;\n"
|
||||
" color = p3d_Color * p3d_ColorScale;\n"
|
||||
"}\n";
|
||||
|
||||
static const string default_fshader =
|
||||
|
|
@ -3127,6 +3127,10 @@ reset() {
|
|||
}
|
||||
#endif
|
||||
|
||||
// Do we guarantee that we can apply the color scale via a shader? We set
|
||||
// this false if there is a chance that the fixed-function pipeline is used.
|
||||
_runtime_color_scale = !has_fixed_function_pipeline();
|
||||
|
||||
#ifndef OPENGLES
|
||||
if (_gl_shadlang_ver_major >= 4 || has_extension("GL_NV_gpu_program5")) {
|
||||
// gp5fp - OpenGL fragment profile for GeForce 400 Series and up
|
||||
|
|
@ -10341,8 +10345,7 @@ set_state_and_transform(const RenderState *target,
|
|||
_target_rs = target;
|
||||
|
||||
#ifndef OPENGLES_1
|
||||
_target_shader = (const ShaderAttrib *)
|
||||
_target_rs->get_attrib_def(ShaderAttrib::get_class_slot());
|
||||
determine_target_shader();
|
||||
_instance_count = _target_shader->get_instance_count();
|
||||
|
||||
if (_target_shader != _state_shader) {
|
||||
|
|
|
|||
|
|
@ -95,6 +95,27 @@ reset_data() {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an implementation-defined handle or pointer that can be used
|
||||
* to interface directly with the underlying API.
|
||||
* Returns 0 if the underlying implementation does not support this.
|
||||
*/
|
||||
uint64_t CLP(TextureContext)::
|
||||
get_native_id() const {
|
||||
return _index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to get_native_id, but some implementations use a separate
|
||||
* identifier for the buffer object associated with buffer textures.
|
||||
* Returns 0 if the underlying implementation does not support this, or
|
||||
* if this is not a buffer texture.
|
||||
*/
|
||||
uint64_t CLP(TextureContext)::
|
||||
get_native_buffer_id() const {
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ public:
|
|||
virtual void evict_lru();
|
||||
void reset_data();
|
||||
|
||||
virtual uint64_t get_native_id() const;
|
||||
virtual uint64_t get_native_buffer_id() const;
|
||||
|
||||
#ifndef OPENGLES
|
||||
void make_handle_resident();
|
||||
GLuint64 get_handle();
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@ PUBLISHED:
|
|||
MAKE_SEQ_PROPERTY(points, get_num_points, get_point);
|
||||
MAKE_SEQ_PROPERTY(vectors, get_num_vectors, get_vector);
|
||||
|
||||
// We also define this as a mapping interface, for lookups by name.
|
||||
MAKE_MAP_PROPERTY(columns, has_column, get_column);
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level = 0) const;
|
||||
void write_with_data(ostream &out, int indent_level,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ make(PyUnicodeObject *str) {
|
|||
if (!PyUnicode_CHECK_INTERNED(str)) {
|
||||
// Not an interned string; don't bother.
|
||||
Py_ssize_t len = 0;
|
||||
char *c_str = PyUnicode_AsUTF8AndSize((PyObject *)str, &len);
|
||||
const char *c_str = PyUnicode_AsUTF8AndSize((PyObject *)str, &len);
|
||||
if (c_str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ make(PyUnicodeObject *str) {
|
|||
|
||||
} else {
|
||||
Py_ssize_t len = 0;
|
||||
char *c_str = PyUnicode_AsUTF8AndSize((PyObject *)str, &len);
|
||||
const char *c_str = PyUnicode_AsUTF8AndSize((PyObject *)str, &len);
|
||||
string name(c_str, len);
|
||||
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -539,6 +539,8 @@ PUBLISHED:
|
|||
void set_aux_data(const string &key, TypedReferenceCount *aux_data);
|
||||
void clear_aux_data(const string &key);
|
||||
TypedReferenceCount *get_aux_data(const string &key) const;
|
||||
MAKE_MAP_PROPERTY(aux_data, get_aux_data, get_aux_data,
|
||||
set_aux_data, clear_aux_data);
|
||||
|
||||
INLINE static void set_textures_power_2(AutoTextureScale scale);
|
||||
INLINE static AutoTextureScale get_textures_power_2();
|
||||
|
|
|
|||
|
|
@ -15,6 +15,27 @@
|
|||
|
||||
TypeHandle TextureContext::_type_handle;
|
||||
|
||||
/**
|
||||
* Returns an implementation-defined handle or pointer that can be used
|
||||
* to interface directly with the underlying API.
|
||||
* Returns 0 if the underlying implementation does not support this.
|
||||
*/
|
||||
uint64_t TextureContext::
|
||||
get_native_id() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to get_native_id, but some implementations use a separate
|
||||
* identifier for the buffer object associated with buffer textures.
|
||||
* Returns 0 if the underlying implementation does not support this, or
|
||||
* if this is not a buffer texture.
|
||||
*/
|
||||
uint64_t TextureContext::
|
||||
get_native_buffer_id() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ public:
|
|||
PUBLISHED:
|
||||
INLINE Texture *get_texture() const;
|
||||
INLINE int get_view() const;
|
||||
virtual uint64_t get_native_id() const;
|
||||
virtual uint64_t get_native_buffer_id() const;
|
||||
|
||||
INLINE bool was_modified() const;
|
||||
INLINE bool was_properties_modified() const;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* Initialize the texture stage from other
|
||||
*/
|
||||
INLINE TextureStage::
|
||||
TextureStage(TextureStage ©) {
|
||||
TextureStage(const TextureStage ©) {
|
||||
(*this) = copy;
|
||||
}
|
||||
|
||||
|
|
@ -52,6 +52,10 @@ set_sort(int sort) {
|
|||
// Update the global flag to indicate that all TextureAttribs in the world
|
||||
// must now re-sort their lists.
|
||||
_sort_seq++;
|
||||
|
||||
if (_used_by_auto_shader) {
|
||||
GraphicsStateGuardianBase::mark_rehash_generated_shaders();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -80,6 +84,10 @@ set_priority(int priority) {
|
|||
// Update the global flag to indicate that all TextureAttribs in the world
|
||||
// must now re-sort their lists.
|
||||
_sort_seq++;
|
||||
|
||||
if (_used_by_auto_shader) {
|
||||
GraphicsStateGuardianBase::mark_rehash_generated_shaders();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -99,7 +107,13 @@ get_priority() const {
|
|||
*/
|
||||
INLINE void TextureStage::
|
||||
set_texcoord_name(InternalName *name) {
|
||||
_texcoord_name = name;
|
||||
if (name != _texcoord_name) {
|
||||
_texcoord_name = name;
|
||||
|
||||
if (_used_by_auto_shader) {
|
||||
GraphicsStateGuardianBase::mark_rehash_generated_shaders();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -108,7 +122,7 @@ set_texcoord_name(InternalName *name) {
|
|||
*/
|
||||
INLINE void TextureStage::
|
||||
set_texcoord_name(const string &name) {
|
||||
_texcoord_name = InternalName::get_texcoord_name(name);
|
||||
set_texcoord_name(InternalName::get_texcoord_name(name));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -150,13 +164,16 @@ get_binormal_name() const {
|
|||
*/
|
||||
INLINE void TextureStage::
|
||||
set_mode(TextureStage::Mode mode) {
|
||||
_mode = mode;
|
||||
if (mode != _mode) {
|
||||
_mode = mode;
|
||||
|
||||
if (_mode != M_combine) {
|
||||
_num_combine_rgb_operands = 0;
|
||||
_num_combine_alpha_operands = 0;
|
||||
if (_mode != M_combine) {
|
||||
_num_combine_rgb_operands = 0;
|
||||
_num_combine_alpha_operands = 0;
|
||||
}
|
||||
|
||||
update_color_flags();
|
||||
}
|
||||
update_color_flags();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -202,8 +219,14 @@ get_color() const {
|
|||
*/
|
||||
INLINE void TextureStage::
|
||||
set_rgb_scale(int rgb_scale) {
|
||||
nassertv(rgb_scale == 1 || rgb_scale == 2 || rgb_scale == 4);
|
||||
_rgb_scale = rgb_scale;
|
||||
if (rgb_scale != _rgb_scale) {
|
||||
nassertv(rgb_scale == 1 || rgb_scale == 2 || rgb_scale == 4);
|
||||
_rgb_scale = rgb_scale;
|
||||
|
||||
if (_used_by_auto_shader) {
|
||||
GraphicsStateGuardianBase::mark_rehash_generated_shaders();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -222,8 +245,14 @@ get_rgb_scale() const {
|
|||
*/
|
||||
INLINE void TextureStage::
|
||||
set_alpha_scale(int alpha_scale) {
|
||||
nassertv(alpha_scale == 1 || alpha_scale == 2 || alpha_scale == 4);
|
||||
_alpha_scale = alpha_scale;
|
||||
if (alpha_scale != _alpha_scale) {
|
||||
nassertv(alpha_scale == 1 || alpha_scale == 2 || alpha_scale == 4);
|
||||
_alpha_scale = alpha_scale;
|
||||
|
||||
if (_used_by_auto_shader) {
|
||||
GraphicsStateGuardianBase::mark_rehash_generated_shaders();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -247,7 +276,13 @@ get_alpha_scale() const {
|
|||
*/
|
||||
INLINE void TextureStage::
|
||||
set_saved_result(bool saved_result) {
|
||||
_saved_result = saved_result;
|
||||
if (saved_result != _saved_result) {
|
||||
_saved_result = saved_result;
|
||||
|
||||
if (_used_by_auto_shader) {
|
||||
GraphicsStateGuardianBase::mark_rehash_generated_shaders();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -641,6 +676,14 @@ get_sort_seq() {
|
|||
return _sort_seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this TextureStage as having been used by the auto shader.
|
||||
*/
|
||||
INLINE void TextureStage::
|
||||
mark_used_by_auto_shader() const {
|
||||
_used_by_auto_shader = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates _uses_color, _involves_color_scale, _uses_primary_color and
|
||||
* _uses_last_saved_result appropriately.
|
||||
|
|
@ -658,8 +701,7 @@ update_color_flags() {
|
|||
_combine_alpha_source2 == CS_constant_color_scale)));
|
||||
|
||||
_uses_color =
|
||||
(_involves_color_scale ||
|
||||
_mode == M_blend ||
|
||||
(_mode == M_blend ||
|
||||
(_mode == M_combine &&
|
||||
(_combine_rgb_source0 == CS_constant ||
|
||||
_combine_rgb_source1 == CS_constant ||
|
||||
|
|
@ -685,6 +727,10 @@ update_color_flags() {
|
|||
_combine_alpha_source0 == CS_last_saved_result ||
|
||||
_combine_alpha_source1 == CS_last_saved_result ||
|
||||
_combine_alpha_source2 == CS_last_saved_result));
|
||||
|
||||
if (_used_by_auto_shader) {
|
||||
GraphicsStateGuardianBase::mark_rehash_generated_shaders();
|
||||
}
|
||||
}
|
||||
|
||||
INLINE ostream &
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ TypeHandle TextureStage::_type_handle;
|
|||
* Initialize the texture stage at construction
|
||||
*/
|
||||
TextureStage::
|
||||
TextureStage(const string &name) {
|
||||
TextureStage(const string &name) : _used_by_auto_shader(false) {
|
||||
_name = name;
|
||||
_sort = 0;
|
||||
_priority = 0;
|
||||
|
|
@ -90,6 +90,8 @@ operator = (const TextureStage &other) {
|
|||
|
||||
_uses_color = other._uses_color;
|
||||
_involves_color_scale = other._involves_color_scale;
|
||||
|
||||
_used_by_auto_shader = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "typedWritableReferenceCount.h"
|
||||
#include "updateSeq.h"
|
||||
#include "luse.h"
|
||||
#include "graphicsStateGuardianBase.h"
|
||||
|
||||
class FactoryParams;
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ class FactoryParams;
|
|||
class EXPCL_PANDA_GOBJ TextureStage : public TypedWritableReferenceCount {
|
||||
PUBLISHED:
|
||||
explicit TextureStage(const string &name);
|
||||
INLINE TextureStage(TextureStage ©);
|
||||
INLINE TextureStage(const TextureStage ©);
|
||||
void operator = (const TextureStage ©);
|
||||
|
||||
virtual ~TextureStage();
|
||||
|
|
@ -206,6 +207,8 @@ PUBLISHED:
|
|||
public:
|
||||
INLINE static UpdateSeq get_sort_seq();
|
||||
|
||||
INLINE void mark_used_by_auto_shader() const;
|
||||
|
||||
private:
|
||||
INLINE void update_color_flags();
|
||||
|
||||
|
|
@ -249,6 +252,8 @@ private:
|
|||
static PT(TextureStage) _default_stage;
|
||||
static UpdateSeq _sort_seq;
|
||||
|
||||
mutable bool _used_by_auto_shader;
|
||||
|
||||
public:
|
||||
// Datagram stuff
|
||||
static void register_with_read_factory();
|
||||
|
|
|
|||
|
|
@ -142,6 +142,17 @@ get_weight(size_t n) const {
|
|||
return _entries[n]._weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the nth transform stored in the blend object.
|
||||
*/
|
||||
INLINE void TransformBlend::
|
||||
remove_transform(size_t n) {
|
||||
nassertv(n < _entries.size());
|
||||
_entries.erase(_entries.begin() + n);
|
||||
Thread *current_thread = Thread::get_current_thread();
|
||||
clear_result(current_thread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the nth transform stored in the blend object.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -62,9 +62,15 @@ PUBLISHED:
|
|||
INLINE const VertexTransform *get_transform(size_t n) const;
|
||||
MAKE_SEQ(get_transforms, get_num_transforms, get_transform);
|
||||
INLINE PN_stdfloat get_weight(size_t n) const;
|
||||
INLINE void remove_transform(size_t n);
|
||||
INLINE void set_transform(size_t n, const VertexTransform *transform);
|
||||
INLINE void set_weight(size_t n, PN_stdfloat weight);
|
||||
|
||||
MAKE_SEQ_PROPERTY(transforms, get_num_transforms, get_transform,
|
||||
set_transform, remove_transform);
|
||||
MAKE_SEQ_PROPERTY(weights, get_num_transforms, get_weight, set_weight);
|
||||
MAKE_MAP_PROPERTY(weights, has_transform, get_weight);
|
||||
|
||||
INLINE void update_blend(Thread *current_thread) const;
|
||||
|
||||
INLINE void get_blend(LMatrix4 &result, Thread *current_thread) const;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
AtomicAdjust::Pointer GraphicsStateGuardianBase::_gsg_list;
|
||||
UpdateSeq GraphicsStateGuardianBase::_generated_shader_seq;
|
||||
TypeHandle GraphicsStateGuardianBase::_type_handle;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -223,6 +223,14 @@ public:
|
|||
virtual void bind_light(Spotlight *light_obj, const NodePath &light,
|
||||
int light_id) { }
|
||||
|
||||
virtual void ensure_generated_shader(const RenderState *state)=0;
|
||||
|
||||
static void mark_rehash_generated_shaders() {
|
||||
#ifdef HAVE_CG
|
||||
++_generated_shader_seq;
|
||||
#endif
|
||||
}
|
||||
|
||||
PUBLISHED:
|
||||
static GraphicsStateGuardianBase *get_default_gsg();
|
||||
static void set_default_gsg(GraphicsStateGuardianBase *default_gsg);
|
||||
|
|
@ -235,6 +243,8 @@ public:
|
|||
static void add_gsg(GraphicsStateGuardianBase *gsg);
|
||||
static void remove_gsg(GraphicsStateGuardianBase *gsg);
|
||||
|
||||
size_t _id;
|
||||
|
||||
private:
|
||||
struct GSGList {
|
||||
LightMutex _lock;
|
||||
|
|
@ -245,6 +255,9 @@ private:
|
|||
};
|
||||
static AtomicAdjust::Pointer _gsg_list;
|
||||
|
||||
protected:
|
||||
static UpdateSeq _generated_shader_seq;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
|
|
|
|||
|
|
@ -903,6 +903,14 @@ FLOATNAME(UnalignedLVecBase4)(const FLOATNAME(LVecBase4) ©) {
|
|||
set(copy[0], copy[1], copy[2], copy[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)::
|
||||
FLOATNAME(UnalignedLVecBase4)(FLOATTYPE fill_value) {
|
||||
fill(fill_value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
@ -912,6 +920,19 @@ FLOATNAME(UnalignedLVecBase4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w
|
|||
set(x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets each element of the vector to the indicated fill_value. This is
|
||||
* particularly useful for initializing to zero.
|
||||
*/
|
||||
INLINE_LINMATH void FLOATNAME(UnalignedLVecBase4)::
|
||||
fill(FLOATTYPE fill_value) {
|
||||
TAU_PROFILE("void UnalignedLVecBase4::fill()", " ", TAU_USER);
|
||||
_v(0) = fill_value;
|
||||
_v(1) = fill_value;
|
||||
_v(2) = fill_value;
|
||||
_v(3) = fill_value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -230,8 +230,10 @@ PUBLISHED:
|
|||
|
||||
INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)() DEFAULT_CTOR;
|
||||
INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)(const FLOATNAME(LVecBase4) ©);
|
||||
INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)(FLOATTYPE fill_value);
|
||||
INLINE_LINMATH FLOATNAME(UnalignedLVecBase4)(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
|
||||
|
||||
INLINE_LINMATH void fill(FLOATTYPE fill_value);
|
||||
INLINE_LINMATH void set(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w);
|
||||
|
||||
INLINE_LINMATH FLOATTYPE operator [](int i) const;
|
||||
|
|
|
|||
|
|
@ -91,12 +91,16 @@ PUBLISHED:
|
|||
void clear_tag_states();
|
||||
bool has_tag_state(const string &tag_state) const;
|
||||
CPT(RenderState) get_tag_state(const string &tag_state) const;
|
||||
MAKE_MAP_PROPERTY(tag_states, has_tag_state, get_tag_state,
|
||||
set_tag_state, clear_tag_state);
|
||||
|
||||
void set_aux_scene_data(const NodePath &node_path, AuxSceneData *data);
|
||||
bool clear_aux_scene_data(const NodePath &node_path);
|
||||
AuxSceneData *get_aux_scene_data(const NodePath &node_path) const;
|
||||
void list_aux_scene_data(ostream &out) const;
|
||||
int cleanup_aux_scene_data(Thread *current_thread = Thread::get_current_thread());
|
||||
MAKE_MAP_PROPERTY(aux_scene_data, get_aux_scene_data, get_aux_scene_data,
|
||||
set_aux_scene_data, clear_aux_scene_data);
|
||||
|
||||
private:
|
||||
void add_display_region(DisplayRegion *display_region);
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ make_default() {
|
|||
/**
|
||||
* Returns the basic operation type of the ClipPlaneAttrib. If this is O_set,
|
||||
* the planes listed here completely replace any planes that were already on.
|
||||
* If this is O_add, the planes here are added to the set of of planes that
|
||||
* If this is O_add, the planes here are added to the set of planes that
|
||||
* were already on, and if O_remove, the planes here are removed from the set
|
||||
* of planes that were on.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ ConfigVariableBool uniquify_states
|
|||
"are pointerwise equal. This may improve caching performance, "
|
||||
"but also adds additional overhead to maintain the cache, "
|
||||
"including the need to check for a composition cycle in "
|
||||
"the cache."));
|
||||
"the cache. It is highly recommended to keep this on."));
|
||||
|
||||
ConfigVariableBool uniquify_attribs
|
||||
("uniquify-attribs", true,
|
||||
|
|
|
|||
|
|
@ -142,10 +142,15 @@ munge_geom(GraphicsStateGuardianBase *gsg, GeomMunger *munger,
|
|||
DCAST(ShaderAttrib, ShaderAttrib::make())->set_flag(ShaderAttrib::F_hardware_skinning, true));
|
||||
_state = _state->compose(state);
|
||||
}
|
||||
}
|
||||
|
||||
StateMunger *state_munger = (StateMunger *)munger;
|
||||
_state = state_munger->munge_state(_state);
|
||||
gsg->ensure_generated_shader(_state);
|
||||
} else {
|
||||
// We may need to munge the state for the fixed-function pipeline.
|
||||
StateMunger *state_munger = (StateMunger *)munger;
|
||||
if (state_munger->should_munge_state()) {
|
||||
_state = state_munger->munge_state(_state);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is any animation left in the vertex data after it has been
|
||||
// munged--that is, we couldn't arrange to handle the animation in
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ make_default() {
|
|||
/**
|
||||
* Returns the basic operation type of the LightAttrib. If this is O_set, the
|
||||
* lights listed here completely replace any lights that were already on. If
|
||||
* this is O_add, the lights here are added to the set of of lights that were
|
||||
* this is O_add, the lights here are added to the set of lights that were
|
||||
* already on, and if O_remove, the lights here are removed from the set of
|
||||
* lights that were on.
|
||||
*
|
||||
|
|
@ -833,6 +833,14 @@ compose_impl(const RenderAttrib *other) const {
|
|||
++result;
|
||||
}
|
||||
|
||||
// Increase the attrib_ref of all the lights in this new attribute.
|
||||
Lights::const_iterator it;
|
||||
for (it = new_attrib->_on_lights.begin(); it != new_attrib->_on_lights.end(); ++it) {
|
||||
Light *lobj = (*it).node()->as_light();
|
||||
nassertd(lobj != nullptr) continue;
|
||||
lobj->attrib_ref();
|
||||
}
|
||||
|
||||
return return_new(new_attrib);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -630,9 +630,12 @@ PUBLISHED:
|
|||
void clear_shader();
|
||||
|
||||
void set_shader_input(ShaderInput input);
|
||||
INLINE void set_shader_input(CPT_InternalName id, Texture *tex, int priority=0);
|
||||
|
||||
INLINE void set_shader_input(CPT_InternalName id, Texture *tex, const SamplerState &sampler, int priority=0);
|
||||
INLINE void set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0);
|
||||
|
||||
public:
|
||||
INLINE void set_shader_input(CPT_InternalName id, Texture *tex, int priority=0);
|
||||
INLINE void set_shader_input(CPT_InternalName id, ShaderBuffer *buf, int priority=0);
|
||||
INLINE void set_shader_input(CPT_InternalName id, const NodePath &np, int priority=0);
|
||||
INLINE void set_shader_input(CPT_InternalName id, const PTA_float &v, int priority=0);
|
||||
|
|
@ -654,11 +657,13 @@ PUBLISHED:
|
|||
INLINE void set_shader_input(CPT_InternalName id, const LVecBase4i &v, int priority=0);
|
||||
INLINE void set_shader_input(CPT_InternalName id, const LVecBase3i &v, int priority=0);
|
||||
INLINE void set_shader_input(CPT_InternalName id, const LVecBase2i &v, int priority=0);
|
||||
INLINE void set_shader_input(CPT_InternalName id, int n1, int n2=0, int n3=0,
|
||||
PUBLISHED:
|
||||
INLINE void set_shader_input(CPT_InternalName id, int n1, int n2, int n3=0,
|
||||
int n4=0, int priority=0);
|
||||
INLINE void set_shader_input(CPT_InternalName id, PN_stdfloat n1, PN_stdfloat n2=0,
|
||||
INLINE void set_shader_input(CPT_InternalName id, PN_stdfloat n1, PN_stdfloat n2,
|
||||
PN_stdfloat n3=0, PN_stdfloat n4=0, int priority=0);
|
||||
|
||||
EXTENSION(void set_shader_input(CPT_InternalName, PyObject *, int priority=0));
|
||||
EXTENSION(void set_shader_inputs(PyObject *args, PyObject *kwargs));
|
||||
|
||||
void clear_shader_input(CPT_InternalName id);
|
||||
|
|
@ -908,6 +913,9 @@ PUBLISHED:
|
|||
INLINE bool has_net_tag(const string &key) const;
|
||||
NodePath find_net_tag(const string &key) const;
|
||||
|
||||
MAKE_MAP_PROPERTY(tags, has_tag, get_tag, set_tag, clear_tag);
|
||||
MAKE_MAP_PROPERTY(net_tags, has_net_tag, get_net_tag);
|
||||
|
||||
EXTENSION(INLINE PyObject *get_tag_keys() const);
|
||||
|
||||
EXTENSION(PyObject *get_python_tags());
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "nodePath_ext.h"
|
||||
#include "typedWritable_ext.h"
|
||||
#include "shaderInput_ext.h"
|
||||
#include "shaderAttrib.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
|
@ -25,35 +26,7 @@ extern struct Dtool_PyTypedObject Dtool_LPoint3d;
|
|||
#else
|
||||
extern struct Dtool_PyTypedObject Dtool_LPoint3f;
|
||||
#endif
|
||||
extern struct Dtool_PyTypedObject Dtool_Texture;
|
||||
extern struct Dtool_PyTypedObject Dtool_NodePath;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_float;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_double;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_int;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLVecBase4f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase3f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase2f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLMatrix4f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LMatrix3f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLVecBase4d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase3d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase2d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLMatrix4d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LMatrix3d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLVecBase4i;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase3i;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase2i;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase4f;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase3f;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase2f;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase4d;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase3d;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase2d;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase4i;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase3i;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase2i;
|
||||
extern struct Dtool_PyTypedObject Dtool_ShaderBuffer;
|
||||
extern struct Dtool_PyTypedObject Dtool_ParamValueBase;
|
||||
#endif // CPPPARSER
|
||||
|
||||
/**
|
||||
|
|
@ -241,6 +214,28 @@ py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &da
|
|||
return NodePath::decode_from_bam_stream(data, reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a single shader input.
|
||||
*/
|
||||
void Extension<NodePath>::
|
||||
set_shader_input(CPT_InternalName name, PyObject *value, int priority) {
|
||||
PT(PandaNode) node = _this->node();
|
||||
CPT(RenderAttrib) prev_attrib = node->get_attrib(ShaderAttrib::get_class_slot());
|
||||
PT(ShaderAttrib) attrib;
|
||||
if (prev_attrib == nullptr) {
|
||||
attrib = new ShaderAttrib();
|
||||
} else {
|
||||
attrib = new ShaderAttrib(*(const ShaderAttrib *)prev_attrib.p());
|
||||
}
|
||||
|
||||
ShaderInput &input = attrib->_inputs[name];
|
||||
invoke_extension(&input).__init__(move(name), value);
|
||||
|
||||
if (!_PyErr_OCCURRED()) {
|
||||
node->set_attrib(ShaderAttrib::return_new(attrib));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets multiple shader inputs at the same time. This can be significantly
|
||||
* more efficient if many inputs need to be set at the same time.
|
||||
|
|
@ -278,153 +273,13 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) {
|
|||
}
|
||||
|
||||
CPT_InternalName name(string(buffer, length));
|
||||
ShaderInput input(nullptr, 0);
|
||||
|
||||
if (PyTuple_CheckExact(value)) {
|
||||
// A tuple is interpreted as a vector.
|
||||
Py_ssize_t size = PyTuple_GET_SIZE(value);
|
||||
if (size > 4) {
|
||||
Dtool_Raise_TypeError("NodePath.set_shader_inputs tuple input should not have more than 4 scalars");
|
||||
return;
|
||||
}
|
||||
// If any of them is a float, we are storing it as a float vector.
|
||||
bool is_float = false;
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
if (PyFloat_CheckExact(PyTuple_GET_ITEM(value, i))) {
|
||||
is_float = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_float) {
|
||||
LVecBase4 vec(0);
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
vec[i] = (PN_stdfloat)PyFloat_AsDouble(PyTuple_GET_ITEM(value, i));
|
||||
}
|
||||
input = ShaderInput(move(name), vec);
|
||||
} else {
|
||||
LVecBase4i vec(0);
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
vec[i] = (int)PyLong_AsLong(PyTuple_GET_ITEM(value, i));
|
||||
}
|
||||
input = ShaderInput(move(name), vec);
|
||||
}
|
||||
|
||||
} else if (DtoolCanThisBeAPandaInstance(value)) {
|
||||
Dtool_PyInstDef *inst = (Dtool_PyInstDef *)value;
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_Texture))) {
|
||||
input = ShaderInput(move(name), (Texture *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_NodePath))) {
|
||||
input = ShaderInput(move(name), *(const NodePath *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_float))) {
|
||||
input = ShaderInput(move(name), *(const PTA_float *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_double))) {
|
||||
input = ShaderInput(move(name), *(const PTA_double *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_int))) {
|
||||
input = ShaderInput(move(name), *(const PTA_int *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4f))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LVecBase4f *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3f))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LVecBase3f *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2f))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LVecBase2f *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4f))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LMatrix4f *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3f))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LMatrix3f *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4d))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LVecBase4d *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3d))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LVecBase3d *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2d))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LVecBase2d *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4d))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LMatrix4d *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3d))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LMatrix3d *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4i))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LVecBase4i *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3i))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LVecBase3i *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2i))) {
|
||||
input = ShaderInput(move(name), *(const PTA_LVecBase2i *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4f))) {
|
||||
input = ShaderInput(move(name), *(const LVecBase4f *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3f))) {
|
||||
input = ShaderInput(move(name), *(const LVecBase3f *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2f))) {
|
||||
input = ShaderInput(move(name), *(const LVecBase2f *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4d))) {
|
||||
input = ShaderInput(move(name), *(const LVecBase4d *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3d))) {
|
||||
input = ShaderInput(move(name), *(const LVecBase3d *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2d))) {
|
||||
input = ShaderInput(move(name), *(const LVecBase2d *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4i))) {
|
||||
input = ShaderInput(move(name), *(const LVecBase4i *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3i))) {
|
||||
input = ShaderInput(move(name), *(const LVecBase3i *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2i))) {
|
||||
input = ShaderInput(move(name), *(const LVecBase2i *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ShaderBuffer))) {
|
||||
input = ShaderInput(move(name), (ShaderBuffer *)ptr);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ParamValueBase))) {
|
||||
input = ShaderInput(move(name), (ParamValueBase *)ptr);
|
||||
|
||||
} else {
|
||||
Dtool_Raise_TypeError("unknown type passed to NodePath.set_shader_inputs");
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (PyFloat_Check(value)) {
|
||||
input = ShaderInput(move(name), LVecBase4(PyFloat_AS_DOUBLE(value), 0, 0, 0));
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
} else if (PyInt_Check(value)) {
|
||||
input = ShaderInput(move(name), LVecBase4i((int)PyInt_AS_LONG(value), 0, 0, 0));
|
||||
#endif
|
||||
|
||||
} else if (PyLong_Check(value)) {
|
||||
input = ShaderInput(move(name), LVecBase4i((int)PyLong_AsLong(value), 0, 0, 0));
|
||||
|
||||
} else {
|
||||
Dtool_Raise_TypeError("unknown type passed to NodePath.set_shader_inputs");
|
||||
return;
|
||||
}
|
||||
|
||||
attrib->_inputs[input.get_name()] = move(input);
|
||||
ShaderInput &input = attrib->_inputs[name];
|
||||
invoke_extension(&input).__init__(move(name), value);
|
||||
}
|
||||
|
||||
node->set_attrib(ShaderAttrib::return_new(attrib));
|
||||
if (!_PyErr_OCCURRED()) {
|
||||
node->set_attrib(ShaderAttrib::return_new(attrib));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ public:
|
|||
// This is defined to implement cycle detection in Python tags.
|
||||
INLINE int __traverse__(visitproc visit, void *arg);
|
||||
|
||||
void set_shader_input(CPT_InternalName id, PyObject *value, int priority=0);
|
||||
void set_shader_inputs(PyObject *args, PyObject *kwargs);
|
||||
|
||||
PyObject *get_tight_bounds(const NodePath &other = NodePath()) const;
|
||||
|
|
|
|||
|
|
@ -2,4 +2,6 @@
|
|||
#include "nodePathCollection_ext.cxx"
|
||||
#include "pandaNode_ext.cxx"
|
||||
#include "renderState_ext.cxx"
|
||||
#include "shaderAttrib_ext.cxx"
|
||||
#include "shaderInput_ext.cxx"
|
||||
#include "transformState_ext.cxx"
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ return_unique(RenderAttrib *attrib) {
|
|||
// deleted while it's in it.
|
||||
attrib->ref();
|
||||
}
|
||||
si = _attribs->store(attrib, Empty());
|
||||
si = _attribs->store(attrib, nullptr);
|
||||
|
||||
// Save the index and return the input attrib.
|
||||
attrib->_saved_entry = si;
|
||||
|
|
|
|||
|
|
@ -185,9 +185,7 @@ public:
|
|||
private:
|
||||
// This mutex protects _attribs.
|
||||
static LightReMutex *_attribs_lock;
|
||||
class Empty {
|
||||
};
|
||||
typedef SimpleHashMap<const RenderAttrib *, Empty, indirect_compare_to_hash<const RenderAttrib *> > Attribs;
|
||||
typedef SimpleHashMap<const RenderAttrib *, nullptr_t, indirect_compare_to_hash<const RenderAttrib *> > Attribs;
|
||||
static Attribs *_attribs;
|
||||
|
||||
int _saved_entry;
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ register_slot(TypeHandle type_handle, int sort, RenderAttrib *default_attrib) {
|
|||
// If this attribute was already registered, something odd is going on.
|
||||
nassertr(RenderAttrib::_attribs->find(default_attrib) == -1, 0);
|
||||
default_attrib->_saved_entry =
|
||||
RenderAttrib::_attribs->store(default_attrib, RenderAttrib::Empty());
|
||||
RenderAttrib::_attribs->store(default_attrib, nullptr);
|
||||
}
|
||||
|
||||
// It effectively lives forever. Might as well make it official.
|
||||
|
|
|
|||
|
|
@ -987,6 +987,7 @@ clear_munger_cache() {
|
|||
for (size_t si = 0; si < size; ++si) {
|
||||
RenderState *state = (RenderState *)(_states->get_key(si));
|
||||
state->_mungers.clear();
|
||||
state->_munged_states.clear();
|
||||
state->_last_mi = -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1338,7 +1339,7 @@ return_unique(RenderState *state) {
|
|||
// deleted while it's in it.
|
||||
state->cache_ref();
|
||||
}
|
||||
si = _states->store(state, Empty());
|
||||
si = _states->store(state, nullptr);
|
||||
|
||||
// Save the index and return the input state.
|
||||
state->_saved_entry = si;
|
||||
|
|
@ -1865,7 +1866,7 @@ init_states() {
|
|||
// is declared globally, and lives forever.
|
||||
RenderState *state = new RenderState;
|
||||
state->local_object();
|
||||
state->_saved_entry = _states->store(state, Empty());
|
||||
state->_saved_entry = _states->store(state, nullptr);
|
||||
_empty_state = state;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,10 +30,8 @@
|
|||
#include "lightMutex.h"
|
||||
#include "deletedChain.h"
|
||||
#include "simpleHashMap.h"
|
||||
#include "weakKeyHashMap.h"
|
||||
#include "cacheStats.h"
|
||||
#include "renderAttribRegistry.h"
|
||||
#include "graphicsStateGuardianBase.h"
|
||||
|
||||
class FactoryParams;
|
||||
class ShaderAttrib;
|
||||
|
|
@ -109,6 +107,8 @@ PUBLISHED:
|
|||
INLINE int get_override(TypeHandle type) const;
|
||||
INLINE int get_override(int slot) const;
|
||||
|
||||
MAKE_MAP_PROPERTY(attribs, has_attrib, get_attrib);
|
||||
|
||||
INLINE CPT(RenderState) get_unique() const;
|
||||
|
||||
virtual bool unref() const;
|
||||
|
|
@ -219,15 +219,14 @@ public:
|
|||
// declare this as a ShaderAttrib because that would create a circular
|
||||
// include-file dependency problem. Aaargh.
|
||||
mutable CPT(RenderAttrib) _generated_shader;
|
||||
mutable UpdateSeq _generated_shader_seq;
|
||||
|
||||
private:
|
||||
// This mutex protects _states. It also protects any modification to the
|
||||
// cache, which is encoded in _composition_cache and
|
||||
// _invert_composition_cache.
|
||||
static LightReMutex *_states_lock;
|
||||
class Empty {
|
||||
};
|
||||
typedef SimpleHashMap<const RenderState *, Empty, indirect_compare_to_hash<const RenderState *> > States;
|
||||
typedef SimpleHashMap<const RenderState *, nullptr_t, indirect_compare_to_hash<const RenderState *> > States;
|
||||
static States *_states;
|
||||
static const RenderState *_empty_state;
|
||||
|
||||
|
|
@ -264,10 +263,15 @@ private:
|
|||
// in the RenderState pointer than vice-versa, since there are likely to be
|
||||
// far fewer GSG's than RenderStates. The code to manage this map lives in
|
||||
// GraphicsStateGuardian::get_geom_munger().
|
||||
typedef WeakKeyHashMap<GraphicsStateGuardianBase, PT(GeomMunger) > Mungers;
|
||||
typedef SimpleHashMap<size_t, PT(GeomMunger), size_t_hash> Mungers;
|
||||
mutable Mungers _mungers;
|
||||
mutable int _last_mi;
|
||||
|
||||
// Similarly, this is a cache of munged states. This map is managed by
|
||||
// StateMunger::munge_state().
|
||||
typedef SimpleHashMap<size_t, WCPT(RenderState), size_t_hash> MungedStates;
|
||||
mutable MungedStates _munged_states;
|
||||
|
||||
// This is used to mark nodes as we visit them to detect cycles.
|
||||
UpdateSeq _cycle_detect;
|
||||
static UpdateSeq _last_cycle_detect;
|
||||
|
|
@ -360,6 +364,8 @@ private:
|
|||
friend class GraphicsStateGuardian;
|
||||
friend class RenderAttribRegistry;
|
||||
friend class Extension<RenderState>;
|
||||
friend class ShaderGenerator;
|
||||
friend class StateMunger;
|
||||
};
|
||||
|
||||
// We can safely redefine this as a no-op.
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ PUBLISHED:
|
|||
// Shader Inputs
|
||||
CPT(RenderAttrib) set_shader_input(ShaderInput input) const;
|
||||
|
||||
public:
|
||||
INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, Texture *tex, int priority=0) const;
|
||||
INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, const NodePath &np, int priority=0) const;
|
||||
INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, const PTA_float &v, int priority=0) const;
|
||||
|
|
@ -90,6 +91,10 @@ PUBLISHED:
|
|||
INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, double n1=0, double n2=0, double n3=0, double n4=1,
|
||||
int priority=0) const;
|
||||
|
||||
PUBLISHED:
|
||||
EXTENSION(CPT(RenderAttrib) set_shader_input(CPT_InternalName, PyObject *, int priority=0) const);
|
||||
EXTENSION(CPT(RenderAttrib) set_shader_inputs(PyObject *args, PyObject *kwargs) const);
|
||||
|
||||
CPT(RenderAttrib) set_instance_count(int instance_count) const;
|
||||
|
||||
CPT(RenderAttrib) set_flag(int flag, bool value) const;
|
||||
|
|
@ -150,6 +155,7 @@ private:
|
|||
Inputs _inputs;
|
||||
|
||||
friend class Extension<NodePath>;
|
||||
friend class Extension<ShaderAttrib>;
|
||||
|
||||
PUBLISHED:
|
||||
static int get_class_slot() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file shaderAttrib_ext.cxx
|
||||
* @author rdb
|
||||
* @date 2017-10-08
|
||||
*/
|
||||
|
||||
#include "shaderAttrib_ext.h"
|
||||
#include "shaderInput_ext.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
/**
|
||||
* Returns a new ShaderAttrib with the given shader input set.
|
||||
*/
|
||||
CPT(RenderAttrib) Extension<ShaderAttrib>::
|
||||
set_shader_input(CPT_InternalName name, PyObject *value, int priority) const {
|
||||
ShaderAttrib *attrib = new ShaderAttrib(*_this);
|
||||
|
||||
ShaderInput &input = attrib->_inputs[name];
|
||||
invoke_extension(&input).__init__(move(name), value);
|
||||
|
||||
return ShaderAttrib::return_new(attrib);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new ShaderAttrib with the given shader inputs set. This is a
|
||||
* more efficient way to set multiple shader inputs than calling
|
||||
* set_shader_input multiple times.
|
||||
*/
|
||||
CPT(RenderAttrib) Extension<ShaderAttrib>::
|
||||
set_shader_inputs(PyObject *args, PyObject *kwargs) const {
|
||||
if (PyObject_Size(args) > 0) {
|
||||
Dtool_Raise_TypeError("ShaderAttrib.set_shader_inputs takes only keyword arguments");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ShaderAttrib *attrib = new ShaderAttrib(*_this);
|
||||
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
|
||||
while (PyDict_Next(kwargs, &pos, &key, &value)) {
|
||||
char *buffer;
|
||||
Py_ssize_t length;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
buffer = (char *)PyUnicode_AsUTF8AndSize(key, &length);
|
||||
if (buffer == nullptr) {
|
||||
#else
|
||||
if (PyString_AsStringAndSize(key, &buffer, &length) == -1) {
|
||||
#endif
|
||||
Dtool_Raise_TypeError("ShaderAttrib.set_shader_inputs accepts only string keywords");
|
||||
delete attrib;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CPT_InternalName name(string(buffer, length));
|
||||
ShaderInput &input = attrib->_inputs[name];
|
||||
invoke_extension(&input).__init__(move(name), value);
|
||||
}
|
||||
|
||||
return ShaderAttrib::return_new(attrib);
|
||||
}
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file shaderAttrib_ext.h
|
||||
* @author rdb
|
||||
* @date 2017-10-08
|
||||
*/
|
||||
|
||||
#ifndef SHADERATTRIB_EXT_H
|
||||
#define SHADERATTRIB_EXT_H
|
||||
|
||||
#include "dtoolbase.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "extension.h"
|
||||
#include "shaderAttrib.h"
|
||||
#include "py_panda.h"
|
||||
|
||||
/**
|
||||
* This class defines the extension methods for ShaderAttrib, which are called
|
||||
* instead of any C++ methods with the same prototype.
|
||||
*/
|
||||
template<>
|
||||
class Extension<ShaderAttrib> : public ExtensionBase<ShaderAttrib> {
|
||||
public:
|
||||
CPT(RenderAttrib) set_shader_input(CPT_InternalName id, PyObject *value, int priority=0) const;
|
||||
CPT(RenderAttrib) set_shader_inputs(PyObject *args, PyObject *kwargs) const;
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#endif // SHADERATTRIB_EXT_H
|
||||
|
|
@ -417,6 +417,14 @@ ShaderInput(CPT_InternalName name, const LVecBase2i &vec, int priority) :
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE ShaderInput::
|
||||
operator bool () const {
|
||||
return _type != M_invalid;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -46,7 +46,11 @@ PUBLISHED:
|
|||
};
|
||||
|
||||
static const ShaderInput &get_blank();
|
||||
INLINE ShaderInput(CPT_InternalName name, int priority=0);
|
||||
INLINE explicit ShaderInput(CPT_InternalName name, int priority=0);
|
||||
|
||||
EXTENSION(explicit ShaderInput(CPT_InternalName name, PyObject *value, int priority=0));
|
||||
|
||||
public:
|
||||
INLINE ShaderInput(CPT_InternalName name, Texture *tex, int priority=0);
|
||||
INLINE ShaderInput(CPT_InternalName name, ParamValueBase *param, int priority=0);
|
||||
INLINE ShaderInput(CPT_InternalName name, ShaderBuffer *buf, int priority=0);
|
||||
|
|
@ -83,6 +87,8 @@ PUBLISHED:
|
|||
INLINE ShaderInput(CPT_InternalName name, const LVecBase2i &vec, int priority=0);
|
||||
|
||||
ShaderInput(CPT_InternalName name, const NodePath &np, int priority=0);
|
||||
|
||||
PUBLISHED:
|
||||
ShaderInput(CPT_InternalName name, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0);
|
||||
ShaderInput(CPT_InternalName name, Texture *tex, const SamplerState &sampler, int priority=0);
|
||||
|
||||
|
|
@ -98,6 +104,7 @@ PUBLISHED:
|
|||
M_buffer,
|
||||
};
|
||||
|
||||
INLINE operator bool() const;
|
||||
INLINE bool operator == (const ShaderInput &other) const;
|
||||
INLINE bool operator != (const ShaderInput &other) const;
|
||||
INLINE bool operator < (const ShaderInput &other) const;
|
||||
|
|
@ -132,6 +139,7 @@ private:
|
|||
int _type;
|
||||
|
||||
friend class ShaderAttrib;
|
||||
friend class Extension<ShaderInput>;
|
||||
};
|
||||
|
||||
#include "shaderInput.I"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,539 @@
|
|||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file shaderInput_ext.cxx
|
||||
* @author rdb
|
||||
* @date 2017-10-06
|
||||
*/
|
||||
|
||||
#include "shaderInput_ext.h"
|
||||
#include "paramNodePath.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#ifndef CPPPARSER
|
||||
extern struct Dtool_PyTypedObject Dtool_Texture;
|
||||
extern struct Dtool_PyTypedObject Dtool_NodePath;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToVoid;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_float;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_double;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_int;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLVecBase4f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase3f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase2f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLMatrix4f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LMatrix3f;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLVecBase4d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase3d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase2d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLMatrix4d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LMatrix3d;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLVecBase4i;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase3i;
|
||||
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase2i;
|
||||
extern struct Dtool_PyTypedObject Dtool_LMatrix4f;
|
||||
extern struct Dtool_PyTypedObject Dtool_LMatrix3f;
|
||||
extern struct Dtool_PyTypedObject Dtool_LMatrix4d;
|
||||
extern struct Dtool_PyTypedObject Dtool_LMatrix3d;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase4f;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase3f;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase2f;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase4d;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase3d;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase2d;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase4i;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase3i;
|
||||
extern struct Dtool_PyTypedObject Dtool_LVecBase2i;
|
||||
extern struct Dtool_PyTypedObject Dtool_ShaderBuffer;
|
||||
extern struct Dtool_PyTypedObject Dtool_ParamValueBase;
|
||||
#endif // CPPPARSER
|
||||
|
||||
/**
|
||||
* Sets a shader input from an arbitrary Python object.
|
||||
*/
|
||||
void Extension<ShaderInput>::
|
||||
__init__(CPT_InternalName name, PyObject *value, int priority) {
|
||||
_this->_name = move(name);
|
||||
_this->_priority = priority;
|
||||
|
||||
if (PyTuple_CheckExact(value) && PyTuple_GET_SIZE(value) <= 4) {
|
||||
// A tuple is interpreted as a vector.
|
||||
Py_ssize_t size = PyTuple_GET_SIZE(value);
|
||||
|
||||
// If any of them is a float, we are storing it as a float vector.
|
||||
bool is_float = false;
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
if (PyFloat_CheckExact(PyTuple_GET_ITEM(value, i))) {
|
||||
is_float = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_float) {
|
||||
LVecBase4 vec(0);
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
vec[i] = (PN_stdfloat)PyFloat_AsDouble(PyTuple_GET_ITEM(value, i));
|
||||
}
|
||||
_this->_type = ShaderInput::M_vector;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector = vec;
|
||||
} else {
|
||||
LVecBase4i vec(0);
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
vec[i] = (int)PyLong_AsLong(PyTuple_GET_ITEM(value, i));
|
||||
}
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector = LCAST(PN_stdfloat, vec);
|
||||
}
|
||||
|
||||
} else if (DtoolCanThisBeAPandaInstance(value)) {
|
||||
Dtool_PyInstDef *inst = (Dtool_PyInstDef *)value;
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_Texture))) {
|
||||
_this->_type = ShaderInput::M_texture;
|
||||
_this->_value = (Texture *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_NodePath))) {
|
||||
_this->_type = ShaderInput::M_nodepath;
|
||||
_this->_value = new ParamNodePath(*(const NodePath *)ptr);
|
||||
|
||||
} else if (inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToVoid)) {
|
||||
if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_float))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_float *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_double))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_double *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_int))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_int *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4f))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LVecBase4f *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3f))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LVecBase3f *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2f))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LVecBase2f *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4f))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LMatrix4f *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3f))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LMatrix3f *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4d))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LVecBase4d *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3d))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LVecBase3d *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2d))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LVecBase2d *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4d))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LMatrix4d *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3d))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LMatrix3d *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4i))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LVecBase4i *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3i))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LVecBase3i *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2i))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const PTA_LVecBase2i *)ptr;
|
||||
|
||||
} else {
|
||||
Dtool_Raise_TypeError("unknown type passed to ShaderInput");
|
||||
return;
|
||||
}
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LMatrix4f))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const LMatrix4f *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LMatrix3f))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const LMatrix3f *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LMatrix4d))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const LMatrix4d *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LMatrix3d))) {
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = *(const LMatrix3d *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4f))) {
|
||||
const LVecBase4f &vec = *(const LVecBase4f *)ptr;
|
||||
_this->_type = ShaderInput::M_vector;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector = LCAST(PN_stdfloat, vec);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3f))) {
|
||||
const LVecBase3f &vec = *(const LVecBase3f *)ptr;
|
||||
_this->_type = ShaderInput::M_vector;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector.set(vec[0], vec[1], vec[2], 0);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2f))) {
|
||||
const LVecBase2f &vec = *(const LVecBase2f *)ptr;
|
||||
_this->_type = ShaderInput::M_vector;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector.set(vec[0], vec[1], 0, 0);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4d))) {
|
||||
const LVecBase4d &vec = *(const LVecBase4d *)ptr;
|
||||
_this->_type = ShaderInput::M_vector;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector = LCAST(PN_stdfloat, vec);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3d))) {
|
||||
const LVecBase3d &vec = *(const LVecBase3d *)ptr;
|
||||
_this->_type = ShaderInput::M_vector;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector.set(vec[0], vec[1], vec[2], 0);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2d))) {
|
||||
const LVecBase2d &vec = *(const LVecBase2d *)ptr;
|
||||
_this->_type = ShaderInput::M_vector;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector.set(vec[0], vec[1], 0, 0);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4i))) {
|
||||
const LVecBase4i &vec = *(const LVecBase4i *)ptr;
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector = LCAST(PN_stdfloat, vec);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3i))) {
|
||||
const LVecBase3i &vec = *(const LVecBase3i *)ptr;
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector.set(vec[0], vec[1], vec[2], 0);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2i))) {
|
||||
const LVecBase2i &vec = *(const LVecBase2i *)ptr;
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector.set(vec[0], vec[1], 0, 0);
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ShaderBuffer))) {
|
||||
_this->_type = ShaderInput::M_buffer;
|
||||
_this->_value = (ShaderBuffer *)ptr;
|
||||
|
||||
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ParamValueBase))) {
|
||||
_this->_type = ShaderInput::M_param;
|
||||
_this->_value = (ParamValueBase *)ptr;
|
||||
|
||||
} else {
|
||||
Dtool_Raise_TypeError("unknown type passed to ShaderInput");
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (PyFloat_Check(value)) {
|
||||
LVecBase4 vec(PyFloat_AS_DOUBLE(value), 0, 0, 0);
|
||||
_this->_type = ShaderInput::M_vector;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector = vec;
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
} else if (PyInt_Check(value)) {
|
||||
LVecBase4i vec((int)PyInt_AS_LONG(value), 0, 0, 0);
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector.set((PN_stdfloat)vec[0], 0, 0, 0);
|
||||
#endif
|
||||
|
||||
} else if (PyLong_Check(value)) {
|
||||
LVecBase4i vec((int)PyLong_AsLong(value), 0, 0, 0);
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
_this->_stored_ptr = vec;
|
||||
_this->_stored_vector.set((PN_stdfloat)vec[0], 0, 0, 0);
|
||||
|
||||
} else if (PySequence_Check(value) && !PyUnicode_CheckExact(value)) {
|
||||
// Iterate over the sequence to make sure all have the same type.
|
||||
PyObject *fast = PySequence_Fast(value, "unknown type passed to ShaderInput");
|
||||
if (fast == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Py_ssize_t num_items = PySequence_Fast_GET_SIZE(value);
|
||||
if (num_items <= 0) {
|
||||
// We can't determine the type of a list of size 0.
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
Py_DECREF(fast);
|
||||
return;
|
||||
}
|
||||
|
||||
bool has_float = false;
|
||||
Py_ssize_t known_itemsize = -1;
|
||||
|
||||
PyObject **items = PySequence_Fast_ITEMS(fast);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *item = items[i];
|
||||
|
||||
if (PySequence_Check(item)) {
|
||||
Py_ssize_t itemsize = PySequence_Size(item);
|
||||
if (known_itemsize >= 0 && itemsize != known_itemsize) {
|
||||
Dtool_Raise_TypeError("inconsistent sequence length among elements of sequence passed to ShaderInput");
|
||||
Py_DECREF(fast);
|
||||
return;
|
||||
}
|
||||
known_itemsize = itemsize;
|
||||
|
||||
// Check their types.
|
||||
for (Py_ssize_t j = 0; j < itemsize; ++j) {
|
||||
PyObject *subitem = PySequence_ITEM(item, j);
|
||||
if (PyFloat_CheckExact(subitem)) {
|
||||
Py_DECREF(subitem);
|
||||
has_float = true;
|
||||
break;
|
||||
} else if (PyLongOrInt_Check(subitem)) {
|
||||
} else {
|
||||
Dtool_Raise_TypeError("unknown element type in sequence passed as element of sequence passed to ShaderInput");
|
||||
Py_DECREF(subitem);
|
||||
Py_DECREF(fast);
|
||||
break;
|
||||
}
|
||||
Py_DECREF(subitem);
|
||||
}
|
||||
} else if (PyFloat_CheckExact(item)) {
|
||||
has_float = true;
|
||||
} else if (PyLongOrInt_Check(item)) {
|
||||
} else {
|
||||
Dtool_Raise_TypeError("unknown element type in sequence passed to ShaderInput");
|
||||
Py_DECREF(fast);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have verified the dimensions and type of the PTA, we can
|
||||
// read in the actual elements.
|
||||
switch (known_itemsize) {
|
||||
case -1:
|
||||
if (has_float) {
|
||||
PTA_float pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
pta.push_back(PyFloat_AsDouble(items[i]));
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
} else {
|
||||
PTA_int pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
pta.push_back((int)PyLongOrInt_AS_LONG(items[i]));
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (has_float) {
|
||||
PTA_float pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *item = items[i];
|
||||
if (PySequence_Check(item)) {
|
||||
PyObject *subitem = PySequence_ITEM(item, 0);
|
||||
pta.push_back(PyFloat_AsDouble(subitem));
|
||||
Py_DECREF(subitem);
|
||||
} else {
|
||||
pta.push_back(PyFloat_AsDouble(item));
|
||||
}
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
} else {
|
||||
PTA_int pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *item = items[i];
|
||||
if (PySequence_Check(item)) {
|
||||
PyObject *subitem = PySequence_ITEM(item, 0);
|
||||
pta.push_back((int)PyLongOrInt_AS_LONG(subitem));
|
||||
Py_DECREF(subitem);
|
||||
} else {
|
||||
pta.push_back((int)PyLongOrInt_AS_LONG(item));
|
||||
}
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (has_float) {
|
||||
PTA_LVecBase2f pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *item = items[i];
|
||||
if (PySequence_Check(item)) {
|
||||
PyObject *subitem0 = PySequence_ITEM(item, 0);
|
||||
PyObject *subitem1 = PySequence_ITEM(item, 1);
|
||||
pta.push_back(LVecBase2f(PyFloat_AsDouble(subitem0),
|
||||
PyFloat_AsDouble(subitem1)));
|
||||
Py_DECREF(subitem0);
|
||||
Py_DECREF(subitem1);
|
||||
} else {
|
||||
pta.push_back(PyFloat_AsDouble(item));
|
||||
}
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
} else {
|
||||
PTA_LVecBase2i pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *item = items[i];
|
||||
if (PySequence_Check(item)) {
|
||||
PyObject *subitem0 = PySequence_ITEM(item, 0);
|
||||
PyObject *subitem1 = PySequence_ITEM(item, 1);
|
||||
pta.push_back(LVecBase2i((int)PyLongOrInt_AS_LONG(subitem0),
|
||||
(int)PyLongOrInt_AS_LONG(subitem1)));
|
||||
Py_DECREF(subitem0);
|
||||
Py_DECREF(subitem1);
|
||||
} else {
|
||||
pta.push_back((int)PyLongOrInt_AS_LONG(item));
|
||||
}
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (has_float) {
|
||||
PTA_LVecBase3f pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *item = items[i];
|
||||
if (PySequence_Check(item)) {
|
||||
PyObject *subitem0 = PySequence_ITEM(item, 0);
|
||||
PyObject *subitem1 = PySequence_ITEM(item, 1);
|
||||
PyObject *subitem2 = PySequence_ITEM(item, 2);
|
||||
pta.push_back(LVecBase3f(PyFloat_AsDouble(subitem0),
|
||||
PyFloat_AsDouble(subitem1),
|
||||
PyFloat_AsDouble(subitem2)));
|
||||
Py_DECREF(subitem0);
|
||||
Py_DECREF(subitem1);
|
||||
Py_DECREF(subitem2);
|
||||
} else {
|
||||
pta.push_back(PyFloat_AsDouble(item));
|
||||
}
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
} else {
|
||||
PTA_LVecBase3i pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *item = items[i];
|
||||
if (PySequence_Check(item)) {
|
||||
PyObject *subitem0 = PySequence_ITEM(item, 0);
|
||||
PyObject *subitem1 = PySequence_ITEM(item, 1);
|
||||
PyObject *subitem2 = PySequence_ITEM(item, 2);
|
||||
pta.push_back(LVecBase3i((int)PyLongOrInt_AS_LONG(subitem0),
|
||||
(int)PyLongOrInt_AS_LONG(subitem1),
|
||||
(int)PyLongOrInt_AS_LONG(subitem2)));
|
||||
Py_DECREF(subitem0);
|
||||
Py_DECREF(subitem1);
|
||||
Py_DECREF(subitem2);
|
||||
} else {
|
||||
pta.push_back((int)PyLongOrInt_AS_LONG(item));
|
||||
}
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (has_float) {
|
||||
PTA_LVecBase4f pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *item = items[i];
|
||||
if (PySequence_Check(item)) {
|
||||
PyObject *subitem0 = PySequence_ITEM(item, 0);
|
||||
PyObject *subitem1 = PySequence_ITEM(item, 1);
|
||||
PyObject *subitem2 = PySequence_ITEM(item, 2);
|
||||
PyObject *subitem3 = PySequence_ITEM(item, 3);
|
||||
pta.push_back(LVecBase4f(PyFloat_AsDouble(subitem0),
|
||||
PyFloat_AsDouble(subitem1),
|
||||
PyFloat_AsDouble(subitem2),
|
||||
PyFloat_AsDouble(subitem3)));
|
||||
Py_DECREF(subitem0);
|
||||
Py_DECREF(subitem1);
|
||||
Py_DECREF(subitem2);
|
||||
Py_DECREF(subitem3);
|
||||
} else {
|
||||
pta.push_back(PyFloat_AsDouble(item));
|
||||
}
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
} else {
|
||||
PTA_LVecBase4i pta;
|
||||
pta.reserve(num_items);
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *item = items[i];
|
||||
if (PySequence_Check(item)) {
|
||||
PyObject *subitem0 = PySequence_ITEM(item, 0);
|
||||
PyObject *subitem1 = PySequence_ITEM(item, 1);
|
||||
PyObject *subitem2 = PySequence_ITEM(item, 2);
|
||||
PyObject *subitem3 = PySequence_ITEM(item, 3);
|
||||
pta.push_back(LVecBase4i((int)PyLongOrInt_AS_LONG(subitem0),
|
||||
(int)PyLongOrInt_AS_LONG(subitem1),
|
||||
(int)PyLongOrInt_AS_LONG(subitem2),
|
||||
(int)PyLongOrInt_AS_LONG(subitem3)));
|
||||
Py_DECREF(subitem0);
|
||||
Py_DECREF(subitem1);
|
||||
Py_DECREF(subitem2);
|
||||
Py_DECREF(subitem3);
|
||||
} else {
|
||||
pta.push_back((int)PyLongOrInt_AS_LONG(item));
|
||||
}
|
||||
}
|
||||
_this->_stored_ptr = pta;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
Dtool_Raise_TypeError("sequence passed to ShaderInput contains an empty sequence");
|
||||
break;
|
||||
|
||||
default:
|
||||
Dtool_Raise_TypeError("sequence passed to ShaderInput contains a sequence of more than 4 elements");
|
||||
break;
|
||||
}
|
||||
|
||||
_this->_type = ShaderInput::M_numeric;
|
||||
|
||||
Py_DECREF(fast);
|
||||
|
||||
} else {
|
||||
Dtool_Raise_TypeError("unknown type passed to ShaderInput");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* 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."
|
||||
*
|
||||
* @file shaderInput_ext.h
|
||||
* @author rdb
|
||||
* @date 2017-10-06
|
||||
*/
|
||||
|
||||
#ifndef SHADERINPUT_EXT_H
|
||||
#define SHADERINPUT_EXT_H
|
||||
|
||||
#include "dtoolbase.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "extension.h"
|
||||
#include "shaderInput.h"
|
||||
#include "py_panda.h"
|
||||
|
||||
/**
|
||||
* This class defines the extension methods for NodePath, which are called
|
||||
* instead of any C++ methods with the same prototype.
|
||||
*/
|
||||
template<>
|
||||
class Extension<ShaderInput> : public ExtensionBase<ShaderInput> {
|
||||
public:
|
||||
void __init__(CPT_InternalName name, PyObject *value, int priority=0);
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#endif // SHADERINPUT_EXT_H
|
||||
|
|
@ -16,6 +16,15 @@
|
|||
*/
|
||||
INLINE StateMunger::
|
||||
StateMunger(GraphicsStateGuardianBase *gsg) :
|
||||
GeomMunger(gsg)
|
||||
GeomMunger(gsg),
|
||||
_should_munge_state(false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this munger has something interesting to do to the state.
|
||||
*/
|
||||
INLINE bool StateMunger::
|
||||
should_munge_state() const {
|
||||
return _should_munge_state;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,15 +27,20 @@ StateMunger::
|
|||
*/
|
||||
CPT(RenderState) StateMunger::
|
||||
munge_state(const RenderState *state) {
|
||||
int mi = _state_map.find(state);
|
||||
RenderState::MungedStates &munged_states = state->_munged_states;
|
||||
|
||||
int id = get_gsg()->_id;
|
||||
int mi = munged_states.find(id);
|
||||
if (mi != -1) {
|
||||
if (!_state_map.get_data(mi).was_deleted()) {
|
||||
return _state_map.get_data(mi).p();
|
||||
if (!munged_states.get_data(mi).was_deleted()) {
|
||||
return munged_states.get_data(mi).p();
|
||||
} else {
|
||||
munged_states.remove_element(mi);
|
||||
}
|
||||
}
|
||||
|
||||
CPT(RenderState) result = munge_state_impl(state);
|
||||
_state_map.store(state, result.p());
|
||||
munged_states.store(id, result.p());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,11 +30,12 @@ public:
|
|||
virtual ~StateMunger();
|
||||
CPT(RenderState) munge_state(const RenderState *state);
|
||||
|
||||
INLINE bool should_munge_state() const;
|
||||
|
||||
protected:
|
||||
virtual CPT(RenderState) munge_state_impl(const RenderState *state);
|
||||
|
||||
typedef WeakKeyHashMap<RenderState, WCPT(RenderState) > StateMap;
|
||||
StateMap _state_map;
|
||||
bool _should_munge_state;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
|
|
|||
|
|
@ -64,12 +64,18 @@ PUBLISHED:
|
|||
|
||||
int find_on_stage(const TextureStage *stage) const;
|
||||
|
||||
MAKE_SEQ_PROPERTY(on_stages, get_num_on_stages, get_on_stage);
|
||||
MAKE_MAP_PROPERTY(on_stages, find_on_stage, get_on_stage);
|
||||
|
||||
INLINE int get_num_off_stages() const;
|
||||
INLINE TextureStage *get_off_stage(int n) const;
|
||||
MAKE_SEQ(get_off_stages, get_num_off_stages, get_off_stage);
|
||||
INLINE bool has_off_stage(TextureStage *stage) const;
|
||||
INLINE bool has_all_off() const;
|
||||
|
||||
MAKE_SEQ_PROPERTY(off_stages, get_num_off_stages, get_off_stage);
|
||||
MAKE_MAP_PROPERTY(off_stages, has_off_stage, get_off_stage);
|
||||
|
||||
INLINE bool is_identity() const;
|
||||
|
||||
CPT(RenderAttrib) add_on_stage(TextureStage *stage, Texture *tex, int override = 0) const;
|
||||
|
|
|
|||
|
|
@ -1512,7 +1512,7 @@ return_unique(TransformState *state) {
|
|||
// deleted while it's in it.
|
||||
state->cache_ref();
|
||||
}
|
||||
si = _states->store(state, Empty());
|
||||
si = _states->store(state, nullptr);
|
||||
|
||||
// Save the index and return the input state.
|
||||
state->_saved_entry = si;
|
||||
|
|
|
|||
|
|
@ -253,9 +253,7 @@ private:
|
|||
// cache, which is encoded in _composition_cache and
|
||||
// _invert_composition_cache.
|
||||
static LightReMutex *_states_lock;
|
||||
class Empty {
|
||||
};
|
||||
typedef SimpleHashMap<const TransformState *, Empty, indirect_equals_hash<const TransformState *> > States;
|
||||
typedef SimpleHashMap<const TransformState *, nullptr_t, indirect_equals_hash<const TransformState *> > States;
|
||||
static States *_states;
|
||||
static CPT(TransformState) _identity_state;
|
||||
static CPT(TransformState) _invalid_state;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,14 @@ TypeHandle ShaderGenerator::_type_handle;
|
|||
|
||||
#ifdef HAVE_CG
|
||||
|
||||
#define PACK_COMBINE(src0, op0, src1, op1, src2, op2) ( \
|
||||
((uint16_t)src0) | ((((uint16_t)op0 - 1u) & 3u) << 3u) | \
|
||||
((uint16_t)src1 << 5u) | ((((uint16_t)op1 - 1u) & 3u) << 8u) | \
|
||||
((uint16_t)src2 << 10u) | ((((uint16_t)op2 - 1u) & 3u) << 13u))
|
||||
|
||||
#define UNPACK_COMBINE_SRC(from, n) (TextureStage::CombineSource)((from >> ((uint16_t)n * 5u)) & 7u)
|
||||
#define UNPACK_COMBINE_OP(from, n) (TextureStage::CombineOperand)(((from >> (((uint16_t)n * 5u) + 3u)) & 3u) + 1u)
|
||||
|
||||
static PStatCollector lookup_collector("*:Munge:ShaderGen:Lookup");
|
||||
static PStatCollector synthesize_collector("*:Munge:ShaderGen:Synthesize");
|
||||
|
||||
|
|
@ -60,7 +68,7 @@ static PStatCollector synthesize_collector("*:Munge:ShaderGen:Synthesize");
|
|||
* shader generator belongs.
|
||||
*/
|
||||
ShaderGenerator::
|
||||
ShaderGenerator(GraphicsStateGuardianBase *gsg) {
|
||||
ShaderGenerator(const GraphicsStateGuardianBase *gsg) {
|
||||
// The ATTR# input semantics seem to map to generic vertex attributes in
|
||||
// both arbvp1 and glslv, which behave more consistently. However, they
|
||||
// don't exist in Direct3D 9. Use this silly little check for now.
|
||||
|
|
@ -298,10 +306,17 @@ analyze_renderstate(ShaderKey &key, const RenderState *rs) {
|
|||
Texture *tex = texture->get_on_texture(stage);
|
||||
nassertd(tex != nullptr) continue;
|
||||
|
||||
// Mark this TextureStage as having been used by the shader generator, so
|
||||
// that the next time its properties change, it will cause the state to be
|
||||
// rehashed to ensure that the shader is regenerated if needed.
|
||||
stage->mark_used_by_auto_shader();
|
||||
|
||||
ShaderKey::TextureInfo info;
|
||||
info._type = tex->get_texture_type();
|
||||
info._mode = stage->get_mode();
|
||||
info._flags = 0;
|
||||
info._combine_rgb = 0u;
|
||||
info._combine_alpha = 0u;
|
||||
|
||||
// While we look at the mode, determine whether we need to change the mode
|
||||
// in order to reflect disabled features.
|
||||
|
|
@ -357,6 +372,40 @@ analyze_renderstate(ShaderKey &key, const RenderState *rs) {
|
|||
info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_gloss;
|
||||
}
|
||||
break;
|
||||
|
||||
case TextureStage::M_combine:
|
||||
// If we have this rare, special mode, we encode all these extra
|
||||
// parameters as flags to prevent bloating the shader key.
|
||||
info._flags |= (uint32_t)stage->get_combine_rgb_mode() << ShaderKey::TF_COMBINE_RGB_MODE_SHIFT;
|
||||
info._flags |= (uint32_t)stage->get_combine_alpha_mode() << ShaderKey::TF_COMBINE_ALPHA_MODE_SHIFT;
|
||||
if (stage->get_rgb_scale() == 2) {
|
||||
info._flags |= ShaderKey::TF_rgb_scale_2;
|
||||
}
|
||||
if (stage->get_rgb_scale() == 4) {
|
||||
info._flags |= ShaderKey::TF_rgb_scale_4;
|
||||
}
|
||||
if (stage->get_alpha_scale() == 2) {
|
||||
info._flags |= ShaderKey::TF_alpha_scale_2;
|
||||
}
|
||||
if (stage->get_alpha_scale() == 4) {
|
||||
info._flags |= ShaderKey::TF_alpha_scale_4;
|
||||
}
|
||||
info._combine_rgb = PACK_COMBINE(
|
||||
stage->get_combine_rgb_source0(), stage->get_combine_rgb_operand0(),
|
||||
stage->get_combine_rgb_source1(), stage->get_combine_rgb_operand1(),
|
||||
stage->get_combine_rgb_source2(), stage->get_combine_rgb_operand2());
|
||||
info._combine_alpha = PACK_COMBINE(
|
||||
stage->get_combine_alpha_source0(), stage->get_combine_alpha_operand0(),
|
||||
stage->get_combine_alpha_source1(), stage->get_combine_alpha_operand1(),
|
||||
stage->get_combine_alpha_source2(), stage->get_combine_alpha_operand2());
|
||||
|
||||
if (stage->uses_primary_color()) {
|
||||
info._flags |= ShaderKey::TF_uses_primary_color;
|
||||
}
|
||||
if (stage->uses_last_saved_result()) {
|
||||
info._flags |= ShaderKey::TF_uses_last_saved_result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// In fact, perhaps this stage should be disabled altogether?
|
||||
|
|
@ -417,17 +466,31 @@ analyze_renderstate(ShaderKey &key, const RenderState *rs) {
|
|||
info._gen_mode = TexGenAttrib::M_off;
|
||||
}
|
||||
|
||||
// If we have this rare, special mode, just include a pointer to the
|
||||
// TextureStage object, because I can't be bothered to bloat the shader
|
||||
// key with all these extra relevant properties.
|
||||
if (stage->get_mode() == TextureStage::M_combine) {
|
||||
info._stage = stage;
|
||||
// Does this stage require saving its result?
|
||||
if (stage->get_saved_result()) {
|
||||
info._flags |= ShaderKey::TF_saved_result;
|
||||
}
|
||||
|
||||
// Does this stage need a texcolor_# input?
|
||||
if (stage->uses_color()) {
|
||||
info._flags |= ShaderKey::TF_uses_color;
|
||||
}
|
||||
|
||||
key._textures.push_back(info);
|
||||
key._texture_flags |= info._flags;
|
||||
}
|
||||
|
||||
// Does nothing use the saved result? If so, don't bother saving it.
|
||||
if ((key._texture_flags & ShaderKey::TF_uses_last_saved_result) == 0 &&
|
||||
(key._texture_flags & ShaderKey::TF_saved_result) != 0) {
|
||||
|
||||
pvector<ShaderKey::TextureInfo>::iterator it;
|
||||
for (it = key._textures.begin(); it != key._textures.end(); ++it) {
|
||||
(*it)._flags &= ~ShaderKey::TF_saved_result;
|
||||
}
|
||||
key._texture_flags &= ~ShaderKey::TF_saved_result;
|
||||
}
|
||||
|
||||
// Decide whether to separate ambient and diffuse calculations.
|
||||
if (have_ambient) {
|
||||
if (key._material_flags & Material::F_ambient) {
|
||||
|
|
@ -463,6 +526,74 @@ analyze_renderstate(ShaderKey &key, const RenderState *rs) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rehashes all the states with generated shaders, removing the ones that are
|
||||
* no longer fresh.
|
||||
*
|
||||
* Call this if certain state has changed in such a way as to require a rerun
|
||||
* of the shader generator. This should be rare because in most cases, the
|
||||
* shader generator will automatically regenerate shaders as necessary.
|
||||
*/
|
||||
void ShaderGenerator::
|
||||
rehash_generated_shaders() {
|
||||
LightReMutexHolder holder(*RenderState::_states_lock);
|
||||
|
||||
// With uniquify-states turned on, we can actually go through all the states
|
||||
// and check whether their generated shader is still OK.
|
||||
size_t size = RenderState::_states->get_num_entries();
|
||||
for (size_t si = 0; si < size; ++si) {
|
||||
const RenderState *state = RenderState::_states->get_key(si);
|
||||
|
||||
if (state->_generated_shader != nullptr) {
|
||||
ShaderKey key;
|
||||
analyze_renderstate(key, state);
|
||||
|
||||
GeneratedShaders::const_iterator si;
|
||||
si = _generated_shaders.find(key);
|
||||
if (si != _generated_shaders.end()) {
|
||||
if (si->second != state->_generated_shader) {
|
||||
state->_generated_shader = si->second;
|
||||
state->_munged_states.clear();
|
||||
}
|
||||
} else {
|
||||
// We have not yet generated a shader for this modified state.
|
||||
state->_generated_shader.clear();
|
||||
state->_munged_states.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have uniquify-states, however, the above list won't contain
|
||||
// all the state. We can change a global seq value to require Panda to
|
||||
// rehash the states the next time it tries to render an object with it.
|
||||
if (!uniquify_states) {
|
||||
GraphicsStateGuardianBase::mark_rehash_generated_shaders();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all previously generated shaders, requiring all shaders to be
|
||||
* regenerated. Does not clear cache of compiled shaders.
|
||||
*/
|
||||
void ShaderGenerator::
|
||||
clear_generated_shaders() {
|
||||
LightReMutexHolder holder(*RenderState::_states_lock);
|
||||
|
||||
size_t size = RenderState::_states->get_num_entries();
|
||||
for (size_t si = 0; si < size; ++si) {
|
||||
const RenderState *state = RenderState::_states->get_key(si);
|
||||
state->_generated_shader.clear();
|
||||
}
|
||||
|
||||
_generated_shaders.clear();
|
||||
|
||||
// If we don't have uniquify-states, we can't clear all the ShaderAttribs
|
||||
// that are cached on the states, but we can simulate the effect of that.
|
||||
if (!uniquify_states) {
|
||||
GraphicsStateGuardianBase::mark_rehash_generated_shaders();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the routine that implements the next-gen fixed function pipeline by
|
||||
* synthesizing a shader. It also takes care of setting up any buffers needed
|
||||
|
|
@ -827,7 +958,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
|
|||
text << "\t uniform float4x4 texmat_" << i << ",\n";
|
||||
}
|
||||
|
||||
if (tex._mode == TextureStage::M_blend) {
|
||||
if (tex._flags & ShaderKey::TF_uses_color) {
|
||||
text << "\t uniform float4 texcolor_" << i << ",\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -1251,24 +1382,12 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
|
|||
}
|
||||
}
|
||||
|
||||
// Loop first to see if something is using primary_color or
|
||||
// last_saved_result.
|
||||
bool have_saved_result = false;
|
||||
bool have_primary_color = false;
|
||||
for (size_t i = 0; i < key._textures.size(); ++i) {
|
||||
const ShaderKey::TextureInfo &tex = key._textures[i];
|
||||
if (tex._stage == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tex._stage->uses_primary_color() && !have_primary_color) {
|
||||
text << "\t float4 primary_color = result;\n";
|
||||
have_primary_color = true;
|
||||
}
|
||||
if (tex._stage->uses_last_saved_result() && !have_saved_result) {
|
||||
text << "\t float4 last_saved_result = result;\n";
|
||||
have_saved_result = true;
|
||||
}
|
||||
// Store these if any stages will use it.
|
||||
if (key._texture_flags & ShaderKey::TF_uses_primary_color) {
|
||||
text << "\t float4 primary_color = result;\n";
|
||||
}
|
||||
if (key._texture_flags & ShaderKey::TF_uses_last_saved_result) {
|
||||
text << "\t float4 last_saved_result = result;\n";
|
||||
}
|
||||
|
||||
// Now loop through the textures to compose our magic blending formulas.
|
||||
|
|
@ -1310,24 +1429,21 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
|
|||
}
|
||||
break;
|
||||
case TextureStage::M_combine:
|
||||
// Only in the case of M_combine have we filled in the _stage pointer.
|
||||
text << "\t result.rgb = ";
|
||||
if (tex._stage->get_combine_rgb_mode() != TextureStage::CM_undefined) {
|
||||
text << combine_mode_as_string(tex._stage, tex._stage->get_combine_rgb_mode(), false, i);
|
||||
} else {
|
||||
text << "tex" << i << ".rgb";
|
||||
text << combine_mode_as_string(tex, (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_RGB_MODE_MASK) >> ShaderKey::TF_COMBINE_RGB_MODE_SHIFT), false, i);
|
||||
if (tex._flags & ShaderKey::TF_rgb_scale_2) {
|
||||
text << " * 2";
|
||||
}
|
||||
if (tex._stage->get_rgb_scale() != 1) {
|
||||
text << " * " << tex._stage->get_rgb_scale();
|
||||
if (tex._flags & ShaderKey::TF_rgb_scale_4) {
|
||||
text << " * 4";
|
||||
}
|
||||
text << ";\n\t result.a = ";
|
||||
if (tex._stage->get_combine_alpha_mode() != TextureStage::CM_undefined) {
|
||||
text << combine_mode_as_string(tex._stage, tex._stage->get_combine_alpha_mode(), true, i);
|
||||
} else {
|
||||
text << "tex" << i << ".a";
|
||||
text << combine_mode_as_string(tex, (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_ALPHA_MODE_MASK) >> ShaderKey::TF_COMBINE_ALPHA_MODE_SHIFT), false, i);
|
||||
if (tex._flags & ShaderKey::TF_alpha_scale_2) {
|
||||
text << " * 2";
|
||||
}
|
||||
if (tex._stage->get_alpha_scale() != 1) {
|
||||
text << " * " << tex._stage->get_alpha_scale();
|
||||
if (tex._flags & ShaderKey::TF_alpha_scale_4) {
|
||||
text << " * 4";
|
||||
}
|
||||
text << ";\n";
|
||||
break;
|
||||
|
|
@ -1337,7 +1453,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if ((tex._flags & ShaderKey::TF_saved_result) != 0 && have_saved_result) {
|
||||
if (tex._flags & ShaderKey::TF_saved_result) {
|
||||
text << "\t last_saved_result = result;\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -1464,53 +1580,53 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
|
|||
* This 'synthesizes' a combine mode into a string.
|
||||
*/
|
||||
const string ShaderGenerator::
|
||||
combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode, bool alpha, short texindex) {
|
||||
combine_mode_as_string(const ShaderKey::TextureInfo &info, TextureStage::CombineMode c_mode, bool alpha, short texindex) {
|
||||
ostringstream text;
|
||||
switch (c_mode) {
|
||||
case TextureStage::CM_modulate:
|
||||
text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
|
||||
text << " * ";
|
||||
text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
|
||||
break;
|
||||
case TextureStage::CM_add:
|
||||
text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
|
||||
text << " + ";
|
||||
text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
|
||||
break;
|
||||
case TextureStage::CM_add_signed:
|
||||
text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
|
||||
text << " + ";
|
||||
text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
|
||||
if (alpha) {
|
||||
text << " - 0.5";
|
||||
} else {
|
||||
text << " - float3(0.5, 0.5, 0.5)";
|
||||
}
|
||||
break;
|
||||
case TextureStage::CM_interpolate:
|
||||
text << "lerp(";
|
||||
text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
|
||||
text << ", ";
|
||||
text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
|
||||
text << ", ";
|
||||
text << combine_source_as_string(stage, 2, alpha, true, texindex);
|
||||
text << ")";
|
||||
break;
|
||||
case TextureStage::CM_subtract:
|
||||
text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
|
||||
text << " + ";
|
||||
text << combine_source_as_string(stage, 1, alpha, alpha, texindex);
|
||||
break;
|
||||
case TextureStage::CM_dot3_rgb:
|
||||
pgraphnodes_cat.error() << "TextureStage::CombineMode DOT3_RGB not yet supported in per-pixel mode.\n";
|
||||
break;
|
||||
case TextureStage::CM_dot3_rgba:
|
||||
pgraphnodes_cat.error() << "TextureStage::CombineMode DOT3_RGBA not yet supported in per-pixel mode.\n";
|
||||
break;
|
||||
case TextureStage::CM_replace:
|
||||
default: // Not sure if this is correct as default value.
|
||||
text << combine_source_as_string(stage, 0, alpha, alpha, texindex);
|
||||
break;
|
||||
case TextureStage::CM_modulate:
|
||||
text << combine_source_as_string(info, 0, alpha, alpha, texindex);
|
||||
text << " * ";
|
||||
text << combine_source_as_string(info, 1, alpha, alpha, texindex);
|
||||
break;
|
||||
case TextureStage::CM_add:
|
||||
text << combine_source_as_string(info, 0, alpha, alpha, texindex);
|
||||
text << " + ";
|
||||
text << combine_source_as_string(info, 1, alpha, alpha, texindex);
|
||||
break;
|
||||
case TextureStage::CM_add_signed:
|
||||
text << combine_source_as_string(info, 0, alpha, alpha, texindex);
|
||||
text << " + ";
|
||||
text << combine_source_as_string(info, 1, alpha, alpha, texindex);
|
||||
if (alpha) {
|
||||
text << " - 0.5";
|
||||
} else {
|
||||
text << " - float3(0.5, 0.5, 0.5)";
|
||||
}
|
||||
break;
|
||||
case TextureStage::CM_interpolate:
|
||||
text << "lerp(";
|
||||
text << combine_source_as_string(info, 1, alpha, alpha, texindex);
|
||||
text << ", ";
|
||||
text << combine_source_as_string(info, 0, alpha, alpha, texindex);
|
||||
text << ", ";
|
||||
text << combine_source_as_string(info, 2, alpha, true, texindex);
|
||||
text << ")";
|
||||
break;
|
||||
case TextureStage::CM_subtract:
|
||||
text << combine_source_as_string(info, 0, alpha, alpha, texindex);
|
||||
text << " + ";
|
||||
text << combine_source_as_string(info, 1, alpha, alpha, texindex);
|
||||
break;
|
||||
case TextureStage::CM_dot3_rgb:
|
||||
pgraphnodes_cat.error() << "TextureStage::CombineMode DOT3_RGB not yet supported in per-pixel mode.\n";
|
||||
break;
|
||||
case TextureStage::CM_dot3_rgba:
|
||||
pgraphnodes_cat.error() << "TextureStage::CombineMode DOT3_RGBA not yet supported in per-pixel mode.\n";
|
||||
break;
|
||||
case TextureStage::CM_replace:
|
||||
default: // Not sure if this is correct as default value.
|
||||
text << combine_source_as_string(info, 0, alpha, alpha, texindex);
|
||||
break;
|
||||
}
|
||||
return text.str();
|
||||
}
|
||||
|
|
@ -1519,39 +1635,15 @@ combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode
|
|||
* This 'synthesizes' a combine source into a string.
|
||||
*/
|
||||
const string ShaderGenerator::
|
||||
combine_source_as_string(CPT(TextureStage) stage, short num, bool alpha, bool single_value, short texindex) {
|
||||
TextureStage::CombineSource c_src = TextureStage::CS_undefined;
|
||||
TextureStage::CombineOperand c_op = TextureStage::CO_undefined;
|
||||
if (alpha) {
|
||||
switch (num) {
|
||||
case 0:
|
||||
c_src = stage->get_combine_alpha_source0();
|
||||
c_op = stage->get_combine_alpha_operand0();
|
||||
break;
|
||||
case 1:
|
||||
c_src = stage->get_combine_alpha_source1();
|
||||
c_op = stage->get_combine_alpha_operand1();
|
||||
break;
|
||||
case 2:
|
||||
c_src = stage->get_combine_alpha_source2();
|
||||
c_op = stage->get_combine_alpha_operand2();
|
||||
break;
|
||||
}
|
||||
combine_source_as_string(const ShaderKey::TextureInfo &info, short num, bool alpha, bool single_value, short texindex) {
|
||||
TextureStage::CombineSource c_src;
|
||||
TextureStage::CombineOperand c_op;
|
||||
if (!alpha) {
|
||||
c_src = UNPACK_COMBINE_SRC(info._combine_rgb, num);
|
||||
c_op = UNPACK_COMBINE_OP(info._combine_rgb, num);
|
||||
} else {
|
||||
switch (num) {
|
||||
case 0:
|
||||
c_src = stage->get_combine_rgb_source0();
|
||||
c_op = stage->get_combine_rgb_operand0();
|
||||
break;
|
||||
case 1:
|
||||
c_src = stage->get_combine_rgb_source1();
|
||||
c_op = stage->get_combine_rgb_operand1();
|
||||
break;
|
||||
case 2:
|
||||
c_src = stage->get_combine_rgb_source2();
|
||||
c_op = stage->get_combine_rgb_operand2();
|
||||
break;
|
||||
}
|
||||
c_src = UNPACK_COMBINE_SRC(info._combine_alpha, num);
|
||||
c_op = UNPACK_COMBINE_OP(info._combine_alpha, num);
|
||||
}
|
||||
ostringstream csource;
|
||||
if (c_op == TextureStage::CO_one_minus_src_color ||
|
||||
|
|
@ -1562,10 +1654,9 @@ combine_source_as_string(CPT(TextureStage) stage, short num, bool alpha, bool si
|
|||
case TextureStage::CS_texture:
|
||||
csource << "tex" << texindex;
|
||||
break;
|
||||
case TextureStage::CS_constant: {
|
||||
LVecBase4 c = stage->get_color();
|
||||
csource << "float4(" << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << ")";
|
||||
break; }
|
||||
case TextureStage::CS_constant:
|
||||
csource << "texcolor_" << texindex;
|
||||
break;
|
||||
case TextureStage::CS_primary_color:
|
||||
csource << "primary_color";
|
||||
break;
|
||||
|
|
@ -1684,8 +1775,11 @@ operator < (const ShaderKey &other) const {
|
|||
if (tex._flags != other_tex._flags) {
|
||||
return tex._flags < other_tex._flags;
|
||||
}
|
||||
if (tex._stage != other_tex._stage) {
|
||||
return tex._stage < other_tex._stage;
|
||||
if (tex._combine_rgb != other_tex._combine_rgb) {
|
||||
return tex._combine_rgb < other_tex._combine_rgb;
|
||||
}
|
||||
if (tex._combine_alpha != other_tex._combine_alpha) {
|
||||
return tex._combine_alpha < other_tex._combine_alpha;
|
||||
}
|
||||
}
|
||||
if (_lights.size() != other._lights.size()) {
|
||||
|
|
@ -1759,7 +1853,8 @@ operator == (const ShaderKey &other) const {
|
|||
tex._mode != other_tex._mode ||
|
||||
tex._gen_mode != other_tex._gen_mode ||
|
||||
tex._flags != other_tex._flags ||
|
||||
tex._stage != other_tex._stage) {
|
||||
tex._combine_rgb != other_tex._combine_rgb ||
|
||||
tex._combine_alpha != other_tex._combine_alpha) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,18 +65,15 @@ class GeomVertexAnimationSpec;
|
|||
*/
|
||||
class EXPCL_PANDA_PGRAPHNODES ShaderGenerator : public TypedReferenceCount {
|
||||
PUBLISHED:
|
||||
ShaderGenerator(GraphicsStateGuardianBase *gsg);
|
||||
ShaderGenerator(const GraphicsStateGuardianBase *gsg);
|
||||
virtual ~ShaderGenerator();
|
||||
virtual CPT(ShaderAttrib) synthesize_shader(const RenderState *rs,
|
||||
const GeomVertexAnimationSpec &anim);
|
||||
|
||||
protected:
|
||||
static const string combine_mode_as_string(CPT(TextureStage) stage,
|
||||
TextureStage::CombineMode c_mode, bool alpha, short texindex);
|
||||
static const string combine_source_as_string(CPT(TextureStage) stage,
|
||||
short num, bool alpha, bool single_value, short texindex);
|
||||
static const string texture_type_as_string(Texture::TextureType ttype);
|
||||
void rehash_generated_shaders();
|
||||
void clear_generated_shaders();
|
||||
|
||||
protected:
|
||||
// Shader register allocation:
|
||||
|
||||
bool _use_generic_attr;
|
||||
|
|
@ -101,15 +98,28 @@ protected:
|
|||
|
||||
GeomVertexAnimationSpec _anim_spec;
|
||||
enum TextureFlags {
|
||||
TF_has_rgb = 1,
|
||||
TF_has_alpha = 2,
|
||||
TF_has_texscale = 4,
|
||||
TF_has_texmat = 8,
|
||||
TF_saved_result = 16,
|
||||
TF_map_normal = 32,
|
||||
TF_map_height = 64,
|
||||
TF_map_glow = 128,
|
||||
TF_map_gloss = 256,
|
||||
TF_has_rgb = 0x001,
|
||||
TF_has_alpha = 0x002,
|
||||
TF_has_texscale = 0x004,
|
||||
TF_has_texmat = 0x008,
|
||||
TF_saved_result = 0x010,
|
||||
TF_map_normal = 0x020,
|
||||
TF_map_height = 0x040,
|
||||
TF_map_glow = 0x080,
|
||||
TF_map_gloss = 0x100,
|
||||
TF_uses_color = 0x200,
|
||||
TF_uses_primary_color = 0x400,
|
||||
TF_uses_last_saved_result = 0x800,
|
||||
|
||||
TF_rgb_scale_2 = 0x1000,
|
||||
TF_rgb_scale_4 = 0x2000,
|
||||
TF_alpha_scale_2 = 0x4000,
|
||||
TF_alpha_scale_4 = 0x8000,
|
||||
|
||||
TF_COMBINE_RGB_MODE_SHIFT = 16,
|
||||
TF_COMBINE_RGB_MODE_MASK = 0x0000f0000,
|
||||
TF_COMBINE_ALPHA_MODE_SHIFT = 20,
|
||||
TF_COMBINE_ALPHA_MODE_MASK = 0x000f00000,
|
||||
};
|
||||
|
||||
ColorAttrib::Type _color_type;
|
||||
|
|
@ -122,9 +132,8 @@ protected:
|
|||
TextureStage::Mode _mode;
|
||||
TexGenAttrib::Mode _gen_mode;
|
||||
int _flags;
|
||||
|
||||
// Stored only if combine modes / blend color is used
|
||||
CPT(TextureStage) _stage;
|
||||
uint16_t _combine_rgb;
|
||||
uint16_t _combine_alpha;
|
||||
};
|
||||
pvector<TextureInfo> _textures;
|
||||
|
||||
|
|
@ -159,6 +168,12 @@ protected:
|
|||
|
||||
void analyze_renderstate(ShaderKey &key, const RenderState *rs);
|
||||
|
||||
static const string combine_mode_as_string(const ShaderKey::TextureInfo &info,
|
||||
TextureStage::CombineMode c_mode, bool alpha, short texindex);
|
||||
static const string combine_source_as_string(const ShaderKey::TextureInfo &info,
|
||||
short num, bool alpha, bool single_value, short texindex);
|
||||
static const string texture_type_as_string(Texture::TextureType ttype);
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ store(const Key &key, const Value &data) {
|
|||
}
|
||||
if (is_element(index, key)) {
|
||||
// This element is already in the map; replace the data at that key.
|
||||
_table[index]._data = data;
|
||||
set_data(index, data);
|
||||
#ifdef _DEBUG
|
||||
nassertr(validate(), index);
|
||||
#endif
|
||||
|
|
@ -151,7 +151,7 @@ store(const Key &key, const Value &data) {
|
|||
return index;
|
||||
}
|
||||
if (is_element(index, key)) {
|
||||
_table[index]._data = data;
|
||||
set_data(index, data);
|
||||
#ifdef _DEBUG
|
||||
nassertr(validate(), index);
|
||||
#endif
|
||||
|
|
@ -200,8 +200,7 @@ remove(const Key &key) {
|
|||
|
||||
// Swap it with the last one, so that we don't get any gaps in the table
|
||||
// of entries.
|
||||
_table[index]._key = move(_table[last]._key);
|
||||
_table[index]._data = move(_table[last]._data);
|
||||
_table[index] = move(_table[last]);
|
||||
index_array[(size_t)other_slot] = index;
|
||||
}
|
||||
|
||||
|
|
@ -311,8 +310,8 @@ get_key(size_t n) const {
|
|||
template<class Key, class Value, class Compare>
|
||||
INLINE const Value &SimpleHashMap<Key, Value, Compare>::
|
||||
get_data(size_t n) const {
|
||||
nassertr(n < _num_entries, _table[n]._data);
|
||||
return _table[n]._data;
|
||||
nassertr(n < _num_entries, _table[n].get_data());
|
||||
return _table[n].get_data();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -323,8 +322,8 @@ get_data(size_t n) const {
|
|||
template<class Key, class Value, class Compare>
|
||||
INLINE Value &SimpleHashMap<Key, Value, Compare>::
|
||||
modify_data(size_t n) {
|
||||
nassertr(n < _num_entries, _table[n]._data);
|
||||
return _table[n]._data;
|
||||
nassertr(n < _num_entries, _table[n].modify_data());
|
||||
return _table[n].modify_data();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -336,7 +335,19 @@ template<class Key, class Value, class Compare>
|
|||
INLINE void SimpleHashMap<Key, Value, Compare>::
|
||||
set_data(size_t n, const Value &data) {
|
||||
nassertv(n < _num_entries);
|
||||
_table[n]._data = data;
|
||||
_table[n].set_data(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the data for the nth entry of the table.
|
||||
*
|
||||
* @param n should be in the range 0 <= n < size().
|
||||
*/
|
||||
template<class Key, class Value, class Compare>
|
||||
INLINE void SimpleHashMap<Key, Value, Compare>::
|
||||
set_data(size_t n, Value &&data) {
|
||||
nassertv(n < _num_entries);
|
||||
_table[n].set_data(move(data));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,6 +18,52 @@
|
|||
#include "pvector.h"
|
||||
#include "config_util.h"
|
||||
|
||||
/**
|
||||
* Entry in the SimpleHashMap.
|
||||
*/
|
||||
template<class Key, class Value>
|
||||
class SimpleKeyValuePair {
|
||||
public:
|
||||
INLINE SimpleKeyValuePair(const Key &key, const Value &data) :
|
||||
_key(key),
|
||||
_data(data) {}
|
||||
|
||||
Key _key;
|
||||
|
||||
ALWAYS_INLINE const Value &get_data() const {
|
||||
return _data;
|
||||
}
|
||||
ALWAYS_INLINE Value &modify_data() {
|
||||
return _data;
|
||||
}
|
||||
ALWAYS_INLINE void set_data(const Value &data) {
|
||||
_data = data;
|
||||
}
|
||||
ALWAYS_INLINE void set_data(Value &&data) {
|
||||
_data = move(data);
|
||||
}
|
||||
|
||||
private:
|
||||
Value _data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialisation of SimpleKeyValuePair to not waste memory for nullptr_t
|
||||
* values. This allows effectively using SimpleHashMap as a set.
|
||||
*/
|
||||
template<class Key>
|
||||
class SimpleKeyValuePair<Key, nullptr_t> {
|
||||
public:
|
||||
INLINE SimpleKeyValuePair(const Key &key, nullptr_t data) :
|
||||
_key(key) {}
|
||||
|
||||
Key _key;
|
||||
|
||||
ALWAYS_INLINE_CONSTEXPR static nullptr_t get_data() { return nullptr; }
|
||||
ALWAYS_INLINE_CONSTEXPR static nullptr_t modify_data() { return nullptr; }
|
||||
ALWAYS_INLINE static void set_data(nullptr_t) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* This template class implements an unordered map of keys to data,
|
||||
* implemented as a hashtable. It is similar to STL's hash_map, but
|
||||
|
|
@ -28,6 +74,8 @@
|
|||
* (d) it allows for efficient iteration over the entries,
|
||||
* (e) permits removal and resizing during forward iteration, and
|
||||
* (f) it has a constexpr constructor.
|
||||
*
|
||||
* It can also be used as a set, by using nullptr_t as Value typename.
|
||||
*/
|
||||
template<class Key, class Value, class Compare = method_hash<Key, less<Key> > >
|
||||
class SimpleHashMap {
|
||||
|
|
@ -55,6 +103,7 @@ public:
|
|||
INLINE const Value &get_data(size_t n) const;
|
||||
INLINE Value &modify_data(size_t n);
|
||||
INLINE void set_data(size_t n, const Value &data);
|
||||
INLINE void set_data(size_t n, Value &&data);
|
||||
void remove_element(size_t n);
|
||||
|
||||
INLINE size_t get_num_entries() const;
|
||||
|
|
@ -67,8 +116,6 @@ public:
|
|||
INLINE bool consider_shrink_table();
|
||||
|
||||
private:
|
||||
class TableEntry;
|
||||
|
||||
INLINE size_t get_hash(const Key &key) const;
|
||||
INLINE size_t next_hash(size_t hash) const;
|
||||
|
||||
|
|
@ -82,23 +129,8 @@ private:
|
|||
INLINE bool consider_expand_table();
|
||||
void resize_table(size_t new_size);
|
||||
|
||||
class TableEntry {
|
||||
public:
|
||||
INLINE TableEntry(const Key &key, const Value &data) :
|
||||
_key(key),
|
||||
_data(data) {}
|
||||
INLINE TableEntry(const TableEntry ©) :
|
||||
_key(copy._key),
|
||||
_data(copy._data) {}
|
||||
#ifdef USE_MOVE_SEMANTICS
|
||||
INLINE TableEntry(TableEntry &&from) NOEXCEPT :
|
||||
_key(move(from._key)),
|
||||
_data(move(from._data)) {}
|
||||
#endif
|
||||
Key _key;
|
||||
Value _data;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef SimpleKeyValuePair<Key, Value> TableEntry;
|
||||
TableEntry *_table;
|
||||
DeletedBufferChain *_deleted_chain;
|
||||
size_t _table_size;
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ handle_args(ProgramBase::Args &args) {
|
|||
file_path.append_directory(filename.get_dirname());
|
||||
|
||||
if (_force_complete) {
|
||||
if (!file_data.load_externals()) {
|
||||
if (!file_data.load_externals(file_path)) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ class FireflyDemo(ShowBase):
|
|||
color_g = random.uniform(0.8, 1.0)
|
||||
color_b = min(color_g, random.uniform(0.5, 1.0))
|
||||
fly.setColor(color_r, color_g, color_b, 1.0)
|
||||
fly.setShaderInput("lightcolor", color_r, color_g, color_b, 1.0)
|
||||
fly.setShaderInput("lightcolor", (color_r, color_g, color_b, 1.0))
|
||||
int1 = fly.posInterval(random.uniform(7, 12), pos1, pos2)
|
||||
int2 = fly.posInterval(random.uniform(7, 12), pos2, pos1)
|
||||
si1 = fly.scaleInterval(random.uniform(0.8, 1.5),
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class World(DirectObject):
|
|||
self.pandaModel = Actor.Actor('panda-model', {'walk': 'panda-walk4'})
|
||||
self.pandaModel.reparentTo(self.pandaAxis)
|
||||
self.pandaModel.setPos(9, 0, 0)
|
||||
self.pandaModel.setShaderInput("scale", 0.01, 0.01, 0.01, 1.0)
|
||||
self.pandaModel.setShaderInput("scale", (0.01, 0.01, 0.01, 1.0))
|
||||
self.pandaWalk = self.pandaModel.actorInterval('walk', playRate=1.8)
|
||||
self.pandaWalk.loop()
|
||||
self.pandaMovement = self.pandaAxis.hprInterval(
|
||||
|
|
@ -113,7 +113,7 @@ class World(DirectObject):
|
|||
self.teapot = loader.loadModel('teapot')
|
||||
self.teapot.reparentTo(render)
|
||||
self.teapot.setPos(0, -20, 10)
|
||||
self.teapot.setShaderInput("texDisable", 1, 1, 1, 1)
|
||||
self.teapot.setShaderInput("texDisable", (1, 1, 1, 1))
|
||||
self.teapotMovement = self.teapot.hprInterval(50, LPoint3(0, 360, 360))
|
||||
self.teapotMovement.loop()
|
||||
|
||||
|
|
@ -145,9 +145,9 @@ class World(DirectObject):
|
|||
# setting up shader
|
||||
render.setShaderInput('light', self.LCam)
|
||||
render.setShaderInput('Ldepthmap', Ldepthmap)
|
||||
render.setShaderInput('ambient', self.ambient, 0, 0, 1.0)
|
||||
render.setShaderInput('texDisable', 0, 0, 0, 0)
|
||||
render.setShaderInput('scale', 1, 1, 1, 1)
|
||||
render.setShaderInput('ambient', (self.ambient, 0, 0, 1.0))
|
||||
render.setShaderInput('texDisable', (0, 0, 0, 0))
|
||||
render.setShaderInput('scale', (1, 1, 1, 1))
|
||||
|
||||
# Put a shader on the Light camera.
|
||||
lci = NodePath(PandaNode("Light Camera Initializer"))
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ class World(DirectObject):
|
|||
self.teapot = loader.loadModel('teapot')
|
||||
self.teapot.reparentTo(render)
|
||||
self.teapot.setPos(0, -20, 10)
|
||||
self.teapot.setShaderInput("texDisable", 1, 1, 1, 1)
|
||||
self.teapotMovement = self.teapot.hprInterval(50, LPoint3(0, 360, 360))
|
||||
self.teapotMovement.loop()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue