@@ -719,6 +719,65 @@ ASTstructselect::print (std::ostream &out, int indentlevel) const
719719
720720
721721
722+ ASTswizzle::ASTswizzle (OSLCompilerImpl *comp, ASTNode *expr, ustring field) :
723+ ASTfieldselect(swizzle_node, comp, expr, field)
724+ {
725+ if (field.size () == 1 ) m_typespec = TypeDesc::TypeFloat;
726+ else m_typespec = TypeDesc::TypeVector;
727+ }
728+
729+
730+
731+ size_t ASTswizzle::indices (ustring components, int *indexes, size_t N, bool consts)
732+ {
733+ size_t i = 0 ;
734+ do {
735+ switch (components[i]) {
736+ case ' r' :
737+ case ' x' : indexes[i] = 0 ; break ;
738+ case ' g' :
739+ case ' y' : indexes[i] = 1 ; break ;
740+ case ' b' :
741+ case ' z' : indexes[i] = 2 ; break ;
742+
743+ case ' 0' :
744+ if (!consts)
745+ return 0 ;
746+ indexes[i] = const_offset;
747+ break ;
748+ case ' 1' :
749+ if (!consts)
750+ return 0 ;
751+ indexes[i] = const_offset + 1 ;
752+ break ;
753+
754+ case ' \0 ' : return i;
755+
756+ default : return 0 ;
757+ }
758+ } while (++i < N);
759+
760+ return i;
761+ }
762+
763+
764+
765+ const char *
766+ ASTswizzle::childname (size_t i) const
767+ {
768+ return type_c_str (m_typespec);
769+ }
770+
771+
772+ void
773+ ASTswizzle::print (std::ostream &out, int indentlevel) const
774+ {
775+ ASTNode::print (out, indentlevel);
776+ indent (out, indentlevel+1 );
777+ out << " components " << field () << " \n " ;
778+ }
779+
780+
722781ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr,
723782 ustring field)
724783{
@@ -728,25 +787,55 @@ ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr,
728787 const TypeSpec &type = expr->nodetype () != structselect_node ? expr->typespec () :
729788 static_cast <ASTstructselect*>(expr)->fieldsym ()->typespec ();
730789
731- if (type.aggregate () == TypeDesc::VEC3) {
732- int component = -1 ;
733- switch (field[0 ]) {
734- case ' r' : component = 0 ; break ;
735- case ' g' : component = 1 ; break ;
736- case ' b' : component = 2 ; break ;
790+ if (type.aggregate () == TypeDesc::VEC3 && field.size () <= 3 ) {
791+ // Early out swizle to native component ordering.
792+ if (field == " rgb" || field == " xyz" )
793+ return expr;
737794
738- case ' x' : component = 0 ; break ;
739- case ' y' : component = 1 ; break ;
740- case ' z' : component = 2 ; break ;
795+ ASTindex* index = expr->nodetype () != index_node ? nullptr : static_cast <ASTindex*>(expr);
741796
742- default : break ;
743- }
744- if (component != -1 ) {
745- if (expr->nodetype () == index_node) {
746- static_cast <ASTindex*>(expr)->extend (new ASTliteral (comp, component));
747- return expr;
797+ int indexes[3 ];
798+ switch (ASTswizzle::indices (field, indexes, 3 , true )) {
799+ case 1 : {
800+ if (!index)
801+ return new ASTindex (comp, expr, new ASTliteral (comp, indexes[0 ]));
802+ index->extend (new ASTliteral (comp, indexes[0 ]));
803+ return index;
748804 }
749- return new ASTindex (comp, expr, new ASTliteral (comp, component));
805+
806+ case 3 : {
807+ // Don't leak soon to be unused expr node
808+ std::unique_ptr<ASTNode> cleanup (index);
809+ ASTNode* index0 = nullptr ;
810+ if (index) {
811+ index0 = index->index ().get ();
812+ expr = index->lvalue ().get ();
813+ }
814+
815+ ASTNode *args[3 ];
816+ for (int i = 0 ; i < 3 ; ++i) {
817+ if (indexes[i] >= 0 ) {
818+ args[i] = new ASTliteral (comp, indexes[i]);
819+ if (i == 0 && index) {
820+ // Re-use expr by extending the ASTindex.
821+ index->extend (args[i]);
822+ args[0 ] = cleanup.release ();
823+ } else {
824+ args[i] = !index0 ? new ASTindex (comp, expr, args[i]) :
825+ new ASTindex (comp, expr, index0, args[i]);
826+ }
827+ } else {
828+ float cval = indexes[i] - ASTswizzle::const_offset;
829+ ASSERT ((cval==0 ) || (cval==1 ));
830+ args[i] = new ASTliteral (comp, cval);
831+ }
832+ }
833+ args[0 ]->append (args[1 ]);
834+ args[1 ]->append (args[2 ]);
835+ return new ASTswizzle (comp, args[0 ], field);
836+ }
837+
838+ default : break ;
750839 }
751840 }
752841
0 commit comments