home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QD3D / WorldRayPickSample / Source / WRay_Scene.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  17.9 KB  |  752 lines  |  [TEXT/CWIE]

  1. /* 
  2.  *    WRay_Scene.c
  3.  *
  4.  *    QuickDraw 3D 1.6 Sample
  5.  *    Robert Dierkes
  6.  *
  7.  *     07/28/98    RDD        Created.
  8.  */
  9.  
  10. /*------------------*/
  11. /*    Include Files    */
  12. /*------------------*/
  13. #include "QD3D.h"
  14. #include "QD3DDrawContext.h"
  15. #include "QD3DCamera.h"
  16. #include "QD3DLight.h"
  17. #include "QD3DGeometry.h"
  18. #include "QD3DGroup.h"
  19. #include "QD3DMath.h"
  20. #include "QD3DRenderer.h"
  21. #include "QD3DShader.h"
  22. #include "QD3DTransform.h"
  23. #include "QD3DView.h"
  24.  
  25. #include "WRay_Error.h"
  26. #include "WRay_Document.h"
  27. #include "WRay_Main.h"
  28. #include "WRay_Memory.h"
  29. #include "WRay_Scene.h"
  30. #include "WRay_System.h"
  31.  
  32. #include <math.h>
  33.  
  34.  
  35. /*------------------*/
  36. /*      Constants        */
  37. /*------------------*/
  38. #define    kDefaultCamLoc        0.0, 0.0, 10.0
  39. #define    kDefaultPtOfInt        0.0, 0.0, 0.0
  40. #define    kDefaultUpVector    0.0, 1.0, 0.0
  41. #define    kAngleDelta            Q3Math_DegreesToRadians(2.0f)
  42.  
  43.  
  44. /*----------------------*/
  45. /*    Global Declarations    */
  46. /*----------------------*/
  47. static    TQ3CameraObject    gCamera            = NULL;
  48. static    float            gRotationAngle    = Q3Math_DegreesToRadians(90.0f);
  49. static    TQ3Boolean        gDoRotation        = kQ3False;
  50.  
  51.  
  52. /*----------------------*/
  53. /*    Local Prototypes    */
  54. /*----------------------*/
  55. static
  56. TQ3DrawContextObject Scene_NewDrawContext(
  57.             WindowPtr        pWindow);
  58. static
  59. TQ3Status Scene_ChangeViewAttributes(
  60.             TQ3ViewObject    view);
  61. static
  62. TQ3Status Scene_NewRenderer(
  63.             TQ3ViewObject    view,
  64.             TQ3ObjectType    rendererType);
  65. static
  66. TQ3CameraObject Scene_NewCamera(
  67.             Rect            *pWindowRect);
  68. static
  69. TQ3GroupObject Scene_NewLights(
  70.             void);
  71. static
  72. TQ3Status    Scene_NewStyles(
  73.             TQ3GroupObject    group);
  74. static
  75. TQ3Status    Scene_NewScene(
  76.             TQ3GroupObject    group);
  77. static
  78. TQ3Status    Scene_NewBoxSides(
  79.             TQ3GroupObject    group,
  80.             TQ3BoundingBox    *pBBox);
  81.  
  82.  
  83. /*
  84.  *    Scene_NewView
  85.  */
  86. TQ3ViewObject     Scene_NewView(
  87.     WindowPtr        pWindow)
  88. {
  89.     TQ3Status                status = kQ3Failure;
  90.     TQ3ViewObject            view;
  91.     TQ3DrawContextObject    drawContext;
  92.     TQ3CameraObject            camera;
  93.     TQ3GroupObject            lights;
  94.  
  95.     view = Q3View_New();
  96.     DEBUG_ASSERT(view != NULL, Scene_NewView);
  97.     if (view == NULL) {
  98.         goto bail;
  99.     }
  100.  
  101.     /* Create and set draw context */
  102.     DEBUG_ASSERT(pWindow != NULL, Scene_NewView);
  103.     if ((drawContext = Scene_NewDrawContext(pWindow)) == NULL) {
  104.         goto bail;
  105.     }
  106.  
  107.     if ((status = Q3View_SetDrawContext(view, drawContext)) == kQ3Failure) {
  108.         goto bail;
  109.     }
  110.     Object_Dispose_NULL(&drawContext);
  111.  
  112.     /* Change view's attributes */
  113.     if ((status = Scene_ChangeViewAttributes(view)) == kQ3Failure) {
  114.         goto bail;
  115.     }
  116.  
  117.     /* Create and set renderer */
  118.     if ((status = Scene_NewRenderer(view, kQ3RendererTypeInteractive)) == kQ3Failure) {
  119.         goto bail;
  120.     }
  121.  
  122.     /* Create and set camera */
  123.     if ((camera = Scene_NewCamera(&pWindow->portRect)) == NULL) {
  124.         goto bail;
  125.     }
  126.  
  127.     if ((status = Q3View_SetCamera(view, camera)) == kQ3Failure) {
  128.         goto bail;
  129.     }
  130.     /* Save reference to camera */
  131.     gCamera = camera;
  132.     Object_Dispose_NULL(&camera);
  133.  
  134.  
  135.     /* Create and set lights */
  136.     if ((lights = Scene_NewLights()) == NULL) {
  137.         goto bail;
  138.     }
  139.  
  140.     if ((status = Q3View_SetLightGroup(view, lights)) == kQ3Failure) {
  141.         goto bail;
  142.     }
  143.     Object_Dispose_NULL(&lights);
  144.  
  145.     return (view);
  146.  
  147. bail:
  148.     return NULL;
  149. }
  150.  
  151.  
  152. /*
  153.  *    Scene_NewDrawContext
  154.  */
  155. static
  156. TQ3DrawContextObject Scene_NewDrawContext(
  157.     WindowPtr        pWindow)
  158. {
  159.     TQ3DrawContextObject        drawContext;
  160.     TQ3DrawContextData            *pDCData;
  161.     TQ3MacDrawContextData        macDrawContextData;
  162.  
  163.     pDCData = &macDrawContextData.drawContextData;
  164.  
  165.     #define    kDefaultClearImageColor        1.0, 0.15, 0.15, 0.15
  166.  
  167.     /* Fill in common draw context data */
  168.     pDCData->clearImageMethod = kQ3ClearMethodWithColor;
  169.     Q3ColorARGB_Set(&pDCData->clearImageColor, kDefaultClearImageColor);
  170.     pDCData->paneState         = kQ3False;
  171.     pDCData->maskState         = kQ3False;
  172.  
  173.  
  174.     /* Mac draw context */
  175.     pDCData->doubleBufferState = kQ3True;
  176.  
  177.     /* This is the window associated with the view */
  178.     DEBUG_ASSERT(pWindow != NULL, Scene_NewDrawContext);
  179.     macDrawContextData.window   = (CGrafPtr) pWindow;
  180.     macDrawContextData.library  = kQ3Mac2DLibraryNone;
  181.     macDrawContextData.viewPort = NULL;
  182.     macDrawContextData.grafPort = NULL;
  183.  
  184.     /* Create draw context and return it, if it’s nil the caller must handle */
  185.     drawContext = Q3MacDrawContext_New(&macDrawContextData);
  186.  
  187.     DEBUG_ASSERT(drawContext != NULL, Scene_NewDrawContext);
  188.  
  189.     #undef    kDefaultClearImageColor
  190.  
  191.     return drawContext;
  192. }
  193.  
  194.  
  195. /*
  196.  *    Scene_ChangeViewAttributes
  197.  */
  198. TQ3Status Scene_ChangeViewAttributes(
  199.     TQ3ViewObject    view)
  200. {
  201.     TQ3Status            status = kQ3Failure;
  202.     TQ3AttributeSet     attributeSet = NULL;
  203.     TQ3ColorRGB            color = { 1.0, 0.0, 0.0 };
  204.  
  205.     status = Q3View_GetDefaultAttributeSet(view, &attributeSet);
  206.     DEBUG_ASSERT(status == kQ3Success, Q3View_GetDefaultAttributeSet);
  207.     DEBUG_ASSERT(attributeSet != NULL, Q3View_GetDefaultAttributeSet);
  208.     if (status == kQ3Failure) {
  209.         return status;
  210.     }
  211.  
  212.     /* Change view's specular color */
  213.     Q3AttributeSet_Add(attributeSet, kQ3AttributeTypeSpecularColor, &color);
  214.  
  215.     status = Q3View_SetDefaultAttributeSet(view, attributeSet);
  216.     DEBUG_ASSERT(status == kQ3Success, Q3View_SetDefaultAttributeSet);
  217.     Object_Dispose_NULL(&attributeSet);
  218.  
  219.     return status;
  220. }
  221.  
  222.  
  223. /*
  224.  *    Scene_NewRenderer
  225.  */
  226. TQ3Status Scene_NewRenderer(
  227.     TQ3ViewObject    view,
  228.     TQ3ObjectType    rendererType)
  229. {
  230.     TQ3Status            status = kQ3Failure;
  231.     TQ3RendererObject    renderer = NULL;
  232.  
  233.     if (view == NULL) {
  234.         ERROR_DEBUG_STR("Scene_NewRenderer: view == NULL.");
  235.         return status;
  236.     }
  237.  
  238.     /* Use the interactive software renderer if present */
  239.     if ((renderer = Q3Renderer_NewFromType(rendererType)) != NULL) {
  240.  
  241.         if ((status = Q3View_SetRenderer(view, renderer)) == kQ3Success) {
  242.             /* Use hardware accelerator for IR if present */
  243.             if (rendererType == kQ3RendererTypeInteractive) {
  244.                 Q3InteractiveRenderer_SetDoubleBufferBypass(renderer, kQ3True);
  245.             } 
  246.         } 
  247.         else {
  248.             ERROR_DEBUG_STR("Scene_NewRenderer: Q3View_SetRenderer failed.");
  249.         }
  250.     }
  251.     else {
  252.         /* Default to wireframe renderer */
  253.         if ((renderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame)) != NULL) {
  254.  
  255.             if ((status = Q3View_SetRenderer(view, renderer)) == kQ3Failure) {
  256.                 ERROR_DEBUG_STR("Scene_NewRenderer: Q3View_SetRenderer(WF) failed.");
  257.             }
  258.         }
  259.     }
  260.  
  261.     Object_Dispose_NULL(&renderer);
  262.  
  263.     return status;
  264. }
  265.  
  266.  
  267. /*
  268.  *    Scene_NewCamera
  269.  */
  270. static
  271. TQ3CameraObject Scene_NewCamera(
  272.     Rect            *pWindowRect)
  273. {
  274.     TQ3ViewAngleAspectCameraData
  275.                         perspectiveData;
  276.     TQ3CameraObject        camera;
  277.     TQ3Point3D             from    = { kDefaultCamLoc };
  278.     TQ3Point3D             to        = { kDefaultPtOfInt };
  279.     TQ3Vector3D         up        = { kDefaultUpVector };
  280.  
  281.     perspectiveData.cameraData.placement.cameraLocation     = from;
  282.     perspectiveData.cameraData.placement.pointOfInterest     = to;
  283.     perspectiveData.cameraData.placement.upVector             = up;
  284.  
  285.     perspectiveData.cameraData.range.hither    = kDefaultHither;
  286.     perspectiveData.cameraData.range.yon     = kDefaultYon;
  287.  
  288.     perspectiveData.cameraData.viewPort.origin.x = -1.0;
  289.     perspectiveData.cameraData.viewPort.origin.y =  1.0;
  290.     perspectiveData.cameraData.viewPort.width    =  2.0;
  291.     perspectiveData.cameraData.viewPort.height   =  2.0;
  292.  
  293.     perspectiveData.fov                = kDefaultFieldOfView;
  294.     perspectiveData.aspectRatioXToY    =
  295.         (float) (pWindowRect->right -  pWindowRect->left) / 
  296.         (float) (pWindowRect->bottom - pWindowRect->top);
  297.  
  298.     camera = Q3ViewAngleAspectCamera_New(&perspectiveData);
  299.     DEBUG_ASSERT(camera != NULL, Scene_NewCamera);
  300.  
  301.     return camera;
  302. }
  303.  
  304.  
  305. /*----------------------------------------------------------------------------------*/
  306.  
  307. /*
  308.  *    Scene_NewLights
  309.  */
  310. static
  311. TQ3GroupObject Scene_NewLights(
  312.     void)
  313. {
  314.     TQ3GroupPosition        groupPosition = NULL;
  315.     TQ3GroupObject            lightGroup = NULL;
  316.     TQ3LightObject            light = NULL;
  317.     TQ3DirectionalLightData    comboLightData;
  318.  
  319.     /* Create light group and add each of the lights into the group */
  320.     lightGroup = Q3LightGroup_New();
  321.     if (lightGroup == NULL)
  322.         goto bail;
  323.  
  324.  
  325.     /* Create ambient light */
  326.     comboLightData.lightData.isOn        = kQ3True;
  327.     comboLightData.lightData.brightness = 0.6f;
  328.     Q3ColorRGB_Set(&comboLightData.lightData.color, 1.0f, 1.0f, 1.0f);
  329.  
  330.     light = Q3AmbientLight_New(&comboLightData.lightData);
  331.     DEBUG_ASSERT(light != NULL, Q3AmbientLight_New);
  332.     if (light == NULL)
  333.         goto bail;
  334.  
  335.     groupPosition = Q3Group_AddObject(lightGroup, light);
  336.     DEBUG_ASSERT(groupPosition != NULL, Q3Group_AddObject);
  337.     if (groupPosition == NULL)
  338.         goto bail;
  339.     Object_Dispose_NULL(&light);
  340.  
  341.  
  342.     /* Create a yellow directional light */
  343.     comboLightData.lightData.brightness    = 0.9f;
  344.     Q3ColorRGB_Set(&comboLightData.lightData.color, 0.9f, 0.9f, 0.0f);
  345.     comboLightData.castsShadows            = kQ3True;
  346.     Q3Vector3D_Set(&comboLightData.direction, 1.0f, -1.0f, -2.0f);
  347.  
  348.     light = Q3DirectionalLight_New(&comboLightData);
  349.     DEBUG_ASSERT(light != NULL, Q3DirectionalLight_New);
  350.     if (light == NULL)
  351.         goto bail;
  352.  
  353.     groupPosition = Q3Group_AddObject(lightGroup, light);
  354.     DEBUG_ASSERT(groupPosition != NULL, Q3Group_AddObject);
  355.     if (groupPosition == NULL)
  356.         goto bail;
  357.     Object_Dispose_NULL(&light);
  358.  
  359.  
  360.     /* Create a magenta directional light */
  361.     comboLightData.lightData.brightness    = 0.9f;
  362.     Q3ColorRGB_Set(&comboLightData.lightData.color, 0.9f, 0.0f, 0.9f);
  363.     comboLightData.castsShadows            = kQ3True;
  364.     Q3Vector3D_Set(&comboLightData.direction, -1.0f, 1.0f, 2.0f);
  365.  
  366.     light = Q3DirectionalLight_New(&comboLightData);
  367.     DEBUG_ASSERT(light != NULL, Q3DirectionalLight_New);
  368.     if (light == NULL)
  369.         goto bail;
  370.  
  371.     groupPosition = Q3Group_AddObject(lightGroup, light);
  372.     DEBUG_ASSERT(groupPosition != NULL, Q3Group_AddObject);
  373.     if (groupPosition == NULL)
  374.         goto bail;
  375.     Object_Dispose_NULL(&light);
  376.  
  377.     return (lightGroup);
  378.  
  379. bail:
  380.     Object_Dispose_NULL(&light);
  381.     Object_Dispose_NULL(&lightGroup);
  382.  
  383.     return (NULL);
  384. }
  385.  
  386.  
  387. /*
  388.  *    Scene_NewModel
  389.  */
  390. TQ3GroupObject Scene_NewModel(
  391.     void)
  392. {
  393.     TQ3Status                status = kQ3Failure;
  394.     TQ3GroupObject            model = NULL;
  395.     TQ3DisplayGroupState    state;
  396.     TQ3ShaderObject            illuminationShader = NULL;
  397.  
  398.     if ((model = Q3OrderedDisplayGroup_New()) != NULL) {
  399.  
  400.         /* Make group inline so state isn't pushed */
  401.         if (Q3DisplayGroup_GetState(model, &state) == kQ3Success) {
  402.             state |= kQ3DisplayGroupStateMaskIsInline;
  403.             Q3DisplayGroup_SetState(model, state);
  404.         }
  405.  
  406.         /* Add shader to model */
  407.         if ((illuminationShader = Q3PhongIllumination_New()) != NULL) {
  408.             Q3Group_AddObject(model, illuminationShader);
  409.             Object_Dispose_NULL(&illuminationShader);
  410.  
  411.             /* Add styles to model */
  412.             if ((status = Scene_NewStyles(model)) == kQ3Success) {
  413.  
  414.                 /* Add geometries to model */
  415.                 status = Scene_NewScene(model);
  416.             }
  417.         }
  418.  
  419.         if (status == kQ3Failure) {
  420.             Object_Dispose_NULL(&model);
  421.         }
  422.     }
  423.  
  424.     return (model);
  425. }
  426.  
  427.  
  428. /*
  429.  *    Scene_NewStyles
  430.  */
  431. static
  432. TQ3Status Scene_NewStyles(
  433.     TQ3GroupObject    group)
  434. {
  435.     TQ3StyleObject        style;
  436.  
  437.     if (group == NULL) {
  438.         ERROR_DEBUG_STR("Scene_NewStyles: group == NULL.");
  439.         return kQ3Failure;
  440.     }
  441.  
  442.     /* Interpolation Style */
  443.     if ((style = Q3InterpolationStyle_New(kQ3InterpolationStyleVertex)) == NULL) {
  444.         ERROR_DEBUG_STR("Scene_NewStyles: Q3InterpolationStyle_New failed.");
  445.         return kQ3Failure;
  446.     }
  447.     Q3Group_AddObject(group, style);
  448.     Object_Dispose_NULL(&style);
  449.  
  450.  
  451.     /* Backfacing Style */
  452.     if ((style = Q3BackfacingStyle_New(kQ3BackfacingStyleBoth)) == NULL) {
  453.         ERROR_DEBUG_STR("Scene_NewStyles: Q3BackfacingStyle_New failed.");
  454.         return kQ3Failure;
  455.     }
  456.     Q3Group_AddObject(group, style);
  457.     Object_Dispose_NULL(&style);
  458.  
  459.  
  460.     /* Fill Style */
  461.     if ((style = Q3FillStyle_New(kQ3FillStyleFilled)) == NULL) {
  462.         ERROR_DEBUG_STR("Scene_NewStyles: Q3FillStyle_New failed.");
  463.         return kQ3Failure;
  464.     }
  465.     Q3Group_AddObject(group, style);
  466.     Object_Dispose_NULL(&style);
  467.  
  468.  
  469.     /* Subdivision Style */
  470.     {
  471.         TQ3SubdivisionStyleData        data;
  472.  
  473.         data.method    = kQ3SubdivisionMethodConstant;
  474.         data.c1        = 9.0f;
  475.         data.c2        = 9.0f;
  476.  
  477.         if ((style = Q3SubdivisionStyle_New(&data)) == NULL) {
  478.             ERROR_DEBUG_STR("Scene_NewStyles: Q3SubdivisionStyle_New failed.");
  479.             return kQ3Failure;
  480.         }
  481.         Q3Group_AddObject(group, style);
  482.         Object_Dispose_NULL(&style);
  483.     }
  484.  
  485.     return kQ3Success;
  486. }
  487.  
  488.  
  489. #pragma mark -
  490.  
  491. /*
  492.  *    Scene_NewScene
  493.  */
  494. static
  495. TQ3Status Scene_NewScene(
  496.     TQ3GroupObject    group)
  497. {
  498.     TQ3Status            status = kQ3Success;
  499.     TQ3BoundingBox        sceneBBox;
  500.     TQ3GeometryObject    geometry = NULL;
  501.     TQ3CylinderData        cylinderData;
  502.     TQ3AttributeSet        attr = NULL;
  503.     unsigned long        rx, cy;
  504.  
  505.     #define    kNumRows            5    /* X */
  506.     #define    kNumColumns            7    /* Y */
  507.  
  508.     #define    kCylHeight            4.0f
  509.     #define    kCylDiameter        (2.0f * kCylRadius)
  510.     #define    kCylGap                (0.9f * kCylRadius)
  511.  
  512.     #define    kSceneWidth            ((kNumColumns * kCylDiameter) + ((kNumColumns-1) * kCylGap))
  513.     #define    kSceneHeight        ((kNumRows    * kCylDiameter) + ((kNumRows-1)    * kCylGap))
  514.     #define    kSceneDepth            kCylHeight
  515.  
  516.     #define    kSceneHalfWidth        (kSceneWidth    / 2.0f)
  517.     #define    kSceneHalfHeight    (kSceneHeight    / 2.0f)
  518.     #define    kSceneHalfDepth        (kSceneDepth    / 2.0f)
  519.  
  520.     if (group == NULL) {
  521.         ERROR_DEBUG_STR("Scene_NewScene: group == NULL.");
  522.         return kQ3Failure;
  523.     }
  524.  
  525.     /* Create a 4 sided box */
  526.     Q3Point3D_Set(&sceneBBox.min, -kSceneHalfWidth, -kSceneHalfHeight, -kSceneHalfDepth);
  527.     Q3Point3D_Set(&sceneBBox.max,  kSceneHalfWidth,  kSceneHalfHeight,  kSceneHalfDepth);
  528.     sceneBBox.isEmpty = kQ3False;
  529.  
  530.     if (Scene_NewBoxSides(group, &sceneBBox) == kQ3Failure) {
  531.         return kQ3Failure;
  532.     }
  533.  
  534.     /* Create cylinders inside box */
  535.     for (rx = 0; rx < kNumColumns; rx++) {
  536.         for (cy = 0; cy < kNumRows; cy++) {
  537.  
  538.             /* Skip middle geometry */
  539.             if ((rx == (kNumColumns / 2))  &&  (cy == (kNumRows / 2))) {
  540.                 continue;
  541.             }
  542.             /* Every other geometry */
  543.             if ((rx + cy) & 1) {
  544.                 continue;
  545.             }
  546.  
  547.             /* Cylinder is parallel to z-axis */
  548.             Q3Point3D_Set(&cylinderData.origin,
  549.                 (((float) rx) * (kCylDiameter + kCylGap)) + kCylRadius - kSceneHalfWidth,
  550.                 (((float) cy) * (kCylDiameter + kCylGap)) + kCylRadius - kSceneHalfHeight,
  551.                 -kSceneHalfDepth);
  552.  
  553.             Q3Vector3D_Set(&cylinderData.orientation,    0.0,        0.0,        kCylHeight);
  554.             Q3Vector3D_Set(&cylinderData.majorRadius,    kCylRadius,    0.0,        0.0);
  555.             Q3Vector3D_Set(&cylinderData.minorRadius,    0.0,        kCylRadius,    0.0);
  556.  
  557.             cylinderData.uMin = cylinderData.vMin = 0.0f;
  558.             cylinderData.uMax = cylinderData.vMax = 1.0f;
  559.             cylinderData.caps = kQ3EndCapMaskTop | kQ3EndCapMaskBottom;
  560.  
  561.             cylinderData.interiorAttributeSet    = NULL;
  562.             cylinderData.topAttributeSet        = NULL;
  563.             cylinderData.faceAttributeSet        = NULL;
  564.             cylinderData.bottomAttributeSet        = NULL;
  565.             cylinderData.cylinderAttributeSet    = NULL;
  566.  
  567.             attr = Q3AttributeSet_New();
  568.             if (attr != NULL) {
  569.                 TQ3ColorRGB        rgbColor;
  570.  
  571.                 Q3ColorRGB_Set(&rgbColor,
  572.                                 0.0,
  573.                                 (float) (kNumColumns - rx) / kNumColumns,
  574.                                 (float) cy / kNumRows);
  575.                 Q3AttributeSet_Add(attr, kQ3AttributeTypeDiffuseColor, &rgbColor);
  576.             }
  577.             cylinderData.cylinderAttributeSet = attr;
  578.  
  579.             geometry = Q3Cylinder_New(&cylinderData);
  580.             if (geometry == NULL) {
  581.                 status = kQ3Failure;
  582.                 break;
  583.             }
  584.  
  585.             Object_Dispose_NULL(&attr);
  586.  
  587.             Q3Group_AddObject(group, geometry);
  588.             Object_Dispose_NULL(&geometry);
  589.         }
  590.     }
  591.  
  592.     Object_Dispose_NULL(&attr);
  593.     Object_Dispose_NULL(&geometry);
  594.  
  595.     return status;
  596. }
  597.  
  598.  
  599. static
  600. TQ3Status Scene_NewBoxSides(
  601.     TQ3GroupObject    group,
  602.     TQ3BoundingBox    *pBBox)
  603. {
  604.     #define    kMaxPolygons    4
  605.     #define    kMaxPolyVerts    4
  606.     #define    kOutsetScale    0.15f
  607.  
  608.     TQ3Status            status   = kQ3Success;
  609.     TQ3GeometryObject    geometry = NULL;
  610.     TQ3PolygonData        polyData;
  611.     TQ3Vertex3D            vertices[kMaxPolyVerts],
  612.                         *pVertex;
  613.     TQ3Point3D            min, max;
  614.     unsigned long        side;
  615.     TQ3AttributeSet        attr = NULL;
  616.     float                boxOutset;
  617.  
  618.     min = pBBox->min;
  619.     max = pBBox->max;
  620.  
  621.     boxOutset = (max.x - min.x) * kOutsetScale;
  622.     min.x -= boxOutset;    max.x += boxOutset;
  623.  
  624.     boxOutset = (max.y - min.y) * kOutsetScale;
  625.     min.y -= boxOutset;    max.y += boxOutset;
  626.  
  627.     boxOutset = (max.z - min.z) * kOutsetScale;
  628.     min.z -= boxOutset;    max.z += boxOutset;
  629.  
  630.     polyData.numVertices = kMaxPolyVerts;
  631.     polyData.vertices     = vertices;
  632.  
  633.     pVertex = polyData.vertices;
  634.  
  635.     vertices[0].attributeSet =
  636.     vertices[1].attributeSet =
  637.     vertices[2].attributeSet =
  638.     vertices[3].attributeSet = NULL;
  639.  
  640.     for (side = 0; side < kMaxPolygons; side++) {
  641.  
  642.         attr = Q3AttributeSet_New();
  643.         if (attr != NULL) {
  644.             TQ3ColorRGB        rgbColor;
  645.  
  646.             Q3ColorRGB_Set(&rgbColor, 0.0, 0.5, 0.5);
  647.             Q3AttributeSet_Add(attr, kQ3AttributeTypeDiffuseColor, &rgbColor);
  648.         }
  649.         polyData.polygonAttributeSet = attr;
  650.  
  651.         switch (side) {
  652.         case 0:
  653.             Q3Point3D_Set(&pVertex[0].point, min.x, min.y, min.z);
  654.             Q3Point3D_Set(&pVertex[1].point, min.x, min.y, max.z);
  655.             Q3Point3D_Set(&pVertex[2].point, max.x, min.y, max.z);
  656.             Q3Point3D_Set(&pVertex[3].point, max.x, min.y, min.z);
  657.             break;
  658.  
  659.         case 1:
  660.             Q3Point3D_Set(&pVertex[0].point, max.x, min.y, min.z);
  661.             Q3Point3D_Set(&pVertex[1].point, max.x, min.y, max.z);
  662.             Q3Point3D_Set(&pVertex[2].point, max.x, max.y, max.z);
  663.             Q3Point3D_Set(&pVertex[3].point, max.x, max.y, min.z);
  664.             break;
  665.  
  666.         case 2:
  667.             Q3Point3D_Set(&pVertex[0].point, min.x, max.y, min.z);
  668.             Q3Point3D_Set(&pVertex[1].point, max.x, max.y, min.z);
  669.             Q3Point3D_Set(&pVertex[2].point, max.x, max.y, max.z);
  670.             Q3Point3D_Set(&pVertex[3].point, min.x, max.y, max.z);
  671.             break;
  672.  
  673.         case 3:
  674.             Q3Point3D_Set(&pVertex[0].point, min.x, min.y, min.z);
  675.             Q3Point3D_Set(&pVertex[1].point, min.x, max.y, min.z);
  676.             Q3Point3D_Set(&pVertex[2].point, min.x, max.y, max.z);
  677.             Q3Point3D_Set(&pVertex[3].point, min.x, min.y, max.z);
  678.             break;
  679.         }
  680.  
  681.         geometry = Q3Polygon_New(&polyData);
  682.         Object_Dispose_NULL(&polyData.polygonAttributeSet);
  683.         if (geometry == NULL) {
  684.             return kQ3Failure;
  685.         }
  686.  
  687.         Q3Group_AddObject(group, geometry);
  688.         Object_Dispose_NULL(&geometry);
  689.     }
  690.  
  691.     return kQ3Success;
  692. }
  693.  
  694.  
  695. #pragma mark -
  696.  
  697. /*
  698.  *    Scene_IsRotating
  699.  */
  700. TQ3Boolean Scene_IsRotating(
  701.     void)
  702. {
  703.     return gDoRotation;
  704. }
  705.  
  706.  
  707. /*
  708.  *    Scene_SetIsRotating
  709.  */
  710. TQ3Boolean Scene_SetIsRotating(
  711.     TQ3Boolean        newIsRotating)
  712. {
  713.     TQ3Boolean    oldIsRotating = gDoRotation;
  714.  
  715.     gDoRotation = newIsRotating;
  716.  
  717.     return oldIsRotating;
  718. }
  719.  
  720.  
  721. /*
  722.  *    Scene_Rotate
  723.  *
  724.  *    Global:
  725.  *        gCamera
  726.  */
  727. TQ3Status Scene_Rotate(
  728.     void)
  729. {
  730.     TQ3Status            status = kQ3Failure;
  731.     TQ3CameraPlacement    placement;
  732.     float                cameraDist;
  733.  
  734.     if (gDoRotation) {
  735.         gRotationAngle += kAngleDelta;
  736.  
  737.         status = Q3Camera_GetPlacement(gCamera, &placement);
  738.         DEBUG_ASSERT(status == kQ3Success, Q3Camera_GetPlacement);
  739.  
  740.         cameraDist = Q3Point3D_Distance(&placement.cameraLocation, &placement.pointOfInterest);
  741.  
  742.         /* Assumes pointOfInterest is at origin any pointOfInterest.y is 0 */
  743.         placement.cameraLocation.x = cos(gRotationAngle) * cameraDist;
  744.         placement.cameraLocation.z = sin(gRotationAngle) * cameraDist;
  745.  
  746.         status = Q3Camera_SetPlacement(gCamera, &placement);
  747.         DEBUG_ASSERT(status == kQ3Success, Q3Camera_SetPlacement);
  748.     }
  749.  
  750.     return status;
  751. }
  752.