2012-04-16 08:18:41 +00:00
using System ;
using System.Runtime.InteropServices ;
using System.Text ;
using System.Threading ;
using System.Collections.Generic ;
using System.Windows.Forms ;
using System.Drawing ;
using System.Drawing.Drawing2D ;
using System.Drawing.Imaging ;
2012-06-10 02:19:36 +00:00
//using dx=SlimDX;
//using d3d=SlimDX.Direct3D9;
2012-04-16 08:18:41 +00:00
namespace BizHawk.MultiClient
{
2012-06-10 02:19:36 +00:00
/// <summary>
/// encapsulates thread-safe concept of pending/current display surfaces, reusing buffers where matching
/// sizes are available and keeping them cleaned up when they dont seem like theyll need to be used anymore
/// </summary>
class SwappableDisplaySurfaceSet
{
DisplaySurface Pending , Current ;
Queue < DisplaySurface > ReleasedSurfaces = new Queue < DisplaySurface > ( ) ;
/// <summary>
/// retrieves a surface with the specified size, reusing an old buffer if available and clearing if requested
/// </summary>
public DisplaySurface AllocateSurface ( int width , int height , bool needsClear = true )
{
for ( ; ; )
{
DisplaySurface trial ;
lock ( this )
{
if ( ReleasedSurfaces . Count = = 0 ) break ;
trial = ReleasedSurfaces . Dequeue ( ) ;
}
if ( trial . Width = = width & & trial . Height = = height )
{
if ( needsClear ) trial . Clear ( ) ;
return trial ;
}
trial . Dispose ( ) ;
}
return new DisplaySurface ( width , height ) ;
}
/// <summary>
/// sets the provided buffer as pending. takes control of the supplied buffer
/// </summary>
public void SetPending ( DisplaySurface newPending )
{
lock ( this )
{
if ( Pending ! = null ) ReleasedSurfaces . Enqueue ( Pending ) ;
Pending = newPending ;
}
}
public void ReleaseSurface ( DisplaySurface surface )
{
lock ( this ) ReleasedSurfaces . Enqueue ( surface ) ;
}
/// <summary>
/// returns the current buffer, making the most recent pending buffer (if there is such) as the new current first.
/// </summary>
public DisplaySurface GetCurrent ( )
{
lock ( this )
{
if ( Pending ! = null )
{
if ( Current ! = null ) ReleasedSurfaces . Enqueue ( Current ) ;
Current = Pending ;
Pending = null ;
}
}
return Current ;
}
}
2012-04-16 08:18:41 +00:00
public interface IDisplayFilter
{
/// <summary>
/// describes how this filter will respond to an input format
/// </summary>
DisplayFilterAnalysisReport Analyze ( Size sourceSize ) ;
/// <summary>
/// runs the filter
/// </summary>
DisplaySurface Execute ( DisplaySurface surface ) ;
}
public class DisplayFilterAnalysisReport
{
public bool Success ;
public Size OutputSize ;
}
2012-06-10 02:19:36 +00:00
interface IDisplayDriver
{
}
class Direct3DDisplayDriver : IDisplayDriver
{
}
2012-06-10 19:52:54 +00:00
public unsafe class DisplaySurface : IDisposable
2012-04-16 08:18:41 +00:00
{
2012-06-10 19:52:54 +00:00
Bitmap bmp ;
BitmapData bmpdata ;
int [ ] pixels ;
public unsafe void Clear ( )
{
FromBitmap ( false ) ;
Util . memset ( PixelPtr , 0 , Stride * Height ) ;
}
public Bitmap PeekBitmap ( )
{
ToBitmap ( ) ;
return bmp ;
}
2012-04-16 08:18:41 +00:00
/// <summary>
/// returns a Graphics object used to render to this surface. be sure to dispose it!
/// </summary>
public Graphics GetGraphics ( )
{
2012-06-10 19:52:54 +00:00
ToBitmap ( ) ;
2012-04-16 08:18:41 +00:00
return Graphics . FromImage ( bmp ) ;
}
2012-06-10 19:52:54 +00:00
public unsafe void ToBitmap ( bool copy = true )
2012-04-16 08:18:41 +00:00
{
2012-06-10 19:52:54 +00:00
if ( isBitmap ) return ;
isBitmap = true ;
if ( bmp = = null )
{
bmp = new Bitmap ( Width , Height , PixelFormat . Format32bppArgb ) ;
}
if ( copy )
{
bmpdata = bmp . LockBits ( new Rectangle ( 0 , 0 , Width , Height ) , ImageLockMode . WriteOnly , PixelFormat . Format32bppArgb ) ;
int w = Width ;
int h = Height ;
int stride = bmpdata . Stride / 4 ;
int * bmpbuf = ( int * ) bmpdata . Scan0 . ToPointer ( ) ;
for ( int y = 0 , i = 0 ; y < h ; y + + )
for ( int x = 0 ; x < w ; x + + )
bmpbuf [ y * stride + x ] = pixels [ i + + ] ;
bmp . UnlockBits ( bmpdata ) ;
}
2012-04-16 08:18:41 +00:00
}
2012-06-10 19:52:54 +00:00
public bool IsBitmap { get { return isBitmap ; } }
bool isBitmap = false ;
public unsafe void FromBitmap ( bool copy = true )
2012-04-16 08:18:41 +00:00
{
2012-06-10 19:52:54 +00:00
if ( ! isBitmap ) return ;
isBitmap = false ;
if ( copy )
{
bmpdata = bmp . LockBits ( new Rectangle ( 0 , 0 , Width , Height ) , ImageLockMode . ReadOnly , PixelFormat . Format32bppArgb ) ;
int w = Width ;
int h = Height ;
int stride = bmpdata . Stride / 4 ;
int * bmpbuf = ( int * ) bmpdata . Scan0 . ToPointer ( ) ;
for ( int y = 0 , i = 0 ; y < h ; y + + )
for ( int x = 0 ; x < w ; x + + )
pixels [ i + + ] = bmpbuf [ y * stride + x ] ;
bmp . UnlockBits ( bmpdata ) ;
}
2012-04-16 08:18:41 +00:00
}
2012-06-10 19:52:54 +00:00
2012-06-10 02:19:36 +00:00
public static DisplaySurface DisplaySurfaceWrappingBitmap ( Bitmap bmp )
{
DisplaySurface ret = new DisplaySurface ( ) ;
ret . Width = bmp . Width ;
ret . Height = bmp . Height ;
ret . bmp = bmp ;
2012-06-10 19:52:54 +00:00
ret . isBitmap = true ;
2012-06-10 02:19:36 +00:00
return ret ;
}
private DisplaySurface ( )
{
}
2012-04-16 08:18:41 +00:00
public DisplaySurface ( int width , int height )
{
//can't create a bitmap with zero dimensions, so for now, just bump it up to one
if ( width = = 0 ) width = 1 ;
2012-04-16 22:12:11 +00:00
if ( height = = 0 ) height = 1 ;
Width = width ;
Height = height ;
2012-06-10 19:52:54 +00:00
pixels = new int [ width * height ] ;
LockPixels ( ) ;
}
public int * PixelPtr { get { return ( int * ) ptr ; } }
public IntPtr PixelIntPtr { get { return new IntPtr ( ptr ) ; } }
public int Stride { get { return Width * 4 ; } }
public int OffsetOf ( int x , int y ) { return y * Stride + x * 4 ; }
void * ptr ;
GCHandle handle ;
void LockPixels ( )
{
UnlockPixels ( ) ;
handle = GCHandle . Alloc ( pixels , GCHandleType . Pinned ) ;
ptr = handle . AddrOfPinnedObject ( ) . ToPointer ( ) ;
}
void UnlockPixels ( )
{
if ( handle . IsAllocated ) handle . Free ( ) ;
2012-04-16 08:18:41 +00:00
}
/// <summary>
/// returns a new surface
/// </summary>
/// <param name="xpad"></param>
/// <param name="ypad"></param>
/// <returns></returns>
2012-06-10 19:52:54 +00:00
public DisplaySurface ToPaddedSurface ( int xpad0 , int ypad0 , int xpad1 , int ypad1 )
{
2012-07-15 07:38:36 +00:00
int new_width = Width + xpad0 + xpad1 ;
int new_height = Height + ypad0 + ypad1 ;
DisplaySurface ret = new DisplaySurface ( new_width , new_height ) ;
int * dptr = ret . PixelPtr ;
int * sptr = PixelPtr ;
int dstride = ret . Stride / 4 ;
int sstride = Stride / 4 ;
for ( int y = 0 ; y < Height ; y + + )
for ( int x = 0 ; x < Width ; x + + )
{
dptr [ ( y + ypad0 ) * dstride + x + xpad0 ] = sptr [ y * sstride + x ] ;
}
return ret ;
2012-04-16 08:18:41 +00:00
}
public int Width { get ; private set ; }
public int Height { get ; private set ; }
public void Dispose ( )
{
if ( bmp ! = null )
bmp . Dispose ( ) ;
bmp = null ;
2012-06-10 19:52:54 +00:00
UnlockPixels ( ) ;
2012-04-16 08:18:41 +00:00
}
2012-06-10 19:52:54 +00:00
//public unsafe int[] ToIntArray() { }
2012-04-16 08:18:41 +00:00
2012-06-10 19:52:54 +00:00
public void AcceptIntArray ( int [ ] newpixels )
2012-04-16 08:18:41 +00:00
{
2012-06-10 19:52:54 +00:00
FromBitmap ( false ) ;
UnlockPixels ( ) ;
pixels = newpixels ;
LockPixels ( ) ;
2012-04-16 08:18:41 +00:00
}
}
public class OSDManager
{
public string FPS { get ; set ; }
public string MT { get ; set ; }
2012-06-10 23:27:30 +00:00
IBlitterFont MessageFont ;
IBlitterFont AlertFont ;
2012-04-16 08:18:41 +00:00
public void Dispose ( )
{
2012-06-10 23:27:30 +00:00
}
public void Begin ( IBlitter blitter )
{
MessageFont = blitter . GetFontType ( "MessageFont" ) ;
AlertFont = blitter . GetFontType ( "AlertFont" ) ;
2012-04-16 08:18:41 +00:00
}
2012-06-10 23:27:30 +00:00
public System . Drawing . Color FixedMessagesColor { get { return System . Drawing . Color . FromArgb ( Global . Config . MessagesColor ) ; } }
public System . Drawing . Color FixedAlertMessageColor { get { return System . Drawing . Color . FromArgb ( Global . Config . AlertMessageColor ) ; } }
2012-04-16 08:18:41 +00:00
public OSDManager ( )
{
}
2012-06-10 23:27:30 +00:00
private float GetX ( IBlitter g , int x , int anchor , IBlitterFont font , string message )
2012-04-16 08:18:41 +00:00
{
var size = g . MeasureString ( message , font ) ;
//Rectangle rect = g.MeasureString(Sprite, message, new DrawTextFormat());
switch ( anchor )
{
default :
case 0 : //Top Left
case 2 : //Bottom Left
return x ;
case 1 : //Top Right
case 3 : //Bottom Right
return g . ClipBounds . Width - x - size . Width ;
}
}
2012-06-10 23:27:30 +00:00
private float GetY ( IBlitter g , int y , int anchor , IBlitterFont font , string message )
2012-04-16 08:18:41 +00:00
{
var size = g . MeasureString ( message , font ) ;
switch ( anchor )
{
default :
case 0 : //Top Left
case 1 : //Top Right
return y ;
case 2 : //Bottom Left
case 3 : //Bottom Right
return g . ClipBounds . Height - y - size . Height ;
}
}
private string MakeFrameCounter ( )
{
2012-09-03 19:42:53 +00:00
if ( Global . MovieSession . Movie . IsFinished )
2012-04-16 08:18:41 +00:00
{
2012-09-03 19:42:53 +00:00
return Global . Emulator . Frame . ToString ( ) + "/" + Global . MovieSession . Movie . Frames . ToString ( ) + " (Finished)" ;
2012-04-16 08:18:41 +00:00
}
2012-09-03 19:42:53 +00:00
else if ( Global . MovieSession . Movie . IsPlaying )
2012-04-16 08:18:41 +00:00
{
2012-09-03 19:42:53 +00:00
return Global . Emulator . Frame . ToString ( ) + "/" + Global . MovieSession . Movie . Frames . ToString ( ) ;
2012-04-16 08:18:41 +00:00
}
2012-09-03 19:42:53 +00:00
else if ( Global . MovieSession . Movie . IsRecording )
{
2012-04-16 08:18:41 +00:00
return Global . Emulator . Frame . ToString ( ) ;
2012-09-03 19:42:53 +00:00
}
2012-04-16 08:18:41 +00:00
else
{
return Global . Emulator . Frame . ToString ( ) ;
}
}
private string MakeLagCounter ( )
{
return Global . Emulator . LagCount . ToString ( ) ;
}
private List < UIMessage > messages = new List < UIMessage > ( 5 ) ;
private List < UIDisplay > GUITextList = new List < UIDisplay > ( ) ;
public void AddMessage ( string message )
{
messages . Add ( new UIMessage { Message = message , ExpireAt = DateTime . Now + TimeSpan . FromSeconds ( 2 ) } ) ;
}
2012-06-10 23:27:30 +00:00
public void AddGUIText ( string message , int x , int y , bool alert , Color BackGround , Color ForeColor , int anchor )
2012-04-16 08:18:41 +00:00
{
2012-06-10 23:27:30 +00:00
GUITextList . Add ( new UIDisplay { Message = message , X = x , Y = y , BackGround = BackGround , ForeColor = ForeColor , Alert = alert , Anchor = anchor } ) ;
2012-04-16 08:18:41 +00:00
}
public void ClearGUIText ( )
{
GUITextList . Clear ( ) ;
}
2012-06-10 23:27:30 +00:00
public void DrawMessages ( IBlitter g )
2012-04-16 08:18:41 +00:00
{
2012-08-28 01:48:01 +00:00
if ( ! Global . ClientControls [ "MaxTurbo" ] )
2012-04-16 08:18:41 +00:00
{
2012-08-28 01:48:01 +00:00
messages . RemoveAll ( m = > DateTime . Now > m . ExpireAt ) ;
int line = 1 ;
2012-09-26 04:00:42 +00:00
if ( Global . Config . StackOSDMessages )
2012-06-10 23:27:30 +00:00
{
2012-09-26 04:00:42 +00:00
for ( int i = messages . Count - 1 ; i > = 0 ; i - - , line + + )
2012-09-25 04:04:54 +00:00
{
2012-09-26 04:00:42 +00:00
float x = GetX ( g , Global . Config . DispMessagex , Global . Config . DispMessageanchor , MessageFont , messages [ i ] . Message ) ;
float y = GetY ( g , Global . Config . DispMessagey , Global . Config . DispMessageanchor , MessageFont , messages [ i ] . Message ) ;
if ( Global . Config . DispMessageanchor < 2 )
{
y + = ( ( line - 1 ) * 18 ) ;
}
else
{
y - = ( ( line - 1 ) * 18 ) ;
}
g . DrawString ( messages [ i ] . Message , MessageFont , Color . Black , x + 2 , y + 2 ) ;
g . DrawString ( messages [ i ] . Message , MessageFont , FixedMessagesColor , x , y ) ;
2012-09-25 04:04:54 +00:00
}
2012-09-26 04:00:42 +00:00
}
else
{
if ( messages . Count > 0 )
2012-09-25 04:04:54 +00:00
{
2012-09-26 04:00:42 +00:00
int i = messages . Count - 1 ;
float x = GetX ( g , Global . Config . DispMessagex , Global . Config . DispMessageanchor , MessageFont , messages [ i ] . Message ) ;
float y = GetY ( g , Global . Config . DispMessagey , Global . Config . DispMessageanchor , MessageFont , messages [ i ] . Message ) ;
if ( Global . Config . DispMessageanchor < 2 )
{
y + = ( ( line - 1 ) * 18 ) ;
}
else
{
y - = ( ( line - 1 ) * 18 ) ;
}
g . DrawString ( messages [ i ] . Message , MessageFont , Color . Black , x + 2 , y + 2 ) ;
g . DrawString ( messages [ i ] . Message , MessageFont , FixedMessagesColor , x , y ) ;
2012-09-25 04:04:54 +00:00
}
2012-06-10 23:27:30 +00:00
}
2012-09-26 04:00:42 +00:00
2012-08-28 01:48:01 +00:00
for ( int x = 0 ; x < GUITextList . Count ; x + + )
2012-06-10 23:27:30 +00:00
{
2012-08-28 01:48:01 +00:00
try
{
float posx = GetX ( g , GUITextList [ x ] . X , GUITextList [ x ] . Anchor , MessageFont , GUITextList [ x ] . Message ) ;
float posy = GetY ( g , GUITextList [ x ] . Y , GUITextList [ x ] . Anchor , MessageFont , GUITextList [ x ] . Message ) ;
g . DrawString ( GUITextList [ x ] . Message , MessageFont , GUITextList [ x ] . BackGround , posx + 2 , posy + 2 ) ;
//g.DrawString(GUITextList[x].Message, MessageFont, Color.Gray, posx + 1, posy + 1);
if ( GUITextList [ x ] . Alert )
g . DrawString ( GUITextList [ x ] . Message , MessageFont , FixedMessagesColor , posx , posy ) ;
else
g . DrawString ( GUITextList [ x ] . Message , MessageFont , GUITextList [ x ] . ForeColor , posx , posy ) ;
}
catch ( Exception )
{
return ;
}
2012-06-10 23:27:30 +00:00
}
}
2012-04-16 08:18:41 +00:00
}
public string MakeInputDisplay ( )
{
StringBuilder s ;
2012-09-05 02:07:30 +00:00
if ( ! Global . MovieSession . Movie . IsActive | | Global . MovieSession . Movie . IsFinished )
2012-09-03 19:42:53 +00:00
{
2012-04-16 08:18:41 +00:00
s = new StringBuilder ( Global . GetOutputControllersAsMnemonic ( ) ) ;
2012-09-03 19:42:53 +00:00
}
2012-04-16 08:18:41 +00:00
else
2012-09-03 19:42:53 +00:00
{
s = new StringBuilder ( Global . MovieSession . Movie . GetInput ( Global . Emulator . Frame - 1 ) ) ;
}
s . Replace ( "." , " " ) . Replace ( "|" , "" ) . Replace ( "l" , "" ) ; //Note: if l is ever a mnemonic this will squash it. But this is done because on the NES core I put l in the command mnemonic to indicate lag (was a bad a idea)
2012-04-16 20:19:08 +00:00
2012-04-16 08:18:41 +00:00
return s . ToString ( ) ;
}
public string MakeRerecordCount ( )
{
2012-09-03 19:42:53 +00:00
if ( Global . MovieSession . Movie . IsActive )
{
2012-04-16 08:18:41 +00:00
return "Rerecord Count: " + Global . MovieSession . Movie . Rerecords . ToString ( ) ;
2012-09-03 19:42:53 +00:00
}
2012-04-16 08:18:41 +00:00
else
2012-09-03 19:42:53 +00:00
{
2012-04-16 08:18:41 +00:00
return "" ;
2012-09-03 19:42:53 +00:00
}
2012-04-16 08:18:41 +00:00
}
/// <summary>
/// Display all screen info objects like fps, frame counter, lag counter, and input display
/// </summary>
2012-06-10 23:27:30 +00:00
public void DrawScreenInfo ( IBlitter g )
2012-04-16 08:18:41 +00:00
{
if ( Global . Config . DisplayFrameCounter )
{
string message = MakeFrameCounter ( ) ;
float x = GetX ( g , Global . Config . DispFrameCx , Global . Config . DispFrameanchor , MessageFont , message ) ;
float y = GetY ( g , Global . Config . DispFrameCy , Global . Config . DispFrameanchor , MessageFont , message ) ;
2012-06-10 23:27:30 +00:00
g . DrawString ( message , MessageFont , Color . Black , x + 1 , y + 1 ) ;
g . DrawString ( message , MessageFont , Color . FromArgb ( Global . Config . MessagesColor ) , x , y ) ;
2012-04-16 08:18:41 +00:00
}
if ( Global . Config . DisplayInput )
{
string input = MakeInputDisplay ( ) ;
Color c ;
float x = GetX ( g , Global . Config . DispInpx , Global . Config . DispInpanchor , MessageFont , input ) ;
float y = GetY ( g , Global . Config . DispInpy , Global . Config . DispInpanchor , MessageFont , input ) ;
2012-09-03 19:42:53 +00:00
if ( Global . MovieSession . Movie . IsPlaying & & ! Global . MovieSession . Movie . IsRecording )
2012-04-16 08:18:41 +00:00
{
c = Color . FromArgb ( Global . Config . MovieInput ) ;
}
else
2012-09-03 19:42:53 +00:00
{
2012-04-16 08:18:41 +00:00
c = Color . FromArgb ( Global . Config . MessagesColor ) ;
2012-09-03 19:42:53 +00:00
}
2012-04-16 08:18:41 +00:00
2012-06-10 23:27:30 +00:00
g . DrawString ( input , MessageFont , Color . Black , x + 1 , y + 1 ) ;
g . DrawString ( input , MessageFont , c , x , y ) ;
2012-04-16 08:18:41 +00:00
}
if ( Global . MovieSession . MultiTrack . IsActive )
{
2012-06-10 23:27:30 +00:00
g . DrawString ( MT , MessageFont , Color . Black ,
2012-04-16 08:18:41 +00:00
Global . Config . DispFPSx + 1 , //TODO: Multitrack position variables
Global . Config . DispFPSy + 1 ) ;
2012-06-10 23:27:30 +00:00
g . DrawString ( MT , MessageFont , FixedMessagesColor ,
Global . Config . DispFPSx , //TODO: Multitrack position variables
Global . Config . DispFPSy ) ;
2012-04-16 08:18:41 +00:00
}
if ( Global . Config . DisplayFPS & & FPS ! = null )
{
float x = GetX ( g , Global . Config . DispFPSx , Global . Config . DispFPSanchor , MessageFont , FPS ) ;
float y = GetY ( g , Global . Config . DispFPSy , Global . Config . DispFPSanchor , MessageFont , FPS ) ;
2012-06-10 23:27:30 +00:00
g . DrawString ( FPS , MessageFont , Color . Black , x + 1 , y + 1 ) ;
g . DrawString ( FPS , MessageFont , FixedMessagesColor , x , y ) ;
2012-04-16 08:18:41 +00:00
}
if ( Global . Config . DisplayLagCounter )
{
string counter = MakeLagCounter ( ) ;
if ( Global . Emulator . IsLagFrame )
{
float x = GetX ( g , Global . Config . DispLagx , Global . Config . DispLaganchor , AlertFont , counter ) ;
float y = GetY ( g , Global . Config . DispLagy , Global . Config . DispLaganchor , AlertFont , counter ) ;
2012-09-14 21:31:00 +00:00
g . DrawString ( counter , AlertFont , Color . Black , x + 1 , y + 1 ) ;
g . DrawString ( counter , AlertFont , FixedAlertMessageColor , x , y ) ;
2012-04-16 08:18:41 +00:00
}
else
{
float x = GetX ( g , Global . Config . DispLagx , Global . Config . DispLaganchor , MessageFont , counter ) ;
float y = GetY ( g , Global . Config . DispLagy , Global . Config . DispLaganchor , MessageFont , counter ) ;
2012-06-10 23:27:30 +00:00
g . DrawString ( counter , MessageFont , Color . Black , x + 1 , y + 1 ) ;
g . DrawString ( counter , MessageFont , FixedMessagesColor , x , y ) ;
2012-04-16 08:18:41 +00:00
}
}
if ( Global . Config . DisplayRerecordCount )
{
string rerec = MakeRerecordCount ( ) ;
float x = GetX ( g , Global . Config . DispRecx , Global . Config . DispRecanchor , MessageFont , rerec ) ;
float y = GetY ( g , Global . Config . DispRecy , Global . Config . DispRecanchor , MessageFont , rerec ) ;
2012-06-10 23:27:30 +00:00
g . DrawString ( rerec , MessageFont , Color . Black , x + 1 , y + 1 ) ;
g . DrawString ( rerec , MessageFont , FixedMessagesColor , x , y ) ;
2012-04-16 08:18:41 +00:00
}
2012-09-14 21:31:00 +00:00
if ( Global . ClientControls [ "Autohold" ] )
{
StringBuilder disp = new StringBuilder ( "Held: " ) ;
foreach ( string s in Global . StickyXORAdapter . CurrentStickies )
{
disp . Append ( s ) ;
disp . Append ( ' ' ) ;
}
2012-09-15 13:11:29 +00:00
foreach ( string s in Global . AutofireStickyXORAdapter . CurrentStickies )
{
disp . Append ( "Auto-" ) ;
disp . Append ( s ) ;
disp . Append ( ' ' ) ;
}
2012-09-26 23:25:43 +00:00
g . DrawString ( disp . ToString ( ) , MessageFont , Color . White , GetX ( g , Global . Config . DispAutoholdx , Global . Config . DispAutoholdanchor , MessageFont ,
disp . ToString ( ) ) , GetY ( g , Global . Config . DispAutoholdy , Global . Config . DispAutoholdanchor , MessageFont , disp . ToString ( ) ) ) ;
2012-09-14 21:31:00 +00:00
}
2012-09-03 19:42:53 +00:00
//TODO
//if (Global.MovieSession.Movie.IsPlaying)
//{
// //int r = (int)g.ClipBounds.Width;
// //Point[] p = { new Point(r - 20, 2),
// // new Point(r - 4, 12),
// // new Point(r - 20, 22) };
// //g.FillPolygon(new SolidBrush(Color.Red), p);
// //g.DrawPolygon(new Pen(new SolidBrush(Color.Pink)), p);
//}
//else if (Global.MovieSession.Movie.IsRecording)
//{
// //g.FillEllipse(new SolidBrush(Color.Red), new Rectangle((int)g.ClipBounds.Width - 22, 2, 20, 20));
// //g.DrawEllipse(new Pen(new SolidBrush(Color.Pink)), new Rectangle((int)g.ClipBounds.Width - 22, 2, 20, 20));
//}
if ( Global . MovieSession . Movie . IsActive & & Global . Config . DisplaySubtitles )
2012-04-16 08:18:41 +00:00
{
2012-04-16 20:00:11 +00:00
List < Subtitle > s = Global . MovieSession . Movie . Subtitles . GetSubtitles ( Global . Emulator . Frame ) ;
2012-09-03 19:42:53 +00:00
if ( s = = null )
{
return ;
}
2012-04-16 20:00:11 +00:00
for ( int i = 0 ; i < s . Count ; i + + )
{
2012-09-03 19:42:53 +00:00
g . DrawString ( s [ i ] . Message , MessageFont , Color . Black , s [ i ] . X + 1 , s [ i ] . Y + 1 ) ;
g . DrawString ( s [ i ] . Message , MessageFont , Color . FromArgb ( ( int ) s [ i ] . Color ) , s [ i ] . X , s [ i ] . Y ) ;
2012-04-16 20:00:11 +00:00
}
2012-04-16 08:18:41 +00:00
}
}
}
public class DisplayManager : IDisposable
{
public DisplayManager ( )
{
//have at least something here at the start
luaNativeSurfacePreOSD = new DisplaySurface ( 1 , 1 ) ;
}
2012-06-10 20:48:04 +00:00
volatile bool VsyncToggle = false ;
volatile bool VsyncRequested = false ;
2012-04-16 08:18:41 +00:00
SwappableDisplaySurfaceSet sourceSurfaceSet = new SwappableDisplaySurfaceSet ( ) ;
2012-09-02 14:54:30 +00:00
DisplaySurface luaEmuSurface = null ;
public void PreFrameUpdateLuaSource ( )
{
luaEmuSurface = luaEmuSurfaceSet . GetCurrent ( ) ;
}
2012-09-21 18:01:24 +00:00
/// <summary>update Global.RenderPanel from the passed IVideoProvider</summary>
2012-04-16 08:18:41 +00:00
public void UpdateSource ( IVideoProvider videoProvider )
2012-09-21 18:01:24 +00:00
{
UpdateSourceEx ( videoProvider , Global . RenderPanel ) ;
}
/// <summary>
/// update the passed IRenderer with the passed IVideoProvider
/// </summary>
/// <param name="videoProvider"></param>
/// <param name="renderPanel">also must implement IBlitter</param>
public void UpdateSourceEx ( IVideoProvider videoProvider , IRenderer renderPanel )
2012-04-16 08:18:41 +00:00
{
var newPendingSurface = sourceSurfaceSet . AllocateSurface ( videoProvider . BufferWidth , videoProvider . BufferHeight , false ) ;
2012-06-10 23:27:30 +00:00
newPendingSurface . AcceptIntArray ( videoProvider . GetVideoBuffer ( ) ) ;
2012-04-16 08:18:41 +00:00
sourceSurfaceSet . SetPending ( newPendingSurface ) ;
2012-06-10 23:27:30 +00:00
if ( renderPanel = = null ) return ;
2012-06-10 20:48:04 +00:00
2012-09-21 18:01:24 +00:00
currNativeWidth = renderPanel . NativeSize . Width ;
currNativeHeight = renderPanel . NativeSize . Height ;
2012-06-10 23:27:30 +00:00
2012-07-15 07:38:36 +00:00
currentSourceSurface = sourceSurfaceSet . GetCurrent ( ) ;
if ( currentSourceSurface = = null ) return ;
2012-06-10 23:27:30 +00:00
//if we're configured to use a scaling filter, apply it now
//SHOULD THIS BE RUN REPEATEDLY?
//some filters may need to run repeatedly (temporal interpolation, ntsc scanline field alternating)
//but its sort of wasted work.
2012-07-15 09:13:46 +00:00
CheckFilter ( ) ;
2012-06-10 23:27:30 +00:00
int w = currNativeWidth ;
int h = currNativeHeight ;
2012-09-02 14:54:30 +00:00
2012-06-10 23:27:30 +00:00
DisplaySurface luaSurface = luaNativeSurfaceSet . GetCurrent ( ) ;
//do we have anything to do?
//bool complexComposite = false;
//if (luaEmuSurface != null) complexComposite = true;
//if (luaSurface != null) complexComposite = true;
2012-07-15 09:13:46 +00:00
DisplaySurface surfaceToRender = filteredSurface ;
if ( surfaceToRender = = null ) surfaceToRender = currentSourceSurface ;
2012-09-21 18:01:24 +00:00
renderPanel . Clear ( Color . FromArgb ( videoProvider . BackgroundColor ) ) ;
renderPanel . Render ( surfaceToRender ) ;
2012-06-10 23:27:30 +00:00
if ( luaEmuSurface ! = null )
2012-09-02 14:54:30 +00:00
{
2012-09-21 18:01:24 +00:00
renderPanel . RenderOverlay ( luaEmuSurface ) ;
2012-09-02 14:54:30 +00:00
}
2012-06-10 23:27:30 +00:00
2012-09-21 18:01:24 +00:00
RenderOSD ( ( IBlitter ) renderPanel ) ;
2012-06-10 23:27:30 +00:00
2012-09-21 18:01:24 +00:00
renderPanel . Present ( ) ;
2012-06-10 20:48:04 +00:00
2012-07-15 09:13:46 +00:00
if ( filteredSurface ! = null )
filteredSurface . Dispose ( ) ;
filteredSurface = null ;
2012-04-16 08:18:41 +00:00
}
public bool Disposed { get ; private set ; }
public void Dispose ( )
{
if ( Disposed ) return ;
Disposed = true ;
}
2012-07-15 09:13:46 +00:00
DisplaySurface currentSourceSurface , filteredSurface ;
2012-04-16 08:18:41 +00:00
//the surface to use to render a lua layer at native resolution (under the OSD)
DisplaySurface luaNativeSurfacePreOSD ;
SwappableDisplaySurfaceSet luaNativeSurfaceSet = new SwappableDisplaySurfaceSet ( ) ;
public void SetLuaSurfaceNativePreOSD ( DisplaySurface surface ) { luaNativeSurfaceSet . SetPending ( surface ) ; }
public DisplaySurface GetLuaSurfaceNative ( )
{
return luaNativeSurfaceSet . AllocateSurface ( currNativeWidth , currNativeHeight ) ;
}
2012-05-06 07:09:04 +00:00
SwappableDisplaySurfaceSet luaEmuSurfaceSet = new SwappableDisplaySurfaceSet ( ) ;
public void SetLuaSurfaceEmu ( DisplaySurface surface ) { luaEmuSurfaceSet . SetPending ( surface ) ; }
public DisplaySurface GetLuaEmuSurfaceEmu ( )
{
int width = 1 , height = 1 ;
if ( currentSourceSurface ! = null )
width = currentSourceSurface . Width ;
if ( currentSourceSurface ! = null )
height = currentSourceSurface . Height ;
return luaEmuSurfaceSet . AllocateSurface ( width , height ) ;
}
2012-04-16 08:18:41 +00:00
int currNativeWidth , currNativeHeight ;
2012-06-10 23:27:30 +00:00
2012-04-16 08:18:41 +00:00
/// <summary>
/// suspends the display manager so that tricky things can be changed without the display thread going in and getting all confused and hating
/// </summary>
public void Suspend ( )
{
}
/// <summary>
/// resumes the display manager after a suspend
/// </summary>
public void Resume ( )
{
}
2012-09-21 18:01:24 +00:00
void RenderOSD ( IBlitter renderPanel )
2012-04-16 08:18:41 +00:00
{
2012-09-21 18:01:24 +00:00
Global . OSD . Begin ( renderPanel ) ;
renderPanel . Open ( ) ;
Global . OSD . DrawScreenInfo ( renderPanel ) ;
Global . OSD . DrawMessages ( renderPanel ) ;
renderPanel . Close ( ) ;
2012-06-10 23:27:30 +00:00
}
2012-06-10 20:48:04 +00:00
2012-07-15 08:50:24 +00:00
void CheckFilter ( )
{
IDisplayFilter filter = null ;
switch ( Global . Config . TargetDisplayFilter )
{
2012-07-15 09:13:46 +00:00
case 0 :
//no filter
break ;
2012-07-15 08:50:24 +00:00
case 1 :
filter = new Hq2xBase_2xSai ( ) ;
break ;
case 2 :
filter = new Hq2xBase_Super2xSai ( ) ;
break ;
case 3 :
filter = new Hq2xBase_SuperEagle ( ) ;
break ;
}
2012-07-15 09:13:46 +00:00
if ( filter = = null )
filteredSurface = null ;
else
filteredSurface = filter . Execute ( currentSourceSurface ) ;
2012-07-15 08:50:24 +00:00
}
2012-06-10 20:48:04 +00:00
2012-06-10 23:27:30 +00:00
SwappableDisplaySurfaceSet nativeDisplaySurfaceSet = new SwappableDisplaySurfaceSet ( ) ;
2012-04-16 08:18:41 +00:00
Thread displayThread ;
}
}