loader_aw

Load OBJ/MTL file formats
git clone git://git.meso-star.fr/loader_aw.git
Log | Files | Refs | README | LICENSE

test_aw_obj.c (22519B)


      1 /* Copyright (C) 2014-2017, 2020-2023 Vincent Forest (vaplv@free.fr)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU Lesser General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU Lesser General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "aw.h"
     17 
     18 #include <rsys/double3.h>
     19 #include <rsys/double4.h>
     20 #include <rsys/logger.h>
     21 #include <rsys/mem_allocator.h>
     22 
     23 #include <string.h>
     24 
     25 static void
     26 test_plane(struct aw_obj* obj)
     27 {
     28   static const char* plane_obj =
     29     "mtllib master.mtl"
     30     "\n"
     31     "g\n"
     32     "o plane\n"
     33     "v 0.0000 2.0000 0.0000\n"
     34     "v 0.0000 0.0000 0.0000\n"
     35     "v 2.0000 0.0000 0.0000\n"
     36     "v 2.0000 2.0000 0.0000\n"
     37     "vt 0.0000 1.0000 0.0000\n"
     38     "vt 0.0000 0.0000 0.0000\n"
     39     "vt 1.0000 0.0000 0.0000\n"
     40     "vt 1.0000 1.0000 0.0000\n"
     41     "# 4 vertices\n"
     42     "\n"
     43     "usemtl wood\n"
     44     "f 1/1 2/2 3/3 4/4\n"
     45     "# 1 element\n";
     46   double v4[4];
     47   struct aw_obj_desc desc;
     48   struct aw_obj_face face;
     49   struct aw_obj_named_group group;
     50   struct aw_obj_named_group mtl;
     51   struct aw_obj_vertex vertex;
     52   struct aw_obj_vertex_data vdata;
     53   const double* data = NULL;
     54   FILE* file;
     55   const char* mtllib;
     56 
     57   CHK(obj != NULL);
     58 
     59   file = fopen("test_obj_plane.obj", "w");
     60   CHK(file != NULL);
     61   fwrite(plane_obj, sizeof(char), strlen(plane_obj), file);
     62   CHK(fclose(file) == 0);
     63 
     64   CHK(aw_obj_load(obj, NULL) == RES_BAD_ARG);
     65   CHK(aw_obj_load(NULL, "test_obj_plane.obj") == RES_BAD_ARG);
     66   CHK(aw_obj_load(obj, "none.obj") == RES_IO_ERR);
     67   CHK(aw_obj_load(obj, "test_obj_plane.obj") == RES_OK);
     68 
     69   CHK(aw_obj_get_desc(NULL, NULL) == RES_BAD_ARG);
     70   CHK(aw_obj_get_desc(obj, NULL) == RES_BAD_ARG);
     71   CHK(aw_obj_get_desc(NULL, &desc) == RES_BAD_ARG);
     72   CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
     73   CHK(desc.faces_count == 1);
     74   CHK(desc.positions_count == 4);
     75   CHK(desc.texcoords_count == 4);
     76   CHK(desc.normals_count == 0);
     77   CHK(desc.groups_count == 1);
     78   CHK(desc.smooth_groups_count == 0);
     79   CHK(desc.usemtls_count == 1);
     80   CHK(desc.mtllibs_count == 1);
     81 
     82   CHK(aw_obj_get_face(NULL, 0, &face) == RES_BAD_ARG);
     83   CHK(aw_obj_get_face(obj, AW_ID_NONE, &face) == RES_BAD_ARG);
     84   CHK(aw_obj_get_face(obj, 0, NULL) == RES_BAD_ARG);
     85   CHK(aw_obj_get_face(obj, 0, &face) == RES_OK);
     86   CHK(face.vertex_id == 0);
     87   CHK(face.vertices_count == 4);
     88   CHK(face.group_id == 0);
     89   CHK(face.smooth_group_id == AW_ID_NONE);
     90   CHK(face.mtl_id == 0);
     91 
     92   CHK(aw_obj_get_mtl(NULL, 0, &mtl) == RES_BAD_ARG);
     93   CHK(aw_obj_get_mtl(obj, AW_ID_NONE, &mtl) == RES_BAD_ARG);
     94   CHK(aw_obj_get_mtl(obj, 0, NULL) == RES_BAD_ARG);
     95   CHK(aw_obj_get_mtl(obj, 0, &mtl) == RES_OK);
     96   CHK(!strcmp(mtl.name, "wood"));
     97   CHK(mtl.face_id == 0);
     98   CHK(mtl.faces_count == 1);
     99 
    100   CHK(aw_obj_get_mtllib(NULL, 0, &mtllib) == RES_BAD_ARG);
    101   CHK(aw_obj_get_mtllib(obj, AW_ID_NONE, &mtllib) == RES_BAD_ARG);
    102   CHK(aw_obj_get_mtllib(obj, 0, NULL) == RES_BAD_ARG);
    103   CHK(aw_obj_get_mtllib(obj, 0, &mtllib) == RES_OK);
    104   CHK(strcmp(mtllib, "master.mtl") == 0);
    105 
    106   CHK(aw_obj_get_vertex(NULL, 0, &vertex) == RES_BAD_ARG);
    107   CHK(aw_obj_get_vertex(obj, AW_ID_NONE, &vertex) == RES_BAD_ARG);
    108   CHK(aw_obj_get_vertex(obj, 0, NULL) == RES_BAD_ARG);
    109   CHK(aw_obj_get_vertex(obj, 0, &vertex) == RES_OK);
    110 
    111   CHK(aw_obj_get_vertex_data(NULL, &vertex, &vdata) == RES_BAD_ARG);
    112   CHK(aw_obj_get_vertex_data(obj, NULL, &vdata) == RES_BAD_ARG);
    113   CHK(aw_obj_get_vertex_data(obj, &vertex, NULL) == RES_BAD_ARG);
    114 
    115   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    116   CHK(d4_eq(vdata.position, d4(v4, 0, 2, 0, 1)));
    117   CHK(d3_eq(vdata.texcoord, d3(v4, 0, 1, 0)));
    118 
    119   vertex.position_id = 4;
    120   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_BAD_ARG);
    121   vertex.position_id = 0;
    122   vertex.texcoord_id = 4;
    123   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_BAD_ARG);
    124   vertex.texcoord_id = 0;
    125   vertex.normal_id = 0;
    126   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_BAD_ARG);
    127 
    128   CHK(aw_obj_get_vertex(obj, 1, &vertex) == RES_OK);
    129   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    130   CHK(d4_eq(vdata.position, d4(v4, 0, 0, 0, 1)));
    131   CHK(d3_eq(vdata.texcoord, d3(v4, 0, 0, 0)));
    132 
    133   CHK(aw_obj_get_vertex(obj, 2, &vertex) == RES_OK);
    134   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    135   CHK(d4_eq(vdata.position, d4(v4, 2, 0, 0, 1)));
    136   CHK(d3_eq(vdata.texcoord, d3(v4, 1, 0, 0)));
    137 
    138   CHK(aw_obj_get_vertex(obj, 3, &vertex) == RES_OK);
    139   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    140   CHK(d4_eq(vdata.position, d4(v4, 2, 2, 0, 1)));
    141   CHK(d3_eq(vdata.texcoord, d3(v4, 1, 1, 0)));
    142 
    143   CHK(aw_obj_get_group(NULL, 0, &group) == RES_BAD_ARG);
    144   CHK(aw_obj_get_group(obj, AW_ID_NONE, &group) == RES_BAD_ARG);
    145   CHK(aw_obj_get_group(obj, 0, NULL) == RES_BAD_ARG);
    146   CHK(aw_obj_get_group(obj, 0, &group) == RES_OK);
    147   CHK(!strcmp(group.name, "default"));
    148   CHK(group.face_id == 0);
    149   CHK(group.faces_count == 1);
    150 
    151   CHK(aw_obj_get_positions(NULL, &data) == RES_BAD_ARG);
    152   CHK(aw_obj_get_positions(obj, NULL) == RES_BAD_ARG);
    153   CHK(aw_obj_get_positions(obj, &data) == RES_OK);
    154   CHK(d4_eq(data+0, d4(v4,0,2,0,1)));
    155   CHK(d4_eq(data+4, d4(v4,0,0,0,1)));
    156   CHK(d4_eq(data+8, d4(v4,2,0,0,1)));
    157   CHK(d4_eq(data+12, d4(v4,2,2,0,1)));
    158 
    159   CHK(aw_obj_get_texcoords(NULL, &data) == RES_BAD_ARG);
    160   CHK(aw_obj_get_texcoords(obj, NULL) == RES_BAD_ARG);
    161   CHK(aw_obj_get_texcoords(obj, &data) == RES_OK);
    162   CHK(d3_eq(data+0, d3(v4,0,1,0)));
    163   CHK(d3_eq(data+3, d3(v4,0,0,0)));
    164   CHK(d3_eq(data+6, d3(v4,1,0,0)));
    165   CHK(d3_eq(data+9, d3(v4,1,1,0)));
    166 }
    167 
    168 static void
    169 test_squares(struct aw_obj* obj)
    170 {
    171   static const char* squares_obj =
    172     "v 0.000000 2.000000 0.000000\n"
    173     "v 0.000000 0.000000 0.000000\n"
    174     "v 2.000000 0.000000 0.000000\n"
    175     "v 2.000000 2.000000 0.000000\n"
    176     "v 4.000000 0.000000 -1.255298\n"
    177     "v 4.000000 2.000000 -1.255298\n"
    178     "vn 0.000000 0.000000 1.000000\n"
    179     "vn 0.000000 0.000000 1.000000\n"
    180     "vn 0.276597 0.000000 0.960986\n"
    181     "vn 0.276597 0.000000 0.960986\n"
    182     "vn 0.531611 0.000000 0.846988\n"
    183     "vn 0.531611 0.000000 0.846988\n"
    184     "# 6 vertices\n"
    185     "\n"
    186     "# 6 normals\n"
    187     "\n"
    188     "g all\n"
    189     "s 1\n"
    190     "f 1//1 2//2 3//3 4//4\n"
    191     "f 4//4 3//3 5//5 6//6\n"
    192     "# 2 elements\n";
    193   double v4[4];
    194   struct aw_obj_desc desc;
    195   struct aw_obj_face face;
    196   struct aw_obj_named_group group;
    197   struct aw_obj_named_group mtl;
    198   struct aw_obj_smooth_group sgroup;
    199   struct aw_obj_vertex vertex;
    200   struct aw_obj_vertex_data vdata;
    201   const double* data = NULL;
    202   FILE* file;
    203 
    204   CHK(obj != NULL);
    205 
    206   file = fopen("test_obj_squares.obj", "w");
    207   CHK(file != NULL);
    208   fwrite(squares_obj, sizeof(char), strlen(squares_obj), file);
    209   CHK(fclose(file) == 0);
    210   CHK(aw_obj_load(obj, "test_obj_squares.obj") == RES_OK);
    211 
    212   CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
    213   CHK(desc.faces_count == 2);
    214   CHK(desc.positions_count == 6);
    215   CHK(desc.texcoords_count == 0);
    216   CHK(desc.normals_count == 6);
    217   CHK(desc.groups_count == 1);
    218   CHK(desc.smooth_groups_count == 1);
    219   CHK(desc.usemtls_count == 0);
    220   CHK(desc.mtllibs_count == 0);
    221 
    222   CHK(aw_obj_get_face(obj, 0, &face) == RES_OK);
    223   CHK(face.vertex_id == 0);
    224   CHK(face.vertices_count == 4);
    225   CHK(face.group_id == 0);
    226   CHK(face.smooth_group_id == 0);
    227   CHK(face.mtl_id == AW_ID_NONE);
    228 
    229   CHK(aw_obj_get_vertex(obj, 0, &vertex) == RES_OK);
    230   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    231   CHK(d4_eq(vdata.position, d4(v4, 0.0, 2.0, 0.0, 1.0)));
    232   CHK(d3_eq(vdata.normal, d3(v4, 0.0, 0.0, 1.0)));
    233   CHK(aw_obj_get_vertex(obj, 1, &vertex) == RES_OK);
    234   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    235   CHK(d4_eq(vdata.position, d4(v4, 0.0, 0.0, 0.0, 1.0)));
    236   CHK(d3_eq(vdata.normal, d3(v4, 0.0, 0.0, 1.0)));
    237   CHK(aw_obj_get_vertex(obj, 2, &vertex) == RES_OK);
    238   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    239   CHK(d4_eq(vdata.position, d4(v4, 2.0, 0.0, 0.0, 1.0)));
    240   CHK(d3_eq(vdata.normal, d3(v4, 0.276597, 0.0, 0.960986)));
    241   CHK(aw_obj_get_vertex(obj, 3, &vertex) == RES_OK);
    242   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    243   CHK(d4_eq(vdata.position, d4(v4, 2.0, 2.0, 0.0, 1.0)));
    244   CHK(d3_eq(vdata.normal, d3(v4, 0.276597, 0.0, 0.960986)));
    245 
    246   CHK(aw_obj_get_face(obj, 1, &face) == RES_OK);
    247   CHK(face.vertex_id == 4);
    248   CHK(face.vertices_count == 4);
    249   CHK(face.group_id == 0);
    250   CHK(face.smooth_group_id == 0);
    251   CHK(face.mtl_id == AW_ID_NONE);
    252 
    253   CHK(aw_obj_get_vertex(obj, 4, &vertex) == RES_OK);
    254   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    255   CHK(d4_eq(vdata.position, d4(v4, 2.0, 2.0, 0.0, 1.0)));
    256   CHK(d3_eq(vdata.normal, d3(v4, 0.276597, 0.0, 0.960986)));
    257   CHK(aw_obj_get_vertex(obj, 5, &vertex) == RES_OK);
    258   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    259   CHK(d4_eq(vdata.position, d4(v4, 2.0, 0.0, 0.0, 1.0)));
    260   CHK(d3_eq(vdata.normal, d3(v4, 0.276597, 0.0, 0.960986)));
    261   CHK(aw_obj_get_vertex(obj, 6, &vertex) == RES_OK);
    262   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    263   CHK(d4_eq(vdata.position, d4(v4, 4.0, 0.0, -1.255298, 1.0)));
    264   CHK(d3_eq(vdata.normal, d3(v4, 0.531611, 0.0, 0.8469880)));
    265   CHK(aw_obj_get_vertex(obj, 7, &vertex) == RES_OK);
    266   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    267   CHK(d4_eq(vdata.position, d4(v4, 4.0, 2.0, -1.255298, 1.0)) == 1);
    268   CHK(d3_eq(vdata.normal, d3(v4, 0.531611, 0.0, 0.846988)) == 1);
    269 
    270   CHK(aw_obj_get_group(NULL, 0, &group) == RES_BAD_ARG);
    271   CHK(aw_obj_get_group(obj, AW_ID_NONE, &group) == RES_BAD_ARG);
    272   CHK(aw_obj_get_group(obj, 0, NULL) == RES_BAD_ARG);
    273   CHK(aw_obj_get_group(obj, 0, &group) == RES_OK);
    274   CHK(strcmp(group.name, "all") == 0);
    275   CHK(group.face_id == 0);
    276   CHK(group.faces_count == 2);
    277 
    278   CHK(aw_obj_get_smooth_group(NULL, 0, &sgroup) == RES_BAD_ARG);
    279   CHK(aw_obj_get_smooth_group(obj, AW_ID_NONE, &sgroup) == RES_BAD_ARG);
    280   CHK(aw_obj_get_smooth_group(obj, 0, NULL) == RES_BAD_ARG);
    281   CHK(aw_obj_get_smooth_group(obj, 0, &sgroup) == RES_OK);
    282   CHK(sgroup.is_smoothed == 1);
    283   CHK(sgroup.face_id == 0);
    284   CHK(sgroup.faces_count == 2);
    285 
    286   CHK(aw_obj_get_mtl(obj, 0, &mtl) == RES_BAD_ARG);
    287 
    288   CHK(aw_obj_get_positions(obj, &data) == RES_OK);
    289   CHK(d4_eq(data+0, d4(v4,0,2,0,1)));
    290   CHK(d4_eq(data+4, d4(v4,0,0,0,1)));
    291   CHK(d4_eq(data+8, d4(v4,2,0,0,1)));
    292   CHK(d4_eq(data+12, d4(v4,2,2,0,1)));
    293   CHK(d4_eq(data+16, d4(v4,4,0,-1.255298,1)));
    294   CHK(d4_eq(data+20, d4(v4,4,2,-1.255298,1)));
    295 
    296   CHK(aw_obj_get_normals(NULL, &data) == RES_BAD_ARG);
    297   CHK(aw_obj_get_normals(obj, NULL) == RES_BAD_ARG);
    298   CHK(aw_obj_get_normals(obj, &data) == RES_OK);
    299   CHK(d3_eq(data+0, d3(v4,0,0,1)));
    300   CHK(d3_eq(data+3, d3(v4,0,0,1)));
    301   CHK(d3_eq(data+6, d3(v4,0.276597,0,0.960986)));
    302   CHK(d3_eq(data+9, d3(v4,0.276597,0,0.960986)));
    303   CHK(d3_eq(data+12, d3(v4,0.531611,0,0.846988)));
    304   CHK(d3_eq(data+15, d3(v4,0.531611,0,0.846988)));
    305 }
    306 
    307 static void
    308 test_cube(struct aw_obj* obj)
    309 {
    310   static const char* cube_obj =
    311     "# Cube with a different material applied to each of its faces\n"
    312     "mtllib master.mtl hop.mtl\n"
    313     "mtllib my.mtl\n"
    314     "v\t0.0000 2.0000 2.0000\n"
    315     "v 0.0000 0.0000 2.0000\n"
    316     "v 2.0000 0.0000 2.0000\n"
    317     "v 2.0000 2.0000 2.0000\n"
    318     "v 0.0000 2.0000 0.0000\n"
    319     "v 0.0000 0.0000 0.0000\n"
    320     "v 2.0000 0.0000 0.0000\n"
    321     "v 2.0000 2.0000 0.0000\n"
    322     "# 8 vertices\n"
    323     "g front\n"
    324     "usemtl red\n"
    325     "f 1\t\t\t 2 3 4\n"
    326     "g back\n"
    327     "usemtl blue\n"
    328     "f 8 7 6 5\n"
    329     "g right\n"
    330     "usemtl green\n"
    331     "f 4 3 7 8\n"
    332     "g top\n"
    333     "usemtl\tgold\n"
    334     "f 5 1\t4 8\n"
    335     "g left\n"
    336     "usemtl orange\n"
    337     "f 5 6 2 1\n"
    338     "g bottom\n"
    339     "usemtl purple\n"
    340     "f 2 6 7 3\n"
    341     "# 6 elements\n";
    342   double v4[4];
    343   const char* group_names[6] =
    344     { "front", "back", "right", "top", "left", "bottom" };
    345   const char* mtl_names[6] =
    346     { "red", "blue", "green", "gold", "orange", "purple" };
    347   struct aw_obj_desc desc;
    348   FILE* file;
    349   const char* mtllib;
    350   const double* data;
    351   size_t i;
    352 
    353   CHK(obj != NULL);
    354 
    355   file = fopen("test_obj_cube.obj", "w+");
    356   CHK(file != NULL);
    357   fwrite(cube_obj, sizeof(char), strlen(cube_obj), file);
    358   CHK(fseek(file, 0, SEEK_SET) == 0);
    359 
    360   CHK(aw_obj_load_stream(obj, NULL, NULL) == RES_BAD_ARG);
    361   CHK(aw_obj_load_stream(NULL, file, NULL) == RES_BAD_ARG);
    362   CHK(aw_obj_load_stream(obj, file, NULL) == RES_OK);
    363 
    364   CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
    365   CHK(desc.faces_count == 6);
    366   CHK(desc.positions_count == 8);
    367   CHK(desc.texcoords_count == 0);
    368   CHK(desc.normals_count == 0);
    369   CHK(desc.groups_count == 6);
    370   CHK(desc.smooth_groups_count == 0);
    371   CHK(desc.usemtls_count == 6);
    372   CHK(desc.mtllibs_count == 3);
    373 
    374   CHK(aw_obj_clear(NULL) == RES_BAD_ARG);
    375   CHK(aw_obj_clear(obj) == RES_OK);
    376   CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
    377   CHK(desc.faces_count == 0);
    378   CHK(desc.groups_count == 0);
    379   CHK(desc.smooth_groups_count == 0);
    380   CHK(desc.usemtls_count == 0);
    381   CHK(desc.mtllibs_count == 0);
    382 
    383   CHK(fseek(file, 0, SEEK_SET) == 0);
    384   CHK(aw_obj_load_stream(obj, file, "cube") == RES_OK);
    385   CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
    386 
    387   FOR_EACH(i, 0, 6) {
    388     struct aw_obj_face face;
    389     CHK(aw_obj_get_face(obj, i, &face) == RES_OK);
    390     CHK(face.vertex_id == i*4);
    391     CHK(face.vertices_count == 4);
    392     CHK(face.group_id == i);
    393     CHK(face.smooth_group_id == AW_ID_NONE);
    394     CHK(face.mtl_id == i);
    395   }
    396 
    397   FOR_EACH(i, 0, 6) {
    398     struct aw_obj_named_group group;
    399     CHK(aw_obj_get_group(obj, i, &group) == RES_OK);
    400     CHK(!strcmp(group.name, group_names[i]));
    401     CHK(group.face_id == i);
    402     CHK(group.faces_count == 1);
    403   }
    404 
    405   FOR_EACH(i, 0, 6) {
    406     struct aw_obj_named_group mtl;
    407     CHK(aw_obj_get_mtl(obj, i, &mtl) == RES_OK);
    408     CHK(!strcmp(mtl.name, mtl_names[i]));
    409     CHK(mtl.face_id == i);
    410     CHK(mtl.faces_count == 1);
    411   }
    412 
    413   CHK(aw_obj_get_mtllib(obj, 0, &mtllib) == RES_OK);
    414   CHK(!strcmp(mtllib, "master.mtl"));
    415   CHK(aw_obj_get_mtllib(obj, 1, &mtllib) == RES_OK);
    416   CHK(!strcmp(mtllib, "hop.mtl"));
    417   CHK(aw_obj_get_mtllib(obj, 2, &mtllib) == RES_OK);
    418   CHK(!strcmp(mtllib, "my.mtl"));
    419   CHK(aw_obj_get_mtllib(obj, 3, &mtllib) == RES_BAD_ARG);
    420 
    421   CHK(aw_obj_get_positions(obj, &data) == RES_OK);
    422   CHK(d4_eq(data+0, d4(v4,0,2,2,1)));
    423   CHK(d4_eq(data+4, d4(v4,0,0,2,1)));
    424   CHK(d4_eq(data+8, d4(v4,2,0,2,1)));
    425   CHK(d4_eq(data+12, d4(v4,2,2,2,1)));
    426   CHK(d4_eq(data+16, d4(v4,0,2,0,1)));
    427   CHK(d4_eq(data+20, d4(v4,0,0,0,1)));
    428   CHK(d4_eq(data+24, d4(v4,2,0,0,1)));
    429   CHK(d4_eq(data+28, d4(v4,2,2,0,1)));
    430 
    431   CHK(aw_obj_purge(NULL) == RES_BAD_ARG);
    432   CHK(aw_obj_purge(obj) == RES_OK);
    433   CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
    434   CHK(desc.faces_count == 0);
    435   CHK(desc.groups_count == 0);
    436   CHK(desc.smooth_groups_count == 0);
    437   CHK(desc.usemtls_count == 0);
    438   CHK(desc.mtllibs_count == 0);
    439 
    440   CHK(fclose(file) == 0);
    441 }
    442 
    443 static void
    444 test_cbox(struct aw_obj* obj)
    445 {
    446   static const char* cbox_obj =
    447     "mtllib cbox.mtl\n"
    448     "v -1.01 0 0.99\n"
    449     "v 1 0 0.99\n"
    450     "v 1 0 -1.04\n"
    451     "v -0.99  0 -1.04\n"
    452     "g floor\n"
    453     "usemtl floor\n"
    454     "f -4 -3 -2 -1\n"
    455 
    456     "v -1.02 1.99 0.99\n"
    457     "v -1.02 1.99 -1.04\n"
    458     "v 1 1.99 -1.04\n"
    459     "v 1 1.99 0.99\n"
    460     "g ceiling\n"
    461     "usemtl ceiling\n"
    462     "f -4 -3 -2 -1\n"
    463 
    464     "v -0.99 0 -1.04\n"
    465     "v 1 0 -1.04\n"
    466     "v 1 1.99 -1.04\n"
    467     "v -1.02 1.99 -1.04\n"
    468     "g back\n"
    469     "usemtl back\n"
    470     "f -4 -3 -2 -1\n"
    471 
    472     "v 1 0 -1.04\n"
    473     "v 1 0 0.99\n"
    474     "v 1 1.99 0.99\n"
    475     "v 1 1.99 -1.04\n"
    476     "g right\n"
    477     "usemtl right\n"
    478     "f -4 -3 -2 -1\n"
    479 
    480     "v -1.01 0 0.99\n"
    481     "v -0.99 0 -1.04\n"
    482     "v -1.02 1.99 -1.04\n"
    483     "v -1.02 1.99 0.99\n"
    484     "g left\n"
    485     "usemtl left\n"
    486     "f -4 -3 -2 -1";
    487   struct aw_obj_desc desc;
    488   struct aw_obj_face face;
    489   struct aw_obj_vertex vertex;
    490   struct aw_obj_vertex_data vdata;
    491   struct aw_obj_named_group group;
    492   struct aw_obj_named_group mtl;
    493   double v4[4];
    494   double tmp[3];
    495   const double* data;
    496   FILE* file;
    497 
    498   CHK(obj != NULL);
    499 
    500   file = fopen("test_cbox.obj", "w+");
    501   CHK(file != NULL);
    502   fwrite(cbox_obj, sizeof(char), strlen(cbox_obj), file);
    503   CHK(fseek(file, 0, SEEK_SET) == 0);
    504   CHK(aw_obj_load_stream(obj, file, "cbox") == RES_OK);
    505   CHK(fclose(file) == 0);
    506 
    507   CHK(aw_obj_get_desc(obj, &desc) == RES_OK);
    508   CHK(desc.faces_count == 5);
    509   CHK(desc.positions_count == 20);
    510   CHK(desc.texcoords_count == 0);
    511   CHK(desc.normals_count == 0);
    512   CHK(desc.groups_count == 5);
    513   CHK(desc.smooth_groups_count == 0);
    514   CHK(desc.usemtls_count == 5);
    515   CHK(desc.mtllibs_count == 1);
    516 
    517   CHK(aw_obj_get_face(obj, 0, &face) == RES_OK);
    518   CHK(face.vertex_id == 0);
    519   CHK(face.vertices_count == 4);
    520   CHK(face.group_id == 0);
    521   CHK(face.mtl_id == 0);
    522 
    523   CHK(aw_obj_get_group(obj, 0, &group) == RES_OK);
    524   CHK(!strcmp(group.name, "floor"));
    525   CHK(group.face_id == 0);
    526   CHK(group.faces_count == 1);
    527 
    528   CHK(aw_obj_get_mtl(obj, 0, &mtl) == RES_OK);
    529   CHK(!strcmp(mtl.name, "floor"));
    530   CHK(mtl.face_id == 0);
    531   CHK(mtl.faces_count == 1);
    532 
    533   CHK(aw_obj_get_vertex(obj, 0, &vertex) == RES_OK);
    534   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    535   CHK(d3_eq_eps(vdata.position, d3(tmp, -1.01, 0.0, 0.99), 1.e-6));
    536   CHK(aw_obj_get_vertex(obj, 1, &vertex) == RES_OK);
    537   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    538   CHK(d3_eq_eps(vdata.position, d3(tmp, 1.0, 0.0, 0.99), 1.e-6));
    539   CHK(aw_obj_get_vertex(obj, 2, &vertex) == RES_OK);
    540   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    541   CHK(d3_eq_eps(vdata.position, d3(tmp, 1.f, 0.0, -1.04), 1.e-6));
    542   CHK(aw_obj_get_vertex(obj, 3, &vertex) == RES_OK);
    543   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    544   CHK(d3_eq_eps(vdata.position, d3(tmp, -0.99, 0.0, -1.04), 1.e-6));
    545 
    546   CHK(aw_obj_get_face(obj, 1, &face) == RES_OK);
    547   CHK(face.vertex_id == 4);
    548   CHK(face.vertices_count == 4);
    549   CHK(face.group_id == 1);
    550   CHK(face.mtl_id == 1);
    551 
    552   CHK(aw_obj_get_group(obj, 1, &group) == RES_OK);
    553   CHK(!strcmp(group.name, "ceiling"));
    554   CHK(group.face_id == 1);
    555   CHK(group.faces_count == 1);
    556 
    557   CHK(aw_obj_get_mtl(obj, 1, &mtl) == RES_OK);
    558   CHK(!strcmp(mtl.name, "ceiling"));
    559   CHK(mtl.face_id == 1);
    560   CHK(mtl.faces_count == 1);
    561 
    562   CHK(aw_obj_get_vertex(obj, 4, &vertex) == RES_OK);
    563   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    564   CHK(d3_eq_eps(vdata.position, d3(tmp, -1.02, 1.99, 0.99), 1.e-6));
    565   CHK(aw_obj_get_vertex(obj, 5, &vertex) == RES_OK);
    566   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    567   CHK(d3_eq_eps(vdata.position, d3(tmp, -1.02, 1.99, -1.04), 1.e-6f));
    568   CHK(aw_obj_get_vertex(obj, 6, &vertex) == RES_OK);
    569   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    570   CHK(d3_eq_eps(vdata.position, d3(tmp, 1.0, 1.99, -1.04), 1.e-6f));
    571   CHK(aw_obj_get_vertex(obj, 7, &vertex) == RES_OK);
    572   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    573   CHK(d3_eq_eps(vdata.position, d3(tmp, 1.0, 1.99, 0.99), 1.e-6f));
    574 
    575   CHK(aw_obj_get_face(obj, 4, &face) == RES_OK);
    576   CHK(face.vertex_id == 16);
    577   CHK(face.vertices_count == 4);
    578   CHK(face.group_id == 4);
    579   CHK(face.mtl_id == 4);
    580 
    581   CHK(aw_obj_get_group(obj, 4, &group) == RES_OK);
    582   CHK(!strcmp(group.name, "left"));
    583   CHK(group.face_id == 4);
    584   CHK(group.faces_count == 1);
    585 
    586   CHK(aw_obj_get_mtl(obj, 4, &mtl) == RES_OK);
    587   CHK(!strcmp(mtl.name, "left"));
    588   CHK(mtl.face_id == 4);
    589   CHK(mtl.faces_count == 1);
    590 
    591   CHK(aw_obj_get_vertex(obj, 16, &vertex) == RES_OK);
    592   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    593   CHK(d3_eq_eps(vdata.position, d3(tmp, -1.01, 0.0, 0.99), 1.e-6));
    594   CHK(aw_obj_get_vertex(obj, 17, &vertex) == RES_OK);
    595   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    596   CHK(d3_eq_eps(vdata.position, d3(tmp, -0.99, 0.0, -1.04), 1.e-6));
    597   CHK(aw_obj_get_vertex(obj, 18, &vertex) == RES_OK);
    598   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    599   CHK(d3_eq_eps(vdata.position, d3(tmp, -1.02, 1.99, -1.04), 1.e-6));
    600   CHK(aw_obj_get_vertex(obj, 19, &vertex) == RES_OK);
    601   CHK(aw_obj_get_vertex_data(obj, &vertex, &vdata) == RES_OK);
    602   CHK(d3_eq_eps(vdata.position, d3(tmp, -1.02, 1.99, 0.99), 1.e-6));
    603 
    604   CHK(aw_obj_get_positions(obj, &data) == RES_OK);
    605   CHK(d4_eq(data+0, d4(v4,-1.01,0,0.99,1)));
    606   CHK(d4_eq(data+4, d4(v4,1,0,0.99,1)));
    607   CHK(d4_eq(data+8, d4(v4,1,0,-1.04,1)));
    608   CHK(d4_eq(data+12, d4(v4,-0.99,0,-1.04,1)));
    609   CHK(d4_eq(data+16, d4(v4,-1.02,1.99,0.99,1)));
    610   CHK(d4_eq(data+20, d4(v4,-1.02,1.99,-1.04,1)));
    611   CHK(d4_eq(data+24, d4(v4,1,1.99,-1.04,1)));
    612   CHK(d4_eq(data+28, d4(v4,1,1.99,0.99,1)));
    613   CHK(d4_eq(data+32, d4(v4,-0.99,0,-1.04,1)));
    614   CHK(d4_eq(data+36, d4(v4,1,0,-1.04,1)));
    615   CHK(d4_eq(data+40, d4(v4,1,1.99,-1.04,1)));
    616   CHK(d4_eq(data+44, d4(v4,-1.02,1.99,-1.04,1)));
    617   CHK(d4_eq(data+48, d4(v4,1,0,-1.04,1)));
    618   CHK(d4_eq(data+52, d4(v4,1,0,0.99,1)));
    619   CHK(d4_eq(data+56, d4(v4,1,1.99,0.99,1)));
    620   CHK(d4_eq(data+60, d4(v4,1,1.99,-1.04,1)));
    621   CHK(d4_eq(data+64, d4(v4,-1.01,0,0.99,1)));
    622   CHK(d4_eq(data+68, d4(v4,-0.99,0,-1.04,1)));
    623   CHK(d4_eq(data+72, d4(v4,-1.02,1.99,-1.04,1)));
    624   CHK(d4_eq(data+76, d4(v4,-1.02,1.99,0.99,1)));
    625 }
    626 
    627 int
    628 main(int argc, char** argv)
    629 {
    630   struct mem_allocator allocator;
    631   struct aw_obj* obj;
    632   int i;
    633 
    634   mem_init_proxy_allocator(&allocator, &mem_default_allocator);
    635 
    636   CHK(aw_obj_create(LOGGER_DEFAULT, NULL, 1, NULL) == RES_BAD_ARG);
    637   CHK(aw_obj_create(LOGGER_DEFAULT, &allocator, 1, NULL) == RES_BAD_ARG);
    638   CHK(aw_obj_create(LOGGER_DEFAULT, NULL, 1, &obj) == RES_OK);
    639 
    640   CHK(aw_obj_ref_get(NULL) == RES_BAD_ARG);
    641   CHK(aw_obj_ref_get(obj) == RES_OK);
    642   CHK(aw_obj_ref_put(NULL) == RES_BAD_ARG);
    643   CHK(aw_obj_ref_put(obj) == RES_OK);
    644   CHK(aw_obj_ref_put(obj) == RES_OK);
    645 
    646   CHK(aw_obj_create(NULL, &allocator, 1, &obj) == RES_OK);
    647 
    648   test_plane(obj);
    649   test_squares(obj);
    650   test_cube(obj);
    651   test_cbox(obj);
    652   FOR_EACH(i, 1, argc)
    653     CHK(aw_obj_load(obj, argv[i]) == RES_OK);
    654 
    655   CHK(aw_obj_ref_put(obj) == RES_OK);
    656 
    657   if(MEM_ALLOCATED_SIZE(&allocator)) {
    658     char dump[512];
    659     MEM_DUMP(&allocator, dump, sizeof(dump)/sizeof(char));
    660     fprintf(stderr, "%s\n", dump);
    661     FATAL("Memory leaks\n");
    662   }
    663   mem_shutdown_proxy_allocator(&allocator);
    664   CHK(mem_allocated_size() == 0);
    665   return 0;
    666 }
    667