diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2018-03-05 14:16:53 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2018-03-05 14:16:53 +0300 |
commit | c63e9a32e859f7225ea4c964f407047d7a843763 (patch) | |
tree | 76127898701f1349c8b02ea44d49ba04fc3941ee /source | |
parent | d1596dc1709701e731fd4943918d2990c7efbee2 (diff) | |
parent | caa0b0fadf928b4f34be8ce761ac342b72450bcb (diff) |
Merge branch 'master' into soc-2017-normal-tools
Diffstat (limited to 'source')
12 files changed, 238 insertions, 70 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 26aecb526d4..15469e3ae4b 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -3910,17 +3910,25 @@ void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs) { int i; if (attribs->totorco) { - glUniform1i(attribs->orco.gl_info_index, 0); + if (attribs->orco.gl_info_index != -1) { + glUniform1i(attribs->orco.gl_info_index, 0); + } } for (i = 0; i < attribs->tottface; i++) { - glUniform1i(attribs->tface[i].gl_info_index, 0); + if (attribs->tface[i].gl_info_index != -1) { + glUniform1i(attribs->tface[i].gl_info_index, 0); + } } for (i = 0; i < attribs->totmcol; i++) { - glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB); + if (attribs->mcol[i].gl_info_index != -1) { + glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB); + } } for (i = 0; i < attribs->tottang; i++) { - glUniform1i(attribs->tang[i].gl_info_index, 0); + if (attribs->tang[i].gl_info_index != -1) { + glUniform1i(attribs->tang[i].gl_info_index, 0); + } } } diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.cpp b/source/blender/compositor/operations/COM_MapRangeOperation.cpp index 7a89ba91b4c..7a38d066122 100644 --- a/source/blender/compositor/operations/COM_MapRangeOperation.cpp +++ b/source/blender/compositor/operations/COM_MapRangeOperation.cpp @@ -65,6 +65,11 @@ void MapRangeOperation::executePixelSampled(float output[4], float x, float y, P dest_min = inputs[3]; dest_max = inputs[4]; + if (fabsf(source_max - source_min) < 1e-6f) { + output[0] = 0.0f; + return; + } + if (value >= -BLENDER_ZMAX && value <= BLENDER_ZMAX) { value = (value - source_min) / (source_max - source_min); value = dest_min + value * (dest_max - dest_min); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index c9fa35bd551..026aa309b02 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -46,6 +46,8 @@ namespace DEG { +namespace { + typedef enum eCyclicCheckVisitedState { /* Not is not visited at all during traversal. */ NODE_NOT_VISITED = 0, @@ -55,6 +57,30 @@ typedef enum eCyclicCheckVisitedState { NODE_IN_STACK = 2, } eCyclicCheckVisitedState; +struct StackEntry { + OperationDepsNode *node; + StackEntry *from; + DepsRelation *via_relation; +}; + +struct CyclesSolverState { + CyclesSolverState(Depsgraph *graph) + : graph(graph), + traversal_stack(BLI_stack_new(sizeof(StackEntry), + "DEG detect cycles stack")), + num_cycles(0) { + } + ~CyclesSolverState() { + BLI_stack_free(traversal_stack); + if (num_cycles != 0) { + printf("Detected %d dependency cycles\n", num_cycles); + } + } + Depsgraph *graph; + BLI_Stack *traversal_stack; + int num_cycles; +}; + BLI_INLINE void set_node_visited_state(DepsNode *node, eCyclicCheckVisitedState state) { @@ -76,19 +102,20 @@ BLI_INLINE int get_node_num_visited_children(DepsNode *node) return node->done >> 2; } -void deg_graph_detect_cycles(Depsgraph *graph) +void schedule_node_to_stack(CyclesSolverState *state, OperationDepsNode *node) { - struct StackEntry { - OperationDepsNode *node; - StackEntry *from; - DepsRelation *via_relation; - }; - - BLI_Stack *traversal_stack = BLI_stack_new(sizeof(StackEntry), - "DEG detect cycles stack"); + StackEntry entry; + entry.node = node; + entry.from = NULL; + entry.via_relation = NULL; + BLI_stack_push(state->traversal_stack, &entry); + set_node_visited_state(node, NODE_IN_STACK); +} - int num_cycles = 0; - foreach (OperationDepsNode *node, graph->operations) { +/* Schedule leaf nodes (node without input links) for traversal. */ +void schedule_leaf_nodes(CyclesSolverState *state) +{ + foreach (OperationDepsNode *node, state->graph->operations) { bool has_inlinks = false; foreach (DepsRelation *rel, node->inlinks) { if (rel->from->type == DEG_NODE_TYPE_OPERATION) { @@ -97,18 +124,32 @@ void deg_graph_detect_cycles(Depsgraph *graph) } node->done = 0; if (has_inlinks == false) { - StackEntry entry; - entry.node = node; - entry.from = NULL; - entry.via_relation = NULL; - BLI_stack_push(traversal_stack, &entry); - set_node_visited_state(node, NODE_IN_STACK); + schedule_node_to_stack(state, node); } else { set_node_visited_state(node, NODE_NOT_VISITED); } } +} + +/* Schedule node which was not checked yet for being belong to + * any of dependency cycle. + */ +bool schedule_non_checked_node(CyclesSolverState *state) +{ + foreach (OperationDepsNode *node, state->graph->operations) { + if (get_node_visited_state(node) == NODE_NOT_VISITED) { + schedule_node_to_stack(state, node); + return true; + } + } + return false; +} +/* Solve cycles with all nodes which are scheduled for traversal. */ +void solve_cycles(CyclesSolverState *state) +{ + BLI_Stack *traversal_stack = state->traversal_stack; while (!BLI_stack_is_empty(traversal_stack)) { StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack); OperationDepsNode *node = entry->node; @@ -137,7 +178,7 @@ void deg_graph_detect_cycles(Depsgraph *graph) } /* TODO(sergey): So called russian roulette cycle solver. */ rel->flag |= DEPSREL_FLAG_CYCLIC; - ++num_cycles; + ++state->num_cycles; } else if (to_state == NODE_NOT_VISITED) { StackEntry new_entry; @@ -157,11 +198,23 @@ void deg_graph_detect_cycles(Depsgraph *graph) BLI_stack_discard(traversal_stack); } } +} - BLI_stack_free(traversal_stack); +} // namespace - if (num_cycles != 0) { - printf("Detected %d dependency cycles\n", num_cycles); +void deg_graph_detect_cycles(Depsgraph *graph) +{ + CyclesSolverState state(graph); + /* First we solve cycles which are reachable from leaf nodes. */ + schedule_leaf_nodes(&state); + solve_cycles(&state); + /* We are not done yet. It is possible to have closed loop cycle, + * for example A -> B -> C -> A. These nodes were not scheduled + * yet (since they all have inlinks), and were not traversed since + * nobody else points to them. + */ + while (schedule_non_checked_node(&state)) { + solve_cycles(&state); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 7572ee90c0b..0f21c152192 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -239,6 +239,22 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( name_tag); } +OperationDepsNode *DepsgraphNodeBuilder::ensure_operation_node( + ID *id, + eDepsNode_Type comp_type, + const DepsEvalOperationCb& op, + eDepsOperation_Code opcode, + const char *name, + int name_tag) +{ + OperationDepsNode *operation = + find_operation_node(id, comp_type, opcode, name, name_tag); + if (operation != NULL) { + return operation; + } + return add_operation_node(id, comp_type, op, opcode, name, name_tag); +} + bool DepsgraphNodeBuilder::has_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, @@ -516,30 +532,54 @@ void DepsgraphNodeBuilder::build_animdata(ID *id) * \param id: ID-Block that driver is attached to * \param fcu: Driver-FCurve */ -OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu) +void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve) { /* Create data node for this driver */ - /* TODO(sergey): Avoid creating same operation multiple times, - * in the future we need to avoid lookup of the operation as well - * and use some tagging magic instead. - */ - OperationDepsNode *driver_op = find_operation_node(id, - DEG_NODE_TYPE_PARAMETERS, - DEG_OPCODE_DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - - if (driver_op == NULL) { - driver_op = add_operation_node(id, - DEG_NODE_TYPE_PARAMETERS, - function_bind(BKE_animsys_eval_driver, _1, id, fcu), - DEG_OPCODE_DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); + ensure_operation_node(id, + DEG_NODE_TYPE_PARAMETERS, + function_bind(BKE_animsys_eval_driver, _1, id, fcurve), + DEG_OPCODE_DRIVER, + fcurve->rna_path ? fcurve->rna_path : "", + fcurve->array_index); + build_driver_variables(id, fcurve); +} + +void DepsgraphNodeBuilder::build_driver_variables(ID * id, FCurve *fcurve) +{ + build_driver_id_property(id, fcurve->rna_path); + LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) { + DRIVER_TARGETS_USED_LOOPER(dvar) + { + build_driver_id_property(dtar->id, dtar->rna_path); + } + DRIVER_TARGETS_LOOPER_END } +} - /* return driver node created */ - return driver_op; +void DepsgraphNodeBuilder::build_driver_id_property(ID *id, + const char *rna_path) +{ + if (id == NULL || rna_path == NULL) { + return; + } + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + RNA_id_pointer_create(id, &id_ptr); + if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) { + return; + } + if (prop == NULL) { + return; + } + if (!RNA_property_is_idprop(prop)) { + return; + } + const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); + ensure_operation_node(id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_ID_PROPERTY, + prop_identifier); } /* Recursively build graph for world */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 825015194e2..9d47dc6bced 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -99,6 +99,13 @@ struct DepsgraphNodeBuilder { const char *name = "", int name_tag = -1); + OperationDepsNode *ensure_operation_node(ID *id, + eDepsNode_Type comp_type, + const DepsEvalOperationCb& op, + eDepsOperation_Code opcode, + const char *name = "", + int name_tag = -1); + bool has_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, @@ -130,7 +137,9 @@ struct DepsgraphNodeBuilder { void build_particles(Object *object); void build_cloth(Object *object); void build_animdata(ID *id); - OperationDepsNode *build_driver(ID *id, FCurve *fcurve); + void build_driver(ID *id, FCurve *fcurve); + void build_driver_variables(ID *id, FCurve *fcurve); + void build_driver_id_property(ID *id, const char *rna_path); void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 0d85b1dfc93..40db9d1b5f1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1126,7 +1126,26 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) } else { RNAPathKey target_key(id, rna_path); - add_relation(driver_key, target_key, "Driver -> Target"); + if (RNA_pointer_is_null(&target_key.ptr)) { + /* TODO(sergey): This would only mean that driver is broken. + * so we can't create relation anyway. However, we need to avoid + * adding drivers which are known to be buggy to a dependency + * graph, in order to save computational power. + */ + } + else { + if (target_key.prop != NULL && + RNA_property_is_idprop(target_key.prop)) + { + OperationKey parameters_key(id, + DEG_NODE_TYPE_PARAMETERS, + DEG_OPCODE_PARAMETERS_EVAL); + add_relation(target_key, + parameters_key, + "Driver Target -> Properties"); + } + add_relation(driver_key, target_key, "Driver -> Target"); + } } } diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 841242b995e..2e87786639c 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -214,10 +214,18 @@ static bool pointer_to_component_node_criteria( } if (prop != NULL) { /* All unknown data effectively falls under "parameter evaluation". */ - *type = DEG_NODE_TYPE_PARAMETERS; - *operation_code = DEG_OPCODE_PARAMETERS_EVAL; - *operation_name = ""; - *operation_name_tag = -1; + if (RNA_property_is_idprop(prop)) { + *type = DEG_NODE_TYPE_PARAMETERS; + *operation_code = DEG_OPCODE_ID_PROPERTY; + *operation_name = RNA_property_identifier((PropertyRNA *)prop); + *operation_name_tag = -1; + } + else { + *type = DEG_NODE_TYPE_PARAMETERS; + *operation_code = DEG_OPCODE_PARAMETERS_EVAL; + *operation_name = ""; + *operation_name_tag = -1; + } return true; } return false; diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 675002d6b90..41c72d11eac 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -81,6 +81,7 @@ static const char *stringify_opcode(eDepsOperation_Code opcode) #define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name /* Generic Operations. */ STRINGIFY_OPCODE(OPERATION); + STRINGIFY_OPCODE(ID_PROPERTY); STRINGIFY_OPCODE(PARAMETERS_EVAL); STRINGIFY_OPCODE(PLACEHOLDER); /* Animation, Drivers, etc. */ diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h index b2dbe5d2a62..2d0b67f7ee6 100644 --- a/source/blender/depsgraph/intern/depsgraph_types.h +++ b/source/blender/depsgraph/intern/depsgraph_types.h @@ -137,6 +137,7 @@ typedef enum eDepsOperation_Code { DEG_OPCODE_OPERATION = 0, /* Generic parameters evaluation. */ + DEG_OPCODE_ID_PROPERTY, DEG_OPCODE_PARAMETERS_EVAL, // XXX: Placeholder while porting depsgraph code diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 2ec4f96931f..50f21c8891c 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -1858,7 +1858,7 @@ static bool is_track_clean(MovieTrackingTrack *track, int frames, int del) } } - if (count == 0) { + if (del && count == 0) { ok = 0; } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 29a7e11d859..0895d28fba7 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -671,6 +671,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) Sequence *seqn = NULL; bool skip_dup = false; + /* Unlike soft-cut, it's important to use the same value for both strips. */ + const bool is_end_exact = ((seq->start + seq->len) == cutframe); + /* backup values */ ts.start = seq->start; ts.machine = seq->machine; @@ -683,7 +686,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) ts.anim_startofs = seq->anim_startofs; ts.anim_endofs = seq->anim_endofs; ts.len = seq->len; - + /* First Strip! */ /* strips with extended stillfames before */ @@ -695,6 +698,8 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) BKE_sequence_calc(scene, seq); } + /* Important to offset the start when 'cutframe == seq->start' + * because we need at least one frame of content after start/end still have clipped it. */ if ((seq->startstill) && (cutframe <= seq->start)) { /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { @@ -709,13 +714,15 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) } } /* normal strip */ - else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) { + else if ((is_end_exact == false) && + ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len)))) + { seq->endofs = 0; seq->endstill = 0; seq->anim_endofs += (seq->start + seq->len) - cutframe; } /* strips with extended stillframes after */ - else if (((seq->start + seq->len) == cutframe) || + else if ((is_end_exact == true) || (((seq->start + seq->len) < cutframe) && (seq->endstill))) { seq->endstill -= seq->enddisp - cutframe; @@ -735,7 +742,11 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) if (seqn) { seqn->flag |= SELECT; - + + /* Important not to re-assign this (unlike soft-cut) */ +#if 0 + is_end_exact = ((seqn->start + seqn->len) == cutframe); +#endif /* Second Strip! */ /* strips with extended stillframes before */ if ((seqn->startstill) && (cutframe == seqn->start + 1)) { @@ -744,9 +755,11 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) seqn->anim_endofs = ts.anim_endofs; seqn->endstill = ts.endstill; } - + /* normal strip */ - else if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) { + else if ((is_end_exact == false) && + ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len)))) + { seqn->start = cutframe; seqn->startstill = 0; seqn->startofs = 0; @@ -755,9 +768,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) seqn->anim_endofs = ts.anim_endofs; seqn->endstill = ts.endstill; } - + /* strips with extended stillframes after */ - else if (((seqn->start + seqn->len) == cutframe) || + else if ((is_end_exact == true) || (((seqn->start + seqn->len) < cutframe) && (seqn->endstill))) { seqn->start = cutframe; @@ -766,7 +779,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) seqn->endstill = ts.enddisp - cutframe - 1; seqn->startstill = 0; } - + BKE_sequence_reload_new_file(scene, seqn, false); BKE_sequence_calc(scene, seqn); } @@ -779,6 +792,8 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) Sequence *seqn = NULL; bool skip_dup = false; + bool is_end_exact = ((seq->start + seq->len) == cutframe); + /* backup values */ ts.start = seq->start; ts.machine = seq->machine; @@ -791,10 +806,12 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) ts.anim_startofs = seq->anim_startofs; ts.anim_endofs = seq->anim_endofs; ts.len = seq->len; - + /* First Strip! */ /* strips with extended stillfames before */ - + + /* Important to offset the start when 'cutframe == seq->start' + * because we need at least one frame of content after start/end still have clipped it. */ if ((seq->startstill) && (cutframe <= seq->start)) { /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { @@ -809,11 +826,13 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) } } /* normal strip */ - else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) { + else if ((is_end_exact == false) && + (cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) + { seq->endofs = (seq->start + seq->len) - cutframe; } /* strips with extended stillframes after */ - else if (((seq->start + seq->len) == cutframe) || + else if ((is_end_exact == true) || (((seq->start + seq->len) < cutframe) && (seq->endstill))) { seq->endstill -= seq->enddisp - cutframe; @@ -832,7 +851,9 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) if (seqn) { seqn->flag |= SELECT; - + + is_end_exact = ((seqn->start + seqn->len) == cutframe); + /* Second Strip! */ /* strips with extended stillframes before */ if ((seqn->startstill) && (cutframe == seqn->start + 1)) { @@ -843,15 +864,17 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) } /* normal strip */ - if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) { + else if ((is_end_exact == false) && + (cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) + { seqn->startstill = 0; seqn->startofs = cutframe - ts.start; seqn->endofs = ts.endofs; seqn->endstill = ts.endstill; } - + /* strips with extended stillframes after */ - else if (((seqn->start + seqn->len) == cutframe) || + else if ((is_end_exact == true) || (((seqn->start + seqn->len) < cutframe) && (seqn->endstill))) { seqn->start = cutframe - ts.len + 1; @@ -859,7 +882,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) seqn->endstill = ts.enddisp - cutframe - 1; seqn->startstill = 0; } - + BKE_sequence_calc(scene, seqn); } return seqn; diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index bbbf8c633bd..b6bcc592cc8 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -1115,6 +1115,7 @@ static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs) gattribs->layer[0].type = CD_MTFACE; gattribs->layer[0].name[0] = '\0'; gattribs->layer[0].gltexco = 1; + gattribs->layer[0].glinfoindoex = -1; gattribs->totlayer = 1; /* bind material */ |