@@ -805,6 +805,65 @@ ASTstructselect::print (std::ostream &out, int indentlevel) const
805805
806806
807807
808+ ASTswizzle::ASTswizzle (OSLCompilerImpl *comp, ASTNode *expr, ustring field) :
809+ ASTfieldselect(swizzle_node, comp, expr, field)
810+ {
811+ if (field.size () == 1 ) m_typespec = TypeDesc::TypeFloat;
812+ else m_typespec = TypeDesc::TypeVector;
813+ }
814+
815+
816+
817+ size_t ASTswizzle::indices (ustring components, int *indexes, size_t N, bool consts)
818+ {
819+ size_t i = 0 ;
820+ do {
821+ switch (components[i]) {
822+ case ' r' :
823+ case ' x' : indexes[i] = 0 ; break ;
824+ case ' g' :
825+ case ' y' : indexes[i] = 1 ; break ;
826+ case ' b' :
827+ case ' z' : indexes[i] = 2 ; break ;
828+
829+ case ' 0' :
830+ if (!consts)
831+ return 0 ;
832+ indexes[i] = const_offset;
833+ break ;
834+ case ' 1' :
835+ if (!consts)
836+ return 0 ;
837+ indexes[i] = const_offset + 1 ;
838+ break ;
839+
840+ case ' \0 ' : return i;
841+
842+ default : return 0 ;
843+ }
844+ } while (++i < N);
845+
846+ return i;
847+ }
848+
849+
850+
851+ const char *
852+ ASTswizzle::childname (size_t i) const
853+ {
854+ return type_c_str (m_typespec);
855+ }
856+
857+
858+ void
859+ ASTswizzle::print (std::ostream &out, int indentlevel) const
860+ {
861+ ASTNode::print (out, indentlevel);
862+ indent (out, indentlevel+1 );
863+ out << " components " << field () << " \n " ;
864+ }
865+
866+
808867ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr,
809868 ustring field)
810869{
@@ -814,25 +873,55 @@ ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr,
814873 const TypeSpec &type = expr->nodetype () != structselect_node ? expr->typespec () :
815874 static_cast <ASTstructselect*>(expr)->fieldsym ()->typespec ();
816875
817- if (type.aggregate () == TypeDesc::VEC3) {
818- int component = -1 ;
819- switch (field[0 ]) {
820- case ' r' : component = 0 ; break ;
821- case ' g' : component = 1 ; break ;
822- case ' b' : component = 2 ; break ;
876+ if (type.aggregate () == TypeDesc::VEC3 && field.size () <= 3 ) {
877+ // Early out swizle to native component ordering.
878+ if (field == " rgb" || field == " xyz" )
879+ return expr;
823880
824- case ' x' : component = 0 ; break ;
825- case ' y' : component = 1 ; break ;
826- case ' z' : component = 2 ; break ;
881+ ASTindex* index = expr->nodetype () != index_node ? nullptr : static_cast <ASTindex*>(expr);
827882
828- default : break ;
829- }
830- if (component != -1 ) {
831- if (expr->nodetype () == index_node) {
832- static_cast <ASTindex*>(expr)->extend (new ASTliteral (comp, component));
833- return expr;
883+ int indexes[3 ];
884+ switch (ASTswizzle::indices (field, indexes, 3 , true )) {
885+ case 1 : {
886+ if (!index)
887+ return new ASTindex (comp, expr, new ASTliteral (comp, indexes[0 ]));
888+ index->extend (new ASTliteral (comp, indexes[0 ]));
889+ return index;
890+ }
891+
892+ case 3 : {
893+ // Don't leak soon to be unused expr node
894+ std::unique_ptr<ASTNode> cleanup (index);
895+ ASTNode* index0 = nullptr ;
896+ if (index) {
897+ index0 = index->index ().get ();
898+ expr = index->lvalue ().get ();
899+ }
900+
901+ ASTNode *args[3 ];
902+ for (int i = 0 ; i < 3 ; ++i) {
903+ if (indexes[i] >= 0 ) {
904+ args[i] = new ASTliteral (comp, indexes[i]);
905+ if (i == 0 && index) {
906+ // Re-use expr by extending the ASTindex.
907+ index->extend (args[i]);
908+ args[0 ] = cleanup.release ();
909+ } else {
910+ args[i] = !index0 ? new ASTindex (comp, expr, args[i]) :
911+ new ASTindex (comp, expr, index0, args[i]);
912+ }
913+ } else {
914+ float cval = indexes[i] - ASTswizzle::const_offset;
915+ ASSERT ((cval==0 ) || (cval==1 ));
916+ args[i] = new ASTliteral (comp, cval);
917+ }
918+ }
919+ args[0 ]->append (args[1 ]);
920+ args[1 ]->append (args[2 ]);
921+ return new ASTswizzle (comp, args[0 ], field);
834922 }
835- return new ASTindex (comp, expr, new ASTliteral (comp, component));
923+
924+ default : break ;
836925 }
837926 }
838927
0 commit comments