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