2009-07-17 19:27:04 +02:00
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file :
* Copyright ( C ) 2002 Xodnizel
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program 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 General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2012-12-14 18:18:20 +01:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2009-07-17 19:27:04 +02:00
*/
# ifndef WIN32
# include <stdint.h>
# endif
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <zlib.h>
# include "types.h"
# include "video.h"
# include "fceu.h"
# include "file.h"
# include "utils/memory.h"
# include "utils/crc32.h"
# include "state.h"
# include "movie.h"
# include "palette.h"
# include "nsf.h"
# include "input.h"
# include "vsuni.h"
# include "drawing.h"
# include "driver.h"
# ifdef _S9XLUA_H
# include "fceulua.h"
# endif
2010-08-29 23:15:42 +02:00
# ifdef WIN32
# include "drivers/win/common.h" //For DirectX constants
# include "drivers/win/input.h"
# endif
2009-07-17 19:27:04 +02:00
# ifdef CREATE_AVI
# include "drivers/videolog/nesvideos-piece.h"
# endif
uint8 * XBuf = NULL ;
uint8 * XBackBuf = NULL ;
int ClipSidesOffset = 0 ; //Used to move displayed messages when Clips left and right sides is checked
static uint8 * xbsave = NULL ;
GUIMESSAGE guiMessage ;
GUIMESSAGE subtitleMessage ;
//for input display
extern int input_display ;
extern uint32 cur_input_display ;
2010-08-29 23:15:42 +02:00
bool oldInputDisplay = false ;
2012-12-14 18:18:20 +01:00
unsigned int lastu = 0 ;
2010-08-29 23:15:42 +02:00
std : : string AsSnapshotName = " " ; //adelikat:this will set the snapshot name when for s savesnapshot as function
void FCEUI_SetSnapshotAsName ( std : : string name ) { AsSnapshotName = name ; }
std : : string FCEUI_GetSnapshotAsName ( ) { return AsSnapshotName ; }
2009-07-17 19:27:04 +02:00
void FCEU_KillVirtualVideo ( void )
{
//mbg merge TODO 7/17/06 temporarily removed
//if(xbsave)
//{
// free(xbsave);
// xbsave=0;
//}
//if(XBuf)
//{
//UnmapViewOfFile(XBuf);
//CloseHandle(mapXBuf);
//mapXBuf=NULL;
//}
//if(XBackBuf)
//{
// free(XBackBuf);
// XBackBuf=0;
//}
}
/**
* Return : Flag that indicates whether the function was succesful or not .
*
* TODO : This function is Windows - only . It should probably be moved .
* */
int FCEU_InitVirtualVideo ( void )
{
if ( ! XBuf ) /* Some driver code may allocate XBuf externally. */
/* 256 bytes per scanline, * 240 scanline maximum, +16 for alignment,
*/
if ( ! ( XBuf = ( uint8 * ) ( FCEU_malloc ( 256 * 256 + 16 ) ) ) | |
! ( XBackBuf = ( uint8 * ) ( FCEU_malloc ( 256 * 256 + 16 ) ) ) )
{
return 0 ;
}
xbsave = XBuf ;
if ( sizeof ( uint8 * ) = = 4 )
{
uintptr_t m = ( uintptr_t ) XBuf ;
m = ( 8 - m ) & 7 ;
XBuf + = m ;
}
memset ( XBuf , 128 , 256 * 256 ) ; //*240);
memset ( XBackBuf , 128 , 256 * 256 ) ;
return 1 ;
}
# ifdef FRAMESKIP
void FCEU_PutImageDummy ( void )
{
ShowFPS ( ) ;
if ( GameInfo - > type ! = GIT_NSF )
{
FCEU_DrawNTSCControlBars ( XBuf ) ;
FCEU_DrawSaveStates ( XBuf ) ;
FCEU_DrawMovies ( XBuf ) ;
}
if ( guiMessage . howlong ) guiMessage . howlong - - ; /* DrawMessage() */
}
# endif
static int dosnapsave = 0 ;
void FCEUI_SaveSnapshot ( void )
{
dosnapsave = 1 ;
}
2010-08-29 23:15:42 +02:00
void FCEUI_SaveSnapshotAs ( void )
{
dosnapsave = 2 ;
}
2009-07-17 19:27:04 +02:00
static void ReallySnap ( void )
{
int x = SaveSnapshot ( ) ;
if ( ! x )
2010-08-29 23:15:42 +02:00
FCEU_DispMessage ( " Error saving screen snapshot. " , 0 ) ;
2009-07-17 19:27:04 +02:00
else
2010-08-29 23:15:42 +02:00
FCEU_DispMessage ( " Screen snapshot %d saved. " , 0 , x - 1 ) ;
2009-07-17 19:27:04 +02:00
}
void FCEU_PutImage ( void )
{
2010-08-29 23:15:42 +02:00
if ( dosnapsave = = 2 ) //Save screenshot as, currently only flagged & run by the Win32 build. //TODO SDL: implement this?
{
char nameo [ 512 ] ;
strcpy ( nameo , FCEUI_GetSnapshotAsName ( ) . c_str ( ) ) ;
if ( nameo )
{
SaveSnapshot ( nameo ) ;
FCEU_DispMessage ( " Snapshot Saved. " , 0 ) ;
}
dosnapsave = 0 ;
}
2009-07-17 19:27:04 +02:00
if ( GameInfo - > type = = GIT_NSF )
{
DrawNSF ( XBuf ) ;
//Save snapshot after NSF screen is drawn. Why would we want to do it before?
2010-08-29 23:15:42 +02:00
if ( dosnapsave = = 1 )
2009-07-17 19:27:04 +02:00
{
ReallySnap ( ) ;
dosnapsave = 0 ;
}
2012-12-14 18:18:20 +01:00
}
2009-07-17 19:27:04 +02:00
else
{
//Save backbuffer before overlay stuff is written.
if ( ! FCEUI_EmulationPaused ( ) )
memcpy ( XBackBuf , XBuf , 256 * 256 ) ;
//Some messages need to be displayed before the avi is dumped
DrawMessage ( true ) ;
2012-12-14 18:18:20 +01:00
# ifdef _S9XLUA_H
// Lua gui should draw before the avi is dumped.
2009-07-17 19:27:04 +02:00
FCEU_LuaGui ( XBuf ) ;
2012-12-14 18:18:20 +01:00
# endif
2009-07-17 19:27:04 +02:00
2012-01-09 02:59:06 +01:00
//Save snapshot
2010-08-29 23:15:42 +02:00
if ( dosnapsave = = 1 )
2009-07-17 19:27:04 +02:00
{
ReallySnap ( ) ;
dosnapsave = 0 ;
}
2012-01-09 02:59:06 +01:00
if ( ! FCEUI_AviEnableHUDrecording ( ) ) snapAVI ( ) ;
2009-07-17 19:27:04 +02:00
if ( GameInfo - > type = = GIT_VSUNI )
FCEU_VSUniDraw ( XBuf ) ;
FCEU_DrawSaveStates ( XBuf ) ;
FCEU_DrawMovies ( XBuf ) ;
FCEU_DrawLagCounter ( XBuf ) ;
FCEU_DrawNTSCControlBars ( XBuf ) ;
FCEU_DrawRecordingStatus ( XBuf ) ;
2012-12-14 18:18:20 +01:00
ShowFPS ( ) ;
2009-07-17 19:27:04 +02:00
}
if ( FCEUD_ShouldDrawInputAids ( ) )
FCEU_DrawInput ( XBuf ) ;
//Fancy input display code
if ( input_display )
{
2010-08-29 23:15:42 +02:00
extern uint32 JSAutoHeld ;
uint32 held ;
2012-12-14 18:18:20 +01:00
int controller , c , ci , color ;
2009-07-17 19:27:04 +02:00
int i , j ;
2010-08-29 23:15:42 +02:00
uint32 on = FCEUMOV_Mode ( MOVIEMODE_PLAY ) ? 0x90 : 0xA7 ; //Standard, or Gray depending on movie mode
uint32 oni = 0xA0 ; //Color for immediate keyboard buttons
uint32 blend = 0xB6 ; //Blend of immiate and last held buttons
uint32 ahold = 0x87 ; //Auto hold
uint32 off = 0xCF ;
2012-12-14 18:18:20 +01:00
2010-08-29 23:15:42 +02:00
uint8 * t = XBuf + ( FSettings . LastSLine - 9 ) * 256 + 20 ; //mbg merge 7/17/06 changed t to uint8*
2009-07-17 19:27:04 +02:00
if ( input_display > 4 ) input_display = 4 ;
for ( controller = 0 ; controller < input_display ; controller + + , t + = 56 )
{
for ( i = 0 ; i < 34 ; i + + )
for ( j = 0 ; j < 9 ; j + + )
t [ i + j * 256 ] = ( t [ i + j * 256 ] & 0x30 ) | 0xC1 ;
for ( i = 3 ; i < 6 ; i + + )
for ( j = 3 ; j < 6 ; j + + )
t [ i + j * 256 ] = 0xCF ;
c = cur_input_display > > ( controller * 8 ) ;
2010-08-29 23:15:42 +02:00
// This doesn't work in anything except windows for now.
// It doesn't get set anywhere in other ports.
# ifdef WIN32
if ( ! oldInputDisplay ) ci = FCEUMOV_Mode ( MOVIEMODE_PLAY ) ? 0 : GetGamepadPressedImmediate ( ) > > ( controller * 8 ) ;
else ci = 0 ;
if ( ! oldInputDisplay & & ! FCEUMOV_Mode ( MOVIEMODE_PLAY ) ) held = ( JSAutoHeld > > ( controller * 8 ) ) ;
else held = 0 ;
# else
// Put other port info here
ci = 0 ;
held = 0 ;
# endif
//adelikat: I apologize to anyone who ever sifts through this color assignment
2009-07-17 19:27:04 +02:00
//A
2010-08-29 23:15:42 +02:00
if ( held & 1 ) { //If auto-hold
2012-12-14 18:18:20 +01:00
if ( ! ( ci & 1 ) ) color = ahold ;
else
2010-08-29 23:15:42 +02:00
color = ( c & 1 ) ? on : off ; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
}
else {
if ( c & 1 ) color = ( ci & 1 ) ? blend : on ; //If immedaite buttons are pressed and they match the previous frame, blend the colors
else color = ( ci & 1 ) ? oni : off ;
}
2009-07-17 19:27:04 +02:00
for ( i = 0 ; i < 4 ; i + + )
{
for ( j = 0 ; j < 4 ; j + + )
{
if ( i % 3 = = 0 & & j % 3 = = 0 )
continue ;
t [ 30 + 4 * 256 + i + j * 256 ] = color ;
}
}
//B
2010-08-29 23:15:42 +02:00
if ( held & 2 ) { //If auto-hold
2012-12-14 18:18:20 +01:00
if ( ! ( ci & 2 ) ) color = ahold ;
else
2010-08-29 23:15:42 +02:00
color = ( c & 2 ) ? on : off ; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
}
else {
if ( c & 2 ) color = ( ci & 2 ) ? blend : on ; //If immedaite buttons are pressed and they match the previous frame, blend the colors
else color = ( ci & 2 ) ? oni : off ;
}
2009-07-17 19:27:04 +02:00
for ( i = 0 ; i < 4 ; i + + )
{
for ( j = 0 ; j < 4 ; j + + )
{
if ( i % 3 = = 0 & & j % 3 = = 0 )
continue ;
t [ 24 + 4 * 256 + i + j * 256 ] = color ;
}
}
//Select
2010-08-29 23:15:42 +02:00
if ( held & 4 ) { //If auto-hold
2012-12-14 18:18:20 +01:00
if ( ! ( ci & 4 ) ) color = ahold ;
else
2010-08-29 23:15:42 +02:00
color = ( c & 4 ) ? on : off ; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
}
else {
if ( c & 4 ) color = ( ci & 4 ) ? blend : on ; //If immedaite buttons are pressed and they match the previous frame, blend the colors
else color = ( ci & 4 ) ? oni : off ;
}
2009-07-17 19:27:04 +02:00
for ( i = 0 ; i < 4 ; i + + )
{
t [ 11 + 5 * 256 + i ] = color ;
t [ 11 + 6 * 256 + i ] = color ;
}
//Start
2010-08-29 23:15:42 +02:00
if ( held & 8 ) { //If auto-hold
2012-12-14 18:18:20 +01:00
if ( ! ( ci & 8 ) ) color = ahold ;
else
2010-08-29 23:15:42 +02:00
color = ( c & 8 ) ? on : off ; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
}
else {
if ( c & 8 ) color = ( ci & 8 ) ? blend : on ; //If immedaite buttons are pressed and they match the previous frame, blend the colors
else color = ( ci & 8 ) ? oni : off ;
}
2009-07-17 19:27:04 +02:00
for ( i = 0 ; i < 4 ; i + + )
{
t [ 17 + 5 * 256 + i ] = color ;
t [ 17 + 6 * 256 + i ] = color ;
}
//Up
2010-08-29 23:15:42 +02:00
if ( held & 16 ) { //If auto-hold
2012-12-14 18:18:20 +01:00
if ( ! ( ci & 16 ) ) color = ahold ;
else
2010-08-29 23:15:42 +02:00
color = ( c & 16 ) ? on : off ; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
}
else {
if ( c & 16 ) color = ( ci & 16 ) ? blend : on ; //If immedaite buttons are pressed and they match the previous frame, blend the colors
else color = ( ci & 16 ) ? oni : off ;
}
2009-07-17 19:27:04 +02:00
for ( i = 0 ; i < 3 ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
{
t [ 3 + i + 256 * j ] = color ;
}
}
//Down
2010-08-29 23:15:42 +02:00
if ( held & 32 ) { //If auto-hold
2012-12-14 18:18:20 +01:00
if ( ! ( ci & 32 ) ) color = ahold ;
2010-08-29 23:15:42 +02:00
else
color = ( c & 32 ) ? on : off ; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
}
else {
if ( c & 32 ) color = ( ci & 32 ) ? blend : on ; //If immedaite buttons are pressed and they match the previous frame, blend the colors
else color = ( ci & 32 ) ? oni : off ;
}
2009-07-17 19:27:04 +02:00
for ( i = 0 ; i < 3 ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
{
t [ 3 + i + 256 * j + 6 * 256 ] = color ;
}
}
//Left
2010-08-29 23:15:42 +02:00
if ( held & 64 ) { //If auto-hold
2012-12-14 18:18:20 +01:00
if ( ! ( ci & 64 ) ) color = ahold ;
else
2010-08-29 23:15:42 +02:00
color = ( c & 64 ) ? on : off ; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
}
else {
if ( c & 64 ) color = ( ci & 64 ) ? blend : on ; //If immedaite buttons are pressed and they match the previous frame, blend the colors
else color = ( ci & 64 ) ? oni : off ;
}
2009-07-17 19:27:04 +02:00
for ( i = 0 ; i < 3 ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
{
t [ 3 * 256 + i + 256 * j ] = color ;
}
}
//Right
2010-08-29 23:15:42 +02:00
if ( held & 128 ) { //If auto-hold
2012-12-14 18:18:20 +01:00
if ( ! ( ci & 128 ) ) color = ahold ;
else
2010-08-29 23:15:42 +02:00
color = ( c & 128 ) ? on : off ; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
}
else {
if ( c & 128 ) color = ( ci & 128 ) ? blend : on ; //If immedaite buttons are pressed and they match the previous frame, blend the colors
else color = ( ci & 128 ) ? oni : off ;
}
2009-07-17 19:27:04 +02:00
for ( i = 0 ; i < 3 ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
{
t [ 6 + 3 * 256 + i + 256 * j ] = color ;
}
}
}
}
2012-01-09 02:59:06 +01:00
if ( FCEUI_AviEnableHUDrecording ( ) )
{
if ( FCEUI_AviDisableMovieMessages ( ) )
{
snapAVI ( ) ;
DrawMessage ( false ) ;
} else
{
DrawMessage ( false ) ;
snapAVI ( ) ;
}
} else DrawMessage ( false ) ;
}
void snapAVI ( )
{
//Update AVI
if ( ! FCEUI_EmulationPaused ( ) )
FCEUI_AviVideoUpdate ( XBuf ) ;
2009-07-17 19:27:04 +02:00
}
void FCEU_DispMessageOnMovie ( char * format , . . . )
{
va_list ap ;
va_start ( ap , format ) ;
vsnprintf ( guiMessage . errmsg , sizeof ( guiMessage . errmsg ) , format , ap ) ;
va_end ( ap ) ;
guiMessage . howlong = 180 ;
guiMessage . isMovieMessage = true ;
2010-08-29 23:15:42 +02:00
guiMessage . linesFromBottom = 0 ;
2010-03-11 07:30:34 +01:00
if ( FCEUI_AviIsRecording ( ) & & FCEUI_AviDisableMovieMessages ( ) )
guiMessage . howlong = 0 ;
2009-07-17 19:27:04 +02:00
}
2010-08-29 23:15:42 +02:00
void FCEU_DispMessage ( char * format , int disppos = 0 , . . . )
2009-07-17 19:27:04 +02:00
{
2012-06-30 04:12:05 +02:00
# ifndef GEKKO
2009-07-17 19:27:04 +02:00
va_list ap ;
2010-08-29 23:15:42 +02:00
va_start ( ap , disppos ) ;
2009-07-17 19:27:04 +02:00
vsnprintf ( guiMessage . errmsg , sizeof ( guiMessage . errmsg ) , format , ap ) ;
2012-12-14 18:18:20 +01:00
va_end ( ap ) ;
2012-01-09 02:59:06 +01:00
// also log messages
char temp [ 2048 ] ;
2012-12-14 18:18:20 +01:00
va_start ( ap , disppos ) ;
2012-01-09 02:59:06 +01:00
vsnprintf ( temp , sizeof ( temp ) , format , ap ) ;
2012-12-14 18:18:20 +01:00
va_end ( ap ) ;
2012-01-09 02:59:06 +01:00
strcat ( temp , " \n " ) ;
FCEU_printf ( temp ) ;
2012-06-30 04:12:05 +02:00
2009-07-17 19:27:04 +02:00
guiMessage . howlong = 180 ;
guiMessage . isMovieMessage = false ;
2010-08-29 23:15:42 +02:00
guiMessage . linesFromBottom = disppos ;
2010-03-11 07:30:34 +01:00
//adelikat: Pretty sure this code fails, Movie playback stopped is done with FCEU_DispMessageOnMovie()
2009-07-17 19:27:04 +02:00
# ifdef CREATE_AVI
if ( LoggingEnabled = = 2 )
{
/* While in AVI recording mode, only display bare minimum
* of messages
*/
if ( strcmp ( guiMessage . errmsg , " Movie playback stopped. " ) ! = 0 )
guiMessage . howlong = 0 ;
}
# endif
2012-06-30 04:12:05 +02:00
# endif
2009-07-17 19:27:04 +02:00
}
void FCEU_ResetMessages ( )
{
guiMessage . howlong = 0 ;
guiMessage . isMovieMessage = false ;
2010-08-29 23:15:42 +02:00
guiMessage . linesFromBottom = 0 ;
2009-07-17 19:27:04 +02:00
}
static int WritePNGChunk ( FILE * fp , uint32 size , char * type , uint8 * data )
{
uint32 crc ;
uint8 tempo [ 4 ] ;
tempo [ 0 ] = size > > 24 ;
tempo [ 1 ] = size > > 16 ;
tempo [ 2 ] = size > > 8 ;
tempo [ 3 ] = size ;
if ( fwrite ( tempo , 4 , 1 , fp ) ! = 1 )
return 0 ;
if ( fwrite ( type , 4 , 1 , fp ) ! = 1 )
return 0 ;
if ( size )
if ( fwrite ( data , 1 , size , fp ) ! = size )
return 0 ;
crc = CalcCRC32 ( 0 , ( uint8 * ) type , 4 ) ;
if ( size )
crc = CalcCRC32 ( crc , data , size ) ;
tempo [ 0 ] = crc > > 24 ;
tempo [ 1 ] = crc > > 16 ;
tempo [ 2 ] = crc > > 8 ;
tempo [ 3 ] = crc ;
if ( fwrite ( tempo , 4 , 1 , fp ) ! = 1 )
return 0 ;
return 1 ;
}
2010-08-29 23:15:42 +02:00
uint32 GetScreenPixel ( int x , int y , bool usebackup ) {
2012-12-14 18:18:20 +01:00
2010-08-29 23:15:42 +02:00
uint8 r , g , b ;
if ( ( ( x < 0 ) | | ( x > 255 ) ) | | ( ( y < 0 ) | | ( y > 255 ) ) )
return - 1 ;
if ( usebackup )
FCEUD_GetPalette ( XBackBuf [ ( y * 256 ) + x ] , & r , & g , & b ) ;
else
FCEUD_GetPalette ( XBuf [ ( y * 256 ) + x ] , & r , & g , & b ) ;
return ( ( int ) ( r ) < < 16 ) | ( ( int ) ( g ) < < 8 ) | ( int ) ( b ) ;
}
int GetScreenPixelPalette ( int x , int y , bool usebackup ) {
if ( ( ( x < 0 ) | | ( x > 255 ) ) | | ( ( y < 0 ) | | ( y > 255 ) ) )
return - 1 ;
if ( usebackup )
return XBackBuf [ ( y * 256 ) + x ] & 0x3f ;
else
return XBuf [ ( y * 256 ) + x ] & 0x3f ;
}
2009-07-17 19:27:04 +02:00
int SaveSnapshot ( void )
{
int totallines = FSettings . LastSLine - FSettings . FirstSLine + 1 ;
int x , u , y ;
FILE * pp = NULL ;
uint8 * compmem = NULL ;
uLongf compmemsize = totallines * 263 + 12 ;
if ( ! ( compmem = ( uint8 * ) FCEU_malloc ( compmemsize ) ) )
return 0 ;
2012-12-14 18:18:20 +01:00
for ( u = lastu ; u < 99999 ; + + u )
2009-07-17 19:27:04 +02:00
{
2012-01-09 02:59:06 +01:00
pp = FCEUD_UTF8fopen ( FCEU_MakeFName ( FCEUMKF_SNAP , u , " png " ) . c_str ( ) , " rb " ) ;
2009-07-17 19:27:04 +02:00
if ( pp = = NULL ) break ;
fclose ( pp ) ;
}
2012-12-14 18:18:20 +01:00
lastu = u ;
2009-07-17 19:27:04 +02:00
2012-01-09 02:59:06 +01:00
if ( ! ( pp = FCEUD_UTF8fopen ( FCEU_MakeFName ( FCEUMKF_SNAP , u , " png " ) . c_str ( ) , " wb " ) ) )
2009-07-17 19:27:04 +02:00
{
2010-08-29 23:15:42 +02:00
free ( compmem ) ;
2009-07-17 19:27:04 +02:00
return 0 ;
}
2012-01-09 02:59:06 +01:00
2009-07-17 19:27:04 +02:00
{
static uint8 header [ 8 ] = { 137 , 80 , 78 , 71 , 13 , 10 , 26 , 10 } ;
if ( fwrite ( header , 8 , 1 , pp ) ! = 1 )
goto PNGerr ;
}
{
uint8 chunko [ 13 ] ;
chunko [ 0 ] = chunko [ 1 ] = chunko [ 3 ] = 0 ;
chunko [ 2 ] = 0x1 ; // Width of 256
chunko [ 4 ] = chunko [ 5 ] = chunko [ 6 ] = 0 ;
chunko [ 7 ] = totallines ; // Height
chunko [ 8 ] = 8 ; // bit depth
chunko [ 9 ] = 3 ; // Color type; indexed 8-bit
chunko [ 10 ] = 0 ; // compression: deflate
chunko [ 11 ] = 0 ; // Basic adapative filter set(though none are used).
chunko [ 12 ] = 0 ; // No interlace.
if ( ! WritePNGChunk ( pp , 13 , " IHDR " , chunko ) )
goto PNGerr ;
}
{
uint8 pdata [ 256 * 3 ] ;
for ( x = 0 ; x < 256 ; x + + )
FCEUD_GetPalette ( x , pdata + x * 3 , pdata + x * 3 + 1 , pdata + x * 3 + 2 ) ;
if ( ! WritePNGChunk ( pp , 256 * 3 , " PLTE " , pdata ) )
goto PNGerr ;
}
{
uint8 * tmp = XBuf + FSettings . FirstSLine * 256 ;
uint8 * dest , * mal , * mork ;
2010-10-06 05:57:22 +02:00
if ( ! ( mal = mork = dest = ( uint8 * ) FCEU_dmalloc ( ( totallines < < 8 ) + totallines ) ) )
2009-07-17 19:27:04 +02:00
goto PNGerr ;
// mork=dest=XBuf;
for ( y = 0 ; y < totallines ; y + + )
{
* dest = 0 ; // No filter.
dest + + ;
for ( x = 256 ; x ; x - - , tmp + + , dest + + )
2012-12-14 18:18:20 +01:00
* dest = * tmp ;
2009-07-17 19:27:04 +02:00
}
if ( compress ( compmem , & compmemsize , mork , ( totallines < < 8 ) + totallines ) ! = Z_OK )
{
if ( mal ) free ( mal ) ;
goto PNGerr ;
}
if ( mal ) free ( mal ) ;
if ( ! WritePNGChunk ( pp , compmemsize , " IDAT " , compmem ) )
goto PNGerr ;
}
if ( ! WritePNGChunk ( pp , 0 , " IEND " , 0 ) )
goto PNGerr ;
free ( compmem ) ;
fclose ( pp ) ;
return u + 1 ;
2010-08-29 23:15:42 +02:00
PNGerr :
if ( compmem )
free ( compmem ) ;
if ( pp )
fclose ( pp ) ;
return ( 0 ) ;
}
//overloaded SaveSnapshot for "Savesnapshot As" function
int SaveSnapshot ( char fileName [ 512 ] )
{
int totallines = FSettings . LastSLine - FSettings . FirstSLine + 1 ;
int x , y ;
FILE * pp = NULL ;
uint8 * compmem = NULL ;
uLongf compmemsize = totallines * 263 + 12 ;
if ( ! ( compmem = ( uint8 * ) FCEU_malloc ( compmemsize ) ) )
return 0 ;
if ( ! ( pp = FCEUD_UTF8fopen ( fileName , " wb " ) ) )
{
free ( compmem ) ;
return 0 ;
}
{
static uint8 header [ 8 ] = { 137 , 80 , 78 , 71 , 13 , 10 , 26 , 10 } ;
if ( fwrite ( header , 8 , 1 , pp ) ! = 1 )
goto PNGerr ;
}
{
uint8 chunko [ 13 ] ;
chunko [ 0 ] = chunko [ 1 ] = chunko [ 3 ] = 0 ;
chunko [ 2 ] = 0x1 ; // Width of 256
chunko [ 4 ] = chunko [ 5 ] = chunko [ 6 ] = 0 ;
chunko [ 7 ] = totallines ; // Height
chunko [ 8 ] = 8 ; // bit depth
chunko [ 9 ] = 3 ; // Color type; indexed 8-bit
chunko [ 10 ] = 0 ; // compression: deflate
chunko [ 11 ] = 0 ; // Basic adapative filter set(though none are used).
chunko [ 12 ] = 0 ; // No interlace.
if ( ! WritePNGChunk ( pp , 13 , " IHDR " , chunko ) )
goto PNGerr ;
}
{
uint8 pdata [ 256 * 3 ] ;
for ( x = 0 ; x < 256 ; x + + )
FCEUD_GetPalette ( x , pdata + x * 3 , pdata + x * 3 + 1 , pdata + x * 3 + 2 ) ;
if ( ! WritePNGChunk ( pp , 256 * 3 , " PLTE " , pdata ) )
goto PNGerr ;
}
{
uint8 * tmp = XBuf + FSettings . FirstSLine * 256 ;
uint8 * dest , * mal , * mork ;
2010-10-06 05:57:22 +02:00
if ( ! ( mal = mork = dest = ( uint8 * ) FCEU_dmalloc ( ( totallines < < 8 ) + totallines ) ) )
2010-08-29 23:15:42 +02:00
goto PNGerr ;
// mork=dest=XBuf;
for ( y = 0 ; y < totallines ; y + + )
{
* dest = 0 ; // No filter.
dest + + ;
for ( x = 256 ; x ; x - - , tmp + + , dest + + )
2012-12-14 18:18:20 +01:00
* dest = * tmp ;
2010-08-29 23:15:42 +02:00
}
if ( compress ( compmem , & compmemsize , mork , ( totallines < < 8 ) + totallines ) ! = Z_OK )
{
if ( mal ) free ( mal ) ;
goto PNGerr ;
}
if ( mal ) free ( mal ) ;
if ( ! WritePNGChunk ( pp , compmemsize , " IDAT " , compmem ) )
goto PNGerr ;
}
if ( ! WritePNGChunk ( pp , 0 , " IEND " , 0 ) )
goto PNGerr ;
free ( compmem ) ;
fclose ( pp ) ;
return 0 ;
2009-07-17 19:27:04 +02:00
PNGerr :
if ( compmem )
free ( compmem ) ;
if ( pp )
fclose ( pp ) ;
return ( 0 ) ;
}
2012-12-14 18:18:20 +01:00
// called when another ROM is opened
void ResetScreenshotsCounter ( )
{
lastu = 0 ;
}
2009-07-17 19:27:04 +02:00
uint64 FCEUD_GetTime ( void ) ;
uint64 FCEUD_GetTimeFreq ( void ) ;
2012-12-14 18:18:20 +01:00
bool Show_FPS = false ;
// Control whether the frames per second of the emulation is rendered.
bool FCEUI_ShowFPS ( )
{
return Show_FPS ;
}
void FCEUI_SetShowFPS ( bool showFPS )
{
Show_FPS = showFPS ;
}
void FCEUI_ToggleShowFPS ( )
{
Show_FPS ^ = 1 ;
}
2009-07-17 19:27:04 +02:00
static uint64 boop [ 60 ] ;
static int boopcount = 0 ;
void ShowFPS ( void )
2012-12-14 18:18:20 +01:00
{
# ifndef GEKKO
if ( Show_FPS = = false )
return ;
2009-07-17 19:27:04 +02:00
uint64 da = FCEUD_GetTime ( ) - boop [ boopcount ] ;
char fpsmsg [ 16 ] ;
int booplimit = PAL ? 50 : 60 ;
boop [ boopcount ] = FCEUD_GetTime ( ) ;
2012-12-14 18:18:20 +01:00
sprintf ( fpsmsg , " %.1f " , ( double ) booplimit / ( ( double ) da / FCEUD_GetTimeFreq ( ) ) ) ;
DrawTextTrans ( XBuf + ( ( 256 - ClipSidesOffset ) - 40 ) + ( FSettings . FirstSLine + 4 ) * 256 , 256 , ( uint8 * ) fpsmsg , 0xA0 ) ;
2009-07-17 19:27:04 +02:00
// It's not averaging FPS over exactly 1 second, but it's close enough.
boopcount = ( boopcount + 1 ) % booplimit ;
2010-10-06 05:57:22 +02:00
# endif
2012-12-14 18:18:20 +01:00
}