mirror of https://github.com/snes9xgit/snes9x.git
246 lines
6.2 KiB
C++
246 lines
6.2 KiB
C++
|
#include "snes9x.h"
|
||
|
#include <windows.h>
|
||
|
#include <png.h>
|
||
|
#include "dxerr.h"
|
||
|
#include "image_functions.h"
|
||
|
|
||
|
#ifdef HAVE_LIBPNG
|
||
|
bool loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool &outHasAlpha, unsigned char **outData) {
|
||
|
png_structp png_ptr;
|
||
|
png_infop info_ptr;
|
||
|
unsigned int sig_read = 0;
|
||
|
int color_type, interlace_type;
|
||
|
FILE *fp;
|
||
|
|
||
|
if ((fp = _tfopen(name, TEXT("rb"))) == NULL)
|
||
|
return false;
|
||
|
|
||
|
/* Create and initialize the png_struct
|
||
|
* with the desired error handler
|
||
|
* functions. If you want to use the
|
||
|
* default stderr and longjump method,
|
||
|
* you can supply NULL for the last
|
||
|
* three parameters. We also supply the
|
||
|
* the compiler header file version, so
|
||
|
* that we know if the application
|
||
|
* was compiled with a compatible version
|
||
|
* of the library. REQUIRED
|
||
|
*/
|
||
|
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
|
||
|
NULL, NULL, NULL);
|
||
|
|
||
|
if (png_ptr == NULL) {
|
||
|
fclose(fp);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/* Allocate/initialize the memory
|
||
|
* for image information. REQUIRED. */
|
||
|
info_ptr = png_create_info_struct(png_ptr);
|
||
|
if (info_ptr == NULL) {
|
||
|
fclose(fp);
|
||
|
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/* Set error handling if you are
|
||
|
* using the setjmp/longjmp method
|
||
|
* (this is the normal method of
|
||
|
* doing things with libpng).
|
||
|
* REQUIRED unless you set up
|
||
|
* your own error handlers in
|
||
|
* the png_create_read_struct()
|
||
|
* earlier.
|
||
|
*/
|
||
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
||
|
/* Free all of the memory associated
|
||
|
* with the png_ptr and info_ptr */
|
||
|
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||
|
fclose(fp);
|
||
|
/* If we get here, we had a
|
||
|
* problem reading the file */
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/* Set up the output control if
|
||
|
* you are using standard C streams */
|
||
|
png_init_io(png_ptr, fp);
|
||
|
|
||
|
/* If we have already
|
||
|
* read some of the signature */
|
||
|
png_set_sig_bytes(png_ptr, sig_read);
|
||
|
|
||
|
/*
|
||
|
* If you have enough memory to read
|
||
|
* in the entire image at once, and
|
||
|
* you need to specify only
|
||
|
* transforms that can be controlled
|
||
|
* with one of the PNG_TRANSFORM_*
|
||
|
* bits (this presently excludes
|
||
|
* dithering, filling, setting
|
||
|
* background, and doing gamma
|
||
|
* adjustment), then you can read the
|
||
|
* entire image (including pixels)
|
||
|
* into the info structure with this
|
||
|
* call
|
||
|
*
|
||
|
* PNG_TRANSFORM_STRIP_16 |
|
||
|
* PNG_TRANSFORM_PACKING forces 8 bit
|
||
|
* PNG_TRANSFORM_EXPAND forces to
|
||
|
* expand a palette into RGB
|
||
|
*/
|
||
|
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, (png_voidp)NULL);
|
||
|
|
||
|
outWidth = png_get_image_width(png_ptr, info_ptr);
|
||
|
outHeight = png_get_image_height(png_ptr, info_ptr);
|
||
|
switch (png_get_color_type(png_ptr, info_ptr)) {
|
||
|
case PNG_COLOR_TYPE_RGBA:
|
||
|
outHasAlpha = true;
|
||
|
break;
|
||
|
case PNG_COLOR_TYPE_RGB:
|
||
|
outHasAlpha = false;
|
||
|
break;
|
||
|
default:
|
||
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||
|
fclose(fp);
|
||
|
return false;
|
||
|
}
|
||
|
unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr);
|
||
|
*outData = (unsigned char*)malloc(row_bytes * outHeight);
|
||
|
|
||
|
png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
|
||
|
|
||
|
for (int i = 0; i < outHeight; i++) {
|
||
|
memcpy(*outData + (row_bytes * i), row_pointers[i], row_bytes);
|
||
|
}
|
||
|
|
||
|
/* Clean up after the read,
|
||
|
* and free any memory allocated */
|
||
|
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||
|
|
||
|
/* Close the file */
|
||
|
fclose(fp);
|
||
|
|
||
|
/* That's it */
|
||
|
return true;
|
||
|
}
|
||
|
#else
|
||
|
bool loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool &outHasAlpha, GLubyte **outData) {
|
||
|
/* No PNG support */
|
||
|
return false;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
bool loadTGA(const TCHAR *filename, STGA& tgaFile)
|
||
|
{
|
||
|
FILE *file;
|
||
|
unsigned char type[4];
|
||
|
unsigned char info[6];
|
||
|
|
||
|
file = _tfopen(filename, TEXT("rb"));
|
||
|
|
||
|
if (!file)
|
||
|
return false;
|
||
|
|
||
|
fread(&type, sizeof(char), 3, file);
|
||
|
fseek(file, 12, SEEK_SET);
|
||
|
fread(&info, sizeof(char), 6, file);
|
||
|
|
||
|
//image type either 2 (color) or 3 (greyscale)
|
||
|
if (type[1] != 0 || (type[2] != 2 && type[2] != 3))
|
||
|
{
|
||
|
fclose(file);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
tgaFile.width = info[0] + info[1] * 256;
|
||
|
tgaFile.height = info[2] + info[3] * 256;
|
||
|
tgaFile.byteCount = info[4] / 8;
|
||
|
|
||
|
if (tgaFile.byteCount != 3 && tgaFile.byteCount != 4) {
|
||
|
fclose(file);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
long imageSize = tgaFile.width * tgaFile.height * tgaFile.byteCount;
|
||
|
|
||
|
//allocate memory for image data
|
||
|
unsigned char *tempBuf = new unsigned char[imageSize];
|
||
|
tgaFile.data = new unsigned char[tgaFile.width * tgaFile.height * 4];
|
||
|
|
||
|
//read in image data
|
||
|
fread(tempBuf, sizeof(unsigned char), imageSize, file);
|
||
|
|
||
|
//swap line order and convert to RBGA
|
||
|
for (int i = 0; i<tgaFile.height; i++) {
|
||
|
unsigned char* source = tempBuf + tgaFile.width * (tgaFile.height - 1 - i) * tgaFile.byteCount;
|
||
|
unsigned char* destination = tgaFile.data + tgaFile.width * i * 4;
|
||
|
for (int j = 0; j<tgaFile.width; j++) {
|
||
|
destination[0] = source[2];
|
||
|
destination[1] = source[1];
|
||
|
destination[2] = source[0];
|
||
|
destination[3] = tgaFile.byteCount == 4 ? source[3] : 0xff;
|
||
|
source += tgaFile.byteCount;
|
||
|
destination += 4;
|
||
|
}
|
||
|
}
|
||
|
delete[] tempBuf;
|
||
|
tgaFile.byteCount = 4;
|
||
|
|
||
|
//close file
|
||
|
fclose(file);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool d3d_create_texture_from_file(LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DTEXTURE9 *ppTexture)
|
||
|
{
|
||
|
int strLen = lstrlen(pSrcFile);
|
||
|
if (strLen<5)
|
||
|
return false;
|
||
|
|
||
|
int width, height;
|
||
|
bool hasAlpha = false, needFree = false;
|
||
|
STGA stga;
|
||
|
unsigned char *bytes;
|
||
|
|
||
|
if (!_tcsicmp(&pSrcFile[strLen - 4], TEXT(".png"))) {
|
||
|
if (!loadPngImage(pSrcFile, width, height, hasAlpha, &bytes))
|
||
|
return false;
|
||
|
|
||
|
needFree = true;
|
||
|
}
|
||
|
else if (!_tcsicmp(&pSrcFile[strLen - 4], TEXT(".tga"))) {
|
||
|
if (!loadTGA(pSrcFile, stga))
|
||
|
return false;
|
||
|
|
||
|
width = stga.width;
|
||
|
height = stga.height;
|
||
|
bytes = stga.data;
|
||
|
hasAlpha = true;
|
||
|
}
|
||
|
|
||
|
bool ret = false;
|
||
|
HRESULT hr = pDevice->CreateTexture(width, height, 1, 0, hasAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, ppTexture, NULL);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
LPDIRECT3DTEXTURE9 pTexture = *ppTexture;
|
||
|
D3DLOCKED_RECT lr;
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (FAILED(hr = pTexture->LockRect(0, &lr, NULL, 0))) {
|
||
|
pTexture->Release();
|
||
|
DXTRACE_ERR_MSGBOX(TEXT("Unable to lock texture"), hr);
|
||
|
}
|
||
|
else {
|
||
|
memcpy(lr.pBits, bytes, lr.Pitch * height);
|
||
|
pTexture->UnlockRect(0);
|
||
|
ret = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (needFree)
|
||
|
free(bytes);
|
||
|
|
||
|
return ret;
|
||
|
}
|