star-3d

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

test_s3d_scene_view.c (35482B)


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