Fixed sound thread issues in Subversion

Updated SDL port so that it now compiles with fex_mini.cpp
Added custom GLSL shader support to Win32 OGL renderer (requires GLEW)
Updated code in OpenGL renderer to be more tidy
This commit is contained in:
mudlord 2007-12-13 03:45:51 +00:00
parent 98079e809a
commit 4fff47a824
12 changed files with 590 additions and 466 deletions

View File

@ -50,9 +50,9 @@ ${MAINDIR}/hq2x${OE} ${MAINDIR}/GBA-thumb${OE} ${MAINDIR}/GBA-arm${OE} ${MAINDIR
${MAINDIR}/Mode1${OE} ${MAINDIR}/Mode2${OE} ${MAINDIR}/Mode3${OE} ${MAINDIR}/Mode4${OE} \
${MAINDIR}/Mode5${OE} ${MAINDIR}/motionblur${OE} ${MAINDIR}/pixel${OE} ${MAINDIR}/portable${OE} \
${MAINDIR}/remote${OE} ${MAINDIR}/RTC${OE} ${MAINDIR}/scanline${OE} ${MAINDIR}/simpleFilter${OE} \
${MAINDIR}/snd_interp${OE} ${MAINDIR}/Sound${OE} ${MAINDIR}/Sram${OE} ${MAINDIR}/Text${OE} \
${MAINDIR}/fex_mini${OE} ${MAINDIR}/Sound${OE} ${MAINDIR}/Sram${OE} ${MAINDIR}/Text${OE} \
${MAINDIR}/unzip${OE} ${MAINDIR}/Util${OE} ${MAINDIR}/exprNode${OE} ${MAINDIR}/getopt${OE} \
${MAINDIR}/getopt1${OE} ${MAINDIR}/memgzio${OE} ${MAINDIR}/expr-lex${OE} ${MAINDIR}/expr${OE}
${MAINDIR}/getopt1${OE} ${MAINDIR}/memgzio${OE} ${MAINDIR}/expr-lex${OE} ${MAINDIR}/expr${OE} \
DMGOBJ=${DMGDIR}/GB${OE} ${DMGDIR}/gbCheats${OE} ${DMGDIR}/gbDis${OE} ${DMGDIR}/gbGfx${OE} \
${DMGDIR}/gbGlobals${OE} ${DMGDIR}/gbMemory${OE} ${DMGDIR}/gbPrinter${OE} ${DMGDIR}/gbSGB${OE} \

280
src/fex.h
View File

@ -1,140 +1,140 @@
/* Compressed file archive C interface (also usable from C++) */
/* File_Extractor 0.4.3 */
#ifndef FEX_H
#define FEX_H
#ifdef __cplusplus
extern "C" {
#endif
/* Error string returned by library functions, or NULL if no error (success).
If function takes fex_err_t* err_out, it sets *err_out to NULL on success,
otherwise error string, or you can pass NULL if you don't care about exact
cause of error (these functions still report error by returning NULL). */
typedef const char* fex_err_t;
/* First parameter of most extractor_ functions is a pointer to the
File_Extractor being acted on. */
typedef struct File_Extractor File_Extractor;
/**** Basics ****/
/* Opens archive and returns pointer to it, or NULL if error. */
File_Extractor* fex_open( const char* path, fex_err_t* err_out );
/* True if at end of archive. */
int fex_done( File_Extractor const* );
/* Name of current file. */
const char* fex_name( File_Extractor const* );
/* Size of current file. */
long fex_size( File_Extractor const* );
/* Extracts n bytes and writes them to *out. Returns error if all n
bytes couldn't be extracted (due to end of file or read error). */
fex_err_t fex_read( File_Extractor*, void* out, long n );
/* Goes to next file in archive (skips directories). */
fex_err_t fex_next( File_Extractor* );
/* Closes archive and frees memory. */
void fex_close( File_Extractor* );
/**** Advanced ****/
/* Goes back to first file in archive. */
fex_err_t fex_rewind( File_Extractor* );
/* Hints to fex_next() that no file extraction will occur, speeding scanning
of some archive types. */
void fex_scan_only( File_Extractor* );
/* Modification date of current file (MS-DOS format). */
unsigned long fex_dos_date( File_Extractor const* );
/* Number of bytes remaining to be read from current file. */
long fex_remain( File_Extractor const* );
/* Reads at most n bytes and returns number actually read, or negative if error. */
long fex_read_avail( File_Extractor*, void* out, long n );
/* Extracts first n bytes and ignores rest. Faster than a normal read since it
doesn't need to read any more data. Must not be called twice in a row. */
fex_err_t fex_read_once( File_Extractor*, void* out, long n );
/* Loads file data into memory (if not already) and returns pointer to it, or
NULL if error. Pointer is valid until fex_next(), fex_rewind(), or fex_close() are
called. Will return same pointer if called more than once. */
const unsigned char* fex_data( File_Extractor*, fex_err_t* err_out );
/**** Archive types ****/
/* fex_type_t is a pointer to this structure. For example, fex_zip_type->extension is
"ZIP" and ex_zip_type->new_fex() is equilvant to 'new Zip_Extractor' (in C++). */
struct fex_type_t_
{
const char* extension; /* file extension/type */
File_Extractor* (*new_fex)();
};
/* Archive type constants for each supported file type */
extern struct fex_type_t_ const
fex_7z_type [1], /* .7z (7-zip) */
fex_gz_type [1], /* .gz (gzip) */
/*fex_rar_type [1],*/ /* .rar */
fex_zip_type [1], /* .zip */
fex_bin_type [1]; /* binary file, possibly gzipped */
typedef struct fex_type_t_ const* fex_type_t;
/* Array of supported archive types, with NULL entry at end. */
fex_type_t const* fex_type_list();
/* Type of archive this extractor handles. */
fex_type_t fex_type( File_Extractor const* );
/******** Advanced opening ********/
/* Error returned if file is wrong type */
extern const char fex_wrong_file_type [29];
/* Determines likely archive type based on first four bytes of file. Returns string
containing proper file suffix (i.e. "ZIP", "GZ", etc.) or "" (empty string) if file
header is not recognized. */
const char* fex_identify_header( void const* header );
/* Gets corresponding archive type for file path or extension passed in. Returns NULL
if type isn't recognized. */
fex_type_t fex_identify_extension( const char* path_or_extension );
/* Determines file type based on filename extension, or file header (if extension
isn't recognized). Returns NULL if unrecognized or error. */
fex_type_t fex_identify_file( const char* path, fex_err_t* err_out );
/* Opens archive of specific type and returns pointer to it, or NULL if error. */
File_Extractor* fex_open_type( fex_type_t, const char* path, fex_err_t* err_out );
/******** User data ********/
/* Sets/gets pointer to data you want to associate with this extractor.
You can use this for whatever you want. */
void fex_set_user_data( File_Extractor*, void* new_user_data );
void* fex_user_data( File_Extractor const* );
/* Registers cleanup function to be called when closing extractor, or NULL to
clear it. Passes user_data (see above) to cleanup function. */
typedef void (*fex_user_cleanup_t)( void* user_data );
void fex_set_user_cleanup( File_Extractor*, fex_user_cleanup_t func );
#ifdef __cplusplus
}
#endif
#endif
/* Compressed file archive C interface (also usable from C++) */
/* File_Extractor 0.4.3 */
#ifndef FEX_H
#define FEX_H
#ifdef __cplusplus
extern "C" {
#endif
/* Error string returned by library functions, or NULL if no error (success).
If function takes fex_err_t* err_out, it sets *err_out to NULL on success,
otherwise error string, or you can pass NULL if you don't care about exact
cause of error (these functions still report error by returning NULL). */
typedef const char* fex_err_t;
/* First parameter of most extractor_ functions is a pointer to the
File_Extractor being acted on. */
typedef struct File_Extractor File_Extractor;
/**** Basics ****/
/* Opens archive and returns pointer to it, or NULL if error. */
File_Extractor* fex_open( const char* path, fex_err_t* err_out );
/* True if at end of archive. */
int fex_done( File_Extractor const* );
/* Name of current file. */
const char* fex_name( File_Extractor* );
/* Size of current file. */
long fex_size( File_Extractor const* );
/* Extracts n bytes and writes them to *out. Returns error if all n
bytes couldn't be extracted (due to end of file or read error). */
fex_err_t fex_read( File_Extractor*, void* out, long n );
/* Goes to next file in archive (skips directories). */
fex_err_t fex_next( File_Extractor* );
/* Closes archive and frees memory. */
void fex_close( File_Extractor* );
/**** Advanced ****/
/* Goes back to first file in archive. */
fex_err_t fex_rewind( File_Extractor* );
/* Hints to fex_next() that no file extraction will occur, speeding scanning
of some archive types. */
void fex_scan_only( File_Extractor* );
/* Modification date of current file (MS-DOS format). */
unsigned long fex_dos_date( File_Extractor const* );
/* Number of bytes remaining to be read from current file. */
long fex_remain( File_Extractor const* );
/* Reads at most n bytes and returns number actually read, or negative if error. */
long fex_read_avail( File_Extractor*, void* out, long n );
/* Extracts first n bytes and ignores rest. Faster than a normal read since it
doesn't need to read any more data. Must not be called twice in a row. */
fex_err_t fex_read_once( File_Extractor*, void* out, long n );
/* Loads file data into memory (if not already) and returns pointer to it, or
NULL if error. Pointer is valid until fex_next(), fex_rewind(), or fex_close() are
called. Will return same pointer if called more than once. */
const unsigned char* fex_data( File_Extractor*, fex_err_t* err_out );
/**** Archive types ****/
/* fex_type_t is a pointer to this structure. For example, fex_zip_type->extension is
"ZIP" and ex_zip_type->new_fex() is equilvant to 'new Zip_Extractor' (in C++). */
struct fex_type_t_
{
const char* extension; /* file extension/type */
File_Extractor* (*new_fex)();
};
/* Archive type constants for each supported file type */
extern struct fex_type_t_ const
fex_7z_type [1], /* .7z (7-zip) */
fex_gz_type [1], /* .gz (gzip) */
/*fex_rar_type [1],*/ /* .rar */
fex_zip_type [1], /* .zip */
fex_bin_type [1]; /* binary file, possibly gzipped */
typedef struct fex_type_t_ const* fex_type_t;
/* Array of supported archive types, with NULL entry at end. */
fex_type_t const* fex_type_list();
/* Type of archive this extractor handles. */
fex_type_t fex_type( File_Extractor const* );
/******** Advanced opening ********/
/* Error returned if file is wrong type */
extern const char fex_wrong_file_type [29];
/* Determines likely archive type based on first four bytes of file. Returns string
containing proper file suffix (i.e. "ZIP", "GZ", etc.) or "" (empty string) if file
header is not recognized. */
const char* fex_identify_header( void const* header );
/* Gets corresponding archive type for file path or extension passed in. Returns NULL
if type isn't recognized. */
fex_type_t fex_identify_extension( const char* path_or_extension );
/* Determines file type based on filename extension, or file header (if extension
isn't recognized). Returns NULL if unrecognized or error. */
fex_type_t fex_identify_file( const char* path, fex_err_t* err_out );
/* Opens archive of specific type and returns pointer to it, or NULL if error. */
File_Extractor* fex_open_type( fex_type_t, const char* path, fex_err_t* err_out );
/******** User data ********/
/* Sets/gets pointer to data you want to associate with this extractor.
You can use this for whatever you want. */
void fex_set_user_data( File_Extractor*, void* new_user_data );
void* fex_user_data( File_Extractor const* );
/* Registers cleanup function to be called when closing extractor, or NULL to
clear it. Passes user_data (see above) to cleanup function. */
typedef void (*fex_user_cleanup_t)( void* user_data );
void fex_set_user_cleanup( File_Extractor*, fex_user_cleanup_t func );
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,222 +1,222 @@
// Minimal implementation of fex.h. Supports gzipped files if you have zlib
// available and HAVE_ZLIB_H is defined.
// File_Extractor 0.4.3. http://www.slack.net/~ant/
#include "fex.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* Copyright (C) 2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef HAVE_ZLIB_H
#define FILE_GZ( norm, gz ) norm
#define FILE_READ( ptr, size, file ) fread( ptr, 1, size, file )
#else
#define FILE_GZ( norm, gz ) gz
#define FILE_READ( ptr, size, file ) gzread( file, ptr, size )
#include "zlib.h"
static const char* get_gzip_size( const char* path, long* eof )
{
FILE* file = fopen( path, "rb" );
if ( !file )
return "Couldn't open file";
unsigned char buf [4];
if ( fread( buf, 2, 1, file ) > 0 && buf [0] == 0x1F && buf [1] == 0x8B )
{
fseek( file, -4, SEEK_END );
fread( buf, 4, 1, file );
*eof = buf [3] * 0x1000000 + buf [2] * 0x10000 + buf [1] * 0x100 + buf [0];
}
else
{
fseek( file, 0, SEEK_END );
*eof = ftell( file );
}
const char* err = (ferror( file ) || feof( file )) ? "Couldn't get file size" : 0;
fclose( file );
return err;
}
#endif
const char fex_wrong_file_type [] = "Archive format not supported";
struct File_Extractor
{
FILE_GZ(FILE*,gzFile) file;
int done;
long size;
void* data; // file data read into memory, ot 0 if not read
void* user_data;
fex_user_cleanup_t user_cleanup;
char* name() { return (char*) (this + 1); }
};
// Always identify as single file extractor
fex_type_t_ const fex_bin_type [1] = {{ "" , 0 }};
const char* fex_identify_header ( void const* ) { return ""; }
fex_type_t fex_identify_extension( const char* ) { return fex_bin_type; }
fex_type_t fex_identify_file ( const char*, fex_err_t* e ) { if ( e ) *e = 0; return fex_bin_type; }
static fex_err_t fex_open_( const char* path, File_Extractor** fe_out )
{
*fe_out = 0;
// name
const char* name = strrchr( path, '\\' ); // DOS
if ( !name )
name = strrchr( path, '/' ); // UNIX
if ( !name )
name = strrchr( path, ':' ); // Mac
if ( !name )
name = path;
// allocate space for struct and name
long name_size = strlen( name ) + 1;
File_Extractor* fe = (File_Extractor*) malloc( sizeof (File_Extractor) + name_size );
if ( !fe ) return "Out of memory";
fe->done = 0;
fe->data = 0;
fe->user_data = 0;
fe->user_cleanup = 0;
memcpy( fe->name(), name, name_size );
#ifdef HAVE_ZLIB_H
// get gzip size BEFORE opening file
const char* err = get_gzip_size( path, &fe->size );
if ( err )
{
free( fe );
return err;
}
#endif
// open file
fe->file = FILE_GZ(fopen,gzopen)( path, "rb" );
if ( !fe->file )
{
free( fe );
return "Couldn't open file";
}
// get normal size
#ifndef HAVE_ZLIB_H
fseek( fe->file, 0, SEEK_END );
fe->size = ftell( fe->file );
rewind( fe->file );
#endif
*fe_out = fe;
return 0;
}
File_Extractor* fex_open( const char* path, fex_err_t* err_out )
{
File_Extractor* fe;
fex_err_t err = fex_open_( path, &fe );
if ( err_out )
*err_out = err;
return fe;
}
File_Extractor* fex_open_type( fex_type_t, const char* path, fex_err_t* err_out )
{
return fex_open( path, err_out );
}
void* fex_user_data ( File_Extractor const* fe ) { return fe->user_data; }
void fex_set_user_data ( File_Extractor* fe, void* new_user_data ) { fe->user_data = new_user_data; }
void fex_set_user_cleanup ( File_Extractor* fe, fex_user_cleanup_t func ) { fe->user_cleanup = func; }
fex_type_t fex_type ( File_Extractor const* ) { return fex_bin_type; }
int fex_done ( File_Extractor const* fe ) { return fe->done; }
const char* fex_name ( File_Extractor const* fe ) { return fe->name(); }
unsigned long fex_dos_date ( File_Extractor const* ) { return 0; }
long fex_size ( File_Extractor const* fe ) { return fe->size; }
long fex_remain ( File_Extractor const* fe ) { return fe->size - FILE_GZ(ftell,gztell)( fe->file ); }
void fex_scan_only ( File_Extractor* ) { }
fex_err_t fex_read_once ( File_Extractor* fe, void* out, long count ) { return fex_read( fe, out, count ); }
long fex_read_avail ( File_Extractor* fe, void* out, long count ) { return FILE_READ( out, count, fe->file ); }
fex_err_t fex_read( File_Extractor* fe, void* out, long count )
{
if ( count == (long) FILE_READ( out, count, fe->file ) )
return 0;
if ( FILE_GZ(feof,gzeof)( fe->file ) )
return "Unexpected end of file";
return "Couldn't read from file";
}
fex_err_t fex_next( File_Extractor* fe )
{
fe->done = 1;
return 0;
}
fex_err_t fex_rewind( File_Extractor* fe )
{
fe->done = 0;
FILE_GZ(rewind,gzrewind)( fe->file );
return 0;
}
static fex_err_t fex_data_( File_Extractor* fe )
{
if ( !fe->data )
{
fe->data = malloc( fe->size );
if ( !fe->data ) return "Out of memory";
fex_err_t err = fex_read( fe, fe->data, fe->size );
if ( err )
{
free( fe->data );
return err;
}
}
return 0;
}
const unsigned char* fex_data( File_Extractor* fe, fex_err_t* err_out )
{
fex_err_t err = fex_data_( fe );
if ( err_out )
*err_out = err;
return (const unsigned char*) fe->data;
}
void fex_close( File_Extractor* fe )
{
if ( fe )
{
free( fe->data );
FILE_GZ(fclose,gzclose)( fe->file );
if ( fe->user_cleanup )
fe->user_cleanup( fe->user_data );
free( fe );
}
}
// Minimal implementation of fex.h. Supports gzipped files if you have zlib
// available and HAVE_ZLIB_H is defined.
// File_Extractor 0.4.3. http://www.slack.net/~ant/
#include "fex.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* Copyright (C) 2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef HAVE_ZLIB_H
#define FILE_GZ( norm, gz ) norm
#define FILE_READ( ptr, size, file ) fread( ptr, 1, size, file )
#else
#define FILE_GZ( norm, gz ) gz
#define FILE_READ( ptr, size, file ) gzread( file, ptr, size )
#include "zlib.h"
static const char* get_gzip_size( const char* path, long* eof )
{
FILE* file = fopen( path, "rb" );
if ( !file )
return "Couldn't open file";
unsigned char buf [4];
if ( fread( buf, 2, 1, file ) > 0 && buf [0] == 0x1F && buf [1] == 0x8B )
{
fseek( file, -4, SEEK_END );
fread( buf, 4, 1, file );
*eof = buf [3] * 0x1000000 + buf [2] * 0x10000 + buf [1] * 0x100 + buf [0];
}
else
{
fseek( file, 0, SEEK_END );
*eof = ftell( file );
}
const char* err = (ferror( file ) || feof( file )) ? "Couldn't get file size" : 0;
fclose( file );
return err;
}
#endif
const char fex_wrong_file_type [] = "Archive format not supported";
struct File_Extractor
{
FILE_GZ(FILE*,gzFile) file;
int done;
long size;
void* data; // file data read into memory, ot 0 if not read
void* user_data;
fex_user_cleanup_t user_cleanup;
char* name() { return (char*) (this + 1); }
};
// Always identify as single file extractor
fex_type_t_ const fex_bin_type [1] = {{ "" , 0 }};
const char* fex_identify_header ( void const* ) { return ""; }
fex_type_t fex_identify_extension( const char* ) { return fex_bin_type; }
fex_type_t fex_identify_file ( const char*, fex_err_t* e ) { if ( e ) *e = 0; return fex_bin_type; }
static fex_err_t fex_open_( const char* path, File_Extractor** fe_out )
{
*fe_out = 0;
// name
const char* name = strrchr( path, '\\' ); // DOS
if ( !name )
name = strrchr( path, '/' ); // UNIX
if ( !name )
name = strrchr( path, ':' ); // Mac
if ( !name )
name = path;
// allocate space for struct and name
long name_size = strlen( name ) + 1;
File_Extractor* fe = (File_Extractor*) malloc( sizeof (File_Extractor) + name_size );
if ( !fe ) return "Out of memory";
fe->done = 0;
fe->data = 0;
fe->user_data = 0;
fe->user_cleanup = 0;
memcpy( fe->name(), name, name_size );
#ifdef HAVE_ZLIB_H
// get gzip size BEFORE opening file
const char* err = get_gzip_size( path, &fe->size );
if ( err )
{
free( fe );
return err;
}
#endif
// open file
fe->file = FILE_GZ(fopen,gzopen)( path, "rb" );
if ( !fe->file )
{
free( fe );
return "Couldn't open file";
}
// get normal size
#ifndef HAVE_ZLIB_H
fseek( fe->file, 0, SEEK_END );
fe->size = ftell( fe->file );
rewind( fe->file );
#endif
*fe_out = fe;
return 0;
}
File_Extractor* fex_open( const char* path, fex_err_t* err_out )
{
File_Extractor* fe;
fex_err_t err = fex_open_( path, &fe );
if ( err_out )
*err_out = err;
return fe;
}
File_Extractor* fex_open_type( fex_type_t, const char* path, fex_err_t* err_out )
{
return fex_open( path, err_out );
}
void* fex_user_data ( File_Extractor const* fe ) { return fe->user_data; }
void fex_set_user_data ( File_Extractor* fe, void* new_user_data ) { fe->user_data = new_user_data; }
void fex_set_user_cleanup ( File_Extractor* fe, fex_user_cleanup_t func ) { fe->user_cleanup = func; }
fex_type_t fex_type ( File_Extractor const* ) { return fex_bin_type; }
int fex_done ( File_Extractor const* fe ) { return fe->done; }
const char* fex_name ( File_Extractor* fe ) { return fe->name(); }
unsigned long fex_dos_date ( File_Extractor const* ) { return 0; }
long fex_size ( File_Extractor const* fe ) { return fe->size; }
long fex_remain ( File_Extractor const* fe ) { return fe->size - FILE_GZ(ftell,gztell)( fe->file ); }
void fex_scan_only ( File_Extractor* ) { }
fex_err_t fex_read_once ( File_Extractor* fe, void* out, long count ) { return fex_read( fe, out, count ); }
long fex_read_avail ( File_Extractor* fe, void* out, long count ) { return FILE_READ( out, count, fe->file ); }
fex_err_t fex_read( File_Extractor* fe, void* out, long count )
{
if ( count == (long) FILE_READ( out, count, fe->file ) )
return 0;
if ( FILE_GZ(feof,gzeof)( fe->file ) )
return "Unexpected end of file";
return "Couldn't read from file";
}
fex_err_t fex_next( File_Extractor* fe )
{
fe->done = 1;
return 0;
}
fex_err_t fex_rewind( File_Extractor* fe )
{
fe->done = 0;
FILE_GZ(rewind,gzrewind)( fe->file );
return 0;
}
static fex_err_t fex_data_( File_Extractor* fe )
{
if ( !fe->data )
{
fe->data = malloc( fe->size );
if ( !fe->data ) return "Out of memory";
fex_err_t err = fex_read( fe, fe->data, fe->size );
if ( err )
{
free( fe->data );
return err;
}
}
return 0;
}
const unsigned char* fex_data( File_Extractor* fe, fex_err_t* err_out )
{
fex_err_t err = fex_data_( fe );
if ( err_out )
*err_out = err;
return (const unsigned char*) fe->data;
}
void fex_close( File_Extractor* fe )
{
if ( fe )
{
free( fe->data );
FILE_GZ(fclose,gzclose)( fe->file );
if ( fe->user_cleanup )
fe->user_cleanup( fe->user_data );
free( fe );
}
}

View File

@ -285,11 +285,32 @@ char screenMessageBuffer[21];
u32 screenMessageTime = 0;
// Patch #1382692 by deathpudding.
SDL_sem *sdlBufferLock = NULL;
SDL_sem *sdlBufferFull = NULL;
SDL_sem *sdlBufferEmpty = NULL;
u8 sdlBuffer[4096];
int sdlSoundLen = 0;
const int sdlSoundSamples = 2048;
const int sdlSoundAlign = 4;
const int sdlSoundCapacity = sdlSoundSamples * 2;
const int sdlSoundTotalLen = sdlSoundCapacity + sdlSoundAlign;
static u8 sdlSoundBuffer[sdlSoundTotalLen];
static int sdlSoundRPos;
static int sdlSoundWPos;
static SDL_cond *sdlSoundCond;
static SDL_mutex *sdlSoundMutex;
static inline int soundBufferFree()
{
int ret = sdlSoundRPos - sdlSoundWPos - sdlSoundAlign;
if (ret < 0)
ret += sdlSoundTotalLen;
return ret;
}
static inline int soundBufferUsed()
{
int ret = sdlSoundWPos - sdlSoundRPos;
if (ret < 0)
ret += sdlSoundTotalLen;
return ret;
}
char *arg0;
@ -2078,6 +2099,8 @@ int main(int argc, char **argv)
"FNO:T:Y:G:D:b:c:df:hi:p::s:t:v:1234",
sdlOptions,
NULL)) != -1) {
if (optarg)
optarg++;
switch(op) {
case 0:
// long option already processed by getopt_long
@ -3139,73 +3162,71 @@ void systemScreenCapture(int a)
systemScreenMessage("Screen capture");
}
void soundCallback(void *,u8 *stream,int len)
static void soundCallback(void *,u8 *stream,int len)
{
if (!emulating)
return;
if (len <= 0 || !emulating)
return;
// Patch #1382692 by deathpudding.
/* since this is running in a different thread, speedup and
* throttle can change at any time; save the value so locks
* stay in sync */
bool lock = (!speedup && !throttle) ? true : false;
if (lock)
SDL_SemWait (sdlBufferFull);
SDL_SemWait (sdlBufferLock);
memcpy (stream, sdlBuffer, len);
sdlSoundLen = 0;
SDL_SemPost (sdlBufferLock);
if (lock)
SDL_SemPost (sdlBufferEmpty);
SDL_mutexP(sdlSoundMutex);
const int nAvail = soundBufferUsed();
if (len > nAvail)
len = nAvail;
const int nAvail2 = ((sdlSoundTotalLen - sdlSoundRPos) + sdlSoundTotalLen) % sdlSoundTotalLen;
if (len >= nAvail2) {
memcpy(stream, &sdlSoundBuffer[sdlSoundRPos], nAvail2);
sdlSoundRPos = 0;
stream += nAvail2;
len -= nAvail2;
}
if (len > 0) {
memcpy(stream, &sdlSoundBuffer[sdlSoundRPos], len);
sdlSoundRPos = (sdlSoundRPos + len) % sdlSoundTotalLen;
stream += len;
}
SDL_CondSignal(sdlSoundCond);
SDL_mutexV(sdlSoundMutex);
}
void systemWriteDataToSoundBuffer()
{
// Patch #1382692 by deathpudding.
if (SDL_GetAudioStatus () != SDL_AUDIO_PLAYING)
SDL_PauseAudio (0);
if ((sdlSoundLen + soundBufferLen) >= 2048*2) {
bool lock = (!speedup && !throttle) ? true : false;
if (lock)
SDL_SemWait (sdlBufferEmpty);
SDL_SemWait (sdlBufferLock);
int copied = 2048*2 - sdlSoundLen;
memcpy (sdlBuffer + sdlSoundLen, soundFinalWave, copied);
sdlSoundLen = 2048*2;
SDL_SemPost (sdlBufferLock);
if (lock) {
SDL_SemPost (sdlBufferFull);
/* wait for buffer to be dumped by soundCallback() */
SDL_SemWait (sdlBufferEmpty);
SDL_SemPost (sdlBufferEmpty);
SDL_SemWait (sdlBufferLock);
memcpy (sdlBuffer, ((u8 *)soundFinalWave) + copied,
soundBufferLen - copied);
sdlSoundLen = soundBufferLen - copied;
SDL_SemPost (sdlBufferLock);
}
else {
SDL_SemWait (sdlBufferLock);
memcpy (sdlBuffer, ((u8 *) soundFinalWave) + copied, soundBufferLen);
SDL_SemPost (sdlBufferLock);
}
if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING)
{
SDL_PauseAudio(0);
}
else {
SDL_SemWait (sdlBufferLock);
memcpy (sdlBuffer + sdlSoundLen, soundFinalWave, soundBufferLen);
sdlSoundLen += soundBufferLen;
SDL_SemPost (sdlBufferLock);
int remain = soundBufferLen;
const u8 *wave = reinterpret_cast<const u8 *>(soundFinalWave);
if (remain <= 0)
return;
SDL_mutexP(sdlSoundMutex);
int n;
while (remain >= (n = soundBufferFree())) {
const int nAvail = ((sdlSoundTotalLen - sdlSoundWPos) + sdlSoundTotalLen) % sdlSoundTotalLen;
if (n >= nAvail) {
memcpy(&sdlSoundBuffer[sdlSoundWPos], wave, nAvail);
sdlSoundWPos = 0;
wave += nAvail;
remain -= nAvail;
n -= nAvail;
}
if (!emulating || speedup || throttle) {
SDL_mutexV(sdlSoundMutex);
return;
}
SDL_CondWait(sdlSoundCond, sdlSoundMutex);
}
const int nAvail = ((sdlSoundTotalLen - sdlSoundWPos) + sdlSoundTotalLen) % sdlSoundTotalLen;
if (remain >= nAvail) {
memcpy(&sdlSoundBuffer[sdlSoundWPos], wave, nAvail);
sdlSoundWPos = 0;
wave += nAvail;
remain -= nAvail;
}
if (remain > 0) {
memcpy(&sdlSoundBuffer[sdlSoundWPos], wave, remain);
sdlSoundWPos = (sdlSoundWPos + remain) % sdlSoundTotalLen;
}
}
SDL_mutexV(sdlSoundMutex);
}
bool systemSoundInit()
{
@ -3234,26 +3255,34 @@ bool systemSoundInit()
fprintf(stderr,"Failed to open audio: %s\n", SDL_GetError());
return false;
}
soundBufferTotalLen = soundBufferLen*10;
// Patch #1382692 by deathpudding.
sdlBufferLock = SDL_CreateSemaphore (1);
sdlBufferFull = SDL_CreateSemaphore (0);
sdlBufferEmpty = SDL_CreateSemaphore (1);
sdlSoundLen = 0;
sdlSoundCond = SDL_CreateCond();
sdlSoundMutex = SDL_CreateMutex();
sdlSoundRPos = sdlSoundWPos = 0;
systemSoundOn = true;
return true;
}
void systemSoundShutdown()
{
// Patch #1382692 by deathpudding.
SDL_CloseAudio (); //TODO: fix freeze
SDL_DestroySemaphore (sdlBufferLock);
SDL_DestroySemaphore (sdlBufferFull);
SDL_DestroySemaphore (sdlBufferEmpty);
sdlBufferLock = NULL;
sdlBufferFull = NULL;
sdlBufferEmpty = NULL;
SDL_mutexP(sdlSoundMutex);
int iSave = emulating;
emulating = 0;
SDL_CondSignal(sdlSoundCond);
SDL_mutexV(sdlSoundMutex);
SDL_DestroyCond(sdlSoundCond);
sdlSoundCond = NULL;
SDL_DestroyMutex(sdlSoundMutex);
sdlSoundMutex = NULL;
SDL_CloseAudio();
emulating = iSave;
systemSoundOn = false;
}
void systemSoundPause()

View File

@ -180,6 +180,8 @@ BEGIN_MESSAGE_MAP(MainWnd, CWnd)
ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLQUADS, OnUpdateOptionsVideoRenderoptionsGlquads)
ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLPOLYGONS, OnOptionsVideoRenderoptionsGlpolygons)
ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLPOLYGONS, OnUpdateOptionsVideoRenderoptionsGlpolygons)
ON_COMMAND(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLSLSHADERS, OnOptionsVideoRenderingoptionsGLSLShaders)
ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO_RENDEROPTIONS_GLSLSHADERS, OnUpdateOptionsVideoRenderingoptionsGLSLShaders)
ON_WM_CONTEXTMENU()
ON_COMMAND(ID_OPTIONS_EMULATOR_ASSOCIATE, OnOptionsEmulatorAssociate)

View File

@ -200,8 +200,8 @@ class MainWnd : public CWnd
afx_msg void OnUpdateOptionsVideoRenderoptionsGlnearest(CCmdUI* pCmdUI);
afx_msg void OnOptionsVideoRenderoptionsGlbilinear();
afx_msg void OnUpdateOptionsVideoRenderoptionsGlbilinear(CCmdUI* pCmdUI);
afx_msg void OnUpdateOptionsVideoRenderoptionsGlanisotropic(CCmdUI* pCmdUI);
afx_msg void OnOptionsVideoRenderoptionsGlanisotropic();
afx_msg void OnOptionsVideoRenderingoptionsGLSLShaders();
afx_msg void OnUpdateOptionsVideoRenderingoptionsGLSLShaders(CCmdUI* pCmdUI);
afx_msg void OnOptionsVideoRenderoptionsGltriangle();
afx_msg void OnUpdateOptionsVideoRenderoptionsGltriangle(CCmdUI* pCmdUI);

View File

@ -625,6 +625,19 @@ void MainWnd::OnUpdateOptionsVideoRenderoptionsGlpolygons(CCmdUI* pCmdUI)
pCmdUI->SetCheck(theApp.glType == 2);
}
void MainWnd::OnUpdateOptionsVideoRenderingoptionsGLSLShaders(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(theApp.GLSLShaders);
}
void MainWnd::OnOptionsVideoRenderingoptionsGLSLShaders()
{
theApp.GLSLShaders = !theApp.GLSLShaders;
if( theApp.GLSLShaders ) {
theApp.display->setOption( _T("GLSLShaders"), theApp.GLSLShaders );
}
}
void MainWnd::OnOptionsEmulatorAssociate()
{
theApp.winCheckFullscreen();

View File

@ -32,6 +32,8 @@
#include <cmath>
#include "glFont.h"
#pragma comment(lib,"glew32.lib")
#include <GL/glew.h>
// OpenGL
#include <gl/GL.h> // main include file
#ifdef HAS_GLEXT
@ -68,6 +70,9 @@ private:
RECT destRect;
bool failed;
GLFONT font;
char *VertexShaderSource,*FragmentShaderSource;
int VertexShader,FragmentShader;
int ShaderProgram;
void initializeMatrices( int w, int h );
bool initializeTexture( int w, int h );
@ -75,6 +80,10 @@ private:
void setVSync( int interval = 1 );
void calculateDestRect( int w, int h );
void initializeFont();
void InitShader();
void DeInitShader();
void rasterise();
public:
OpenGLDisplay();
@ -93,8 +102,10 @@ public:
virtual int selectFullScreenMode( GUID ** );
};
#include "gzglfont.h"
#include "gzglfont.h"
char *readShaderFile(char *FileName);
void OpenGLDisplay::initializeFont()
{
int ret;
@ -126,7 +137,61 @@ void OpenGLDisplay::initializeFont()
(void)inflateEnd(&strm);
}
char *readShaderFile(char *FileName) {
FILE *fp;
char *DATA = NULL;
int flength = 0;
fp = fopen(FileName,"rt");
fseek(fp, 0, SEEK_END);
flength = ftell(fp);
rewind(fp);
DATA = (char *)malloc(sizeof(char) * (flength+1));
flength = fread(DATA, sizeof(char), flength, fp);
DATA[flength] = '\0';
fclose(fp);
return DATA;
}
void OpenGLDisplay::DeInitShader () {
glDetachObjectARB(ShaderProgram,VertexShader);
glDetachObjectARB(ShaderProgram,FragmentShader);
glDeleteObjectARB(ShaderProgram);
}
void OpenGLDisplay::InitShader () {
GLEW_ARB_vertex_shader;
GLEW_ARB_fragment_shader;
VertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
FragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
VertexShaderSource = readShaderFile("vertex_shader.vert");
FragmentShaderSource = readShaderFile("fragment_shader.frag");
const char * VS = VertexShaderSource;
const char * FS = FragmentShaderSource;
glShaderSourceARB(VertexShader, 1, &VS,NULL);
glShaderSourceARB(FragmentShader, 1, &FS,NULL);
free(VertexShaderSource);free(FragmentShaderSource);
glCompileShaderARB(VertexShader);
glCompileShaderARB(FragmentShader);
ShaderProgram = glCreateProgramObjectARB();
glAttachObjectARB(ShaderProgram,VertexShader);
glAttachObjectARB(ShaderProgram,FragmentShader);
glLinkProgramARB(ShaderProgram);
}
OpenGLDisplay::OpenGLDisplay()
{
@ -143,6 +208,7 @@ OpenGLDisplay::OpenGLDisplay()
OpenGLDisplay::~OpenGLDisplay()
{
DeInitShader();
cleanup();
}
@ -205,8 +271,8 @@ bool OpenGLDisplay::initialize()
glEnable( GL_TEXTURE_2D );
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glewInit();
initializeMatrices( theApp.surfaceSizeX, theApp.surfaceSizeY );
setVSync( theApp.vsync );
@ -243,12 +309,8 @@ void OpenGLDisplay::clear()
glClear( GL_COLOR_BUFFER_BIT );
}
void OpenGLDisplay::render()
void OpenGLDisplay::rasterise()
{
clear();
int pitch = theApp.filterWidth * (systemColorDepth>>3) + 4;
u8 *data = pix + ( theApp.sizeX + 1 ) * 4;
@ -273,17 +335,7 @@ void OpenGLDisplay::render()
} else {
glPixelStorei( GL_UNPACK_ROW_LENGTH, theApp.sizeX + 1 );
}
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
width,
height,
GL_RGBA,
GL_UNSIGNED_BYTE,
data );
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,data );
if( theApp.glType == 0 ) {
glBegin( GL_TRIANGLE_STRIP );
@ -377,12 +429,30 @@ void OpenGLDisplay::render()
}
}
}
void OpenGLDisplay::render()
{
clear();
if (theApp.GLSLShaders){
InitShader();
glUseProgramObjectARB(ShaderProgram);
int texture_location = glGetUniformLocationARB(ShaderProgram, "ShaderTexture");
glUniform1iARB(texture_location, 0);
}
else{
glUseProgramObjectARB(NULL);
DeInitShader();
}
rasterise();
glFlush();
SwapBuffers( hDC );
// since OpenGL draws on the back buffer,
// we have to swap it to the front buffer to see it
// draw informations with GDI on the front buffer
}

View File

@ -288,6 +288,7 @@ VBA::VBA()
ddrawUseVideoMemory = false;
d3dFilter = 0;
glFilter = 0;
GLSLShaders = 0;
glType = 0;
skin = NULL;
skinName = "";
@ -1489,6 +1490,10 @@ void VBA::loadSettings()
if(glFilter < 0 || glFilter > 1)
glFilter = 1;
GLSLShaders = regQueryDwordValue("GLSLShaders", 0);
if(GLSLShaders < 0 || GLSLShaders > 1)
GLSLShaders = 0;
glType = regQueryDwordValue("glType", 0);
if(glType < 0 || glType > 2)
glType = 0;
@ -2571,6 +2576,7 @@ void VBA::saveSettings()
regSetDwordValue("d3dFilter", d3dFilter);
regSetDwordValue("glFilter", glFilter);
regSetDwordValue("GLSLShaders", GLSLShaders);
regSetDwordValue("glType", glType);
regSetDwordValue("filter", filterType);

View File

@ -163,6 +163,7 @@ class VBA : public CWinApp
bool ddrawUseVideoMemory;
int d3dFilter;
int glFilter;
int GLSLShaders;
int glType;
bool dinputKeyFocus;
CSkin *skin;

View File

@ -1595,6 +1595,7 @@ BEGIN
MENUITEM " Vertex: Triangle", ID_OPTIONS_VIDEO_RENDEROPTIONS_GLTRIANGLE
MENUITEM " Vertex: Quads", ID_OPTIONS_VIDEO_RENDEROPTIONS_GLQUADS
MENUITEM " Vertex: Polygons", ID_OPTIONS_VIDEO_RENDEROPTIONS_GLPOLYGONS
MENUITEM " GLSL Shaders", ID_OPTIONS_VIDEO_RENDEROPTIONS_GLSLSHADERS
MENUITEM SEPARATOR
MENUITEM "&VSync", ID_OPTIONS_VIDEO_VSYNC
MENUITEM "Triple Buffering", ID_OPTIONS_VIDEO_TRIPLEBUFFERING

View File

@ -813,13 +813,15 @@
#define ID_OUTPUTAPI_SOFTWAREMIXING 40348
#define ID_OUTPUTAPI_CONFIGURATION 40349
#define ID_OUTPUTAPI_OALCONFIGURATION 40350
#define ID_RENDERAPI_FILTER 40351
#define ID_OPTIONS_VIDEO_RENDEROPTIONS_GLSLSHADERS 40352
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 161
#define _APS_NEXT_COMMAND_VALUE 40351
#define _APS_NEXT_COMMAND_VALUE 40353
#define _APS_NEXT_CONTROL_VALUE 1270
#define _APS_NEXT_SYMED_VALUE 103
#endif