db5_comb.c

Go to the documentation of this file.
00001 /*                      D B 5 _ C O M B . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup db5 */
00023 
00024 /*@{*/
00025 /** @file db5_comb.c
00026  *  Handle import/export of combinations (union tree) in v5 format.
00027  *
00028  *  The on-disk record looks like this:
00029  *      width byte
00030  *      n matricies (only non-identity matricies stored).
00031  *      n leaves
00032  *      len of RPN expression.  (len=0 signals all-union expression)
00033  *      depth of stack
00034  *      Section 1:  matricies
00035  *      Section 2:  leaves
00036  *      Section 3:  (Optional) RPN expression.
00037  *
00038  *  Encoding of a matrix is (ELEMENTS_PER_MAT * SIZEOF_NETWORK_DOUBLE) bytes,
00039  *  in network order (big-Endian, IEEE double precision).
00040  *
00041  *  Author -
00042  *      Michael John Muuss
00043  *
00044  *  Source -
00045  *      The U. S. Army Research Laboratory
00046  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00047  *
00048  */
00049 /*@}*/
00050 
00051 #ifndef lint
00052 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/db5_comb.c,v 14.11 2006/09/16 02:04:24 lbutler Exp $ (ARL)";
00053 #endif
00054 
00055 #include "common.h"
00056 
00057 #include <stdlib.h>
00058 #include <stdio.h>
00059 #ifdef HAVE_STRING_H
00060 #  include <string.h>
00061 #else
00062 #  include <strings.h>
00063 #endif
00064 
00065 #include "machine.h"
00066 #include "bu.h"
00067 #include "vmath.h"
00068 #include "bn.h"
00069 #include "db5.h"
00070 #include "raytrace.h"
00071 
00072 #include "./debug.h"
00073 
00074 
00075 struct db_tree_counter_state {
00076         long    magic;
00077         long    n_mat;                  /* # leaves with non-identity matricies */
00078         long    n_leaf;                 /* # leaf nodes */
00079         long    n_oper;                 /* # operator nodes */
00080         long    leafbytes;              /* # bytes for name section */
00081         int     non_union_seen;         /* boolean, 1 = non-unions seen */
00082 };
00083 #define DB_TREE_COUNTER_STATE_MAGIC     0x64546373      /* dTcs */
00084 #define DB_CK_TREE_COUNTER_STATE(_p)    BU_CKMAG(_p, DB_TREE_COUNTER_STATE_MAGIC, "db_tree_counter_state");
00085 
00086 /**
00087  *                      D B _ T R E E _ C O U N T E R
00088  *
00089  *  Count number of non-identity matricies,
00090  *  number of leaf nodes, number of operator nodes, etc.
00091  *
00092  *  Returns -
00093  *      maximum depth of stack needed to unpack this tree, if serialized.
00094  *
00095  *  Notes -
00096  *      We over-estimate the size of the width fields used for
00097  *      holding the matrix subscripts.
00098  *      The caller is responsible for correcting by saying:
00099  *              tcsp->leafbytes -= tcsp->n_leaf * (8 - db5_enc_len[wid]);
00100  */
00101 long
00102 db_tree_counter( const union tree *tp, struct db_tree_counter_state *tcsp )
00103 {
00104         long    ldepth, rdepth;
00105 
00106         RT_CK_TREE(tp);
00107         DB_CK_TREE_COUNTER_STATE(tcsp);
00108 
00109         switch( tp->tr_op )  {
00110         case OP_DB_LEAF:
00111                 tcsp->n_leaf++;
00112                 if( tp->tr_l.tl_mat && !bn_mat_is_identity(tp->tr_l.tl_mat) )  tcsp->n_mat++;
00113                 /* Over-estimate storage requirement for matrix # */
00114                 tcsp->leafbytes += strlen(tp->tr_l.tl_name) + 1 + 8;
00115                 return 1;
00116 
00117         case OP_NOT:
00118                 /* Unary ops */
00119                 tcsp->n_oper++;
00120                 tcsp->non_union_seen = 1;
00121                 return 1 + db_tree_counter( tp->tr_b.tb_left, tcsp );
00122 
00123         case OP_UNION:
00124                 /* This node is known to be a binary op */
00125                 tcsp->n_oper++;
00126                 ldepth = db_tree_counter( tp->tr_b.tb_left, tcsp );
00127                 rdepth = db_tree_counter( tp->tr_b.tb_right, tcsp );
00128                 if( ldepth > rdepth )  return ldepth;
00129                 return rdepth;
00130 
00131         case OP_INTERSECT:
00132         case OP_SUBTRACT:
00133         case OP_XOR:
00134                 /* This node is known to be a binary op */
00135                 tcsp->n_oper++;
00136                 tcsp->non_union_seen = 1;
00137                 ldepth = db_tree_counter( tp->tr_b.tb_left, tcsp );
00138                 rdepth = db_tree_counter( tp->tr_b.tb_right, tcsp );
00139                 if( ldepth > rdepth )  return ldepth;
00140                 return rdepth;
00141 
00142         default:
00143                 bu_log("db_tree_counter: bad op %d\n", tp->tr_op);
00144                 bu_bomb("db_tree_counter\n");
00145                 /* NOTREACHED */
00146         }
00147         /* NOTREACHED */
00148         return 0;
00149 }
00150 
00151 #define DB5COMB_TOKEN_LEAF              1
00152 #define DB5COMB_TOKEN_UNION             2
00153 #define DB5COMB_TOKEN_INTERSECT         3
00154 #define DB5COMB_TOKEN_SUBTRACT          4
00155 #define DB5COMB_TOKEN_XOR               5
00156 #define DB5COMB_TOKEN_NOT               6
00157 
00158 struct rt_comb_v5_serialize_state  {
00159         long            magic;
00160         long            mat_num;        /* current matrix number */
00161         long            nmat;           /* # matricies, total */
00162         unsigned char   *matp;
00163         unsigned char   *leafp;
00164         unsigned char   *exprp;
00165         int             wid;
00166 };
00167 #define RT_COMB_V5_SERIALIZE_STATE_MAGIC        0x43357373      /* C5ss */
00168 #define RT_CK_COMB_V5_SERIALIZE_STATE(_p)       BU_CKMAG(_p, RT_COMB_V5_SERIALIZE_STATE_MAGIC, "rt_comb_v5_serialize_state")
00169 
00170 /**
00171  *                      R T _ C O M B _ V 5 _ S E R I A L I Z E
00172  *
00173  *  In one single pass through the tree, serialize out all three
00174  *  output sections at once.
00175  */
00176 void
00177 rt_comb_v5_serialize(
00178         const union tree        *tp,
00179         struct rt_comb_v5_serialize_state       *ssp)
00180 {
00181         int     n;
00182         int     mi;
00183 
00184         RT_CK_TREE(tp);
00185         RT_CK_COMB_V5_SERIALIZE_STATE(ssp);
00186 
00187         switch( tp->tr_op )  {
00188         case OP_DB_LEAF:
00189                 /*
00190                  *  Encoding of the leaf:
00191                  *      A null-terminated name string, and
00192                  *      the matrix subscript.  -1 == identity.
00193                  */
00194                 n = strlen(tp->tr_l.tl_name) + 1;
00195                 bcopy( tp->tr_l.tl_name, ssp->leafp, n );
00196                 ssp->leafp += n;
00197 
00198                 if( tp->tr_l.tl_mat && !bn_mat_is_identity(tp->tr_l.tl_mat) )
00199                         mi = ssp->mat_num++;
00200                 else
00201                         mi = -1;
00202                 BU_ASSERT_LONG( mi, <, ssp->nmat );
00203                 ssp->leafp = db5_encode_length( ssp->leafp, mi, ssp->wid );
00204 
00205                 /* Encoding of the matrix */
00206                 if( mi > -1 )  {
00207                         htond( ssp->matp,
00208                                 (const unsigned char *)tp->tr_l.tl_mat,
00209                                 ELEMENTS_PER_MAT );
00210                         ssp->matp += ELEMENTS_PER_MAT * SIZEOF_NETWORK_DOUBLE;
00211                 }
00212 
00213                 /* Encoding of the "leaf" operator */
00214                 if( ssp->exprp )
00215                         *ssp->exprp++ = DB5COMB_TOKEN_LEAF;
00216                 return;
00217 
00218         case OP_NOT:
00219                 /* Unary ops */
00220                 rt_comb_v5_serialize( tp->tr_b.tb_left, ssp );
00221                 if( ssp->exprp )
00222                         *ssp->exprp++ = DB5COMB_TOKEN_NOT;
00223                 return;
00224 
00225         case OP_UNION:
00226                 /* This node is known to be a binary op */
00227                 rt_comb_v5_serialize( tp->tr_b.tb_left, ssp );
00228                 rt_comb_v5_serialize( tp->tr_b.tb_right, ssp );
00229                 if( ssp->exprp )
00230                         *ssp->exprp++ = DB5COMB_TOKEN_UNION;
00231                 return;
00232         case OP_INTERSECT:
00233                 /* This node is known to be a binary op */
00234                 rt_comb_v5_serialize( tp->tr_b.tb_left, ssp );
00235                 rt_comb_v5_serialize( tp->tr_b.tb_right, ssp );
00236                 if( ssp->exprp )
00237                         *ssp->exprp++ = DB5COMB_TOKEN_INTERSECT;
00238                 return;
00239         case OP_SUBTRACT:
00240                 /* This node is known to be a binary op */
00241                 rt_comb_v5_serialize( tp->tr_b.tb_left, ssp );
00242                 rt_comb_v5_serialize( tp->tr_b.tb_right, ssp );
00243                 if( ssp->exprp )
00244                         *ssp->exprp++ = DB5COMB_TOKEN_SUBTRACT;
00245                 return;
00246         case OP_XOR:
00247                 /* This node is known to be a binary op */
00248                 rt_comb_v5_serialize( tp->tr_b.tb_left, ssp );
00249                 rt_comb_v5_serialize( tp->tr_b.tb_right, ssp );
00250                 if( ssp->exprp )
00251                         *ssp->exprp++ = DB5COMB_TOKEN_XOR;
00252                 return;
00253 
00254         default:
00255                 bu_log("rt_comb_v5_serialize: bad op %d\n", tp->tr_op);
00256                 bu_bomb("rt_comb_v5_serialize\n");
00257         }
00258 }
00259 
00260 /**
00261  *                      R T _ C O M B _ E X P O R T 5
00262  */
00263 int
00264 rt_comb_export5(
00265         struct bu_external              *ep,
00266         const struct rt_db_internal     *ip,
00267         double                          local2mm,
00268         const struct db_i               *dbip,
00269         struct resource                 *resp)
00270 {
00271         struct rt_comb_internal *comb;
00272         struct db_tree_counter_state            tcs;
00273         struct rt_comb_v5_serialize_state       ss;
00274         long    max_stack_depth;
00275         long    need;
00276         int     rpn_len = 0;    /* # items in RPN expression */
00277         int     wid;
00278         unsigned char   *cp;
00279         unsigned char   *leafp_end;
00280         struct bu_attribute_value_set *avsp;
00281         struct bu_vls   value;
00282 
00283         RT_CK_DB_INTERNAL( ip );
00284         RT_CK_RESOURCE(resp);
00285 
00286         if( ip->idb_type != ID_COMBINATION ) bu_bomb("rt_comb_export5() type not ID_COMBINATION");
00287         comb = (struct rt_comb_internal *)ip->idb_ptr;
00288         RT_CK_COMB(comb);
00289 
00290         /* First pass -- count number of non-identity matricies,
00291          * number of leaf nodes, number of operator nodes.
00292          */
00293         bzero( (char *)&tcs, sizeof(tcs) );
00294         tcs.magic = DB_TREE_COUNTER_STATE_MAGIC;
00295         if( comb->tree )
00296                 max_stack_depth = db_tree_counter( comb->tree, &tcs );
00297         else
00298                 max_stack_depth = 0;    /* some combinations have no tree */
00299 
00300         if( tcs.non_union_seen )  {
00301                 /* RPN expression needs one byte for each leaf or operator node */
00302                 rpn_len = tcs.n_leaf + tcs.n_oper;
00303         } else {
00304                 rpn_len = 0;
00305         }
00306 
00307         wid = db5_select_length_encoding(
00308                 tcs.n_mat | tcs.n_leaf | tcs.leafbytes |
00309                 rpn_len | max_stack_depth );
00310 
00311         /* Apply correction factor to tcs.leafbytes now that we know 'wid'.
00312          * Ignore the slight chance that a smaller 'wid' might now be possible.
00313          */
00314         tcs.leafbytes -= tcs.n_leaf * (8 - db5_enc_len[wid]);
00315 
00316         /* Second pass -- determine amount of on-disk storage needed */
00317         need =  1 +                     /* width code */
00318                 db5_enc_len[wid] +      /* size for nmatricies */
00319                 db5_enc_len[wid] +      /* size for nleaves */
00320                 db5_enc_len[wid] +      /* size for leafbytes */
00321                 db5_enc_len[wid] +      /* size for len of RPN */
00322                 db5_enc_len[wid] +      /* size for max_stack_depth */
00323                 tcs.n_mat * (ELEMENTS_PER_MAT * SIZEOF_NETWORK_DOUBLE) +        /* sizeof matrix array */
00324                 tcs.leafbytes +         /* size for leaf nodes */
00325                 rpn_len;                /* storage for RPN expression */
00326 
00327         BU_INIT_EXTERNAL(ep);
00328         ep->ext_nbytes = need;
00329 #if 0
00330         ep->ext_buf = bu_malloc( need, "rt_comb_export5 ext_buf" );
00331 #else
00332         ep->ext_buf = bu_calloc( 1, need, "rt_comb_export5 ext_buf" );
00333 #endif
00334 
00335         /* Build combination's on-disk header section */
00336         cp = (unsigned char *)ep->ext_buf;
00337         *cp++ = wid;
00338         cp = db5_encode_length( cp, tcs.n_mat, wid );
00339         cp = db5_encode_length( cp, tcs.n_leaf, wid );
00340         cp = db5_encode_length( cp, tcs.leafbytes, wid );
00341         cp = db5_encode_length( cp, rpn_len, wid );
00342         cp = db5_encode_length( cp, max_stack_depth, wid );
00343 
00344         /*
00345          *  The output format has three sections:
00346          *      Section 1:  matricies
00347          *      Section 2:  leaf nodes
00348          *      Section 3:  Optional RPN expression
00349          *
00350          *  We have pre-computed the exact size of all three sections,
00351          *  so they can all be searialized together in one pass.
00352          *  Establish pointers to the start of each section.
00353          */
00354         ss.magic = RT_COMB_V5_SERIALIZE_STATE_MAGIC;
00355         ss.wid = wid;
00356         ss.mat_num = 0;
00357         ss.nmat = tcs.n_mat;
00358         ss.matp = cp;
00359         ss.leafp = cp + tcs.n_mat * (ELEMENTS_PER_MAT * SIZEOF_NETWORK_DOUBLE);
00360         leafp_end = ss.leafp + tcs.leafbytes;
00361         if( rpn_len )
00362                 ss.exprp = leafp_end;
00363         else
00364                 ss.exprp = NULL;
00365 
00366         if( comb->tree )
00367                 rt_comb_v5_serialize( comb->tree, &ss );
00368 
00369         BU_ASSERT_LONG( ss.mat_num, ==, tcs.n_mat );
00370         BU_ASSERT_PTR( ss.matp, ==, cp + tcs.n_mat * (ELEMENTS_PER_MAT * SIZEOF_NETWORK_DOUBLE) );
00371         BU_ASSERT_PTR( ss.leafp, ==, leafp_end );
00372         if( rpn_len )
00373                 BU_ASSERT_PTR( ss.exprp, <=, ((unsigned char *)ep->ext_buf) + ep->ext_nbytes );
00374 
00375         /* Encode all the other stuff as attributes. */
00376         bu_vls_init( &value );
00377         /* WARNING:  We remove const from the ip pointer!!! */
00378         avsp = (struct bu_attribute_value_set *)&ip->idb_avs;
00379         if( avsp->magic != BU_AVS_MAGIC )
00380                 bu_avs_init( avsp, 32, "rt_comb v5 attributes" );
00381         if( comb->region_flag )  {
00382                 /* Presence of this attribute means this comb is a region. */
00383                 /* Current code values are 0, 1, and 2; all are regions.
00384                  * See raytrace.h for meanings of different values
00385                  */
00386                 bu_vls_trunc( &value, 0 );
00387                 switch (comb->is_fastgen) {
00388                 case REGION_FASTGEN_PLATE:
00389                     bu_vls_printf(&value, "P");
00390                     break;
00391                 case REGION_FASTGEN_VOLUME:
00392                     bu_vls_printf(&value, "V");
00393                     break;
00394                 case REGION_NON_FASTGEN: /* fallthrough */
00395                 default:
00396                     bu_vls_printf(&value, "R");
00397                     break;
00398                 }
00399                 bu_avs_add_vls( avsp, "region", &value );
00400         } else
00401                 bu_avs_remove( avsp, "region" );
00402 
00403         if( comb->inherit )
00404                 bu_avs_add( avsp, "inherit", "1" );
00405         else
00406                 bu_avs_remove( avsp, "inherit" );
00407 
00408         if( comb->rgb_valid )  {
00409                 bu_vls_trunc( &value, 0 );
00410                 bu_vls_printf( &value, "%d/%d/%d", V3ARGS(comb->rgb) );
00411                 bu_avs_add_vls( avsp, "rgb", &value );
00412         } else
00413                 bu_avs_remove( avsp, "rgb" );
00414 
00415         /* optical shader string goes out in Tcl format */
00416         if( bu_vls_strlen( &comb->shader ) > 0 )
00417                 bu_avs_add_vls( avsp, "oshader", &comb->shader );
00418         else
00419                 bu_avs_remove( avsp, "oshader" );
00420 
00421 #if 0
00422         if( bu_vls_strlen( &comb->material ) > 0 )
00423                 bu_avs_add_vls( avsp, "material", &comb->material );
00424         else
00425                 bu_avs_remove( avsp, "material" );
00426 #endif
00427 #if 0
00428         if( comb->temperature > 0 )  {
00429                 bu_vls_trunc( &value, 0 );
00430                 bu_vls_printf( &value, "%f", comb->temperature );
00431                 bu_avs_add_vls( avsp, "temp", &value );
00432         } else
00433                 bu_avs_remove( avsp, "temp" );
00434 #endif
00435         /* GIFT compatability */
00436         if( comb->region_id != 0 )  {
00437             bu_vls_trunc( &value, 0 );
00438             bu_vls_printf( &value, "%d", comb->region_id );
00439             bu_avs_add_vls( avsp, "region_id", &value );
00440         } else
00441             bu_avs_remove( avsp, "region_id" );
00442 
00443         if( comb->aircode != 0 )  {
00444             bu_vls_trunc( &value, 0 );
00445             bu_vls_printf( &value, "%d", comb->aircode );
00446             bu_avs_add_vls( avsp, "aircode", &value );
00447         } else
00448             bu_avs_remove( avsp, "aircode" );
00449 
00450         if( comb->GIFTmater != 0 )  {
00451             bu_vls_trunc( &value, 0 );
00452             bu_vls_printf( &value, "%d", comb->GIFTmater );
00453             bu_avs_add_vls( avsp, "material_id", &value );
00454         } else
00455             bu_avs_remove( avsp, "material_id" );
00456 
00457         if( comb->los != 0 )  {
00458             bu_vls_trunc( &value, 0 );
00459             bu_vls_printf( &value, "%d", comb->los );
00460             bu_avs_add_vls( avsp, "los", &value );
00461         } else
00462             bu_avs_remove( avsp, "los" );
00463 
00464         bu_vls_free( &value );
00465         return 0;       /* OK */
00466 }
00467 
00468 /**
00469  *                      R T _ C O M B _ I M P O R T 5
00470  *
00471  *  Read a combination object in v5 external (on-disk) format,
00472  *  and convert it into the internal format described in h/rtgeom.h
00473  *
00474  *  This is an unusual conversion, because some of the data is taken
00475  *  from attributes, not just from the object body.
00476  *  By the time this is called, the attributes will already have been
00477  *  cracked into ip->idb_avs, we get the attributes from there.
00478  *
00479  *  Returns -
00480  *      0       OK
00481  *      -1      FAIL
00482  */
00483 int
00484 rt_comb_import5(
00485         struct rt_db_internal   *ip,
00486         const struct bu_external *ep,
00487         const mat_t             mat,
00488         const struct db_i       *dbip,
00489         struct resource         *resp,
00490         const int               minor_type)
00491 {
00492         struct rt_comb_internal *comb;
00493         unsigned char   *cp;
00494         int             wid;
00495         long            nmat, nleaf, rpn_len, max_stack_depth;
00496         long            leafbytes;
00497         unsigned char   *matp;
00498         unsigned char   *leafp;
00499         unsigned char   *leafp_end;
00500         unsigned char   *exprp;
00501 #define MAX_V5_STACK    8000
00502         union tree      *stack[MAX_V5_STACK];
00503         union tree      **sp;                   /* stack pointer */
00504         const char      *ap;
00505         int             i;
00506 
00507         RT_CK_DB_INTERNAL( ip );
00508         BU_CK_EXTERNAL(ep);
00509         RT_CK_DBI(dbip);
00510         RT_CK_RESOURCE(resp);
00511 
00512         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00513         ip->idb_type = ID_COMBINATION;
00514         ip->idb_meth = &rt_functab[ID_COMBINATION];
00515         BU_GETSTRUCT( comb, rt_comb_internal );
00516         ip->idb_ptr = (genptr_t)comb;
00517         comb->magic = RT_COMB_MAGIC;
00518         bu_vls_init( &comb->shader );
00519         bu_vls_init( &comb->material );
00520         comb->temperature = -1;
00521 
00522         cp = ep->ext_buf;
00523         wid = *cp++;
00524         cp += db5_decode_length( &nmat, cp, wid );
00525         cp += db5_decode_length( &nleaf, cp, wid );
00526         cp += db5_decode_length( &leafbytes, cp, wid );
00527         cp += db5_decode_length( &rpn_len, cp, wid );
00528         cp += db5_decode_length( &max_stack_depth, cp, wid );
00529         matp = cp;
00530         leafp = cp + nmat * (ELEMENTS_PER_MAT * SIZEOF_NETWORK_DOUBLE);
00531         exprp = leafp + leafbytes;
00532         leafp_end = exprp;
00533 
00534         if( rpn_len == 0 )  {
00535                 /* This tree is all union operators, import it as a balanced tree */
00536 
00537                 int     i;
00538                 struct bu_ptbl *tbl1, *tbl2;
00539 
00540                 tbl1 = (struct bu_ptbl *)bu_malloc( sizeof( struct bu_ptbl ), "rt_comb_import5: tbl1" );
00541                 tbl2 = (struct bu_ptbl *)bu_malloc( sizeof( struct bu_ptbl ), "rt_comb_import5: tbl2" );
00542 
00543                 /* insert all the leaf nodes into a bu_ptbl */
00544                 bu_ptbl_init( tbl1, nleaf, "rt_comb_import5: tbl" );
00545                 for( i = nleaf-1; i >= 0; i-- )  {
00546                         union tree      *tp;
00547                         long            mi;
00548 
00549                         RT_GET_TREE( tp, resp );
00550                         tp->tr_l.magic = RT_TREE_MAGIC;
00551                         tp->tr_l.tl_op = OP_DB_LEAF;
00552                         tp->tr_l.tl_name = bu_strdup( (const char *)leafp );
00553                         leafp += strlen( (const char *)leafp) + 1;
00554 
00555                         /* Get matrix index */
00556                         mi = 4095;                      /* sanity */
00557                         leafp += db5_decode_signed( &mi, leafp, wid );
00558 
00559                         if( mi < 0 )  {
00560                                 /* Signal identity matrix */
00561                                 if( !mat || bn_mat_is_identity( mat ) ) {
00562                                         tp->tr_l.tl_mat = (matp_t)NULL;
00563                                 } else
00564                                         tp->tr_l.tl_mat = bn_mat_dup( mat );
00565                         } else {
00566                                 mat_t diskmat;
00567 
00568                                 /* Unpack indicated matrix mi */
00569                                 BU_ASSERT_LONG( mi, <, nmat );
00570                                 ntohd( (unsigned char *)diskmat,
00571                                         &matp[mi*ELEMENTS_PER_MAT*SIZEOF_NETWORK_DOUBLE],
00572                                         ELEMENTS_PER_MAT);
00573                                 if( !mat || bn_mat_is_identity( mat ) ) {
00574                                         tp->tr_l.tl_mat = bn_mat_dup( diskmat );
00575                                 } else {
00576                                         tp->tr_l.tl_mat = (matp_t)bu_malloc(
00577                                                 sizeof(mat_t), "v5comb mat");
00578                                         bn_mat_mul( tp->tr_l.tl_mat, mat, diskmat );
00579                                         if( bn_mat_is_identity( tp->tr_l.tl_mat ) ) {
00580                                                 bu_free( (char *)tp->tr_l.tl_mat,"tl_mat");
00581                                                 tp->tr_l.tl_mat = (matp_t)NULL;
00582                                         }
00583                                 }
00584                         }
00585                         bu_ptbl_ins( tbl1, (long *)tp );
00586                 }
00587 
00588                 /* use a second bu_ptbl to help build a balanced tree
00589                  *  1 - pick off pairs of pointers from tbl1
00590                  *  2 - make a small tree thats unions the pair
00591                  *  3 - insert that tree into tbl2
00592                  *  4 - insert any leftover pointer from tbl1 into tbl2
00593                  *  5 - swap tbl1 and tbl2
00594                  *  6 - truncate tbl2 and go to step 1
00595                  * stop when tbl2 has less than 2 members
00596                  */
00597                 bu_ptbl_init( tbl2, (BU_PTBL_LEN( tbl1) + 1)/2, "rt_comb_import5: tbl1" );
00598                 while( 1 ) {
00599                         struct bu_ptbl *tmp;
00600 
00601                         for( i=0 ; i<BU_PTBL_LEN( tbl1 ) ; i += 2 ) {
00602                                 union tree *tp1, *tp2, *unionp;
00603                                 int j;
00604 
00605                                 j = i + 1;
00606                                 tp1 = (union tree *)BU_PTBL_GET( tbl1, i );
00607                                 if( j < BU_PTBL_LEN( tbl1 ) ) {
00608                                         tp2 = (union tree *)BU_PTBL_GET( tbl1, j );
00609                                 } else {
00610                                         tp2 = (union tree *)NULL;
00611                                 }
00612 
00613                                 if( tp2 ) {
00614                                         RT_GET_TREE( unionp, resp );
00615                                         unionp->tr_b.magic = RT_TREE_MAGIC;
00616                                         unionp->tr_b.tb_op = OP_UNION;
00617                                         unionp->tr_b.tb_left = tp1;
00618                                         unionp->tr_b.tb_right = tp2;
00619                                         bu_ptbl_ins( tbl2, (long *)unionp );
00620                                 } else {
00621                                         bu_ptbl_ins( tbl2, (long *)tp1 );
00622                                 }
00623 
00624                         }
00625 
00626                         if( BU_PTBL_LEN( tbl2 ) == 0 ) {
00627                                 comb->tree = (union tree *)NULL;
00628                                 bu_ptbl_free( tbl1 );
00629                                 bu_ptbl_free( tbl2 );
00630                                 bu_free( (char *)tbl1, "rt_comb_import5: tbl1" );
00631                                 bu_free( (char *)tbl2, "rt_comb_import5: tbl2" );
00632                                 break;
00633                         } else if( BU_PTBL_LEN( tbl2 ) == 1 ) {
00634                                 comb->tree = (union tree *)BU_PTBL_GET( tbl2, 0 );
00635                                 bu_ptbl_free( tbl1 );
00636                                 bu_ptbl_free( tbl2 );
00637                                 bu_free( (char *)tbl1, "rt_comb_import5: tbl1" );
00638                                 bu_free( (char *)tbl2, "rt_comb_import5: tbl2" );
00639                                 break;
00640                         }
00641 
00642                         tmp = tbl2;
00643                         tbl2 = tbl1;
00644                         tbl1 = tmp;
00645                         bu_ptbl_trunc( tbl2, 0 );
00646                 }
00647                 BU_ASSERT_PTR( leafp, ==, leafp_end );
00648                 goto finish;
00649         }
00650 
00651         /*
00652          *  Bring the RPN expression back from the disk,
00653          *  populating leaves and matricies in the order they are encountered.
00654          */
00655         if( max_stack_depth > MAX_V5_STACK )  {
00656                 bu_log("Combination needs stack depth %d, only have %d, aborted\n",
00657                         max_stack_depth, MAX_V5_STACK);
00658                 return -1;
00659         }
00660         sp = &stack[0];
00661 
00662         for( i=0; i < rpn_len; i++,exprp++ )  {
00663                 union tree      *tp;
00664                 long            mi;
00665 
00666                 RT_GET_TREE( tp, resp );
00667                 tp->tr_b.magic = RT_TREE_MAGIC;
00668 
00669                 switch( *exprp )  {
00670                 case DB5COMB_TOKEN_LEAF:
00671                         tp->tr_l.tl_op = OP_DB_LEAF;
00672                         tp->tr_l.tl_name = bu_strdup( (const char *)leafp );
00673                         leafp += strlen( (const char *)leafp) + 1;
00674 
00675                         /* Get matrix index */
00676                         mi = 4095;                      /* sanity */
00677                         leafp += db5_decode_signed( &mi, leafp, wid );
00678 
00679                         if( mi < 0 )  {
00680                                 /* Signal identity matrix */
00681                                 if( !mat || bn_mat_is_identity( mat ) ) {
00682                                         tp->tr_l.tl_mat = (matp_t)NULL;
00683                                 } else
00684                                         tp->tr_l.tl_mat = bn_mat_dup( mat );
00685                         } else {
00686                                 mat_t diskmat;
00687 
00688                                 /* Unpack indicated matrix mi */
00689                                 BU_ASSERT_LONG( mi, <, nmat );
00690                                 ntohd( (unsigned char *)diskmat,
00691                                         &matp[mi*ELEMENTS_PER_MAT*SIZEOF_NETWORK_DOUBLE],
00692                                         ELEMENTS_PER_MAT);
00693                                 if( !mat || bn_mat_is_identity( mat ) ) {
00694                                         tp->tr_l.tl_mat = bn_mat_dup( diskmat );
00695                                 } else {
00696                                         tp->tr_l.tl_mat = (matp_t)bu_malloc(
00697                                                 sizeof(mat_t), "v5comb mat");
00698                                         bn_mat_mul( tp->tr_l.tl_mat, mat, diskmat );
00699                                         if( bn_mat_is_identity( tp->tr_l.tl_mat ) ) {
00700                                                 bu_free( (char *)tp->tr_l.tl_mat,"tl_mat");
00701                                                 tp->tr_l.tl_mat = (matp_t)NULL;
00702                                         }
00703                                 }
00704                         }
00705                         break;
00706 
00707                 case DB5COMB_TOKEN_UNION:
00708                 case DB5COMB_TOKEN_INTERSECT:
00709                 case DB5COMB_TOKEN_SUBTRACT:
00710                 case DB5COMB_TOKEN_XOR:
00711                         /* These are all binary operators */
00712                         tp->tr_b.tb_regionp = REGION_NULL;
00713                         tp->tr_b.tb_right = *--sp;
00714                         RT_CK_TREE(tp->tr_b.tb_right);
00715                         tp->tr_b.tb_left = *--sp;
00716                         RT_CK_TREE(tp->tr_b.tb_left);
00717                         switch( *exprp )  {
00718                         case DB5COMB_TOKEN_UNION:
00719                                 tp->tr_b.tb_op = OP_UNION;
00720                                 break;
00721                         case DB5COMB_TOKEN_INTERSECT:
00722                                 tp->tr_b.tb_op = OP_INTERSECT;
00723                                 break;
00724                         case DB5COMB_TOKEN_SUBTRACT:
00725                                 tp->tr_b.tb_op = OP_SUBTRACT;
00726                                 break;
00727                         case DB5COMB_TOKEN_XOR:
00728                                 tp->tr_b.tb_op = OP_XOR;
00729                                 break;
00730                         }
00731                         break;
00732 
00733                 case DB5COMB_TOKEN_NOT:
00734                         /* This is a unary operator */
00735                         tp->tr_b.tb_regionp = REGION_NULL;
00736                         tp->tr_b.tb_left = *--sp;
00737                         RT_CK_TREE(tp->tr_b.tb_left);
00738                         tp->tr_b.tb_right = TREE_NULL;
00739                         tp->tr_b.tb_op = OP_NOT;
00740                         break;
00741                 default:
00742                         bu_log("rt_comb_import5() unknown RPN expression token=%d, import aborted\n", *exprp);
00743                         return -1;
00744                 }
00745 
00746                 /* Push this node on the stack */
00747                 *sp++ = tp;
00748         }
00749         BU_ASSERT_PTR( leafp, ==, leafp_end );
00750 
00751         /* There should only be one thing left on the stack, the result */
00752         BU_ASSERT_PTR( sp, ==, &stack[1] );
00753 
00754         comb->tree = stack[0];
00755         RT_CK_TREE(comb->tree);
00756 
00757 finish:
00758         if( ip->idb_avs.magic != BU_AVS_MAGIC )  return 0;      /* OK */
00759 
00760         /* Unpack the attributes */
00761         comb->rgb_valid = 0;
00762         if( (ap = bu_avs_get( &ip->idb_avs, "rgb" )) != NULL )  {
00763                 int     ibuf[3];
00764                 if( sscanf( ap, "%d/%d/%d", ibuf, ibuf+1, ibuf+2 ) == 3 )  {
00765                         VMOVE( comb->rgb, ibuf );
00766                         comb->rgb_valid = 1;
00767                 } else {
00768                         bu_log("unable to parse 'rgb' attribute '%s'\n", ap);
00769                 }
00770         }
00771         if( (ap = bu_avs_get( &ip->idb_avs, "inherit" )) != NULL ) {
00772                 comb->inherit = atoi( ap );
00773         }
00774         if( (ap = bu_avs_get( &ip->idb_avs, "region" )) != NULL )  {
00775             /* Presence of this attribute implies it is a region */
00776             comb->region_flag = 1;
00777 
00778             /* Determine if this is a FASTGEN region */
00779             switch (*ap) {
00780             case 'V' : /* fallthrough */
00781             case '2' :
00782                 comb->is_fastgen = REGION_FASTGEN_VOLUME;
00783                 break;
00784             case 'P' : /* fallthrough */
00785             case '1' :
00786                 comb->is_fastgen = REGION_FASTGEN_PLATE;
00787                 break;
00788             case 'R' : /* fallthrough */
00789             case '0' :
00790                 comb->is_fastgen = REGION_NON_FASTGEN;
00791                 break;
00792             default:
00793                 bu_log("unable to parse 'region' attribute '%s'\n", ap);
00794                 break;
00795             }
00796 
00797             /* get the other GIFT "region" attributes */
00798             if( (ap = bu_avs_get( &ip->idb_avs, "region_id" )) != NULL )  {
00799                 comb->region_id = atoi( ap );
00800             }
00801             if( (ap = bu_avs_get( &ip->idb_avs, "aircode" )) != NULL )  {
00802                 comb->aircode = atoi( ap );
00803             }
00804             if( (ap = bu_avs_get( &ip->idb_avs, "material_id" )) != NULL )  {
00805                 comb->GIFTmater = atoi( ap );
00806 #if 0
00807                 bu_vls_printf( &comb->material, "gift%d", comb->GIFTmater );
00808 #endif
00809             }
00810             if( (ap = bu_avs_get( &ip->idb_avs, "los" )) != NULL )  {
00811                 comb->los = atoi( ap );
00812             }
00813         }
00814         if( (ap = bu_avs_get( &ip->idb_avs, "oshader" )) != NULL )  {
00815                 bu_vls_strcat( &comb->shader, ap );
00816         }
00817 
00818         return 0;                       /* OK */
00819 }
00820 
00821 /*
00822  * Local Variables:
00823  * mode: C
00824  * tab-width: 8
00825  * c-basic-offset: 4
00826  * indent-tabs-mode: t
00827  * End:
00828  * ex: shiftwidth=4 tabstop=8
00829  */

Generated on Mon Sep 18 01:24:49 2006 for BRL-CAD by  doxygen 1.4.6