snes9x/shaders/shader_helpers.cpp

246 lines
6.1 KiB
C++
Raw Normal View History

/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
2018-05-11 01:47:55 +02:00
#include <png.h>
#include <stdlib.h>
#include <string.h>
#include "shader_helpers.h"
#include "shader_platform.h"
2018-05-11 01:47:55 +02:00
2019-01-09 00:18:17 +01:00
static void gl_error_callback(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar *message, const void *userParam)
2018-05-11 01:47:55 +02:00
{
2019-01-09 00:18:17 +01:00
if (type == GL_DEBUG_TYPE_ERROR)
2018-05-11 01:47:55 +02:00
{
2019-01-09 00:18:17 +01:00
fprintf(stderr, "GL: %s type = 0x%x, severity = 0x%x, \n %s\n",
(type == GL_DEBUG_TYPE_ERROR ? "*ERROR*" : ""), type, severity,
message);
2018-05-11 01:47:55 +02:00
}
else
{
2019-01-09 00:18:17 +01:00
fprintf(stderr, "GL type = 0x%x, severity = 0x%x, \n %s\n", type,
severity, message);
2018-05-11 01:47:55 +02:00
}
return;
}
2019-01-09 02:43:51 +01:00
int gl_version()
{
2019-01-09 00:18:17 +01:00
static int version = -1;
2019-01-09 00:18:17 +01:00
if (version < 0)
{
2019-01-09 00:18:17 +01:00
const char *version_string = (const char *)glGetString(GL_VERSION);
static int major_version = 1;
static int minor_version = 0;
2019-01-09 00:18:17 +01:00
sscanf(version_string, "%d.%d", &major_version, &minor_version);
version = major_version * 10 + minor_version;
}
2019-01-09 00:18:17 +01:00
return version;
}
2019-01-09 00:18:17 +01:00
bool gl_srgb_available(void)
{
2019-01-09 00:18:17 +01:00
if (gl_version() >= 30)
return true;
2019-01-09 00:18:17 +01:00
const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
2019-01-09 00:18:17 +01:00
if (strstr(extensions, "texture_sRGB") &&
strstr(extensions, "framebuffer_sRGB"))
return true;
return false;
}
2019-01-09 00:18:17 +01:00
bool gl_float_texture_available(void)
{
2019-01-09 00:18:17 +01:00
if (gl_version() >= 32)
return true;
2019-01-09 00:18:17 +01:00
const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
2019-01-09 00:18:17 +01:00
if (strstr(extensions, "texture_float"))
return true;
return false;
}
2019-01-09 00:18:17 +01:00
void gl_log_errors(void)
2018-05-11 01:47:55 +02:00
{
2019-01-09 00:18:17 +01:00
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback((GLDEBUGPROC)gl_error_callback, 0);
2018-05-11 01:47:55 +02:00
}
2019-01-09 00:18:17 +01:00
bool loadPngImage(const char *name, int &outWidth, int &outHeight,
bool &grayscale, bool &outHasAlpha, GLubyte **outData)
2018-05-11 01:47:55 +02:00
{
#ifdef HAVE_LIBPNG
2018-05-11 01:47:55 +02:00
png_structp png_ptr;
png_infop info_ptr;
unsigned int sig_read = 0;
2019-01-09 00:18:17 +01:00
FILE *fp;
2018-05-11 01:47:55 +02:00
if ((fp = fopen(name, "rb")) == NULL)
return false;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
2019-01-09 00:18:17 +01:00
if (png_ptr == NULL)
{
2018-05-11 01:47:55 +02:00
fclose(fp);
return false;
}
info_ptr = png_create_info_struct(png_ptr);
2019-01-09 00:18:17 +01:00
if (info_ptr == NULL)
{
2018-05-11 01:47:55 +02:00
fclose(fp);
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
return false;
}
2019-01-09 00:18:17 +01:00
if (setjmp(png_jmpbuf(png_ptr)))
{
2018-05-11 01:47:55 +02:00
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fclose(fp);
return false;
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, sig_read);
2019-01-09 00:18:17 +01:00
png_read_png(png_ptr, info_ptr,
PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING |
PNG_TRANSFORM_EXPAND,
(png_voidp)NULL);
2018-05-11 01:47:55 +02:00
outWidth = png_get_image_width(png_ptr, info_ptr);
outHeight = png_get_image_height(png_ptr, info_ptr);
2019-01-09 00:18:17 +01:00
switch (png_get_color_type(png_ptr, info_ptr))
{
2018-05-11 01:47:55 +02:00
case PNG_COLOR_TYPE_RGBA:
outHasAlpha = true;
grayscale = false;
2018-05-11 01:47:55 +02:00
break;
case PNG_COLOR_TYPE_RGB:
outHasAlpha = false;
grayscale = false;
break;
case PNG_COLOR_TYPE_GRAY:
grayscale = true;
2018-05-11 01:47:55 +02:00
break;
default:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
return false;
}
2019-01-09 00:18:17 +01:00
2018-05-11 01:47:55 +02:00
unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr);
2019-01-09 00:18:17 +01:00
*outData = (unsigned char *)malloc(row_bytes * outHeight);
2018-05-11 01:47:55 +02:00
png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
2019-01-09 00:18:17 +01:00
for (int i = 0; i < outHeight; i++)
{
2018-05-11 01:47:55 +02:00
memcpy(*outData + (row_bytes * i), row_pointers[i], row_bytes);
}
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fclose(fp);
return true;
#else
return false;
#endif
2018-05-11 01:47:55 +02:00
}
2019-01-09 00:18:17 +01:00
bool loadTGA(const char *filename, STGA &tgaFile)
2018-05-11 01:47:55 +02:00
{
2019-01-09 00:18:17 +01:00
FILE *file;
2018-05-11 01:47:55 +02:00
unsigned char type[4];
unsigned char info[6];
file = fopen(filename, "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)
2019-01-09 00:18:17 +01:00
if (type[1] != 0 || (type[2] != 2 && type[2] != 3))
{
2018-05-11 01:47:55 +02:00
fclose(file);
return false;
}
tgaFile.width = info[0] + info[1] * 256;
tgaFile.height = info[2] + info[3] * 256;
tgaFile.byteCount = info[4] / 8;
2019-01-09 00:18:17 +01:00
if (tgaFile.byteCount != 3 && tgaFile.byteCount != 4)
{
2018-05-11 01:47:55 +02:00
fclose(file);
return false;
}
long imageSize = tgaFile.width * tgaFile.height * tgaFile.byteCount;
2019-01-09 00:18:17 +01:00
unsigned char *tempBuf = new unsigned char[imageSize];
2018-05-11 01:47:55 +02:00
tgaFile.data = new unsigned char[tgaFile.width * tgaFile.height * 4];
fread(tempBuf, sizeof(unsigned char), imageSize, file);
2019-01-13 18:39:54 +01:00
// swap line order and convert to RGBA
2019-01-09 00:18:17 +01:00
for (int i = 0; i < tgaFile.height; i++)
{
unsigned char *source = tempBuf + tgaFile.width *
2019-01-13 18:39:54 +01:00
(tgaFile.height - 1 - i) *
tgaFile.byteCount;
2019-01-09 00:18:17 +01:00
unsigned char *destination = tgaFile.data + tgaFile.width * i * 4;
for (int j = 0; j < tgaFile.width; j++)
{
2018-05-11 01:47:55 +02:00
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;
fclose(file);
return true;
}
2019-01-13 18:39:54 +01:00
void reduce_to_path(char *filename)
{
for (int i = strlen(filename); i >= 0; i--)
{
if (filename[i] == '\\' || filename[i] == '/')
{
filename[i] = 0;
break;
}
}
}