home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / directx2 / sdk / samples / misc / texture.c < prev   
Encoding:
C/C++ Source or Header  |  1996-05-28  |  25.4 KB  |  765 lines

  1. /*
  2.  *  Copyright (C) 1995, 1996 Microsoft Corporation. All Rights Reserved.
  3.  *
  4.  *  File: texture.c
  5.  *
  6.  *  Loads and manages textures.  Part of D3DApp.
  7.  *
  8.  *  D3DApp is a collection of helper functions for Direct3D applications.
  9.  *  D3DApp consists of the following files:
  10.  *      d3dapp.h    Main D3DApp header to be included by application
  11.  *      d3dappi.h   Internal header
  12.  *      d3dapp.c    D3DApp functions seen by application.
  13.  *      ddcalls.c   All calls to DirectDraw objects except textures
  14.  *      d3dcalls.c  All calls to Direct3D objects except textures
  15.  *      texture.c   Texture loading and managing texture list
  16.  *      misc.c      Miscellaneous calls
  17.  */
  18.  
  19. #include "d3dappi.h"
  20.  
  21. /*
  22.  * STATIC FUNCTION DECLARATIONS
  23.  */
  24. static void D3DAppIAddPathList(const char *path);
  25. static void D3DAppIInitialisePathList();
  26. static FILE * D3DAppIFindFile(const char *name, const char *mode);
  27.  
  28. /***************************************************************************/
  29. /*                        Managing the texture list                        */
  30. /***************************************************************************/
  31. /*
  32.  * D3DAppILoadTextureSurf
  33.  * Creates a texture map surface and texture object from the numbered PPM
  34.  * file.  This is done in a two step process.  A source texture surface and
  35.  * object are created in system memory.  A second, initially empty, texture
  36.  * surface is created (in video memory if hardware is present).  The source
  37.  * texture is loaded into the destination texture surface and then discarded.
  38.  * This process allows a device to compress or reformat a texture map as it
  39.  * enters video memory during the Load call.
  40.  */
  41. BOOL
  42. D3DAppILoadTextureSurf(int n)
  43. {
  44.     DDSURFACEDESC ddsd;
  45.     LPDIRECTDRAWSURFACE lpSrcTextureSurf = NULL;
  46.     LPDIRECT3DTEXTURE lpSrcTexture = NULL;
  47.     LPDIRECTDRAWPALETTE lpDstPalette = NULL;
  48.     PALETTEENTRY ppe[256];
  49.     DWORD pcaps;
  50.     /*
  51.      * Release the surface if it is hanging around
  52.      */
  53.     RELEASE(d3dappi.lpTextureSurf[n]);
  54.     /*
  55.      * Create a surface in system memory and load the PPM file into it.
  56.      * Query for the texture interface.
  57.      */
  58.     lpSrcTextureSurf = D3DAppILoadSurface(d3dappi.lpDD, d3dappi.ImageFile[n],
  59.                                           &d3dappi.ThisTextureFormat.ddsd,
  60.                                           DDSCAPS_SYSTEMMEMORY);
  61.     if (!lpSrcTextureSurf)
  62.         goto exit_with_error;
  63.     LastError = lpSrcTextureSurf->lpVtbl->QueryInterface(lpSrcTextureSurf,
  64.                                              &IID_IDirect3DTexture,
  65.                                              (LPVOID*)&lpSrcTexture);
  66.     if (LastError != DD_OK) {
  67.         D3DAppISetErrorString("Failed to obtain D3D texture interface for a source texture.\n%s", D3DAppErrorToString(LastError));
  68.         goto exit_with_error;
  69.     }
  70.     /*
  71.      * Create an empty texture surface to load the source texture into.
  72.      * The DDSCAPS_ALLOCONLOAD flag allows the DD driver to wait until the
  73.      * load call to allocate the texture in memory because at this point,
  74.      * we may not know how much memory the texture will take up (e.g. it
  75.      * could be compressed to an unknown size in video memory).
  76.      */
  77.     LastError = D3DAppIGetSurfDesc(&ddsd, lpSrcTextureSurf);
  78.     if (LastError != DD_OK) {
  79.         D3DAppISetErrorString("Could not get the surface description of the source texture.\n%s",
  80.                               D3DAppErrorToString(LastError));
  81.         goto exit_with_error;
  82.     }
  83.     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  84.     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD;
  85.     LastError = D3DAppICreateSurface(&ddsd, &d3dappi.lpTextureSurf[n]);
  86.     if (LastError != DD_OK) {
  87.         D3DAppISetErrorString("Could not create the destination texture surface.\n%s",
  88.                               D3DAppErrorToString(LastError));
  89.         goto exit_with_error;
  90.     }
  91.     if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
  92.         pcaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256;
  93.     } else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) {
  94.         pcaps = DDPCAPS_4BIT;
  95.     } else {
  96.         pcaps = 0;
  97.     }
  98.     if (pcaps) {
  99.         memset(ppe, 0, sizeof(PALETTEENTRY) * 256);
  100.         LastError = d3dappi.lpDD->lpVtbl->CreatePalette(d3dappi.lpDD, pcaps,
  101.                                                  ppe, &lpDstPalette, NULL);
  102.         if (LastError != DD_OK) {
  103.             D3DAppISetErrorString("Failed to create a palette for the destination texture.\n%s",
  104.                                   D3DAppErrorToString(LastError));
  105.             goto exit_with_error;
  106.         }
  107.         LastError = d3dappi.lpTextureSurf[n]->lpVtbl->SetPalette(d3dappi.lpTextureSurf[n],
  108.                                 lpDstPalette);
  109.         if (LastError != DD_OK) {
  110.             D3DAppISetErrorString("Failed to set the destination texture's palette.\n%s",
  111.                                   D3DAppErrorToString(LastError));
  112.             goto exit_with_error;
  113.         }
  114. //      lpDstPalette->lpVtbl->Release(lpDstPalette);
  115.     }
  116.     /*
  117.      * Query our destination surface for a texture interface
  118.      */
  119.     LastError = d3dappi.lpTextureSurf[n]->lpVtbl->QueryInterface(d3dappi.lpTextureSurf[n],
  120.                                              &IID_IDirect3DTexture,
  121.                                              (LPVOID*)&d3dappi.lpTexture[n]);
  122.     if (LastError != DD_OK) {
  123.         D3DAppISetErrorString("Failed to obtain D3D texture interface for a destination texture.\n%s",
  124.                               D3DAppErrorToString(LastError));
  125.         goto exit_with_error;
  126.     }
  127.     /*
  128.      * Load the source texture into the destination.  During this call, a
  129.      * driver could compress or reformat the texture surface and put it in
  130.      * video memory.
  131.      */
  132.     LastError = d3dappi.lpTexture[n]->lpVtbl->Load(d3dappi.lpTexture[n], lpSrcTexture);
  133.     if (LastError != DD_OK) {
  134.         D3DAppISetErrorString("Could not load a source texture into a destination texture.\n%s",
  135.                               D3DAppErrorToString(LastError));
  136.         goto exit_with_error;
  137.     }
  138.  
  139.     /* 
  140.      * Now we are done with the source texture
  141.      */
  142.     RELEASE(lpSrcTexture);
  143.     RELEASE(lpSrcTextureSurf);
  144.  
  145.     /*
  146.      * Did the texture end up in video memory?
  147.      */
  148.     LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpTextureSurf[n]);
  149.     if (LastError != DD_OK) {
  150.         D3DAppISetErrorString("Could not get the surface description of the loaded texture surface.\n%s",
  151.                               D3DAppErrorToString(LastError));
  152.         goto exit_with_error;
  153.     }
  154.     if (!(ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
  155.         d3dappi.bTexturesInVideo = FALSE;
  156.     
  157.     
  158.     return TRUE;
  159.  
  160. exit_with_error:
  161.     RELEASE(lpSrcTexture);
  162.     RELEASE(lpSrcTextureSurf);
  163.     RELEASE(lpDstPalette);
  164.     RELEASE(d3dappi.lpTexture[n]);
  165.     RELEASE(d3dappi.lpTextureSurf[n]);
  166.     return FALSE;       
  167. }
  168.  
  169. /*
  170.  * D3DAppIReloadTextureSurf
  171.  * Reloads a lost and restored texture surface
  172.  */
  173. BOOL
  174. D3DAppIReloadTextureSurf(int n)
  175. {
  176.     LPDIRECTDRAWSURFACE lpSrcTextureSurf = NULL;
  177.     LPDIRECT3DTEXTURE lpSrcTexture = NULL;
  178.  
  179.     /*
  180.      * Create a surface in system memory and load the PPM file into it.
  181.      * Query for the texture interface.
  182.      */
  183.     lpSrcTextureSurf = D3DAppILoadSurface(d3dappi.lpDD, d3dappi.ImageFile[n],
  184.                                           &d3dappi.ThisTextureFormat.ddsd,
  185.                                           DDSCAPS_SYSTEMMEMORY);
  186.     if (!lpSrcTextureSurf)
  187.         goto exit_with_error;
  188.     LastError = lpSrcTextureSurf->lpVtbl->QueryInterface(lpSrcTextureSurf,
  189.                                              &IID_IDirect3DTexture,
  190.                                              (LPVOID*)&lpSrcTexture);
  191.     if (LastError != DD_OK) {
  192.         D3DAppISetErrorString("Failed to obtain D3D texture interface for a source texture.\n%s", D3DAppErrorToString(LastError));
  193.         goto exit_with_error;
  194.     }
  195.     /*
  196.      * Load the source texture into the destination.  During this call, a
  197.      * driver could compress or reformat the texture surface and put it in
  198.      * video memory.
  199.      */
  200.     LastError = d3dappi.lpTexture[n]->lpVtbl->Load(d3dappi.lpTexture[n], lpSrcTexture);
  201.     if (LastError != DD_OK) {
  202.         D3DAppISetErrorString("Could not load a source texture into a destination texture.\n%s",
  203.                               D3DAppErrorToString(LastError));
  204.         goto exit_with_error;
  205.     }
  206.     /* 
  207.      * Now we are done with the source texture
  208.      */
  209.     RELEASE(lpSrcTexture);
  210.     RELEASE(lpSrcTextureSurf);
  211.  
  212.     return TRUE;
  213.  
  214. exit_with_error:
  215.     RELEASE(lpSrcTexture);
  216.     RELEASE(lpSrcTextureSurf);
  217.     return FALSE;       
  218. }
  219.  
  220.  
  221. /*
  222.  * D3DAppIGetTextureHandle
  223.  * Get a texture handle from the current D3D device for this texture and save
  224.  * it in the MasterTextureHandle list and public texture handle list.
  225.  */
  226. BOOL
  227. D3DAppIGetTextureHandle(int n)
  228. {
  229.     if (d3dappi.ThisDriver.bIsHardware && !d3dappi.bTexturesInVideo) {
  230.         D3DAppISetErrorString("Could not put all the textures in video memory for this hardware device.\n");
  231.         goto exit_with_error;
  232.     }
  233.     LastError = d3dappi.lpTexture[n]->lpVtbl->GetHandle(d3dappi.lpTexture[n],
  234.                                d3dappi.lpD3DDevice, &MasterTextureHandle[n]);
  235.     if (LastError != DD_OK) {
  236.         D3DAppISetErrorString("Could not get a handle to loaded texture %i.\n%s",
  237.                               n, D3DAppErrorToString(LastError));
  238.         goto exit_with_error;
  239.     }
  240.     /*
  241.      * If textures are enabled, put the handle in the public texture list,
  242.      * otherwise, keep it as zero.
  243.      */
  244.     if (!d3dappi.bTexturesDisabled) {
  245.         d3dappi.TextureHandle[n] = MasterTextureHandle[n];
  246.     } else {
  247.         d3dappi.TextureHandle[n] = 0;
  248.     }
  249.     return TRUE;
  250. exit_with_error:
  251.     MasterTextureHandle[n] = 0;
  252.     d3dappi.TextureHandle[n] = 0;
  253.     return FALSE;       
  254. }
  255.  
  256. /*
  257.  * D3DAppIReleaseTexture
  258.  * Release this texture surface and texture interface.  Remember, a texture
  259.  * handle is NOT and object and does not need to be released or destroyed.
  260.  * The handle is no longer valid after the device is destroyed, so set it to
  261.  * zero here.
  262.  */
  263. void
  264. D3DAppIReleaseTexture(int n)
  265. {
  266.     RELEASE(d3dappi.lpTexture[n]);
  267.     RELEASE(d3dappi.lpTextureSurf[n]);
  268.     MasterTextureHandle[n] = 0;
  269.     d3dappi.TextureHandle[n] = 0;
  270. }
  271.  
  272. /*
  273.  * D3DAppIReleaseAllTextures
  274.  * Release all texture surfaces and texture interfaces
  275.  */
  276. void
  277. D3DAppIReleaseAllTextures(void)
  278. {
  279.     int i;
  280.     for (i = 0; i < d3dappi.NumTextures; i++) {
  281.         D3DAppIReleaseTexture(i);
  282.     }
  283. }
  284.  
  285. /*
  286.  * D3DAppILoadAllTextures
  287.  * Load all texture surfaces, qeury them for texture interfaces and get
  288.  * handles for them from the current D3D driver.
  289.  */
  290. BOOL
  291. D3DAppILoadAllTextures(void)
  292. {
  293.     int i;
  294.     if (d3dappi.ThisDriver.bDoesTextures) {
  295.         d3dappi.bTexturesInVideo = TRUE;
  296.         for (i = 0; i < d3dappi.NumTextures; i++) {
  297.             ATTEMPT(D3DAppILoadTextureSurf(i));
  298.             ATTEMPT(D3DAppIGetTextureHandle(i));
  299.         }
  300.     } else {
  301.         d3dappi.bTexturesInVideo = FALSE;
  302.     }
  303.     return TRUE;
  304.  
  305. exit_with_error:
  306.     for (i = 0; i < d3dappi.NumTextures; i++) {
  307.         D3DAppIReleaseTexture(i);
  308.     }
  309.     return FALSE;
  310. }
  311.  
  312. /***************************************************************************/
  313. /*                    Loading a PPM file into a surface                    */
  314. /***************************************************************************/
  315. /*
  316.  * LoadSurface
  317.  * Loads a ppm file into a texture map DD surface of the given format.  The
  318.  * memory flag specifies DDSCAPS_SYSTEMMEMORY or DDSCAPS_VIDEOMEMORY.
  319.  */
  320. LPDIRECTDRAWSURFACE
  321. D3DAppILoadSurface(LPDIRECTDRAW lpDD, LPCSTR lpName,
  322.                    LPDDSURFACEDESC lpFormat, DWORD memoryflag)
  323. {
  324.     LPDIRECTDRAWSURFACE lpDDS;
  325.     DDSURFACEDESC ddsd, format;
  326.     D3DCOLOR colors[256];
  327.     D3DCOLOR c;
  328.     DWORD dwWidth, dwHeight;
  329.     int i, j;
  330.     FILE *fp;
  331.     char *lpC;
  332.     CHAR buf[100];
  333.     LPDIRECTDRAWPALETTE lpDDPal;
  334.     PALETTEENTRY ppe[256];
  335.     int psize;
  336.     DWORD pcaps;
  337.     int color_count;
  338.     BOOL bQuant = FALSE;
  339.     HRESULT ddrval;
  340.  
  341.     /*
  342.      * Find the image file and open it
  343.      */
  344.     fp = D3DAppIFindFile(lpName, "rb");
  345.     if (fp == NULL) {
  346.         D3DAppISetErrorString("Cannot find %s.\n", lpName);
  347.         return NULL;
  348.     }
  349.     /*
  350.      * Is it a PPM file?
  351.      */
  352.     fgets(buf, sizeof buf, fp);
  353.     if (lstrcmp(buf, "P6\n")) {
  354.         fclose(fp);
  355.         D3DAppISetErrorString("%s is not a PPM file.\n", lpName);
  356.         return NULL;
  357.     }
  358.     /*
  359.      * Skip any comments
  360.      */
  361.     do {
  362.         fgets(buf, sizeof buf, fp);
  363.     } while (buf[0] == '#');
  364.     /*
  365.      * Read the width and height
  366.      */
  367.     sscanf(buf, "%d %d\n", &dwWidth, &dwHeight);
  368.     fgets(buf, sizeof buf, fp); /* skip next line */
  369.     /*
  370.      * Create a surface of the given format using the dimensions of the PPM
  371.      * file.
  372.      */
  373.     memcpy(&format, lpFormat, sizeof(DDSURFACEDESC));
  374.     if (format.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
  375.         bQuant = TRUE;
  376.         psize = 256;
  377.         pcaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256;
  378.     } else if (format.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) {
  379.         bQuant = TRUE;
  380.         psize = 16;
  381.         pcaps = DDPCAPS_4BIT;
  382.     }
  383.     memcpy(&ddsd, &format, sizeof(DDSURFACEDESC));
  384.     ddsd.dwSize = sizeof(DDSURFACEDESC);
  385.     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  386.     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | memoryflag;
  387.     ddsd.dwHeight = dwHeight;
  388.     ddsd.dwWidth = dwWidth;
  389.  
  390.     ddrval = lpDD->lpVtbl->CreateSurface(lpDD, &ddsd, &lpDDS, NULL);
  391.     if (ddrval != DD_OK) {
  392.         D3DAppISetErrorString("CreateSurface for texture failed (loadtex).\n%s",
  393.                               D3DAppErrorToString(ddrval));
  394.         return NULL;
  395.     }
  396.     /*
  397.      * Lock the surface so it can be filled with the PPM file
  398.      */
  399.     memset(&ddsd, 0, sizeof(DDSURFACEDESC));
  400.     ddsd.dwSize = sizeof(DDSURFACEDESC);
  401.     ddrval = lpDDS->lpVtbl->Lock(lpDDS, NULL, &ddsd, 0, NULL);
  402.     if (ddrval != DD_OK) {
  403.         lpDDS->lpVtbl->Release(lpDDS);
  404.         D3DAppISetErrorString("Lock failed while loading surface (loadtex).\n%s",
  405.                               D3DAppErrorToString(ddrval));
  406.         return NULL;
  407.     }
  408.     /*
  409.      * The method of loading depends on the pixel format of the dest surface
  410.      */
  411.     if (!bQuant) {
  412.         /*
  413.          * The texture surface is not palettized
  414.          */
  415.         unsigned long* lpLP;
  416.         unsigned short* lpSP;
  417.         unsigned char* lpCP;
  418.         unsigned long m;
  419.         int s;
  420.         int red_shift, red_scale;
  421.         int green_shift, green_scale;
  422.         int blue_shift, blue_scale;
  423.         /*
  424.          * Determine the red, green and blue masks' shift and scale.
  425.          */
  426.         for (s = 0, m = format.ddpfPixelFormat.dwRBitMask; !(m & 1);
  427.                                                                s++, m >>= 1);
  428.         red_shift = s;
  429.         red_scale = 255 / (format.ddpfPixelFormat.dwRBitMask >> s);
  430.         for (s = 0, m = format.ddpfPixelFormat.dwGBitMask; !(m & 1);
  431.                                                                s++, m >>= 1);
  432.         green_shift = s;
  433.         green_scale = 255 / (format.ddpfPixelFormat.dwGBitMask >> s);
  434.         for (s = 0, m = format.ddpfPixelFormat.dwBBitMask; !(m & 1);
  435.                                                                s++, m >>= 1);
  436.         blue_shift = s;
  437.         blue_scale = 255 / (format.ddpfPixelFormat.dwBBitMask >> s);
  438.         /*
  439.          * Each RGB bit count requires different pointers
  440.          */
  441.         switch (format.ddpfPixelFormat.dwRGBBitCount) {
  442.             case 32 :
  443.                 for (j = 0; j < (int)dwHeight; j++) {
  444.                     /*
  445.                      * Point to next row in texture surface
  446.                      */
  447.                     lpLP = (unsigned long*)(((char*)ddsd.lpSurface) +
  448.                                                             ddsd.lPitch * j);
  449.                     for (i = 0; i < (int)dwWidth; i++) {
  450.                         int r, g, b;
  451.                         /*
  452.                          * Read each value, scale it and shift it into position
  453.                          */
  454.                         r = getc(fp) / red_scale;
  455.                         g = getc(fp) / green_scale;
  456.                         b = getc(fp) / blue_scale;
  457.                         *lpLP = (r << red_shift) | (g << green_shift) |
  458.                                 (b << blue_shift);
  459.                         lpLP++;
  460.                     }
  461.                 }
  462.                 break;
  463.             case 16 :
  464.                 for (j = 0; j < (int)dwHeight; j++) {
  465.                     lpSP = (unsigned short*)(((char*)ddsd.lpSurface) +
  466.                                                             ddsd.lPitch * j);
  467.                     for (i = 0; i < (int)dwWidth; i++) {
  468.                         int r, g, b;
  469.                         r = getc(fp) / red_scale;
  470.                         g = getc(fp) / green_scale;
  471.                         b = getc(fp) / blue_scale;
  472.                         *lpSP = (r << red_shift) | (g << green_shift) |
  473.                                 (b << blue_shift);
  474.                         lpSP++;
  475.                     }
  476.                 }
  477.                 break;
  478.             case 8:
  479.                 for (j = 0; j < (int)dwHeight; j++) {
  480.                     lpCP = (unsigned char*)(((char*)ddsd.lpSurface) +
  481.                                                             ddsd.lPitch * j);
  482.                     for (i = 0; i < (int)dwWidth; i++) {
  483.                         int r, g, b;
  484.                         r = getc(fp) / red_scale;
  485.                         g = getc(fp) / green_scale;
  486.                         b = getc(fp) / blue_scale;
  487.                         *lpCP = (r << red_shift) | (g << green_shift) | 
  488.                                 (b << blue_shift);
  489.                         lpCP++;
  490.                     }
  491.                 }
  492.                 break;
  493.             default:
  494.                 /*
  495.                  * This wasn't a format I recognize
  496.                  */
  497.                 lpDDS->lpVtbl->Unlock(lpDDS, NULL);
  498.                 fclose(fp);
  499.                 lpDDS->lpVtbl->Release(lpDDS);
  500.                 D3DAppISetErrorString("Unknown pixel format (loadtex).");
  501.                 return NULL;
  502.         }
  503.         /*
  504.          * Unlock the texture and return the surface pointer
  505.          */
  506.         lpDDS->lpVtbl->Unlock(lpDDS, NULL);
  507.         fclose(fp);
  508.         return (lpDDS);
  509.     }
  510.  
  511.     /*
  512.      * We assume the 8-bit palettized case
  513.      */
  514.     color_count = 0;    /* number of colors in the texture */
  515.     for (j = 0; j < (int)dwHeight; j++) {
  516.         /*
  517.          * Point to next row in surface
  518.          */
  519.         lpC = ((char*)ddsd.lpSurface) + ddsd.lPitch * j;
  520.         for (i = 0; i < (int)dwWidth; i++) {
  521.             int r, g, b, k;
  522.             /*
  523.              * Get the next red, green and blue values and turn them into a
  524.              * D3DCOLOR
  525.              */
  526.             r = getc(fp);
  527.             g = getc(fp);
  528.             b = getc(fp);
  529.             c = RGB_MAKE(r, g, b);
  530.             /*
  531.              * Search for this color in a table of colors in this texture
  532.              */
  533.             for (k = 0; k < color_count; k++)
  534.                 if (c == colors[k]) break;
  535.             if (k == color_count) {
  536.                 /*
  537.                  * This is a new color, so add it to the list
  538.                  */
  539.                 color_count++;
  540.                 /*
  541.                  * More than 256 and we fail (8-bit) 
  542.                  */
  543.                 if (color_count > psize) {
  544.                     color_count--;
  545.                     k = color_count - 1;
  546.                     //goto burst_colors;
  547.                 }
  548.                 colors[k] = c;
  549.             }
  550.             /*
  551.              * Set the "pixel" value on the surface to be the index into the
  552.              * color table
  553.              */
  554.             if (psize == 16) {
  555.                 if ((i & 1) == 0)
  556.                     *lpC = k & 0xf;
  557.                 else {
  558.                     *lpC |= (k & 0xf) << 4;
  559.                     lpC++;
  560.                 }
  561.             } else {
  562.                 *lpC = (char)k;
  563.                 lpC++;
  564.             }
  565.         }
  566.     }
  567.     /*
  568.      * Close the file and unlock the surface
  569.      */
  570.     fclose(fp);
  571.     lpDDS->lpVtbl->Unlock(lpDDS, NULL);
  572.  
  573. //burst_colors:
  574.     if (color_count > psize) {
  575.         /*
  576.          * If there are more than 256 colors, we overran our palette
  577.          */
  578.         lpDDS->lpVtbl->Unlock(lpDDS, NULL);
  579.         lpDDS->lpVtbl->Release(lpDDS);
  580.         D3DAppISetErrorString("Palette burst. (loadtex).\n");
  581.         return (NULL);
  582.     }
  583.  
  584.     /*
  585.      * Create a palette with the colors in our color table
  586.      */
  587.     memset(ppe, 0, sizeof(PALETTEENTRY) * 256);
  588.     for (i = 0; i < color_count; i++) {
  589.         ppe[i].peRed = (unsigned char)RGB_GETRED(colors[i]);
  590.         ppe[i].peGreen = (unsigned char)RGB_GETGREEN(colors[i]);
  591.         ppe[i].peBlue = (unsigned char)RGB_GETBLUE(colors[i]);
  592.     }
  593.     /*
  594.      * Set all remaining entry flags to D3DPAL_RESERVED, which are ignored by
  595.      * the renderer.
  596.      */
  597.     for (; i < 256; i++)
  598.         ppe[i].peFlags = D3DPAL_RESERVED;
  599.     /*
  600.      * Create the palette with the DDPCAPS_ALLOW256 flag because we want to
  601.      * have access to all entries.
  602.      */
  603.     ddrval = lpDD->lpVtbl->CreatePalette(lpDD,
  604.                                          DDPCAPS_INITIALIZE | pcaps,
  605.                                          ppe, &lpDDPal, NULL);
  606.     if (ddrval != DD_OK) {
  607.         lpDDS->lpVtbl->Release(lpDDS);
  608.         D3DAppISetErrorString("Create palette failed while loading surface (loadtex).\n%s",
  609.                               D3DAppErrorToString(ddrval));
  610.         return (NULL);
  611.     }
  612.     /*
  613.      * Finally, bind the palette to the surface
  614.      */
  615.     ddrval = lpDDS->lpVtbl->SetPalette(lpDDS, lpDDPal);
  616.     if (ddrval != DD_OK) {
  617.         lpDDS->lpVtbl->Release(lpDDS);
  618.         lpDDPal->lpVtbl->Release(lpDDPal);
  619.         D3DAppISetErrorString("SetPalette failed while loading surface (loadtex).\n%s",
  620.                               D3DAppErrorToString(ddrval));
  621.         return (NULL);
  622.     }
  623.  
  624.     lpDDPal->lpVtbl->Release(lpDDPal);
  625.  
  626.     return lpDDS;
  627. }
  628.  
  629. /***************************************************************************/
  630. /*                         Finding Textures                                */
  631. /***************************************************************************/
  632.  
  633. #define MAXPATH    256
  634. #define PATHSEP    ';'
  635. #define FILESEP    '\\'
  636. #define MAXCONTENTS 25
  637. #define RESPATH     "Software\\Microsoft\\Direct3D"
  638.  
  639. static int PathListInitialised = FALSE;
  640.  
  641. /*
  642.  * PathList structure
  643.  * A list of directories in which to search for the texture.
  644.  */
  645. static struct {
  646.     int count;
  647.     char *contents[MAXCONTENTS];
  648. } PathList;
  649.  
  650. /*
  651.  * D3DAppIAddPathList
  652.  * Add this string to the search path list
  653.  */
  654. static void 
  655. D3DAppIAddPathList(const char *path)
  656. {
  657.     char *p;
  658.     char *elt;
  659.     int len;
  660.  
  661.     while (path) {
  662.         p = LSTRCHR(path, PATHSEP);
  663.         if (p)
  664.             len = p - path;
  665.         else
  666.             len = lstrlen(path);
  667.         elt = (char *) malloc(len + 1);
  668.         if (elt == NULL)
  669.             return;
  670.         lstrcpyn(elt, path, len + 1);
  671.         elt[len] = '\0';
  672.         PathList.contents[PathList.count] = elt;
  673.         PathList.count++;
  674.         if (p)
  675.             path = p + 1;
  676.         else
  677.             path = NULL;
  678.         if (PathList.count == MAXCONTENTS)
  679.             return;
  680.     }
  681.     return;
  682. }
  683.  
  684. /*
  685.  * D3DAppIInitialisePathList
  686.  * Create a search path with the D3DPATH env. var and D3D Path registry entry
  687.  */
  688. static void 
  689. D3DAppIInitialisePathList()
  690. {
  691.     long result;
  692.     HKEY key;
  693.     DWORD type, size;
  694.     static char buf[512];
  695.     char* path;
  696.  
  697.     if (PathListInitialised)
  698.         return;
  699.     PathListInitialised = TRUE;
  700.  
  701.     PathList.count = 0;
  702.     path = getenv("D3DPATH");
  703.     D3DAppIAddPathList(".");
  704.     if (path != NULL) {
  705.         D3DAppIAddPathList(path);
  706.         return;
  707.     }
  708.     result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RESPATH, 0, KEY_READ, &key);
  709.     if (result == ERROR_SUCCESS) {
  710.         size = sizeof(buf);
  711.         result = RegQueryValueEx(key, "D3D Path", NULL, &type, (LPBYTE) buf,
  712.                                  &size);
  713.         RegCloseKey(key);
  714.         if (result == ERROR_SUCCESS && type == REG_SZ)
  715.             D3DAppIAddPathList(buf);
  716.     }
  717. }
  718.  
  719.  
  720. /*
  721.  * D3DAppIFindFile
  722.  * Find and open a file using the current search path.
  723.  */
  724. static FILE*
  725. D3DAppIFindFile(const char *name, const char *mode)
  726. {
  727.     FILE *fp;
  728.     char buf[MAXPATH];
  729.     static char filesep[] = {FILESEP, 0};
  730.     int i;
  731.  
  732.     D3DAppIInitialisePathList();
  733.  
  734.     fp = fopen(name, mode);
  735.     if (fp != NULL)
  736.         return fp;
  737.  
  738.     for (i = 0; i < PathList.count; i++) {
  739.         lstrcpy(buf, PathList.contents[i]);
  740.         lstrcat(buf, filesep);
  741.         lstrcat(buf, name);
  742.         fp = fopen(buf, mode);
  743.         if (fp)
  744.             return fp;
  745.     }
  746.     return NULL;
  747. }
  748.  
  749. /*
  750.  * D3DAppIReleasePathList
  751.  * Release the path list for program termination
  752.  */
  753. void
  754. D3DAppIReleasePathList(void)
  755. {
  756.     int i;
  757.     for (i = 0; i < PathList.count; i++) {
  758.         free(PathList.contents[i]);
  759.         PathList.contents[i] = NULL;
  760.     }
  761.     PathList.count = 0;
  762.     PathListInitialised = FALSE;
  763. }
  764.  
  765.