/*****************************************************************************\ 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. \*****************************************************************************/ #include #include #include #include "shader_helpers.h" #include "shader_platform.h" static void gl_error_callback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam ) { if (type== GL_DEBUG_TYPE_ERROR) { fprintf( stderr, "GL: %s type = 0x%x, severity = 0x%x, \n %s\n", (type == GL_DEBUG_TYPE_ERROR ? "*ERROR*" : ""), type, severity, message ); } else { fprintf( stderr, "GL type = 0x%x, severity = 0x%x, \n %s\n", type, severity, message); } return; } bool gl_version_at_least (int maj, int min) { static int major_version = -1; static int minor_version = -1; if (major_version < 0 || minor_version < 0) { const char *version_string = (const char *) glGetString (GL_VERSION); sscanf (version_string, "%d.%d", &major_version, &minor_version); } if (major_version > maj) return true; if (maj == major_version && minor_version >= min) return true; return false; } bool srgb_available (void) { if (gl_version_at_least (3, 0)) return true; const char *extensions = (const char *) glGetString (GL_EXTENSIONS); if (strstr (extensions, "texture_sRGB") && strstr (extensions, "framebuffer_sRGB")) return true; return false; } bool float_texture_available (void) { if (gl_version_at_least (3, 2)) return true; const char *extensions = (const char *) glGetString (GL_EXTENSIONS); if (strstr (extensions, "texture_float")) return true; return false; } void glLogErrors (void) { glEnable (GL_DEBUG_OUTPUT); glDebugMessageCallback ((GLDEBUGPROC) gl_error_callback, 0); } bool loadPngImage(const char* name, int& outWidth, int& outHeight, bool& outHasAlpha, GLubyte** outData) { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; FILE* fp; if ((fp = fopen(name, "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; } bool loadTGA(const char* filename, STGA& tgaFile) { FILE* file; 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) 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; }