Changeset 110

Show
Ignore:
Timestamp:
11/13/07 22:49:48 (1 year ago)
Author:
baxissimo
Message:

Big huge update to dynamic property reflection and the PlyReader/Writer?.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/OpenMeshD/OpenMesh/Apps/GLViewer/GLViewer.d

    r104 r110  
    88// Created: 01 Sep 2007 
    99// Written in the D Programming Language (http://www.digitalmars.com/d) 
    10 //============================================================================ 
    11 // $Id:$ 
    1210//============================================================================ 
    1311 
  • trunk/OpenMeshD/OpenMesh/Apps/GLViewer/MeshDrawerT.d

    r104 r110  
    122122                dout.writefln( "File provides texture coordinates"); 
    123123 
     124            { 
     125                auto vpit = mesh_.vprops_begin, vpend = mesh.vprops_end; 
     126                for(; vpit!=vpend; ++vpit) { 
     127                    if (!vpit.val) { continue; } 
     128                    string pname = vpit.val.name; 
     129                    if (pname.length >= 2 && pname[0..2]=="v:")  
     130                        continue; // reserved prop name 
     131                    TypeInfo ptype = vpit.val.element_type; 
     132                    dout.writefln("File provides per-vertex property '%s' of type %s", 
     133                                  pname, ptype); 
     134                } 
     135                 
     136            } 
     137            { 
     138                auto vpit = mesh_.fprops_begin, vpend = mesh.fprops_end; 
     139                for(; vpit!=vpend; ++vpit) { 
     140                    if (!vpit.val) { continue; } 
     141                    string pname = vpit.val.name; 
     142                    if (pname.length >= 2 && pname[0..2]=="f:")  
     143                        continue; // reserved prop name 
     144                    TypeInfo ptype = vpit.val.element_type; 
     145                    dout.writefln("File provides per-face property '%s' of type %s", 
     146                                  pname, ptype); 
     147                } 
     148            } 
    124149 
    125150            // info 
  • trunk/OpenMeshD/OpenMesh/Core/Geometry/VectorT.d

    r108 r110  
    293293        assert(_i<N); values_[_i] = v; 
    294294    } 
     295    int opApply(int delegate(ref Scalar) loop) { 
     296        foreach(ref x; values_) { 
     297            int ret = loop(x); 
     298            if (ret) return ret; 
     299        } 
     300        return 0; 
     301    } 
     302    int opApply(int delegate(ref size_t, ref Scalar) loop) { 
     303        foreach(i, ref x; values_) { 
     304            int ret = loop(i,x); 
     305            if (ret) return ret; 
     306        } 
     307        return 0; 
     308    } 
     309    int opApplyReverse(int delegate(ref Scalar) loop) { 
     310        foreach_reverse(ref x; values_) { 
     311            int ret = loop(x); 
     312            if (ret) return ret; 
     313        } 
     314        return 0; 
     315    } 
     316    int opApplyReverse(int delegate(ref size_t, ref Scalar) loop) { 
     317        foreach_reverse(i, ref x; values_) { 
     318            int ret = loop(i,x); 
     319            if (ret) return ret; 
     320        } 
     321        return 0; 
     322    } 
     323 
     324 
    295325    //---------------------------------------------------------------- comparsion 
    296326    /// component-wise comparison 
     
    720750alias VectorT!(double,4) Vec4d; 
    721751 
     752/* 
     753template Vector2(T) { alias VectorT!(T,2) Vector2; } 
     754template Vector3(T) { alias VectorT!(T,3) Vector3; } 
     755template Vector4(T) { alias VectorT!(T,4) Vector4; } 
     756template Vector5(T) { alias VectorT!(T,5) Vector5; } 
     757template Vector6(T) { alias VectorT!(T,6) Vector6; } 
     758template Vector7(T) { alias VectorT!(T,7) Vector7; } 
     759template Vector8(T) { alias VectorT!(T,8) Vector8; } 
     760*/ 
    722761 
    723762 
  • trunk/OpenMeshD/OpenMesh/Core/IO/BinaryHelper.d

    r82 r110  
    99// Written in the D Programming Language (http://www.digitalmars.com/d) 
    1010//============================================================================ 
    11 // $Id:$ 
    12 //============================================================================ 
    1311 
    1412module OpenMesh.Core.IO.BinaryHelper; 
     
    7573    union SC { short s;      ubyte[2] c; } 
    7674    union IC { int i;        ubyte[4] c; } 
     75    union LC { long l;       ubyte[8] c; } 
    7776    union FC { float f;      ubyte[4] c; } 
    7877    union DC { double d;     ubyte[8] c; } 
     
    106105} 
    107106 
     107/** Binary read a \c long from \c _in and perform byte swapping if 
     108    \c _swap is true */ 
     109long read_long(Stream _in, bool _swap=false) 
     110{ 
     111    LC ic; 
     112    uint got = _in.read(ic.c); 
     113    assert(got==ic.c.length); 
     114    if (_swap) { 
     115        util.swap(ic.c[0], ic.c[7]); 
     116        util.swap(ic.c[1], ic.c[6]); 
     117        util.swap(ic.c[2], ic.c[5]); 
     118        util.swap(ic.c[3], ic.c[4]); 
     119    } 
     120    return ic.l; 
     121} 
     122 
    108123/** Binary read a \c float from \c _is and perform byte swapping if 
    109124    \c _swap is true */ 
     
    162177} 
    163178 
     179/** Binary write a \c long to \c _out and perform byte swapping if 
     180    \c _swap is true */ 
     181void write_long(long _l, Stream _out, bool _swap=false) 
     182{ 
     183    LC ic; 
     184    ic.l = _l; 
     185    if (_swap) { 
     186        util.swap(ic.c[0], ic.c[7]); 
     187        util.swap(ic.c[1], ic.c[6]); 
     188        util.swap(ic.c[2], ic.c[5]); 
     189        util.swap(ic.c[3], ic.c[4]); 
     190    } 
     191    uint wrote = _out.write(ic.c); 
     192    assert(wrote == ic.c.length); 
     193} 
     194 
    164195/** Binary write a \c float to \c _os and perform byte swapping if 
    165196    \c _swap is true */ 
     
    193224 
    194225 
     226/** Binary rean an elementary value from _in and perform byte swapping if 
     227    _swap is true */ 
     228void read_binary(T)(ref T _v, Stream _in, bool _swap=false) 
     229{ 
     230    static      if(is(T == ubyte)) { _in.read(_v); } 
     231    else static if(is(T ==  byte)) { _in.read(_v); } 
     232    else static if(is(T ==  bool)) { ubyte b; _in.read(b); _v=b; } 
     233    else static if(is(T == short)||is(T==ushort)) { _v = cast(T)read_short(_in,_swap); } 
     234    else static if(is(T ==   int)||is(T==uint))   { _v = cast(T)read_int(_in,_swap); } 
     235    else static if(is(T ==  long)||is(T==ulong))  { _v = cast(T)read_long(_in,_swap); } 
     236    else static if(is(T == float)) { _v = read_float(_in,_swap); } 
     237    else static if(is(T == double)) { _v = read_double(_in,_swap); } 
     238    else { 
     239        static assert(false, "read_binary: Unsupported type: "~T.stringof); 
     240    } 
     241} 
     242 
     243/** Binary write an elementary value to _out and perform byte swapping if 
     244    _swap is true */ 
     245void write_binary(T)(T _v, Stream _out, bool _swap=false) 
     246{ 
     247    static      if(is(T == ubyte)) { _out.write(_v); } 
     248    else static if(is(T ==  byte)) { _out.write(_v); } 
     249    else static if(is(T ==  bool)) { _out.write(cast(ubyte)_v); } 
     250    else static if(is(T == short)||is(T==ushort)) { write_short(cast(short)_v,_out,_swap); } 
     251    else static if(is(T ==   int)||is(T==uint)) { write_int(cast(int)_v,_out,_swap); } 
     252    else static if(is(T ==  long)||is(T==ulong)) { write_long(cast(long)_v,_out,_swap); } 
     253    else static if(is(T == float)) { write_float(_v,_out,_swap); } 
     254    else static if(is(T == double)) { write_double(_v,_out,_swap); } 
     255    else { 
     256        static assert(false, "write_binary: Unsupported type: "~T.stringof); 
     257    } 
     258} 
     259 
    195260 
    196261//------------------ FILE* interface ----------------------------- 
     
    214279} 
    215280 
     281/** Binary read a \c long from \c _is and perform byte swapping if 
     282    \c _swap is true */ 
     283long read_long(FILE* _in, bool _swap=false) 
     284{ 
     285    scope _cin = new CFile(_in,FileMode.In); 
     286    scope(exit) _cin.file=null; 
     287    return read_long(_cin, _swap); 
     288} 
     289 
    216290/** Binary read a \c float from \c _is and perform byte swapping if 
    217291    \c _swap is true */ 
     
    239313    scope _cout = new CFile(_out,FileMode.Out); 
    240314    scope(exit) _cout.file=null; 
    241     return write_short(_i, _cout, _swap); 
     315    write_short(_i, _cout, _swap); 
    242316} 
    243317 
     
    248322    scope _cout = new CFile(_out,FileMode.Out); 
    249323    scope(exit) _cout.file=null; 
    250     return write_int(_i, _cout, _swap); 
     324    write_int(_i, _cout, _swap); 
     325
     326 
     327/** Binary write a \c long to \c _os and perform byte swapping if 
     328    \c _swap is true */ 
     329void write_long(long _i, FILE* _out, bool _swap=false) 
     330
     331    scope _cout = new CFile(_out,FileMode.Out); 
     332    scope(exit) _cout.file=null; 
     333    write_long(_i, _cout, _swap); 
    251334} 
    252335 
     
    257340    scope _cout = new CFile(_out,FileMode.Out); 
    258341    scope(exit) _cout.file=null; 
    259     return write_float(_f, _cout, _swap); 
     342    write_float(_f, _cout, _swap); 
    260343} 
    261344 
     
    266349    scope _cout = new CFile(_out,FileMode.Out); 
    267350    scope(exit) _cout.file=null; 
    268     return write_double(_d, _cout, _swap); 
    269 } 
    270  
    271     
     351    write_double(_d, _cout, _swap); 
     352} 
     353 
     354/** Swap the endian-ness of the data v */ 
    272355void swap_endian(T)(ref T v) 
    273356{ 
  • trunk/OpenMeshD/OpenMesh/Core/IO/IOManager.d

    r98 r110  
    88// Created: 01 Sep 2007 
    99// Written in the D Programming Language (http://www.digitalmars.com/d) 
    10 //============================================================================ 
    11 // $Id:$ 
    1210//============================================================================ 
    1311 
  • trunk/OpenMeshD/OpenMesh/Core/IO/MeshIO.d

    r98 r110  
    7676  Options opt; 
    7777  return read_mesh(_mesh, _filename, opt); 
     78  if (_optout) *_optout = opt; 
    7879} 
    7980 
  • trunk/OpenMeshD/OpenMesh/Core/IO/exporter/BaseExporter.d

    r5 r110  
    77// Author:  William V. Baxter III 
    88// Created: 01 Sep 2007 
     9// License: LGPL 2.1 
    910// Written in the D Programming Language (http://www.digitalmars.com/d) 
    10 //============================================================================ 
    11 // $Id:$ 
    1211//============================================================================ 
    1312 
     
    10099    bool has_face_normals()     /*const*/ { return false; } 
    101100    bool has_face_colors()      /*const*/ { return false; } 
     101 
     102     
     103 
    102104} 
    103105 
  • trunk/OpenMeshD/OpenMesh/Core/IO/importer/ImporterT.d

    r103 r110  
    99// Written in the D Programming Language (http://www.digitalmars.com/d) 
    1010//============================================================================ 
    11 // $Id:$ 
    12 //============================================================================ 
    1311 
    1412module OpenMesh.Core.IO.importer.ImporterT; 
     
    6563//=== IMPLEMENTATION ========================================================== 
    6664 
     65private { 
     66    const string[] supported_types =  
     67        ["byte","ubyte","short","ushort","int","uint","float","double", 
     68         "Vec3f","Vec3d","Vec3ub","Vec2f","Vec2d","Vec2ub","Vec4f","Vec4d","Vec4ub"]; 
     69    // Very simple compile-time pattern subsitution.   
     70    // Just replaces all % chars with sub 
     71    string ctfe_subs(string str, string sub) { 
     72        string ret; 
     73        foreach(c; str) { 
     74            if (c=='%') { ret ~= sub; } 
     75            else { ret ~= c; } 
     76        } 
     77        return ret; 
     78    } 
     79    // Assumes calling code has a TypeInfo ti variable. 
     80    // Assumes templ uses '%' as a stand-in for the type name 
     81    string do_type_cases(string templ) { 
     82        // Generates a big if-else block of the form 
     83        //     if(false) {} 
     84        //     else if(ti == typeid(int)) { <templ> } 
     85        //     else if(ti == typeid(float)) { <templ> } 
     86        //     ... 
     87        string ret = "if(false){}\n"; 
     88        foreach(t; supported_types) { 
     89            ret ~= "else if (ti == typeid("~t~")) { "; 
     90            ret ~= ctfe_subs(templ,t); 
     91            ret ~= " }\n"; 
     92        } 
     93        ret ~= "else assert(false, \"Unsupported type: \"~ti.toString);"; 
     94        return ret; 
     95    } 
     96} 
    6797 
    6898/** 
     
    183213 
    184214    /// check if a property type is supported 
    185     bool supports_property_data_type(TypeInfo _ti) { 
    186         if (_ti == typeid(int)) { 
    187         } 
    188         else if (_ti == typeid(float)) 
    189         { 
    190         } 
    191         else if (_ti == typeid(Vec3f)) 
    192         { 
    193         } 
    194         else if (_ti == typeid(Vec3ub)) 
    195         { 
    196         } 
    197         else 
    198             return false; 
    199  
    200         return true; 
     215    bool supports_property_data_type(TypeInfo ti) { 
     216        bool ok=false; 
     217         
     218        mixin(do_type_cases( "ok=true;" )); 
     219 
     220        return ok; 
    201221    } 
    202222 
     
    245265        } 
    246266         
    247         if (ti == typeid(int)) { 
    248             set_vpropertyT!(int)(_vh, _propname, va_arg!(int)(aptr)); 
    249         } 
    250         else if (ti == typeid(float)) 
    251         { 
    252             set_vpropertyT!(float)(_vh, _propname, va_arg!(float)(aptr)); 
    253         } 
    254         else if (ti == typeid(Vec3f)) 
    255         { 
    256             set_vpropertyT!(Vec3f)(_vh, _propname, va_arg!(Vec3f)(aptr)); 
    257         } 
    258         else if (ti == typeid(Vec3ub)) 
    259         { 
    260             set_vpropertyT!(Vec3ub)(_vh, _propname, va_arg!(Vec3ub)(aptr)); 
    261         } 
    262         else 
    263             assert(0); 
    264          
    265         return; 
    266         //auto prop_ptr = mesh_.get_property(_propname); 
    267         //for (j = 0; j < arguments.length; ) 
    268         //{ 
    269         //} 
     267        mixin(do_type_cases( "set_vpropertyT!( % )(_vh, _propname, va_arg!( % )(aptr));" )); 
     268 
    270269    } 
    271270 
     
    273272    void set_property(FaceHandle _fh, string _propname, ...) 
    274273    { 
    275         if (_arguments.length != 1)  
    276             throw new Exception("set_property takes exactly 1 value argument"); 
     274        if (_arguments.length == 0)  
     275            throw new Exception("set_property takes 1 value argument, or a typeinfo and a void*"); 
     276 
    277277        TypeInfo ti = _arguments[0]; 
    278         if (ti == typeid(int)) { 
    279             set_fpropertyT!(int)(_fh, _propname, va_arg!(int)(_argptr)); 
    280         } 
    281         else if (ti == typeid(float)) 
    282         { 
    283             set_fpropertyT!(float)(_fh, _propname, va_arg!(float)(_argptr)); 
    284         } 
    285         else if (ti == typeid(Vec3f)) 
    286         { 
    287             set_fpropertyT!(Vec3f)(_fh, _propname, va_arg!(Vec3f)(_argptr)); 
    288         } 
    289         else if (ti == typeid(Vec3ub)) 
    290         { 
    291             set_fpropertyT!(Vec3ub)(_fh, _propname, va_arg!(Vec3ub)(_argptr)); 
    292         } 
    293         return; 
     278        void *aptr = _argptr; 
     279        //writefln("set_property(fh..) type:%s  args.lengt: %s", _arguments[0], _arguments.length); 
     280        if (_arguments.length == 2) { 
     281            if (ti == typeid(TypeInfo)) { 
     282                //writefln(  "  ti was: ", ti); 
     283                ti = va_arg!(TypeInfo)(_argptr); 
     284                aptr = va_arg!(void*)(_argptr); 
     285                //writefln(  "  ti now: ", ti); 
     286            } 
     287            else { 
     288                throw new Exception("set_property with 2 arguments should have a typeinfo as arg 1"); 
     289            } 
     290        } 
     291        else if (_arguments.length>2 ) { 
     292            throw new Exception("set_property takes 1 value argument, or a typeinfo and a void*"); 
     293        } 
     294 
     295        mixin(do_type_cases( "set_fpropertyT!( % )(_fh, _propname, va_arg!( % )(_argptr));" )); 
    294296    } 
    295297 
  • trunk/OpenMeshD/OpenMesh/Core/IO/reader/OFFReader.d

    r98 r110  
    178178                    read_ascii(_in, _bi)); 
    179179 
    180         // Can't tell if there were face colors or not till after you read it. 
     180        // Thanks to the foobar mess that is OFF format,  
     181        // You can't tell if there were face colors or not till after you read it. 
    181182        if (options_.face_has_color) _opt += Options.FaceColor; 
    182183        return ret; 
  • trunk/OpenMeshD/OpenMesh/Core/IO/reader/PLYReader.d

    r103 r110  
    5555    bool startsWith(string s, string sub) { 
    5656        return (s.length>=sub.length && s[0..sub.length]==sub); 
     57    } 
     58    bool endsWith(string s, string sub) { 
     59        return (s.length>=sub.length && s[$-sub.length..$]==sub); 
    5760    } 
    5861 
     
    280283        // READ FACES 
    281284        FaceHandle[] fh_list; fh_list.length = 10; 
     285        struct NamedBox { 
     286            string name; 
     287            boxer.Box box; 
     288        } 
     289        NamedBox[] extra_fprops; 
    282290        for (int i=0; i<nF; ) 
    283291        { 
     
    299307            bool got_color = false; 
    300308            boxer.Box ret; 
     309            int iextras = 0; 
    301310            foreach(prop; _desc.fprops) { 
     311                //debug { dout.writefln("reading fprop.name = %s",prop.name).flush; } 
    302312                if (is_binary) { 
    303313                    ret = prop.read_prop_binary(_in, _bi, _opt, _desc.need_swap); 
     
    318328                case "vertex_indices": vids = unbox_convert!(uint[])(ret); break; 
    319329                default: 
    320                     //ignore 
     330                    if (prop.type_supported) { 
     331                        if (iextras+1>extra_fprops.length) { 
     332                            extra_fprops.length = extra_fprops.length+1; 
     333                            extra_fprops[$-1].name = prop.name.dup; 
     334                        } 
     335                        else { 
     336                            assert(extra_fprops[iextras].name==prop.name, 
     337                                   "these prop names should be in sync"); 
     338                        } 
     339                        extra_fprops[iextras++].box = ret; 
     340                    } 
     341                     
    321342                } 
    322343            } 
     
    325346 
    326347            fh_list.length = 0; 
    327             _bi.add_face(vs, &fh_list);  
     348            _bi.add_face(vs, &fh_list); // returns list if face got triangulated 
    328349 
    329350            foreach(fh; fh_list) { 
     
    335356                    _bi.set_color(fh,color); 
    336357                    _opt += Options.FaceColor; 
     358                } 
     359                foreach (ref xprop; extra_fprops) { 
     360                    // ack! need to go box to prop->box 
     361                    TypeInfo[] types; void* data; 
     362                    boxer.boxArrayToArguments([xprop.box], types, data); 
     363                    _bi.set_property(fh, xprop.name, types[0], data); 
    337364                } 
    338365            } 
     
    351378        alias std.string.split split; 
    352379 
    353         string[string] known_vprops =  
    354             [ 
    355                 "x"[]:"x"[],    "y":"y",   "z":"z", 
    356                 "nx":"nx", "ny":"ny", "nz":"nz", 
    357                 "r":"r",    "g":"g",   "b":"b", 
    358                 "red":"r",    "green":"g",   "blue":"b", 
    359                 "t":"t",    "s":"s", 
    360              ]; 
    361         string[string] known_fprops =  
    362             [ 
    363                 "nx"[]:"nx"[], "ny":"ny", "nz":"nz", 
    364                 "r":"r",    "g":"g",   "b":"b", 
    365                 "red":"r",    "green":"g",   "blue":"b", 
    366                 "vertex_indices":"vertex_indices", 
    367              ]; 
    368         string[] words; 
    369  
    370         Prop[]* prop_ptr = null; 
    371         string[string]* known_props_ptr = null; 
    372         string cur_element; 
    373  
    374  
    375         void update_desc_from_prop(ref string propname)  
    376         { 
    377             if (auto _ret = propname in *known_props_ptr) { 
    378                 propname = *_ret; 
    379             } 
    380             if (cur_element == "vertex") { 
    381                 switch(propname) { 
    382                 case "x": case "y": case "z": 
    383                     _desc.vertex_has_position = true; break; 
    384                 case "nx": case "ny": case "nz": 
    385                     _desc.vertex_has_normal = true; break; 
    386                 case "r": case "g": case "b": 
    387                     _desc.vertex_has_color = true; break; 
    388                 case "s": case "t": 
    389                     _desc.vertex_has_texcoord = true; break; 
    390                 default: 
    391                     _desc.vertex_has_other = true; break; 
    392                 } 
    393             } 
    394             else if (cur_element == "face") { 
    395                 switch(propname) { 
    396                 case "nx": case "ny": case "nz": 
    397                     _desc.face_has_normal = true; break; 
    398                 case "r": case "g": case "b": 
    399                     _desc.face_has_color = true; break; 
    400                 default: 
    401                     _desc.face_has_other = true; break; 
    402                 } 
    403             } 
    404         } 
    405         void add_prop(string[] words) { 
    406             string propname = words[1]; 
    407             update_desc_from_prop(propname); 
    408             bool ok = _bi.supports_property_data_type(ply_data_type_typeid(words[0])); 
    409             (*prop_ptr) ~= new ScalarProp(propname, words[0], ok); 
    410         } 
    411         void add_list_prop(string[] words) { 
    412             string propname = words[2]; 
    413             update_desc_from_prop(propname); 
    414             bool ok = _bi.supports_property_data_type(ply_data_type_typeid(words[1])); 
    415             (*prop_ptr) ~= new ListProp(propname,words[0],words[1], ok); 
    416         } 
    417  
    418380        char[] line; line.length = 4; 
     381 
    419382        _is.readExact(line.ptr,4); 
    420383        if (line != "ply\n") { 
     
    422385                "File is not a PLY file.  Missing magic number 'ply\\n' (first line was '"~line~"'"); 
    423386        } 
    424  
     387         
     388        string[] words; 
     389        string[][] fprops,vprops; 
     390        string cur_element; 
     391         
    425392        bool got_end_header = false; 
    426393        for(int lnum=2; !_is.eof(); ++lnum) 
     
    473440                if (words[1] == "vertex") { 
    474441                    _desc.n_vertices = std.conv.toUint(words[2]); 
    475                     prop_ptr = &_desc.vprops; 
    476                     known_props_ptr = &known_vprops; 
     442                    //prop_ptr = &_desc.vprops; 
     443                    //known_props_ptr = &known_vprops; 
    477444                    cur_element = "vertex"; 
    478445                }  
    479446                else if (words[1] == "face") { 
    480447                    _desc.n_faces = std.conv.toUint(words[2]); 
    481                     prop_ptr = &_desc.fprops; 
    482                     known_props_ptr = &known_fprops; 
     448                    //prop_ptr = &_desc.fprops; 
     449                    //known_props_ptr = &known_fprops; 
    483450                    cur_element = "face"; 
    484451                } 
     
    492459                if (_bi) { // skip the work if we're just scanning header, not actually importing 
    493460                    words = line.split(); 
    494  
    495                     if (words[1] == "list") { 
    496                         add_list_prop(words[2..$]); 
    497                         if (!(words[4] in *known_props_ptr)) { 
    498                             derr.writefln( 
    499                                 "line: %s: Ignoring unsupported %s list property: ", lnum,words[3],words[4]).flush; 
    500                         } 
     461                    if (cur_element=="vertex") { 
     462                        vprops ~= words.dup; 
    501463                    } 
    502  
    503                     else { 
    504                         add_prop(words[1..$]); 
    505                          
    506                         if (!(words[2] in *known_props_ptr)) { 
    507                             if ((*prop_ptr)[$-1].type_supported) { 
    508                                 dlog.writefln("reading extra %s property, '%s'", lnum, words[1],words[2]).flush; 
    509                             } else { 
    510                                 derr.writefln("line: %s: Ignoring unsupported %s property: ", lnum, words[1],words[2]).flush; 
    511                             } 
    512                         } 
    513                     }                     
    514                 } 
     464                    else if (cur_element == "face") { 
     465                        fprops ~= words.dup; 
     466                    } 
     467                }                     
    515468            } 
    516469            else { 
     
    523476        } 
    524477 
     478        if (_bi) { 
     479            _process_property_descriptions(_desc, _bi, vprops,fprops); 
     480        } 
    525481        return true; 
     482    } 
     483 
     484    private void _process_property_descriptions(_Descrip _desc, BaseImporter _bi, 
     485                                                string[][] vprops, string[][] fprops) 
     486    { 
     487        string[string] known_vprops =  
     488            [ 
     489                "x"[]:"x"[],    "y":"y",   "z":"z", 
     490                "nx":"nx", "ny":"ny", "nz":"nz", 
     491                "r":"r",    "g":"g",   "b":"b", 
     492                "red":"r",    "green":"g",   "blue":"b", 
     493                "t":"t",    "s":"s", 
     494             ]; 
     495        string[string] known_fprops =  
     496            [ 
     497                "nx"[]:"nx"[], "ny":"ny", "nz":"nz", 
     498                "r":"r",    "g":"g",   "b":"b", 
     499                "red":"r",    "green":"g",   "blue":"b", 
     500                "vertex_indices":"vertex_indices", 
     501             ]; 
     502        string[][string] known_vector_suffixes =  
     503            // These can also be preceeded by an '_' 
     504            [ 
     505                "x"[] : cast(string[])["x","y","z","w"], 
     506                "r"   : ["r", "g", "b", "a"], 
     507                "s"   : ["s", "t", "r", "q"], 
     508                "red" : ["red", "green", "blue", "alpha"], 
     509                "0"   : ["0","1","2","3"], 
     510                "1"   : ["1","2","3","4"], 
     511             ]; 
     512        string[] words; 
     513 
     514        enum ElemT { BadElem=-1,VertexElem=0,FaceElem=1 }; 
     515        Prop[]*[2] prop_ptrs = [&_desc.vprops, &_desc.fprops]; 
     516        string[string][2] known_props = [known_vprops,known_fprops]; 
     517        ElemT cur_element=ElemT.BadElem; 
     518 
     519        void update_desc_from_prop(ref string propname)  
     520        { 
     521            if (auto _ret = propname in known_props[cur_element]) { 
     522                propname = *_ret; 
     523            } 
     524            if (cur_element == ElemT.VertexElem) { 
     525                switch(propname) { 
     526                case "x": case "y": case "z": 
     527                    _desc.vertex_has_position = true; break; 
     528                case "nx": case "ny": case "nz": 
     529                    _desc.vertex_has_normal = true; break; 
     530                case "r": case "g": case "b": 
     531                    _desc.vertex_has_color = true; break; 
     532                case "s": case "t": 
     533                    _desc.vertex_has_texcoord = true; break; 
     534                default: 
     535                    _desc.vertex_has_other = true; break; 
     536                } 
     537            } 
     538            else if (cur_element == ElemT.FaceElem) { 
     539                switch(propname) { 
     540                case "nx": case "ny": case "nz": 
     541                    _desc.face_has_normal = true; break; 
     542                case "r": case "g": case "b": 
     543                    _desc.face_has_color = true; break; 
     544                default: 
     545                    _desc.face_has_other = true; break; 
     546                } 
     547            } 
     548        } 
     549        void add_prop(string[] words) { 
     550            // words is like ["float32", "x"] -- "property" stripped 
     551            string propname = words[1]; 
     552            update_desc_from_prop(propname); 
     553            bool ok = _bi.supports_property_data_type(ply_data_type_typeid(words[0])); 
     554            *prop_ptrs[cur_element] ~= new ScalarProp(propname, words[0], ok); 
     555            if (!(words[1] in known_props[cur_element])) { 
     556                if ((*prop_ptrs[cur_element])[$-1].type_supported) { 
     557                    dlog.writefln("PLYReader: reading extra %s property, '%s'",  
     558                                  words[0],words[1]).flush; 
     559                } else { 
     560                    derr.writefln("PLYReader: Ignoring unsupported %s property, '%s'",  
     561                                  words[0],words[1]).flush; 
     562                } 
     563            } 
     564        } 
     565        void add_vector_prop(string[][] lines, string first_suffix, int N) 
     566        { 
     567            // each lines[i] is like  ["property", "float32", "pos_x"] 
     568            // merge the sequence into one VectorT prop 
     569            string prop_base_name = lines[0][2][0..$-first_suffix.length]; 
     570            string prop_type = lines[0][1]; 
     571 
     572            TypeInfo ti; 
     573            switch(N) { 
     574            case 2: ti = ply_data_vector_type_typeid!(2)(prop_type); break; 
     575            case 3: ti = ply_data_vector_type_typeid!(3)(prop_type); break; 
     576            case 4: ti = ply_data_vector_type_typeid!(4)(prop_type); break; 
     577            default: 
     578                assert(false, "Unsupported vector length"); 
     579            } 
     580            bool ok = _bi.supports_property_data_type(ti); 
     581            *prop_ptrs[cur_element] ~= new VectorProp(prop_base_name, N, prop_type, ok); 
     582            if ((*prop_ptrs[cur_element])[$-1].type_supported) { 
     583                dlog.writefln("PLYReader: reading extra %s-vector %s property, '%s'",  
     584                              N,prop_type,prop_base_name).flush; 
     585            } else { 
     586                derr.writefln("PLYReader: Ignoring unsupported %s-vector %s property: ",  
     587                              N,prop_type,prop_base_name).flush; 
     588            } 
     589        } 
     590 
     591        void add_list_prop(string[] words) { 
     592            // words is a tokenized ply list property line without the  
     593            // leading "property list" part. 
     594            // Something like: ["uint8", "int32", "vertex_indices"] 
     595            string propname = words[2]; 
     596            update_desc_from_prop(propname); 
     597            bool ok = _bi.supports_property_data_type(ply_data_type_typeid(words[1])); 
     598            *prop_ptrs[cur_element] ~= new ListProp(propname,words[0],words[1], ok); 
     599            if (!(words[2] in known_props[cur_element])) { 
     600                derr.writefln( 
     601                    "PLYReader: Ignoring unsupported %s list property: ", 
     602                    words[1],words[2]).flush; 
     603            } 
     604        } 
     605 
     606 
     607        int vector_sequence_length(string prop_lines[][], ref string first_suffix) 
     608        { 
     609            // prop_lines[0] is regular tokenized ply prop line  
     610            // like ["property", "float32", "ambient_r"] 
     611            // see if there is a sequence following this one like "ambient_g","ambient_b" 
     612            // If so make it a vector. 
     613            string pname0 = prop_lines[0][2]; 
     614            // known props like just r,g,b are handled separately 
     615            if (pname0 in known_props[cur_element]) return 0;  
     616            string ptype0 = prop_lines[0][1]; 
     617            foreach(start,suffixes; known_vector_suffixes)  
     618            { 
     619                bool got_start=false; 
     620                string sep = ""; 
     621                if (pname0.endsWith("_"~start)) { got_start=true; sep="_";} 
     622                else if (pname0.endsWith(start)) { got_start=true; } 
     623                if (got_start) { 
     624                    // see how big the sequence is 
     625                    string basename0 = pname0[0..$-start.length]; 
     626                    int i=1; 
     627                    while(i<suffixes.length  
     628                          && i<prop_lines.length 
     629                          && prop_lines[i][1]==ptype0 /* catches "list" too*/ 
     630                          && prop_lines[i][2].startsWith(basename0) 
     631                          && prop_lines[i][2].endsWith(sep~suffixes[i])) 
     632                    { ++i; } 
     633                     
     634                    if (i>1) { 
     635                        first_suffix = sep~start; 
     636                        return i; 
     637                    } 
     638                } 
     639            } 
     640            return 0; 
     641        } 
     642 
     643        void process_category(ElemT cur_el, string[][] prop_lines) 
     644        { 
     645            cur_element = cur_el; 
     646 
     647            for(int idx = 0; idx<prop_lines.length; ++idx) 
     648            { 
     649                string[] words = prop_lines[idx]; 
     650                if (words[1] == "list") { 
     651                    add_list_prop(words[2..$]); 
     652                } 
     653                else { 
     654                    string first_suffix; 
     655                    int len = vector_sequence_length(prop_lines[idx..$], first_suffix); 
     656                    switch(len) { 
     657                    case 0: case 1:  
     658                        add_prop(words[1..$]); break; 
     659 
     660                    case 2: case 3: case 4: 
     661                        add_vector_prop(prop_lines[idx..idx+len], first_suffix, len); idx+=len-1; break; 
     662                    default: 
     663                        assert(false, "bad length for vector property"); 
     664                    } 
     665                } 
     666            } 
     667        } 
     668 
     669        process_category(ElemT.VertexElem, vprops); 
     670 
     671        process_category(ElemT.FaceElem, fprops); 
    526672    } 
    527673 
     
    555701        case "float64": return typeid(double); 
    556702 
     703        default: return null; 
     704        } 
     705    } 
     706    static TypeInfo ply_data_vector_type_typeid(int N)(string type) { 
     707        switch(type) { 
     708        case "int8":   return typeid(VectorT!(byte,N)); 
     709        case "uint8":  return typeid(VectorT!(ubyte,N)); 
     710        case "int16":  return typeid(VectorT!(short,N)); 
     711        case "uint16": return typeid(VectorT!(ushort,N)); 
     712        case "int32":    return typeid(VectorT!(int,N));<