2006-07-29 05:46:15 +00:00
/* FCE Ultra - NES/Famicom Emulator
2008-06-17 06:55:07 +00:00
*
* 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-08-04 22:33:16 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2008-06-17 06:55:07 +00:00
*/
2006-07-29 05:46:15 +00:00
2008-06-06 03:03:14 +00:00
# ifndef WIN32
2008-06-06 01:41:13 +00:00
# include <stdint.h>
2008-06-06 03:03:14 +00:00
# endif
2006-07-29 05:46:15 +00:00
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <zlib.h>
# include "types.h"
# include "video.h"
# include "fceu.h"
2006-08-01 05:50:19 +00:00
# include "file.h"
# include "utils/memory.h"
# include "utils/crc32.h"
2006-07-29 05:46:15 +00:00
# include "state.h"
# include "movie.h"
# include "palette.h"
# include "nsf.h"
# include "input.h"
# include "vsuni.h"
2008-06-09 08:15:20 +00:00
# include "drawing.h"
2008-06-08 13:16:34 +00:00
# include "driver.h"
2008-09-24 06:06:31 +00:00
# ifdef _S9XLUA_H
2008-07-23 06:54:14 +00:00
# include "fceulua.h"
2008-09-24 06:06:31 +00:00
# endif
2006-07-29 05:46:15 +00:00
2010-05-13 21:08:37 +00:00
# ifdef WIN32
# include "drivers/win/common.h" //For DirectX constants
# include "drivers/win/input.h"
# endif
2008-10-25 12:36:03 +00:00
# ifdef CREATE_AVI
# include "drivers/videolog/nesvideos-piece.h"
# endif
2006-07-29 05:46:15 +00:00
uint8 * XBuf = NULL ;
uint8 * XBackBuf = NULL ;
2008-11-16 04:38:19 +00:00
int ClipSidesOffset = 0 ; //Used to move displayed messages when Clips left and right sides is checked
2006-07-29 05:46:15 +00:00
static uint8 * xbsave = NULL ;
2008-05-27 04:40:03 +00:00
GUIMESSAGE guiMessage ;
2008-11-23 23:49:15 +00:00
GUIMESSAGE subtitleMessage ;
2008-05-27 04:40:03 +00:00
2006-07-29 05:46:15 +00:00
//for input display
extern int input_display ;
extern uint32 cur_input_display ;
2010-05-14 03:09:27 +00:00
bool oldInputDisplay = false ;
2010-06-07 15:41:52 +00: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 ; }
2006-07-29 05:46:15 +00:00
void FCEU_KillVirtualVideo ( void )
{
//mbg merge TODO 7/17/06 temporarily removed
2008-06-17 06:55:07 +00:00
//if(xbsave)
//{
// free(xbsave);
// xbsave=0;
//}
//if(XBuf)
//{
2006-07-29 05:46:15 +00:00
//UnmapViewOfFile(XBuf);
//CloseHandle(mapXBuf);
//mapXBuf=NULL;
2008-06-17 06:55:07 +00:00
//}
//if(XBackBuf)
//{
// free(XBackBuf);
// XBackBuf=0;
//}
2006-07-29 05:46:15 +00:00
}
2007-02-05 20:41:23 +00:00
/**
* Return : Flag that indicates whether the function was succesful or not .
*
* TODO : This function is Windows - only . It should probably be moved .
* */
2006-07-29 05:46:15 +00:00
int FCEU_InitVirtualVideo ( void )
{
2007-02-05 20:41:23 +00:00
if ( ! XBuf ) /* Some driver code may allocate XBuf externally. */
2008-06-17 06:55:07 +00:00
/* 256 bytes per scanline, * 240 scanline maximum, +16 for alignment,
*/
2007-02-05 20:41:23 +00:00
2008-06-17 06:55:07 +00:00
if ( ! ( XBuf = ( uint8 * ) ( FCEU_malloc ( 256 * 256 + 16 ) ) ) | |
! ( XBackBuf = ( uint8 * ) ( FCEU_malloc ( 256 * 256 + 16 ) ) ) )
{
return 0 ;
}
xbsave = XBuf ;
2007-02-05 20:41:23 +00:00
2008-06-17 06:55:07 +00:00
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 ;
2006-07-29 05:46:15 +00:00
}
# ifdef FRAMESKIP
void FCEU_PutImageDummy ( void )
{
2008-06-17 06:55:07 +00:00
ShowFPS ( ) ;
if ( GameInfo - > type ! = GIT_NSF )
{
FCEU_DrawNTSCControlBars ( XBuf ) ;
FCEU_DrawSaveStates ( XBuf ) ;
FCEU_DrawMovies ( XBuf ) ;
}
if ( guiMessage . howlong ) guiMessage . howlong - - ; /* DrawMessage() */
2006-07-29 05:46:15 +00:00
}
# endif
static int dosnapsave = 0 ;
void FCEUI_SaveSnapshot ( void )
{
2008-06-17 06:55:07 +00:00
dosnapsave = 1 ;
2006-07-29 05:46:15 +00:00
}
2008-05-26 01:55:45 +00:00
2010-06-07 04:26:16 +00:00
void FCEUI_SaveSnapshotAs ( void )
{
dosnapsave = 2 ;
}
2006-07-29 05:46:15 +00:00
static void ReallySnap ( void )
{
2008-05-27 04:40:03 +00:00
int x = SaveSnapshot ( ) ;
if ( ! x )
2010-05-16 04:18:49 +00:00
FCEU_DispMessage ( " Error saving screen snapshot. " , 0 ) ;
2008-05-27 04:40:03 +00:00
else
2010-05-16 04:18:49 +00:00
FCEU_DispMessage ( " Screen snapshot %d saved. " , 0 , x - 1 ) ;
2006-07-29 05:46:15 +00:00
}
void FCEU_PutImage ( void )
{
2010-06-07 15:41:52 +00:00
if ( dosnapsave = = 2 ) //Save screenshot as, currently only flagged & run by the Win32 build. //TODO SDL: implement this?
2010-06-07 04:26:16 +00:00
{
char nameo [ 512 ] ;
2010-06-07 15:41:52 +00:00
strcpy ( nameo , FCEUI_GetSnapshotAsName ( ) . c_str ( ) ) ;
if ( nameo )
2010-06-07 04:26:16 +00:00
{
SaveSnapshot ( nameo ) ;
FCEU_DispMessage ( " Snapshot Saved. " , 0 ) ;
}
dosnapsave = 0 ;
}
2008-05-27 04:40:03 +00:00
if ( GameInfo - > type = = GIT_NSF )
{
DrawNSF ( XBuf ) ;
2008-06-17 06:55:07 +00:00
2008-05-27 04:40:03 +00:00
//Save snapshot after NSF screen is drawn. Why would we want to do it before?
2010-06-07 04:26:16 +00:00
if ( dosnapsave = = 1 )
2008-05-27 04:40:03 +00:00
{
ReallySnap ( ) ;
dosnapsave = 0 ;
}
2012-10-21 16:40:04 +00:00
}
2008-05-27 04:40:03 +00:00
else
{
2008-08-10 02:43:54 +00:00
//Save backbuffer before overlay stuff is written.
if ( ! FCEUI_EmulationPaused ( ) )
memcpy ( XBackBuf , XBuf , 256 * 256 ) ;
2008-05-27 04:40:03 +00:00
//Some messages need to be displayed before the avi is dumped
DrawMessage ( true ) ;
2012-09-23 12:45:28 +00:00
# ifdef _S9XLUA_H
// Lua gui should draw before the avi is dumped.
2008-07-25 19:14:19 +00:00
FCEU_LuaGui ( XBuf ) ;
2012-09-23 12:45:28 +00:00
# endif
2008-07-25 19:14:19 +00:00
2011-09-23 18:09:40 +00:00
//Save snapshot
2010-06-07 04:26:16 +00:00
if ( dosnapsave = = 1 )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
ReallySnap ( ) ;
dosnapsave = 0 ;
}
2011-09-26 12:00:48 +00:00
if ( ! FCEUI_AviEnableHUDrecording ( ) ) snapAVI ( ) ;
2008-05-27 04:40:03 +00:00
if ( GameInfo - > type = = GIT_VSUNI )
FCEU_VSUniDraw ( XBuf ) ;
FCEU_DrawSaveStates ( XBuf ) ;
FCEU_DrawMovies ( XBuf ) ;
2008-07-10 02:17:42 +00:00
FCEU_DrawLagCounter ( XBuf ) ;
2008-05-27 04:40:03 +00:00
FCEU_DrawNTSCControlBars ( XBuf ) ;
FCEU_DrawRecordingStatus ( XBuf ) ;
2012-08-14 17:06:43 +00:00
ShowFPS ( ) ;
2008-05-27 04:40:03 +00:00
}
2008-06-17 06:55:07 +00:00
2008-06-08 10:22:33 +00:00
if ( FCEUD_ShouldDrawInputAids ( ) )
FCEU_DrawInput ( XBuf ) ;
2008-05-27 04:40:03 +00:00
//Fancy input display code
if ( input_display )
{
2010-05-16 02:34:51 +00:00
extern uint32 JSAutoHeld ;
2010-05-16 14:23:23 +00:00
uint32 held ;
2010-05-16 02:34:51 +00:00
2012-10-21 16:40:04 +00:00
int controller , c , ci , color ;
2008-05-27 04:40:03 +00:00
int i , j ;
2010-05-16 03:18:17 +00: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-10-21 16:40:04 +00:00
2010-05-14 03:09:27 +00:00
uint8 * t = XBuf + ( FSettings . LastSLine - 9 ) * 256 + 20 ; //mbg merge 7/17/06 changed t to uint8*
2008-05-27 04:40:03 +00: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 + + )
2008-12-03 01:33:05 +00:00
t [ i + j * 256 ] = ( t [ i + j * 256 ] & 0x30 ) | 0xC1 ;
2008-05-27 04:40:03 +00:00
for ( i = 3 ; i < 6 ; i + + )
for ( j = 3 ; j < 6 ; j + + )
2008-12-03 01:33:05 +00:00
t [ i + j * 256 ] = 0xCF ;
2008-05-27 04:40:03 +00:00
c = cur_input_display > > ( controller * 8 ) ;
2010-05-13 19:33:27 +00:00
// This doesn't work in anything except windows for now.
// It doesn't get set anywhere in other ports.
2010-05-13 21:08:37 +00:00
# ifdef WIN32
2010-05-14 03:09:27 +00:00
if ( ! oldInputDisplay ) ci = FCEUMOV_Mode ( MOVIEMODE_PLAY ) ? 0 : GetGamepadPressedImmediate ( ) > > ( controller * 8 ) ;
else ci = 0 ;
2010-05-16 03:18:17 +00:00
2010-05-16 14:23:23 +00:00
if ( ! oldInputDisplay & & ! FCEUMOV_Mode ( MOVIEMODE_PLAY ) ) held = ( JSAutoHeld > > ( controller * 8 ) ) ;
2010-05-16 03:18:17 +00:00
else held = 0 ;
2010-05-13 21:08:37 +00:00
# else
// Put other port info here
ci = 0 ;
2010-05-16 03:18:17 +00:00
held = 0 ;
2010-05-13 21:08:37 +00:00
# endif
2010-05-13 19:33:27 +00:00
2010-05-16 03:18:17 +00:00
//adelikat: I apologize to anyone who ever sifts through this color assignment
2008-05-27 04:40:03 +00:00
//A
2010-05-16 03:18:17 +00:00
if ( held & 1 ) { //If auto-hold
2012-10-21 16:40:04 +00:00
if ( ! ( ci & 1 ) ) color = ahold ;
else
2010-05-16 03:18:17 +00: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 ;
}
2008-05-27 04:40:03 +00:00
for ( i = 0 ; i < 4 ; i + + )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
for ( j = 0 ; j < 4 ; j + + )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
if ( i % 3 = = 0 & & j % 3 = = 0 )
continue ;
t [ 30 + 4 * 256 + i + j * 256 ] = color ;
2006-07-29 05:46:15 +00:00
}
2008-05-27 04:40:03 +00:00
}
//B
2010-05-16 03:18:17 +00:00
if ( held & 2 ) { //If auto-hold
2012-10-21 16:40:04 +00:00
if ( ! ( ci & 2 ) ) color = ahold ;
else
2010-05-16 03:18:17 +00: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 ;
}
2008-05-27 04:40:03 +00:00
for ( i = 0 ; i < 4 ; i + + )
{
for ( j = 0 ; j < 4 ; j + + )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
if ( i % 3 = = 0 & & j % 3 = = 0 )
continue ;
t [ 24 + 4 * 256 + i + j * 256 ] = color ;
2006-07-29 05:46:15 +00:00
}
2008-05-27 04:40:03 +00:00
}
//Select
2010-05-16 03:18:17 +00:00
if ( held & 4 ) { //If auto-hold
2012-10-21 16:40:04 +00:00
if ( ! ( ci & 4 ) ) color = ahold ;
else
2010-05-16 03:18:17 +00: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 ;
}
2008-05-27 04:40:03 +00:00
for ( i = 0 ; i < 4 ; i + + )
{
t [ 11 + 5 * 256 + i ] = color ;
t [ 11 + 6 * 256 + i ] = color ;
}
//Start
2010-05-16 03:18:17 +00:00
if ( held & 8 ) { //If auto-hold
2012-10-21 16:40:04 +00:00
if ( ! ( ci & 8 ) ) color = ahold ;
else
2010-05-16 03:18:17 +00: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 ;
}
2008-05-27 04:40:03 +00:00
for ( i = 0 ; i < 4 ; i + + )
{
t [ 17 + 5 * 256 + i ] = color ;
t [ 17 + 6 * 256 + i ] = color ;
}
//Up
2010-05-16 03:18:17 +00:00
if ( held & 16 ) { //If auto-hold
2012-10-21 16:40:04 +00:00
if ( ! ( ci & 16 ) ) color = ahold ;
else
2010-05-16 03:18:17 +00: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 ;
}
2008-05-27 04:40:03 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
t [ 3 + i + 256 * j ] = color ;
2006-07-29 05:46:15 +00:00
}
2008-05-27 04:40:03 +00:00
}
//Down
2010-05-16 03:18:17 +00:00
if ( held & 32 ) { //If auto-hold
2012-10-21 16:40:04 +00:00
if ( ! ( ci & 32 ) ) color = ahold ;
2010-05-16 04:18:49 +00:00
else
2010-05-16 03:18:17 +00:00
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 ;
}
2008-05-27 04:40:03 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
t [ 3 + i + 256 * j + 6 * 256 ] = color ;
2006-07-29 05:46:15 +00:00
}
2008-05-27 04:40:03 +00:00
}
//Left
2010-05-16 03:18:17 +00:00
if ( held & 64 ) { //If auto-hold
2012-10-21 16:40:04 +00:00
if ( ! ( ci & 64 ) ) color = ahold ;
else
2010-05-16 03:18:17 +00: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 ;
}
2008-05-27 04:40:03 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
t [ 3 * 256 + i + 256 * j ] = color ;
2006-07-29 05:46:15 +00:00
}
2008-05-27 04:40:03 +00:00
}
//Right
2010-05-16 03:18:17 +00:00
if ( held & 128 ) { //If auto-hold
2012-10-21 16:40:04 +00:00
if ( ! ( ci & 128 ) ) color = ahold ;
else
2010-05-16 03:18:17 +00: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 ;
}
2008-05-27 04:40:03 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
t [ 6 + 3 * 256 + i + 256 * j ] = color ;
2006-07-29 05:46:15 +00:00
}
}
}
2008-05-27 04:40:03 +00:00
}
2011-09-26 12:00:48 +00:00
2011-09-23 18:09:40 +00:00
if ( FCEUI_AviEnableHUDrecording ( ) )
{
if ( FCEUI_AviDisableMovieMessages ( ) )
{
snapAVI ( ) ;
DrawMessage ( false ) ;
} else
{
DrawMessage ( false ) ;
snapAVI ( ) ;
}
} else DrawMessage ( false ) ;
2011-09-26 12:00:48 +00:00
2011-09-23 18:09:40 +00:00
}
void snapAVI ( )
{
//Update AVI
if ( ! FCEUI_EmulationPaused ( ) )
FCEUI_AviVideoUpdate ( XBuf ) ;
2006-07-29 05:46:15 +00:00
}
2008-05-27 04:40:03 +00:00
void FCEU_DispMessageOnMovie ( char * format , . . . )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
va_list ap ;
2006-07-29 05:46:15 +00:00
2008-05-27 04:40:03 +00:00
va_start ( ap , format ) ;
2008-08-12 03:35:54 +00:00
vsnprintf ( guiMessage . errmsg , sizeof ( guiMessage . errmsg ) , format , ap ) ;
2008-05-27 04:40:03 +00:00
va_end ( ap ) ;
guiMessage . howlong = 180 ;
guiMessage . isMovieMessage = true ;
2010-05-16 04:18:49 +00:00
guiMessage . linesFromBottom = 0 ;
2010-03-02 03:34:15 +00:00
if ( FCEUI_AviIsRecording ( ) & & FCEUI_AviDisableMovieMessages ( ) )
guiMessage . howlong = 0 ;
2008-05-27 04:40:03 +00:00
}
2010-05-16 04:18:49 +00:00
void FCEU_DispMessage ( char * format , int disppos = 0 , . . . )
2008-05-27 04:40:03 +00:00
{
va_list ap ;
2006-07-29 05:46:15 +00:00
2010-05-16 04:18:49 +00:00
va_start ( ap , disppos ) ;
2008-08-12 03:35:54 +00:00
vsnprintf ( guiMessage . errmsg , sizeof ( guiMessage . errmsg ) , format , ap ) ;
2012-11-02 13:39:46 +00:00
va_end ( ap ) ;
2011-09-30 19:49:21 +00:00
// also log messages
char temp [ 2048 ] ;
2012-11-02 13:39:46 +00:00
va_start ( ap , disppos ) ;
2011-09-30 19:49:21 +00:00
vsnprintf ( temp , sizeof ( temp ) , format , ap ) ;
2012-11-02 13:39:46 +00:00
va_end ( ap ) ;
2011-09-30 19:49:21 +00:00
strcat ( temp , " \n " ) ;
FCEU_printf ( temp ) ;
2006-07-29 05:46:15 +00:00
2008-05-27 04:40:03 +00:00
guiMessage . howlong = 180 ;
guiMessage . isMovieMessage = false ;
2010-05-16 04:18:49 +00:00
guiMessage . linesFromBottom = disppos ;
2010-03-02 03:34:15 +00:00
//adelikat: Pretty sure this code fails, Movie playback stopped is done with FCEU_DispMessageOnMovie()
2008-10-25 12:36:03 +00: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
2006-07-29 05:46:15 +00:00
}
2008-05-27 04:40:03 +00:00
void FCEU_ResetMessages ( )
2006-07-29 05:46:15 +00:00
{
2008-05-27 04:40:03 +00:00
guiMessage . howlong = 0 ;
guiMessage . isMovieMessage = false ;
2010-05-16 04:18:49 +00:00
guiMessage . linesFromBottom = 0 ;
2006-07-29 05:46:15 +00:00
}
static int WritePNGChunk ( FILE * fp , uint32 size , char * type , uint8 * data )
{
2008-06-17 06:55:07 +00:00
uint32 crc ;
2006-07-29 05:46:15 +00:00
2008-06-17 06:55:07 +00:00
uint8 tempo [ 4 ] ;
2006-07-29 05:46:15 +00:00
2008-06-17 06:55:07 +00:00
tempo [ 0 ] = size > > 24 ;
tempo [ 1 ] = size > > 16 ;
tempo [ 2 ] = size > > 8 ;
tempo [ 3 ] = size ;
2006-07-29 05:46:15 +00:00
2008-06-17 06:55:07 +00:00
if ( fwrite ( tempo , 4 , 1 , fp ) ! = 1 )
return 0 ;
if ( fwrite ( type , 4 , 1 , fp ) ! = 1 )
return 0 ;
2006-07-29 05:46:15 +00:00
2008-06-17 06:55:07 +00:00
if ( size )
if ( fwrite ( data , 1 , size , fp ) ! = size )
return 0 ;
2006-07-29 05:46:15 +00:00
2008-06-17 06:55:07 +00:00
crc = CalcCRC32 ( 0 , ( uint8 * ) type , 4 ) ;
if ( size )
crc = CalcCRC32 ( crc , data , size ) ;
2006-07-29 05:46:15 +00:00
2008-06-17 06:55:07 +00:00
tempo [ 0 ] = crc > > 24 ;
tempo [ 1 ] = crc > > 16 ;
tempo [ 2 ] = crc > > 8 ;
tempo [ 3 ] = crc ;
2006-07-29 05:46:15 +00:00
2008-06-17 06:55:07 +00:00
if ( fwrite ( tempo , 4 , 1 , fp ) ! = 1 )
return 0 ;
return 1 ;
2006-07-29 05:46:15 +00:00
}
2010-05-10 16:52:27 +00:00
uint32 GetScreenPixel ( int x , int y , bool usebackup ) {
2012-10-21 16:40:04 +00:00
2010-05-10 07:20:55 +00:00
uint8 r , g , b ;
if ( ( ( x < 0 ) | | ( x > 255 ) ) | | ( ( y < 0 ) | | ( y > 255 ) ) )
return - 1 ;
2010-05-10 16:52:27 +00:00
if ( usebackup )
FCEUD_GetPalette ( XBackBuf [ ( y * 256 ) + x ] , & r , & g , & b ) ;
else
FCEUD_GetPalette ( XBuf [ ( y * 256 ) + x ] , & r , & g , & b ) ;
2010-05-10 07:20:55 +00:00
return ( ( int ) ( r ) < < 16 ) | ( ( int ) ( g ) < < 8 ) | ( int ) ( b ) ;
}
2010-05-10 16:52:27 +00:00
int GetScreenPixelPalette ( int x , int y , bool usebackup ) {
2010-05-10 07:20:55 +00:00
if ( ( ( x < 0 ) | | ( x > 255 ) ) | | ( ( y < 0 ) | | ( y > 255 ) ) )
return - 1 ;
2010-05-10 16:52:27 +00:00
if ( usebackup )
return XBackBuf [ ( y * 256 ) + x ] & 0x3f ;
else
return XBuf [ ( y * 256 ) + x ] & 0x3f ;
2010-05-10 07:20:55 +00:00
}
2006-07-29 05:46:15 +00:00
int SaveSnapshot ( void )
{
2009-02-07 17:55:10 +00:00
unsigned int lastu = 0 ;
2008-06-17 06:55:07 +00:00
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 ;
for ( u = lastu ; u < 99999 ; u + + )
{
2011-06-09 12:17:47 +00:00
pp = FCEUD_UTF8fopen ( FCEU_MakeFName ( FCEUMKF_SNAP , u , " png " ) . c_str ( ) , " rb " ) ;
2008-06-17 06:55:07 +00:00
if ( pp = = NULL ) break ;
fclose ( pp ) ;
}
lastu = u ;
2011-06-09 12:17:47 +00:00
if ( ! ( pp = FCEUD_UTF8fopen ( FCEU_MakeFName ( FCEUMKF_SNAP , u , " png " ) . c_str ( ) , " wb " ) ) )
2008-06-17 06:55:07 +00:00
{
2010-08-12 06:27:06 +00:00
free ( compmem ) ;
2008-06-17 06:55:07 +00:00
return 0 ;
}
2011-06-09 12:17:47 +00:00
2008-06-17 06:55:07 +00: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-09-19 00:00:38 +00:00
if ( ! ( mal = mork = dest = ( uint8 * ) FCEU_dmalloc ( ( totallines < < 8 ) + totallines ) ) )
2008-06-17 06:55:07 +00: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-10-21 16:40:04 +00:00
* dest = * tmp ;
2008-06-17 06:55:07 +00: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-06-07 04:26:16 +00:00
PNGerr :
if ( compmem )
free ( compmem ) ;
if ( pp )
fclose ( pp ) ;
return ( 0 ) ;
}
2010-06-07 15:41:52 +00:00
//overloaded SaveSnapshot for "Savesnapshot As" function
2010-06-07 04:26:16 +00:00
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 " ) ) )
{
2010-08-12 06:27:06 +00:00
free ( compmem ) ;
2010-06-07 04:26:16 +00:00
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-09-19 00:00:38 +00:00
if ( ! ( mal = mork = dest = ( uint8 * ) FCEU_dmalloc ( ( totallines < < 8 ) + totallines ) ) )
2010-06-07 04:26:16 +00: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-10-21 16:40:04 +00:00
* dest = * tmp ;
2010-06-07 04:26:16 +00: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 ;
2008-06-17 06:55:07 +00:00
PNGerr :
if ( compmem )
free ( compmem ) ;
if ( pp )
fclose ( pp ) ;
return ( 0 ) ;
2006-07-29 05:46:15 +00:00
}
uint64 FCEUD_GetTime ( void ) ;
uint64 FCEUD_GetTimeFreq ( void ) ;
2012-08-10 15:50:57 +00:00
bool Show_FPS = false ;
// Control whether the frames per second of the emulation is rendered.
2012-08-12 16:22:22 +00:00
bool FCEUI_ShowFPS ( )
{
return Show_FPS ;
2012-09-26 20:19:01 +00:00
}
2012-08-12 16:22:22 +00:00
void FCEUI_SetShowFPS ( bool showFPS )
2012-08-10 15:50:57 +00:00
{
Show_FPS = showFPS ;
2012-09-26 20:19:01 +00:00
}
void FCEUI_ToggleShowFPS ( )
{
Show_FPS ^ = 1 ;
}
2006-07-29 05:46:15 +00:00
static uint64 boop [ 60 ] ;
static int boopcount = 0 ;
void ShowFPS ( void )
2012-10-21 16:40:04 +00:00
{
2012-08-10 15:50:57 +00:00
if ( Show_FPS = = false )
return ;
2008-06-17 06:55:07 +00:00
uint64 da = FCEUD_GetTime ( ) - boop [ boopcount ] ;
char fpsmsg [ 16 ] ;
int booplimit = PAL ? 50 : 60 ;
boop [ boopcount ] = FCEUD_GetTime ( ) ;
2012-09-26 20:19:01 +00:00
sprintf ( fpsmsg , " %.1f " , ( double ) booplimit / ( ( double ) da / FCEUD_GetTimeFreq ( ) ) ) ;
DrawTextTrans ( XBuf + ( ( 256 - ClipSidesOffset ) - 40 ) + ( FSettings . FirstSLine + 4 ) * 256 , 256 , ( uint8 * ) fpsmsg , 0xA0 ) ;
2008-06-17 06:55:07 +00:00
// It's not averaging FPS over exactly 1 second, but it's close enough.
boopcount = ( boopcount + 1 ) % booplimit ;
2006-07-29 05:46:15 +00:00
}