home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / graphics / ftpovstc / csg.c < prev    next >
C/C++ Source or Header  |  1994-05-25  |  16KB  |  605 lines

  1. /****************************************************************************
  2. *
  3. *  ATTENTION!!!
  4. *
  5. *  THIS FILE HAS BEEN MODIFIED!!! IT IS NOT PART OF THE OFFICAL
  6. *  POV-RAY 2.2 DISTRIBUTION!!!
  7. *
  8. *  THIS FILE IS PART OF "FASTER THAN POV-RAY" (VERSION 1.1),
  9. *  A SPED-UP VERSION OF POV-RAY 2.2. USE AT YOUR OWN RISK!!!!!!
  10. *
  11. *  New files: addon0.c, addon1.c, addon2.c, addon3.c, addon.h
  12. *
  13. *  The additional modules were written by Dieter Bayer.
  14. *
  15. *  Send comments, suggestions, bugs, ideas ... to:
  16. *
  17. *  dieter@cip.e-technik.uni-erlangen.de
  18. *
  19. *  All changed/added lines are enclosed in #ifdef DB_CODE ... #endif
  20. *
  21. *  The vista projection was taken from:
  22. *
  23. *    A. Hashimoto, T. Akimoto, K. Mase, and Y. Suenaga, 
  24. *    "Vista Ray-Tracing: High Speed Ray Tracing Using Perspective
  25. *    Projection Image", New Advances in Computer Graphics, Proceedings
  26. *    of CG International '89, R. A. Earnshaw, B. Wyvill (Eds.), 
  27. *    Springer, ..., pp. 549-560
  28. *
  29. *  The idea for the light buffer was taken from:
  30. *
  31. *    E. Haines and D. Greenberg, "The Light Buffer: A Shadow-Testing 
  32. *    Accelerator", IEEE CG&A, Vol. 6, No. 9, Sept. 1986, pp. 6-16
  33. *
  34. *****************************************************************************/
  35.  
  36. /****************************************************************************
  37. *                   csg.c
  38. *
  39. *  This module implements routines for constructive solid geometry.
  40. *
  41. *  from Persistence of Vision Raytracer
  42. *  Copyright 1993 Persistence of Vision Team
  43. *---------------------------------------------------------------------------
  44. *  NOTICE: This source code file is provided so that users may experiment
  45. *  with enhancements to POV-Ray and to port the software to platforms other
  46. *  than those supported by the POV-Ray Team.  There are strict rules under
  47. *  which you are permitted to use this file.  The rules are in the file
  48. *  named POVLEGAL.DOC which should be distributed with this file. If
  49. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  50. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  51. *  Forum.  The latest version of POV-Ray may be found there as well.
  52. *
  53. * This program is based on the popular DKB raytracer version 2.12.
  54. * DKBTrace was originally written by David K. Buck.
  55. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  56. *
  57. *****************************************************************************/
  58.  
  59. #include "frame.h"
  60. #include "vector.h"
  61. #include "povproto.h"
  62. #ifdef DB_CODE
  63. /* Changes necessary for better bounding box calculation of intersections. */
  64. #include "addon.h"
  65.  
  66. extern METHODS Plane_Methods;
  67. #endif
  68.  
  69. METHODS CSG_Union_Methods =
  70.   { 
  71.   All_CSG_Union_Intersections,
  72.   Inside_CSG_Union, NULL /*Normal*/,
  73.   Copy_CSG,
  74.   Translate_CSG, Rotate_CSG,
  75.   Scale_CSG, Transform_CSG, Invert_CSG_Union, Destroy_CSG
  76. };
  77.  
  78. METHODS CSG_Merge_Methods =
  79.   { 
  80.   All_CSG_Merge_Intersections,
  81.   Inside_CSG_Union, NULL /*Normal*/,
  82.   Copy_CSG,
  83.   Translate_CSG, Rotate_CSG,
  84.   Scale_CSG, Transform_CSG, Invert_CSG_Union, Destroy_CSG
  85. };
  86.  
  87. METHODS CSG_Intersection_Methods =
  88.   { 
  89.   All_CSG_Intersect_Intersections,
  90.   Inside_CSG_Intersection, NULL /*Normal*/,
  91.   Copy_CSG,
  92.   Translate_CSG, Rotate_CSG,
  93.   Scale_CSG, Transform_CSG, Invert_CSG_Intersection, Destroy_CSG
  94. };
  95.  
  96. int All_CSG_Union_Intersections (Object, Ray, Depth_Stack)
  97. OBJECT *Object;
  98. RAY *Ray;
  99. ISTACK *Depth_Stack;
  100.   {
  101.   register int Found;
  102.   OBJECT *Current_Sib, *Clip;
  103.   ISTACK *Local_Stack;
  104.   INTERSECTION *Sibling_Intersection;
  105.  
  106.   Found = FALSE;
  107.  
  108.   if ((Clip = Object->Clip) == NULL) /* Use shortcut if no clip */
  109.     {
  110.     for (Current_Sib = ((CSG *)Object)->Children;
  111.          Current_Sib != NULL ;
  112.          Current_Sib = Current_Sib->Sibling)
  113.       if (Ray_In_Bounds (Ray, Current_Sib->Bound))
  114.         if (All_Intersections (Current_Sib, Ray, Depth_Stack))
  115.           Found = TRUE;
  116.     }
  117.   else
  118.     {
  119.     Local_Stack = open_istack ();
  120.  
  121.     for (Current_Sib = ((CSG *)Object)->Children;
  122.          Current_Sib != NULL ;
  123.          Current_Sib = Current_Sib->Sibling)
  124.       if (Ray_In_Bounds (Ray, Current_Sib->Bound))
  125.         if (All_Intersections (Current_Sib, Ray, Local_Stack))
  126.           while ((Sibling_Intersection = pop_entry(Local_Stack)) != NULL)
  127.             if (Point_In_Clip (&Sibling_Intersection->IPoint, Clip))
  128.               {
  129.               push_copy (Depth_Stack, Sibling_Intersection);
  130.               Found = TRUE;
  131.               }
  132.     close_istack (Local_Stack);
  133.     }
  134.   return (Found);
  135.   }
  136.  
  137. int All_CSG_Intersect_Intersections (Object, Ray, Depth_Stack)
  138. OBJECT *Object;
  139. RAY *Ray;
  140. ISTACK *Depth_Stack;
  141.   {
  142.   int Maybe_Found, Found;
  143.   OBJECT *Current_Sib, *Inside_Sib;
  144.   ISTACK *Local_Stack;
  145.   INTERSECTION *Sibling_Intersection;
  146.  
  147.   Local_Stack = open_istack ();
  148.  
  149.   Found = FALSE;
  150.  
  151.   for (Current_Sib = ((CSG *)Object)->Children;
  152.   Current_Sib != NULL;
  153.   Current_Sib = Current_Sib->Sibling) 
  154.     {
  155.     if (Ray_In_Bounds (Ray, Current_Sib->Bound))
  156.       if (All_Intersections (Current_Sib, Ray, Local_Stack))
  157.         while ((Sibling_Intersection = pop_entry(Local_Stack)) != NULL)
  158.           {
  159.           Maybe_Found = TRUE;
  160.           for (Inside_Sib = ((CSG *)Object)->Children;
  161.           Inside_Sib != NULL;
  162.           Inside_Sib = Inside_Sib->Sibling)
  163.             if (Inside_Sib != Current_Sib)
  164.               if (!Inside_Object (&Sibling_Intersection->IPoint, Inside_Sib)) 
  165.                 {
  166.                 Maybe_Found = FALSE;
  167.                 break;
  168.                 }
  169.           if (Maybe_Found)
  170.             if (Point_In_Clip (&Sibling_Intersection->IPoint, Object->Clip))
  171.               {
  172.               push_copy(Depth_Stack, Sibling_Intersection);
  173.               Found = TRUE;
  174.               }
  175.           }
  176.     }
  177.   close_istack (Local_Stack);
  178.   return (Found);
  179.   }
  180.  
  181. int All_CSG_Merge_Intersections (Object, Ray, Depth_Stack)
  182. OBJECT *Object;
  183. RAY *Ray;
  184. ISTACK *Depth_Stack;
  185.   {
  186.   register int Found, inside_flag;
  187.   OBJECT *Sib1, *Sib2;
  188.   ISTACK *Local_Stack;
  189.   INTERSECTION *Sibling_Intersection;
  190.  
  191.   Found = FALSE;
  192.  
  193.   Local_Stack = open_istack ();
  194.  
  195.   for (Sib1 = ((CSG *)Object)->Children;
  196.        Sib1 != NULL ;
  197.        Sib1 = Sib1->Sibling)
  198.     if (Ray_In_Bounds (Ray, Sib1->Bound))
  199.       if (All_Intersections (Sib1, Ray, Local_Stack))
  200.         while ((Sibling_Intersection = pop_entry (Local_Stack)) !=  NULL)
  201.           if (Point_In_Clip (&Sibling_Intersection->IPoint,Object->Clip)) 
  202.           {
  203.           inside_flag = TRUE;
  204.           for (Sib2 = ((CSG *)Object)->Children;
  205.                Sib2 != NULL && inside_flag == TRUE;
  206.                Sib2 = Sib2->Sibling)
  207.             if (Sib1 != Sib2)
  208.               if (Inside_Object(&Sibling_Intersection->IPoint,Sib2))
  209.                 inside_flag = FALSE;
  210.           if (inside_flag == TRUE) 
  211.             {
  212.             Found = TRUE;
  213.             push_copy (Depth_Stack, Sibling_Intersection);
  214.             }
  215.           }
  216.   close_istack (Local_Stack);
  217.   return (Found);
  218.   }
  219.  
  220. int Inside_CSG_Union (IPoint, Object)
  221. VECTOR *IPoint;
  222. OBJECT *Object;
  223.   {
  224.   OBJECT *Current_Sib;
  225.  
  226.   for (Current_Sib = ((CSG *)Object)->Children;
  227.   Current_Sib != NULL ;
  228.   Current_Sib = Current_Sib->Sibling)
  229.     if (Inside_Object (IPoint, Current_Sib))
  230.       return (TRUE);
  231.  
  232.   return (FALSE);
  233.   }
  234.  
  235. int Inside_CSG_Intersection (IPoint, Object)
  236. OBJECT *Object;
  237. VECTOR *IPoint;
  238.   {
  239.   OBJECT *Current_Sib;
  240.  
  241.   for (Current_Sib = ((CSG *)Object)->Children;
  242.   Current_Sib != NULL ;
  243.   Current_Sib = Current_Sib->Sibling)
  244.     if (!Inside_Object (IPoint, Current_Sib))
  245.       return (FALSE);
  246.  
  247.   return (TRUE);
  248.   }
  249.  
  250. void *Copy_CSG (Object)
  251. OBJECT *Object;
  252.   {
  253.   CSG *New;
  254.   OBJECT *Old_Sib, *New_Sib, *Prev_Sib;
  255.  
  256.   if ((New = (CSG *) malloc (sizeof (CSG))) == NULL)
  257.     MAError ("CSG");
  258.  
  259. #ifdef DB_CODE
  260.   /* Changes necessary for better bounding box calculation of intersections. */
  261.   /* Make sure that all entries of the old csg is copied */
  262.   *New = *(CSG *)Object;
  263. #endif
  264.  
  265.   New->Children = Prev_Sib = NULL;
  266.  
  267.   for (Old_Sib = ((CSG *)Object)->Children;
  268.   Old_Sib != NULL ;
  269.   Old_Sib = Old_Sib->Sibling) 
  270.     {
  271.     New_Sib = Copy_Object (Old_Sib);
  272.  
  273.     if (New->Children == NULL)
  274.       New->Children = New_Sib;
  275.  
  276.     if (Prev_Sib != NULL)
  277.       Prev_Sib->Sibling = New_Sib;
  278.  
  279.     Prev_Sib = New_Sib;
  280.     }
  281.  
  282.   return (New);
  283.   }
  284.  
  285. void Translate_CSG (Object, Vector)
  286. OBJECT *Object;
  287. VECTOR *Vector;
  288.   {
  289.   OBJECT *Sib;
  290. #ifdef DB_CODE
  291.   /* Changes necessary for better bounding box calculation of intersections. */
  292.   TRANSFORM Trans;
  293. #endif
  294.  
  295.   for (Sib = ((CSG *) Object)->Children;
  296.   Sib != NULL ;
  297.   Sib = Sib->Sibling)
  298.     Translate_Object (Sib, Vector);
  299. #ifdef DB_CODE
  300.   /* Changes necessary for better bounding box calculation of intersections. */
  301.   /* Compute_CSG_Bounds must not be used here!!! */
  302.   Compute_Translation_Transform(&Trans, Vector);
  303.   recompute_bbox(&Object->Bounds, &Trans);
  304. #else
  305.   Compute_CSG_Bounds(Object);
  306. #endif
  307.   }
  308.  
  309. void Rotate_CSG (Object, Vector)
  310. OBJECT *Object;
  311. VECTOR *Vector;
  312.   {
  313.   OBJECT *Sib;
  314. #ifdef DB_CODE
  315.   /* Changes necessary for better bounding box calculation of intersections. */
  316.   TRANSFORM Trans;
  317. #endif
  318.  
  319.   for (Sib = ((CSG *) Object)->Children;
  320.   Sib != NULL ;
  321.   Sib = Sib->Sibling)
  322.     Rotate_Object (Sib, Vector);
  323. #ifdef DB_CODE
  324.   /* Changes necessary for better bounding box calculation of intersections. */
  325.   /* Compute_CSG_Bounds must not be used here!!! */
  326.   Compute_Rotation_Transform(&Trans, Vector);
  327.   recompute_bbox(&Object->Bounds, &Trans);
  328. #else
  329.   Compute_CSG_Bounds(Object);
  330. #endif
  331.   }
  332.  
  333. void Scale_CSG (Object, Vector)
  334. OBJECT *Object;
  335. VECTOR *Vector;
  336.   {
  337.   OBJECT *Sib;
  338. #ifdef DB_CODE
  339.   /* Changes necessary for better bounding box calculation of intersections. */
  340.   TRANSFORM Trans;
  341. #endif
  342.  
  343.   for (Sib = ((CSG *) Object)->Children;
  344.   Sib != NULL ;
  345.   Sib = Sib->Sibling)
  346.     Scale_Object (Sib, Vector);
  347. #ifdef DB_CODE
  348.   /* Changes necessary for better bounding box calculation of intersections. */
  349.   /* Compute_CSG_Bounds must not be used here!!! */
  350.   Compute_Scaling_Transform(&Trans, Vector);
  351.   recompute_bbox(&Object->Bounds, &Trans);
  352. #else
  353.   Compute_CSG_Bounds(Object);
  354. #endif
  355.   }
  356.  
  357. void Transform_CSG (Object, Trans)
  358. OBJECT *Object;
  359. TRANSFORM *Trans;
  360.   {
  361.   OBJECT *Sib;
  362.  
  363.   for (Sib = ((CSG *) Object)->Children;
  364.   Sib != NULL ;
  365.   Sib = Sib->Sibling)
  366.     Transform_Object (Sib, Trans);
  367.   Compute_CSG_Bounds(Object);
  368.   }
  369.  
  370. void Destroy_CSG (Object)
  371. OBJECT *Object;
  372.   {
  373.   Destroy_Object (((CSG *) Object)->Children);
  374.   free (Object);
  375.   }
  376.  
  377. void Invert_CSG_Union (Object)
  378. OBJECT *Object;
  379.   {
  380.   OBJECT *Sib;
  381.  
  382.   Object->Methods = &CSG_Intersection_Methods;
  383.  
  384.   for (Sib = ((CSG *)Object)->Children;
  385.   Sib != NULL ;
  386.   Sib = Sib->Sibling)
  387.     Invert_Object (Sib);
  388. #ifdef DB_CODE
  389.   /* Changes necessary for better bounding box calculation of intersections. */
  390.   ((CSG *)Object)->Inverted ^= TRUE;
  391. #endif
  392.   }
  393.  
  394. void Invert_CSG_Intersection (Object)
  395. OBJECT *Object;
  396.   {
  397.   OBJECT *Sib;
  398.  
  399.   Object->Methods = &CSG_Union_Methods;
  400.  
  401.   for (Sib = ((CSG *)Object)->Children;
  402.   Sib != NULL ;
  403.   Sib = Sib->Sibling)
  404.     Invert_Object (Sib);
  405. #ifdef DB_CODE
  406.   /* Changes necessary for better bounding box calculation of intersections. */
  407.   ((CSG *)Object)->Inverted ^= TRUE;
  408. #endif
  409.   }
  410.  
  411. CSG *Create_CSG_Union ()
  412.   {
  413.   CSG *New;
  414.  
  415.   if ((New = (CSG *) malloc (sizeof (CSG))) == NULL)
  416.     MAError ("union");
  417.  
  418.   INIT_OBJECT_FIELDS(New, UNION_OBJECT, &CSG_Union_Methods)
  419.  
  420.     New->Children = NULL;
  421. #ifdef DB_CODE
  422.   /* Changes necessary for better bounding box calculation of intersections. */
  423.   New->Inverted = FALSE;
  424. #endif
  425.   return (New);
  426.   }
  427.  
  428. CSG *Create_CSG_Merge ()
  429.   {
  430.   CSG *New;
  431.  
  432.   if ((New = (CSG *) malloc (sizeof (CSG))) == NULL)
  433.     MAError ("merge");
  434.  
  435.   INIT_OBJECT_FIELDS(New, MERGE_OBJECT, &CSG_Merge_Methods)
  436.  
  437.     New->Children = NULL;
  438. #ifdef DB_CODE
  439.   /* Changes necessary for better bounding box calculation of intersections. */
  440.   New->Inverted = FALSE;
  441. #endif
  442.   return (New);
  443.   }
  444.  
  445. CSG *Create_CSG_Intersection ()
  446.   {
  447.   CSG *New;
  448.  
  449.   if ((New = (CSG *) malloc (sizeof (CSG))) == NULL)
  450.     MAError ("intersection");
  451.  
  452.   INIT_OBJECT_FIELDS(New, INTERSECTION_OBJECT, &CSG_Intersection_Methods)
  453.  
  454.     New->Children = NULL;
  455. #ifdef DB_CODE
  456.   /* Changes necessary for better bounding box calculation of intersections. */
  457.   New->Inverted = FALSE;
  458. #endif
  459.   return (New);
  460.   }
  461.  
  462. void Compute_CSG_Bounds (Object)
  463. OBJECT *Object;
  464.   {
  465. #ifdef DB_CODE
  466.   /* Changes necessary for better bounding box calculation of intersections. */
  467.   DBL Old_Volume, New_Volume;
  468.   VECTOR NewMin, NewMax, TmpMin, TmpMax;
  469.   OBJECT *Sib;
  470.  
  471.   if (Object->Methods == &CSG_Intersection_Methods)
  472.   {
  473.     /* Calculate the bounding box of a CSG intersection object
  474.        by intersecting the bounding boxes of all children. */
  475.  
  476.     NewMin.x = NewMin.y = NewMin.z = -BOUND_HUGE;
  477.     NewMax.x = NewMax.y = NewMax.z = +BOUND_HUGE;
  478.  
  479.     for (Sib = ((CSG *)Object)->Children; Sib != NULL; Sib = Sib->Sibling)
  480.     {
  481.       /* Inverted objects mustn't be considered */
  482.  
  483.       if (!Test_Inverted(Sib))
  484.       {
  485.     if (Sib->Methods == &Plane_Methods)
  486.     {
  487.       Compute_Plane_Min_Max((PLANE *)Sib, &TmpMin, &TmpMax);
  488.     }
  489.     else
  490.     {
  491.       TmpMin.x = Sib->Bounds.Lower_Left.x;
  492.       TmpMin.y = Sib->Bounds.Lower_Left.y;
  493.       TmpMin.z = Sib->Bounds.Lower_Left.z;
  494.       TmpMax.x = Sib->Bounds.Lower_Left.x + Sib->Bounds.Lengths.x;
  495.       TmpMax.y = Sib->Bounds.Lower_Left.y + Sib->Bounds.Lengths.y;
  496.       TmpMax.z = Sib->Bounds.Lower_Left.z + Sib->Bounds.Lengths.z;
  497.     }
  498.  
  499.     NewMin.x = max(NewMin.x, TmpMin.x);
  500.     NewMin.y = max(NewMin.y, TmpMin.y);
  501.     NewMin.z = max(NewMin.z, TmpMin.z);
  502.     NewMax.x = min(NewMax.x, TmpMax.x);
  503.     NewMax.y = min(NewMax.y, TmpMax.y);
  504.     NewMax.z = min(NewMax.z, TmpMax.z);
  505.       }
  506.     }
  507.   }
  508.   else
  509.   {
  510.     /* Calculate the bounding box of a CSG merge/union object. */
  511.  
  512.     NewMin.x = NewMin.y = NewMin.z = +BOUND_HUGE;
  513.     NewMax.x = NewMax.y = NewMax.z = -BOUND_HUGE;
  514.  
  515.     for (Sib = ((CSG *)Object)->Children; Sib != NULL; Sib = Sib->Sibling)
  516.     {
  517.       if (Sib->Methods == &Plane_Methods)
  518.       {
  519.     Compute_Plane_Min_Max((PLANE *)Sib, &TmpMin, &TmpMax);
  520.       }
  521.       else
  522.       {
  523.     TmpMin.x = Sib->Bounds.Lower_Left.x;
  524.     TmpMin.y = Sib->Bounds.Lower_Left.y;
  525.     TmpMin.z = Sib->Bounds.Lower_Left.z;
  526.     TmpMax.x = Sib->Bounds.Lower_Left.x + Sib->Bounds.Lengths.x;
  527.     TmpMax.y = Sib->Bounds.Lower_Left.y + Sib->Bounds.Lengths.y;
  528.     TmpMax.z = Sib->Bounds.Lower_Left.z + Sib->Bounds.Lengths.z;
  529.       }
  530.  
  531.       NewMin.x = min(NewMin.x, TmpMin.x);
  532.       NewMin.y = min(NewMin.y, TmpMin.y);
  533.       NewMin.z = min(NewMin.z, TmpMin.z);
  534.       NewMax.x = max(NewMax.x, TmpMax.x);
  535.       NewMax.y = max(NewMax.y, TmpMax.y);
  536.       NewMax.z = max(NewMax.z, TmpMax.z);
  537.     }
  538.   }
  539.  
  540.   if ((NewMin.x > NewMax.x) || (NewMin.y > NewMax.y) || (NewMin.z > NewMax.z))
  541.   {
  542.     Warn("Degenerate CSG bounding box (not used!)\n",1.0);
  543.   }
  544.   else
  545.   {
  546.     New_Volume = (NewMax.x - NewMin.x) *
  547.          (NewMax.y - NewMin.y) *
  548.          (NewMax.z - NewMin.z);
  549.  
  550.     BOUNDS_VOLUME(Old_Volume, Object->Bounds);
  551.  
  552.     if (New_Volume < Old_Volume)
  553.     {
  554.       Object->Bounds.Lower_Left = NewMin;
  555.       VSub (Object->Bounds.Lengths, NewMax, NewMin);
  556.  
  557.       /* Beware of lengths too large */
  558.  
  559.       if (Object->Bounds.Lengths.x > CRITICAL_LENGTH)
  560.       {
  561.     Object->Bounds.Lower_Left.x = -BOUND_HUGE/2;
  562.     Object->Bounds.Lengths.x = BOUND_HUGE;
  563.       }
  564.       if (Object->Bounds.Lengths.y > CRITICAL_LENGTH)
  565.       {
  566.     Object->Bounds.Lower_Left.y = -BOUND_HUGE/2;
  567.     Object->Bounds.Lengths.y = BOUND_HUGE;
  568.       }
  569.       if (Object->Bounds.Lengths.z > CRITICAL_LENGTH)
  570.       {
  571.     Object->Bounds.Lower_Left.z = -BOUND_HUGE/2;
  572.     Object->Bounds.Lengths.z = BOUND_HUGE;
  573.       }
  574.     }
  575.   }
  576. #else
  577.   VECTOR mins, maxs;
  578.   DBL tmin, tmax;
  579.   OBJECT *Sib;
  580.  
  581.   Make_Vector(&mins,  BOUND_HUGE,  BOUND_HUGE,  BOUND_HUGE);
  582.   Make_Vector(&maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
  583.  
  584.   for (Sib = ((CSG *) Object)->Children;
  585.   Sib != NULL ;
  586.   Sib = Sib->Sibling)
  587.     {
  588.     tmin = Sib->Bounds.Lower_Left.x;
  589.     tmax = Sib->Bounds.Lower_Left.x + Sib->Bounds.Lengths.x;
  590.     if (tmin < mins.x) mins.x = tmin;
  591.     if (tmax > maxs.x) maxs.x = tmax;
  592.     tmin = Sib->Bounds.Lower_Left.y;
  593.     tmax = Sib->Bounds.Lower_Left.y + Sib->Bounds.Lengths.y;
  594.     if (tmin < mins.y) mins.y = tmin;
  595.     if (tmax > maxs.y) maxs.y = tmax;
  596.     tmin = Sib->Bounds.Lower_Left.z;
  597.     tmax = Sib->Bounds.Lower_Left.z + Sib->Bounds.Lengths.z;
  598.     if (tmin < mins.z) mins.z = tmin;
  599.     if (tmax > maxs.z) maxs.z = tmax;
  600.     }
  601.   Object->Bounds.Lower_Left = mins;
  602.   VSub(Object->Bounds.Lengths, maxs, mins);
  603. #endif
  604.   }
  605.