home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / uvis / uvis.cpp < prev    next >
C/C++ Source or Header  |  1997-07-14  |  14KB  |  539 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995, 1996 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File: uvis.cpp
  6.  *
  7.  ***************************************************************************/
  8.  
  9. #include <math.h>
  10. #include <stdlib.h>
  11. #include <d3d.h>
  12. #include "d3dmacs.h"
  13. #include "rmdemo.h"
  14.  
  15. typedef struct _Flame {
  16.     int        valid;
  17.     D3DVECTOR    velocity;    /* direction the flame is going */
  18.     D3DVECTOR    orientation;    /* random vector normal to velocity */
  19.     D3DVECTOR    position;    /* current position */
  20.     int        time;        /* current time */
  21.     int        lifetime;    /* time to die */
  22. } Flame;
  23.  
  24. /*
  25.  * A flame is a diamond shape oriented along its direction vector.
  26.  * This updates the four vertices of the flame, given its current time.
  27.  */
  28. void UpdateFlame(Flame* flame, D3DVERTEX v[])
  29. {
  30.     D3DVECTOR dir = flame->velocity;
  31.     D3DVECTOR off = flame->orientation;
  32.     D3DVECTOR norm;
  33.     D3DVECTOR start, end, left, right;
  34.     double size;
  35.     int i;
  36.  
  37.     D3DRMVectorNormalise(&dir);
  38.  
  39.     /*
  40.      * Calculate a normal vector to the flame
  41.      */
  42.     D3DRMVectorCrossProduct(&norm, &dir, &off);
  43.     D3DRMVectorNormalise(&norm);
  44.  
  45.     /*
  46.      * The size starts off small, gets bigger towards the middle
  47.      * and smaller towards the end.
  48.      */
  49.     if (flame->time < flame->lifetime / 2)
  50.     size = (double) flame->time / (double)(flame->lifetime / 2);
  51.     else
  52.     size = ((double) (flame->lifetime - flame->time)
  53.         / (double)(flame->lifetime / 2));
  54.  
  55.     /*
  56.      * Calculate the four corners of the diamond.
  57.      */
  58.     D3DRMVectorScale(&dir, &dir, D3DVAL(size));
  59.     D3DRMVectorScale(&off, &off, D3DVAL(size / 4));
  60.     start = flame->position;
  61.     D3DRMVectorAdd(&end, &start, &dir);
  62.     D3DRMVectorScale(&dir, &dir, D3DVAL(0.5));
  63.     D3DRMVectorAdd(&left, &start, &dir);
  64.     right = left;
  65.     D3DRMVectorAdd(&left, &left, &off);
  66.     D3DRMVectorSubtract(&right, &right, &off);
  67.  
  68.  
  69.     /*
  70.      * Update the flame's position.
  71.      */
  72.     D3DRMVectorAdd(&flame->position, &flame->position, &flame->velocity);
  73.     flame->time++;
  74.     if (flame->time == flame->lifetime)
  75.     flame->valid = 0;
  76.  
  77.     /*
  78.      * And fill in the vertices.  There are eight, four for each side of
  79.      * the flame.
  80.      */
  81.     i = 0;
  82.     v[i].x = start.x; v[i].y = start.y; v[i].z = start.z;
  83.     v[i].nx = -norm.x; v[i].ny = -norm.y; v[i].nz = -norm.z;
  84.     v[i].tu = D3DVAL(0); v[i].tv = D3DVAL(0);
  85.     i++;
  86.  
  87.     v[i].x = left.x; v[i].y = left.y; v[i].z = left.z;
  88.     v[i].nx = -norm.x; v[i].ny = -norm.y; v[i].nz = -norm.z;
  89.     v[i].tu = D3DVAL(1); v[i].tv = D3DVAL(0);
  90.     i++;
  91.  
  92.     v[i].x = end.x; v[i].y = end.y; v[i].z = end.z;
  93.     v[i].nx = -norm.x; v[i].ny = -norm.y; v[i].nz = -norm.z;
  94.     v[i].tu = D3DVAL(1); v[i].tv = D3DVAL(1);
  95.     i++;
  96.  
  97.     v[i].x = right.x; v[i].y = right.y; v[i].z = right.z;
  98.     v[i].nx = -norm.x; v[i].ny = -norm.y; v[i].nz = -norm.z;
  99.     v[i].tu = D3DVAL(0); v[i].tv = D3DVAL(1);
  100.     i++;
  101.  
  102.     v[i].x = start.x; v[i].y = start.y; v[i].z = start.z;
  103.     v[i].nx = norm.x; v[i].ny = norm.y; v[i].nz = norm.z;
  104.     v[i].tu = D3DVAL(0); v[i].tv = D3DVAL(0);
  105.     i++;
  106.  
  107.     v[i].x = right.x; v[i].y = right.y; v[i].z = right.z;
  108.     v[i].nx = norm.x; v[i].ny = norm.y; v[i].nz = norm.z;
  109.     v[i].tu = D3DVAL(0); v[i].tv = D3DVAL(1);
  110.     i++;
  111.  
  112.     v[i].x = end.x; v[i].y = end.y; v[i].z = end.z;
  113.     v[i].nx = norm.x; v[i].ny = norm.y; v[i].nz = norm.z;
  114.     v[i].tu = D3DVAL(1); v[i].tv = D3DVAL(1);
  115.     i++;
  116.  
  117.     v[i].x = left.x; v[i].y = left.y; v[i].z = left.z;
  118.     v[i].nx = norm.x; v[i].ny = norm.y; v[i].nz = norm.z;
  119.     v[i].tu = D3DVAL(1); v[i].tv = D3DVAL(0);
  120.     i++;
  121.  
  122. }
  123.  
  124. void InitFlame(Flame* flame)
  125. {
  126.     D3DVECTOR d, u;
  127.  
  128.     flame->valid = TRUE;
  129.  
  130.     do {
  131.       D3DRMVectorRandom(&d);
  132.       d.y = d.y * d.y;
  133.       d.y = d.y * d.y;
  134.     } while (d.y < D3DVAL(0.3));
  135.  
  136.     /*
  137.      * Pick a vector normal to d
  138.      */
  139.     if (d.y != D3DVAL(0.0) || d.z != D3DVAL(0.0))
  140.     {
  141.     u.x = D3DVAL(0.0);
  142.     if (d.y == D3DVAL(0.0))
  143.     {
  144.         u.y = D3DVAL(1.0);
  145.         u.z = D3DVAL(0.0);
  146.     } else {
  147.         D3DVALUE n_fix =
  148.         D3DVAL(1.0)
  149.         + D3DDivide(D3DMultiply(d.z, d.z), D3DMultiply(d.y, d.y));
  150.         u.z = D3DVAL(sqrt(D3DDivide(D3DVAL(1.0), D3DVAL(n_fix))));
  151.         u.y = -D3DMultiply(u.z, D3DDivide(d.z, d.y));
  152.     }
  153.     } else {
  154.     u.x = D3DVAL(0.0);
  155.     u.y = D3DVAL(0.0);
  156.     u.z = D3DVAL(1.0);
  157.     }
  158.  
  159.     /*
  160.      * Randomize it.
  161.      */
  162.     D3DRMVectorRotate(&u, &u, &d, D3DDivide(D3DVAL(6.28 * (rand() % 100)),
  163.                             D3DVAL(100.0)));
  164.  
  165.     D3DRMVectorScale(&d, &d, D3DVAL(0.1));
  166.     flame->velocity = d;
  167.     flame->orientation = u;
  168.     flame->position.x = D3DVAL(0);
  169.     flame->position.y = D3DVAL(0);
  170.     flame->position.z = D3DVAL(0);
  171.     flame->time = 0;
  172.     do {
  173.     flame->lifetime = rand() % 30;
  174.     } while (flame->lifetime < 5);
  175. }
  176.  
  177. #define MAX_FLAMES    100
  178.  
  179. typedef struct _Fire {
  180.     Flame flames[MAX_FLAMES];
  181.     LPDIRECT3DRMDEVICE dev;
  182.     LPDIRECT3DEXECUTEBUFFER eb;
  183.     LPDIRECT3DMATERIAL mat;
  184. } Fire;
  185.  
  186. void CDECL CleanupFireObjects(LPDIRECT3DRMOBJECT dev, void* arg)
  187. {
  188.     Fire* fire = (Fire*) arg;
  189.  
  190.     if (fire->eb) {
  191.     fire->eb->Release();
  192.     fire->mat->Release();
  193.     fire->eb = NULL;
  194.     fire->dev = NULL;
  195.     }
  196. }
  197.  
  198. typedef struct _FireExecuteBuffer {
  199.     D3DVERTEX        v[8 * MAX_FLAMES];
  200.     D3DINSTRUCTION    op_state_light1;
  201.     D3DSTATE        state1;
  202.     D3DINSTRUCTION    op_set_status;
  203.     D3DSTATUS        setstatus1;
  204.     D3DINSTRUCTION    op_process_vertices1;
  205.     D3DPROCESSVERTICES    processvertices1;
  206.     D3DINSTRUCTION    op_state_render;
  207.     D3DSTATE        state2;
  208.     D3DSTATE        state3;
  209.     D3DSTATE        state4;
  210.     D3DINSTRUCTION    op_triangle_list;
  211.     D3DTRIANGLE        tri[4 * MAX_FLAMES];
  212.     D3DINSTRUCTION    exit1;
  213. } FireExecuteBuffer;
  214.  
  215. BOOL CreateFireObjects(Fire* fire, LPDIRECT3DRMDEVICE dev)
  216. {
  217.     D3DEXECUTEBUFFERDESC desc;
  218.     D3DEXECUTEDATA data;
  219.     LPDIRECT3D lpD3D = NULL;
  220.     LPDIRECT3DDEVICE lpD3DDev = NULL;
  221.     LPDIRECT3DMATERIAL mat = NULL;
  222.     LPDIRECT3DEXECUTEBUFFER eb = NULL;
  223.     D3DMATERIALHANDLE hMat;
  224.     D3DMATERIAL orange;
  225.     void* p;
  226.     int i;
  227.  
  228.     RELEASE(fire->eb);
  229.  
  230.     dev->GetDirect3DDevice(&lpD3DDev);
  231.     if (!lpD3DDev)
  232.     goto generic_error;
  233.     if (FAILED(lpD3DDev->GetDirect3D(&lpD3D)))
  234.     goto generic_error;
  235.  
  236.     desc.dwSize = sizeof(desc);
  237.     desc.dwFlags = D3DDEB_BUFSIZE;
  238.     desc.dwBufferSize = sizeof(FireExecuteBuffer);
  239.     
  240.     if (FAILED(lpD3DDev->CreateExecuteBuffer(&desc, &eb, NULL)))
  241.     goto generic_error;
  242.  
  243.     if (FAILED(lpD3D->CreateMaterial(&mat, NULL)))
  244.     goto generic_error;
  245.     if (FAILED(mat->GetHandle(lpD3DDev, &hMat)))
  246.     goto generic_error;
  247.  
  248.     memset(&orange, 0, sizeof(orange));
  249.     orange.dwSize = sizeof(orange);
  250.     orange.diffuse.r = D3DVAL(1.0);
  251.     orange.diffuse.g = D3DVAL(0.5);
  252.     orange.diffuse.b = D3DVAL(0.0);
  253.     orange.ambient.r = D3DVAL(1.0);
  254.     orange.ambient.g = D3DVAL(0.5);
  255.     orange.ambient.b = D3DVAL(0.0);
  256.     orange.dwRampSize = 32;
  257.     if (FAILED(mat->SetMaterial(&orange)))
  258.     goto generic_error;
  259.  
  260.     if (FAILED(eb->Lock(&desc)))
  261.     goto generic_error;
  262.     p = (void*) ((char*) desc.lpData + 8 * MAX_FLAMES * sizeof(D3DVERTEX));
  263.  
  264.     OP_STATE_LIGHT(1, p);
  265.     STATE_DATA(D3DLIGHTSTATE_MATERIAL, hMat, p);
  266.     
  267.     OP_SET_STATUS(D3DSETSTATUS_ALL, D3DSTATUS_DEFAULT, 2048, 2048, 0, 0, p);
  268.     
  269.     OP_PROCESS_VERTICES(1, p);
  270.     PROCESSVERTICES_DATA(D3DPROCESSVERTICES_TRANSFORMLIGHT,
  271.              0, 8 * MAX_FLAMES, p);
  272.     OP_STATE_RENDER(3, p);
  273.     STATE_DATA(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT, p);
  274.     STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, 0, p);
  275.     STATE_DATA(D3DRENDERSTATE_BLENDENABLE, FALSE, p);
  276.  
  277.     OP_TRIANGLE_LIST(4 * MAX_FLAMES, p);
  278.     for (i = 0; i < MAX_FLAMES; i++) {
  279.     D3DTRIANGLE* t;
  280.     int base;
  281.  
  282.     t = (D3DTRIANGLE*) p;
  283.     base = 4 * i;
  284.  
  285.     t->v1 = base + 0;
  286.     t->v2 = base + 1;
  287.     t->v3 = base + 3;
  288.     t->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  289.     t++;
  290.  
  291.     t->v1 = base + 1;
  292.     t->v2 = base + 2;
  293.     t->v3 = base + 3;
  294.     t->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  295.     t++;
  296.     
  297.     t->v1 = base + 0;
  298.     t->v2 = base + 1;
  299.     t->v3 = base + 3;
  300.     t->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  301.     t++;
  302.  
  303.     t->v1 = base + 1;
  304.     t->v2 = base + 2;
  305.     t->v3 = base + 3;
  306.     t->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  307.     t++;
  308.     
  309.     p = (char*) t;
  310.     }
  311.     OP_EXIT(p);
  312.  
  313.     if (FAILED(eb->Unlock()))
  314.     goto generic_error;
  315.  
  316.     data.dwSize = sizeof(data);
  317.     data.dwVertexOffset = 0;
  318.     data.dwVertexCount = 8 * MAX_FLAMES;
  319.     data.dwInstructionOffset = 8 * MAX_FLAMES * sizeof(D3DVERTEX);
  320.     data.dwInstructionLength = sizeof(FireExecuteBuffer) - data.dwInstructionOffset;
  321.     data.dwHVertexOffset = 0;
  322.     if (FAILED(eb->SetExecuteData(&data)))
  323.     goto generic_error;
  324.  
  325.     fire->eb = eb;
  326.     fire->mat = mat;
  327.     fire->dev = dev;
  328.     if (FAILED(dev->AddDestroyCallback(CleanupFireObjects, fire)))
  329.     goto generic_error;
  330.  
  331.     RELEASE(lpD3DDev);
  332.     RELEASE(lpD3D);
  333.     return TRUE;
  334. generic_error:
  335.     RELEASE(lpD3D);
  336.     RELEASE(lpD3DDev);
  337.     RELEASE(mat);
  338.     RELEASE(eb);
  339.     return FALSE;
  340. }
  341.  
  342. BOOL RenderFire(Fire* fire, LPDIRECT3DRMDEVICE dev, LPDIRECT3DRMVIEWPORT view)
  343. {
  344.     D3DVERTEX* v;
  345.     D3DEXECUTEBUFFERDESC desc;
  346.     D3DEXECUTEDATA data;
  347.     LPDIRECT3DDEVICE lpD3DDev = NULL;
  348.     LPDIRECT3DVIEWPORT lpD3DView = NULL;
  349.     int i;
  350.  
  351.     if (fire->dev != dev) {
  352.     if (!CreateFireObjects(fire, dev))
  353.         return FALSE;
  354.     }
  355.  
  356.     dev->GetDirect3DDevice(&lpD3DDev);
  357.     view->GetDirect3DViewport(&lpD3DView);
  358.     if (!lpD3DDev || !lpD3DView)
  359.     goto ret_with_error;
  360.  
  361.     for (i = 0; i < MAX_FLAMES; i++)
  362.     if (!fire->flames[i].valid)
  363.         InitFlame(&fire->flames[i]);
  364.  
  365.     desc.dwSize = sizeof(desc);
  366.     desc.dwFlags = 0;
  367.     
  368.     if (FAILED(fire->eb->Lock(&desc)))
  369.     goto ret_with_error;
  370.     v = (D3DVERTEX*) desc.lpData;
  371.  
  372.     for (i = 0; i < MAX_FLAMES; i++)
  373.     UpdateFlame(&fire->flames[i], &v[8 * i]);
  374.  
  375.     if (FAILED(fire->eb->Unlock()))
  376.     goto ret_with_error;
  377.  
  378.     if (FAILED(lpD3DDev->Execute(fire->eb, lpD3DView, D3DEXECUTE_CLIPPED)))
  379.     goto ret_with_error;
  380.  
  381.     data.dwSize = sizeof data;
  382.     if (FAILED(fire->eb->GetExecuteData(&data)))
  383.     goto ret_with_error;
  384.     if (FAILED(view->ForceUpdate(data.dsStatus.drExtent.x1,
  385.               data.dsStatus.drExtent.y1,
  386.               data.dsStatus.drExtent.x2,
  387.               data.dsStatus.drExtent.y2)))
  388.               goto ret_with_error;
  389.  
  390.     RELEASE(lpD3DDev);
  391.     RELEASE(lpD3DView);
  392.     return TRUE;
  393. ret_with_error:
  394.     RELEASE(lpD3DDev);
  395.     RELEASE(lpD3DView);
  396.     return FALSE;
  397. }
  398.  
  399. int CDECL FireCallback(LPDIRECT3DRMUSERVISUAL uvis,
  400.          void* arg,
  401.          D3DRMUSERVISUALREASON reason,
  402.          LPDIRECT3DRMDEVICE dev,
  403.          LPDIRECT3DRMVIEWPORT view)
  404. {
  405.     Fire* fire = (Fire*) arg;
  406.  
  407.     if (reason == D3DRMUSERVISUAL_CANSEE)
  408.     return TRUE;
  409.  
  410.     if (reason == D3DRMUSERVISUAL_RENDER) {
  411.     if (!RenderFire(fire, dev, view))
  412.         return DDERR_GENERIC;
  413.     else
  414.         return D3D_OK;
  415.     }
  416.  
  417.     return 0;
  418. }
  419.  
  420. void CDECL DestroyFire(LPDIRECT3DRMOBJECT obj, void* arg)
  421. {
  422.     Fire* fire = (Fire*) arg;
  423.  
  424.     if (fire->dev)
  425.     fire->dev->DeleteDestroyCallback(CleanupFireObjects, arg);
  426.     CleanupFireObjects((LPDIRECT3DRMOBJECT)fire->dev, (void*) fire);
  427.     free(fire);
  428. }
  429.  
  430. LPDIRECT3DRMUSERVISUAL CreateFire()
  431. {
  432.     Fire* fire;
  433.     LPDIRECT3DRMUSERVISUAL uvis = NULL;
  434.  
  435.     fire = (Fire*)malloc(sizeof(Fire));
  436.     if (!fire)
  437.     goto ret_with_error;
  438.     memset(fire, 0, sizeof(Fire));
  439.  
  440.     if (FAILED(lpD3DRM->CreateUserVisual(FireCallback, (void*) fire, &uvis)))
  441.     goto ret_with_error;
  442.     if (FAILED(uvis->AddDestroyCallback(DestroyFire, (void*) fire)))
  443.     goto ret_with_error;   
  444.     return uvis;
  445. ret_with_error:
  446.     if (fire)
  447.     free(fire);
  448.     RELEASE(uvis);
  449.     return NULL;
  450. }
  451.  
  452. BOOL
  453. BuildScene(LPDIRECT3DRMDEVICE dev, LPDIRECT3DRMVIEWPORT view,
  454.        LPDIRECT3DRMFRAME scene, LPDIRECT3DRMFRAME camera)
  455. {
  456.     D3DRMRENDERQUALITY quality = D3DRMRENDER_GOURAUD;
  457.     LPDIRECT3DRMFRAME lights = NULL;
  458.     LPDIRECT3DRMFRAME frame = NULL;
  459.     LPDIRECT3DRMLIGHT light1 = NULL;
  460.     LPDIRECT3DRMLIGHT light2 = NULL;
  461.     LPDIRECT3DRMUSERVISUAL uvis = NULL;
  462.  
  463.     view = view;        /* not used */
  464.  
  465.     if (FAILED(dev->SetQuality(quality)))
  466.     goto generic_error;
  467.  
  468.     /*
  469.      * initialize the lights in the scene
  470.      */
  471.     if (FAILED(lpD3DRM->CreateFrame(scene, &lights)))
  472.     goto generic_error;
  473.     if (FAILED(lights->SetPosition(scene, D3DVAL(5), D3DVAL(5), -D3DVAL(1))))
  474.     goto generic_error;
  475.     if(FAILED(lights->SetOrientation(scene, D3DVAL(0), D3DVAL(0), D3DVAL(1),
  476.                D3DVAL(0), D3DVAL(1), D3DVAL(1))))
  477.                goto generic_error;
  478.     if(FAILED(lpD3DRM->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, D3DVAL(0.9),
  479.               D3DVAL(0.8), D3DVAL(0.7), &light1)))
  480.               goto generic_error;
  481.     if (FAILED(lights->AddLight(light1)))
  482.     goto generic_error;
  483.     if(FAILED(lpD3DRM->CreateLightRGB(D3DRMLIGHT_AMBIENT, D3DVAL(0.1),
  484.               D3DVAL(0.1), D3DVAL(0.1), &light2)))
  485.               goto generic_error;
  486.     if (FAILED(scene->AddLight(light2)))
  487.     goto generic_error;
  488.  
  489.     /*
  490.      * create a frame within the scene
  491.      */
  492.     if (FAILED(lpD3DRM->CreateFrame(scene, &frame)))
  493.     goto generic_error;
  494.  
  495.     /*
  496.      * add the fire into the frame
  497.      */
  498.     uvis = CreateFire();
  499.     if (!uvis)
  500.     goto generic_error;
  501.     if (FAILED(frame->AddVisual(uvis)))
  502.     goto generic_error;
  503.  
  504.     /*
  505.      * set up the frames position, orientation and rotation
  506.      */
  507.     if (FAILED(camera->SetPosition(scene, D3DVAL(0), D3DVAL(0.5), -D3DVAL(10))))
  508.     goto generic_error;
  509.     if(FAILED(camera->SetOrientation(scene, D3DVAL(0), D3DVAL(0), D3DVAL(1), D3DVAL(0),
  510.                D3DVAL(1), D3DVAL(0))))
  511.                goto generic_error;
  512.     if(FAILED(frame->SetRotation(scene, D3DVAL(0), D3DVAL(1), D3DVAL(0),
  513.                D3DVAL(0.02))))
  514.                goto generic_error;
  515.  
  516.     RELEASE(uvis);
  517.     RELEASE(frame);
  518.     RELEASE(lights);
  519.     RELEASE(light1);
  520.     RELEASE(light2);
  521.     return TRUE;
  522. generic_error:
  523.     Msg("A failure occurred while building the scene.\n");
  524.     RELEASE(lights);
  525.     RELEASE(frame);
  526.     RELEASE(light1);
  527.     RELEASE(light2);
  528.     RELEASE(uvis);
  529.     return FALSE;
  530. }
  531.  
  532. void
  533. OverrideDefaults(Defaults *defaults)
  534. {
  535.     defaults->bConstRenderQuality = TRUE;
  536.     defaults->bNoTextures = TRUE;
  537.     lstrcpy(defaults->Name, "User Visual Direct3DRM Example");
  538. }
  539.