home *** CD-ROM | disk | FTP | other *** search
/ NEXT Generation 27 / NEXT27.iso / pc / demos / emperor / dx3.exe / SDK / SAMPLES / UVIS / UVIS.CPP < prev    next >
C/C++ Source or Header  |  1996-08-28  |  15KB  |  534 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.     D3DINSTRUCTION      op_triangle_list;
  209.     D3DTRIANGLE         tri[4 * MAX_FLAMES];
  210.     D3DINSTRUCTION      exit1;
  211. } FireExecuteBuffer;
  212.  
  213. BOOL CreateFireObjects(Fire* fire, LPDIRECT3DRMDEVICE dev)
  214. {
  215.     D3DEXECUTEBUFFERDESC desc;
  216.     D3DEXECUTEDATA data;
  217.     LPDIRECT3D lpD3D = NULL;
  218.     LPDIRECT3DDEVICE lpD3DDev = NULL;
  219.     LPDIRECT3DMATERIAL mat = NULL;
  220.     LPDIRECT3DEXECUTEBUFFER eb = NULL;
  221.     D3DMATERIALHANDLE hMat;
  222.     D3DMATERIAL orange;
  223.     void* p;
  224.     int i;
  225.  
  226.     RELEASE(fire->eb);
  227.  
  228.     dev->GetDirect3DDevice(&lpD3DDev);
  229.     if (!lpD3DDev)
  230.         goto generic_error;
  231.     if (FAILED(lpD3DDev->GetDirect3D(&lpD3D)))
  232.         goto generic_error;
  233.  
  234.     desc.dwSize = sizeof(desc);
  235.     desc.dwFlags = D3DDEB_BUFSIZE;
  236.     desc.dwBufferSize = sizeof(FireExecuteBuffer);
  237.     
  238.     if (FAILED(lpD3DDev->CreateExecuteBuffer(&desc, &eb, NULL)))
  239.         goto generic_error;
  240.  
  241.     if (FAILED(lpD3D->CreateMaterial(&mat, NULL)))
  242.         goto generic_error;
  243.     if (FAILED(mat->GetHandle(lpD3DDev, &hMat)))
  244.         goto generic_error;
  245.  
  246.     memset(&orange, 0, sizeof(orange));
  247.     orange.dwSize = sizeof(orange);
  248.     orange.diffuse.r = D3DVAL(1.0);
  249.     orange.diffuse.g = D3DVAL(0.5);
  250.     orange.diffuse.b = D3DVAL(0.0);
  251.     orange.ambient.r = D3DVAL(1.0);
  252.     orange.ambient.g = D3DVAL(0.5);
  253.     orange.ambient.b = D3DVAL(0.0);
  254.     orange.dwRampSize = 32;
  255.     if (FAILED(mat->SetMaterial(&orange)))
  256.         goto generic_error;
  257.  
  258.     if (FAILED(eb->Lock(&desc)))
  259.         goto generic_error;
  260.     p = (void*) ((char*) desc.lpData + 8 * MAX_FLAMES * sizeof(D3DVERTEX));
  261.  
  262.     OP_STATE_LIGHT(1, p);
  263.         STATE_DATA(D3DLIGHTSTATE_MATERIAL, hMat, p);
  264.         
  265.     OP_SET_STATUS(D3DSETSTATUS_ALL, D3DSTATUS_DEFAULT, 2048, 2048, 0, 0, p);
  266.     
  267.     OP_PROCESS_VERTICES(1, p);
  268.         PROCESSVERTICES_DATA(D3DPROCESSVERTICES_TRANSFORMLIGHT,
  269.                          0, 8 * MAX_FLAMES, p);
  270.     OP_STATE_RENDER(1, p);
  271.         STATE_DATA(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT, p);
  272.     OP_TRIANGLE_LIST(4 * MAX_FLAMES, p);
  273.     for (i = 0; i < MAX_FLAMES; i++) {
  274.         D3DTRIANGLE* t;
  275.         int base;
  276.  
  277.         t = (D3DTRIANGLE*) p;
  278.         base = 4 * i;
  279.  
  280.         t->v1 = base + 0;
  281.         t->v2 = base + 1;
  282.         t->v3 = base + 3;
  283.         t->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  284.         t++;
  285.  
  286.         t->v1 = base + 1;
  287.         t->v2 = base + 2;
  288.         t->v3 = base + 3;
  289.         t->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  290.         t++;
  291.         
  292.         t->v1 = base + 0;
  293.         t->v2 = base + 1;
  294.         t->v3 = base + 3;
  295.         t->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  296.         t++;
  297.  
  298.         t->v1 = base + 1;
  299.         t->v2 = base + 2;
  300.         t->v3 = base + 3;
  301.         t->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  302.         t++;
  303.         
  304.         p = (char*) t;
  305.     }
  306.     OP_EXIT(p);
  307.  
  308.     if (FAILED(eb->Unlock()))
  309.         goto generic_error;
  310.  
  311.     data.dwSize = sizeof(data);
  312.     data.dwVertexOffset = 0;
  313.     data.dwVertexCount = 8 * MAX_FLAMES;
  314.     data.dwInstructionOffset = 8 * MAX_FLAMES * sizeof(D3DVERTEX);
  315.     data.dwInstructionLength = sizeof(FireExecuteBuffer) - data.dwInstructionOffset;
  316.     data.dwHVertexOffset = 0;
  317.     if (FAILED(eb->SetExecuteData(&data)))
  318.         goto generic_error;
  319.  
  320.     fire->eb = eb;
  321.     fire->mat = mat;
  322.     fire->dev = dev;
  323.     if (FAILED(dev->AddDestroyCallback(CleanupFireObjects, fire)))
  324.         goto generic_error;
  325.  
  326.     RELEASE(lpD3DDev);
  327.     RELEASE(lpD3D);
  328.     return TRUE;
  329. generic_error:
  330.     RELEASE(lpD3D);
  331.     RELEASE(lpD3DDev);
  332.     RELEASE(mat);
  333.     RELEASE(eb);
  334.     return FALSE;
  335. }
  336.  
  337. BOOL RenderFire(Fire* fire, LPDIRECT3DRMDEVICE dev, LPDIRECT3DRMVIEWPORT view)
  338. {
  339.     D3DVERTEX* v;
  340.     D3DEXECUTEBUFFERDESC desc;
  341.     D3DEXECUTEDATA data;
  342.     LPDIRECT3DDEVICE lpD3DDev = NULL;
  343.     LPDIRECT3DVIEWPORT lpD3DView = NULL;
  344.     int i;
  345.  
  346.     if (fire->dev != dev) {
  347.         if (!CreateFireObjects(fire, dev))
  348.             return FALSE;
  349.     }
  350.  
  351.     dev->GetDirect3DDevice(&lpD3DDev);
  352.     view->GetDirect3DViewport(&lpD3DView);
  353.     if (!lpD3DDev || !lpD3DView)
  354.         goto ret_with_error;
  355.  
  356.     for (i = 0; i < MAX_FLAMES; i++)
  357.         if (!fire->flames[i].valid)
  358.             InitFlame(&fire->flames[i]);
  359.  
  360.     desc.dwSize = sizeof(desc);
  361.     desc.dwFlags = 0;
  362.     
  363.     if (FAILED(fire->eb->Lock(&desc)))
  364.         goto ret_with_error;
  365.     v = (D3DVERTEX*) desc.lpData;
  366.  
  367.     for (i = 0; i < MAX_FLAMES; i++)
  368.         UpdateFlame(&fire->flames[i], &v[8 * i]);
  369.  
  370.     if (FAILED(fire->eb->Unlock()))
  371.         goto ret_with_error;
  372.  
  373.     if (FAILED(lpD3DDev->Execute(fire->eb, lpD3DView, D3DEXECUTE_CLIPPED)))
  374.         goto ret_with_error;
  375.  
  376.     data.dwSize = sizeof data;
  377.     if (FAILED(fire->eb->GetExecuteData(&data)))
  378.         goto ret_with_error;
  379.     if (FAILED(view->ForceUpdate(data.dsStatus.drExtent.x1,
  380.                       data.dsStatus.drExtent.y1,
  381.                       data.dsStatus.drExtent.x2,
  382.                       data.dsStatus.drExtent.y2)))
  383.                       goto ret_with_error;
  384.  
  385.     RELEASE(lpD3DDev);
  386.     RELEASE(lpD3DView);
  387.     return TRUE;
  388. ret_with_error:
  389.     RELEASE(lpD3DDev);
  390.     RELEASE(lpD3DView);
  391.     return FALSE;
  392. }
  393.  
  394. int CDECL FireCallback(LPDIRECT3DRMUSERVISUAL uvis,
  395.                  void* arg,
  396.                  D3DRMUSERVISUALREASON reason,
  397.                  LPDIRECT3DRMDEVICE dev,
  398.                  LPDIRECT3DRMVIEWPORT view)
  399. {
  400.     Fire* fire = (Fire*) arg;
  401.  
  402.     if (reason == D3DRMUSERVISUAL_CANSEE)
  403.         return TRUE;
  404.  
  405.     if (reason == D3DRMUSERVISUAL_RENDER) {
  406.         if (!RenderFire(fire, dev, view))
  407.             return DDERR_GENERIC;
  408.         else
  409.             return D3D_OK;
  410.     }
  411.  
  412.     return 0;
  413. }
  414.  
  415. void CDECL DestroyFire(LPDIRECT3DRMOBJECT obj, void* arg)
  416. {
  417.     Fire* fire = (Fire*) arg;
  418.  
  419.     if (fire->dev)
  420.         fire->dev->DeleteDestroyCallback(CleanupFireObjects, arg);
  421.     CleanupFireObjects((LPDIRECT3DRMOBJECT)fire->dev, (void*) fire);
  422.     free(fire);
  423. }
  424.  
  425. LPDIRECT3DRMUSERVISUAL CreateFire()
  426. {
  427.     Fire* fire;
  428.     LPDIRECT3DRMUSERVISUAL uvis = NULL;
  429.  
  430.     fire = (Fire*)malloc(sizeof(Fire));
  431.     if (!fire)
  432.         goto ret_with_error;
  433.     memset(fire, 0, sizeof(Fire));
  434.  
  435.     if (FAILED(lpD3DRM->CreateUserVisual(FireCallback, (void*) fire, &uvis)))
  436.         goto ret_with_error;
  437.     if (FAILED(uvis->AddDestroyCallback(DestroyFire, (void*) fire)))
  438.         goto ret_with_error;   
  439.     return uvis;
  440. ret_with_error:
  441.     if (fire)
  442.         free(fire);
  443.     RELEASE(uvis);
  444.     return NULL;
  445. }
  446.  
  447. BOOL
  448. BuildScene(LPDIRECT3DRMDEVICE dev, LPDIRECT3DRMVIEWPORT view,
  449.            LPDIRECT3DRMFRAME scene, LPDIRECT3DRMFRAME camera)
  450. {
  451.     D3DRMRENDERQUALITY quality = D3DRMRENDER_GOURAUD;
  452.     LPDIRECT3DRMFRAME lights = NULL;
  453.     LPDIRECT3DRMFRAME frame = NULL;
  454.     LPDIRECT3DRMLIGHT light1 = NULL;
  455.     LPDIRECT3DRMLIGHT light2 = NULL;
  456.     LPDIRECT3DRMUSERVISUAL uvis = NULL;
  457.  
  458.     view = view;                /* not used */
  459.  
  460.     if (FAILED(dev->SetQuality(quality)))
  461.         goto generic_error;
  462.  
  463.     /*
  464.      * initialize the lights in the scene
  465.      */
  466.     if (FAILED(lpD3DRM->CreateFrame(scene, &lights)))
  467.         goto generic_error;
  468.     if (FAILED(lights->SetPosition(scene, D3DVAL(5), D3DVAL(5), -D3DVAL(1))))
  469.         goto generic_error;
  470.     if(FAILED(lights->SetOrientation(scene, D3DVAL(0), D3DVAL(0), D3DVAL(1),
  471.                            D3DVAL(0), D3DVAL(1), D3DVAL(1))))
  472.                            goto generic_error;
  473.     if(FAILED(lpD3DRM->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, D3DVAL(0.9),
  474.                           D3DVAL(0.8), D3DVAL(0.7), &light1)))
  475.                           goto generic_error;
  476.     if (FAILED(lights->AddLight(light1)))
  477.         goto generic_error;
  478.     if(FAILED(lpD3DRM->CreateLightRGB(D3DRMLIGHT_AMBIENT, D3DVAL(0.1),
  479.                           D3DVAL(0.1), D3DVAL(0.1), &light2)))
  480.                           goto generic_error;
  481.     if (FAILED(scene->AddLight(light2)))
  482.         goto generic_error;
  483.  
  484.     /*
  485.      * create a frame within the scene
  486.      */
  487.     if (FAILED(lpD3DRM->CreateFrame(scene, &frame)))
  488.         goto generic_error;
  489.  
  490.     /*
  491.      * add the fire into the frame
  492.      */
  493.     uvis = CreateFire();
  494.     if (!uvis)
  495.         goto generic_error;
  496.     if (FAILED(frame->AddVisual(uvis)))
  497.         goto generic_error;
  498.  
  499.     /*
  500.      * set up the frames position, orientation and rotation
  501.      */
  502.     if (FAILED(camera->SetPosition(scene, D3DVAL(0), D3DVAL(0.5), -D3DVAL(10))))
  503.         goto generic_error;
  504.     if(FAILED(camera->SetOrientation(scene, D3DVAL(0), D3DVAL(0), D3DVAL(1), D3DVAL(0),
  505.                            D3DVAL(1), D3DVAL(0))))
  506.                            goto generic_error;
  507.     if(FAILED(frame->SetRotation(scene, D3DVAL(0), D3DVAL(1), D3DVAL(0),
  508.                        D3DVAL(0.02))))
  509.                        goto generic_error;
  510.  
  511.     RELEASE(uvis);
  512.     RELEASE(frame);
  513.     RELEASE(lights);
  514.     RELEASE(light1);
  515.     RELEASE(light2);
  516.     return TRUE;
  517. generic_error:
  518.     Msg("A failure occurred while building the scene.\n");
  519.     RELEASE(lights);
  520.     RELEASE(frame);
  521.     RELEASE(light1);
  522.     RELEASE(light2);
  523.     RELEASE(uvis);
  524.     return FALSE;
  525. }
  526.  
  527. void
  528. OverrideDefaults(Defaults *defaults)
  529. {
  530.     defaults->bConstRenderQuality = TRUE;
  531.     defaults->bNoTextures = TRUE;
  532.     lstrcpy(defaults->Name, "User Visual Direct3DRM Example");
  533. }
  534.