star-3d

Surface structuring for efficient 3D geometric queries
git clone git://git.meso-star.fr/star-3d.git
Log | Files | Refs | README | LICENSE

test_s3d_scene_view.c (35455B)


      1 /* Copyright (C) 2015-2023 |Méso|Star> (contact@meso-star.com)
      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 General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "s3d.h"
     17 #include "test_s3d_utils.h"
     18 
     19 #include <rsys/float3.h>
     20 #include <rsys/float2.h>
     21 
     22 #include <string.h>
     23 
     24 struct mesh_context {
     25   const float* verts;
     26   const unsigned* ids;
     27 };
     28 
     29 static int
     30 filter
     31   (const struct s3d_hit* hit,
     32    const float org[3],
     33    const float dir[3],
     34    const float range[2],
     35    void* ray_data,
     36    void* filter_data)
     37 {
     38   (void)org, (void)dir, (void)range, (void)ray_data, (void)filter_data;
     39   CHK(S3D_HIT_NONE(hit) == 0);
     40   return hit->prim.prim_id % 2 == 0;
     41 }
     42 
     43 /*******************************************************************************
     44  * Cube data
     45  ******************************************************************************/
     46 static const float cube_verts[] = {
     47   0.f, 0.f, 0.f,
     48   1.f, 0.f, 0.f,
     49   0.f, 1.f, 0.f,
     50   1.f, 1.f, 0.f,
     51   0.f, 0.f, 1.f,
     52   1.f, 0.f, 1.f,
     53   0.f, 1.f, 1.f,
     54   1.f, 1.f, 1.f
     55 };
     56 static const unsigned cube_nverts = sizeof(cube_verts) / (sizeof(float)*3);
     57 
     58 /* Front faces are CW. The normals point into the cube */
     59 static const unsigned cube_ids[] = {
     60   0, 2, 1, 1, 2, 3, /* Front */
     61   0, 4, 2, 2, 4, 6, /* Left */
     62   4, 5, 6, 6, 5, 7, /* Back */
     63   3, 7, 1, 1, 7, 5, /* Right */
     64   2, 6, 3, 3, 6, 7, /* Top */
     65   0, 1, 4, 4, 1, 5 /* Bottom */
     66 };
     67 static const unsigned cube_ntris = sizeof(cube_ids) / (sizeof(unsigned)*3);
     68 
     69 /*******************************************************************************
     70  * Plane data
     71  ******************************************************************************/
     72 static const float plane_verts[] = {
     73   0.f, 0.f, 0.5f,
     74   1.f, 0.f, 0.5f,
     75   1.f, 1.f, 0.5f,
     76   0.f, 1.f, 0.5f
     77 };
     78 static const unsigned plane_nverts = sizeof(plane_verts) / (sizeof(float)*3);
     79 
     80 static const unsigned plane_ids[] = { 0, 1, 2, 2, 3, 0 };
     81 static const unsigned plane_ntris = sizeof(plane_ids) / (sizeof(unsigned)*3);
     82 
     83 /*******************************************************************************
     84  * helper function
     85  ******************************************************************************/
     86 static void
     87 get_ids(const unsigned itri, unsigned ids[3], void* data)
     88 {
     89   const unsigned id = itri * 3;
     90   const struct mesh_context* ctx = data;
     91   CHK(ctx != NULL);
     92   CHK(ids != NULL);
     93   ids[0] = ctx->ids[id + 0];
     94   ids[1] = ctx->ids[id + 1];
     95   ids[2] = ctx->ids[id + 2];
     96 }
     97 
     98 static void
     99 get_pos(const unsigned ivert, float pos[3], void* data)
    100 {
    101   const unsigned i = ivert*3;
    102   const struct mesh_context* ctx = data;
    103   CHK(ctx != NULL);
    104   CHK(pos != NULL);
    105   pos[0] = ctx->verts[i + 0];
    106   pos[1] = ctx->verts[i + 1];
    107   pos[2] = ctx->verts[i + 2];
    108 }
    109 
    110 static void
    111 test_miscellaneous
    112   (struct s3d_device* dev,
    113    struct s3d_shape* cube,
    114    struct s3d_shape* plane)
    115 {
    116   struct s3d_scene* scn;
    117   struct s3d_scene_view* scnview;
    118   float V;
    119   float A;
    120   int mask;
    121 
    122   CHK(s3d_scene_create(dev, &scn) == RES_OK);
    123   CHK(s3d_scene_attach_shape(scn, cube) == RES_OK);
    124   CHK(s3d_scene_attach_shape(scn, plane) == RES_OK);
    125 
    126   CHK(s3d_scene_view_create(NULL, 0, NULL) == RES_BAD_ARG);
    127   CHK(s3d_scene_view_create(scn, 0, NULL) == RES_BAD_ARG);
    128   CHK(s3d_scene_view_create(NULL, S3D_SAMPLE, NULL) == RES_BAD_ARG);
    129   CHK(s3d_scene_view_create(scn, S3D_SAMPLE, NULL) == RES_BAD_ARG);
    130   CHK(s3d_scene_view_create(NULL, 0, &scnview) == RES_BAD_ARG);
    131   CHK(s3d_scene_view_create(NULL, S3D_SAMPLE, &scnview) == RES_BAD_ARG);
    132   CHK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview) == RES_OK);
    133 
    134   CHK(s3d_scene_view_get_mask(NULL, NULL) == RES_BAD_ARG);
    135   CHK(s3d_scene_view_get_mask(scnview, NULL) == RES_BAD_ARG);
    136   CHK(s3d_scene_view_get_mask(NULL, &mask) == RES_BAD_ARG);
    137   CHK(s3d_scene_view_get_mask(scnview, &mask) == RES_OK);
    138   CHK(mask == S3D_SAMPLE);
    139 
    140   CHK(s3d_scene_view_ref_get(NULL) == RES_BAD_ARG);
    141   CHK(s3d_scene_view_ref_get(scnview) == RES_OK);
    142   CHK(s3d_scene_view_ref_put(NULL) == RES_BAD_ARG);
    143   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    144   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    145 
    146   CHK(s3d_scene_view_create(scn, S3D_TRACE|S3D_GET_PRIMITIVE, &scnview) == RES_OK);
    147   CHK(s3d_scene_view_get_mask(scnview, &mask) == RES_OK);
    148   CHK((mask & S3D_TRACE) == S3D_TRACE);
    149   CHK((mask & S3D_GET_PRIMITIVE) == S3D_GET_PRIMITIVE);
    150   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    151 
    152   CHK(s3d_scene_view_create(scn, S3D_SAMPLE|S3D_GET_PRIMITIVE, &scnview) == RES_OK);
    153   CHK(s3d_scene_view_get_mask(scnview, &mask) == RES_OK);
    154   CHK((mask & S3D_SAMPLE) == S3D_SAMPLE);
    155   CHK((mask & S3D_GET_PRIMITIVE) == S3D_GET_PRIMITIVE);
    156   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    157 
    158   CHK(s3d_scene_detach_shape(scn, plane) == RES_OK);
    159   CHK(s3d_scene_view_create(scn, 0, &scnview) == RES_OK);
    160   CHK(s3d_scene_view_get_mask(scnview, &mask) == RES_OK);
    161   CHK(mask == 0);
    162   CHK(s3d_scene_view_compute_volume(scnview, &V) == RES_OK);
    163   CHK(s3d_scene_view_compute_area(scnview, &A) == RES_OK);
    164   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    165   CHK(eq_eps(A, 6.f, 1.e-6f));
    166   CHK(eq_eps(V, 1.f, 1.e-6f));
    167 
    168   CHK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview) == RES_OK);
    169   CHK(s3d_scene_view_compute_volume(scnview, &V) == RES_OK);
    170   CHK(s3d_scene_view_compute_area(scnview, &A) == RES_OK);
    171   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    172   CHK(eq_eps(A, 6.f, 1.e-6f));
    173   CHK(eq_eps(V, 1.f, 1.e-6f));
    174 
    175   CHK(s3d_scene_ref_put(scn) == RES_OK);
    176 }
    177 
    178 static void
    179 test_trace_ray
    180   (struct s3d_device* dev,
    181    struct s3d_shape* cube,
    182    struct s3d_shape* plane)
    183 {
    184   struct s3d_scene* scn;
    185   struct s3d_scene* scn2;
    186   struct s3d_scene* scn3;
    187   struct s3d_scene_view* scnview;
    188   struct s3d_scene_view* scnview2;
    189   struct s3d_scene_view* scnview3;
    190   struct s3d_shape* inst0;
    191   struct s3d_shape* inst1;
    192   struct s3d_hit hit, hit2;
    193   float org[3], dir[3], range[2];
    194   unsigned icube;
    195   unsigned iplane;
    196   unsigned iinst0;
    197   unsigned iinst1;
    198 
    199   f3(org, 0.5f, 0.25f, 0.25f);
    200   f3(dir, 0.f, 0.f, 1.f);
    201   f2(range, 0.f, FLT_MAX);
    202 
    203   CHK(s3d_shape_get_id(cube, &icube) == RES_OK);
    204   CHK(s3d_shape_get_id(plane, &iplane) == RES_OK);
    205 
    206   CHK(s3d_scene_create(dev, &scn) == RES_OK);
    207   CHK(s3d_scene_create(dev, &scn2) == RES_OK);
    208   CHK(s3d_scene_create(dev, &scn3) == RES_OK);
    209 
    210   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview) == RES_OK);
    211   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    212   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    213 
    214   CHK(s3d_scene_attach_shape(scn, plane) == RES_OK);
    215   CHK(s3d_scene_attach_shape(scn, cube) == RES_OK);
    216   CHK(s3d_scene_attach_shape(scn2, cube) == RES_OK);
    217   CHK(s3d_scene_attach_shape(scn2, plane) == RES_OK);
    218 
    219   CHK(s3d_scene_view_create(scn, S3D_SAMPLE|S3D_GET_PRIMITIVE, &scnview) == RES_OK);
    220 
    221   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_BAD_OP);
    222 
    223   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview2) == RES_OK);
    224   CHK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit) == RES_OK);
    225   CHK(S3D_HIT_NONE(&hit) == 0);
    226   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    227   CHK(hit.prim.geom_id == iplane);
    228   CHK(hit.prim.prim_id == 0);
    229 
    230   f3(dir, 0.f, 0.f, -1.f);
    231   CHK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit) == RES_OK);
    232   CHK(S3D_HIT_NONE(&hit) == 0);
    233   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    234   CHK(hit.prim.geom_id == icube);
    235   CHK(hit.prim.prim_id == 0);
    236   f3(dir, 0.f, 0.f, 1.f);
    237 
    238   CHK(s3d_shape_enable(plane, 0) == RES_OK);
    239   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    240   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview) == RES_OK);
    241 
    242   CHK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit) == RES_OK);
    243   CHK(S3D_HIT_NONE(&hit) == 0);
    244   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    245   CHK(hit.prim.geom_id == iplane);
    246   CHK(hit.prim.prim_id == 0);
    247 
    248   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    249   CHK(S3D_HIT_NONE(&hit) == 0);
    250   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    251   CHK(hit.prim.geom_id == icube);
    252   CHK(hit.prim.prim_id == 4);
    253 
    254   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    255   CHK(s3d_scene_view_ref_put(scnview2) == RES_OK);
    256   CHK(s3d_shape_enable(plane, 1) == RES_OK);
    257 
    258   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview) == RES_OK);
    259   CHK(s3d_scene_view_create(scn2, S3D_TRACE, &scnview2) == RES_OK);
    260 
    261   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    262   CHK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit2) == RES_OK);
    263   CHK(f3_eq(hit.normal, hit2.normal) == 1);
    264   CHK(f2_eq(hit.uv, hit2.uv) == 1);
    265   CHK(hit.distance == hit2.distance);
    266   CHK(S3D_PRIMITIVE_EQ(&hit.prim, &hit2.prim) == 1);
    267   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    268   CHK(hit.prim.geom_id == iplane);
    269   CHK(hit.prim.prim_id == 0);
    270 
    271   CHK(s3d_scene_detach_shape(scn2, plane) == RES_OK);
    272   CHK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit2) == RES_OK);
    273   CHK(f3_eq(hit.normal, hit2.normal) == 1);
    274   CHK(f2_eq(hit.uv, hit2.uv) == 1);
    275   CHK(hit.distance == hit2.distance);
    276   CHK(S3D_PRIMITIVE_EQ(&hit.prim, &hit2.prim) == 1);
    277 
    278   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    279   CHK(s3d_scene_view_ref_put(scnview2) == RES_OK);
    280 
    281   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview) == RES_OK);
    282   CHK(s3d_scene_view_create(scn2, S3D_TRACE, &scnview2) == RES_OK);
    283 
    284   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    285   CHK(f3_eq(hit.normal, hit2.normal) == 1);
    286   CHK(f2_eq(hit.uv, hit2.uv) == 1);
    287   CHK(hit.distance == hit2.distance);
    288   CHK(S3D_PRIMITIVE_EQ(&hit.prim, &hit2.prim) == 1);
    289   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    290   CHK(hit.prim.geom_id == iplane);
    291   CHK(hit.prim.prim_id == 0);
    292 
    293   CHK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit2) == RES_OK);
    294   CHK(hit2.prim.inst_id == S3D_INVALID_ID);
    295   CHK(hit2.prim.geom_id == icube);
    296   CHK(hit2.prim.prim_id == 4);
    297 
    298   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    299   CHK(s3d_scene_view_ref_put(scnview2) == RES_OK);
    300 
    301   CHK(s3d_scene_instantiate(scn2, &inst0) == RES_OK);
    302   CHK(s3d_scene_instantiate(scn2, &inst1) == RES_OK);
    303   CHK(s3d_shape_get_id(inst0, &iinst0) == RES_OK);
    304   CHK(s3d_shape_get_id(inst1, &iinst1) == RES_OK);
    305   CHK(s3d_instance_translate
    306     (inst0, S3D_WORLD_TRANSFORM, f3(org,-2.f, 0.f, 0.f)) == RES_OK);
    307   CHK(s3d_instance_translate
    308     (inst1, S3D_WORLD_TRANSFORM, f3(org, 2.f, 0.f, 0.f)) == RES_OK);
    309 
    310   CHK(s3d_scene_attach_shape(scn3, inst0) == RES_OK);
    311   CHK(s3d_scene_attach_shape(scn3, inst1) == RES_OK);
    312   CHK(s3d_scene_attach_shape(scn, inst0) == RES_OK);
    313   CHK(s3d_scene_attach_shape(scn, inst1) == RES_OK);
    314 
    315   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview) == RES_OK);
    316   CHK(s3d_scene_view_create(scn3, S3D_TRACE, &scnview3) == RES_OK);
    317 
    318   f3(org, 0.5f, 0.25f, 0.25f);
    319   f3(dir, 0.f, 0.f, 1.f);
    320   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    321   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    322   CHK(hit.prim.geom_id == iplane);
    323   CHK(hit.prim.prim_id == 0);
    324 
    325   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    326   CHK(S3D_HIT_NONE(&hit) == 1);
    327 
    328   f3(org, -1.5f, 0.25f, 0.25f);
    329   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    330   CHK(hit.prim.inst_id == iinst0);
    331   CHK(hit.prim.geom_id == icube);
    332   CHK(hit.prim.prim_id == 4);
    333 
    334   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit2) == RES_OK);
    335   CHK(hit2.prim.inst_id == iinst0);
    336   CHK(hit2.prim.geom_id == icube);
    337   CHK(hit2.prim.prim_id == 4);
    338 
    339   CHK(f3_eq(hit.normal, hit2.normal) == 1);
    340   CHK(f2_eq(hit.uv, hit2.uv) == 1);
    341   CHK(hit.distance == hit2.distance);
    342 
    343   CHK(s3d_scene_clear(scn2) == RES_OK);
    344 
    345   f3(org, 2.5f, 0.25f, 0.25f);
    346 
    347   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    348   CHK(hit.prim.inst_id == iinst1);
    349   CHK(hit.prim.geom_id == icube);
    350   CHK(hit.prim.prim_id == 4);
    351 
    352   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit2) == RES_OK);
    353   CHK(hit2.prim.inst_id == iinst1);
    354   CHK(hit2.prim.geom_id == icube);
    355   CHK(hit2.prim.prim_id == 4);
    356 
    357   CHK(f3_eq(hit.normal, hit2.normal) == 1);
    358   CHK(f2_eq(hit.uv, hit2.uv) == 1);
    359   CHK(hit.distance == hit2.distance);
    360 
    361   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    362   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview) == RES_OK);
    363 
    364   f3(org, -1.5f, 0.25f, 0.25f);
    365   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    366   CHK(S3D_HIT_NONE(&hit) == 1);
    367   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    368   CHK(hit.prim.inst_id == iinst0);
    369   CHK(hit.prim.geom_id == icube);
    370   CHK(hit.prim.prim_id == 4);
    371 
    372   f3(org, 2.5f, 0.25f, 0.25f);
    373   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    374   CHK(S3D_HIT_NONE(&hit) == 1);
    375   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    376   CHK(hit.prim.inst_id == iinst1);
    377   CHK(hit.prim.geom_id == icube);
    378   CHK(hit.prim.prim_id == 4);
    379 
    380   f3(org, 0.5f, 0.25f, 0.25f);
    381   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    382   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    383   CHK(hit.prim.geom_id == iplane);
    384   CHK(hit.prim.prim_id == 0);
    385   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    386   CHK(S3D_HIT_NONE(&hit) == 1);
    387 
    388   CHK(s3d_scene_attach_shape(scn2, plane) == RES_OK);
    389   CHK(s3d_mesh_set_hit_filter_function(plane, filter, NULL) == RES_OK);
    390 
    391   f3(org, 0.5f, 0.25f, 0.25f);
    392   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    393   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    394   CHK(hit.prim.geom_id == iplane);
    395   CHK(hit.prim.prim_id == 0);
    396 
    397   CHK(s3d_scene_view_ref_put(scnview3) == RES_OK);
    398   CHK(s3d_scene_view_create(scn3, S3D_TRACE, &scnview3) == RES_OK);
    399 
    400   f3(org, -1.5f, 0.25f, 0.25f);
    401   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    402   CHK(S3D_HIT_NONE(&hit) == 1);
    403   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    404   CHK(S3D_HIT_NONE(&hit) == 1);
    405 
    406   f3(org, -1.5f, 0.75f, 0.25f);
    407   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    408   CHK(S3D_HIT_NONE(&hit) == 1);
    409   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    410   CHK(hit.prim.inst_id == iinst0);
    411   CHK(hit.prim.geom_id == iplane);
    412   CHK(hit.prim.prim_id == 1);
    413 
    414   f3(org, 2.5f, 0.25f, 0.25f);
    415   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    416   CHK(S3D_HIT_NONE(&hit) == 1);
    417   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    418   CHK(S3D_HIT_NONE(&hit) == 1);
    419 
    420   f3(org, 2.5f, 0.75f, 0.25f);
    421   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    422   CHK(S3D_HIT_NONE(&hit) == 1);
    423   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    424   CHK(hit.prim.inst_id == iinst1);
    425   CHK(hit.prim.geom_id == iplane);
    426   CHK(hit.prim.prim_id == 1);
    427 
    428   f3(org, 0.5f, 0.25f, 0.25f);
    429   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    430   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    431   CHK(hit.prim.geom_id == iplane);
    432   CHK(hit.prim.prim_id == 0);
    433   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    434   CHK(S3D_HIT_NONE(&hit) == 1);
    435 
    436   f3(org, 0.5f, 0.75f, 0.25f);
    437   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    438   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    439   CHK(hit.prim.geom_id == iplane);
    440   CHK(hit.prim.prim_id == 1);
    441   CHK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit) == RES_OK);
    442   CHK(S3D_HIT_NONE(&hit) == 1);
    443 
    444   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    445   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview) == RES_OK);
    446   f3(org, 0.5f, 0.25f, 0.25f);
    447   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    448   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    449   CHK(hit.prim.geom_id == icube);
    450   CHK(hit.prim.prim_id == 4);
    451   f3(org, 0.5f, 0.75f, 0.25f);
    452   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    453   CHK(hit.prim.inst_id == S3D_INVALID_ID);
    454   CHK(hit.prim.geom_id == iplane);
    455   CHK(hit.prim.prim_id == 1);
    456 
    457   f3(org, -1.5f, 0.25f, 0.25f);
    458   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    459   CHK(S3D_HIT_NONE(&hit) == 1);
    460   f3(org, -1.5f, 0.75f, 0.25f);
    461   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    462   CHK(hit.prim.inst_id == iinst0);
    463   CHK(hit.prim.geom_id == iplane);
    464   CHK(hit.prim.prim_id == 1);
    465 
    466   f3(org, 2.5f, 0.25f, 0.25f);
    467   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    468   CHK(S3D_HIT_NONE(&hit) == 1);
    469   f3(org, 2.5f, 0.75f, 0.25f);
    470   CHK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_OK);
    471   CHK(hit.prim.inst_id == iinst1);
    472   CHK(hit.prim.geom_id == iplane);
    473   CHK(hit.prim.prim_id == 1);
    474 
    475   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    476   CHK(s3d_scene_view_ref_put(scnview3) == RES_OK);
    477 
    478   CHK(s3d_shape_ref_put(inst0) == RES_OK);
    479   CHK(s3d_shape_ref_put(inst1) == RES_OK);
    480   CHK(s3d_scene_ref_put(scn) == RES_OK);
    481   CHK(s3d_scene_ref_put(scn2) == RES_OK);
    482   CHK(s3d_scene_ref_put(scn3) == RES_OK);
    483 }
    484 
    485 static void
    486 test_sample
    487   (struct s3d_device* dev,
    488    struct s3d_shape* cube,
    489    struct s3d_shape* plane)
    490 {
    491   #define NSAMPS 512
    492   struct s3d_scene* scn;
    493   struct s3d_scene* scn2;
    494   struct s3d_scene* scn3;
    495   struct s3d_scene_view* scnview;
    496   struct s3d_scene_view* scnview3;
    497   struct s3d_shape* inst0;
    498   struct s3d_shape* inst1;
    499   struct s3d_primitive prims[NSAMPS];
    500   float u, v, w, st[2];
    501   float pos[3];
    502   unsigned icube;
    503   unsigned iplane;
    504   unsigned iinst0;
    505   unsigned iinst1;
    506   int nsamps_cube;
    507   int nsamps_plane;
    508   int nsamps_inst0;
    509   int nsamps_inst1;
    510   int i;
    511 
    512   CHK(s3d_scene_create(dev, &scn) == RES_OK);
    513   CHK(s3d_scene_create(dev, &scn2) == RES_OK);
    514   CHK(s3d_scene_create(dev, &scn3) == RES_OK);
    515   CHK(s3d_scene_attach_shape(scn, cube) == RES_OK);
    516   CHK(s3d_scene_attach_shape(scn, plane) == RES_OK);
    517   CHK(s3d_shape_get_id(cube, &icube) == RES_OK);
    518   CHK(s3d_shape_get_id(plane, &iplane) == RES_OK);
    519 
    520   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview) == RES_OK);
    521   CHK(s3d_scene_view_sample(scnview, 0.f, 0.f, 0.f, &prims[0], st) == RES_BAD_OP);
    522   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    523 
    524   CHK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview) == RES_OK);
    525   CHK(s3d_scene_view_sample(scnview, 0.f, 0.f, 0.f, &prims[0], st) == RES_OK);
    526   CHK(prims[0].inst_id == S3D_INVALID_ID);
    527   CHK(prims[0].geom_id == icube || prims[0].geom_id == iplane);
    528 
    529   nsamps_cube = 0;
    530   nsamps_plane = 0;
    531   srand(0);
    532   FOR_EACH(i, 0, NSAMPS) {
    533     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    534     CHK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st) == RES_OK);
    535     CHK(prims[i].inst_id == S3D_INVALID_ID);
    536     if(prims[i].geom_id == icube) {
    537       ++nsamps_cube;
    538     } else {
    539       CHK(prims[i].geom_id == iplane);
    540       ++nsamps_plane;
    541     }
    542   }
    543   CHK(nsamps_cube != 0);
    544   CHK(nsamps_plane != 0);
    545 
    546   CHK(s3d_shape_enable(cube, 0) == RES_OK);
    547   srand(0);
    548   FOR_EACH(i, 0, NSAMPS) {
    549     struct s3d_primitive prim;
    550     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    551     CHK(s3d_scene_view_sample(scnview, u, v, w, &prim, st) == RES_OK);
    552     CHK(S3D_PRIMITIVE_EQ(&prim, &prims[i]) == 1);
    553   }
    554 
    555   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    556   CHK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview) == RES_OK);
    557 
    558   srand(0);
    559   FOR_EACH(i, 0, NSAMPS) {
    560     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    561     CHK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st) == RES_OK);
    562     CHK(prims[i].inst_id == S3D_INVALID_ID);
    563     CHK(prims[i].geom_id == iplane);
    564   }
    565 
    566   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    567 
    568   CHK(s3d_shape_enable(cube, 1) == RES_OK);
    569   CHK(s3d_scene_attach_shape(scn2, cube) == RES_OK);
    570   CHK(s3d_scene_instantiate(scn2, &inst0) == RES_OK);
    571   CHK(s3d_scene_instantiate(scn2, &inst1) == RES_OK);
    572   CHK(s3d_shape_get_id(inst0, &iinst0) == RES_OK);
    573   CHK(s3d_shape_get_id(inst1, &iinst1) == RES_OK);
    574   CHK(s3d_instance_translate
    575     (inst0, S3D_WORLD_TRANSFORM, f3(pos,-2.f, 0.f, 0.f)) == RES_OK);
    576   CHK(s3d_instance_translate
    577     (inst1, S3D_WORLD_TRANSFORM, f3(pos, 2.f, 0.f, 0.f)) == RES_OK);
    578 
    579   CHK(s3d_scene_attach_shape(scn, inst0) == RES_OK);
    580   CHK(s3d_scene_attach_shape(scn, inst1) == RES_OK);
    581   CHK(s3d_scene_attach_shape(scn3, inst0) == RES_OK);
    582   CHK(s3d_scene_attach_shape(scn3, inst1) == RES_OK);
    583 
    584   CHK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview) == RES_OK);
    585   CHK(s3d_scene_view_create(scn3, S3D_SAMPLE, &scnview3) == RES_OK);
    586 
    587   CHK(s3d_scene_detach_shape(scn2, cube) == RES_OK);
    588 
    589   nsamps_cube = 0;
    590   nsamps_inst0 = 0;
    591   nsamps_inst1 = 0;
    592   nsamps_plane = 0;
    593   srand(0);
    594   FOR_EACH(i, 0, NSAMPS) {
    595     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    596     CHK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st) == RES_OK);
    597     if(prims[i].inst_id != S3D_INVALID_ID) {
    598       CHK(prims[i].geom_id == icube);
    599       if(prims[i].inst_id == iinst0) {
    600         ++nsamps_inst0;
    601       } else {
    602         CHK(prims[i].inst_id == iinst1);
    603         ++nsamps_inst1;
    604       }
    605     } else {
    606       if(prims[i].geom_id == icube) {
    607         ++nsamps_cube;
    608       } else {
    609         CHK(prims[i].geom_id == iplane);
    610         ++nsamps_plane;
    611       }
    612     }
    613 
    614   }
    615   CHK(nsamps_cube != 0);
    616   CHK(nsamps_inst0 != 0);
    617   CHK(nsamps_inst1 != 0);
    618   CHK(nsamps_plane != 0);
    619 
    620   nsamps_inst0 = 0;
    621   nsamps_inst1 = 0;
    622   srand(0);
    623   FOR_EACH(i, 0, NSAMPS) {
    624     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    625     CHK(s3d_scene_view_sample(scnview3, u, v, w, &prims[i], st) == RES_OK);
    626     CHK(prims[i].geom_id == icube);
    627     if(prims[i].inst_id == iinst0) {
    628       ++nsamps_inst0;
    629     } else {
    630       CHK(prims[i].inst_id == iinst1);
    631       ++nsamps_inst1;
    632     }
    633   }
    634   CHK(nsamps_inst0 != 0);
    635   CHK(nsamps_inst1 != 0);
    636 
    637   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    638   CHK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview) == RES_OK);
    639 
    640   nsamps_cube = 0;
    641   nsamps_plane = 0;
    642   srand(0);
    643   FOR_EACH(i, 0, NSAMPS) {
    644     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    645     CHK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st) == RES_OK);
    646     CHK(prims[i].inst_id == S3D_INVALID_ID);
    647     if(prims[i].geom_id == icube) {
    648       ++nsamps_cube;
    649     } else {
    650       CHK(prims[i].geom_id == iplane);
    651       ++nsamps_plane;
    652     }
    653   }
    654   CHK(nsamps_cube != 0);
    655   CHK(nsamps_plane != 0);
    656 
    657   nsamps_inst0 = 0;
    658   nsamps_inst1 = 0;
    659   srand(0);
    660   FOR_EACH(i, 0, NSAMPS) {
    661     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    662     CHK(s3d_scene_view_sample(scnview3, u, v, w, &prims[i], st) == RES_OK);
    663     CHK(prims[i].geom_id == icube);
    664     if(prims[i].inst_id == iinst0) {
    665       ++nsamps_inst0;
    666     } else {
    667       CHK(prims[i].inst_id == iinst1);
    668       ++nsamps_inst1;
    669     }
    670   }
    671   CHK(nsamps_inst0 != 0);
    672   CHK(nsamps_inst1 != 0);
    673 
    674   CHK(s3d_scene_attach_shape(scn2, plane) == RES_OK);
    675 
    676   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    677   CHK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview) == RES_OK);
    678 
    679   FOR_EACH(i, 0, NSAMPS) {
    680     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    681     CHK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st) == RES_OK);
    682     if(prims[i].inst_id != S3D_INVALID_ID) {
    683       CHK(prims[i].geom_id == iplane);
    684       if(prims[i].inst_id == iinst0) {
    685         ++nsamps_inst0;
    686       } else {
    687         CHK(prims[i].inst_id == iinst1);
    688         ++nsamps_inst1;
    689       }
    690     } else {
    691       if(prims[i].geom_id == icube) {
    692         ++nsamps_cube;
    693       } else {
    694         CHK(prims[i].geom_id == iplane);
    695         ++nsamps_plane;
    696       }
    697     }
    698 
    699   }
    700   CHK(nsamps_cube != 0);
    701   CHK(nsamps_inst0 != 0);
    702   CHK(nsamps_inst1 != 0);
    703   CHK(nsamps_plane != 0);
    704 
    705   nsamps_inst0 = 0;
    706   nsamps_inst1 = 0;
    707   srand(0);
    708   FOR_EACH(i, 0, NSAMPS) {
    709     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    710     CHK(s3d_scene_view_sample(scnview3, u, v, w, &prims[i], st) == RES_OK);
    711     CHK(prims[i].geom_id == icube);
    712     if(prims[i].inst_id == iinst0) {
    713       ++nsamps_inst0;
    714     } else {
    715       CHK(prims[i].inst_id == iinst1);
    716       ++nsamps_inst1;
    717     }
    718   }
    719   CHK(nsamps_inst0 != 0);
    720   CHK(nsamps_inst1 != 0);
    721 
    722   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    723   CHK(s3d_scene_view_ref_put(scnview3) == RES_OK);
    724 
    725   CHK(s3d_scene_view_create(scn3, S3D_SAMPLE, &scnview3) == RES_OK);
    726   nsamps_inst0 = 0;
    727   nsamps_inst1 = 0;
    728   srand(0);
    729   FOR_EACH(i, 0, NSAMPS) {
    730     u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
    731     CHK(s3d_scene_view_sample(scnview3, u, v, w, &prims[i], st) == RES_OK);
    732     CHK(prims[i].geom_id == iplane);
    733     if(prims[i].inst_id == iinst0) {
    734       ++nsamps_inst0;
    735     } else {
    736       CHK(prims[i].inst_id == iinst1);
    737       ++nsamps_inst1;
    738     }
    739   }
    740   CHK(nsamps_inst0 != 0);
    741   CHK(nsamps_inst1 != 0);
    742 
    743   CHK(s3d_scene_view_ref_put(scnview3) == RES_OK);
    744 
    745   CHK(s3d_scene_ref_put(scn) == RES_OK);
    746   CHK(s3d_scene_ref_put(scn2) == RES_OK);
    747   CHK(s3d_scene_ref_put(scn3) == RES_OK);
    748   CHK(s3d_shape_ref_put(inst0) == RES_OK);
    749   CHK(s3d_shape_ref_put(inst1) == RES_OK);
    750 }
    751 
    752 static void
    753 test_get_primitive
    754   (struct s3d_device* dev,
    755    struct s3d_shape* cube,
    756    struct s3d_shape* plane)
    757 {
    758   struct s3d_scene* scn;
    759   struct s3d_scene* scn2;
    760   struct s3d_scene* scn3;
    761   struct s3d_scene_view* scnview;
    762   struct s3d_scene_view* scnview3;
    763   struct s3d_shape* inst0;
    764   struct s3d_shape* inst1;
    765   struct s3d_primitive prim;
    766   size_t nprims;
    767   unsigned i;
    768   unsigned icube;
    769   unsigned iplane;
    770   unsigned iinst0;
    771   unsigned iinst1;
    772   float pos[3];
    773   int cube_prims[12];
    774   int plane_prims[2];
    775   int inst0_prims[12];
    776   int inst1_prims[12];
    777 
    778   CHK(s3d_scene_create(dev, &scn) == RES_OK);
    779   CHK(s3d_scene_create(dev, &scn2) == RES_OK);
    780   CHK(s3d_scene_create(dev, &scn3) == RES_OK);
    781   CHK(s3d_scene_attach_shape(scn, cube) == RES_OK);
    782   CHK(s3d_scene_attach_shape(scn, plane) == RES_OK);
    783   CHK(s3d_shape_get_id(cube, &icube) == RES_OK);
    784   CHK(s3d_shape_get_id(plane, &iplane) == RES_OK);
    785 
    786   CHK(s3d_scene_view_create(scn, S3D_TRACE, &scnview) == RES_OK);
    787   CHK(s3d_scene_view_get_primitive(scnview, 0, &prim) == RES_BAD_OP);
    788   CHK(s3d_scene_view_primitives_count(scnview, &nprims) == RES_OK);
    789   CHK(nprims == 14);
    790   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    791 
    792   CHK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview) == RES_OK);
    793   CHK(s3d_scene_view_primitives_count(scnview, &nprims) == RES_OK);
    794   CHK(nprims == 14);
    795 
    796   memset(cube_prims, 0, sizeof(cube_prims));
    797   memset(plane_prims, 0, sizeof(plane_prims));
    798   FOR_EACH(i, 0, nprims) {
    799     CHK(s3d_scene_view_get_primitive(scnview, i, &prim) == RES_OK);
    800     CHK(prim.inst_id == S3D_INVALID_ID);
    801     CHK(prim.scene_prim_id == i);
    802     if(prim.geom_id == icube) {
    803       cube_prims[prim.prim_id] = 1;
    804     } else {
    805       CHK(prim.geom_id == iplane);
    806       plane_prims[prim.prim_id] = 1;
    807     }
    808   }
    809   FOR_EACH(i, 0, 12) CHK(cube_prims[i] == 1);
    810   FOR_EACH(i, 0, 2) CHK(plane_prims[i] == 1);
    811 
    812   CHK(s3d_scene_detach_shape(scn, cube) == RES_OK);
    813   CHK(s3d_scene_view_primitives_count(scnview, &nprims) == RES_OK);
    814   CHK(nprims == 14);
    815   memset(cube_prims, 0, sizeof(cube_prims));
    816   memset(plane_prims, 0, sizeof(plane_prims));
    817   FOR_EACH(i, 0, nprims) {
    818     CHK(s3d_scene_view_get_primitive(scnview, i, &prim) == RES_OK);
    819     CHK(prim.inst_id == S3D_INVALID_ID);
    820     CHK(prim.scene_prim_id == i);
    821     if(prim.geom_id == icube) {
    822       cube_prims[prim.prim_id] = 1;
    823     } else {
    824       CHK(prim.geom_id == iplane);
    825       plane_prims[prim.prim_id] = 1;
    826     }
    827   }
    828   FOR_EACH(i, 0, 12) CHK(cube_prims[i] == 1);
    829   FOR_EACH(i, 0, 2) CHK(plane_prims[i] == 1);
    830 
    831   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    832   CHK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview) == RES_OK);
    833   CHK(s3d_scene_view_primitives_count(scnview, &nprims) == RES_OK);
    834   CHK(nprims == 2);
    835   memset(plane_prims, 0, sizeof(plane_prims));
    836   FOR_EACH(i, 0, nprims) {
    837     CHK(s3d_scene_view_get_primitive(scnview, i, &prim) == RES_OK);
    838     CHK(prim.inst_id == S3D_INVALID_ID);
    839     CHK(prim.scene_prim_id == i);
    840     CHK(prim.geom_id == iplane);
    841     plane_prims[prim.prim_id] = 1;
    842   }
    843   FOR_EACH(i, 0, 2) CHK(plane_prims[i] == 1);
    844 
    845   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    846 
    847   CHK(s3d_scene_attach_shape(scn, cube) == RES_OK);
    848 
    849   CHK(s3d_scene_attach_shape(scn2, plane) == RES_OK);
    850   CHK(s3d_scene_instantiate(scn2, &inst0) == RES_OK);
    851   CHK(s3d_scene_instantiate(scn2, &inst1) == RES_OK);
    852   CHK(s3d_shape_get_id(inst0, &iinst0) == RES_OK);
    853   CHK(s3d_shape_get_id(inst1, &iinst1) == RES_OK);
    854   CHK(s3d_instance_translate
    855     (inst0, S3D_WORLD_TRANSFORM, f3(pos,-2.f, 0.f, 0.f)) == RES_OK);
    856   CHK(s3d_instance_translate
    857     (inst1, S3D_WORLD_TRANSFORM, f3(pos, 2.f, 0.f, 0.f)) == RES_OK);
    858 
    859   CHK(s3d_scene_attach_shape(scn, inst0) == RES_OK);
    860   CHK(s3d_scene_attach_shape(scn3, inst0) == RES_OK);
    861   CHK(s3d_scene_attach_shape(scn3, inst1) == RES_OK);
    862 
    863   CHK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview) == RES_OK);
    864   CHK(s3d_scene_view_create(scn3, S3D_GET_PRIMITIVE, &scnview3) == RES_OK);
    865 
    866   CHK(s3d_scene_clear(scn2) == RES_OK);
    867 
    868   CHK(s3d_scene_view_primitives_count(scnview, &nprims) == RES_OK);
    869   CHK(nprims == 16);
    870   memset(plane_prims, 0, sizeof(plane_prims));
    871   memset(cube_prims, 0, sizeof(cube_prims));
    872   memset(inst0_prims, 0, sizeof(inst0_prims));
    873   FOR_EACH(i, 0, nprims) {
    874     CHK(s3d_scene_view_get_primitive(scnview, i, &prim) == RES_OK);
    875     if(prim.inst_id != S3D_INVALID_ID) {
    876       CHK(prim.inst_id == iinst0);
    877       CHK(prim.geom_id == iplane);
    878       inst0_prims[prim.prim_id] = 1;
    879     } else {
    880       if(prim.geom_id == icube) {
    881         cube_prims[prim.prim_id] = 1;
    882       } else {
    883         CHK(prim.geom_id == iplane);
    884         plane_prims[prim.prim_id] = 1;
    885       }
    886     }
    887   }
    888   FOR_EACH(i, 0, 12) CHK(cube_prims[i] == 1);
    889   FOR_EACH(i, 0, 2) CHK(plane_prims[i] == 1);
    890   FOR_EACH(i, 0, 2) CHK(inst0_prims[i] == 1);
    891 
    892   CHK(s3d_scene_view_primitives_count(scnview3, &nprims) == RES_OK);
    893   CHK(nprims == 4);
    894   memset(inst0_prims, 0, sizeof(inst0_prims));
    895   memset(inst1_prims, 0, sizeof(inst1_prims));
    896   FOR_EACH(i, 0, nprims) {
    897     CHK(s3d_scene_view_get_primitive(scnview3, i, &prim) == RES_OK);
    898     CHK(prim.inst_id != S3D_INVALID_ID);
    899     CHK(prim.geom_id == iplane);
    900     if(prim.inst_id == iinst0) {
    901       inst0_prims[prim.prim_id] = 1;
    902     } else {
    903       CHK(prim.inst_id == iinst1);
    904       inst1_prims[prim.prim_id] = 1;
    905     }
    906   }
    907   FOR_EACH(i, 0, 2) CHK(inst1_prims[i] == 1);
    908   FOR_EACH(i, 0, 2) CHK(inst1_prims[i] == 1);
    909 
    910   CHK(s3d_scene_view_ref_put(scnview3) == RES_OK);
    911 
    912   CHK(s3d_scene_view_create(scn3, S3D_GET_PRIMITIVE, &scnview3) == RES_OK);
    913   CHK(s3d_scene_view_primitives_count(scnview3, &nprims) == RES_OK);
    914   CHK(nprims == 0);
    915   CHK(s3d_scene_view_ref_put(scnview3) == RES_OK);
    916 
    917   CHK(s3d_scene_attach_shape(scn2, cube) == RES_OK);
    918   CHK(s3d_scene_view_create(scn3, S3D_GET_PRIMITIVE, &scnview3) == RES_OK);
    919 
    920   CHK(s3d_scene_view_primitives_count(scnview, &nprims) == RES_OK);
    921   CHK(nprims == 16);
    922   memset(plane_prims, 0, sizeof(plane_prims));
    923   memset(cube_prims, 0, sizeof(cube_prims));
    924   memset(inst0_prims, 0, sizeof(inst0_prims));
    925   FOR_EACH(i, 0, nprims) {
    926     CHK(s3d_scene_view_get_primitive(scnview, i, &prim) == RES_OK);
    927     if(prim.inst_id != S3D_INVALID_ID) {
    928       CHK(prim.inst_id == iinst0);
    929       CHK(prim.geom_id == iplane);
    930       inst0_prims[prim.prim_id] = 1;
    931     } else {
    932       if(prim.geom_id == icube) {
    933         cube_prims[prim.prim_id] = 1;
    934       } else {
    935         CHK(prim.geom_id == iplane);
    936         plane_prims[prim.prim_id] = 1;
    937       }
    938     }
    939   }
    940   FOR_EACH(i, 0, 12) CHK(cube_prims[i] == 1);
    941   FOR_EACH(i, 0, 2) CHK(plane_prims[i] == 1);
    942   FOR_EACH(i, 0, 2) CHK(inst0_prims[i] == 1);
    943 
    944   CHK(s3d_scene_view_primitives_count(scnview3, &nprims) == RES_OK);
    945   CHK(nprims == 24);
    946   memset(inst0_prims, 0, sizeof(inst0_prims));
    947   memset(inst1_prims, 0, sizeof(inst1_prims));
    948   FOR_EACH(i, 0, nprims) {
    949     CHK(s3d_scene_view_get_primitive(scnview3, i, &prim) == RES_OK);
    950     CHK(prim.inst_id != S3D_INVALID_ID);
    951     CHK(prim.geom_id == icube);
    952     if(prim.inst_id == iinst0) {
    953       inst0_prims[prim.prim_id] = 1;
    954     } else {
    955       CHK(prim.inst_id == iinst1);
    956       inst1_prims[prim.prim_id] = 1;
    957     }
    958   }
    959   FOR_EACH(i, 0, 12) CHK(inst1_prims[i] == 1);
    960   FOR_EACH(i, 0, 12) CHK(inst1_prims[i] == 1);
    961 
    962   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    963   CHK(s3d_scene_view_ref_put(scnview3) == RES_OK);
    964 
    965   CHK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview) == RES_OK);
    966 
    967   CHK(s3d_scene_view_primitives_count(scnview, &nprims) == RES_OK);
    968   CHK(nprims == 26);
    969   memset(plane_prims, 0, sizeof(plane_prims));
    970   memset(cube_prims, 0, sizeof(cube_prims));
    971   memset(inst0_prims, 0, sizeof(inst0_prims));
    972   FOR_EACH(i, 0, nprims) {
    973     CHK(s3d_scene_view_get_primitive(scnview, i, &prim) == RES_OK);
    974     if(prim.inst_id != S3D_INVALID_ID) {
    975       CHK(prim.inst_id == iinst0);
    976       CHK(prim.geom_id == icube);
    977       inst0_prims[prim.prim_id] = 1;
    978     } else {
    979       if(prim.geom_id == icube) {
    980         cube_prims[prim.prim_id] = 1;
    981       } else {
    982         CHK(prim.geom_id == iplane);
    983         plane_prims[prim.prim_id] = 1;
    984       }
    985     }
    986   }
    987   FOR_EACH(i, 0, 12) CHK(cube_prims[i] == 1);
    988   FOR_EACH(i, 0, 2) CHK(plane_prims[i] == 1);
    989   FOR_EACH(i, 0, 12) CHK(inst0_prims[i] == 1);
    990 
    991   CHK(s3d_scene_view_ref_put(scnview) == RES_OK);
    992 
    993   CHK(s3d_shape_ref_put(inst0) == RES_OK);
    994   CHK(s3d_shape_ref_put(inst1) == RES_OK);
    995   CHK(s3d_scene_ref_put(scn) == RES_OK);
    996   CHK(s3d_scene_ref_put(scn2) == RES_OK);
    997   CHK(s3d_scene_ref_put(scn3) == RES_OK);
    998 }
    999 
   1000 /*******************************************************************************
   1001  * Main test function
   1002  ******************************************************************************/
   1003 int
   1004 main(int argc, char** argv)
   1005 {
   1006   struct mem_allocator allocator;
   1007   struct mesh_context ctx;
   1008   struct s3d_device* dev;
   1009   struct s3d_shape* cube;
   1010   struct s3d_shape* plane;
   1011   struct s3d_vertex_data vdata;
   1012   (void)argc, (void)argv;
   1013 
   1014   mem_init_proxy_allocator(&allocator, &mem_default_allocator);
   1015 
   1016   CHK(s3d_device_create(NULL, &allocator, 1, &dev) == RES_OK);
   1017 
   1018   vdata.type = S3D_FLOAT3;
   1019   vdata.usage = S3D_POSITION;
   1020   vdata.get = get_pos;
   1021 
   1022   ctx.ids = cube_ids;
   1023   ctx.verts = cube_verts;
   1024   CHK(s3d_shape_create_mesh(dev, &cube) == RES_OK);
   1025   CHK(s3d_mesh_setup_indexed_vertices
   1026     (cube, cube_ntris, get_ids, cube_nverts, &vdata, 1, &ctx) == RES_OK);
   1027 
   1028   ctx.ids = plane_ids;
   1029   ctx.verts = plane_verts;
   1030   CHK(s3d_shape_create_mesh(dev, &plane) == RES_OK);
   1031   CHK(s3d_mesh_setup_indexed_vertices
   1032     (plane, plane_ntris, get_ids, plane_nverts, &vdata, 1, &ctx) == RES_OK);
   1033 
   1034   test_miscellaneous(dev, cube, plane);
   1035   test_trace_ray(dev, cube, plane);
   1036   test_sample(dev, cube, plane);
   1037   test_get_primitive(dev, cube, plane);
   1038 
   1039   CHK(s3d_shape_ref_put(cube) == RES_OK);
   1040   CHK(s3d_shape_ref_put(plane) == RES_OK);
   1041   CHK(s3d_device_ref_put(dev) == RES_OK);
   1042 
   1043   check_memory_allocator(&allocator);
   1044   mem_shutdown_proxy_allocator(&allocator);
   1045   CHK(mem_allocated_size() == 0);
   1046   return 0;
   1047 }
   1048