
Source code release, imported from: https://www.gamefront.com/games/aliens-vs-predator-3/file/avp-gold-complete-source-code All text files were converted to Unix format.
316 lines
11 KiB
C
316 lines
11 KiB
C
/***************************************************************************/
|
|
/* Loading a PPM file into a surface */
|
|
/***************************************************************************/
|
|
/*
|
|
* LoadSurface
|
|
* Loads a ppm file into a texture map DD surface of the given format. The
|
|
* memory flag specifies DDSCAPS_SYSTEMMEMORY or DDSCAPS_VIDEOMEMORY.
|
|
*/
|
|
LPDIRECTDRAWSURFACE
|
|
D3DAppILoadSurface(LPDIRECTDRAW lpDD, LPCSTR lpName,
|
|
LPDDSURFACEDESC lpFormat, DWORD memoryflag)
|
|
{
|
|
LPDIRECTDRAWSURFACE lpDDS;
|
|
DDSURFACEDESC ddsd, format;
|
|
D3DCOLOR colors[256];
|
|
D3DCOLOR c;
|
|
DWORD dwWidth, dwHeight;
|
|
int i, j;
|
|
FILE *fp;
|
|
char *lpC;
|
|
CHAR buf[100];
|
|
LPDIRECTDRAWPALETTE lpDDPal;
|
|
PALETTEENTRY ppe[256];
|
|
int psize;
|
|
DWORD pcaps;
|
|
int color_count;
|
|
BOOL bQuant = FALSE;
|
|
HRESULT ddrval;
|
|
|
|
/*
|
|
* Find the image file and open it
|
|
*/
|
|
fp = D3DAppIFindFile(lpName, "rb");
|
|
if (fp == NULL) {
|
|
D3DAppISetErrorString("Cannot find %s.\n", lpName);
|
|
return NULL;
|
|
}
|
|
/*
|
|
* Is it a PPM file?
|
|
*/
|
|
fgets(buf, sizeof buf, fp);
|
|
if (lstrcmp(buf, "P6\n")) {
|
|
fclose(fp);
|
|
D3DAppISetErrorString("%s is not a PPM file.\n", lpName);
|
|
return NULL;
|
|
}
|
|
/*
|
|
* Skip any comments
|
|
*/
|
|
do {
|
|
fgets(buf, sizeof buf, fp);
|
|
} while (buf[0] == '#');
|
|
/*
|
|
* Read the width and height
|
|
*/
|
|
sscanf(buf, "%d %d\n", &dwWidth, &dwHeight);
|
|
fgets(buf, sizeof buf, fp); /* skip next line */
|
|
/*
|
|
* Create a surface of the given format using the dimensions of the PPM
|
|
* file.
|
|
*/
|
|
memcpy(&format, lpFormat, sizeof(DDSURFACEDESC));
|
|
if (format.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
|
|
bQuant = TRUE;
|
|
psize = 256;
|
|
pcaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256;
|
|
} else if (format.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) {
|
|
bQuant = TRUE;
|
|
psize = 16;
|
|
pcaps = DDPCAPS_4BIT;
|
|
}
|
|
memcpy(&ddsd, &format, sizeof(DDSURFACEDESC));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC);
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | memoryflag;
|
|
ddsd.dwHeight = dwHeight;
|
|
ddsd.dwWidth = dwWidth;
|
|
|
|
ddrval = lpDD->lpVtbl->CreateSurface(lpDD, &ddsd, &lpDDS, NULL);
|
|
if (ddrval != DD_OK) {
|
|
D3DAppISetErrorString("CreateSurface for texture failed (loadtex).\n%s",
|
|
D3DAppErrorToString(ddrval));
|
|
return NULL;
|
|
}
|
|
/*
|
|
* Lock the surface so it can be filled with the PPM file
|
|
*/
|
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC);
|
|
ddrval = lpDDS->lpVtbl->Lock(lpDDS, NULL, &ddsd, 0, NULL);
|
|
if (ddrval != DD_OK) {
|
|
lpDDS->lpVtbl->Release(lpDDS);
|
|
D3DAppISetErrorString("Lock failed while loading surface (loadtex).\n%s",
|
|
D3DAppErrorToString(ddrval));
|
|
return NULL;
|
|
}
|
|
/*
|
|
* The method of loading depends on the pixel format of the dest surface
|
|
*/
|
|
if (!bQuant) {
|
|
/*
|
|
* The texture surface is not palettized
|
|
*/
|
|
unsigned long* lpLP;
|
|
unsigned short* lpSP;
|
|
unsigned char* lpCP;
|
|
unsigned long m;
|
|
int s;
|
|
int red_shift, red_scale;
|
|
int green_shift, green_scale;
|
|
int blue_shift, blue_scale;
|
|
/*
|
|
* Determine the red, green and blue masks' shift and scale.
|
|
*/
|
|
for (s = 0, m = format.ddpfPixelFormat.dwRBitMask; !(m & 1);
|
|
s++, m >>= 1);
|
|
red_shift = s;
|
|
red_scale = 255 / (format.ddpfPixelFormat.dwRBitMask >> s);
|
|
for (s = 0, m = format.ddpfPixelFormat.dwGBitMask; !(m & 1);
|
|
s++, m >>= 1);
|
|
green_shift = s;
|
|
green_scale = 255 / (format.ddpfPixelFormat.dwGBitMask >> s);
|
|
for (s = 0, m = format.ddpfPixelFormat.dwBBitMask; !(m & 1);
|
|
s++, m >>= 1);
|
|
blue_shift = s;
|
|
blue_scale = 255 / (format.ddpfPixelFormat.dwBBitMask >> s);
|
|
/*
|
|
* Each RGB bit count requires different pointers
|
|
*/
|
|
switch (format.ddpfPixelFormat.dwRGBBitCount) {
|
|
case 32 :
|
|
for (j = 0; j < (int)dwHeight; j++) {
|
|
/*
|
|
* Point to next row in texture surface
|
|
*/
|
|
lpLP = (unsigned long*)(((char*)ddsd.lpSurface) +
|
|
ddsd.lPitch * j);
|
|
for (i = 0; i < (int)dwWidth; i++) {
|
|
int r, g, b;
|
|
/*
|
|
* Read each value, scale it and shift it into position
|
|
*/
|
|
r = getc(fp) / red_scale;
|
|
g = getc(fp) / green_scale;
|
|
b = getc(fp) / blue_scale;
|
|
*lpLP = (r << red_shift) | (g << green_shift) |
|
|
(b << blue_shift);
|
|
lpLP++;
|
|
}
|
|
}
|
|
break;
|
|
case 16 :
|
|
for (j = 0; j < (int)dwHeight; j++) {
|
|
lpSP = (unsigned short*)(((char*)ddsd.lpSurface) +
|
|
ddsd.lPitch * j);
|
|
for (i = 0; i < (int)dwWidth; i++) {
|
|
int r, g, b;
|
|
r = getc(fp) / red_scale;
|
|
g = getc(fp) / green_scale;
|
|
b = getc(fp) / blue_scale;
|
|
*lpSP = (r << red_shift) | (g << green_shift) |
|
|
(b << blue_shift);
|
|
lpSP++;
|
|
}
|
|
}
|
|
break;
|
|
case 8:
|
|
for (j = 0; j < (int)dwHeight; j++) {
|
|
lpCP = (unsigned char*)(((char*)ddsd.lpSurface) +
|
|
ddsd.lPitch * j);
|
|
for (i = 0; i < (int)dwWidth; i++) {
|
|
int r, g, b;
|
|
r = getc(fp) / red_scale;
|
|
g = getc(fp) / green_scale;
|
|
b = getc(fp) / blue_scale;
|
|
*lpCP = (r << red_shift) | (g << green_shift) |
|
|
(b << blue_shift);
|
|
lpCP++;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
/*
|
|
* This wasn't a format I recognize
|
|
*/
|
|
lpDDS->lpVtbl->Unlock(lpDDS, NULL);
|
|
fclose(fp);
|
|
lpDDS->lpVtbl->Release(lpDDS);
|
|
D3DAppISetErrorString("Unknown pixel format (loadtex).");
|
|
return NULL;
|
|
}
|
|
/*
|
|
* Unlock the texture and return the surface pointer
|
|
*/
|
|
lpDDS->lpVtbl->Unlock(lpDDS, NULL);
|
|
fclose(fp);
|
|
return (lpDDS);
|
|
}
|
|
|
|
/*
|
|
* We assume the 8-bit palettized case
|
|
*/
|
|
color_count = 0; /* number of colors in the texture */
|
|
for (j = 0; j < (int)dwHeight; j++) {
|
|
/*
|
|
* Point to next row in surface
|
|
*/
|
|
lpC = ((char*)ddsd.lpSurface) + ddsd.lPitch * j;
|
|
for (i = 0; i < (int)dwWidth; i++) {
|
|
int r, g, b, k;
|
|
/*
|
|
* Get the next red, green and blue values and turn them into a
|
|
* D3DCOLOR
|
|
*/
|
|
r = getc(fp);
|
|
g = getc(fp);
|
|
b = getc(fp);
|
|
c = RGB_MAKE(r, g, b);
|
|
/*
|
|
* Search for this color in a table of colors in this texture
|
|
*/
|
|
for (k = 0; k < color_count; k++)
|
|
if (c == colors[k]) break;
|
|
if (k == color_count) {
|
|
/*
|
|
* This is a new color, so add it to the list
|
|
*/
|
|
color_count++;
|
|
/*
|
|
* More than 256 and we fail (8-bit)
|
|
*/
|
|
if (color_count > psize) {
|
|
color_count--;
|
|
k = color_count - 1;
|
|
//goto burst_colors;
|
|
}
|
|
colors[k] = c;
|
|
}
|
|
/*
|
|
* Set the "pixel" value on the surface to be the index into the
|
|
* color table
|
|
*/
|
|
if (psize == 16) {
|
|
if ((i & 1) == 0)
|
|
*lpC = k & 0xf;
|
|
else {
|
|
*lpC |= (k & 0xf) << 4;
|
|
lpC++;
|
|
}
|
|
} else {
|
|
*lpC = (char)k;
|
|
lpC++;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Close the file and unlock the surface
|
|
*/
|
|
fclose(fp);
|
|
lpDDS->lpVtbl->Unlock(lpDDS, NULL);
|
|
|
|
//burst_colors:
|
|
if (color_count > psize) {
|
|
/*
|
|
* If there are more than 256 colors, we overran our palette
|
|
*/
|
|
lpDDS->lpVtbl->Unlock(lpDDS, NULL);
|
|
lpDDS->lpVtbl->Release(lpDDS);
|
|
D3DAppISetErrorString("Palette burst. (loadtex).\n");
|
|
return (NULL);
|
|
}
|
|
|
|
/*
|
|
* Create a palette with the colors in our color table
|
|
*/
|
|
memset(ppe, 0, sizeof(PALETTEENTRY) * 256);
|
|
for (i = 0; i < color_count; i++) {
|
|
ppe[i].peRed = (unsigned char)RGB_GETRED(colors[i]);
|
|
ppe[i].peGreen = (unsigned char)RGB_GETGREEN(colors[i]);
|
|
ppe[i].peBlue = (unsigned char)RGB_GETBLUE(colors[i]);
|
|
}
|
|
/*
|
|
* Set all remaining entry flags to D3DPAL_RESERVED, which are ignored by
|
|
* the renderer.
|
|
*/
|
|
for (; i < 256; i++)
|
|
ppe[i].peFlags = D3DPAL_RESERVED;
|
|
/*
|
|
* Create the palette with the DDPCAPS_ALLOW256 flag because we want to
|
|
* have access to all entries.
|
|
*/
|
|
ddrval = lpDD->lpVtbl->CreatePalette(lpDD,
|
|
DDPCAPS_INITIALIZE | pcaps,
|
|
ppe, &lpDDPal, NULL);
|
|
if (ddrval != DD_OK) {
|
|
lpDDS->lpVtbl->Release(lpDDS);
|
|
D3DAppISetErrorString("Create palette failed while loading surface (loadtex).\n%s",
|
|
D3DAppErrorToString(ddrval));
|
|
return (NULL);
|
|
}
|
|
/*
|
|
* Finally, bind the palette to the surface
|
|
*/
|
|
ddrval = lpDDS->lpVtbl->SetPalette(lpDDS, lpDDPal);
|
|
if (ddrval != DD_OK) {
|
|
lpDDS->lpVtbl->Release(lpDDS);
|
|
lpDDPal->lpVtbl->Release(lpDDPal);
|
|
D3DAppISetErrorString("SetPalette failed while loading surface (loadtex).\n%s",
|
|
D3DAppErrorToString(ddrval));
|
|
return (NULL);
|
|
}
|
|
|
|
lpDDPal->lpVtbl->Release(lpDDPal);
|
|
|
|
return lpDDS;
|
|
}
|