Video: Exclusive fullscreen mode (wip)

This commit is contained in:
Souryo 2017-11-29 23:24:26 -05:00
parent dc3202fbfc
commit 114d9d2313
31 changed files with 764 additions and 265 deletions

View file

@ -101,7 +101,7 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
if(mapper) {
if(_mapper) {
//Send notification only if a game was already running and we successfully loaded the new one
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
MessageManager::SendNotification(ConsoleNotificationType::GameStopped, (void*)1);
}
if(_romFilepath != (string)romFile || _patchFilename != (string)patchFile) {

View file

@ -9,4 +9,5 @@ class IRenderingDevice
virtual void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) = 0;
virtual void Render() = 0;
virtual void Reset() = 0;
virtual void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) = 0;
};

View file

@ -51,6 +51,7 @@ namespace Mesen.GUI.Config
public bool ForceSpritesFirstColumn = false;
public bool FullscreenForceIntegerScale = false;
public bool UseExclusiveFullscreen = false;
public bool UseCustomVsPalette = false;
public bool ShowColorIndexes = true;

View file

@ -256,6 +256,7 @@
<Control ID="chkFullscreenForceIntegerScale">Fes servir valors enters d'escalat al mode de pantalla completa</Control>
<Control ID="chkShowFps">Mostra els FPS</Control>
<Control ID="chkUseHdPacks">Fes servir els paquets d'alta resolució d'HDNes</Control>
<Control ID="chkUseExclusiveFullscreen">Use exclusive fullscreen mode</Control>
<Control ID="tpgOverscan">Sobreescaneig</Control>
<Control ID="grpCropping">Retall de vídeo</Control>
<Control ID="lblLeft">Esquerra</Control>

View file

@ -256,6 +256,7 @@
<Control ID="chkFullscreenForceIntegerScale">Utilizar valores enteros de escalado en modo de pantalla completa</Control>
<Control ID="chkShowFps">Mostrar FPS</Control>
<Control ID="chkUseHdPacks">Utilizar los paquetes de alta resolución de HDNes</Control>
<Control ID="chkUseExclusiveFullscreen">Use exclusive fullscreen mode</Control>
<Control ID="tpgOverscan">Overscan</Control>
<Control ID="grpCropping">Recorte</Control>
<Control ID="lblLeft">Izquierda</Control>

View file

@ -259,6 +259,7 @@
<Control ID="chkFullscreenForceIntegerScale">Utiliser une valeur entière pour l'échelle vidéo en mode plein écran</Control>
<Control ID="chkShowFps">Afficher le FPS</Control>
<Control ID="chkUseHdPacks">Utiliser les packs haute-définition de HDNes</Control>
<Control ID="chkUseExclusiveFullscreen">Utiliser le mode plein écran exclusif</Control>
<Control ID="tpgOverscan">Overscan</Control>
<Control ID="grpCropping">Overscan</Control>
<Control ID="lblLeft">Gauche</Control>

View file

@ -260,6 +260,7 @@
<Control ID="chkFullscreenForceIntegerScale">全画面表示モードに入る時、画面サイズの倍率を整数にする</Control>
<Control ID="chkShowFps">フレームレート表示</Control>
<Control ID="chkUseHdPacks">HDNesのHDパックを使う</Control>
<Control ID="chkUseExclusiveFullscreen">排他的なフルスクリーンモードを使う</Control>
<Control ID="tpgOverscan">オーバースキャン</Control>
<Control ID="grpCropping">オーバースキャン</Control>
<Control ID="lblLeft"></Control>

View file

@ -256,6 +256,7 @@
<Control ID="chkFullscreenForceIntegerScale">Usar valores de escala inteira ao entrar no modo de tela cheia</Control>
<Control ID="chkShowFps">Mostrar FPS</Control>
<Control ID="chkUseHdPacks">Usar os pacotes de alta definição do HDNes</Control>
<Control ID="chkUseExclusiveFullscreen">Use exclusive fullscreen mode</Control>
<Control ID="tpgOverscan">Overscan</Control>
<Control ID="grpCropping">Recorte</Control>
<Control ID="lblLeft">Esquerda</Control>

View file

@ -258,6 +258,7 @@
<Control ID="chkFullscreenForceIntegerScale">Use integer scale values when entering fullscreen mode</Control>
<Control ID="chkShowFps">Показывать FPS</Control>
<Control ID="chkUseHdPacks">Использовать HDNes HD packs</Control>
<Control ID="chkUseExclusiveFullscreen">Use exclusive fullscreen mode</Control>
<Control ID="tpgOverscan">Overscan</Control>
<Control ID="grpCropping">Overscan</Control>
<Control ID="lblLeft">Слева</Control>

View file

@ -258,6 +258,7 @@
<Control ID="chkFullscreenForceIntegerScale">Використовуйте цілі значення масштабу при введенні повноекранного режиму</Control>
<Control ID="chkShowFps">Показувати FPS</Control>
<Control ID="chkUseHdPacks">Використовувати HDNes HD packs</Control>
<Control ID="chkUseExclusiveFullscreen">Use exclusive fullscreen mode</Control>
<Control ID="tpgOverscan">Overscan</Control>
<Control ID="grpCropping">Overscan</Control>
<Control ID="lblLeft">Злiва</Control>

View file

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Forms
{
public class BaseInputForm : BaseForm, IMessageFilter
{
private static Stack<Form> _inputForms = new Stack<Form>();
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;
private const int WM_SYSKEYDOWN = 0x104;
private const int WM_SYSKEYUP = 0x105;
private Timer _tmrUpdateBackground;
public BaseInputForm()
{
if(!this.DesignMode) {
_inputForms.Push(this);
Application.AddMessageFilter(this);
this._tmrUpdateBackground = new Timer();
this._tmrUpdateBackground.Start();
this._tmrUpdateBackground.Tick += tmrUpdateBackground_Tick;
}
}
bool IMessageFilter.PreFilterMessage(ref Message m)
{
if(this.ContainsFocus) {
if(m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYUP) {
int scanCode = (Int32)(((Int64)m.LParam & 0x1FF0000) >> 16);
InteropEmu.SetKeyState(scanCode, false);
} else if(m.Msg == WM_SYSKEYDOWN || m.Msg == WM_KEYDOWN) {
int scanCode = (Int32)(((Int64)m.LParam & 0x1FF0000) >> 16);
InteropEmu.SetKeyState(scanCode, true);
}
}
return false;
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
Application.RemoveMessageFilter(this);
_tmrUpdateBackground.Stop();
_tmrUpdateBackground.Dispose();
_inputForms.Pop();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if(Program.IsMono) {
//Mono does not trigger the activate/deactivate events when opening a modal popup, but it does set the form to disabled
//Use this to reset key states
this.EnabledChanged += (object s, EventArgs evt) => {
InteropEmu.ResetKeyState();
};
}
}
protected override void OnDeactivate(EventArgs e)
{
base.OnDeactivate(e);
InteropEmu.ResetKeyState();
}
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
InteropEmu.ResetKeyState();
}
private void tmrUpdateBackground_Tick(object sender, EventArgs e)
{
UpdateFocusFlag();
}
private void UpdateFocusFlag()
{
if(_inputForms.Peek() == this) {
InteropEmu.SetFlag(EmulationFlags.InBackground, !this.ContainsFocus);
}
}
}
}

View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="tmrUpdateBackground.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
</metadata>
</root>

View file

@ -10,14 +10,12 @@ using System.Windows.Forms;
namespace Mesen.GUI.Forms.Config
{
public partial class frmGetKey : BaseForm, IMessageFilter
public partial class frmGetKey : BaseInputForm
{
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
private bool _singleKeyMode = false;
private List<UInt32> _prevScanCodes = new List<UInt32>();
public KeyCombination ShortcutKey { get; set; }
public frmGetKey(bool singleKeyMode)
{
@ -37,36 +35,14 @@ namespace Mesen.GUI.Forms.Config
//Prevent other keybindings from interfering/activating
InteropEmu.DisableAllKeys(true);
Application.AddMessageFilter(this);
}
bool IMessageFilter.PreFilterMessage(ref Message m)
{
if(m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYUP) {
int virtualKeyCode = (Int32)m.WParam;
int scanCode = (Int32)(((Int64)m.LParam & 0x1FF0000) >> 16);
InteropEmu.SetKeyState(scanCode, false);
} else if(m.Msg == WM_SYSKEYDOWN || m.Msg == WM_KEYDOWN) {
int virtualKeyCode = (Int32)((Int64)m.WParam & 0xFF);
int scanCode = (Int32)(((Int64)m.LParam & 0x1FF0000) >> 16);
InteropEmu.SetKeyState(scanCode, true);
}
return false;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
Application.RemoveMessageFilter(this);
InteropEmu.ResetKeyState();
InteropEmu.DisableAllKeys(false);
base.OnFormClosing(e);
}
public KeyCombination ShortcutKey { get; set; }
private List<UInt32> _prevScanCodes = new List<UInt32>();
private void tmrCheckKey_Tick(object sender, EventArgs e)
{
List<UInt32> scanCodes = InteropEmu.GetPressedKeys();

View file

@ -44,6 +44,7 @@ namespace Mesen.GUI.Forms.Config
this.nudCustomRatio = new Mesen.GUI.Controls.MesenNumericUpDown();
this.chkFullscreenForceIntegerScale = new System.Windows.Forms.CheckBox();
this.chkShowFps = new System.Windows.Forms.CheckBox();
this.chkUseExclusiveFullscreen = new System.Windows.Forms.CheckBox();
this.chkIntegerFpsMode = new System.Windows.Forms.CheckBox();
this.tabMain = new System.Windows.Forms.TabControl();
this.tpgGeneral = new System.Windows.Forms.TabPage();
@ -108,6 +109,8 @@ namespace Mesen.GUI.Forms.Config
this.chkDisableSprites = new Mesen.GUI.Controls.ctrlRiskyOption();
this.chkForceBackgroundFirstColumn = new Mesen.GUI.Controls.ctrlRiskyOption();
this.chkForceSpritesFirstColumn = new Mesen.GUI.Controls.ctrlRiskyOption();
this.lblScreenRotation = new System.Windows.Forms.Label();
this.cboScreenRotation = new System.Windows.Forms.ComboBox();
this.contextPicturePresets = new System.Windows.Forms.ContextMenuStrip(this.components);
this.mnuPresetComposite = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPresetSVideo = new System.Windows.Forms.ToolStripMenuItem();
@ -125,8 +128,6 @@ namespace Mesen.GUI.Forms.Config
this.mnuPaletteSonyCxa2025As = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPaletteUnsaturated = new System.Windows.Forms.ToolStripMenuItem();
this.mnuPaletteYuv = new System.Windows.Forms.ToolStripMenuItem();
this.lblScreenRotation = new System.Windows.Forms.Label();
this.cboScreenRotation = new System.Windows.Forms.ComboBox();
this.tlpMain.SuspendLayout();
this.flowLayoutPanel7.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picHdNesTooltip)).BeginInit();
@ -173,17 +174,18 @@ namespace Mesen.GUI.Forms.Config
this.tlpMain.Controls.Add(this.lblVideoScale, 0, 0);
this.tlpMain.Controls.Add(this.chkVerticalSync, 0, 3);
this.tlpMain.Controls.Add(this.lblDisplayRatio, 0, 1);
this.tlpMain.Controls.Add(this.flowLayoutPanel7, 0, 4);
this.tlpMain.Controls.Add(this.flowLayoutPanel7, 0, 6);
this.tlpMain.Controls.Add(this.nudScale, 1, 0);
this.tlpMain.Controls.Add(this.flowLayoutPanel6, 1, 1);
this.tlpMain.Controls.Add(this.chkFullscreenForceIntegerScale, 0, 5);
this.tlpMain.Controls.Add(this.chkShowFps, 0, 6);
this.tlpMain.Controls.Add(this.chkShowFps, 0, 7);
this.tlpMain.Controls.Add(this.chkUseExclusiveFullscreen, 0, 4);
this.tlpMain.Controls.Add(this.chkIntegerFpsMode, 0, 2);
this.tlpMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpMain.Location = new System.Drawing.Point(3, 3);
this.tlpMain.Margin = new System.Windows.Forms.Padding(0);
this.tlpMain.Name = "tlpMain";
this.tlpMain.RowCount = 8;
this.tlpMain.RowCount = 9;
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
@ -192,6 +194,7 @@ namespace Mesen.GUI.Forms.Config
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpMain.Size = new System.Drawing.Size(521, 370);
this.tlpMain.TabIndex = 1;
//
@ -233,7 +236,7 @@ namespace Mesen.GUI.Forms.Config
this.flowLayoutPanel7.Controls.Add(this.chkUseHdPacks);
this.flowLayoutPanel7.Controls.Add(this.picHdNesTooltip);
this.flowLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel7.Location = new System.Drawing.Point(0, 92);
this.flowLayoutPanel7.Location = new System.Drawing.Point(0, 138);
this.flowLayoutPanel7.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel7.Name = "flowLayoutPanel7";
this.flowLayoutPanel7.Size = new System.Drawing.Size(521, 23);
@ -381,13 +384,25 @@ namespace Mesen.GUI.Forms.Config
this.chkShowFps.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkShowFps.AutoSize = true;
this.tlpMain.SetColumnSpan(this.chkShowFps, 2);
this.chkShowFps.Location = new System.Drawing.Point(3, 141);
this.chkShowFps.Location = new System.Drawing.Point(3, 164);
this.chkShowFps.Name = "chkShowFps";
this.chkShowFps.Size = new System.Drawing.Size(76, 17);
this.chkShowFps.TabIndex = 9;
this.chkShowFps.Text = "Show FPS";
this.chkShowFps.UseVisualStyleBackColor = true;
//
// chkUseExclusiveFullscreen
//
this.chkUseExclusiveFullscreen.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkUseExclusiveFullscreen.AutoSize = true;
this.tlpMain.SetColumnSpan(this.chkUseExclusiveFullscreen, 2);
this.chkUseExclusiveFullscreen.Location = new System.Drawing.Point(3, 95);
this.chkUseExclusiveFullscreen.Name = "chkUseExclusiveFullscreen";
this.chkUseExclusiveFullscreen.Size = new System.Drawing.Size(169, 17);
this.chkUseExclusiveFullscreen.TabIndex = 24;
this.chkUseExclusiveFullscreen.Text = "Use exclusive fullscreen mode";
this.chkUseExclusiveFullscreen.UseVisualStyleBackColor = true;
//
// chkIntegerFpsMode
//
this.chkIntegerFpsMode.Anchor = System.Windows.Forms.AnchorStyles.Left;
@ -1358,6 +1373,25 @@ namespace Mesen.GUI.Forms.Config
this.chkForceSpritesFirstColumn.TabIndex = 3;
this.chkForceSpritesFirstColumn.Text = "Force sprite display in first column";
//
// lblScreenRotation
//
this.lblScreenRotation.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblScreenRotation.AutoSize = true;
this.lblScreenRotation.Location = new System.Drawing.Point(3, 7);
this.lblScreenRotation.Name = "lblScreenRotation";
this.lblScreenRotation.Size = new System.Drawing.Size(87, 13);
this.lblScreenRotation.TabIndex = 4;
this.lblScreenRotation.Text = "Screen Rotation:";
//
// cboScreenRotation
//
this.cboScreenRotation.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboScreenRotation.FormattingEnabled = true;
this.cboScreenRotation.Location = new System.Drawing.Point(96, 3);
this.cboScreenRotation.Name = "cboScreenRotation";
this.cboScreenRotation.Size = new System.Drawing.Size(77, 21);
this.cboScreenRotation.TabIndex = 5;
//
// contextPicturePresets
//
this.contextPicturePresets.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -1481,25 +1515,6 @@ namespace Mesen.GUI.Forms.Config
this.mnuPaletteYuv.Text = "YUV v3 (by FirebrandX)";
this.mnuPaletteYuv.Click += new System.EventHandler(this.mnuPaletteYuv_Click);
//
// lblScreenRotation
//
this.lblScreenRotation.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblScreenRotation.AutoSize = true;
this.lblScreenRotation.Location = new System.Drawing.Point(3, 7);
this.lblScreenRotation.Name = "lblScreenRotation";
this.lblScreenRotation.Size = new System.Drawing.Size(87, 13);
this.lblScreenRotation.TabIndex = 4;
this.lblScreenRotation.Text = "Screen Rotation:";
//
// cboScreenRotation
//
this.cboScreenRotation.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboScreenRotation.FormattingEnabled = true;
this.cboScreenRotation.Location = new System.Drawing.Point(96, 3);
this.cboScreenRotation.Name = "cboScreenRotation";
this.cboScreenRotation.Size = new System.Drawing.Size(77, 21);
this.cboScreenRotation.TabIndex = 5;
//
// frmVideoConfig
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -1663,5 +1678,6 @@ namespace Mesen.GUI.Forms.Config
private System.Windows.Forms.CheckBox chkIntegerFpsMode;
private System.Windows.Forms.Label lblScreenRotation;
private System.Windows.Forms.ComboBox cboScreenRotation;
private System.Windows.Forms.CheckBox chkUseExclusiveFullscreen;
}
}

View file

@ -66,6 +66,7 @@ namespace Mesen.GUI.Forms.Config
AddBinding("ForceBackgroundFirstColumn", chkForceBackgroundFirstColumn);
AddBinding("ForceSpritesFirstColumn", chkForceSpritesFirstColumn);
AddBinding("FullscreenForceIntegerScale", chkFullscreenForceIntegerScale);
AddBinding("UseExclusiveFullscreen", chkUseExclusiveFullscreen);
AddBinding("UseCustomVsPalette", chkUseCustomVsPalette);
@ -83,6 +84,11 @@ namespace Mesen.GUI.Forms.Config
ResourceHelper.ApplyResources(this, contextPaletteList);
ResourceHelper.ApplyResources(this, contextPicturePresets);
if(Program.IsMono) {
//Not available in the linux build (for now)
chkUseExclusiveFullscreen.Visible = false;
}
}
private void UpdatePalette()

View file

@ -20,7 +20,7 @@ namespace Mesen.GUI.Forms
return MessageBox.Show(string.Format("Critical error (" + text + ")"), "Mesen", buttons, icon);
}
} else {
return MessageBox.Show(ResourceHelper.GetMessage(text, args), "Mesen", buttons, icon);
return MessageBox.Show(Application.OpenForms[0], ResourceHelper.GetMessage(text, args), "Mesen", buttons, icon);
}
}
}

View file

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Forms
{
public class frmFullscreenRenderer : BaseInputForm
{
private const int LeftMouseButtonKeyCode = 0x200;
private const int RightMouseButtonKeyCode = 0x201;
private const int MiddleMouseButtonKeyCode = 0x202;
private bool _closing = false;
public frmFullscreenRenderer()
{
this.BackColor = Color.Black;
this.Text = "Mesen Fullscreen Window";
this.FormBorderStyle = FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
_closing = true;
base.OnFormClosing(e);
}
protected override void OnDeactivate(EventArgs e)
{
base.OnDeactivate(e);
if(!_closing) {
//Close fullscreen mode if window loses focus
this.Close();
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
SetMouseButtonState(Control.MouseButtons);
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
SetMouseButtonState(Control.MouseButtons);
}
private void SetMouseButtonState(MouseButtons pressedButtons)
{
InteropEmu.SetKeyState(LeftMouseButtonKeyCode, pressedButtons.HasFlag(MouseButtons.Left));
InteropEmu.SetKeyState(RightMouseButtonKeyCode, pressedButtons.HasFlag(MouseButtons.Right));
InteropEmu.SetKeyState(MiddleMouseButtonKeyCode, pressedButtons.HasFlag(MouseButtons.Middle));
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
InteropEmu.ScreenSize size = InteropEmu.GetScreenSize(false);
int leftMargin = (this.Width - size.Width) / 2;
int topMargin = (this.Height - size.Height) / 2;
CursorManager.OnMouseMove(this);
if(CursorManager.NeedMouseIcon) {
this.Cursor = Cursors.Cross;
}
double xPos = (double)(e.X - leftMargin) / size.Width;
double yPos = (double)(e.Y - topMargin) / size.Height;
xPos = Math.Max(0.0, Math.Min(1.0, xPos));
yPos = Math.Max(0.0, Math.Min(1.0, yPos));
InteropEmu.SetMousePosition(xPos, yPos);
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
CursorManager.OnMouseLeave();
InteropEmu.SetMousePosition(-1, -1);
}
}
}

View file

@ -95,7 +95,7 @@ namespace Mesen.GUI.Forms
using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.InitialDirectory = ConfigManager.SaveStateFolder;
ofd.SetFilter(ResourceHelper.GetMessage("FilterSavestate"));
if(ofd.ShowDialog() == DialogResult.OK) {
if(ofd.ShowDialog(this) == DialogResult.OK) {
InteropEmu.LoadStateFile(ofd.FileName);
}
}
@ -109,7 +109,7 @@ namespace Mesen.GUI.Forms
sfd.InitialDirectory = ConfigManager.SaveStateFolder;
sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".mst";
sfd.SetFilter(ResourceHelper.GetMessage("FilterSavestate"));
if(sfd.ShowDialog() == DialogResult.OK) {
if(sfd.ShowDialog(this) == DialogResult.OK) {
InteropEmu.SaveStateFile(sfd.FileName);
}
}
@ -137,7 +137,7 @@ namespace Mesen.GUI.Forms
ofd.InitialDirectory = ConfigManager.Config.RecentFiles[0].RomFile.Folder;
}
if(ofd.ShowDialog() == DialogResult.OK) {
if(ofd.ShowDialog(this) == DialogResult.OK) {
LoadFile(ofd.FileName);
}
}
@ -196,7 +196,7 @@ namespace Mesen.GUI.Forms
ofd.InitialDirectory = ConfigManager.Config.RecentFiles[0].RomFile.Folder;
}
if(ofd.ShowDialog() == DialogResult.OK) {
if(ofd.ShowDialog(this) == DialogResult.OK) {
LoadROM(ofd.FileName, true, patchFile);
}
}

View file

@ -80,7 +80,7 @@ namespace Mesen.GUI.Forms
ofd.SetFilter(ResourceHelper.GetMessage("FilterTapeFiles"));
ofd.InitialDirectory = ConfigManager.SaveFolder;
ofd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".fbt";
if(ofd.ShowDialog() == DialogResult.OK) {
if(ofd.ShowDialog(this) == DialogResult.OK) {
InteropEmu.LoadTapeFile(ofd.FileName);
}
}
@ -92,7 +92,7 @@ namespace Mesen.GUI.Forms
sfd.SetFilter(ResourceHelper.GetMessage("FilterTapeFiles"));
sfd.InitialDirectory = ConfigManager.SaveFolder;
sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".fbt";
if(sfd.ShowDialog() == DialogResult.OK) {
if(sfd.ShowDialog(this) == DialogResult.OK) {
InteropEmu.StartRecordingTapeFile(sfd.FileName);
}
}

View file

@ -101,7 +101,7 @@ namespace Mesen.GUI.Forms
private void mnuAbout_Click(object sender, EventArgs e)
{
using(frmAbout frm = new frmAbout()) {
frm.ShowDialog();
frm.ShowDialog(this);
}
}

View file

@ -85,7 +85,7 @@ namespace Mesen.GUI.Forms
Configuration configBackup = ConfigManager.Config.Clone();
bool cancelled = false;
using(frmVideoConfig frm = new frmVideoConfig()) {
cancelled = frm.ShowDialog(sender) == DialogResult.Cancel;
cancelled = frm.ShowDialog(sender, this) == DialogResult.Cancel;
}
if(cancelled) {
ConfigManager.RevertToBackup(configBackup);
@ -96,19 +96,25 @@ namespace Mesen.GUI.Forms
if((cancelled || (screenSize.Height == originalScreenSize.Height && screenSize.Width == originalScreenSize.Width)) && this.WindowState == FormWindowState.Normal) {
this.Size = originalSize;
}
if(_fullscreenMode && ConfigManager.Config.VideoInfo.UseExclusiveFullscreen && _frmFullscreenRenderer == null) {
StopFullscreenWindowMode();
if(!this._isNsfPlayerMode) {
SetFullscreenState(true);
}
}
}
private void mnuInput_Click(object sender, EventArgs e)
{
using(frmInputConfig frm = new frmInputConfig()) {
frm.ShowDialog(sender);
frm.ShowDialog(sender, this);
}
}
private void mnuAudioConfig_Click(object sender, EventArgs e)
{
using(frmAudioConfig frm = new frmAudioConfig()) {
frm.ShowDialog(sender);
frm.ShowDialog(sender, this);
}
this.ctrlNsfPlayer.UpdateVolume();
}
@ -116,7 +122,7 @@ namespace Mesen.GUI.Forms
private void mnuPreferences_Click(object sender, EventArgs e)
{
using(frmPreferences frm = new frmPreferences()) {
if(frm.ShowDialog(sender) == DialogResult.OK) {
if(frm.ShowDialog(sender, this) == DialogResult.OK) {
ResourceHelper.LoadResources(ConfigManager.Config.PreferenceInfo.DisplayLanguage);
ResourceHelper.UpdateEmuLanguage();
ResourceHelper.ApplyResources(this);
@ -137,7 +143,7 @@ namespace Mesen.GUI.Forms
private void mnuEmulationConfig_Click(object sender, EventArgs e)
{
using(frmEmulationConfig frm = new frmEmulationConfig()) {
frm.ShowDialog(sender);
frm.ShowDialog(sender, this);
}
}

View file

@ -18,7 +18,7 @@ namespace Mesen.GUI.Forms
ofd.SetFilter(ResourceHelper.GetMessage("FilterTest"));
ofd.InitialDirectory = ConfigManager.TestFolder;
ofd.Multiselect = true;
if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(ofd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
List<string> passedTests = new List<string>();
List<string> failedTests = new List<string>();
List<int> failedFrameCount = new List<int>();
@ -79,7 +79,7 @@ namespace Mesen.GUI.Forms
sfd.SetFilter(ResourceHelper.GetMessage("FilterTest"));
sfd.InitialDirectory = ConfigManager.TestFolder;
sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".mtp";
if(sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.RomTestRecord(sfd.FileName, resetEmu);
}
}
@ -90,12 +90,12 @@ namespace Mesen.GUI.Forms
using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.SetFilter(ResourceHelper.GetMessage("FilterMovie"));
ofd.InitialDirectory = ConfigManager.MovieFolder;
if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(ofd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
SaveFileDialog sfd = new SaveFileDialog();
sfd.SetFilter(ResourceHelper.GetMessage("FilterTest"));
sfd.InitialDirectory = ConfigManager.TestFolder;
sfd.FileName = Path.GetFileNameWithoutExtension(ofd.FileName) + ".mtp";
if(sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.RomTestRecordFromMovie(sfd.FileName, ofd.FileName);
}
}
@ -108,12 +108,12 @@ namespace Mesen.GUI.Forms
ofd.SetFilter(ResourceHelper.GetMessage("FilterTest"));
ofd.InitialDirectory = ConfigManager.TestFolder;
if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(ofd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
SaveFileDialog sfd = new SaveFileDialog();
sfd.SetFilter(ResourceHelper.GetMessage("FilterTest"));
sfd.InitialDirectory = ConfigManager.TestFolder;
sfd.FileName = Path.GetFileNameWithoutExtension(ofd.FileName) + ".mtp";
if(sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.RomTestRecordFromTest(sfd.FileName, ofd.FileName);
}
}
@ -124,7 +124,7 @@ namespace Mesen.GUI.Forms
{
using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.SetFilter("*.nes|*.nes");
if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(ofd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
string filename = ofd.FileName;
Task.Run(() => {

View file

@ -33,7 +33,7 @@ namespace Mesen.GUI.Forms
sfd.SetFilter(ResourceHelper.GetMessage("FilterMovie"));
sfd.InitialDirectory = ConfigManager.MovieFolder;
sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".mmo";
if(sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.MovieRecord(sfd.FileName, resetEmu);
}
}
@ -44,7 +44,7 @@ namespace Mesen.GUI.Forms
using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.SetFilter(ResourceHelper.GetMessage("FilterMovie"));
ofd.InitialDirectory = ConfigManager.MovieFolder;
if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(ofd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.MoviePlay(ofd.FileName);
}
}
@ -71,7 +71,7 @@ namespace Mesen.GUI.Forms
sfd.SetFilter(ResourceHelper.GetMessage("FilterWave"));
sfd.InitialDirectory = ConfigManager.WaveFolder;
sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".wav";
if(sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if(sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.WaveRecord(sfd.FileName);
}
}
@ -85,7 +85,7 @@ namespace Mesen.GUI.Forms
private void mnuAviRecord_Click(object sender, EventArgs e)
{
using(frmRecordAvi frm = new frmRecordAvi()) {
if(frm.ShowDialog(mnuVideoRecorder) == DialogResult.OK) {
if(frm.ShowDialog(mnuVideoRecorder, this) == DialogResult.OK) {
InteropEmu.AviRecord(frm.Filename, ConfigManager.Config.AviRecordInfo.Codec, ConfigManager.Config.AviRecordInfo.CompressionLevel);
}
}
@ -166,7 +166,7 @@ namespace Mesen.GUI.Forms
Task.Run(() => InteropEmu.StopServer());
} else {
using(frmServerConfig frm = new frmServerConfig()) {
if(frm.ShowDialog(sender) == System.Windows.Forms.DialogResult.OK) {
if(frm.ShowDialog(sender, this) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.StartServer(ConfigManager.Config.ServerInfo.Port, ConfigManager.Config.Profile.PlayerName);
}
}
@ -179,7 +179,7 @@ namespace Mesen.GUI.Forms
Task.Run(() => InteropEmu.Disconnect());
} else {
using(frmClientConfig frm = new frmClientConfig()) {
if(frm.ShowDialog(sender) == System.Windows.Forms.DialogResult.OK) {
if(frm.ShowDialog(sender, this) == System.Windows.Forms.DialogResult.OK) {
Task.Run(() => {
InteropEmu.Connect(ConfigManager.Config.ClientConnectionInfo.Host, ConfigManager.Config.ClientConnectionInfo.Port, ConfigManager.Config.Profile.PlayerName, ConfigManager.Config.ClientConnectionInfo.Spectator);
});
@ -191,7 +191,7 @@ namespace Mesen.GUI.Forms
private void mnuProfile_Click(object sender, EventArgs e)
{
using(frmPlayerProfile frm = new frmPlayerProfile()) {
frm.ShowDialog(sender);
frm.ShowDialog(sender, this);
}
}

View file

@ -19,16 +19,12 @@ using Mesen.GUI.Forms.Config;
using Mesen.GUI.Forms.HdPackEditor;
using Mesen.GUI.Forms.NetPlay;
using Mesen.GUI.GoogleDriveIntegration;
using Mesen.GUI.Properties;
namespace Mesen.GUI.Forms
{
public partial class frmMain : BaseForm, IMessageFilter
public partial class frmMain : BaseInputForm
{
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
private InteropEmu.NotificationListener _notifListener;
private Thread _emuThread;
private frmLogWindow _logWindow;
@ -46,13 +42,14 @@ namespace Mesen.GUI.Forms
private bool _isNsfPlayerMode = false;
private object _loadRomLock = new object();
private int _romLoadCounter = 0;
private bool _removeFocus = false;
private bool _showUpgradeMessage = false;
private float _xFactor = 1;
private float _yFactor = 1;
private bool _enableResize = false;
private bool _overrideWindowSize = false;
private frmFullscreenRenderer _frmFullscreenRenderer = null;
private Dictionary<EmulatorShortcut, Func<bool>> _actionEnabledFuncs = new Dictionary<EmulatorShortcut, Func<bool>>();
private string[] _commandLineArgs;
@ -186,29 +183,6 @@ namespace Mesen.GUI.Forms
if(ConfigManager.Config.WindowSize.HasValue && !_overrideWindowSize) {
this.ClientSize = ConfigManager.Config.WindowSize.Value;
}
if(Program.IsMono) {
//Mono does not trigger the activate/deactivate events when opening a modal popup, but it does set the form to disabled
//Use this to reset key states
this.EnabledChanged += (object s, EventArgs evt) => {
_removeFocus = !this.Enabled;
InteropEmu.ResetKeyState();
};
}
}
protected override void OnDeactivate(EventArgs e)
{
base.OnDeactivate(e);
_removeFocus = true;
InteropEmu.ResetKeyState();
}
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
_removeFocus = false;
InteropEmu.ResetKeyState();
}
protected override void OnShown(EventArgs e)
@ -283,7 +257,7 @@ namespace Mesen.GUI.Forms
void InitializeEmu()
{
InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, this.ctrlRenderer.Handle, _noAudio, _noVideo, _noInput);
InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, ctrlRenderer.Handle, _noAudio, _noVideo, _noInput);
if(ConfigManager.Config.PreferenceInfo.OverrideGameFolder && Directory.Exists(ConfigManager.Config.PreferenceInfo.GameFolder)) {
InteropEmu.AddKnownGameFolder(ConfigManager.Config.PreferenceInfo.GameFolder);
}
@ -349,47 +323,108 @@ namespace Mesen.GUI.Forms
}
}
private void SetScaleBasedOnWindowSize()
private void SetScaleBasedOnDimensions(Size dimensions)
{
_customSize = true;
InteropEmu.ScreenSize size = InteropEmu.GetScreenSize(true);
double verticalScale = (double)panelRenderer.ClientSize.Height / size.Height;
double horizontalScale = (double)panelRenderer.ClientSize.Width / size.Width;
double verticalScale = (double)dimensions.Height / size.Height;
double horizontalScale = (double)dimensions.Width / size.Width;
double scale = Math.Min(verticalScale, horizontalScale);
if(_fullscreenMode && ConfigManager.Config.VideoInfo.FullscreenForceIntegerScale) {
if(ConfigManager.Config.VideoInfo.FullscreenForceIntegerScale) {
scale = Math.Floor(scale);
}
UpdateScaleMenu(scale);
VideoInfo.ApplyConfig();
}
private void SetScaleBasedOnWindowSize()
{
SetScaleBasedOnDimensions(panelRenderer.ClientSize);
}
private void SetScaleBasedOnScreenSize()
{
SetScaleBasedOnDimensions(Screen.FromControl(this).Bounds.Size);
}
private void StopExclusiveFullscreenMode()
{
if(_frmFullscreenRenderer != null) {
_frmFullscreenRenderer.Close();
}
}
private void StartExclusiveFullscreenMode()
{
Size screenSize = Screen.FromControl(this).Bounds.Size;
_frmFullscreenRenderer = new frmFullscreenRenderer();
_frmFullscreenRenderer.Shown += (object sender, EventArgs e) => {
ctrlRenderer.Visible = false;
SetScaleBasedOnScreenSize();
InteropEmu.SetFullscreenMode(true, _frmFullscreenRenderer.Handle, (UInt32)screenSize.Width, (UInt32)screenSize.Height);
};
_frmFullscreenRenderer.FormClosing += (object sender, FormClosingEventArgs e) => {
InteropEmu.SetFullscreenMode(false, ctrlRenderer.Handle, (UInt32)screenSize.Width, (UInt32)screenSize.Height);
_frmFullscreenRenderer = null;
ctrlRenderer.Visible = true;
_fullscreenMode = false;
frmMain_Resize(null, EventArgs.Empty);
};
_frmFullscreenRenderer.Show();
}
private void StartFullscreenWindowMode()
{
this.menuStrip.Visible = false;
_originalWindowState = this.WindowState;
this.WindowState = FormWindowState.Normal;
this.FormBorderStyle = FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
SetScaleBasedOnWindowSize();
}
private void StopFullscreenWindowMode()
{
this.menuStrip.Visible = true;
this.WindowState = _originalWindowState;
this.FormBorderStyle = FormBorderStyle.Sizable;
this.frmMain_Resize(null, EventArgs.Empty);
}
private void SetFullscreenState(bool enabled)
{
this.Resize -= frmMain_Resize;
_fullscreenMode = enabled;
if(enabled) {
this.menuStrip.Visible = false;
_originalWindowState = this.WindowState;
this.WindowState = FormWindowState.Normal;
this.FormBorderStyle = FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
SetScaleBasedOnWindowSize();
} else {
this.menuStrip.Visible = true;
this.WindowState = _originalWindowState;
this.FormBorderStyle = FormBorderStyle.Sizable;
this.frmMain_Resize(null, EventArgs.Empty);
if(this._isNsfPlayerMode) {
enabled = false;
}
this.Resize += frmMain_Resize;
UpdateViewerSize();
_fullscreenMode = enabled;
mnuFullscreen.Checked = enabled;
if(ConfigManager.Config.VideoInfo.UseExclusiveFullscreen) {
if(_emuThread != null) {
if(enabled) {
StartExclusiveFullscreenMode();
} else {
StopExclusiveFullscreenMode();
}
}
} else {
this.Resize -= frmMain_Resize;
if(enabled) {
StartFullscreenWindowMode();
} else {
StopFullscreenWindowMode();
}
this.Resize += frmMain_Resize;
UpdateViewerSize();
}
}
private bool HideMenuStrip
{
get
{
return _fullscreenMode || ConfigManager.Config.PreferenceInfo.AutoHideMenu;
return (_fullscreenMode && !ConfigManager.Config.VideoInfo.UseExclusiveFullscreen) || ConfigManager.Config.PreferenceInfo.AutoHideMenu;
}
}
@ -469,6 +504,10 @@ namespace Mesen.GUI.Forms
_hdPackEditorWindow.Close();
}
ctrlRecentGames.Initialize();
if(e.Parameter == IntPtr.Zero) {
//We are completely stopping the emulation, close fullscreen mode
StopExclusiveFullscreenMode();
}
}));
break;
@ -607,6 +646,8 @@ namespace Mesen.GUI.Forms
}
}
bool restoreFullscreen = _frmFullscreenRenderer != null;
switch(shortcut) {
case EmulatorShortcut.Pause: PauseEmu(); break;
case EmulatorShortcut.Reset: this.ResetEmu(); break;
@ -624,7 +665,7 @@ namespace Mesen.GUI.Forms
case EmulatorShortcut.ToggleLagCounter: ToggleLagCounter(); break;
case EmulatorShortcut.ToggleOsd: ToggleOsd(); break;
case EmulatorShortcut.MaxSpeed: ToggleMaxSpeed(); break;
case EmulatorShortcut.ToggleFullscreen: ToggleFullscreen(); break;
case EmulatorShortcut.ToggleFullscreen: ToggleFullscreen(); restoreFullscreen = false; break;
case EmulatorShortcut.OpenFile: OpenFile(); break;
case EmulatorShortcut.IncreaseSpeed: InteropEmu.IncreaseEmulationSpeed(); break;
@ -644,7 +685,7 @@ namespace Mesen.GUI.Forms
case EmulatorShortcut.InputBarcode:
using(frmInputBarcode frm = new frmInputBarcode()) {
frm.ShowDialog();
frm.ShowDialog(this, this);
}
break;
@ -677,6 +718,11 @@ namespace Mesen.GUI.Forms
case EmulatorShortcut.LoadStateSlot7: LoadState(7); break;
case EmulatorShortcut.LoadStateSlot8: LoadState(8); break;
}
if(restoreFullscreen && _frmFullscreenRenderer == null) {
//Need to restore fullscreen mode after showing a dialog
this.SetFullscreenState(true);
}
}
private void ToggleFullscreen()
@ -759,22 +805,6 @@ namespace Mesen.GUI.Forms
ConfigManager.ApplyChanges();
}
private void UpdateFocusFlag()
{
bool hasFocus = false;
if(Application.OpenForms.Count > 0) {
if(Application.OpenForms[0].ContainsFocus) {
hasFocus = true;
}
}
if(_removeFocus) {
hasFocus = false;
}
InteropEmu.SetFlag(EmulationFlags.InBackground, !hasFocus);
}
private void UpdateMenus()
{
try {
@ -790,7 +820,6 @@ namespace Mesen.GUI.Forms
ctrlLoading.Visible = (_romLoadCounter > 0);
UpdateFocusFlag();
UpdateWindowTitle();
bool isNetPlayClient = InteropEmu.IsConnected();
@ -964,20 +993,6 @@ namespace Mesen.GUI.Forms
}
}
bool IMessageFilter.PreFilterMessage(ref Message m)
{
if(Application.OpenForms.Count > 0 && Application.OpenForms[0].ContainsFocus) {
if(m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYUP) {
int scanCode = (Int32)(((Int64)m.LParam & 0x1FF0000) >> 16);
InteropEmu.SetKeyState(scanCode, false);
} else if(m.Msg == WM_SYSKEYDOWN || m.Msg == WM_KEYDOWN) {
int scanCode = (Int32)(((Int64)m.LParam & 0x1FF0000) >> 16);
InteropEmu.SetKeyState(scanCode, true);
}
}
return false;
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(!this.menuStrip.Enabled) {
@ -1016,7 +1031,7 @@ namespace Mesen.GUI.Forms
if(MesenMsgBox.Show("FdsBiosNotFound", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) {
using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.SetFilter(ResourceHelper.GetMessage("FilterAll"));
if(ofd.ShowDialog() == DialogResult.OK) {
if(ofd.ShowDialog(this) == DialogResult.OK) {
string hash = MD5Helper.GetMD5Hash(ofd.FileName).ToLowerInvariant();
if(hash == "ca30b50f880eb660a320674ed365ef7a" || hash == "c1a9e9415a6adde3c8563c622d4c9fce") {
File.Copy(ofd.FileName, Path.Combine(ConfigManager.HomeFolder, "FdsBios.bin"));
@ -1113,6 +1128,8 @@ namespace Mesen.GUI.Forms
this.BeginInvoke((MethodInvoker)(() => this.InitializeNsfMode(updateTextOnly, gameLoaded)));
} else {
if(InteropEmu.IsNsf()) {
this.SetFullscreenState(false);
if(gameLoaded) {
//Force emulation speed to 100 when loading a NSF
SetEmulationSpeed(100);
@ -1132,7 +1149,6 @@ namespace Mesen.GUI.Forms
this.ctrlNsfPlayer.Visible = true;
this.ctrlNsfPlayer.Focus();
NsfHeader header = InteropEmu.NsfGetHeader();
if(header.HasSongName) {
_currentGame = header.GetSongName();

View file

@ -612,6 +612,9 @@
<Compile Include="Forms\BaseConfigForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\BaseInputForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Cheats\ctrlCheatFinder.cs">
<SubType>UserControl</SubType>
</Compile>
@ -678,9 +681,7 @@
<Compile Include="Forms\Config\frmCopyFiles.Designer.cs">
<DependentUpon>frmCopyFiles.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Config\frmGetKey.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Config\frmGetKey.cs" />
<Compile Include="Forms\Config\frmGetKey.Designer.cs">
<DependentUpon>frmGetKey.cs</DependentUpon>
</Compile>
@ -757,6 +758,9 @@
<Compile Include="Forms\frmDownloadProgress.Designer.cs">
<DependentUpon>frmDownloadProgress.cs</DependentUpon>
</Compile>
<Compile Include="Forms\frmFullscreenRenderer.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmHelp.cs">
<SubType>Form</SubType>
</Compile>
@ -777,27 +781,21 @@
</Compile>
<Compile Include="Forms\frmMain.File.cs">
<DependentUpon>frmMain.cs</DependentUpon>
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmMain.Game.cs">
<DependentUpon>frmMain.cs</DependentUpon>
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmMain.Options.cs">
<DependentUpon>frmMain.cs</DependentUpon>
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmMain.Tests.cs">
<DependentUpon>frmMain.cs</DependentUpon>
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmMain.Tools.cs">
<DependentUpon>frmMain.cs</DependentUpon>
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmMain.Help.cs">
<DependentUpon>frmMain.cs</DependentUpon>
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmRecordAvi.cs">
<SubType>Form</SubType>
@ -831,9 +829,7 @@
<Compile Include="Forms\NetPlay\frmClientConfig.Designer.cs">
<DependentUpon>frmClientConfig.cs</DependentUpon>
</Compile>
<Compile Include="Forms\frmMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmMain.cs" />
<Compile Include="Forms\frmMain.Designer.cs">
<DependentUpon>frmMain.cs</DependentUpon>
</Compile>
@ -1035,6 +1031,9 @@
<EmbeddedResource Include="Forms\BaseForm.resx">
<DependentUpon>BaseForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\BaseInputForm.resx">
<DependentUpon>BaseInputForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Cheats\ctrlCheatFinder.resx">
<DependentUpon>ctrlCheatFinder.cs</DependentUpon>
</EmbeddedResource>

View file

@ -24,6 +24,8 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void SetDisplayLanguage(Language lang);
[DllImport(DLLPath)] public static extern void SetFullscreenMode([MarshalAs(UnmanagedType.I1)]bool fullscreen, IntPtr windowHandle, UInt32 monitorWidth, UInt32 monitorHeight);
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsRunning();
[DllImport(DLLPath)] public static extern void LoadROM([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string patchFile);

View file

@ -122,6 +122,14 @@ namespace InteropEmu {
}
}
DllExport void __stdcall SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight)
{
if(_renderer) {
_renderer->SetFullscreenMode(fullscreen, windowHandle, monitorWidth, monitorHeight);
}
}
DllExport bool __stdcall IsRunning() { return Console::IsRunning(); }
DllExport void __stdcall LoadROM(char* filename, char* patchFile) { Console::LoadROM((string)filename, (string)patchFile); }

View file

@ -17,6 +17,11 @@ SdlRenderer::~SdlRenderer()
Cleanup();
}
void SdlRenderer::SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight)
{
//TODO: Implement exclusive fullscreen for Linux
}
void SdlRenderer::Init()
{
SDL_InitSubSystem(SDL_INIT_VIDEO);

View file

@ -64,4 +64,6 @@ public:
void Reset();
void DrawString(std::wstring message, int x, int y, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255, uint8_t opacity = 255);
void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) override;
};

View file

@ -29,24 +29,73 @@ namespace NES
CleanupDevice();
}
void Renderer::SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight)
{
if(fullscreen != _fullscreen || _hWnd != (HWND)windowHandle) {
_hWnd = (HWND)windowHandle;
_monitorWidth = monitorWidth;
_monitorHeight = monitorHeight;
_newFullscreen = fullscreen;
}
}
void Renderer::SetScreenSize(uint32_t width, uint32_t height)
{
ScreenSize screenSize;
VideoDecoder::GetInstance()->GetScreenSize(screenSize, false);
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _resizeFilter != EmulationSettings::GetVideoResizeFilter()) {
_frameLock.Acquire();
_nesFrameHeight = height;
_nesFrameWidth = width;
_newFrameBufferSize = width*height;
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _resizeFilter != EmulationSettings::GetVideoResizeFilter() || _newFullscreen != _fullscreen) {
auto frameLock = _frameLock.AcquireSafe();
auto textureLock = _textureLock.AcquireSafe();
VideoDecoder::GetInstance()->GetScreenSize(screenSize, false);
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _resizeFilter != EmulationSettings::GetVideoResizeFilter() || _newFullscreen != _fullscreen) {
_nesFrameHeight = height;
_nesFrameWidth = width;
_newFrameBufferSize = width*height;
_screenHeight = screenSize.Height;
_screenWidth = screenSize.Width;
bool needReset = _fullscreen != _newFullscreen;
bool fullscreenResizeMode = _fullscreen && _newFullscreen;
_screenBufferSize = _screenHeight*_screenWidth;
if(_pSwapChain && _fullscreen && !_newFullscreen) {
HRESULT hr = _pSwapChain->SetFullscreenState(FALSE, NULL);
if(FAILED(hr)) {
MessageManager::Log("SetFullscreenState(FALSE) failed - Error:" + std::to_string(hr));
}
}
Reset();
_frameLock.Release();
_fullscreen = _newFullscreen;
_screenHeight = screenSize.Height;
_screenWidth = screenSize.Width;
if(_fullscreen) {
_realScreenHeight = _monitorHeight;
_realScreenWidth = _monitorWidth;
} else {
_realScreenHeight = screenSize.Height;
_realScreenWidth = screenSize.Width;
}
_leftMargin = (_realScreenWidth - _screenWidth) / 2;
_topMargin = (_realScreenHeight - _screenHeight) / 2;
_screenBufferSize = _realScreenHeight*_realScreenWidth;
if(!_pSwapChain || needReset) {
Reset();
} else {
if(fullscreenResizeMode) {
ResetNesBuffers();
CreateNesBuffers();
} else {
ResetNesBuffers();
ReleaseRenderTargetView();
_pSwapChain->ResizeBuffers(1, _realScreenWidth, _realScreenHeight, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
CreateRenderTargetView();
CreateNesBuffers();
}
}
}
}
}
@ -62,6 +111,37 @@ namespace NES
}
void Renderer::CleanupDevice()
{
ResetNesBuffers();
ReleaseRenderTargetView();
if(_pAlphaEnableBlendingState) {
_pAlphaEnableBlendingState->Release();
_pAlphaEnableBlendingState = nullptr;
}
if(_pDepthDisabledStencilState) {
_pDepthDisabledStencilState->Release();
_pDepthDisabledStencilState = nullptr;
}
if(_samplerState) {
_samplerState->Release();
_samplerState = nullptr;
}
if(_pSwapChain) {
_pSwapChain->SetFullscreenState(false, nullptr);
_pSwapChain->Release();
_pSwapChain = nullptr;
}
if(_pDeviceContext) {
_pDeviceContext->Release();
_pDeviceContext = nullptr;
}
if(_pd3dDevice) {
_pd3dDevice->Release();
_pd3dDevice = nullptr;
}
}
void Renderer::ResetNesBuffers()
{
if(_pTexture) {
_pTexture->Release();
@ -87,34 +167,69 @@ namespace NES
delete[] _textureBuffer[1];
_textureBuffer[1] = nullptr;
}
if(_samplerState) {
_samplerState->Release();
_samplerState = nullptr;
}
}
void Renderer::ReleaseRenderTargetView()
{
if(_pRenderTargetView) {
_pRenderTargetView->Release();
_pRenderTargetView = nullptr;
}
if(_pSwapChain) {
_pSwapChain->Release();
_pSwapChain = nullptr;
}
HRESULT Renderer::CreateRenderTargetView()
{
// Create a render target view
ID3D11Texture2D* pBackBuffer = nullptr;
HRESULT hr = _pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
if(FAILED(hr)) {
MessageManager::Log("SwapChain::GetBuffer() failed - Error:" + std::to_string(hr));
return hr;
}
if(_pDeviceContext) {
_pDeviceContext->Release();
_pDeviceContext = nullptr;
hr = _pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &_pRenderTargetView);
pBackBuffer->Release();
if(FAILED(hr)) {
MessageManager::Log("D3DDevice::CreateRenderTargetView() failed - Error:" + std::to_string(hr));
return hr;
}
if(_pd3dDevice) {
_pd3dDevice->Release();
_pd3dDevice = nullptr;
_pDeviceContext->OMSetRenderTargets(1, &_pRenderTargetView, nullptr);
return S_OK;
}
HRESULT Renderer::CreateNesBuffers()
{
_textureBuffer[0] = new uint8_t[_nesFrameWidth*_nesFrameHeight * 4];
_textureBuffer[1] = new uint8_t[_nesFrameWidth*_nesFrameHeight * 4];
memset(_textureBuffer[0], 0, _nesFrameWidth*_nesFrameHeight * 4);
memset(_textureBuffer[1], 0, _nesFrameWidth*_nesFrameHeight * 4);
_pTexture = CreateTexture(_nesFrameWidth, _nesFrameHeight);
if(!_pTexture) {
return S_FALSE;
}
if(_pAlphaEnableBlendingState) {
_pAlphaEnableBlendingState->Release();
_pAlphaEnableBlendingState = nullptr;
_overlayTexture = CreateTexture(8, 8);
if(!_overlayTexture) {
return S_FALSE;
}
if(_pDepthDisabledStencilState) {
_pDepthDisabledStencilState->Release();
_pDepthDisabledStencilState = nullptr;
_pTextureSrv = GetShaderResourceView(_pTexture);
if(!_pTextureSrv) {
return S_FALSE;
}
_pOverlaySrv = GetShaderResourceView(_overlayTexture);
if(!_pOverlaySrv) {
return S_FALSE;
}
////////////////////////////////////////////////////////////////////////////
_spriteBatch.reset(new SpriteBatch(_pDeviceContext));
_largeFont.reset(new SpriteFont(_pd3dDevice, L"Resources\\Font.64.spritefont"));
_font.reset(new SpriteFont(_pd3dDevice, L"Resources\\Font.24.spritefont"));
return S_OK;
}
//--------------------------------------------------------------------------------------
@ -149,8 +264,8 @@ namespace NES
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 1;
sd.BufferDesc.Width = _screenWidth;
sd.BufferDesc.Height = _screenHeight;
sd.BufferDesc.Width = _realScreenWidth;
sd.BufferDesc.Height = _realScreenHeight;
sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
@ -167,6 +282,10 @@ namespace NES
featureLevel = D3D_FEATURE_LEVEL_11_1;
hr = D3D11CreateDeviceAndSwapChain(nullptr, driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &sd, &_pSwapChain, &_pd3dDevice, &featureLevel, &_pDeviceContext);
/*if(FAILED(hr)) {
MessageManager::Log("D3D11CreateDeviceAndSwapChain() failed - Error:" + std::to_string(hr));
}*/
if(hr == E_INVALIDARG) {
// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
featureLevel = D3D_FEATURE_LEVEL_11_0;
@ -177,23 +296,27 @@ namespace NES
break;
}
}
if(FAILED(hr)) {
MessageManager::Log("D3D11CreateDeviceAndSwapChain() failed - Error:" + std::to_string(hr));
return hr;
}
// Create a render target view
ID3D11Texture2D* pBackBuffer = nullptr;
hr = _pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
if(FAILED(hr)) {
MessageManager::Log("SwapChain::GetBuffer() failed - Error:" + std::to_string(hr));
return hr;
if(_fullscreen) {
hr = _pSwapChain->SetFullscreenState(TRUE, NULL);
if(FAILED(hr)) {
MessageManager::Log("SetFullscreenState(true) failed - Error:" + std::to_string(hr));
MessageManager::Log("Switching back to windowed mode");
hr = _pSwapChain->SetFullscreenState(FALSE, NULL);
if(FAILED(hr)) {
MessageManager::Log("SetFullscreenState(false) failed - Error:" + std::to_string(hr));
return hr;
}
}
}
hr = _pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &_pRenderTargetView);
pBackBuffer->Release();
hr = CreateRenderTargetView();
if(FAILED(hr)) {
MessageManager::Log("D3DDevice::CreateRenderTargetView() failed - Error:" + std::to_string(hr));
return hr;
}
@ -250,46 +373,32 @@ namespace NES
_pDeviceContext->OMSetBlendState(_pAlphaEnableBlendingState, blendFactor, 0xffffffff);
_pDeviceContext->OMSetDepthStencilState(_pDepthDisabledStencilState, 1);
_pDeviceContext->OMSetRenderTargets(1, &_pRenderTargetView, nullptr);
// Setup the viewport
D3D11_VIEWPORT vp;
vp.Width = (FLOAT)_screenWidth;
vp.Height = (FLOAT)_screenHeight;
vp.Width = (FLOAT)2560;
vp.Height = (FLOAT)1440;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
_pDeviceContext->RSSetViewports(1, &vp);
_textureBuffer[0] = new uint8_t[_nesFrameWidth*_nesFrameHeight*4];
_textureBuffer[1] = new uint8_t[_nesFrameWidth*_nesFrameHeight*4];
memset(_textureBuffer[0], 0, _nesFrameWidth*_nesFrameHeight*4);
memset(_textureBuffer[1], 0, _nesFrameWidth*_nesFrameHeight*4);
_pTexture = CreateTexture(_nesFrameWidth, _nesFrameHeight);
if(!_pTexture) {
return S_FALSE;
}
_overlayTexture = CreateTexture(8, 8);
if(!_overlayTexture) {
return S_FALSE;
}
_pTextureSrv = GetShaderResourceView(_pTexture);
if(!_pTextureSrv) {
return S_FALSE;
}
_pOverlaySrv = GetShaderResourceView(_overlayTexture);
if(!_pOverlaySrv) {
return S_FALSE;
hr = CreateNesBuffers();
if(FAILED(hr)) {
return hr;
}
////////////////////////////////////////////////////////////////////////////
_spriteBatch.reset(new SpriteBatch(_pDeviceContext));
hr = CreateSamplerState();
if(FAILED(hr)) {
return hr;
}
_largeFont.reset(new SpriteFont(_pd3dDevice, L"Resources\\Font.64.spritefont"));
_font.reset(new SpriteFont(_pd3dDevice, L"Resources\\Font.24.spritefont"));
return S_OK;
}
HRESULT Renderer::CreateSamplerState()
{
_resizeFilter = EmulationSettings::GetVideoResizeFilter();
//Sample state
@ -305,14 +414,13 @@ namespace NES
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
hr = _pd3dDevice->CreateSamplerState(&samplerDesc, &_samplerState);
HRESULT hr = _pd3dDevice->CreateSamplerState(&samplerDesc, &_samplerState);
if(FAILED(hr)) {
MessageManager::Log("D3DDevice::CreateSamplerState() failed - Error:" + std::to_string(hr));
return hr;
}
return S_OK;
return hr;
}
ID3D11Texture2D* Renderer::CreateTexture(uint32_t width, uint32_t height)
@ -367,7 +475,7 @@ namespace NES
font = _font.get();
}
font->DrawString(_spriteBatch.get(), text, XMFLOAT2(x, y), color, 0.0f, XMFLOAT2(0, 0), scale);
font->DrawString(_spriteBatch.get(), text, XMFLOAT2(x+_leftMargin, y+_topMargin), color, 0.0f, XMFLOAT2(0, 0), scale);
}
void Renderer::UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height)
@ -376,9 +484,12 @@ namespace NES
uint32_t bpp = 4;
auto lock = _textureLock.AcquireSafe();
memcpy(_textureBuffer[0], frameBuffer, width*height*bpp);
_needFlip = true;
_frameChanged = true;
if(_textureBuffer[0]) {
//_textureBuffer[0] may be null if directx failed to initialize properly
memcpy(_textureBuffer[0], frameBuffer, width*height*bpp);
_needFlip = true;
_frameChanged = true;
}
}
void Renderer::DrawNESScreen()
@ -416,10 +527,10 @@ namespace NES
_pDeviceContext->Unmap(_pTexture, 0);
RECT destRect;
destRect.left = 0;
destRect.top = 0;
destRect.right = _screenWidth;
destRect.bottom = _screenHeight;
destRect.left = _leftMargin;
destRect.top = _topMargin;
destRect.right = _screenWidth+_leftMargin;
destRect.bottom = _screenHeight+_topMargin;
_spriteBatch->Draw(_pTextureSrv, destRect);
}
@ -428,9 +539,9 @@ namespace NES
{
RECT destRect;
destRect.left = 0;
destRect.right = _screenWidth;
destRect.bottom = _screenHeight;
destRect.top = 0;
destRect.right = _realScreenWidth;
destRect.bottom = _realScreenHeight;
D3D11_MAPPED_SUBRESOURCE dd;
HRESULT hr = _pDeviceContext->Map(_overlayTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd);
@ -452,7 +563,9 @@ namespace NES
_spriteBatch->Draw(_pOverlaySrv, destRect);
XMVECTOR stringDimensions = _largeFont->MeasureString(L"PAUSE");
DrawString("PAUSE", (float)_screenWidth / 2 - stringDimensions.m128_f32[0] / 2, (float)_screenHeight / 2 - stringDimensions.m128_f32[1] / 2 - 8, Colors::AntiqueWhite, 1.0f, _largeFont.get());
float x = (float)_screenWidth / 2 - stringDimensions.m128_f32[0] / 2;
float y = (float)_screenHeight / 2 - stringDimensions.m128_f32[1] / 2 - 8;
DrawString("PAUSE", x, y, Colors::AntiqueWhite, 1.0f, _largeFont.get());
}
void Renderer::Render()
@ -462,6 +575,18 @@ namespace NES
_noUpdateCount = 0;
auto lock = _frameLock.AcquireSafe();
if(_newFullscreen != _fullscreen) {
SetScreenSize(_nesFrameWidth, _nesFrameHeight);
}
if(_pDeviceContext == nullptr) {
//DirectX failed to initialize, try to init
Reset();
if(_pDeviceContext == nullptr) {
//Can't init, prevent crash
return;
}
}
// Clear the back buffer
_pDeviceContext->ClearRenderTargetView(_pRenderTargetView, Colors::Black);
@ -499,7 +624,7 @@ namespace NES
void Renderer::DrawString(std::wstring message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity)
{
XMVECTORF32 color = { (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)opacity / 255.0f };
_font->DrawString(_spriteBatch.get(), message.c_str(), XMFLOAT2((float)x, (float)y), color);
_font->DrawString(_spriteBatch.get(), message.c_str(), XMFLOAT2((float)x+_leftMargin, (float)y+_topMargin), color);
}
float Renderer::MeasureString(std::wstring text)

View file

@ -52,6 +52,16 @@ namespace NES {
const uint32_t _bytesPerPixel = 4;
uint32_t _screenBufferSize = 0;
bool _newFullscreen = false;
bool _fullscreen = false;
uint32_t _realScreenHeight = 240;
uint32_t _realScreenWidth = 256;
uint32_t _leftMargin = 0;
uint32_t _topMargin = 0;
uint32_t _monitorWidth = 0;
uint32_t _monitorHeight = 0;
uint32_t _nesFrameHeight = 0;
uint32_t _nesFrameWidth = 0;
uint32_t _newFrameBufferSize = 0;
@ -76,10 +86,18 @@ namespace NES {
float MeasureString(std::wstring text);
bool ContainsCharacter(wchar_t character);
HRESULT CreateRenderTargetView();
void ReleaseRenderTargetView();
HRESULT CreateNesBuffers();
void ResetNesBuffers();
HRESULT CreateSamplerState();
public:
Renderer(HWND hWnd);
~Renderer();
void SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t monitorWidth, uint32_t monitorHeight);
void Reset();
void Render();